package psychWithJava; /* * Chapter A: BitsPP * * Provides Bits++ triggering mechanism and methods to load * Bits++ look up tables. * */ import java.awt.*; import java.awt.image.*; /** * Provides Bits++ triggering mechanism and methods to load * Bits++ look up tables. *
* 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 FullScreen
* @see BitsPPFake
*
* @author boyaci
*
*/
public class BitsPP extends FullScreen {
private BufferedImage lutBI;
private WritableRaster lutWR;
/**
*
* Constructs a BitsPP object on the default screen.
* It initializes the clut line 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 BitsPP() {
this(0);
}
/**
* Constructs a BitsPP object on the screen designated with
* displayID. It initializes the clut line 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 BitsPP(int screen_id) {
super(screen_id);
initClut();
}
/**
* Initializes the clut row used for communicating with Bits++
* hardware device.
*
*/
public void initClut() {
int[] unlock = { 36, 106, 133, 63, 136, 163, 8, 19,
138, 211, 25, 46, 3, 115, 164, 112, 68, 9, 56, 41,
49, 34, 159, 208, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int width = getWidth();
lutBI = new BufferedImage(width, 1, BufferedImage.TYPE_INT_RGB);
lutWR = (WritableRaster) lutBI.getRaster();
try {
lutWR.setPixels(0, 0, unlock.length / 3, 1, unlock);
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Error in BitsPP.initClut(): cannot initialize " +
"clut row (is your screen wide enough (>524 pixels)?)");
e.printStackTrace();
}
int[] table = new int[256];
for (int i = 0; i < table.length; i++) {
table[i] = i << 6;
}
setClut(table);
}
/**
* Sets a new look up table for each color channel. Each element
* in the tables is a 14 bit relation between pixel values and
* relative luminance displayed on the screen.
*
* @param redClut red look up table
* @param greenClut green look up table
* @param blueClut blue look up table
*
* @see #setClut(int[])
*
* @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");
int[] row = new int[len * 2 * 3];
int r;
int g;
int b;
for (int i = 0; i < len; i++) {
r = redClut[i] << 2;
g = greenClut[i] << 2;
b = blueClut[i] << 2;
row[i * 6] = r >> 8;
row[i * 6 + 1] = g >> 8;
row[i * 6 + 2] = b >> 8;
row[i * 6 + 3] = r & 255;
row[i * 6 + 4] = g & 255;
row[i * 6 + 5] = b & 255;
}
lutWR.setPixels(12, 0, row.length / 3, 1, row);
}
/**
* Sets a new look up table for each color channel.
* Each element
* in the table is a 14 bit relation between pixel values and
* relative luminance displayed on the screen.
*
* @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");
int[] row = new int[len * 2 * 3];
int r;
for (int i = 0; i < len; i++) {
r = (clut[i]) << 2;
row[i * 6] = r >> 8;
row[i * 6 + 1] = row[i * 6];
row[i * 6 + 2] = row[i * 6];
row[i * 6 + 3] = r & 255;
row[i * 6 + 4] = row[i * 6 + 3];
row[i * 6 + 5] = row[i * 6 + 3];
}
lutWR.setPixels(12, 0, row.length / 3, 1, row);
}
/**
* 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 draws the clut row at the upper left corner * of the screen to communicate with Bits++ device. That row * determines the look up operation used in that refresh of the screen. * * @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) { Graphics2D g = (Graphics2D)getBufferStrategy().getDrawGraphics(); try { if(g!=null && bi!=null){ g.drawImage(bi, x, y, null); g.drawImage(lutBI, 0, 0, null); } } finally { g.dispose(); } } /** * Displays text at the specified position. * Note that, in case there is a back video buffer * this method draws the text on the back buffer. In that case * user has to invoke the updateScreen() method * to actually display the text on the screen. *
* This method also draws the clut row at the upper left corner * of the screen to communicate with Bits++ device. That row * determines the look up operation used in that refresh of the screen. * * @param x horizontal offset of the upper left corner of the text from the * upper left corner of the screen * @param y vertical offset of the upper left corner of the text from the * upper left corner of the screen * @param text a text message to display * * @see #displayText(String) * @see #updateScreen() * @see #setClut(int[], int[], int[]) * @see #setClut(int[]) */ public void displayText(int x, int y, String text) { Graphics2D g = (Graphics2D)getBufferStrategy().getDrawGraphics(); try { if(g!=null && text!=null){ g.setFont(getFont()); g.setColor(getForeground()); g.drawString(text, x, y); g.drawImage(lutBI, 0, 0, this); } } finally { g.dispose(); } } /** * Blanks the whole screen using the current background color. * Note that, in case there is a back video buffer * this method blanks the back buffer. In that case * user has to invoke the updateScreen() method * to actually blank the screen. *
* This method also draws the clut row at the upper left corner * of the screen to communicate with Bits++ device. That row * determines the look up operation used in that refresh of the screen. * * @see #updateScreen() * @see #setClut(int[], int[], int[]) * @see #setClut(int[]) * */ public void blankScreen() { Graphics2D g = (Graphics2D)getBufferStrategy().getDrawGraphics(); try { if(g!=null){ g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); g.drawImage(lutBI, 0, 0, this); } } finally { g.dispose(); } } /** * Closes the full screen exclusive mode screen. * This method performs also the * following additional steps: it restores a linear look up table * on the Bits++ device (so that the screen has a good looking * condition after the program is terminated), * it switches the resolution back to system setting, * releases all the screen resources to the operating system. * User must invoke this method to re-gain access to normal (good looking) * desktop. * * @see #BitsPP() * @see #BitsPP(int) * */ public void closeScreen() { initClut(); blankScreen(); updateScreen(); try{ Thread.sleep(100); }catch(InterruptedException e){} super.closeScreen(); } }