/**
* @(#)TearTransition.java
* @version 1.51 04/06/97
* @author Robert Temple (robertt@starwave.com)
*/

import java.awt.image.MemoryImageSource;
import java.awt.*;

/**
* The TearTransition class changes one image into another by making it appear
* as if the old image is covering the new image, and the old image is torn
* out from over the new image.
*/
public class TearTransition extends BillTransition {
	/** 
	* The total number of cells this transition will show on the screen before
    * the new image is shown in its entirety
    */
	static final int CELLS = 7;

	/** The number to start the x_cross variable at */
	static final float INITIAL_X_CROSS = 1.6f;

	/** The amount the x_cross number is divided by after each cell */
	static final float X_CROSS_DIVISOR = 3.5f;

	/**
	* A number the cross product of the x and y values of a pixel are
	* multiplied by to give a new x value
	*/
	float x_cross;

	/**
	* Used to initialize the transition right after it is created.
	* creates cells
	* @param owner the component to be used to create images from cells
	*/
	public void init(Component owner, int[] current, int[] next) {		
		init(owner, current, next, CELLS);

		// starting after the first row, Copy the new image into the work pixels
		System.arraycopy((Object)next_pixels, 0, (Object)work_pixels, 
												0, pixels_per_cell);

		// copy all of the current billboard's pixels into the work pixels
		System.arraycopy((Object)current_pixels, 0, (Object)work_pixels, 
                                                0, cell_w);

		x_cross = INITIAL_X_CROSS;

		// Create all the image cells, starting with the last cell.  Since each
		// cell progressively covers more and more of the old image, we start
		// from the last cell to reduce the amount of drawing we need to do from
		// cell to cell.   This is because the last cell covers the least
		// amount of the old image.  So, after drawing the last cell, we can draw
		// right over the work pixels, since we know that we will be covering all
		// that the later cell (the one we had previouly drawn) drew onto the
		// work pixels anyways.  So now we can just draw the pixels of the new
		// image, and don't have to worry about drawing pixels from the old image.
		// email me if this is not clear.  templer@db.erau.edu
		for(int c = CELLS - 1; c >= 0; --c) {

			// give other threads a shot at the CPU
			try { Thread.sleep(100); } catch (InterruptedException e) {}

			// draw the next cell into the work pixels
			Tear();

			// give other threads a shot at the CPU
			try { Thread.sleep(150); } catch (InterruptedException e) {}

			// create the new cell image from the work pixels
			createCellFromWorkPixels(c);

			// set the x_cross for the next cell
			x_cross /= X_CROSS_DIVISOR;
		}

		// we don't need the work pixels anymore
		work_pixels = null;
	}

	/**
	* Create the next cell in the work pixel array
	*/
	final void Tear() {
		float x_increment;
		int p, height_adder;

		// p represent the current offset into the work pixels that we are
		// drawing at
		p = height_adder = cell_w;

		// starting after the first row, draw all the rows, individually into the
		// work pixels
		for (int y = 1; y < cell_h; ++y) {

			// the cross product will equal x_cross * x * y.  Since we are gonna
			// have the same x_cross and y values for this row, calculate it
			// x_cross * y  once for this row, so we don't have to do it for each
			// pixel in this row.  For each pixel we will multiply this value by x
			x_increment = x_cross * y;

			// This if-else structure is a speed optimization.  The first block
			// draws the pixels, pixel by pixel.  The else block draws the pixels
			// by copying sequences of pixels onto the work pixels.
			//##
			// A value of x_increment over 0.50 means that there will never be two
			// adjacent pixels from the old image that will be copied onto the work
			// pixels
			if(x_increment >= 0.50f) {
				float fx = 0.0f;

				// Adding x to a running sum of x_increment + 1 each time is the
				// equivalent of x += x * x_increment, but it is faster
				x_increment += 1.0f;
				int x = 0;

				// draw in the pixels for this row until the end of the row is
				// reached
				do {
					work_pixels[p++] = current_pixels[height_adder + x];

					// Adding x to a running sum of x_increment each time is the
					// equivalent of multiplying x * x_increment
					x = (int)(fx += x_increment);
				} while(x < cell_w);
			}
			else {

				float overflow = 1.0f / x_increment;
				float dst_end = overflow / 2.0f  + 1.49999999f;
				int dst_start = 0, src_offset = 0, length = (int)dst_end;

				while(dst_start + src_offset + length < cell_w) {

					System.arraycopy((Object)current_pixels, p + src_offset, 
								(Object)work_pixels, p, length);

					++src_offset;
					dst_end += overflow;
					p += length;
					dst_start += length;
					length = (int)dst_end - dst_start;
				}

				length = cell_w - src_offset - dst_start;

				System.arraycopy((Object)current_pixels, p + src_offset, 
							(Object)work_pixels, p, length);

			}
			p = height_adder += cell_w;
		}
	}
}


