// 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.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.Locale; import java.util.Scanner; import javax.imageio.ImageIO; import com.jogamp.opengl.*; import com.jogamp.opengl.awt.GLCanvas; import com.jogamp.opengl.util.FPSAnimator; import com.jogamp.opengl.GL.*; import com.jogamp.opengl.GL2.*; 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); // assuming the following structure of input vertex data // struct Vertex { // float position[3]; // float color[4]; // float texCoord[2]; // float normal[3]; // }; int perVertexFloats = (3+4+2+3); float vertexData[] = loadVertexData("pushbike.vbo", perVertexFloats); vertNo = vertexData.length / perVertexFloats; FloatBuffer dataIn = Buffers.newDirectFloatBuffer(vertexData.length); 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, 1.0, 10.0); } public void display(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context gl.glClearColor(0.3f, 0.3f, 0.3f, 0.0f); gl.glClear(GL2.GL_COLOR_BUFFER_BIT | GL2.GL_DEPTH_BUFFER_BIT); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); // camera orbits in the z=1.5 plane // and looks at origin double rad = Math.PI / 180.0f * t; glu.gluLookAt(1.5*Math.cos(rad), 1.5*Math.sin(rad), 1.5f, // eye 0.0, 0.0, 0.0, // look at 0.0, 0.0, 1.0); // up // 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(); } private float[] loadVertexData(String filename, int perVertexFloats) { float[] floatArray = new float[0]; // read vertex data from file int vertSize = 0; try { InputStream is = new FileInputStream(new File(filename)); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line = br.readLine(); if (line != null) { vertSize = Integer.parseInt(line); floatArray = new float[vertSize]; } int i = 0; while ((line = br.readLine()) != null && i < floatArray.length) { floatArray[i] = Float.parseFloat(line); i++; } if (i != vertSize || (vertSize % perVertexFloats) != 0) { floatArray = new float[0]; } br.close(); } catch (FileNotFoundException e) { System.out.println("Can not find vbo data file " + filename); } catch (IOException e) { e.printStackTrace(); } return floatArray; } // 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 ObjToVboExample { public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { MyGui myGUI = new MyGui(); myGUI.createGUI(); } }); } }