2 * Copyright 2012 JogAmp Community. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without modification, are
5 * permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 * The views and conclusions contained in the software and documentation are those of the
25 * authors and should not be interpreted as representing official policies, either expressed
26 * or implied, of JogAmp Community.
31 import javax.media.opengl.GL;
32 import javax.media.opengl.GL2ES2;
33 import javax.media.opengl.GLAutoDrawable;
34 import javax.media.opengl.GLEventListener;
35 import javax.media.opengl.GLProfile;
36 import javax.media.opengl.GLCapabilities;
37 import com.jogamp.newt.opengl.GLWindow;
39 import com.jogamp.opengl.util.*;
40 import com.jogamp.common.nio.Buffers;
42 import java.nio.FloatBuffer;
46 * __ __|_ ___________________________________________________________________________ ___|__ __
48 * //____/ \__ __ _____ _____ _____ _____ _____ | | __ _____ _____ __ __/ \____\\
49 * \ \ / / __| | | __| _ | | _ | | | __| | | __| | /\ \ / /
50 * \____\/_/ | | | | | | | | | | | __| | | | | | | | | | |__ " \_\/____/
51 * /\ \ |_____|_____|_____|__|__|_|_|_|__| | | |_____|_____|_____|_____| _ / /\
52 * / \____\ http://jogamp.org |_| /____/ \
53 * \ / "' _________________________________________________________________________ `" \ /
58 * JOGL2 OpenGL ES 2 demo to expose and learn what the RAW OpenGL ES 2 API looks like.
60 * Compile, run and enjoy:
61 wget http://jogamp.org/deployment/jogamp-current/archive/jogamp-all-platforms.7z
62 7z x jogamp-all-platforms.7z
63 cd jogamp-all-platforms
66 wget https://raw.github.com/xranby/jogl-demos/master/src/demos/es2/RawGL2ES2demo.java
68 javac -cp jar/jogl-all.jar:jar/gluegen-rt.jar demos/es2/RawGL2ES2demo.java
69 java -cp jar/jogl-all.jar:jar/gluegen-rt.jar:. demos.es2.RawGL2ES2demo
73 * @author Xerxes RÄnby (xranby)
76 public class RawGL2ES2demo implements GLEventListener{
78 /* Introducing the OpenGL ES 2 Vertex shader
80 * The main loop inside the vertex shader gets executed
81 * one time for each vertex.
83 * vertex -> * uniform data -> mat4 projection = ( 1, 0, 0, 0,
84 * (0,1,0) / \ 0, 1, 0, 0,
85 * / . \ <- origo (0,0,0) 0, 0, 1, 0,
87 * vertex -> *-------* <- vertex
88 * (-1,-1,0) (1,-1,0) <- attribute data can be used
89 * (0, 0,1) for color, position, normals etc.
91 * The vertex shader recive input data in form of
92 * "uniform" data that are common to all vertex
94 * "attribute" data that are individual to each vertex.
95 * One vertex can have several "attribute" data sources enabled.
97 * The vertex shader produce output used by the fragment shader.
98 * gl_Position are expected to get set to the final vertex position.
99 * You can also send additional user defined
100 * "varying" data to the fragment shader.
102 * Model Translate, Scale and Rotate are done here by matrix-multiplying a
103 * projection matrix against each vertex position.
105 * The whole vertex shader program are a String containing GLSL ES language
106 * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
107 * sent to the GPU driver for compilation.
109 static final String vertexShader =
110 // For GLSL 1 and 1.1 code i highly recomend to not include a
111 // GLSL ES language #version line, GLSL ES section 3.4
112 // Many GPU drivers refuse to compile the shader if #version is different from
113 // the drivers internal GLSL version.
115 "precision mediump float; \n" + // Precision Qualifiers
116 "precision mediump int; \n" + // GLSL ES section 4.5.2
119 "uniform mat4 uniform_Projection; \n" + // Incomming data used by
120 "attribute vec4 attribute_Position; \n" + // the vertex shader
121 "attribute vec4 attribute_Color; \n" + // uniform and attributes
123 "varying vec4 varying_Color; \n" + // Outgoing varying data
124 // sent to the fragment shader
125 "void main(void) \n" +
127 " varying_Color = attribute_Color; \n" +
128 " gl_Position = uniform_Projection * attribute_Position; \n" +
131 /* Introducing the OpenGL ES 2 Fragment shader
133 * The main loop of the fragment shader gets executed for each visible
134 * pixel fragment on the render buffer.
138 * /ffF\ <- This fragment F gl_FragCoord get interpolated
139 * /fffff\ to (0.25,0.25,-1) based on the
140 * vertex-> *fffffff* <-vertex three vertex gl_Position.
141 * (-1,-1,-1) (1,-1,-1)
144 * All incomming "varying" and gl_FragCoord data to the fragment shader
145 * gets interpolated based on the vertex positions.
147 * The fragment shader produce and store the final color data output into
150 * Is up to you to set the final colors and calculate lightning here based on
151 * supplied position, color and normal data.
153 * The whole fragment shader program are a String containing GLSL ES language
154 * http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
155 * sent to the GPU driver for compilation.
157 static final String fragmentShader =
159 "precision mediump float; \n" +
160 "precision mediump int; \n" +
163 "varying vec4 varying_Color; \n" + //incomming varying data to the
165 //sent from the vertex shader
166 "void main (void) \n" +
168 " gl_FragColor = varying_Color; \n" +
171 /* Introducing projection matrix helper functions
173 * OpenGL ES 2 vertex projection transformations gets applied inside the
174 * vertex shader, all you have to do are to calculate and supply a projection matrix.
176 * Its recomended to use the com/jogamp/opengl/util/PMVMatrix.java
177 * import com.jogamp.opengl.util.PMVMatrix;
178 * To simplify all your projection model view matrix creation needs.
180 * These helpers here are based on PMVMatrix code and common linear
181 * algebra for matrix multiplication, translate and rotations.
183 private void glMultMatrixf(FloatBuffer a, FloatBuffer b, FloatBuffer d) {
184 final int aP = a.position();
185 final int bP = b.position();
186 final int dP = d.position();
187 for (int i = 0; i < 4; i++) {
188 final float ai0=a.get(aP+i+0*4), ai1=a.get(aP+i+1*4), ai2=a.get(aP+i+2*4), ai3=a.get(aP+i+3*4);
189 d.put(dP+i+0*4 , ai0 * b.get(bP+0+0*4) + ai1 * b.get(bP+1+0*4) + ai2 * b.get(bP+2+0*4) + ai3 * b.get(bP+3+0*4) );
190 d.put(dP+i+1*4 , ai0 * b.get(bP+0+1*4) + ai1 * b.get(bP+1+1*4) + ai2 * b.get(bP+2+1*4) + ai3 * b.get(bP+3+1*4) );
191 d.put(dP+i+2*4 , ai0 * b.get(bP+0+2*4) + ai1 * b.get(bP+1+2*4) + ai2 * b.get(bP+2+2*4) + ai3 * b.get(bP+3+2*4) );
192 d.put(dP+i+3*4 , ai0 * b.get(bP+0+3*4) + ai1 * b.get(bP+1+3*4) + ai2 * b.get(bP+2+3*4) + ai3 * b.get(bP+3+3*4) );
196 private float[] multiply(float[] a,float[] b){
197 float[] tmp = new float[16];
198 glMultMatrixf(FloatBuffer.wrap(a),FloatBuffer.wrap(b),FloatBuffer.wrap(tmp));
202 private float[] translate(float[] m,float x,float y,float z){
203 float[] t = { 1.0f, 0.0f, 0.0f, 0.0f,
204 0.0f, 1.0f, 0.0f, 0.0f,
205 0.0f, 0.0f, 1.0f, 0.0f,
207 return multiply(m, t);
210 private float[] rotate(float[] m,float a,float x,float y,float z){
212 s = (float)Math.sin(Math.toRadians(a));
213 c = (float)Math.cos(Math.toRadians(a));
215 x * x * (1.0f - c) + c, y * x * (1.0f - c) + z * s, x * z * (1.0f - c) - y * s, 0.0f,
216 x * y * (1.0f - c) - z * s, y * y * (1.0f - c) + c, y * z * (1.0f - c) + x * s, 0.0f,
217 x * z * (1.0f - c) + y * s, y * z * (1.0f - c) - x * s, z * z * (1.0f - c) + c, 0.0f,
218 0.0f, 0.0f, 0.0f, 1.0f };
219 return multiply(m, r);
222 /* Introducing the GL2ES2 demo
224 * How to render a triangle using 424 lines of code using the RAW
226 * The Programmable pipeline in OpenGL ES 2 are both fast and flexible
227 * yet it do take some extra lines of code to setup.
230 private double t0 = System.currentTimeMillis();
231 private double theta;
234 private static int width=1920;
235 private static int height=1080;
237 private int shaderProgram;
238 private int vertShader;
239 private int fragShader;
240 private int ModelViewProjectionMatrix_location;
242 public static void main(String[] s){
244 /* This demo are based on the GL2ES2 GLProfile that allows hardware acceleration
245 * on both desktop OpenGL 2 and mobile OpenGL ES 2 devices.
246 * JogAmp JOGL will probe all the installed libGL.so, libEGL.so and libGLESv2.so librarys on
247 * the system to find which one provide hardware acceleration for your GPU device.
248 * Its common to find more than one version of these librarys installed on a system.
249 * For example on a ARM Linux system JOGL may find
250 * Hardware accelerated Nvidia tegra GPU drivers in: /usr/lib/nvidia-tegra/libEGL.so
251 * Software rendered Mesa Gallium driver in: /usr/lib/arm-linux-gnueabi/mesa-egl/libEGL.so.1
252 * Software rendered Mesa X11 in: /usr/lib/arm-linux-gnueabi/mesa/libGL.so
253 * Good news!: JOGL does all this probing for you all you have to do are to ask for
254 * the GLProfile you want to use.
257 GLCapabilities caps = new GLCapabilities(GLProfile.get(GLProfile.GL2ES2));
258 // We may at this point tweak the caps and request a translucent drawable
259 caps.setBackgroundOpaque(false);
260 GLWindow glWindow = GLWindow.create(caps);
262 /* You may combine the NEWT GLWindow inside existing Swing and AWT
263 * applications by encapsulating the glWindow inside a
264 * com.jogamp.newt.awt.NewtCanvasAWT canvas.
266 * NewtCanvasAWT newtCanvas = new NewtCanvasAWT(glWindow);
267 * JFrame frame = new JFrame("RAW GL2ES2 Demo inside a JFrame!");
268 * frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
269 * frame.setSize(width,height);
270 * frame.add(newtCanvas);
271 * // add some swing code if you like.
272 * // javax.swing.JButton b = new javax.swing.JButton();
273 * // b.setText("Hi");
275 * frame.setVisible(true);
278 // In this demo we prefer to setup and view the GLWindow directly
279 // this allows the demo to run on -Djava.awt.headless=true systems
280 glWindow.setTitle("Raw GL2ES2 Demo");
281 glWindow.setSize(width,height);
282 glWindow.setUndecorated(false);
283 glWindow.setPointerVisible(true);
284 glWindow.setVisible(true);
286 // Finally we connect the GLEventListener application code to the NEWT GLWindow.
287 // GLWindow will call the GLEventListener init, reshape, display and dispose
288 // functions when needed.
289 glWindow.addGLEventListener(new RawGL2ES2demo() /* GLEventListener */);
290 Animator animator = new Animator();
291 animator.add(glWindow);
295 public void init(GLAutoDrawable drawable) {
296 GL2ES2 gl = drawable.getGL().getGL2ES2();
298 System.err.println("Chosen GLCapabilities: " + drawable.getChosenGLCapabilities());
299 System.err.println("INIT GL IS: " + gl.getClass().getName());
300 System.err.println("GL_VENDOR: " + gl.glGetString(GL.GL_VENDOR));
301 System.err.println("GL_RENDERER: " + gl.glGetString(GL.GL_RENDERER));
302 System.err.println("GL_VERSION: " + gl.glGetString(GL.GL_VERSION));
305 //OpenGL ES retuns a index id to be stored for future reference.
306 vertShader = gl.glCreateShader(GL2ES2.GL_VERTEX_SHADER);
307 fragShader = gl.glCreateShader(GL2ES2.GL_FRAGMENT_SHADER);
309 //Compile the vertexShader String into a program.
310 String[] vlines = new String[] { vertexShader };
311 int[] vlengths = new int[] { vlines[0].length() };
312 gl.glShaderSource(vertShader, vlines.length, vlines, vlengths, 0);
313 gl.glCompileShader(vertShader);
315 //Check compile status.
316 int[] compiled = new int[1];
317 gl.glGetShaderiv(vertShader, GL2ES2.GL_COMPILE_STATUS, compiled,0);
318 if(compiled[0]!=0){System.out.println("Horray! vertex shader compiled");}
320 int[] logLength = new int[1];
321 gl.glGetShaderiv(vertShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
323 byte[] log = new byte[logLength[0]];
324 gl.glGetShaderInfoLog(vertShader, logLength[0], (int[])null, 0, log, 0);
326 System.err.println("Error compiling the vertex shader: " + new String(log));
330 //Compile the fragmentShader String into a program.
331 String[] flines = new String[] { fragmentShader };
332 int[] flengths = new int[] { flines[0].length() };
333 gl.glShaderSource(fragShader, flines.length, flines, flengths, 0);
334 gl.glCompileShader(fragShader);
336 //Check compile status.
337 gl.glGetShaderiv(fragShader, GL2ES2.GL_COMPILE_STATUS, compiled,0);
338 if(compiled[0]!=0){System.out.println("Horray! fragment shader compiled");}
340 int[] logLength = new int[1];
341 gl.glGetShaderiv(fragShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
343 byte[] log = new byte[logLength[0]];
344 gl.glGetShaderInfoLog(fragShader, logLength[0], (int[])null, 0, log, 0);
346 System.err.println("Error compiling the fragment shader: " + new String(log));
350 //Each shaderProgram must have
351 //one vertex shader and one fragment shader.
352 shaderProgram = gl.glCreateProgram();
353 gl.glAttachShader(shaderProgram, vertShader);
354 gl.glAttachShader(shaderProgram, fragShader);
356 //Associate attribute ids with the attribute names inside
358 gl.glBindAttribLocation(shaderProgram, 0, "attribute_Position");
359 gl.glBindAttribLocation(shaderProgram, 1, "attribute_Color");
361 gl.glLinkProgram(shaderProgram);
363 //Get a id number to the uniform_Projection matrix
364 //so that we can update it.
365 ModelViewProjectionMatrix_location = gl.glGetUniformLocation(shaderProgram, "uniform_Projection");
368 public void reshape(GLAutoDrawable drawable, int x, int y, int z, int h) {
369 System.out.println("Window resized to width=" + z + " height=" + h);
374 GL2ES2 gl = drawable.getGL().getGL2ES2();
376 // Optional: Set viewport
377 // Render to a square at the center of the window.
378 gl.glViewport((width-height)/2,0,height,height);
381 public void display(GLAutoDrawable drawable) {
382 // Update variables used in animation
383 double t1 = System.currentTimeMillis();
384 theta += (t1-t0)*0.005f;
389 GL2ES2 gl = drawable.getGL().getGL2ES2();
392 gl.glClearColor(1, 0, 1, 0.5f); // Purple
393 gl.glClear(GL2ES2.GL_STENCIL_BUFFER_BIT |
394 GL2ES2.GL_COLOR_BUFFER_BIT |
395 GL2ES2.GL_DEPTH_BUFFER_BIT );
397 // Use the shaderProgram that got linked during the init part.
398 gl.glUseProgram(shaderProgram);
400 /* Change a projection matrix
401 * The matrix multiplications and OpenGL ES2 code below
402 * basically match this OpenGL ES1 code.
403 * note that the model_view_projection matrix gets sent to the vertexShader.
405 * gl.glLoadIdentity();
406 * gl.glTranslatef(0.0f,0.0f,-0.1f);
407 * gl.glRotatef((float)30f*(float)s,1.0f,0.0f,1.0f);
411 float[] model_view_projection;
412 float[] identity_matrix = {
413 1.0f, 0.0f, 0.0f, 0.0f,
414 0.0f, 1.0f, 0.0f, 0.0f,
415 0.0f, 0.0f, 1.0f, 0.0f,
416 0.0f, 0.0f, 0.0f, 1.0f,
418 model_view_projection = translate(identity_matrix,0.0f,0.0f, -0.1f);
419 model_view_projection = rotate(model_view_projection,(float)30f*(float)s,1.0f,0.0f,1.0f);
421 // Send the final projection matrix to the vertex shader by
422 // using the uniform location id obtained during the init part.
423 gl.glUniformMatrix4fv(ModelViewProjectionMatrix_location, 1, false, model_view_projection, 0);
427 * The OpenGL ES2 code below basically match this OpenGL code.
429 * gl.glBegin(GL_TRIANGLES); // Drawing Using Triangles
430 * gl.glVertex3f( 0.0f, 1.0f, 0.0f); // Top
431 * gl.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
432 * gl.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
433 * gl.glEnd(); // Finished Drawing The Triangle
436 float[] vertices = { 0.0f, 1.0f, 0.0f, //Top
437 -1.0f, -1.0f, 0.0f, //Bottom Left
438 1.0f, -1.0f, 0.0f //Bottom Right
442 // Observe that the vertex data passed to glVertexAttribPointer must stay valid
443 // through the OpenGL rendering lifecycle.
444 // Therefore it is mandatory to allocate a NIO Direct buffer that stays pinned in memory
445 // and thus can not get moved by the java garbage collector.
446 // Also we need to keep a reference to the NIO Direct buffer around up untill
447 // we call glDisableVertexAttribArray first then will it be safe to garbage collect the memory.
448 // I will here use the com.jogamp.common.nio.Buffers to quicly wrap the array in a Direct NIO buffer.
449 FloatBuffer fbVertices = Buffers.newDirectFloatBuffer(vertices);
451 gl.glVertexAttribPointer(0, 3, GL2ES2.GL_FLOAT, false, 0, fbVertices);
452 gl.glEnableVertexAttribArray(0);
454 float[] colors = { 1.0f, 0.0f, 0.0f, 1.0f, //Top color (red)
455 0.0f, 0.0f, 0.0f, 1.0f, //Bottom Left color (black)
456 1.0f, 1.0f, 0.0f, 0.9f //Bottom Right color (yellow) with 10% transparence
459 FloatBuffer fbColors = Buffers.newDirectFloatBuffer(colors);
461 gl.glVertexAttribPointer(1, 4, GL2ES2.GL_FLOAT, false, 0, fbColors);
462 gl.glEnableVertexAttribArray(1);
464 gl.glDrawArrays(GL2ES2.GL_TRIANGLES, 0, 3); //Draw the vertices as triangle
466 gl.glDisableVertexAttribArray(0); // Allow release of vertex position memory
467 gl.glDisableVertexAttribArray(1); // Allow release of vertex color memory
468 // It is only safe to let the garbage collector collect the vertices and colors
469 // NIO buffers data after first calling glDisableVertexAttribArray.
474 public void dispose(GLAutoDrawable drawable){
475 System.out.println("cleanup, remember to release shaders");
476 GL2ES2 gl = drawable.getGL().getGL2ES2();
478 gl.glDetachShader(shaderProgram, vertShader);
479 gl.glDeleteShader(vertShader);
480 gl.glDetachShader(shaderProgram, fragShader);
481 gl.glDeleteShader(fragShader);
482 gl.glDeleteProgram(shaderProgram);