import java.awt.*; import java.awt.event.*; import javax.swing.*; import com.jogamp.opengl.*; import com.jogamp.opengl.awt.*; import com.jogamp.common.nio.Buffers; import java.nio.FloatBuffer; import java.nio.IntBuffer; /** * Use OpenGL to draw two cubes, one using glDrawArrays, * and one using glDrawElements. The arrow keys can be * used to rotate both cubes. * * Note that this program does not use lighting. */ public class CubesWithVertexArrays extends GLJPanel implements GLEventListener, KeyListener { /** * A main routine to create and show a window that contains a * panel of type CubesWithVertexArrays. The program ends when the * user closes the window. */ public static void main(String[] args) { JFrame window = new JFrame("USE ARROW KEYS TO ROTATE; HOME KEY RESETS"); CubesWithVertexArrays panel = new CubesWithVertexArrays(); window.setContentPane(panel); window.pack(); window.setLocation(50,50); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setVisible(true); panel.requestFocusInWindow(); } /** * Constructor for class UnlitCube. */ public CubesWithVertexArrays() { super( new GLCapabilities(null) ); // Makes a panel with default OpenGL "capabilities". setPreferredSize( new Dimension(600,300) ); addGLEventListener(this); // A listener is essential! The listener is where the OpenGL programming lives. addKeyListener(this); } private double rotateX = 15; // rotations of the cube about the axes private double rotateY = -15; private double rotateZ = 0; //---------------------- data for glDrawArrays and glDrawElements ---------------- /* Arrays for use with glDrawElements. This is the data for a cube with 6 different * colors at the six vertices. (Looks kind of strange without lighting.) */ private float[] vertexCoords = { // Coordinates for the vertices of a cube. 1,1,1, 1,1,-1, 1,-1,-1, 1,-1,1, -1,1,1, -1,1,-1, -1,-1,-1, -1,-1,1 }; private float[] vertexColors = { // An RGB color value for each vertex 1,1,1, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 0,0,0, 0,1,1 }; private int[] elementArray = { // Vertex number for the six faces. 0,1,2,3, 0,3,7,4, 0,4,5,1, 6,2,1,5, 6,5,4,7, 6,7,3,2 }; /* We will draw edges for the first cube using this array with glDrawElements. * (It looks pretty bad without lighting if edges aren't drawn. */ private int[] edgeElementArray = { 0,1, 1,5, 5,4, 4,0, // edges of the top face 7,3, 3,2, 2,6, 6,7, // edges of the bottom face 1,2, 0,3, 4,7, 5,6 }; // edges connecting top face to bottom face /* Arrays for use with glDrawArrays. The coordinate array contains four sets of vertex * coordinates for each face. The color array must have a color for each vertex. Since * the color of each face is solid, there is a lot of redundancy in the color array. * There is also redundancy in the coordinate array, compared to using glDrawElements. * But note that it is impossible to use a single call to glDrawElements to draw a cube * with six faces where each face has a different solid color, since with glDrawElements, * the colors are associated with the vertices, not the faces. */ private float[] cubeCoords = { 1,1,1, -1,1,1, -1,-1,1, 1,-1,1, // face #1 1,1,1, 1,-1,1, 1,-1,-1, 1,1,-1, // face #2 1,1,1, 1,1,-1, -1,1,-1, -1,1,1, // face #3 -1,-1,-1, -1,1,-1, 1,1,-1, 1,-1,-1, // face #4 -1,-1,-1, -1,-1,1, -1,1,1, -1,1,-1, // face #5 -1,-1,-1, 1,-1,-1, 1,-1,1, -1,-1,1 }; // face #6 private float[] cubeFaceColors = { 1,0,0, 1,0,0, 1,0,0, 1,0,0, // face #1 is red 0,1,0, 0,1,0, 0,1,0, 0,1,0, // face #2 is green 0,0,1, 0,0,1, 0,0,1, 0,0,1, // face #3 is blue 1,1,0, 1,1,0, 1,1,0, 1,1,0, // face #4 is yellow 0,1,1, 0,1,1, 0,1,1, 0,1,1, // face #5 is cyan 1,0,1, 1,0,1, 1,0,1, 1,0,1, }; // face #6 is red // ----------------------- Data Buffers ------------------------------- /* For use with glDrawArrays and glDrawElements with JOGL, the data must * be in "buffers", since Java arrays are not suitable for use with OpenGL. * This is an unfortunate necessity, as it complicates the API. Fortunately, * we can simply wrap the arrays into buffers. */ // For glDrawElements, to draw the cube faces. private FloatBuffer vertexCoordBuffer = Buffers.newDirectFloatBuffer(vertexCoords); private FloatBuffer vertexColorBuffer = Buffers.newDirectFloatBuffer(vertexColors); private IntBuffer elementBuffer = Buffers.newDirectIntBuffer(elementArray); // For glDrawElements, to draw the cube edges. private IntBuffer edgeElementBuffer = Buffers.newDirectIntBuffer(edgeElementArray); // For glDrawArrays, to draw the second cube. private FloatBuffer cubeCoordBuffer = Buffers.newDirectFloatBuffer(cubeCoords); private FloatBuffer cubeFaceColorBuffer = Buffers.newDirectFloatBuffer(cubeFaceColors); //-------------------- GLEventListener Methods ------------------------- /** * The display method is called when the panel needs to be redrawn. * The is where the code goes for drawing the image, using OpenGL commands. */ public void display(GLAutoDrawable drawable) { GL2 gl2 = drawable.getGL().getGL2(); // The object that contains all the OpenGL methods. gl2.glClear( GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT ); gl2.glLoadIdentity(); // Set up modelview transform, first cube. gl2.glTranslated(-2, 0, 0); // Move cube to left half of window. gl2.glRotated(rotateZ,0,0,1); // Apply rotations. gl2.glRotated(rotateY,0,1,0); gl2.glRotated(rotateX,1,0,0); gl2.glVertexPointer( 3, GL2.GL_FLOAT, 0, cubeCoordBuffer ); // Set data type and location, first cube. gl2.glColorPointer( 3,GL2. GL_FLOAT, 0, cubeFaceColorBuffer ); gl2.glEnableClientState( GL2.GL_VERTEX_ARRAY ); gl2.glEnableClientState( GL2.GL_COLOR_ARRAY ); gl2.glDrawArrays( GL2.GL_QUADS, 0, 24 ); // Draw the first cube! // Second cube, using glDrawElements. Also draw the cube edges, and enable polygon offset // while the faces of the cube are being drawn. gl2.glLoadIdentity(); // Set up modelview transform, first cube. gl2. glTranslated(2, 0, 0); // Move cube to right half of window. gl2.glRotated(rotateZ,0,0,1); // Apply rotations. gl2.glRotated(rotateY,0,1,0); gl2.glRotated(rotateX,1,0,0); gl2.glVertexPointer( 3, GL2.GL_FLOAT, 0, vertexCoordBuffer ); // Set data type and location, second cube. gl2.glColorPointer( 3, GL2.GL_FLOAT, 0, vertexColorBuffer ); gl2.glEnable(GL2.GL_POLYGON_OFFSET_FILL); gl2. glPolygonOffset(1,1); gl2.glDrawElements(GL2. GL_QUADS, 24, GL2.GL_UNSIGNED_INT, elementBuffer ); // Draw the second cube! gl2.glDisable(GL2.GL_POLYGON_OFFSET_FILL); gl2.glDisableClientState( GL2.GL_COLOR_ARRAY ); // Don't use color array for the edges. gl2.glColor3f(0,0,0); // The edges will be black. gl2.glLineWidth(2); gl2.glDrawElements( GL2.GL_LINES, 24, GL2.GL_UNSIGNED_INT, edgeElementBuffer ); // Draw the edges! } // end display() public void init(GLAutoDrawable drawable) { // called when the panel is created GL2 gl2 = drawable.getGL().getGL2(); gl2.glMatrixMode(GL2.GL_PROJECTION); gl2.glOrtho(-4, 4, -2, 2, -2, 2); // simple orthographic projection gl2.glMatrixMode(GL2.GL_MODELVIEW); gl2.glClearColor( 0.5F, 0.5F, 0.5F, 1 ); gl2.glEnable(GL2.GL_DEPTH_TEST); } public void dispose(GLAutoDrawable drawable) { // called when the panel is being disposed } public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { // called when user resizes the window } // ---------------- Methods from the KeyListener interface -------------- public void keyPressed(KeyEvent evt) { int key = evt.getKeyCode(); if ( key == KeyEvent.VK_LEFT ) rotateY -= 15; else if ( key == KeyEvent.VK_RIGHT ) rotateY += 15; else if ( key == KeyEvent.VK_DOWN) rotateX += 15; else if ( key == KeyEvent.VK_UP ) rotateX -= 15; else if ( key == KeyEvent.VK_PAGE_UP ) rotateZ += 15; else if ( key == KeyEvent.VK_PAGE_DOWN ) rotateZ -= 15; else if ( key == KeyEvent.VK_HOME ) rotateX = rotateY = rotateZ = 0; repaint(); } public void keyReleased(KeyEvent evt) { } public void keyTyped(KeyEvent evt) { } }