// 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.nio.FloatBuffer; import java.nio.IntBuffer; import java.util.Random; 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 = 1; public int ayimutSegs = 10; public int polarSegs = 10; public boolean recreateVBONotify = false; private int[] vertBufID = { 0 }; private int[] indicesBufID = { 0 }; private int vertSize = 0; public void init(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL graphics context gl.glEnable(GL2.GL_DEPTH_TEST); recreateVBOs(d); } private void recreateVBOs(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL graphics context if(vertBufID[0] !=0) gl.glDeleteBuffers( 1, vertBufID, 0); if(indicesBufID[0] !=0) gl.glDeleteBuffers( 1, indicesBufID, 0); // generating VBO input data int totalSegs = ayimutSegs * polarSegs; FloatBuffer vertexData = Buffers.newDirectFloatBuffer(totalSegs * 3); IntBuffer indicesData = Buffers.newDirectIntBuffer(totalSegs * 4); double ayimutStep = 2.0 * Math.PI / (double)ayimutSegs; double polarStep = Math.PI / (double)polarSegs; double r = 1.0; vertSize = 0; Random generator = new Random(); for(int m=0; m < ayimutSegs; m++) { for(int n=0; n < polarSegs; n++) { double phi = ayimutStep*m; double theta = polarStep * n; // random radius r = 1.0 - 0.3 * Math.abs(generator.nextDouble()); // compute xyz from spherical coordinates float x = (float) (r * Math.sin(theta) * Math.cos(phi)); float y = (float) (r * Math.sin(theta) * Math.sin(phi)); float z = (float) (r * Math.cos(theta)); vertexData.put(x); vertexData.put(y); vertexData.put(z); // create vertex indices indicesData.put(vertSize % totalSegs); indicesData.put((vertSize+ayimutSegs) % totalSegs); indicesData.put((vertSize+ayimutSegs + 1) % totalSegs); indicesData.put((vertSize+1) % totalSegs); vertSize++; } } vertexData.flip(); indicesData.flip(); // generating vertex VBO gl.glGenBuffers(1, vertBufID, 0); gl.glBindBuffer(GL2.GL_ARRAY_BUFFER, vertBufID[0]); gl.glBufferData(GL2.GL_ARRAY_BUFFER, vertexData.capacity()*Buffers.SIZEOF_FLOAT, vertexData, GL2.GL_STATIC_DRAW); // generating index VBO gl.glGenBuffers(1, indicesBufID, 0); gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indicesBufID[0]); gl.glBufferData(GL2.GL_ELEMENT_ARRAY_BUFFER, indicesData.capacity()*Buffers.SIZEOF_INT, indicesData, GL2.GL_STATIC_DRAW); recreateVBONotify = false; } 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, 0.1, 50.0); } public void display(GLAutoDrawable d) { GL2 gl = d.getGL().getGL2(); // get the OpenGL 2 graphics context if(recreateVBONotify) recreateVBOs(d); 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.5, -1.0, 3.5, 0.0, 0.0, 0.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 = 0; gl.glVertexPointer(3, GL2.GL_FLOAT, stride, 0); gl.glEnableClientState(GL2.GL_VERTEX_ARRAY); if(mode == 0) { gl.glColor3f(1.0f,1.0f,1.0f); }else{ gl.glColorPointer(3, GL2.GL_FLOAT, stride, 0); gl.glEnableClientState(GL2.GL_COLOR_ARRAY); } gl.glBindBuffer(GL2.GL_ELEMENT_ARRAY_BUFFER, indicesBufID[0]); gl.glDrawElements(GL2.GL_QUADS, vertSize*4, GL2.GL_UNSIGNED_INT, 0); gl.glDisableClientState(GL2.GL_VERTEX_ARRAY); gl.glDisableClientState(GL2.GL_COLOR_ARRAY); gl.glFlush(); } } class MyGui extends JFrame implements GLEventListener { private Renderer renderer; public void createGUI() { setTitle("Press 1 to change color, 2 to increase vertex count"); 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; case '2': if(renderer.ayimutSegs < 1000) { renderer.ayimutSegs *= 10; renderer.polarSegs *= 10; }else{ renderer.ayimutSegs = 10; renderer.polarSegs = 10; } renderer.recreateVBONotify = true; } 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 VboDrawElements { public static void main(String[] args) { javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { MyGui myGUI = new MyGui(); myGUI.createGUI(); } }); } }