/* * Lesson03.java * * Created on July 14, 2003, 12:35 PM */ import java.awt.*; import java.awt.event.*; import javax.swing.*; import net.java.games.jogl.*; /** Port of the NeHe OpenGL Tutorial (Lesson 3: Colors) * to Java using the Jogl interface to OpenGL. Jogl can be obtained * at http://jogl.dev.java.net/ * * @author Kevin Duling (jattier@hotmail.com) */ public class Lesson03 { static class Renderer implements GLEventListener, KeyListener { /** Called by the drawable to initiate OpenGL rendering by the client. * After all GLEventListeners have been notified of a display event, the * drawable will swap its buffers if necessary. * @param gLDrawable The GLDrawable object. */ public void display(GLDrawable gLDrawable) { final GL gl = gLDrawable.getGL(); gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); gl.glLoadIdentity(); gl.glTranslatef(-1.5f, 0.0f, -6.0f); gl.glBegin(GL.GL_TRIANGLES); // Drawing Using Triangles gl.glColor3f(1.0f, 0.0f, 0.0f); // Set the current drawing color to red gl.glVertex3f( 0.0f, 1.0f, 0.0f); // Top gl.glColor3f(0.0f, 1.0f, 0.0f); // Set the current drawing color to green gl.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left gl.glColor3f(0.0f, 0.0f, 1.0f); // Set the current drawing color to blue gl.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right gl.glEnd(); // Finished Drawing The Triangle gl.glTranslatef(3.0f, 0.0f, 0.0f); gl.glBegin(GL.GL_QUADS); // Draw A Quad gl.glColor3f(0.5f, 0.5f, 1.0f); // Set the current drawing color to light blue gl.glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left gl.glVertex3f( 1.0f, 1.0f, 0.0f); // Top Right gl.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right gl.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left gl.glEnd(); // Done Drawing The Quad gl.glFlush(); gLDrawable.swapBuffers(); } /** Called when the display mode has been changed. !! CURRENTLY UNIMPLEMENTED IN JOGL !! * @param gLDrawable The GLDrawable object. * @param modeChanged Indicates if the video mode has changed. * @param deviceChanged Indicates if the video device has changed. */ public void displayChanged(GLDrawable gLDrawable, boolean modeChanged, boolean deviceChanged) { } /** Called by the drawable immediately after the OpenGL context is * initialized for the first time. Can be used to perform one-time OpenGL * initialization such as setup of lights and display lists. * @param gLDrawable The GLDrawable object. */ public void init(GLDrawable gLDrawable) { final GL gl = gLDrawable.getGL(); gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.glShadeModel(GL.GL_SMOOTH); // try setting this to GL_FLAT and see what happens. gLDrawable.addKeyListener(this); } /** Called by the drawable during the first repaint after the component has * been resized. The client can update the viewport and view volume of the * window appropriately, for example by a call to * GL.glViewport(int, int, int, int); note that for convenience the component * has already called GL.glViewport(int, int, int, int)(x, y, width, height) * when this method is called, so the client may not have to do anything in * this method. * @param gLDrawable The GLDrawable object. * @param x The X Coordinate of the viewport rectangle. * @param y The Y coordinate of the viewport rectanble. * @param width The new width of the window. * @param height The new height of the window. */ public void reshape(GLDrawable gLDrawable, int x, int y, int width, int height) { final GL gl = gLDrawable.getGL(); final GLU glu = gLDrawable.getGLU(); if (height <= 0) // avoid a divide by zero error! height = 1; final float h = (float)width / (float)height; gl.glViewport(0, 0, width, height); gl.glMatrixMode(GL.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective(45.0f, h, 1.0, 20.0); gl.glMatrixMode(GL.GL_MODELVIEW); gl.glLoadIdentity(); } /** Invoked when a key has been pressed. * See the class description for {@link KeyEvent} for a definition of * a key pressed event. * @param e The KeyEvent. */ public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0); } /** Invoked when a key has been released. * See the class description for {@link KeyEvent} for a definition of * a key released event. * @param e The KeyEvent. */ public void keyReleased(KeyEvent e) {} /** Invoked when a key has been typed. * See the class description for {@link KeyEvent} for a definition of * a key typed event. * @param e The KeyEvent. */ public void keyTyped(KeyEvent e) {} } /** * CapsChosser is the 'old' Default chooser of jogl, because * on my system the Windows prefered mode is not Hardware accelerated.... */ static class CapsChooser implements GLCapabilitiesChooser { public CapsChooser() { } private static final boolean DEBUG = false; public int chooseCapabilities(GLCapabilities desired, GLCapabilities[] available) { return chooseCapabilities(desired, available, -1); } public int chooseCapabilities(GLCapabilities desired, GLCapabilities[] available, int windowSystemRecommendedChoice) { if (DEBUG) { for (int i = 0; i < available.length; i++) { System.err.println("Available " + i + ": " + available[i]); } } /* if (windowSystemRecommendedChoice >= 0 && windowSystemRecommendedChoice < available.length && available[windowSystemRecommendedChoice] != null) { if (DEBUG) { System.err.println("Choosing window system's recommended choice of " + windowSystemRecommendedChoice); System.err.println(available[windowSystemRecommendedChoice]); } return windowSystemRecommendedChoice; } */ // Create score array int[] scores = new int[available.length]; int NO_SCORE = -9999999; int DOUBLE_BUFFER_MISMATCH_PENALTY = 1000; int STENCIL_MISMATCH_PENALTY = 500; // Pseudo attempt to keep equal rank penalties scale-equivalent // (e.g., stencil mismatch is 3 * accum because there are 3 accum // components) int COLOR_MISMATCH_PENALTY_SCALE = 36; int DEPTH_MISMATCH_PENALTY_SCALE = 6; int ACCUM_MISMATCH_PENALTY_SCALE = 1; int STENCIL_MISMATCH_PENALTY_SCALE = 3; for (int i = 0; i < scores.length; i++) { scores[i] = NO_SCORE; } // Compute score for each for (int i = 0; i < scores.length; i++) { GLCapabilities cur = available[i]; if (cur == null) { continue; } if (desired.getStereo() != cur.getStereo()) { continue; } int score = 0; // Compute difference in color depth // (Note that this decides the direction of all other penalties) score += (COLOR_MISMATCH_PENALTY_SCALE * ((cur.getRedBits() + cur.getGreenBits() + cur.getBlueBits() + cur.getAlphaBits()) - (desired.getRedBits() + desired.getGreenBits() + desired.getBlueBits() + desired.getAlphaBits()))); // Compute difference in depth buffer depth score += (DEPTH_MISMATCH_PENALTY_SCALE * sign(score) * Math.abs(cur.getDepthBits() - desired.getDepthBits())); // Compute difference in accumulation buffer depth score += (ACCUM_MISMATCH_PENALTY_SCALE * sign(score) * Math.abs((cur.getAccumRedBits() + cur.getAccumGreenBits() + cur.getAccumBlueBits() + cur.getAccumAlphaBits()) - (desired.getAccumRedBits() + desired.getAccumGreenBits() + desired.getAccumBlueBits() + desired.getAccumAlphaBits()))); // Compute difference in stencil bits score += STENCIL_MISMATCH_PENALTY_SCALE * sign(score) * (cur.getStencilBits() - desired.getStencilBits()); if (cur.getDoubleBuffered() != desired.getDoubleBuffered()) { score += sign(score) * DOUBLE_BUFFER_MISMATCH_PENALTY; } if ((desired.getStencilBits() > 0) && (cur.getStencilBits() == 0)) { score += sign(score) * STENCIL_MISMATCH_PENALTY; } scores[i] = score; } // Now prefer hardware-accelerated visuals by pushing scores of // non-hardware-accelerated visuals out boolean gotHW = false; int maxAbsoluteHWScore = 0; for (int i = 0; i < scores.length; i++) { int score = scores[i]; if (score == NO_SCORE) { continue; } GLCapabilities cur = available[i]; if (cur.getHardwareAccelerated()) { int absScore = Math.abs(score); if (!gotHW || (absScore > maxAbsoluteHWScore)) { gotHW = true; maxAbsoluteHWScore = absScore; } } } if (gotHW) { for (int i = 0; i < scores.length; i++) { int score = scores[i]; if (score == NO_SCORE) { continue; } GLCapabilities cur = available[i]; if (!cur.getHardwareAccelerated()) { if (score <= 0) { score -= maxAbsoluteHWScore; } else if (score > 0) { score += maxAbsoluteHWScore; } scores[i] = score; } } } if (DEBUG) { System.err.print("Scores: ["); for (int i = 0; i < available.length; i++) { if (i > 0) { System.err.print(","); } System.err.print(" " + scores[i]); } System.err.println(" ]"); } // Ready to select. Choose score closest to 0. int scoreClosestToZero = NO_SCORE; int chosenIndex = -1; for (int i = 0; i < scores.length; i++) { int score = scores[i]; if (score == NO_SCORE) { continue; } // Don't substitute a positive score for a smaller negative score if ((scoreClosestToZero == NO_SCORE) || (Math.abs(score) < Math.abs(scoreClosestToZero) && ((sign(scoreClosestToZero) < 0) || (sign(score) > 0)))) { scoreClosestToZero = score; chosenIndex = i; } } if (chosenIndex < 0) { throw new GLException("Unable to select one of the provided GLCapabilities"); } if (DEBUG) { System.err.println("Chosen index: " + chosenIndex); System.err.println("Chosen capabilities:"); System.err.println(available[chosenIndex]); } return chosenIndex; } private static int sign(int score) { if (score < 0) { return -1; } return 1; } } /** Program's main entry point * @param args command line arguments. */ public static void main(String[] args) { Frame frame = new Frame("Lesson 3: Colors"); GLCanvas canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities(), new CapsChooser()); canvas.addGLEventListener(new Renderer()); System.out.println("Version of jogl: " + Version.getVersion()); // switch off auto swap canvas.setAutoSwapBufferMode(false); frame.add(canvas); // frame.getContentPane().add(canvas); frame.setSize(640, 480); frame.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.show(); canvas.requestFocus(); } }