/******************************************************************************* * 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.breakout.model; import static com.jogamp.opengl.GL.GL_ARRAY_BUFFER; import static com.jogamp.opengl.GL.GL_BLEND; import static com.jogamp.opengl.GL.GL_ELEMENT_ARRAY_BUFFER; import static com.jogamp.opengl.GL.GL_FLOAT; import static com.jogamp.opengl.GL.GL_ONE_MINUS_SRC_ALPHA; import static com.jogamp.opengl.GL.GL_SRC_ALPHA; import static com.jogamp.opengl.GL.GL_STATIC_DRAW; import static com.jogamp.opengl.GL.GL_TRIANGLES; import static com.jogamp.opengl.GL.GL_UNSIGNED_INT; import static org.andork.math3d.Vecmath.setf; import static org.andork.math3d.Vecmath.subDot3; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.IntBuffer; import java.util.Random; import org.andork.jogl.JoglDrawContext; import org.andork.jogl.JoglDrawable; import org.andork.jogl.JoglResource; import org.andork.jogl.util.JoglUtils; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.opengl.GL2ES2; import com.jogamp.opengl.GL3; public class TransparentTerrain implements JoglDrawable, JoglResource { public static void randomVerts(float[][][] vertices, float[] bounds, Random rand) { for (int row = 0; row < vertices.length; row++) { for (int col = 0; col < vertices[0].length; col++) { float[] v = vertices[row][col]; float r = (float) row / (vertices.length - 1); float c = (float) col / (vertices[0].length - 1); v[0] = bounds[0] + c * (bounds[3] - bounds[0]); v[1] = bounds[1] + (float) Math.sin((r + c) * 10) * (bounds[4] - bounds[1]); v[2] = bounds[2] + r * (bounds[5] - bounds[2]); } } } float[][][] vertices; int numVertexRows; int numVertexCols; int numCellRows; int numCellCols; float[][] corners = new float[4][3]; IntBuffer counts; IntBuffer indices; PointerBuffer indexPointers; boolean initialized; int program; int[] vbo = new int[1]; int[] ebo = new int[1]; float[] color = { 0f, 1f, 0f, 0.5f }; public TransparentTerrain(float[][][] vertices) { super(); this.vertices = vertices; numVertexRows = vertices.length; numVertexCols = vertices[0].length; numCellRows = numVertexRows - 1; numCellCols = numVertexCols - 1; setf(corners[0], vertices[0][0]); setf(corners[1], vertices[0][numCellCols]); setf(corners[2], vertices[numCellRows][0]); setf(corners[3], vertices[numCellRows][numCellCols]); } /** * @return {@code true} iff any of the terrain is in front of the camera. */ private boolean calcOrder(JoglDrawContext context) { float bestDist = -1f; int bestCorner = -1; float[] vi = context.inverseViewXform(); for (int i = 0; i < corners.length; i++) { float dist = subDot3(vi, 12, corners[i], 0, vi, 8); if (dist > bestDist) { bestDist = dist; bestCorner = i; } } if (bestDist < 0f) { return false; } int firstRow; int lastRow; int rowStep; int firstCol; int lastCol; int colStep; if (bestCorner < 2) { firstRow = 0; rowStep = numCellCols * 6; lastRow = rowStep * (numCellRows - 1); } else { rowStep = -numCellCols * 6; firstRow = -rowStep * (numCellRows - 1); lastRow = 0; } if ((bestCorner & 0x1) == 0) { firstCol = 0; colStep = 6; lastCol = (numCellCols - 1) * 6; } else { firstCol = (numCellCols - 1) * 6; colStep = -6; lastCol = 0; } indexPointers.position(0); for (int row = firstRow; row <= lastRow; row += rowStep) { for (int col = firstCol; col <= lastCol; col += colStep) { // indices.position( row + col ); indexPointers.put((row + col) * 4); } } indices.position(0); indexPointers.position(0); return true; } @Override public void dispose(GL2ES2 gl) { if (!initialized) { return; } initialized = false; gl.glDeleteProgram(program); gl.glDeleteBuffers(1, vbo, 0); gl.glDeleteBuffers(1, ebo, 0); } @Override public void draw(JoglDrawContext context, GL2ES2 gl, float[] m, float[] n) { if (!calcOrder(context)) { return; } gl.glUseProgram(program); gl.glEnable(GL_BLEND); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); int loc; loc = gl.glGetUniformLocation(program, "p"); gl.glUniformMatrix4fv(loc, 1, false, context.projXform(), 0); loc = gl.glGetUniformLocation(program, "v"); gl.glUniformMatrix4fv(loc, 1, false, context.viewXform(), 0); loc = gl.glGetUniformLocation(program, "m"); gl.glUniformMatrix4fv(loc, 1, false, m, 0); int posLoc = gl.glGetAttribLocation(program, "a_pos"); gl.glEnableVertexAttribArray(posLoc); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); gl.glVertexAttribPointer(posLoc, 4, GL_FLOAT, false, 16, 0); loc = gl.glGetUniformLocation(program, "u_color"); gl.glUniform4fv(loc, 1, color, 0); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]); // ( ( GL3 ) gl ).glMultiDrawArrays( GL_TRIANGLES , first , 0 , count , // 0 , first.length ); ((GL3) gl).glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPointers, numCellRows * numCellCols); // gl.glDrawElements( GL_TRIANGLES , numCellRows * numCellCols * 6 , // GL_UNSIGNED_INT , 0 ); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); gl.glBindBuffer(GL_ARRAY_BUFFER, 0); gl.glDisableVertexAttribArray(posLoc); gl.glDisable(GL_BLEND); gl.glUseProgram(0); } @Override public void init(GL2ES2 gl) { if (initialized) { return; } initialized = true; String vertexShader = "uniform mat4 p;" + "uniform mat4 v;" + "uniform mat4 m;" + "uniform mat3 n;" + "attribute vec4 a_pos;" + "void main() {" + " gl_Position = p * v * m * a_pos;" + "}"; String fragmentShader = "uniform vec4 u_color;" + "void main() {" + " gl_FragColor = u_color;" + "}"; program = JoglUtils.loadProgram(gl, vertexShader, fragmentShader); ByteBuffer b; b = ByteBuffer.allocateDirect(numVertexRows * numVertexCols * 16); b.order(ByteOrder.nativeOrder()); for (int row = 0; row < numVertexRows; row++) { for (int col = 0; col < numVertexCols; col++) { float[] v = vertices[row][col]; b.putFloat(v[0]); b.putFloat(v[1]); b.putFloat(v[2]); b.putFloat(1f); } } b.position(0); gl.glGenBuffers(1, vbo, 0); gl.glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); gl.glBufferData(GL_ARRAY_BUFFER, b.capacity(), b, GL_STATIC_DRAW); gl.glBindBuffer(GL_ARRAY_BUFFER, 0); b = ByteBuffer.allocateDirect(numCellRows * numCellCols * 24); b.order(ByteOrder.nativeOrder()); indices = b.asIntBuffer(); for (int row = 0; row < numCellRows; row++) { int rowStart = row * numVertexCols; int nextRowStart = rowStart + numVertexCols; for (int col = 0; col < numCellCols; col++) { indices.put(rowStart + col); indices.put(nextRowStart + col + 1); indices.put(nextRowStart + col); indices.put(nextRowStart + col + 1); indices.put(rowStart + col); indices.put(rowStart + col + 1); } } indices.position(0); gl.glGenBuffers(1, ebo, 0); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo[0]); gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.capacity() * 4, indices, GL_STATIC_DRAW); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); b = ByteBuffer.allocateDirect(numCellRows * numCellCols * 4); b.order(ByteOrder.nativeOrder()); counts = b.asIntBuffer(); while (counts.hasRemaining()) { counts.put(6); } counts.position(0); indexPointers = PointerBuffer.allocateDirect(numCellRows * numCellCols); } }