//
// $Id: BackgroundTiler.java,v 1.1 2002/05/07 03:11:17 mdb Exp $

package com.threerings.media.util;

import java.awt.Graphics;
import java.awt.Shape;
import java.awt.image.BufferedImage;

/**
 * Used to tile a background image into regions of various sizes. The
 * source image is divided into nine quadrants (of mostly equal size)
 * which are tiled accordingly to fill whatever size background image is
 * desired.
 */
public class BackgroundTiler
{
    /**
     * Creates a background tiler with the specified source image.
     */
    public BackgroundTiler (BufferedImage src)
    {
        // compute some values
        _width = src.getWidth(null);
        _w3 = _width/3;
        _cw3 = _width-2*_w3;
        _height = src.getHeight(null);
        _h3 = _height/3;
        _ch3 = _height-2*_h3;

        // create our sub-divided images
        int[] sy = { 0, _h3, _h3+_ch3 };
        int[] thei = { _h3, _ch3, _h3 };
        for (int i = 0; i < 3; i++) {
            _tiles[3*i] = src.getSubimage(0, sy[i], _w3, thei[i]);
            _tiles[3*i+1] = src.getSubimage(_w3, sy[i], _cw3, thei[i]);
            _tiles[3*i+2] = src.getSubimage(_width-_w3, sy[i], _w3, thei[i]);
        }
    }

    /**
     * Fills the requested region with the background defined by our
     * source image.
     */
    public void paint (Graphics g, int x, int y, int width, int height)
    {
        int rwid = width-2*_w3, rhei = height-2*_h3, cy = y;
        Shape oclip = g.getClip();

        // tile the top row
        paintRow(0, g, x, cy, width);
        cy += _h3;

        // tile the (complete) intermediate rows
        int ycount = rhei/_ch3;
        for (int row = 0; row < ycount; row++) {
            paintRow(1, g, x, cy, width);
            cy += _ch3;
        }

        // set the clip and paint the clipped intermediate row (if we
        // didn't tile evenly in the vertical direction)
        int yextra = (rhei - ycount * _ch3);
        if (yextra > 0) {
            g.clipRect(x, cy, width, yextra);
            paintRow(1, g, x, cy, width);
            g.setClip(oclip);
        }

        // tile the last row
        int lasty = y + height - _h3;
        paintRow(2, g, x, lasty, width);

        // now, set the clipping rectangle and render the horizontal tiles
        // that we missed the first time around because we want to clip
        // only once instead of once per row
        int xcount = rwid/_cw3;
        int xextra = (rwid - xcount * _cw3);
        int xoff = x + width - _w3 - xextra;
        if (xextra < width) {
            cy = y; // start back at the top
            g.clipRect(xoff, y, xextra, height);
            g.drawImage(_tiles[1], xoff, cy, null);
            cy += _h3;
            for (int row = 0; row < ycount; row++) {
                g.drawImage(_tiles[4], xoff, cy, null);
                cy += _ch3;
            }
            g.drawImage(_tiles[7], xoff, lasty, null);
        }

        // finally, clip the tiny region where the xextra and yextra rects
        // intersect and paint that last niggling bit (we value
        // correctness, so we're doing things properly)
        if (xextra > 0 && yextra > 0) {
            // we know the clip is still set from the xextra render, so we
            // just restrict it once again to the yextra region and the
            // intersection will happen automatically
            g.clipRect(x, cy, width, yextra);
            g.drawImage(_tiles[4], xoff, lasty - yextra, null);
        }

        // phew, we're done
        g.setClip(oclip);
    }

    /**
     * Used by {@link #paint} to render rows.
     */
    protected void paintRow (int srow, Graphics g, int x, int y, int width)
    {
        int xcount = (width-2*_w3)/_cw3;
        int tidx = 3*srow;

        // draw the first image in the row
        g.drawImage(_tiles[tidx++], x, y, null);
        x += _w3;

        // draw the (complete) tiled middle images
        for (int ii = 0; ii < xcount; ii++) {
            g.drawImage(_tiles[tidx], x, y, null);
            x += _cw3;
        }

        // we'll render the last (incomplete) tiled image in a final
        // cleanup render so that we only have to set the clipping region
        // once

        // draw the end image
        x = width-_w3;
        g.drawImage(_tiles[++tidx], x, y, null);
    }

    /** Our nine sub-divided images. */
    protected BufferedImage[] _tiles = new BufferedImage[9];

    /** The width/height of our source image. */
    protected int _width, _height;

    /** One third of width/height of our source image. */
    protected int _w3, _h3;

    /** The size of the center chunk of our subdivided images. */
    protected int _cw3, _ch3;
}

@@ -29,17 +29,17 @@
 ava,v 1.
-1
+2
  2002/05
@@ -49,13 +49,13 @@
  03:
-11:17
+23:46
  mdb
@@ -185,16 +185,50 @@
 Image;%0A%0A
+import com.threerings.media.Log;%0A%0A
 /**%0A * U
@@ -611,32 +611,206 @@
 mage src)%0A    %7B%0A
+        // make sure we were given the goods%0A        if (src == null) %7B%0A            Log.info(%22Backgrounder given null source image. Coping.%22);%0A            return;%0A        %7D%0A%0A
         // compu
@@ -1042,32 +1042,71 @@
 -divided images%0A
+        _tiles = new BufferedImage%5B9%5D;%0A
         int%5B%5D sy
@@ -1375,16 +1375,32 @@
 3*i+2%5D =
+%0A               
  src.get
@@ -1637,22 +1637,175 @@
 height)%0A
-
     %7B%0A
+        // bail out now if we were passed a bogus source image at%0A        // construct time%0A        if (_tiles == null) %7B%0A            return;%0A        %7D%0A%0A
         
@@ -4821,39 +4821,16 @@
 %5D _tiles
- = new BufferedImage%5B9%5D
 ;%0A%0A    /

Make the tiler cope if it's given a null source image.