//
// $Id: BackgroundTiler.java,v 1.2 2002/05/07 03:23:46 mdb Exp $

package com.threerings.media.util;

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

import com.threerings.media.Log;

/**
 * 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)
    {
        // make sure we were given the goods
        if (src == null) {
            Log.info("Backgrounder given null source image. Coping.");
            return;
        }

        // 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
        _tiles = new BufferedImage[9];
        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)
    {
        // bail out now if we were passed a bogus source image at
        // construct time
        if (_tiles == null) {
            return;
        }

        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;

    /** 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;
}

@@ -33,33 +33,36 @@
 v 1.
-2
+3
  2002/0
-5/07 03:23:46 mdb
+9/25 21:49:53 shaper
  Exp
@@ -4225,24 +4225,44 @@
  in the row%0A
+        int cx = x;%0A
         g.dr
@@ -4285,16 +4285,17 @@
 idx++%5D, 
+c
 x, y, nu
@@ -4303,24 +4303,25 @@
 l);%0A        
+c
 x += _w3;%0A%0A 
@@ -4450,24 +4450,25 @@
 iles%5Btidx%5D, 
+c
 x, y, null);
@@ -4480,16 +4480,17 @@
         
+c
 x += _cw
@@ -4701,20 +4701,23 @@
         
+c
 x = 
+x+
 width-_w
@@ -4755,16 +4755,17 @@
 +tidx%5D, 
+c
 x, y, nu

Take into account the x-offset of the rectangle within which the image is being rendered when drawing the right edge of the image.