package psychWithJava; /* * BitsPP.java. * * Copyright (C) 2005-2008 Huseyin Boyaci. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License version 2 for more details * (a copy is included in the LICENSE file that accompanied this code) * (also available at http://www.gnu.org) You should have received a copy of * the GNU General Public License along with this program; if not, write to * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * */ import psychWithJava.FullScreen; 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(); } }