package psychWithJava; /* * Chapter A: BitsPPFake.java * * Provides Fake Bits++ methods for development * */ import java.awt.*; import java.awt.image.*; /** * Provides Fake Bits++ methods for development. The method signitures are * identical to BitsPP class. Therefore * a program using BitsPP class can easily be converted to one * which uses BitsPPFake class and run on a system without the Bits++ device * for developing the actual experimental code while the programmer is * away from his or her labaratory. *
* Inherited from FullScreen class, therefore it has all FullScreen * methods available. Additional methods specific to Bits++ device * is detailed below. *
* See Chapter A: Bits++ in
* The Guide to Psychophysics Programming
* with Java for more information.
*
* @see BitsPP
* @see FullScreen
*
* @author boyaci
*
*/
public class BitsPPFake extends FullScreen {
private BufferedImageOp op;
private LookupTable table;
/**
*
* Constructs a BitsPP object on the default screen.
* It initializes a fake clut line used for software lookup
* operation, as opposed to the real one used to communicate
* with the Bits++ device.
* By default it uses a single video buffer and the current
* display mode. Once it is constructed, FullScreen captures the entire screen
* immediately. At the end client's program must
* terminate this mode and go back to system's default display.
* To do this use the method closeScreen()
.
*
* @see #initClut()
* @see #setDisplayMode(DisplayMode)
* @see #setNBuffers(int)
* @see #closeScreen()
*/
public BitsPPFake() {
this(0);
}
/**
* Constructs a BitsPP object on the screen designated with
* displayID. It initializes a fake clut line used for software lookup
* operation, as opposed to the real one used to communicate
* with the Bits++ device.
* By default it uses a single video buffer and the current
* display mode of the client's OS.
* Once it is constructed, BitsPP captures the entire screen
* immediately. At the end client's program must
* terminate this mode and go back to system's default display.
* To do this use the method closeScreen()
.
*
* @param screen_id a numerical id indicating the screen device
*
* @see #initClut()
* @see #setDisplayMode(DisplayMode)
* @see #setNBuffers(int)
* @see #closeScreen()
*
*/
public BitsPPFake(int screen_id) {
super(screen_id);
initClut();
}
/**
* Initializes the clut row used for software look up
* operation as opposed to the actual one used for
* communicating with Bits++
* hardware device.
*
*/
public void initClut() {
int[] convert = new int[256];
for (int i = 0; i < 256; i++)
convert[i] = i << 6;
setClut(convert);
}
/**
* Sets a new look up table for each color channel for software
* look up operation. It uses the most significant 8 bit of each
* element in the tables. Therefore user should pass the same
* 14 bit values as in actual BitsPP class.
*
* @param redClut red look up table
* @param greenClut green look up table
* @param blueClut blue look up table
*
* @throws ArrayIndexOutOfBoundsException if the number of elements is not
* equal to 256 for any color table
*/
public void setClut(int[] redClut, int[] greenClut, int[] blueClut)
throws ArrayIndexOutOfBoundsException{
int len = 256;
if (redClut.length != len || greenClut.length != len
|| blueClut.length != len)
throw new ArrayIndexOutOfBoundsException(
"Clut should have " + len + " elements");
byte[][] row = new byte[3][len];
for (int i = 0; i < len; i++) {
row[0][i] = (byte) (blueClut[i] >> 6);
row[1][i] = (byte) (greenClut[i] >> 6);
row[2][i] = (byte) (redClut[i] >> 6);
}
table = new ByteLookupTable(0, row);
op = new LookupOp(table, new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
}
/**
* Sets a new look up table for each color channel for software look up
* operation.
* It uses the most significant 8 bit of each
* element in the tables. Therefore user should pass the same
* 14 bit values as in actual BitsPP class.
*
* @param clut look up table for all color channels.
*
* @throws ArrayIndexOutOfBoundsException if the number of elements of clut
* is not equal to 256
*/
public void setClut(int clut[]) throws ArrayIndexOutOfBoundsException{
int len = 256;
if (clut.length != len)
throw new ArrayIndexOutOfBoundsException(
"Clut should have " + len + " elements");
byte[] row = new byte[len];
for (int i = 0; i < len; i++)
row[i] = (byte) (clut[i] >> 6);
table = new ByteLookupTable(0, row);
op = new LookupOp(table, new RenderingHints(
RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON));
}
/**
* Displays a BufferedImage at the specified position.
* Note that, in case there is a back video buffer
* this method draws the image on the back buffer. In that case
* user has to invoke the updateScreen() method
* to actually display the image on the screen.
*
* This method also applies the look up operation specified by the * color look up tables. Currently accepts only TYPE_BYTE_GRAY and * TYPE_3BYTE_BGR types of BufferedImage. It is highly recommended to * use with only gray scale images because a software look up is * a very expensive operation. * * @param x horizontal offset of the upper left corner of the image from the * upper left corner of the screen * @param y vertical offset of the upper left corner of the image from the * upper left corner of the screen * @param bi BufferedImage to display * * @see #displayImage(BufferedImage) * @see #updateScreen() * @see #setClut(int[], int[], int[]) * @see #setClut(int[]) */ public void displayImage(int x, int y, BufferedImage bi) { Graphics g = getBufferStrategy().getDrawGraphics(); try { if(g!=null && bi!=null){ if (bi.getRaster().getNumBands() != table.getNumComponents() || (bi.getType() != BufferedImage.TYPE_3BYTE_BGR && bi.getType() != BufferedImage.TYPE_BYTE_GRAY)) { System.err.println( "Exception in BitsPPFake.displayImage(): Wrong image or table type"); System.err.println( "use either a BufferedImage of TYPE_BYTE_GRAY with setClut(table)"); System.err.println( " or a TYPE_3BYTE_BGR with setClut(tableR, tableG, tableB)"); closeScreen(); System.exit(0); } else g.drawImage(op.filter(bi, null), x, y, null); } } finally { g.dispose(); } } }