Jogamp
Adapt to JOGL changes commit fd418a69eca7b8c1bb74244982305fc6004d0a52
[jogl-demos.git] / src / demos / es2 / RawGL2ES2demo.java
1 /**
2  * Copyright 2012 JogAmp Community. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice, this list of
8  *       conditions and the following disclaimer.
9  *
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.
13  *
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.
23  *
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.
27  */
28
29 package demos.es2;
30
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;
38
39 import com.jogamp.opengl.util.*;
40 import com.jogamp.common.nio.Buffers;
41
42 import java.nio.FloatBuffer;
43
44 /**
45  * <pre>
46  *   __ __|_  ___________________________________________________________________________  ___|__ __
47  *  //    /\                                           _                                  /\    \\
48  * //____/  \__     __ _____ _____ _____ _____ _____  | |     __ _____ _____ __        __/  \____\\
49  *  \    \  / /  __|  |     |   __|  _  |     |  _  | | |  __|  |     |   __|  |      /\ \  /    /
50  *   \____\/_/  |  |  |  |  |  |  |     | | | |   __| | | |  |  |  |  |  |  |  |__   "  \_\/____/
51  *  /\    \     |_____|_____|_____|__|__|_|_|_|__|    | | |_____|_____|_____|_____|  _  /    /\
52  * /  \____\                       http://jogamp.org  |_|                              /____/  \
53  * \  /   "' _________________________________________________________________________ `"   \  /
54  *  \/____.                                                                             .____\/
55  * </pre>
56  *
57  * <p>
58  * JOGL2 OpenGL ES 2 demo to expose and learn what the RAW OpenGL ES 2 API looks like.
59  *
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
64    mkdir -p demos/es2
65    cd demos/es2
66    wget https://raw.github.com/xranby/jogl-demos/master/src/demos/es2/RawGL2ES2demo.java
67    cd ../..
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
70  * </p>
71  *
72  *
73  * @author Xerxes RĂ„nby (xranby)
74  */
75
76 public class RawGL2ES2demo implements GLEventListener{
77
78 /* Introducing the OpenGL ES 2 Vertex shader
79  *
80  * The main loop inside the vertex shader gets executed
81  * one time for each vertex.
82  *
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,
86  *             /     \                                        0, 0,-1, 1 );
87  *  vertex -> *-------* <- vertex
88  *  (-1,-1,0)             (1,-1,0) <- attribute data can be used
89  *                        (0, 0,1)    for color, position, normals etc.
90  *
91  * The vertex shader recive input data in form of
92  * "uniform" data that are common to all vertex
93  * and
94  * "attribute" data that are individual to each vertex.
95  * One vertex can have several "attribute" data sources enabled.
96  *
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.
101  *
102  * Model Translate, Scale and Rotate are done here by matrix-multiplying a
103  * projection matrix against each vertex position.
104  *
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.
108  */
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.
114 "#ifdef GL_ES \n" +
115 "precision mediump float; \n" + // Precision Qualifiers
116 "precision mediump int; \n" +   // GLSL ES section 4.5.2
117 "#endif \n" +
118
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
122
123 "varying vec4    varying_Color; \n" + // Outgoing varying data
124                                       // sent to the fragment shader
125 "void main(void) \n" +
126 "{ \n" +
127 "  varying_Color = attribute_Color; \n" +
128 "  gl_Position = uniform_Projection * attribute_Position; \n" +
129 "} ";
130
131 /* Introducing the OpenGL ES 2 Fragment shader
132  *
133  * The main loop of the fragment shader gets executed for each visible
134  * pixel fragment on the render buffer.
135  *
136  *       vertex-> *
137  *      (0,1,-1) /f\
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)
142  *
143  *
144  * All incomming "varying" and gl_FragCoord data to the fragment shader
145  * gets interpolated based on the vertex positions.
146  *
147  * The fragment shader produce and store the final color data output into
148  * gl_FragColor.
149  *
150  * Is up to you to set the final colors and calculate lightning here based on
151  * supplied position, color and normal data.
152  *
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.
156  */
157 static final String fragmentShader =
158 "#ifdef GL_ES \n" +
159 "precision mediump float; \n" +
160 "precision mediump int; \n" +
161 "#endif \n" +
162
163 "varying   vec4    varying_Color; \n" + //incomming varying data to the
164                                         //frament shader
165                                         //sent from the vertex shader
166 "void main (void) \n" +
167 "{ \n" +
168 "  gl_FragColor = varying_Color; \n" +
169 "} ";
170
171 /* Introducing projection matrix helper functions
172  *
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.
175  *
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.
179  *
180  * These helpers here are based on PMVMatrix code and common linear
181  * algebra for matrix multiplication, translate and rotations.
182  */
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) );
193         }
194     }
195
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));
199         return tmp;
200     }
201
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,
206                       x, y, z, 1.0f };
207         return multiply(m, t);
208     }
209
210     private float[] rotate(float[] m,float a,float x,float y,float z){
211         float s, c;
212         s = (float)Math.sin(Math.toRadians(a));
213         c = (float)Math.cos(Math.toRadians(a));
214         float[] r = {
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);
220         }
221
222 /* Introducing the GL2ES2 demo
223  *
224  * How to render a triangle using 424 lines of code using the RAW
225  * OpenGL ES 2 API.
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.
228  *
229  */
230     private double t0 = System.currentTimeMillis();
231     private double theta;
232     private double s;
233     
234     private static int width=1920;
235     private static int height=1080;
236
237     private int shaderProgram;
238     private int vertShader;
239     private int fragShader;
240     private int ModelViewProjectionMatrix_location;
241
242     public static void main(String[] s){
243
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.
255          */
256
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);
261
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.
265          *
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");
274          *  // frame.add(b); 
275          *  frame.setVisible(true);
276          */
277
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);
285
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);
292         animator.start();
293     }
294
295     public void init(GLAutoDrawable drawable) {
296         GL2ES2 gl = drawable.getGL().getGL2ES2();
297
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));
303
304         //Create shaders
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);
308
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);
314
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");}
319         else {
320             int[] logLength = new int[1];
321             gl.glGetShaderiv(vertShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
322
323             byte[] log = new byte[logLength[0]];
324             gl.glGetShaderInfoLog(vertShader, logLength[0], (int[])null, 0, log, 0);
325
326             System.err.println("Error compiling the vertex shader: " + new String(log));
327             System.exit(1);
328         }
329
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);
335
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");}
339         else {
340             int[] logLength = new int[1];
341             gl.glGetShaderiv(fragShader, GL2ES2.GL_INFO_LOG_LENGTH, logLength, 0);
342
343             byte[] log = new byte[logLength[0]];
344             gl.glGetShaderInfoLog(fragShader, logLength[0], (int[])null, 0, log, 0);
345
346             System.err.println("Error compiling the fragment shader: " + new String(log));
347             System.exit(1);
348         }
349
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);
355
356         //Associate attribute ids with the attribute names inside
357         //the vertex shader.
358         gl.glBindAttribLocation(shaderProgram, 0, "attribute_Position");
359         gl.glBindAttribLocation(shaderProgram, 1, "attribute_Color");
360
361         gl.glLinkProgram(shaderProgram);
362
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");
366     }
367
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);
370         width = z;
371         height = h;
372
373         // Get gl
374         GL2ES2 gl = drawable.getGL().getGL2ES2();
375
376         // Optional: Set viewport
377         // Render to a square at the center of the window.
378         gl.glViewport((width-height)/2,0,height,height);
379     }
380
381     public void display(GLAutoDrawable drawable) {
382         // Update variables used in animation
383         double t1 = System.currentTimeMillis();
384         theta += (t1-t0)*0.005f;
385         t0 = t1;
386         s = Math.sin(theta);
387
388         // Get gl
389         GL2ES2 gl = drawable.getGL().getGL2ES2();
390
391         // Clear screen
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   );
396
397         // Use the shaderProgram that got linked during the init part.
398         gl.glUseProgram(shaderProgram);
399
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.
404          *
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);
408          *
409          */
410
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,
417         };
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);
420
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);
424
425         /*
426          *  Render a triangle:
427          *  The OpenGL ES2 code below basically match this OpenGL code.
428          *
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
434          */
435
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
439                                               };
440
441
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);
450
451         gl.glVertexAttribPointer(0, 3, GL2ES2.GL_FLOAT, false, 0, fbVertices);
452         gl.glEnableVertexAttribArray(0);
453
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
457                                                    };
458                                              
459         FloatBuffer fbColors = Buffers.newDirectFloatBuffer(colors);
460
461         gl.glVertexAttribPointer(1, 4, GL2ES2.GL_FLOAT, false, 0, fbColors);
462         gl.glEnableVertexAttribArray(1);
463
464         gl.glDrawArrays(GL2ES2.GL_TRIANGLES, 0, 3); //Draw the vertices as triangle
465         
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.
470         fbVertices = null;
471         fbColors = null;
472     }
473
474     public void dispose(GLAutoDrawable drawable){
475         System.out.println("cleanup, remember to release shaders");
476         GL2ES2 gl = drawable.getGL().getGL2ES2();
477         gl.glUseProgram(0);
478         gl.glDetachShader(shaderProgram, vertShader);
479         gl.glDeleteShader(vertShader);
480         gl.glDetachShader(shaderProgram, fragShader);
481         gl.glDeleteShader(fragShader);
482         gl.glDeleteProgram(shaderProgram);
483         System.exit(0);
484     }
485 }
http://JogAmp.org git info: FAQ, tutorial and man pages.