// This code example is created for educational purpose // by Thorsten Thormaehlen (contact: www.thormae.de). // It is distributed without any warranty. import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.imageio.ImageIO; import com.jogamp.opengl.GL2; import com.jogamp.opengl.GLAutoDrawable; import com.jogamp.opengl.GLCapabilities; import com.jogamp.opengl.GLEventListener; import com.jogamp.opengl.GLProfile; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.glu.GLU; import javax.swing.JFrame; import com.jogamp.common.nio.Buffers; import com.jogamp.opengl.util.FPSAnimator; class Renderer { private GLU glu = new GLU(); public float t = 0.0f; public int mode = 0; private int[] vertBufID = new int[1]; private int texID = 0; private int vertNo = 0; public void init(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL graphics context gl.glEnable(GL2.GL_DEPTH_TEST); float vertexData[] = { 0.0f, 0.0f, 2.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.0000f,-0.9701f, 0.2425f, -0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f, 0.5f,-0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0000f,-0.9701f, 0.2425f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f, 0.9701f, 0.0000f, 0.2425f, 0.5f,-0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.9701f, 0.0000f, 0.2425f, 0.0f, 0.0f, 2.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.5f, 1.0f, 0.0000f, 0.9701f, 0.2425f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0000f, 0.9701f, 0.2425f, 0.0f, 0.0f, 2.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.5f, 1.0f,-0.9701f, 0.0000f, 0.2425f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f, -0.5f,-0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f,-0.9701f, 0.0000f, 0.2425f }; vertNo = 12; // assuming the following structure of input vertex data // struct Vertex { // float position[3]; // float color[4]; // float texCoord[2]; // float normal[3]; // }; int floatItems = vertNo * (3+4+2+3); FloatBuffer dataIn = Buffers.newDirectFloatBuffer(floatItems); dataIn.put(vertexData); dataIn.flip(); // generating vertex VBO gl.glGenBuffers(1, vertBufID, 0); gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertBufID[0]); gl.glBufferData(GL2.GL_ARRAY_BUFFER, dataIn.capacity()*Buffers.SIZEOF_FLOAT, dataIn, GL2.GL_STATIC_DRAW); texID = loadTexture(d, "checkerboard.png"); } public void resize(GLAutoDrawable d, int w, int h) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glViewport(0, 0, w, h); gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); glu.gluPerspective (30.0, (float)w/(float)h, 2.0, 10.0); } public void display(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); // set camera glu.gluLookAt(3.0, -1.0, 4.5, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0); // draw scene gl.glRotatef(t, 0.0f, 0.0f, 1.0f); // activating VBO gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertBufID[0]); int stride = (3+4+2+3)*Buffers.SIZEOF_FLOAT; int offset = 0; // position gl.glVertexPointer(3, GL2.GL_FLOAT, stride, offset); gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); // color offset = 0 + 3*Buffers.SIZEOF_FLOAT; gl.glColorPointer(4, GL2.GL_FLOAT, stride, offset); gl.glEnableClientState(GL2.GL_COLOR_ARRAY); // texture offset = 0 + (3+4)*Buffers.SIZEOF_FLOAT; gl.glTexCoordPointer(2, GL2.GL_FLOAT, stride, offset); gl.glEnableClientState(GL2.GL_TEXTURE_COORD_ARRAY); // normals offset = 0 + (3+4+2)*Buffers.SIZEOF_FLOAT; gl.glNormalPointer(GL2.GL_FLOAT, stride, offset); gl.glEnableClientState(GL2.GL_NORMAL_ARRAY); // bind texture if(mode == 0) { gl.glEnable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, texID); }else{ gl.glDisable(GL2.GL_TEXTURE_2D); gl.glBindTexture(GL2.GL_TEXTURE_2D, 0); } // render data gl.glDrawArrays(GL2.GL_TRIANGLES, 0, vertNo); gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); gl.glDisableClientState(GL2.GL_COLOR_ARRAY); gl.glDisableClientState(GL2.GL_TEXTURE_COORD_ARRAY); gl.glDisableClientState(GL2.GL_NORMAL_ARRAY); gl.glDisable(GL2.GL_TEXTURE_2D); gl.glFlush(); } // returns a valid textureID on success, otherwise 0 private int loadTexture(GLAutoDrawable d, String filename) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context int width; int height; int level = 0; int border = 0; try{ // open file FileInputStream fileInputStream = new FileInputStream(new File(filename)); // read image BufferedImage bufferedImage = ImageIO.read(fileInputStream); fileInputStream.close(); width = bufferedImage.getWidth(); height = bufferedImage.getHeight(); // convert image to ByteBuffer int[] pixelIntData = new int[width * height]; bufferedImage.getRGB(0, 0, width, height, pixelIntData, 0, width); ByteBuffer buffer = ByteBuffer.allocateDirect(pixelIntData.length * 4); buffer.order(ByteOrder.nativeOrder()); // Unpack the data, each integer into 4 bytes of the ByteBuffer. // Also we need to vertically flip the image because the image origin // in OpenGL is the lower-left corner. for(int y=0; y < height; y++) { int k = (height-1-y) * width; for(int x=0; x < width; x++) { buffer.put((byte)(pixelIntData[k]>>> 16)); buffer.put((byte)(pixelIntData[k]>>> 8)); buffer.put((byte)(pixelIntData[k])); buffer.put((byte)(pixelIntData[k]>>> 24)); k++; } } buffer.rewind(); // data is aligned in byte order gl.glPixelStorei(GL2.GL_UNPACK_ALIGNMENT, 1); //request textureID final int[] textureID = new int[1]; gl.glGenTextures( 1, textureID, 0); // bind texture gl.glBindTexture(GL2.GL_TEXTURE_2D, textureID[0]); //define how to filter the texture (important but ignore for now) gl.glTexParameteri (GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); gl.glTexParameteri (GL2.GL_TEXTURE_2D, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); //texture colors should modulate the original color values gl.glTexEnvf(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE); // specify the 2D texture map gl.glTexImage2D(GL2.GL_TEXTURE_2D, level, GL2.GL_RGB, width, height, border, GL2.GL_RGBA, GL2.GL_UNSIGNED_BYTE, buffer); return textureID[0]; } catch( FileNotFoundException e) { System.out.println("Can not find texture data file " + filename); } catch(IOException e) { e.printStackTrace( ); } return 0; } } class MyGui extends JFrame implements GLEventListener { private Renderer renderer; public void createGUI() { setTitle("Interleaved Data VBO Demo"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); GLProfile glp = GLProfile.getDefault(); GLCapabilities caps = new GLCapabilities(glp); GLCanvas canvas = new GLCanvas(caps); setSize(320, 320); getContentPane().add(canvas); final FPSAnimator ani = new FPSAnimator(canvas, 60, true); canvas.addGLEventListener(this); setVisible(true); renderer = new Renderer(); canvas.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent event) { boolean redraw = false; switch(event.getKeyCode()) { case '1': if(renderer.mode == 1) renderer.mode = 0; else renderer.mode = 1; redraw = true; break; } if(redraw) { // done automatically } } }); ani.start(); } @Override public void init(GLAutoDrawable d) { renderer.init(d); } @Override public void reshape(GLAutoDrawable d, int x, int y, int width, int height) { renderer.resize(d, width, height); } @Override public void display(GLAutoDrawable d) { float offset = 1.0f; renderer.t += offset; renderer.display(d); } @Override public void dispose(GLAutoDrawable d) { } } public class VboStride { public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { MyGui myGUI = new MyGui(); myGUI.createGUI(); } }); } }