/************************************************
 * 6.837 F98 Project #1 - ANIMATED SPRITES
 * @author Copyright (c) Hugo Botelho Barra Fall 1998
 * AlphaRaster.java
 * 
 * This class extends Raster.java to add the following functionality:
 * 
 * - support to Alpha channel handling
 * - support to easier offscreen painting (see explanation on buffer variable below)
 * 
 */

import java.awt.*;
import java.awt.image.*;

class AlphaRaster extends Raster 
	{

	
    ///////////////////////// Variables ////////////////////////////	
	
	
	public boolean alpha;	//Determines whether an raster's alpha channel should be used or not
	
	public Raster buffer;	//This raster may be used for offscreen painting. It is useful
							//for making transformations to the raster that may have to be
							//reversed


    ///////////////////////// Constructors //////////////////////

	
	
    /************************************************
     * This constructor, which takes no arguments,
     * allows for future extension.
     */
    public AlphaRaster()
    {
		super();
		alpha = false;
		
		buffer = new Raster();
    }

	
    /************************************************
     * This constructor creates an uninitialized *OPAQUE*
     * Raster Object of a given size (w x h).
     */
    public AlphaRaster(int w, int h)
    {
		super(w, h);
		alpha = false;
		
		buffer = new Raster(w, h);
    }
	
	
	public AlphaRaster(Image img)
    {
		super(img);
		alpha = false;
		
		buffer = new Raster(img);
    }

	
	/************************************************
     * This constructor creates a Raster object with an Alpha
     * channel. Raster Object of a given size (w x h).
     *
     * This constructor allows for supply of image and alpha
     * channel separately, since Java does not currently support
     * image formats such as TIF, TGA or PSD, which incorporate
     * the channel.
     * 
     * The image used for the alpha channel should contain the 
     * alpha information in its BLUE channel. An easy way to
     * obtain such an image is simply to create a greyscale version
     * of the alpha image (all three R, G and B channels will be equal).
     * 
     * BLACK => completely opaque
     * WHITE => completely transparent
     * 
     */
	public AlphaRaster(Image img, Image alphaChannel)
    {
		super(img);
		
		//Assuming images are of the same size
		int alphaPixel[] = new int[width * height];
        
		//Extract alpha channel information from alpha image
		try {
            PixelGrabber grabber = new PixelGrabber(alphaChannel, 0, 0, -1, -1, true);
            if (grabber.grabPixels()) {
                width = grabber.getWidth();
                height = grabber.getHeight();
                alphaPixel = (int []) grabber.getPixels();
            }
			
        } catch (InterruptedException e) {
        }
		
		
		//Merge alpha-channel information into original Raster
		for (int i = 0; i < width*height; i++) 
		{
			pixel[i] = (alphaPixel[i] << 24) | (pixel[i] & 0x00ffffff);
		}
		
		alpha = true;
		
		//Places a copy of this image inside the auxiliar buffer
		buffer = new Raster(img);
    }

	

    ////////////////////////// Methods //////////////////////////

	

	/************************************************
     * Composite image of Raster with a foreground image.
     * 
     * Experimenting with variable alpha-channel composition, I came to
     * the conclusion that it is not efficient enough to be
     * calculated real-time and that it also yields very strange
     * results in most cases. I FIRMLY believe programs such as Photoshop
     * make adjustments to the original composition equation seen
     * in lecture to get such smooth results.
     * 
     * Therefore, only complete transparecny or opaqueness is implemented,
     * but total alpha blending could be implemented very quickly by
     * plugging the composition equation into this method's loop.
     * 
     */
	public void composite(AlphaRaster foreground, int x, int y, int wMax, int hMax)
	{
		for (int i = x; i < (x + foreground.width); i++) 
		{
			for (int j = y; j < (y + foreground.height); j++)
			{
				if ( ((foreground.getPixel(i - x, j - y)) & 0xff000000) ==  0xff000000) {
					buffer.setPixel(foreground.getPixel(i - x, j - y), i%wMax, j%hMax);
				} else {
					buffer.setPixel(getPixel(i%wMax, j%hMax), i%wMax, j%hMax);
				}
			}
		}
	}
	

	
    /************************************************
     * Returns pixels within a specific area of the Raster.
     * This has been implemented into the new version of Raster.java
     * 
     */
	public int[] getPixels(int x, int y, int w, int h)
	{
		int[] pixels = new int[w * h];
		for (int i = x; i < (x + w); i++)
		{
			for (int j = y; j < (y + h); j++)
			{
				pixels[(j-y)*w+(i-x)] = pixel[j*width+i];
			}
		}
		return pixels;
	}
	

	
    /************************************************
     * Returns pixels within a specific area of the auxiliar buffer.
     * 
     */
	public int[] getBuffer(int x, int y, int w, int h)
	{
		int[] pixels = new int[w * h];
		
		for (int i = x; i < (x + w); i++)
		{
			for (int j = y; j < (y + h); j++)
			{
				if ( (w <= width) & (w >= 0) & (h <= height) & (h >= 0) )
 					pixels[(j-y)*w+(i-x)] = buffer.getPixel(i, j);
				else
					pixels[(j-y)*w+(i-x)] = 0xffffffff;
			}
		}

		return pixels;
	}
	
	

    /************************************************
     * Returns one single pixel of the Raster.
     * **Note: this method does CLIPPING (returns zero if pixel
     *         is not within visible image)
     * 
     */
	public int getPixel(int x, int y)
	{
        if ( (x <= width) & (x >= 0) & (y <= height) & (y >= 0) ) 
			return pixel[y*width+x];
		else
			return 0;
	}
	
	
	
    /************************************************
     * Resets auxiliar buffer by copying Raster data into it.
     * 
     */
	public void resetBuffer(int x, int y, int w, int h, int wMax, int hMax) 
	{
		for (int i = x; i < (x + w); i++) 
		{
			for (int j = y; j < (y + h); j++)
			{
				buffer.setPixel(getPixel(i%wMax, j%hMax), i%wMax, j%hMax);
			}
		}		
	}



}