/** * @(#)FadeTransition.java * @version 1.51 04/06/97 * @author Robert Temple (robertt@starwave.com) */ import java.awt.*; import java.awt.image.MemoryImageSource; /** * The FadeTransition class changes one image into another by drawing * a set of random pixels from the new image onto the old image each cell. * the number of pixels draw each cell is the same for each cell. * * DESIGN NOTE: This class uses a bunch of random number to fill in the pixels * of each cell. If found Java's random number generator too slow for * this purpose, and wrote a really simple one. The numbers are not very * random, but it is very fast compared to Sun's. The numbers generated * are more then random enough for my purposes. Also the it only generates * numbers between 0-7. The only numbers we need * */ public class FadeTransition extends BillTransition { // Static Members /** * The total number of cells this transition will show on the screen before * the new image is shown in its entirety * * DON'T CHANGE THIS NUMBER, the random number generator will not * work because it only produces number between 0-7 */ private static final int CELLS = 7; /** Used by a very-pseudo random number generator */ private static final int MULTIPLIER = 0x5D1E2F; /** * Creates a random array used later to create cells. * The FadeTransition class uses a two dimensional array that holds indexes * a number of random numbers. The first dimension is 8 elements in size, * one element for each Cell. Each element in the second dimension is 1/8 * the size of */ private static int[][] createRandomArray(int number_pixels, int cell_h) { int total_cells = CELLS + 1; int new_pixels_per_cell = number_pixels / total_cells; // A multidimensional array that hold indexes into the work pixel array // for every single pixel in the work pixel array. The first dimension // Holds the pixels for each cell, the other dimension is the pixels // indicies. int[][] random = new int[total_cells][new_pixels_per_cell]; // every cell will have the same number of new pixels draw into // the image. No more no less. So keep track of the number // of random values added to each random cell, so that we don't // try to add too many. The array below keeps count int random_count[] = new int[total_cells]; for(int s = 0; s < total_cells; ++s) { random_count[s] = 0; } int cell; int rounded_new_pixels_per_cell = new_pixels_per_cell * total_cells; // inline random number generator starts here // *** read DESIGN NOTES above *** int seed = (int)System.currentTimeMillis(); int denominator = 10; while((new_pixels_per_cell % denominator > 0 || cell_h % denominator == 0) && denominator > 1) { --denominator; } int new_randoms_per_cell = new_pixels_per_cell / denominator; int new_randoms = rounded_new_pixels_per_cell / denominator; // create a bunch of random numbers and put them into the // array without checking to see if any particular array // is full. Do this until it is possible that one filled // up. for(int p = 0; p < new_randoms_per_cell; ++p) { // Generate a random number between 0 - 7 seed *= MULTIPLIER; cell = (seed >>> 29); random[cell][random_count[cell]++] = p; } // might as well as mix up the random number generator a bit more seed += 0x5050; // give other threads a shot at the CPU try { Thread.sleep(150); } catch (InterruptedException e) {} // generate the rest of the random numbers for(int p = new_randoms_per_cell; p < new_randoms; ++p) { // Generate a random number between 0 - 7 seed *= MULTIPLIER; cell = (seed >>> 29); // if the cell this number is supposed to go in is // full, put it in the next cell while(random_count[cell] >= new_randoms_per_cell) { if(++cell >= total_cells) { cell = 0; } } random[cell][random_count[cell]++] = p; } // we only actually filled up the arrays part of the way. // now fill them up the rest of the way using the numbers // we already generated. Also, we don't need to fill in // the numbers for the last cell, since at the last cell // we know that all the work_pixels would have been filled // in with pixels from the new image anyways. for(int s = 0; s < CELLS; ++s) { for(int ps = new_randoms_per_cell; ps < new_pixels_per_cell; ps += new_randoms_per_cell) { int offset = ps * total_cells; for(int p = 0; p < new_randoms_per_cell; ++p) { random[s][ps + p] = random[s][p] + offset; } } // give other threads a shot at the CPU try { Thread.sleep(50); } catch (InterruptedException e) {} } // this cell is never actually used it is only needed previously // to make sure the random numbers where evenly distributed. random[CELLS] = null; return random; } // Instance Members /** * 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); // copy all of the current billboard's pixels into the work pixels System.arraycopy((Object)current_pixels, 0, (Object)work_pixels, 0, pixels_per_cell); // get the random array for this sized applet from the object table. int random[][] = (int[][])object_table.get( getClass().getName() + pixels_per_cell); // if the random array is not found, create it and put it in the // object table. if(random == null) { random = createRandomArray(pixels_per_cell, cell_h); object_table.put(getClass().getName() + pixels_per_cell, random); } // create all the image cells for(int c = 0; c < CELLS; ++c) { // give other threads a shot at the CPU try { Thread.sleep(100); } catch (InterruptedException e) {} // draw in the pixels that the random array specifies for // this cell from the new image into the work pixels int limit = random[c].length; for(int p = 0; p < limit; ++p) { int pixel_index = random[c][p]; work_pixels[pixel_index] = next_pixels[pixel_index]; } // give other threads a shot at the CPU try { Thread.sleep(50); } catch (InterruptedException e) {} // create the new cell image from the work pixels createCellFromWorkPixels(c); } // we don't need the work pixels anymore work_pixels = null; } }