/******************************************************************************* * 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; import static com.jogamp.opengl.GL.GL_ARRAY_BUFFER; import static com.jogamp.opengl.GL.GL_BLEND; import static com.jogamp.opengl.GL.GL_DYNAMIC_DRAW; import static com.jogamp.opengl.GL.GL_FLOAT; import static com.jogamp.opengl.GL.GL_LINE_LOOP; 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 org.andork.math3d.Vecmath.setf; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Arrays; import java.util.List; import org.andork.jogl.util.JoglUtils; import com.jogamp.opengl.GL2ES2; public class JoglScreenPolygon implements JoglDrawable, JoglResource { private static int programUseCount = 0; private static int program = 0; private static int screenXform_location; private static int a_pos_location; private static int u_outlineColor_location; private boolean initialized; private final float[] outlineColor = { 0f, 1f, 0f, 1f }; private final float[] fillColor = { 0f, 1f, 0f, 0.5f }; private final int[] buffers = new int[2]; private final ByteBuffer[] data = new ByteBuffer[2]; private boolean dataChanged; public void clearPoints() { Arrays.fill(data, null); } @Override public void dispose(GL2ES2 gl) { if (!initialized) { return; } initialized = false; if (--programUseCount == 0) { disposeProgram(gl); } gl.glDeleteBuffers(2, buffers, 0); } private void disposeProgram(GL2ES2 gl) { gl.glDeleteProgram(program); } @Override public void draw(JoglDrawContext context, GL2ES2 gl, float[] m, float[] n) { if (data[0] == null) { dispose(gl); return; } if (!initialized) { init(gl); } gl.glUseProgram(program); gl.glUniformMatrix4fv(screenXform_location, 1, false, context.screenXform(), 0); gl.glEnableVertexAttribArray(a_pos_location); gl.glEnable(GL_BLEND); gl.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // outline gl.glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); if (dataChanged) { gl.glBufferData(GL_ARRAY_BUFFER, data[0].capacity(), data[0], GL_DYNAMIC_DRAW); } gl.glUniform4fv(u_outlineColor_location, 1, outlineColor, 0); gl.glVertexAttribPointer(a_pos_location, 2, GL_FLOAT, false, 8, 0); gl.glDrawArrays(GL_LINE_LOOP, 0, data[0].capacity() / 8); // fill if (data[1] != null) { gl.glBindBuffer(GL_ARRAY_BUFFER, buffers[1]); if (dataChanged) { gl.glBufferData(GL_ARRAY_BUFFER, data[1].capacity(), data[1], GL_STATIC_DRAW); } gl.glUniform4fv(u_outlineColor_location, 1, fillColor, 0); gl.glVertexAttribPointer(a_pos_location, 2, GL_FLOAT, false, 8, 0); gl.glDrawArrays(GL_TRIANGLES, 0, data[1].capacity() / 8); } // ////////////////////////////// gl.glDisable(GL_BLEND); gl.glDisableVertexAttribArray(a_pos_location); gl.glBindBuffer(GL_ARRAY_BUFFER, 0); gl.glUseProgram(0); dataChanged = false; } @Override public void init(GL2ES2 gl) { if (initialized || data[0] == null) { return; } initialized = true; dataChanged = true; if (programUseCount++ == 0) { initProgram(gl); } gl.glGenBuffers(2, buffers, 0); } private void initProgram(GL2ES2 gl) { String vertexShaderCode = "#version 330\n" + "uniform mat4 screenXform;" + "in vec2 a_pos;" + "void main() {" + " gl_Position = screenXform * vec4(a_pos, 0.0, 1.0);" + "}"; String fragmentShaderCode = "#version 330\n" + "uniform vec4 u_outlineColor;" + "out vec4 color;" + "void main() {" + " color = u_outlineColor;" + "}"; program = JoglUtils.loadProgram(gl, vertexShaderCode, fragmentShaderCode); screenXform_location = gl.glGetUniformLocation(program, "screenXform"); a_pos_location = gl.glGetAttribLocation(program, "a_pos"); u_outlineColor_location = gl.glGetUniformLocation(program, "u_outlineColor"); } public void setColor(float... color) { setf(outlineColor, color); } public void setPoints(float[]... points) { setPoints(Arrays.asList(points)); } public void setPoints(int stride, float... points) { int nPoints = points.length / stride; if (data[0] == null || nPoints * 8 != data[0].capacity()) { data[0] = ByteBuffer.allocateDirect(nPoints * 8); data[0].order(ByteOrder.nativeOrder()); } data[0].position(0); // Outline outline = new Outline( ); for (int i = 0; i < points.length; i += stride) { data[0].putFloat(points[i]).putFloat(points[i + 1]); // outline.addVertex( new SVertex( point[ 0 ] , point[ 1 ] , 0f , // true ) ); } data[0].position(0); // if( points.size( ) > 2 ) // { // outline.setClosed( true ); // CDTriangulator2D triangulator2d = new CDTriangulator2D( ); // triangulator2d.addCurve( outline ); // ArrayList<Triangle> triangles = triangulator2d.generate( ); // // if( data[ 1 ] == null || triangles.size( ) * 24 != data[ 1 // ].capacity( ) ) // { // data[ 1 ] = ByteBuffer.allocateDirect( triangles.size( ) * 24 ); // data[ 1 ].order( ByteOrder.nativeOrder( ) ); // } // data[ 1 ].position( 0 ); // for( Triangle triangle : triangles ) // { // for( Vertex vertex : triangle.getVertices( ) ) // { // data[ 1 ].putFloat( vertex.getX( ) ).putFloat( vertex.getY( ) ); // } // } // data[ 1 ].position( 0 ); // } // else // { // data[ 1 ] = null; // } dataChanged = true; } public void setPoints(List<float[]> points) { if (data[0] == null || points.size() * 8 != data[0].capacity()) { data[0] = ByteBuffer.allocateDirect(points.size() * 8); data[0].order(ByteOrder.nativeOrder()); } data[0].position(0); // Outline outline = new Outline( ); for (float[] point : points) { data[0].putFloat(point[0]).putFloat(point[1]); // outline.addVertex( new SVertex( point[ 0 ] , point[ 1 ] , 0f , // true ) ); } data[0].position(0); // if( points.size( ) > 2 ) // { // outline.setClosed( true ); // CDTriangulator2D triangulator2d = new CDTriangulator2D( ); // triangulator2d.addCurve( outline ); // ArrayList<Triangle> triangles = triangulator2d.generate( ); // // if( data[ 1 ] == null || triangles.size( ) * 24 != data[ 1 // ].capacity( ) ) // { // data[ 1 ] = ByteBuffer.allocateDirect( triangles.size( ) * 24 ); // data[ 1 ].order( ByteOrder.nativeOrder( ) ); // } // data[ 1 ].position( 0 ); // for( Triangle triangle : triangles ) // { // for( Vertex vertex : triangle.getVertices( ) ) // { // data[ 1 ].putFloat( vertex.getX( ) ).putFloat( vertex.getY( ) ); // } // } // data[ 1 ].position( 0 ); // } // else // { // data[ 1 ] = null; // } dataChanged = true; } }