/******************************************************************************* * Breakout Cave Survey Visualizer * * Copyright (C) 2014 James Edwards * * jedwards8 at fastmail dot fm * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any later * version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *******************************************************************************/ package org.andork.jogl.util; import static org.andork.jogl.util.JoglUtils.checkGLError; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.CharBuffer; import java.nio.FloatBuffer; import com.jogamp.opengl.GL; import com.jogamp.opengl.GL2ES2; public class IndexedPackedCube { static float verts[] = { // top (red) 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, -1, 0, 1, 0, 1, 0, 0, 1, -1, 1, 1, 0, 1, 0, 1, 0, 0, 1, -1, 1, -1, 0, 1, 0, 1, 0, 0, 1, // bottom (green) 1, -1, 1, 0, -1, 0, 0, 1, 0, 1, -1, -1, 1, 0, -1, 0, 0, 1, 0, 1, 1, -1, -1, 0, -1, 0, 0, 1, 0, 1, -1, -1, -1, 0, -1, 0, 0, 1, 0, 1, // front (blue) 1, -1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, -1, -1, 1, 0, 0, 1, 0, 0, 1, 1, -1, 1, 1, 0, 0, 1, 0, 0, 1, 1, // back (yellow) 1, -1, -1, 0, 0, -1, 1, 1, 0, 1, -1, -1, -1, 0, 0, -1, 1, 1, 0, 1, 1, 1, -1, 0, 0, -1, 1, 1, 0, 1, -1, 1, -1, 0, 0, -1, 1, 1, 0, 1, // left (cyan) -1, -1, -1, -1, 0, 0, 0, 1, 1, 1, -1, -1, 1, -1, 0, 0, 0, 1, 1, 1, -1, 1, -1, -1, 0, 0, 0, 1, 1, 1, -1, 1, 1, -1, 0, 0, 0, 1, 1, 1, // right (magenta) 1, 1, -1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, -1, -1, 1, 0, 0, 1, 0, 1, 1, 1, -1, 1, 1, 0, 0, 1, 0, 1, 1, }; static char indices[] = { 0, 1, 2, 3, 2, 1, 4, 5, 6, 7, 6, 5, 8, 9, 10, 11, 10, 9, 12, 13, 14, 15, 14, 13, 16, 17, 18, 19, 18, 17, 20, 21, 22, 23, 22, 21 }; // number of coordinates per vertex in this array static final int COORDS_PER_VERTEX = 3; static final int NORMALS_PER_VERTEX = 3; static final int COLORS_PER_VERTEX = 4; static final int VALUES_PER_VERTEX = COORDS_PER_VERTEX + NORMALS_PER_VERTEX + COLORS_PER_VERTEX; static final int VERTEX_STRIDE = VALUES_PER_VERTEX * 4; static final int NORMAL_OFFSET = COORDS_PER_VERTEX; static final int COLOR_OFFSET = NORMAL_OFFSET + NORMALS_PER_VERTEX; static final int VERTEX_COUNT = verts.length / VALUES_PER_VERTEX; private final String vertexShaderCode = // This matrix member variable provides a hook to manipulate // the coordinates of the objects that use this vertex shader "uniform mat4 uMVMatrix;" + "uniform mat4 uPMatrix;" + "attribute vec4 vPosition;" + "attribute vec3 vNormal;" + "attribute vec4 vColor;" + "varying vec3 v_fxpos;" + "varying vec3 v_fxlightpos;" + "varying vec3 v_fxnormal;" + "varying vec4 v_fcolor;" + "void main() {" + " v_fcolor = vColor;" + " v_fxpos = (uMVMatrix * vPosition).xyz;" + " v_fxlightpos = (uMVMatrix * vec4(1.1, 1.8, 3.5, 1.0)).xyz;" + " v_fxnormal = normalize((uMVMatrix * vec4(vNormal, 0)).xyz);" + " gl_Position = uPMatrix * uMVMatrix * vPosition;" + "}"; private final String fragmentShaderCode = "precision lowp float;" + "varying vec3 v_fxpos;" + "varying vec3 v_fxlightpos;" + "varying vec3 v_fxnormal;" + "varying vec4 v_fcolor;" + "void main() {" + " vec3 incident = v_fxpos - v_fxlightpos;" + " vec3 ref_light = reflect(normalize(incident), v_fxnormal);" + " float intensity = dot(ref_light, vec3(0.0, 0.0, 1.0)) * 25.0 / (dot(incident, incident) + dot(v_fxpos, v_fxpos));" + " if (dot(v_fxnormal, ref_light) <= 0.0)" + " intensity = 0.0;" + " vec4 color2 = v_fcolor * clamp(intensity, 0.2, 1.0);" + " gl_FragColor = color2;" + "}"; private FloatBuffer vertexBuffer; CharBuffer indexBuffer; private int mProgram; private int mPositionHandle; private int mNormalHandle; private int mMVMatrixHandle; private int mPMatrixHandle; private int mColorHandle; private int vbo; private int ebo; public IndexedPackedCube() { } public void draw(GL2ES2 gl, float[] mvMatrix, float[] pMatrix) { // Add program to OpenGL ES environment gl.glUseProgram(mProgram); checkGLError(gl, "glUseProgram"); mMVMatrixHandle = gl.glGetUniformLocation(mProgram, "uMVMatrix"); checkGLError(gl, "glGetUniformLocation"); gl.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvMatrix, 0); checkGLError(gl, "glUniformMatrix4fv"); mPMatrixHandle = gl.glGetUniformLocation(mProgram, "uPMatrix"); checkGLError(gl, "glGetUniformLocation"); gl.glUniformMatrix4fv(mPMatrixHandle, 1, false, pMatrix, 0); checkGLError(gl, "glUniformMatrix4fv"); gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ebo); checkGLError(gl, "glBindBuffer"); gl.glDrawElements(GL.GL_TRIANGLES, indices.length, GL.GL_UNSIGNED_SHORT, 0); checkGLError(gl, "glDrawArrays"); gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0); checkGLError(gl, "glBindBuffer"); } public void init(GL2ES2 gl) { int vertexShader = JoglUtils.loadShader(gl, GL2ES2.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = JoglUtils.loadShader(gl, GL2ES2.GL_FRAGMENT_SHADER, fragmentShaderCode); mProgram = gl.glCreateProgram(); // create empty OpenGL ES Program checkGLError(gl, "glCreateProgram"); gl.glAttachShader(mProgram, vertexShader); // add the vertex shader checkGLError(gl, "glAttachShader"); // to program gl.glAttachShader(mProgram, fragmentShader); // add the fragment checkGLError(gl, "glAttachShader"); // shader to program gl.glLinkProgram(mProgram); // creates OpenGL ES program executables checkGLError(gl, "glLinkProgram"); // initialize vertex byte buffer for shape coordinates ByteBuffer bb = ByteBuffer.allocateDirect( // (number of coordinate values * 4 bytes per float) verts.length * 4); // use the device hardware's native byte order bb.order(ByteOrder.nativeOrder()); // create a floating point buffer from the ByteBuffer vertexBuffer = bb.asFloatBuffer(); // add the coordinates to the FloatBuffer vertexBuffer.put(verts); // set the buffer to read the first coordinate vertexBuffer.position(0); bb = ByteBuffer.allocateDirect(indices.length * 2); bb.order(ByteOrder.nativeOrder()); indexBuffer = bb.asCharBuffer(); indexBuffer.put(indices); indexBuffer.position(0); int[] vbos = new int[1]; gl.glGenBuffers(1, vbos, 0); vbo = vbos[0]; int[] ebos = new int[1]; gl.glGenBuffers(1, ebos, 0); ebo = ebos[0]; gl.glBindBuffer(GL.GL_ARRAY_BUFFER, vbo); checkGLError(gl, "glBindBuffer"); gl.glBufferData(GL.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GL.GL_STATIC_DRAW); checkGLError(gl, "glBufferData"); // get handle to vertex shader's vPosition member mPositionHandle = gl.glGetAttribLocation(mProgram, "vPosition"); checkGLError(gl, "glGetAttribLocation"); // Enable a handle to the triangle vertices gl.glEnableVertexAttribArray(mPositionHandle); checkGLError(gl, "glEnableVertexAttribArray"); vertexBuffer.position(0); // Prepare the triangle coordinate data gl.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GL.GL_FLOAT, false, VERTEX_STRIDE, 0); checkGLError(gl, "glVertexAttribPointer"); // get handle to fragment shader's vColor member mColorHandle = gl.glGetAttribLocation(mProgram, "vColor"); checkGLError(gl, "glGetAttribLocation"); // Enable a handle to the triangle vertices gl.glEnableVertexAttribArray(mColorHandle); checkGLError(gl, "glEnableVertexAttribArray"); vertexBuffer.position(COLOR_OFFSET); // Prepare the triangle coordinate data gl.glVertexAttribPointer(mColorHandle, COLORS_PER_VERTEX, GL.GL_FLOAT, false, VERTEX_STRIDE, COLOR_OFFSET * 4); checkGLError(gl, "glVertexAttribPointer"); // get handle to fragment shader's vNormal member mNormalHandle = gl.glGetAttribLocation(mProgram, "vNormal"); checkGLError(gl, "glGetAttribLocation"); // Enable a handle to the triangle vertices gl.glEnableVertexAttribArray(mNormalHandle); checkGLError(gl, "glEnableVertexAttribArray"); vertexBuffer.position(NORMAL_OFFSET); // Prepare the triangle coordinate data gl.glVertexAttribPointer(mNormalHandle, NORMALS_PER_VERTEX, GL.GL_FLOAT, false, VERTEX_STRIDE, NORMAL_OFFSET * 4); checkGLError(gl, "glVertexAttribPointer"); gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, ebo); checkGLError(gl, "glBindBuffer"); gl.glBufferData(GL.GL_ELEMENT_ARRAY_BUFFER, indexBuffer.capacity() * 2, indexBuffer, GL.GL_STATIC_DRAW); checkGLError(gl, "glBufferData"); gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); checkGLError(gl, "glBindBuffer"); gl.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, 0); checkGLError(gl, "glBindBuffer"); } }