summaryrefslogtreecommitdiffstats
path: root/src/jogamp/graph/curve
diff options
context:
space:
mode:
authorRami Santina <[email protected]>2011-03-25 03:58:05 +0100
committerSven Gothel <[email protected]>2011-03-25 03:58:05 +0100
commit7f745c32c5734bc9549a16a98d158cdc01215bf5 (patch)
treead798e477be7ff9903a98e3ee3ee51e130453d2e /src/jogamp/graph/curve
parent6c07da79c276abef7a7c2f51b05fb1e04f7666db (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.java363
-rw-r--r--src/jogamp/graph/curve/opengl/VBORegionSPES2.java185
-rw-r--r--src/jogamp/graph/curve/tess/GraphOutline.java81
-rw-r--r--src/jogamp/graph/curve/tess/GraphPoint.java120
-rw-r--r--src/jogamp/graph/curve/tess/HEdge.java131
-rw-r--r--src/jogamp/graph/curve/tess/Loop.java376
-rw-r--r--src/jogamp/graph/curve/text/GlyphShape.java169
-rw-r--r--src/jogamp/graph/curve/text/GlyphString.java163
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();
+ }
+}