diff options
author | Rami Santina <[email protected]> | 2011-03-25 03:58:05 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2011-03-25 03:58:05 +0100 |
commit | 7f745c32c5734bc9549a16a98d158cdc01215bf5 (patch) | |
tree | ad798e477be7ff9903a98e3ee3ee51e130453d2e /src/jogamp/graph/curve | |
parent | 6c07da79c276abef7a7c2f51b05fb1e04f7666db (diff) |
Add initial GPU based curve rendering implementation, utilizing TTF fonts and manual shapes
Diffstat (limited to 'src/jogamp/graph/curve')
-rw-r--r-- | src/jogamp/graph/curve/opengl/VBORegion2PGL3.java | 363 | ||||
-rw-r--r-- | src/jogamp/graph/curve/opengl/VBORegionSPES2.java | 185 | ||||
-rw-r--r-- | src/jogamp/graph/curve/tess/GraphOutline.java | 81 | ||||
-rw-r--r-- | src/jogamp/graph/curve/tess/GraphPoint.java | 120 | ||||
-rw-r--r-- | src/jogamp/graph/curve/tess/HEdge.java | 131 | ||||
-rw-r--r-- | src/jogamp/graph/curve/tess/Loop.java | 376 | ||||
-rw-r--r-- | src/jogamp/graph/curve/text/GlyphShape.java | 169 | ||||
-rw-r--r-- | src/jogamp/graph/curve/text/GlyphString.java | 163 |
8 files changed, 1588 insertions, 0 deletions
diff --git a/src/jogamp/graph/curve/opengl/VBORegion2PGL3.java b/src/jogamp/graph/curve/opengl/VBORegion2PGL3.java new file mode 100644 index 000000000..c5182059e --- /dev/null +++ b/src/jogamp/graph/curve/opengl/VBORegion2PGL3.java @@ -0,0 +1,363 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.opengl; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.ArrayList; + +import javax.media.opengl.GL3; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLUniformData; +import javax.media.opengl.fixedfunc.GLMatrixFunc; + +import com.jogamp.common.nio.Buffers; + +import com.jogamp.graph.geom.AABBox; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.graph.geom.PointTex; + +import com.jogamp.graph.curve.Region; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +public class VBORegion2PGL3 implements Region{ + private int numVertices = 0; + private IntBuffer vboIds; + + private IntBuffer t_vboIds; + + private ArrayList<Triangle<PointTex>> triangles = new ArrayList<Triangle<PointTex>>(); + private ArrayList<PointTex> vertices = new ArrayList<PointTex>(); + private GLContext context; + + private int numBuffers = 3; + + private boolean flipped = false; + + private boolean dirty = false; + + private AABBox box = null; + private IntBuffer texture = IntBuffer.allocate(1); + private IntBuffer fbo = IntBuffer.allocate(1); + private IntBuffer rbo = IntBuffer.allocate(1); + private boolean texInitialized = false; + + private int tex_width_c = 0; + private int tex_height_c = 0; + + private ShaderState st; + + public VBORegion2PGL3(GLContext context, ShaderState st){ + this.context =context; + this.st = st; + } + + public void update(){ + box = new AABBox(); + + GL3 gl = context.getGL().getGL3(); + ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3); + + for(Triangle<PointTex> t:triangles){ + if(t.getVertices()[0].getId() == Integer.MAX_VALUE){ + t.getVertices()[0].setId(numVertices++); + t.getVertices()[1].setId(numVertices++); + t.getVertices()[2].setId(numVertices++); + + vertices.add(t.getVertices()[0]); + vertices.add(t.getVertices()[1]); + vertices.add(t.getVertices()[2]); + + indicies.put((short) t.getVertices()[0].getId()); + indicies.put((short) t.getVertices()[1].getId()); + indicies.put((short) t.getVertices()[2].getId()); + } + else{ + PointTex v1 = t.getVertices()[0]; + PointTex v2 = t.getVertices()[1]; + PointTex v3 = t.getVertices()[2]; + + indicies.put((short) v1.getId()); + indicies.put((short) v2.getId()); + indicies.put((short) v3.getId()); + } + } + indicies.rewind(); + + FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3); + for(PointTex v:vertices){ + verticesBuffer.put(v.getX()); + if(flipped){ + verticesBuffer.put(-1*v.getY()); + } + else{ + verticesBuffer.put(v.getY()); + } + verticesBuffer.put(v.getZ()); + + box.resize(v.getX(), -1*v.getY(), v.getZ()); + } + verticesBuffer.rewind(); + + FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2); + for(PointTex v:vertices){ + float[] tex = v.getTexCoord(); + texCoordBuffer.put(tex[0]); + texCoordBuffer.put(tex[1]); + } + texCoordBuffer.rewind(); + + vboIds = IntBuffer.allocate(numBuffers); + gl.glGenBuffers(numBuffers, vboIds); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices + gl.glBufferData(GL3.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vboIds.get(1)); //texture + gl.glBufferData(GL3.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles + gl.glBufferData(GL3.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, 0); + + dirty = false; + } + + public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){ + if(null == matrix || vp_width <=0 || vp_height <= 0 || width <= 0){ + renderRegion(); + } + else { + if(width != tex_width_c){ + texInitialized = false; + tex_width_c = width; + } + if(!texInitialized){ + initFBOTexture(matrix,vp_width, vp_height); + texInitialized = true; + } +// System.out.println("Scale: " + matrix.glGetMatrixf().get(1+4*3) +" " + matrix.glGetMatrixf().get(2+4*3)); + renderTexture(matrix, vp_width, vp_height); + } + } + + private void renderTexture(PMVMatrix matrix, int width, int hight){ + GL3 gl = context.getGL().getGL3(); + gl.glViewport(0, 0, width, hight); + if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, matrix.glGetPMvMatrixf()))){ + System.out.println("Cnt set tex based mat"); + } + gl.glEnable(GL3.GL_TEXTURE_2D); + gl.glActiveTexture(GL3.GL_TEXTURE0); + gl.glBindTexture(GL3.GL_TEXTURE_2D, texture.get(0)); + + st.glUniform(gl, new GLUniformData("texture", texture.get(0))); + int loc = gl.glGetUniformLocation(st.shaderProgram().id(), "texture"); + gl.glUniform1i(loc, 0); + + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, t_vboIds.get(0)); + gl.glEnableVertexAttribArray(VERTEX_POS_INDX); + gl.glVertexAttribPointer(VERTEX_POS_INDX, 3, GL3.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, t_vboIds.get(1)); + gl.glEnableVertexAttribArray(TEX_COORD); + gl.glVertexAttribPointer(TEX_COORD, 2, GL3.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2)); + gl.glDrawElements(GL3.GL_TRIANGLES, 2 * 3, GL3.GL_UNSIGNED_SHORT, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + } + + private void setupBoundingBuffers(){ + GL3 gl = context.getGL().getGL3(); + ShortBuffer indicies = Buffers.newDirectShortBuffer(6); + indicies.put((short) 0); indicies.put((short) 1); indicies.put((short) 3); + indicies.put((short) 1); indicies.put((short) 2); indicies.put((short) 3); + indicies.rewind(); + + FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(4 * 3); + FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(4 * 2); + + verticesBuffer.put(box.getLow()[0]); + verticesBuffer.put(box.getLow()[1]); + verticesBuffer.put(box.getLow()[2]); + texCoordBuffer.put(5); + texCoordBuffer.put(5); + + verticesBuffer.put(box.getLow()[0]); + verticesBuffer.put(box.getHigh()[1]); + verticesBuffer.put(box.getLow()[2]); + + texCoordBuffer.put(5); + texCoordBuffer.put(6); + + verticesBuffer.put(box.getHigh()[0]); + verticesBuffer.put(box.getHigh()[1]); + verticesBuffer.put(box.getLow()[2]); + + texCoordBuffer.put(6); + texCoordBuffer.put(6); + + verticesBuffer.put(box.getHigh()[0]); + verticesBuffer.put(box.getLow()[1]); + verticesBuffer.put(box.getLow()[2]); + + texCoordBuffer.put(6); + texCoordBuffer.put(5); + + verticesBuffer.rewind(); + texCoordBuffer.rewind(); + + t_vboIds = IntBuffer.allocate(3); + gl.glGenBuffers(numBuffers, t_vboIds); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, t_vboIds.get(0)); // vertices + gl.glBufferData(GL3.GL_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, t_vboIds.get(1)); //texture + gl.glBufferData(GL3.GL_ARRAY_BUFFER, 4 * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, t_vboIds.get(2)); //triangles + gl.glBufferData(GL3.GL_ELEMENT_ARRAY_BUFFER, 4 * 3 * Buffers.SIZEOF_SHORT, indicies, GL3.GL_STATIC_DRAW); + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, 0); + } + + private void initFBOTexture(PMVMatrix m, int width, int hight){ + tex_height_c = (int)(tex_width_c*box.getHeight()/box.getWidth()); + System.out.println("Scale: " + m.glGetMatrixf().get(0) +" " + m.glGetMatrixf().get(5)); + GL3 gl = context.getGL().getGL3(); + + gl.glDeleteFramebuffers(1, fbo); + gl.glDeleteTextures(1, texture); + + gl.glGenTextures(1, texture); + gl.glBindTexture(GL3.GL_TEXTURE_2D, texture.get(0)); + gl.glTexImage2D(GL3.GL_TEXTURE_2D, 0, GL3.GL_RGBA, tex_width_c, + tex_height_c, 0, GL3.GL_RGBA, GL3.GL_UNSIGNED_BYTE, null); + + gl.glTexParameterf(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MIN_FILTER, GL3.GL_LINEAR); + gl.glTexParameterf(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_MAG_FILTER, GL3.GL_LINEAR); + gl.glTexParameterf(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_S, GL3.GL_CLAMP_TO_EDGE); + gl.glTexParameterf(GL3.GL_TEXTURE_2D, GL3.GL_TEXTURE_WRAP_T, GL3.GL_CLAMP_TO_EDGE); + + gl.glGenRenderbuffers(1,rbo); + gl.glBindRenderbuffer(GL3.GL_RENDERBUFFER, rbo.get(0)); + gl.glRenderbufferStorage(GL3.GL_RENDERBUFFER, GL3.GL_DEPTH_COMPONENT, tex_width_c, tex_height_c); + + gl.glGenFramebuffers(1, fbo); + gl.glBindFramebuffer(GL3.GL_DRAW_FRAMEBUFFER, fbo.get(0)); + gl.glFramebufferTexture2D(GL3.GL_DRAW_FRAMEBUFFER, GL3.GL_COLOR_ATTACHMENT0, + GL3.GL_TEXTURE_2D, texture.get(0), 0); + gl.glFramebufferRenderbuffer(GL3.GL_FRAMEBUFFER, GL3.GL_DEPTH_COMPONENT, GL3.GL_RENDERBUFFER, rbo.get(0)); + + int status = gl.glCheckFramebufferStatus(GL3.GL_FRAMEBUFFER); + if(status != GL3.GL_FRAMEBUFFER_COMPLETE){ + System.out.println("FRAAAAAAAAAAAAAAME"); + } + + //render texture + PMVMatrix tex_matrix = new PMVMatrix(); + gl.glBindFramebuffer(GL3.GL_DRAW_FRAMEBUFFER, fbo.get(0)); + gl.glViewport(0, 0, tex_width_c, tex_height_c); + tex_matrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + tex_matrix.glLoadIdentity(); + tex_matrix.glOrthof(box.getLow()[0], box.getHigh()[0], box.getLow()[1], box.getHigh()[1], -1, 1); + + if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, tex_matrix.glGetPMvMatrixf()))){ + System.out.println("Cnt set tex based mat"); + } + + gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + gl.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT); + renderRegion(); + + gl.glBindFramebuffer(GL3.GL_FRAMEBUFFER, 0); + gl.glBindTexture(GL3.GL_TEXTURE_2D, 0); + + setupBoundingBuffers(); + } + + private void renderRegion(){ + GL3 gl = context.getGL().getGL3(); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vboIds.get(0)); + gl.glEnableVertexAttribArray(VERTEX_POS_INDX); + gl.glVertexAttribPointer(VERTEX_POS_INDX, 3, GL3.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vboIds.get(1)); + gl.glEnableVertexAttribArray(TEX_COORD); + gl.glVertexAttribPointer(TEX_COORD, 2, GL3.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); + gl.glDrawElements(GL3.GL_TRIANGLES, triangles.size() * 3, GL3.GL_UNSIGNED_SHORT, 0); + + gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0); + } + + public void addTriangles(ArrayList<Triangle<PointTex>> tris) { + triangles.addAll(tris); + dirty = true; + } + + public int getNumVertices(){ + return numVertices; + } + + public void addVertices(ArrayList<PointTex> verts){ + vertices.addAll(verts); + numVertices = vertices.size(); + dirty = true; + } + + public boolean isDirty(){ + return dirty; + } + + public void destroy() { + GL3 gl = context.getGL().getGL3(); + gl.glDeleteBuffers(numBuffers, vboIds); + gl.glDeleteFramebuffers(1, fbo); + gl.glDeleteTextures(1, texture); + } + + public boolean isFlipped() { + return flipped; + } + + public void setFlipped(boolean flipped) { + this.flipped = flipped; + } +} diff --git a/src/jogamp/graph/curve/opengl/VBORegionSPES2.java b/src/jogamp/graph/curve/opengl/VBORegionSPES2.java new file mode 100644 index 000000000..5ef23d4e0 --- /dev/null +++ b/src/jogamp/graph/curve/opengl/VBORegionSPES2.java @@ -0,0 +1,185 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.opengl; + +import java.nio.FloatBuffer; +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.ArrayList; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLContext; + +import com.jogamp.common.nio.Buffers; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.opengl.util.PMVMatrix; + +public class VBORegionSPES2 implements Region{ + private int numVertices = 0; + private IntBuffer vboIds; + + private ArrayList<Triangle<PointTex>> triangles = new ArrayList<Triangle<PointTex>>(); + private ArrayList<PointTex> vertices = new ArrayList<PointTex>(); + + private GLContext context; + + private int numBuffers = 3; + + private boolean flipped = false; + private boolean dirty = false; + + public VBORegionSPES2(GLContext context){ + this.context =context; + } + + public void update(){ + GL2ES2 gl = context.getGL().getGL2ES2(); + ShortBuffer indicies = Buffers.newDirectShortBuffer(triangles.size() * 3); + + for(Triangle<PointTex> t:triangles){ + final PointTex[] t_vertices = t.getVertices(); + + if(t_vertices[0].getId() == Integer.MAX_VALUE){ + t_vertices[0].setId(numVertices++); + t_vertices[1].setId(numVertices++); + t_vertices[2].setId(numVertices++); + + vertices.add(t.getVertices()[0]); + vertices.add(t.getVertices()[1]); + vertices.add(t.getVertices()[2]); + + indicies.put((short) t.getVertices()[0].getId()); + indicies.put((short) t.getVertices()[1].getId()); + indicies.put((short) t.getVertices()[2].getId()); + } + else{ + PointTex v1 = t_vertices[0]; + PointTex v2 = t_vertices[1]; + PointTex v3 = t_vertices[2]; + + indicies.put((short) v1.getId()); + indicies.put((short) v2.getId()); + indicies.put((short) v3.getId()); + } + } + indicies.rewind(); + + FloatBuffer verticesBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 3); + for(PointTex v:vertices){ + verticesBuffer.put(v.getX()); + if(flipped){ + verticesBuffer.put(-1*v.getY()); + } + else{ + verticesBuffer.put(v.getY()); + } + verticesBuffer.put(v.getZ()); + } + verticesBuffer.rewind(); + + FloatBuffer texCoordBuffer = Buffers.newDirectFloatBuffer(vertices.size() * 2); + for(PointTex v:vertices){ + float[] tex = v.getTexCoord(); + texCoordBuffer.put(tex[0]); + texCoordBuffer.put(tex[1]); + } + texCoordBuffer.rewind(); + + vboIds = IntBuffer.allocate(numBuffers); + gl.glGenBuffers(numBuffers, vboIds); + + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); // vertices + gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 3 * Buffers.SIZEOF_FLOAT, verticesBuffer, GL2ES2.GL_STATIC_DRAW); + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); //texture + gl.glBufferData(GL2ES2.GL_ARRAY_BUFFER, numVertices * 2 * Buffers.SIZEOF_FLOAT, texCoordBuffer, GL2ES2.GL_STATIC_DRAW); + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0); + + gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); //triangles + gl.glBufferData(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, triangles.size()* 3 * Buffers.SIZEOF_SHORT, indicies, GL2ES2.GL_STATIC_DRAW); + gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, 0); + + dirty = false; + } + + private void render() { + GL2ES2 gl = context.getGL().getGL2ES2(); + + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(0)); + gl.glEnableVertexAttribArray(VERTEX_POS_INDX); + gl.glVertexAttribPointer(VERTEX_POS_INDX, 3, GL2ES2.GL_FLOAT, false, 3 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, vboIds.get(1)); + gl.glEnableVertexAttribArray(TEX_COORD); + gl.glVertexAttribPointer(TEX_COORD, 2, GL2ES2.GL_FLOAT, false, 2 * Buffers.SIZEOF_FLOAT, 0); + + gl.glBindBuffer(GL2ES2.GL_ELEMENT_ARRAY_BUFFER, vboIds.get(2)); + gl.glDrawElements(GL2ES2.GL_TRIANGLES, triangles.size() * 3, GL2ES2.GL_UNSIGNED_SHORT, 0); + + gl.glBindBuffer(GL2ES2.GL_ARRAY_BUFFER, 0); + } + + public void render(PMVMatrix matrix, int vp_width, int vp_height, int width){ + render(); + } + + public void addTriangles(ArrayList<Triangle<PointTex>> tris) { + triangles.addAll(tris); + dirty = true; + } + + public int getNumVertices(){ + return numVertices; + } + + public void addVertices(ArrayList<PointTex> verts){ + vertices.addAll(verts); + numVertices = vertices.size(); + dirty = true; + } + + public boolean isDirty(){ + return dirty; + } + + public void destroy() { + GL2ES2 gl = context.getGL().getGL2ES2(); + gl.glDeleteBuffers(numBuffers, vboIds); + } + + public boolean isFlipped() { + return flipped; + } + + public void setFlipped(boolean flipped) { + this.flipped = flipped; + } +} diff --git a/src/jogamp/graph/curve/tess/GraphOutline.java b/src/jogamp/graph/curve/tess/GraphOutline.java new file mode 100644 index 000000000..cf73ab379 --- /dev/null +++ b/src/jogamp/graph/curve/tess/GraphOutline.java @@ -0,0 +1,81 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.tess; + +import java.util.ArrayList; + +import com.jogamp.graph.geom.Outline; +import com.jogamp.graph.geom.PointTex; + +public class GraphOutline <T extends PointTex> { + final private Outline<T> outline; + final private ArrayList<GraphPoint<T>> controlpoints = new ArrayList<GraphPoint<T>>(3); + + public GraphOutline(){ + this.outline = new Outline<T>(); + } + + /**Create a control polyline of control vertices + * the curve pieces can be identified by onCurve flag + * of each cp the control polyline is open by default + */ + public GraphOutline(Outline<T> ol){ + this.outline = ol; + ArrayList<T> vertices = this.outline.getVertices(); + for(T v:vertices){ + this.controlpoints.add(new GraphPoint<T>(v)); + } + } + + public Outline<T> getOutline() { + return outline; + } + + /*public void setOutline(Outline<T> outline) { + this.outline = outline; + }*/ + + + public ArrayList<GraphPoint<T>> getGraphPoint() { + return controlpoints; + } + + public ArrayList<T> getPoints() { + return outline.getVertices(); + } + + /*public void setControlpoints(ArrayList<GraphPoint<T>> controlpoints) { + this.controlpoints = controlpoints; + }*/ + + public void addVertex(GraphPoint<T> v) { + controlpoints.add(v); + outline.addVertex(v.getPoint()); + } + +} diff --git a/src/jogamp/graph/curve/tess/GraphPoint.java b/src/jogamp/graph/curve/tess/GraphPoint.java new file mode 100644 index 000000000..87d0b9929 --- /dev/null +++ b/src/jogamp/graph/curve/tess/GraphPoint.java @@ -0,0 +1,120 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.tess; + +import java.util.ArrayList; + +import com.jogamp.graph.geom.PointTex; + +public class GraphPoint <T extends PointTex> { + private T point; + private ArrayList<HEdge<T>> edges = null; + private boolean boundaryContained = false; + + public GraphPoint(T point) { + this.point = point; + } + + public T getPoint() { + return point; + } + + public float getX(){ + return point.getX(); + } + + public float getY(){ + return point.getY(); + } + + public float getZ(){ + return point.getZ(); + } + public float[] getCoord() { + return point.getCoord(); + } + + public void setPoint(T point) { + this.point = point; + } + + public ArrayList<HEdge<T>> getEdges() { + return edges; + } + + public void setEdges(ArrayList<HEdge<T>> edges) { + this.edges = edges; + } + + public void addEdge(HEdge<T> edge){ + if(edges == null){ + edges = new ArrayList<HEdge<T>>(); + } + edges.add(edge); + } + public void removeEdge(HEdge<T> edge){ + if(edges == null) + return; + edges.remove(edge); + if(edges.size() == 0){ + edges = null; + } + } + public HEdge<T> findNextEdge(GraphPoint<T> nextVert){ + for(HEdge<T> e:edges){ + if(e.getNext().getGraphPoint() == nextVert){ + return e; + } + } + return null; + } + public HEdge<T> findBoundEdge(){ + for(HEdge<T> e:edges){ + if((e.getType() == HEdge.BOUNDARY) || (e.getType() == HEdge.HOLE)){ + return e; + } + } + return null; + } + public HEdge<T> findPrevEdge(GraphPoint<T> prevVert){ + for(HEdge<T> e:edges){ + if(e.getPrev().getGraphPoint() == prevVert){ + return e; + } + } + return null; + } + + public boolean isBoundaryContained() { + return boundaryContained; + } + + public void setBoundaryContained(boolean boundaryContained) { + this.boundaryContained = boundaryContained; + } +} diff --git a/src/jogamp/graph/curve/tess/HEdge.java b/src/jogamp/graph/curve/tess/HEdge.java new file mode 100644 index 000000000..acb32cb4d --- /dev/null +++ b/src/jogamp/graph/curve/tess/HEdge.java @@ -0,0 +1,131 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.tess; + +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Triangle; + + +public class HEdge <T extends PointTex> { + public static int BOUNDARY = 3; + public static int INNER = 1; + public static int HOLE = 2; + + private GraphPoint<T> vert; + private HEdge<T> prev = null; + private HEdge<T> next = null; + private HEdge<T> sibling = null; + private int type = BOUNDARY; + private Triangle<T> triangle = null; + + public HEdge(GraphPoint<T> vert, int type) { + this.vert = vert; + this.type = type; + } + + public HEdge(GraphPoint<T> vert, HEdge<T> prev, HEdge<T> next, HEdge<T> sibling, int type) { + this.vert = vert; + this.prev = prev; + this.next = next; + this.sibling = sibling; + this.type = type; + } + + public HEdge(GraphPoint<T> vert, HEdge<T> prev, HEdge<T> next, HEdge<T> sibling, int type, + Triangle<T> triangle) { + this.vert = vert; + this.prev = prev; + this.next = next; + this.sibling = sibling; + this.type = type; + this.triangle = triangle; + } + + public GraphPoint<T> getGraphPoint() { + return vert; + } + + public void setVert(GraphPoint<T> vert) { + this.vert = vert; + } + + public HEdge<T> getPrev() { + return prev; + } + + public void setPrev(HEdge<T> prev) { + this.prev = prev; + } + + public HEdge<T> getNext() { + return next; + } + + public void setNext(HEdge<T> next) { + this.next = next; + } + + public HEdge<T> getSibling() { + return sibling; + } + + public void setSibling(HEdge<T> sibling) { + this.sibling = sibling; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public Triangle<T> getTriangle() { + return triangle; + } + + public void setTriangle(Triangle<T> triangle) { + this.triangle = triangle; + } + + public static <T extends PointTex> void connect(HEdge<T> first, HEdge<T> next){ + first.setNext(next); + next.setPrev(first); + } + + public static <T extends PointTex> void makeSiblings(HEdge<T> first, HEdge<T> second){ + first.setSibling(second); + second.setSibling(first); + } + + public boolean vertexOnCurveVertex(){ + return vert.getPoint().isOnCurve(); + } + +} diff --git a/src/jogamp/graph/curve/tess/Loop.java b/src/jogamp/graph/curve/tess/Loop.java new file mode 100644 index 000000000..caebd64e4 --- /dev/null +++ b/src/jogamp/graph/curve/tess/Loop.java @@ -0,0 +1,376 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.tess; + +import java.util.ArrayList; + +import jogamp.graph.math.VectorFloatUtil; + +import com.jogamp.graph.geom.AABBox; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Triangle; + +public class Loop <T extends PointTex> { + private HEdge<T> root = null; + private AABBox box = new AABBox(); + private GraphOutline<T> initialOutline = null; + + public Loop(GraphOutline<T> polyline, int direction){ + initialOutline = polyline; + this.root = initFromPolyline(initialOutline, direction); + } + + public HEdge<T> getHEdge(){ + return root; + } + + public Triangle<T> cut(boolean delaunay){ + if(isSimplex()){ + @SuppressWarnings("unchecked") + Triangle<T> t = new Triangle<T>(root.getGraphPoint().getPoint(), root.getNext().getGraphPoint().getPoint(), + root.getNext().getNext().getGraphPoint().getPoint()); + t.setVerticesBoundary(checkVerticesBoundary(root)); + return t; + } + HEdge<T> prev = root.getPrev(); + HEdge<T> next1 = root.getNext(); + + HEdge<T> next2 =findClosestValidNeighbor(next1.getNext(), delaunay); + if(next2 == null){ + root = root.getNext(); + return null; + } + + GraphPoint<T> v1 = root.getGraphPoint(); + GraphPoint<T> v2 = next1.getGraphPoint(); + GraphPoint<T> v3 = next2.getGraphPoint(); + + HEdge<T> v3Edge = new HEdge<T>(v3, HEdge.INNER); + + HEdge.connect(v3Edge, root); + HEdge.connect(next1, v3Edge); + + HEdge<T> v3EdgeSib = v3Edge.getSibling(); + if(v3EdgeSib == null){ + v3EdgeSib = new HEdge<T>(v3Edge.getNext().getGraphPoint(), HEdge.INNER); + HEdge.makeSiblings(v3Edge, v3EdgeSib); + } + + HEdge.connect(prev, v3EdgeSib); + HEdge.connect(v3EdgeSib, next2); + + Triangle<T> t = createTriangle(v1.getPoint(), v2.getPoint(), v3.getPoint(), root); + this.root = next2; + return t; + } + + public boolean isSimplex(){ + return (root.getNext().getNext().getNext() == root); + } + + /**Create a connected list of half edges (loop) + * from the boundary profile + * @param direction requested winding of edges (CCW or CW) + */ + private HEdge<T> initFromPolyline(GraphOutline<T> outline, int direction){ + ArrayList<GraphPoint<T>> vertices = outline.getGraphPoint(); + + if(vertices.size()<3) { + throw new IllegalArgumentException("outline's vertices < 3: " + vertices.size()); + } + boolean isCCW = VectorFloatUtil.ccw(vertices.get(0).getPoint(), vertices.get(1).getPoint(), + vertices.get(2).getPoint()); + boolean invert = isCCW && (direction == VectorFloatUtil.CW); + + HEdge<T> firstEdge = null; + HEdge<T> lastEdge = null; + int index =0; + int max = vertices.size(); + + int edgeType = HEdge.BOUNDARY; + if(invert){ + index = vertices.size() -1; + max = -1; + edgeType = HEdge.HOLE; + } + + while(index != max){ + GraphPoint<T> v1 = vertices.get(index); + box.resize(v1.getX(), v1.getY(), v1.getZ()); + + HEdge<T> edge = new HEdge<T>(v1, edgeType); + + v1.addEdge(edge); + if(lastEdge != null){ + lastEdge.setNext(edge); + edge.setPrev(lastEdge); + } + else{ + firstEdge = edge; + } + + if(!invert){ + if(index == vertices.size()-1){ + edge.setNext(firstEdge); + firstEdge.setPrev(edge); + } + } + else if (index == 0){ + edge.setNext(firstEdge); + firstEdge.setPrev(edge); + } + + lastEdge = edge; + + if(!invert){ + index++; + } + else{ + index--; + } + } + return firstEdge; + } + + public void addConstraintCurve(GraphOutline<T> polyline) { + // GraphOutline outline = new GraphOutline(polyline); + /**needed to generate vertex references.*/ + initFromPolyline(polyline, VectorFloatUtil.CW); + + GraphPoint<T> v3 = locateClosestVertex(polyline); + HEdge<T> v3Edge = v3.findBoundEdge(); + HEdge<T> v3EdgeP = v3Edge.getPrev(); + HEdge<T> crossEdge = new HEdge<T>(root.getGraphPoint(), HEdge.INNER); + + HEdge.connect(root.getPrev(), crossEdge); + HEdge.connect(crossEdge, v3Edge); + + HEdge<T> crossEdgeSib = crossEdge.getSibling(); + if(crossEdgeSib == null) { + crossEdgeSib = new HEdge<T>(crossEdge.getNext().getGraphPoint(), HEdge.INNER); + HEdge.makeSiblings(crossEdge, crossEdgeSib); + } + + HEdge.connect(v3EdgeP, crossEdgeSib); + HEdge.connect(crossEdgeSib, root); + } + + /** Locates the vertex and update the loops root + * to have (root + vertex) as closest pair + * @param polyline the control polyline + * to search for closestvertices + * @return the vertex that is closest to the newly set root Hedge. + */ + private GraphPoint<T> locateClosestVertex(GraphOutline<T> polyline) { + HEdge<T> closestE = null; + GraphPoint<T> closestV = null; + + float minDistance = Float.MAX_VALUE; + boolean inValid = false; + ArrayList<GraphPoint<T>> initVertices = initialOutline.getGraphPoint(); + ArrayList<GraphPoint<T>> vertices = polyline.getGraphPoint(); + + for(int i=0; i< initVertices.size()-1; i++){ + GraphPoint<T> v = initVertices.get(i); + GraphPoint<T> nextV = initVertices.get(i+1); + for(GraphPoint<T> cand:vertices){ + float distance = VectorFloatUtil.computeLength(v.getCoord(), cand.getCoord()); + if(distance < minDistance){ + for (GraphPoint<T> vert:vertices){ + if(vert == v || vert == nextV || vert == cand) + continue; + inValid = VectorFloatUtil.inCircle(v.getPoint(), nextV.getPoint(), + cand.getPoint(), vert.getPoint()); + if(inValid){ + break; + } + } + if(!inValid){ + closestV = cand; + minDistance = distance; + closestE = v.findBoundEdge(); + } + } + + } + } + + if(closestE != null){ + root = closestE; + } + + return closestV; + } + + private HEdge<T> findClosestValidNeighbor(HEdge<T> edge, boolean delaunay) { + HEdge<T> next = root.getNext(); + + if(!VectorFloatUtil.ccw(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(), + edge.getGraphPoint().getPoint())){ + return null; + } + + HEdge<T> candEdge = edge; + boolean inValid = false; + + if(delaunay){ + T cand = candEdge.getGraphPoint().getPoint(); + HEdge<T> e = candEdge.getNext(); + while (e != candEdge){ + if(e.getGraphPoint() == root.getGraphPoint() + || e.getGraphPoint() == next.getGraphPoint() + || e.getGraphPoint().getPoint() == cand){ + e = e.getNext(); + continue; + } + inValid = VectorFloatUtil.inCircle(root.getGraphPoint().getPoint(), next.getGraphPoint().getPoint(), + cand, e.getGraphPoint().getPoint()); + if(inValid){ + break; + } + e = e.getNext(); + } + } + if(!inValid){ + return candEdge; + } + return null; + } + + /** Create a triangle from the param vertices only if + * the triangle is valid. IE not outside region. + * @param v1 vertex 1 + * @param v2 vertex 2 + * @param v3 vertex 3 + * @param root and edge of this triangle + * @return the triangle iff it satisfies, null otherwise + */ + private Triangle<T> createTriangle(T v1, T v2, T v3, HEdge<T> rootT){ + @SuppressWarnings("unchecked") + Triangle<T> t = new Triangle<T>(v1, v2, v3); + t.setVerticesBoundary(checkVerticesBoundary(rootT)); + return t; + } + + private boolean[] checkVerticesBoundary(HEdge<T> rootT) { + boolean[] boundary = new boolean[3]; + HEdge<T> e1 = rootT; + HEdge<T> e2 = rootT.getNext(); + HEdge<T> e3 = rootT.getNext().getNext(); + + if(e1.getGraphPoint().isBoundaryContained()){ + boundary[0] = true; + } + if(e2.getGraphPoint().isBoundaryContained()){ + boundary[1] = true; + } + if(e3.getGraphPoint().isBoundaryContained()){ + boundary[2] = true; + } + return boundary; + } + + + /** Check if vertex inside the Loop + * @param vertex the Vertex + * @return true if the vertex is inside, false otherwise + */ + public boolean checkInside(T vertex) { + if(!box.contains(vertex.getX(), vertex.getY(), vertex.getZ())){ + return false; + } + + float[] center = box.getCenter(); + + int hits = 0; + HEdge<T> current = root; + HEdge<T> next = root.getNext(); + while(next!= root){ + if(current.getType() == HEdge.INNER || next.getType() == HEdge.INNER){ + current = next; + next = current.getNext(); + continue; + } + + T vert1 = current.getGraphPoint().getPoint(); + T vert2 = next.getGraphPoint().getPoint(); + + /** The ray is P0+s*D0, where P0 is the ray origin, D0 is a direction vector and s >= 0. + * The segment is P1+t*D1, where P1 and P1+D1 are the endpoints, and 0 <= t <= 1. + * perp(x,y) = (y,-x). + * if Dot(perp(D1),D0) is not zero, + * s = Dot(perp(D1),P1-P0)/Dot(perp(D1),D0) + * t = Dot(perp(D0),P1-P0)/Dot(perp(D1),D0) + */ + + float[] d0 = new float[]{center[0] - vertex.getX(), center[1]-vertex.getY(), + center[2]-vertex.getZ()}; + float[] d1 = {vert2.getX() - vert1.getX(), vert2.getY() - vert1.getY(), + vert2.getZ() - vert1.getZ()}; + + float[] prepD1 = {d1[1],-1*d1[0], d1[2]}; + float[] prepD0 = {d0[1],-1*d0[0], d0[2]}; + + float[] p0p1 = new float[]{vert1.getX() - vertex.getX(), vert1.getY() - vertex.getY(), + vert1.getZ() - vertex.getZ()}; + + float dotD1D0 = VectorFloatUtil.dot(prepD1, d0); + if(dotD1D0 == 0){ + /** ray parallel to segment */ + current = next; + next = current.getNext(); + continue; + } + + float s = VectorFloatUtil.dot(prepD1,p0p1)/dotD1D0; + float t = VectorFloatUtil.dot(prepD0,p0p1)/dotD1D0; + + if(s >= 0 && t >= 0 && t<= 1){ + hits++; + } + current = next; + next = current.getNext(); + } + + if(hits % 2 != 0){ + /** check if hit count is even */ + return true; + } + return false; + } + + public int computeLoopSize(){ + int size = 0; + HEdge<T> e = root; + do{ + size++; + e = e.getNext(); + }while(e != root); + return size; + } +} diff --git a/src/jogamp/graph/curve/text/GlyphShape.java b/src/jogamp/graph/curve/text/GlyphShape.java new file mode 100644 index 000000000..9862a5407 --- /dev/null +++ b/src/jogamp/graph/curve/text/GlyphShape.java @@ -0,0 +1,169 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.text; + +import java.util.ArrayList; + +import com.jogamp.graph.geom.plane.PathIterator; +import com.jogamp.graph.geom.Line; +import com.jogamp.graph.geom.Point; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Triangle; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.math.Quaternion; + +public class GlyphShape { + + private Quaternion quat= null; + private int numVertices = 0; + private OutlineShape shape = null; + + /** Create a new Glyph shape + * based on Parametric curve control polyline + */ + public GlyphShape(Point.Factory<? extends PointTex> factory){ + shape = new OutlineShape(factory); + } + + /** Create a GlyphShape from a font Path Iterator + * @param pathIterator the path iterator + * + * @see PathIterator + */ + public GlyphShape(Point.Factory<? extends PointTex> factory, PathIterator pathIterator){ + this(factory); + + if(null != pathIterator){ + while(!pathIterator.isDone()){ + float[] coords = new float[6]; + int segmentType = pathIterator.currentSegment(coords); + addOutlineVerticesFromGlyphVector(coords, segmentType); + + pathIterator.next(); + } + } + shape.transformOutlines(OutlineShape.QUADRATIC_NURBS); + } + + public final Point.Factory<? extends PointTex> pointFactory() { return shape.pointFactory(); } + + private void addVertexToLastOutline(PointTex vertex){ + shape.addVertex(vertex); + } + + private void addOutlineVerticesFromGlyphVector(float[] coords, int segmentType){ + if(segmentType == PathIterator.SEG_MOVETO){ + if(!shape.getLastOutline().isEmpty()){ + shape.addEmptyOutline(); + } + PointTex vert = pointFactory().create(coords[0],coords[1]); + vert.setOnCurve(true); + addVertexToLastOutline(vert); + + numVertices++; + } + else if(segmentType == PathIterator.SEG_LINETO){ + PointTex vert1 = pointFactory().create(coords[0],coords[1]); + vert1.setOnCurve(true); + addVertexToLastOutline(vert1); + + numVertices++; + } + else if(segmentType == PathIterator.SEG_QUADTO){ + PointTex vert1 = pointFactory().create(coords[0],coords[1]); + vert1.setOnCurve(false); + addVertexToLastOutline(vert1); + + PointTex vert2 = pointFactory().create(coords[2],coords[3]); + vert2.setOnCurve(true); + addVertexToLastOutline(vert2); + + numVertices+=2; + } + else if(segmentType == PathIterator.SEG_CUBICTO){ + PointTex vert1 = pointFactory().create(coords[0],coords[1]); + vert1.setOnCurve(false); + addVertexToLastOutline(vert1); + + PointTex vert2 = pointFactory().create(coords[2],coords[3]); + vert2.setOnCurve(false); + addVertexToLastOutline(vert2); + + PointTex vert3 = pointFactory().create(coords[4],coords[5]); + vert3.setOnCurve(true); + addVertexToLastOutline(vert3); + + numVertices+=3; + } + else if(segmentType == PathIterator.SEG_CLOSE){ + shape.closeLastOutline(); + } + } + + public int getNumVertices() { + return numVertices; + } + + /** Get the rotational Quaternion attached to this Shape + * @return the Quaternion Object + */ + public Quaternion getQuat() { + return quat; + } + + /** Set the Quaternion that shall defien the rotation + * of this shape. + * @param quat + */ + public void setQuat(Quaternion quat) { + this.quat = quat; + } + + /** Triangluate the glyph shape + * @param sharpness sharpness of the curved regions default = 0.5 + * @return ArrayList of triangles which define this shape + */ + public ArrayList<Triangle<PointTex>> triangulate(float sharpness){ + return shape.triangulate(sharpness); + } + + /** Get the list of Vertices of this Object + * @return arrayList of Vertices + */ + public ArrayList<PointTex> getVertices(){ + return shape.getVertices(); + } + + /** Get the list of AA lines defined by this object + * @return arraylist of lines + */ + public ArrayList<Line<PointTex>> getLines(){ + return shape.getLines(); + } +} diff --git a/src/jogamp/graph/curve/text/GlyphString.java b/src/jogamp/graph/curve/text/GlyphString.java new file mode 100644 index 000000000..d85e59c43 --- /dev/null +++ b/src/jogamp/graph/curve/text/GlyphString.java @@ -0,0 +1,163 @@ +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ +package jogamp.graph.curve.text; + +import java.util.ArrayList; + +import com.jogamp.graph.geom.plane.AffineTransform; +import com.jogamp.graph.geom.plane.Path2D; +import com.jogamp.graph.geom.plane.PathIterator; +import com.jogamp.graph.geom.Point; +import com.jogamp.graph.geom.PointTex; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.graph.geom.opengl.Vertex; + +import javax.media.opengl.GLContext; + + +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.RegionFactory; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +public class GlyphString { + private final Point.Factory<? extends PointTex> pointFactory; + private ArrayList<GlyphShape> glyphs = new ArrayList<GlyphShape>(); + private String str = ""; + private String fontname = ""; + private Region region; + + private Vertex origin = new Vertex(); + + /** Create a new GlyphString object + * @param fontname the name of the font that this String is + * associated with + * @param str the string object + */ + public GlyphString(Point.Factory<? extends PointTex> factory, String fontname, String str){ + pointFactory = factory; + this.fontname = fontname; + this.str = str; + } + + public final Point.Factory<? extends PointTex> pointFactory() { return pointFactory; } + + public void addGlyphShape(GlyphShape glyph){ + glyphs.add(glyph); + } + public String getString(){ + return str; + } + + /** Creates the Curve based Glyphs from a Font + * @param paths a list of FontPath2D objects that define the outline + * @param affineTransform a global affine transformation applied to the paths. + */ + public void createfromFontPath(Path2D[] paths, AffineTransform affineTransform){ + final int numGlyps = paths.length; + for (int index=0;index<numGlyps;index++){ + if(paths[index] == null){ + continue; + } + PathIterator iterator = paths[index].iterator(affineTransform); + GlyphShape glyphShape = new GlyphShape(pointFactory, iterator); + + if(glyphShape.getNumVertices() < 3) { + continue; + } + addGlyphShape(glyphShape); + } + } + + private ArrayList<Triangle<PointTex>> initializeTriangles(float sharpness){ + ArrayList<Triangle<PointTex>> triangles = new ArrayList<Triangle<PointTex>>(); + for(GlyphShape glyph:glyphs){ + ArrayList<Triangle<PointTex>> tris = glyph.triangulate(sharpness); + triangles.addAll(tris); + } + return triangles; + } + + /** Generate a OGL Region to represent this Object. + * @param context the GLContext which the region is defined by. + * @param shaprness the curvature sharpness of the object. + * @param st shader state + */ + public void generateRegion(GLContext context, float shaprness, ShaderState st, int type){ + region = RegionFactory.create(context, st, type); + region.setFlipped(true); + + ArrayList<Triangle<PointTex>> tris = initializeTriangles(shaprness); + region.addTriangles(tris); + + int numVertices = region.getNumVertices(); + for(GlyphShape glyph:glyphs){ + ArrayList<PointTex> gVertices = glyph.getVertices(); + for(PointTex vert:gVertices){ + vert.setId(numVertices++); + } + region.addVertices(gVertices); + } + + /** initialize the region */ + region.update(); + } + + /** Generate a Hashcode for this object + * @return a string defining the hashcode + */ + public String getTextHashCode(){ + return "" + fontname.hashCode() + str.hashCode(); + } + + /** Render the Object based using the associated Region + * previously generated. + */ + public void renderString3D() { + region.render(null, 0, 0, 0); + } + /** Render the Object based using the associated Region + * previously generated. + */ + public void renderString3D(PMVMatrix matrix, int vp_width, int vp_height, int size) { + region.render(matrix, vp_width, vp_height, size); + } + + /** Get the Origion of this GlyphString + * @return + */ + public PointTex getOrigin() { + return origin; + } + + /** Destroy the associated OGL objects + */ + public void destroy(){ + region.destroy(); + } +} |