aboutsummaryrefslogtreecommitdiffstats
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
parent6c07da79c276abef7a7c2f51b05fb1e04f7666db (diff)
Add initial GPU based curve rendering implementation, utilizing TTF fonts and manual shapes
-rw-r--r--doc/alt-algorithm-rsantina-01.pdfbin0 -> 52435 bytes
-rwxr-xr-xsrc/com/jogamp/graph/curve/HwRegionRenderer.java385
-rwxr-xr-xsrc/com/jogamp/graph/curve/OutlineShape.java244
-rwxr-xr-xsrc/com/jogamp/graph/curve/Region.java125
-rwxr-xr-xsrc/com/jogamp/graph/curve/RegionFactory.java58
-rw-r--r--src/com/jogamp/graph/curve/shader/curverenderer.fp99
-rw-r--r--src/com/jogamp/graph/curve/shader/curverenderer.vp13
-rw-r--r--src/com/jogamp/graph/curve/tess/CDTriangulator2D.java213
-rw-r--r--src/com/jogamp/graph/curve/text/HwTextRenderer.java367
-rwxr-xr-xsrc/com/jogamp/graph/math/Quaternion.java382
-rwxr-xr-xsrc/demo/GPURegionNewtDemo01.java230
-rwxr-xr-xsrc/demo/GPURegionNewtDemo02.java227
-rw-r--r--src/demo/GPUTextNewtDemo01.java198
-rw-r--r--src/demo/GPUTextNewtDemo02.java215
-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
-rwxr-xr-xsrc/jogamp/graph/math/VectorFloatUtil.java293
23 files changed, 4637 insertions, 0 deletions
diff --git a/doc/alt-algorithm-rsantina-01.pdf b/doc/alt-algorithm-rsantina-01.pdf
new file mode 100644
index 000000000..969b3a7ae
--- /dev/null
+++ b/doc/alt-algorithm-rsantina-01.pdf
Binary files differ
diff --git a/src/com/jogamp/graph/curve/HwRegionRenderer.java b/src/com/jogamp/graph/curve/HwRegionRenderer.java
new file mode 100755
index 000000000..3c3142061
--- /dev/null
+++ b/src/com/jogamp/graph/curve/HwRegionRenderer.java
@@ -0,0 +1,385 @@
+/**
+ * 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 com.jogamp.graph.curve;
+
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.PointTex;
+
+import jogamp.opengl.Debug;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class HwRegionRenderer {
+ protected static final boolean DEBUG = Debug.debug("RegionRenderer");
+
+ private ShaderState st;
+ private PMVMatrix pmvMatrix = new PMVMatrix();
+
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private float sharpness = 0.5f;
+ private float alpha = 1.0f;
+ private float strength = 3.0f;
+ private boolean initialized = false;
+
+ private int regionType = Region.SINGLE_PASS;
+
+ private GLContext context;
+ private FloatBuffer color = FloatBuffer.allocate(3);
+ private HashMap<Integer, Region> regions = new HashMap<Integer, Region>();
+
+ /** Create a Hardware accelerated Region Renderer
+ * @param context OpenGL rendering context
+ * @param factory optional Point.Factory for PointTex construction. Default is Vertex.Factory.
+ */
+ public HwRegionRenderer(GLContext context) {
+ this.context = context;
+ init(context, 0.5f);
+ }
+ /** Create a Hardware accelerated Region Renderer
+ * @param context OpenGL rendering context
+ * @param type region type (single or multipass)
+ */
+ public HwRegionRenderer(GLContext context, int type) {
+ this.context = context;
+ this.regionType = type;
+ init(context, 0.5f);
+ }
+
+ private boolean init(GLContext context, float sharpvalue){
+ if(initialized){
+ if(DEBUG) {
+ System.err.println("HWRegionRenderer: Already initialized!");
+ }
+ return true;
+ }
+ sharpness = sharpvalue;
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("HWRegionRenderer: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.setSwapInterval(1);
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ initShader(gl);
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetMatrix();
+
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()))) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("p1y", sharpness))) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_alpha", alpha))) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_color", 3, color))) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("a_strength", strength))) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+ st.glUseProgram(gl, false);
+
+ if(DEBUG) {
+ System.err.println("HWRegionRenderer initialized: " + Thread.currentThread()+" "+st);
+ }
+ initialized = true;
+ return true;
+ }
+
+ public float getAlpha() {
+ return alpha;
+ }
+ public void setAlpha(float alpha_t) {
+ alpha = alpha_t;
+ }
+
+ public void setColor(float r, float g, float b){
+ color.put(r);
+ color.put(g);
+ color.put(b);
+ color.rewind();
+ }
+
+ public void rotate(float angle, float x, float y, float z){
+ pmvMatrix.glRotatef(angle, x, y, z);
+ }
+ public void translate(float x, float y, float z){
+ pmvMatrix.glTranslatef(x, y, z);
+ }
+
+ public void resetMatrix(){
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+ }
+
+ /**
+ * @param drawable
+ * @param angle
+ * @param ratio
+ * @param near
+ * @param far
+ * @return
+ */
+ public boolean reshape(GLAutoDrawable drawable, float angle, float ratio, float near, float far){
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.gluPerspective(angle, ratio, near, far);
+
+ if(null==st) {
+ if(DEBUG){
+ System.err.println("HWRegionRenderer: Shader State is null, or not");
+ }
+ return false;
+ }
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ st.glUseProgram(gl, true);
+ GLUniformData ud = st.getUniform("mgl_PMVMatrix");
+ if(null!=ud) {
+ st.glUniform(gl, ud);
+ }
+ st.glUseProgram(gl, false);
+ return true;
+ }
+
+ private void initShader(GL2ES2 gl) {
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, HwRegionRenderer.class,
+ "shader", "shader/bin", "curverenderer");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, HwRegionRenderer.class,
+ "shader", "shader/bin", "curverenderer");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("HWRegionRenderer: Couldn't link program: "+sp);
+ }
+
+ st = new ShaderState();
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+ }
+
+ private Region createRegion(OutlineShape outlineShape) {
+ Region region = RegionFactory.create(context, st, regionType);
+
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle<PointTex>> triangles = (ArrayList<Triangle<PointTex>>) outlineShape.triangulate(sharpness);
+ ArrayList<PointTex> vertices = (ArrayList<PointTex>) outlineShape.getVertices();
+ region.addVertices(vertices);
+ region.addTriangles(triangles);
+
+ region.update();
+ return region;
+ }
+
+ private Region createRegion(OutlineShape[] outlineShapes) {
+ Region region = RegionFactory.create(context, st, regionType);
+
+ int numVertices = region.getNumVertices();
+
+ for(OutlineShape outlineShape:outlineShapes){
+ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS);
+
+ ArrayList<Triangle<PointTex>> triangles = outlineShape.triangulate(sharpness);
+ region.addTriangles(triangles);
+
+ ArrayList<PointTex> vertices = outlineShape.getVertices();
+ for(PointTex vert:vertices){
+ vert.setId(numVertices++);
+ }
+ region.addVertices(vertices);
+ }
+
+ region.update();
+ return region;
+ }
+
+
+ /** Render outline in 3D space at the position provided
+ * the triangles of the shapes will be generated, if not yet generated
+ * @param outlineShape the OutlineShape to Render.
+ * @param position the initial translation of the outlineShape.
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public void renderOutlineShape(OutlineShape outlineShape, float[] position) throws Exception{
+ if(!initialized){
+ throw new Exception("HWRegionRenderer: not initialized!");
+ }
+ int hashCode = getHashCode(outlineShape);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(outlineShape);
+ regions.put(hashCode, region);
+ }
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ st.glUseProgram(gl, true);
+ GLUniformData ud = st.getUniform("mgl_PMVMatrix");
+ if(null!=ud) {
+ st.glUniform(gl, ud);
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_alpha", alpha))) {
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ GLUniformData gcolorUD = st.getUniform("g_color");
+ if(null!=gcolorUD) {
+ st.glUniform(gl, gcolorUD);
+ }
+ if(!st.glUniform(gl, new GLUniformData("a_strength", strength))) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ region.render(null, 0, 0, 0);
+ st.glUseProgram(gl, false);
+ }
+
+ /** Render a list of Outline shapes combined in one region
+ * at the position provided the triangles of the
+ * shapes will be generated, if not yet generated
+ * @param outlineShapes the list of OutlineShapes to Render.
+ * @param position the initial translation of the outlineShapes.
+ * @throws Exception if HwRegionRenderer not initialized
+ */
+ public void renderOutlineShapes(OutlineShape[] outlineShapes, float[] position) throws Exception{
+ if(!initialized){
+ throw new Exception("HWRegionRenderer: not initialized!");
+ }
+
+ int hashCode = getHashCode(outlineShapes);
+ Region region = regions.get(hashCode);
+
+ if(null == region) {
+ region = createRegion(outlineShapes);
+ regions.put(hashCode, region);
+ }
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ st.glUseProgram(gl, true);
+ GLUniformData ud = st.getUniform("mgl_PMVMatrix");
+ if(null!=ud) {
+ st.glUniform(gl, ud);
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_alpha", alpha))) {
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ GLUniformData gcolorUD = st.getUniform("g_color");
+ if(null!=gcolorUD) {
+ st.glUniform(gl, gcolorUD);
+ }
+ if(!st.glUniform(gl, new GLUniformData("a_strength", strength))) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+ region.render(null, 0, 0, 0);
+ st.glUseProgram(gl, false);
+ }
+
+ private int getHashCode(OutlineShape outlineShape){
+ return outlineShape.hashCode();
+ }
+
+ private int getHashCode(OutlineShape[] outlineShapes){
+ int hashcode = 0;
+ for(OutlineShape outlineShape:outlineShapes){
+ hashcode += getHashCode(outlineShape);
+ }
+ return hashcode;
+ }
+
+ /** Clears the cached string curves
+ * and destorys underlying buffers
+ */
+ public void clearCached() {
+ Iterator<Region> iterator = regions.values().iterator();
+ while(iterator.hasNext()){
+ Region region = iterator.next();
+ region.destroy();
+ }
+ regions.clear();
+ }
+}
diff --git a/src/com/jogamp/graph/curve/OutlineShape.java b/src/com/jogamp/graph/curve/OutlineShape.java
new file mode 100755
index 000000000..d939d7427
--- /dev/null
+++ b/src/com/jogamp/graph/curve/OutlineShape.java
@@ -0,0 +1,244 @@
+/**
+ * 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 com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import jogamp.graph.math.VectorFloatUtil;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Line;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Point;
+import com.jogamp.graph.geom.PointTex;
+
+import com.jogamp.graph.curve.tess.CDTriangulator2D;
+
+/** A Generic shape objects which is defined by a list of Outlines.
+ * This Shape can be transformed to Triangulations.
+ * The list of triangles generated are render-able by a Region object.
+ * The triangulation produced by this Shape will define the
+ * closed region defined by the outlines.
+ *
+ * One or more OutlineShape Object can be associated to a region
+ * this is left high-level representation of the Objects. For
+ * possible Optimizations.
+ *
+ * @see Region
+ */
+public class OutlineShape {
+ public static final int QUADRATIC_NURBS = 10;
+ private final Point.Factory<? extends PointTex> pointFactory;
+ private ArrayList<Outline<PointTex>> outlines = new ArrayList<Outline<PointTex>>(3);
+
+ /** Create a new Outline based Shape
+ */
+ public OutlineShape(Point.Factory<? extends PointTex> factory) {
+ pointFactory = factory;
+ outlines.add(new Outline<PointTex>());
+ }
+
+ public final Point.Factory<? extends PointTex> pointFactory() { return pointFactory; }
+
+ /** Add a new empty outline
+ * to the shape, this new outline will
+ * be placed at the end of the outline list.
+ */
+ public void addEmptyOutline(){
+ outlines.add(new Outline<PointTex>());
+ }
+
+ /** Adds an outline to the OutlineShape object
+ * if last outline of the shape is empty, it will replace
+ * that last Outline with the new one. If outline is empty,
+ * it will do nothing.
+ * @param outline an Outline object
+ */
+ public void addOutline(Outline<PointTex> outline){
+ if(outline.isEmpty()){
+ return;
+ }
+ if(getLastOutline().isEmpty()){
+ outlines.remove(getLastOutline());
+ }
+ outlines.add(outline);
+ }
+
+ /** Adds a vertex to the last open outline in the
+ * shape
+ * @param point
+ */
+ public final void addVertex(PointTex point){
+ getLastOutline().addVertex(point);
+ }
+
+ public final void addVertex(float x, float y, boolean onCurve) {
+ getLastOutline().addVertex(pointFactory, x, y, onCurve);
+ }
+
+ public final void addVertex(float x, float y, float z, boolean onCurve) {
+ getLastOutline().addVertex(pointFactory, x, y, z, onCurve);
+ }
+
+ public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ getLastOutline().addVertex(pointFactory, coordsBuffer, offset, length, onCurve);
+ }
+
+ /** Closes the last outline in the shape
+ * if last vertex is not equal to first vertex.
+ * A new temp vertex is added at the end which
+ * is equal to the first.
+ */
+ public void closeLastOutline(){
+ getLastOutline().setClosed(true);
+ }
+
+ /** Get the last added outline to the list
+ * of outlines that define the shape
+ * @return the last outline
+ */
+ public final Outline<PointTex> getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+ /** Make sure that the outlines represent
+ * the specified destinationType, if not
+ * transform outlines to destinationType.
+ * @param destinationType The curve type needed
+ */
+ public void transformOutlines(int destinationType){
+ if(destinationType == QUADRATIC_NURBS){
+ transformOutlinesQuadratic();
+ }
+ }
+
+ private void transformOutlinesQuadratic(){
+ ArrayList<Outline<PointTex>> newOutlines = new ArrayList<Outline<PointTex>>(3);
+
+ /**loop over the outlines and make sure no
+ * adj off-curve vertices
+ */
+ for(Outline<PointTex> outline:outlines){
+ Outline<PointTex> newOutline = new Outline<PointTex>();
+
+ ArrayList<PointTex> vertices = outline.getVertices();
+ int size =vertices.size()-1;
+ for(int i=0;i<size;i++){
+ PointTex currentVertex = vertices.get(i);
+ PointTex nextVertex = vertices.get((i+1)%size);
+ if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
+ newOutline.addVertex(currentVertex);
+
+ float[] newCoords = VectorFloatUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ newOutline.addVertex(pointFactory, newCoords, 0, 3, true);
+ }
+ else {
+ newOutline.addVertex(currentVertex);
+ }
+ }
+ newOutlines.add(newOutline);
+ }
+ outlines = newOutlines;
+ }
+
+ private void generateVertexIds(){
+ int maxVertexId = 0;
+ for(Outline<PointTex> outline:outlines){
+ ArrayList<PointTex> vertices = outline.getVertices();
+ for(PointTex vert:vertices){
+ vert.setId(maxVertexId);
+ maxVertexId++;
+ }
+ }
+ }
+
+ /** @return the list of vertices associated with the
+ * {@code Outline} list of this object
+ */
+ public ArrayList<PointTex> getVertices(){
+ ArrayList<PointTex> vertices = new ArrayList<PointTex>();
+ for(Outline<PointTex> polyline:outlines){
+ vertices.addAll(polyline.getVertices());
+ }
+ return vertices;
+ }
+
+
+ /** Generates the lines the define the noncurved
+ * parts of this graph
+ * @return arraylist of lines
+ */
+ public ArrayList<Line<PointTex>> getLines(){
+ ArrayList<Line<PointTex>> lines = new ArrayList<Line<PointTex>>();
+ for(Outline<PointTex> outline:outlines){
+ ArrayList<PointTex> outVertices = outline.getVertices();
+ int size = outVertices.size();
+ for(int i=0; i < size; i++) {
+ PointTex currentVertex = outVertices.get(i);
+ if(currentVertex.isOnCurve()) {
+ PointTex v2 = outVertices.get((i+1)%size);
+ if(v2.isOnCurve()){
+ lines.add(new Line<PointTex>(currentVertex, v2));
+ }
+ }
+ }
+ }
+ return lines;
+ }
+
+ /** Triangluate the graph object
+ * @param sharpness sharpness of the curved regions default = 0.5
+ */
+ public ArrayList<Triangle<PointTex>> triangulate(float sharpness){
+ if(outlines.size() == 0){
+ return null;
+ }
+ sortOutlines();
+ generateVertexIds();
+
+ CDTriangulator2D<PointTex> triangulator2d = new CDTriangulator2D<PointTex>(sharpness);
+
+ for(int index = 0; index< outlines.size();index++){
+ Outline<PointTex> outline = outlines.get(index);
+ triangulator2d.addCurve(outline);
+ }
+
+ ArrayList<Triangle<PointTex>> triangles = triangulator2d.generateTriangulation();
+ triangulator2d.reset();
+
+ return triangles;
+ }
+
+ /** Sort the outlines from large
+ * to small depending on the AABox
+ */
+ private void sortOutlines() {
+ Collections.sort(outlines);
+ Collections.reverse(outlines);
+ }
+}
diff --git a/src/com/jogamp/graph/curve/Region.java b/src/com/jogamp/graph/curve/Region.java
new file mode 100755
index 000000000..44f426313
--- /dev/null
+++ b/src/com/jogamp/graph/curve/Region.java
@@ -0,0 +1,125 @@
+/**
+ * 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 com.jogamp.graph.curve;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.PointTex;
+import com.jogamp.opengl.util.PMVMatrix;
+
+/** A Region is the OGL binding of one or more OutlineShapes
+ * Defined by its vertices and generated triangles. The Region
+ * defines the final shape of the OutlineShape(s), which shall produced a shaded
+ * region on the screen.
+ *
+ * Implementations of the Region shall take care of the OGL
+ * binding of the depending on its context, profile.
+ *
+ * @see RegionFactory, OutlineShape
+ */
+public interface Region {
+ /** The vertices index in an OGL object
+ */
+ public static int VERTEX_POS_INDX = 0;
+
+ /** The Texture Coord index in an OGL object
+ */
+ public static int TEX_COORD = 1;
+
+ public static int SINGLE_PASS = 10;
+ public static int TWO_PASS = 20;
+
+ /** Updates a graph region by updating the ogl related
+ * objects for use in rendering. if called for the first time
+ * it initialize the objects.
+ */
+ public void update();
+
+ /** Renders the associated OGL objects specifying
+ * current width/hight of window for multi pass rendering
+ * of the region.
+ * @param matrix current pmv matrix.
+ * @param vp_width current screen width
+ * @param vp_height current screen height
+ * @param width texture width for mp rendering
+ *
+ * @see update()
+ */
+ public void render(PMVMatrix matrix, int vp_width, int vp_height, int width);
+
+ /** Adds a list of {@code Triangle} objects to the Region
+ * These triangles are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param tris an arraylist of triangle objects
+ *
+ * @see update()
+ */
+ public void addTriangles(ArrayList<Triangle<PointTex>> tris);
+
+ /** Get the current number of vertices associated
+ * with this region. This number is not necessary equal to
+ * the OGL binded number of vertices.
+ * @return vertices count
+ *
+ * @see isDirty()
+ */
+ public int getNumVertices();
+
+ /** Adds a list of {@code Vertex} objects to the Region
+ * These vertices are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param verts an arraylist of vertex objects
+ *
+ * @see update()
+ */
+ public void addVertices(ArrayList<PointTex> verts);
+
+ /** Check if this region is dirty. A region is marked dirty
+ * when new Vertices, Triangles, and or Lines are added after a
+ * call to update()
+ * @return true if region is Dirty, false otherwise
+ *
+ * @see update();
+ */
+ public boolean isDirty();
+
+ /** Delete and clean the associated OGL
+ * objects
+ */
+ public void destroy();
+
+ public boolean isFlipped();
+
+ /** Set if the y coordinate of the region should be flipped
+ * {@code y=-y} used mainly for fonts since they use opposite vertex
+ * as origion
+ * @param flipped flag if the coordinate is flipped defaults to false.
+ */
+ public void setFlipped(boolean flipped);
+}
diff --git a/src/com/jogamp/graph/curve/RegionFactory.java b/src/com/jogamp/graph/curve/RegionFactory.java
new file mode 100755
index 000000000..158f9db5b
--- /dev/null
+++ b/src/com/jogamp/graph/curve/RegionFactory.java
@@ -0,0 +1,58 @@
+/**
+ * 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 com.jogamp.graph.curve;
+
+import javax.media.opengl.GLContext;
+
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+import jogamp.graph.curve.opengl.VBORegionSPES2;
+import jogamp.graph.curve.opengl.VBORegion2PGL3;
+
+
+/** RegionFactory to create a Context specific Region implementation.
+ *
+ * @see Region
+ */
+public class RegionFactory {
+
+ /**Create a Region based on the GLContext attached
+ * @param context the current opengl context
+ * @param st the shader state object
+ * @param type can be one of Region.SINGLE_PASS or Region.TWO_PASS
+ * @return region
+ */
+ public static Region create(GLContext context, ShaderState st, int type){
+ if(Region.TWO_PASS == type && context.isGL3()){
+ return new VBORegion2PGL3(context, st);
+ }
+ else{
+ return new VBORegionSPES2(context);
+ }
+ }
+}
diff --git a/src/com/jogamp/graph/curve/shader/curverenderer.fp b/src/com/jogamp/graph/curve/shader/curverenderer.fp
new file mode 100644
index 000000000..2b3a0ce1d
--- /dev/null
+++ b/src/com/jogamp/graph/curve/shader/curverenderer.fp
@@ -0,0 +1,99 @@
+//#version 100
+
+uniform float p1y;
+uniform float g_alpha;
+uniform vec3 g_color;
+uniform float a_strength;
+
+varying vec2 v_texCoord;
+
+vec3 b_color = vec3(0.0, 0.0, 0.0);
+
+uniform sampler2D texture;
+vec4 weights = vec4(0.075, 0.06, 0.045, 0.025);
+
+void main (void)
+{
+ vec2 rtex = vec2(abs(v_texCoord.x),abs(v_texCoord.y));
+ vec3 c = g_color;
+
+ float alpha = 0.0;
+
+ if((v_texCoord.x == 0.0) && (v_texCoord.y == 0.0)){
+ alpha = g_alpha;
+ }
+ else if((v_texCoord.x >= 5.0)){
+ vec2 dfx = dFdx(v_texCoord);
+ vec2 dfy = dFdy(v_texCoord);
+
+ vec2 size = 1.0/textureSize(texture,0); //version 130
+ rtex -= 5.0;
+ vec4 t = texture2D(texture, rtex)* 0.18;
+
+ t += texture2D(texture, rtex + size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(1, 0)))*weights.x;
+ t += texture2D(texture, rtex + size*(vec2(0, 1)))*weights.x;
+ t += texture2D(texture, rtex - size*(vec2(0, 1)))*weights.x;
+
+ t += texture2D(texture, rtex + 2.0*size*(vec2(1, 0))) *weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(1, 0)))*weights.y;
+ t += texture2D(texture, rtex + 2.0*size*(vec2(0, 1)))*weights.y;
+ t += texture2D(texture, rtex - 2.0*size*(vec2(0, 1)))*weights.y;
+
+ t += texture2D(texture, rtex + 3.0*size*(vec2(1, 0))) *weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(1, 0)))*weights.z;
+ t += texture2D(texture, rtex + 3.0*size*(vec2(0, 1)))*weights.z;
+ t += texture2D(texture, rtex - 3.0*size*(vec2(0, 1)))*weights.z;
+
+ t += texture2D(texture, rtex + 4.0*size*(vec2(1, 0))) *weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(1, 0)))*weights.w;
+ t += texture2D(texture, rtex + 4.0*size*(vec2(0, 1)))*weights.w;
+ t += texture2D(texture, rtex - 4.0*size*(vec2(0, 1)))*weights.w;
+
+ if(t.w == 0.0){
+ discard;
+ }
+
+ c = t.xyz;
+ alpha = g_alpha* t.w;
+ }
+ ///////////////////////////////////////////////////////////
+ else if ((v_texCoord.x > 0.0) && (rtex.y > 0.0 || rtex.x == 1.0)){
+ vec2 dtx = dFdx(rtex);
+ vec2 dty = dFdy(rtex);
+
+ rtex.y -= 0.1;
+ if(rtex.y < 0.0) {
+ if(v_texCoord.y < 0.0)
+ discard;
+ else{
+ rtex.y = 0.0;
+ }
+ }
+
+ vec2 f = vec2((dtx.y - 2.0*p1y*dtx.x + 4.0*p1y*rtex.x*dtx.x), (dty.y - 2.0*p1y*dty.x + 4.0*p1y*rtex.x*dty.x));
+
+ float position = rtex.y - ((2.0 * rtex.x * p1y) * (1.0 - rtex.x));
+ float d = position/(length(f));
+
+ float a = (0.5 - d * sign(v_texCoord.y));
+
+
+ if (a >= 1.0) {
+ alpha = g_alpha;
+ // c = vec3(1.0,1.0,1.0);
+ }
+ else if (a <= 0.0) {
+ alpha = 0.0;//discard;
+ // c = vec3(0.0,0.0,0.0);
+
+ }
+ else {
+ alpha = g_alpha*a;
+ // c = vec3(a,a,a);
+ mix(b_color,g_color, a);
+ }
+ }
+
+ gl_FragColor = vec4(c, alpha);
+}
diff --git a/src/com/jogamp/graph/curve/shader/curverenderer.vp b/src/com/jogamp/graph/curve/shader/curverenderer.vp
new file mode 100644
index 000000000..bc9ecb41e
--- /dev/null
+++ b/src/com/jogamp/graph/curve/shader/curverenderer.vp
@@ -0,0 +1,13 @@
+//#version 100
+
+uniform mat4 mgl_PMVMatrix[2];
+attribute vec4 v_position;
+attribute vec2 texCoord;
+
+varying vec2 v_texCoord;
+
+void main(void)
+{
+ gl_Position = mgl_PMVMatrix[0] * mgl_PMVMatrix[1] * v_position;
+ v_texCoord = texCoord.st;
+} \ No newline at end of file
diff --git a/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java
new file mode 100644
index 000000000..936965f0c
--- /dev/null
+++ b/src/com/jogamp/graph/curve/tess/CDTriangulator2D.java
@@ -0,0 +1,213 @@
+/**
+ * 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 com.jogamp.graph.curve.tess;
+
+import java.util.ArrayList;
+
+import jogamp.graph.curve.tess.GraphOutline;
+import jogamp.graph.curve.tess.GraphPoint;
+import jogamp.graph.curve.tess.Loop;
+import jogamp.graph.math.VectorFloatUtil;
+
+import com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.PointTex;
+import jogamp.opengl.Debug;
+
+/** Constrained Delaunay Triangulation
+ * implementation of a list of Outlines that define a set of
+ * Closed Regions with optional n holes.
+ *
+ */
+public class CDTriangulator2D <T extends PointTex> {
+
+ protected static final boolean DEBUG = Debug.debug("Triangulation");
+
+ private float sharpness = 0.5f;
+ private ArrayList<Loop<T>> loops;
+ private ArrayList<T> vertices;
+
+ private ArrayList<Triangle<T>> triangles;
+ private int maxTriID = 0;
+
+
+ public CDTriangulator2D() {
+ this(0.5f);
+ }
+
+ /** Constructor for a new Delaunay triangulator
+ * @param curveSharpness the curvature around
+ * the off-curve vertices
+ */
+ public CDTriangulator2D(float curveSharpness) {
+ this.sharpness = curveSharpness;
+ reset();
+ }
+
+ /** Reset the triangulation to initial state
+ * Clearing cached data
+ */
+ public void reset() {
+ maxTriID = 0;
+ vertices = new ArrayList<T>();
+ triangles = new ArrayList<Triangle<T>>(3);
+ loops = new ArrayList<Loop<T>>();
+ }
+
+ /** Add a curve to the list of profiles provided
+ * @param polyline a bounding Outline
+ */
+ public void addCurve(Outline<T> polyline){
+ Loop<T> loop = null;
+
+ if(!loops.isEmpty()){
+ loop = getContainerLoop(polyline);
+ }
+
+ if(loop == null) {
+ GraphOutline<T> outline = new GraphOutline<T>(polyline);
+ GraphOutline<T> innerPoly = extractBoundaryTriangles(outline, false);
+ vertices.addAll(polyline.getVertices());
+ loop = new Loop<T>(innerPoly, VectorFloatUtil.CCW);
+ loops.add(loop);
+ }
+ else {
+ GraphOutline<T> outline = new GraphOutline<T>(polyline);
+ GraphOutline<T> innerPoly = extractBoundaryTriangles(outline, true);
+ vertices.addAll(innerPoly.getPoints());
+ loop.addConstraintCurve(innerPoly);
+ }
+ }
+
+ /** Generate the triangulation of the provided
+ * List of Outlines
+ */
+ public ArrayList<Triangle<T>> generateTriangulation(){
+ for(int i=0;i<loops.size();i++) {
+ Loop<T> loop = loops.get(i);
+ int numTries = 0;
+ int size = loop.computeLoopSize();
+ while(!loop.isSimplex()){
+ Triangle<T> tri = null;
+ if(numTries > size){
+ tri = loop.cut(false);
+ }
+ else{
+ tri = loop.cut(true);
+ }
+ numTries++;
+
+ if(tri != null) {
+ numTries = 0;
+ size--;
+ tri.setId(maxTriID++);
+ triangles.add(tri);
+ if(DEBUG){
+ System.err.println(tri);
+ }
+ }
+ if(numTries > size*2){
+ if(DEBUG){
+ System.err.println("Triangulation not complete!");
+ }
+ break;
+ }
+ }
+ Triangle<T> tri = loop.cut(true);
+ if(tri != null)
+ triangles.add(tri);
+ }
+ return triangles;
+ }
+
+ @SuppressWarnings("unchecked")
+ private GraphOutline<T> extractBoundaryTriangles(GraphOutline<T> outline, boolean hole){
+ GraphOutline<T> innerOutline = new GraphOutline<T>();
+ ArrayList<GraphPoint<T>> outVertices = outline.getGraphPoint();
+ int size = outVertices.size();
+ for(int i=0; i < size; i++) {
+ GraphPoint<T> currentVertex = outVertices.get(i);
+ GraphPoint<T> gv0 = outVertices.get((i+size-1)%size);
+ GraphPoint<T> gv2 = outVertices.get((i+1)%size);
+ GraphPoint<T> gv1 = currentVertex;
+
+ if(!currentVertex.getPoint().isOnCurve()) {
+ T v0 = (T) gv0.getPoint().clone();
+ T v2 = (T) gv2.getPoint().clone();
+ T v1 = (T) gv1.getPoint().clone();
+
+ gv0.setBoundaryContained(true);
+ gv1.setBoundaryContained(true);
+ gv2.setBoundaryContained(true);
+
+ Triangle<T> t= null;
+ boolean holeLike = false;
+ if(VectorFloatUtil.ccw(v0,v1,v2)){
+ t = new Triangle<T>(v0, v1, v2);
+ }
+ else {
+ holeLike = true;
+ t = new Triangle<T>(v2, v1, v0);
+ }
+ t.setId(maxTriID++);
+ triangles.add(t);
+
+ if(hole || holeLike) {
+ v0.setTexCoord(0, -0.1f);
+ v2.setTexCoord(1, -0.1f);
+ v1.setTexCoord(0.5f, -1*sharpness -0.1f);
+ innerOutline.addVertex(currentVertex);
+ }
+ else {
+ v0.setTexCoord(0, 0.1f);
+ v2.setTexCoord(1, 0.1f);
+ v1.setTexCoord(0.5f, sharpness+0.1f);
+ }
+ }
+ else {
+ if(!gv2.getPoint().isOnCurve() || !gv0.getPoint().isOnCurve()){
+ currentVertex.setBoundaryContained(true);
+ }
+ innerOutline.addVertex(currentVertex);
+ }
+ }
+ return innerOutline;
+ }
+
+ private Loop<T> getContainerLoop(Outline<T> polyline){
+ T v = polyline.getVertex(0);
+
+ for (Loop<T> loop:loops){
+ if(loop.checkInside(v)){
+ return loop;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/com/jogamp/graph/curve/text/HwTextRenderer.java b/src/com/jogamp/graph/curve/text/HwTextRenderer.java
new file mode 100644
index 000000000..5813225e4
--- /dev/null
+++ b/src/com/jogamp/graph/curve/text/HwTextRenderer.java
@@ -0,0 +1,367 @@
+/**
+ * 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 com.jogamp.graph.curve.text;
+
+import java.nio.FloatBuffer;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLContext;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLUniformData;
+import javax.media.opengl.fixedfunc.GLMatrixFunc;
+
+import jogamp.graph.curve.text.GlyphString;
+import jogamp.graph.font.typecast.TypecastFontFactory;
+
+import com.jogamp.common.util.ReflectionUtil;
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.font.FontFactory;
+import com.jogamp.graph.geom.plane.AffineTransform;
+import com.jogamp.graph.geom.plane.Path2D;
+import com.jogamp.graph.geom.Point;
+import com.jogamp.graph.geom.PointTex;
+import com.jogamp.graph.geom.opengl.Vertex;
+import jogamp.opengl.Debug;
+import com.jogamp.opengl.util.PMVMatrix;
+import com.jogamp.opengl.util.glsl.ShaderCode;
+import com.jogamp.opengl.util.glsl.ShaderProgram;
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+public class HwTextRenderer {
+ protected static final boolean DEBUG = Debug.debug("TextRenderer");
+ static final boolean FONTTOOL_CUSTOM = false;
+
+ private static FontFactory fontFactory;
+
+ static {
+ FontFactory _fontFactory = null;
+
+ if(FONTTOOL_CUSTOM) {
+ _fontFactory = (FontFactory) ReflectionUtil.createInstance("jogamp.graph.font.ttf.TTFFontFactory", HwTextRenderer.class.getClassLoader());
+ if(null!=_fontFactory) {
+ System.err.println("Using custom font tool");
+ }
+ }
+ if(null==_fontFactory) {
+ _fontFactory = new TypecastFontFactory();
+ }
+ fontFactory = _fontFactory;
+ }
+
+
+ public static FontFactory getFontFactory() {
+ return fontFactory;
+ }
+
+ private ShaderState st;
+ private PMVMatrix pmvMatrix = new PMVMatrix();
+
+ /**Sharpness is equivalent to the value of t value of texture coord
+ * on the off-curve vertex. The high value of sharpness will
+ * result in high curvature.
+ */
+ private float sharpness = 0.5f;
+ private float alpha = 1.0f;
+ private float strength = 1.8f;
+ private boolean initialized = false;
+
+
+ private int regionType = Region.SINGLE_PASS;
+ private GLContext context;
+ private FloatBuffer color = FloatBuffer.allocate(3);
+ private HashMap<String, GlyphString> strings = new HashMap<String, GlyphString>();
+ private final Point.Factory<? extends PointTex> pointFactory;
+
+ int win_width = 0;
+ int win_height = 0;
+
+ /** Create a Hardware accelerated Text Renderer
+ * @param context OpenGL rendering context
+ * @param factory optional Point.Factory for PointTex construction. Default is Vertex.Factory.
+ */
+ public HwTextRenderer(GLContext context, Point.Factory<? extends PointTex> factory, int type) {
+ this.pointFactory = (null != factory) ? factory : Vertex.factory();
+ this.context = context;
+ this.regionType = type;
+ init(context, 0.5f);
+ }
+
+ public Font createFont(Point.Factory<? extends PointTex> factory, String name, int size) {
+ return fontFactory.createFont(factory, name, size);
+ }
+
+
+ public Font createFont(Point.Factory<? extends PointTex> factory,
+ String[] families,
+ String style,
+ String variant,
+ String weight,
+ String size) {
+ return fontFactory.createFont(factory, families, style, variant, weight, size);
+ }
+
+ /** initialize shaders and bindings for GPU based text Rendering, should
+ * be called only onceangle
+ * @param drawable the current drawable
+ * @param shapvalue shaprness around the off-curve vertices
+ * @return true if init succeeded, false otherwise
+ */
+ private boolean init(GLContext context, float sharpvalue){
+ if(initialized){
+ if(DEBUG) {
+ System.err.println("HWTextRenderer: Already initialized!");
+ }
+ return true;
+ }
+ sharpness = sharpvalue;
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+
+ boolean VBOsupported = gl.isFunctionAvailable("glGenBuffers") &&
+ gl.isFunctionAvailable("glBindBuffer") &&
+ gl.isFunctionAvailable("glBufferData") &&
+ gl.isFunctionAvailable("glDrawElements") &&
+ gl.isFunctionAvailable("glVertexAttribPointer") &&
+ gl.isFunctionAvailable("glDeleteBuffers");
+
+ if(DEBUG) {
+ System.err.println("HWTextRenderer: VBO Supported = " + VBOsupported);
+ }
+
+ if(!VBOsupported){
+ return false;
+ }
+
+ gl.setSwapInterval(1);
+
+ gl.glEnable(GL2ES2.GL_BLEND);
+ gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA);
+
+ initShader(gl);
+
+ st.glUseProgram(gl, true);
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ resetMatrix();
+
+ if(!st.glUniform(gl, new GLUniformData("mgl_PMVMatrix", 4, 4, pmvMatrix.glGetPMvMatrixf()))) {
+ if(DEBUG){
+ System.err.println("Error setting PMVMatrix in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("p1y", sharpness))) {
+ if(DEBUG){
+ System.err.println("Error setting sharpness in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_alpha", alpha))) {
+ if(DEBUG){
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_color", 3, color))) {
+ if(DEBUG){
+ System.err.println("Error setting global color in shader: "+st);
+ }
+ return false;
+ }
+ if(!st.glUniform(gl, new GLUniformData("a_strength", strength))) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+
+ st.glUseProgram(gl, false);
+
+ if(DEBUG) {
+ System.err.println("HWTextRenderer initialized: " + Thread.currentThread()+" "+st);
+ }
+ initialized = true;
+ return true;
+ }
+
+ public float getAlpha() {
+ return alpha;
+ }
+ public void setAlpha(float alpha_t) {
+ alpha = alpha_t;
+ }
+
+ public void setColor(float r, float g, float b){
+ color.put(r);
+ color.put(g);
+ color.put(b);
+ color.rewind();
+ }
+
+ public void rotate(float angle, float x, float y, float z){
+ pmvMatrix.glRotatef(angle, x, y, z);
+ }
+ public void translate(float x, float y, float z){
+ pmvMatrix.glTranslatef(x, y, z);
+ }
+
+ public void resetMatrix(){
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
+ pmvMatrix.glLoadIdentity();
+ }
+
+ /**
+ * @param drawable
+ * @param angle
+ * @param ratio
+ * @param near
+ * @param far
+ * @return
+ */
+ public boolean reshape(GLAutoDrawable drawable, float angle, int width, int height, float near, float far){
+ win_width = width;
+ win_height = height;
+ float ratio = (float)width/(float)height;
+ pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
+ pmvMatrix.glLoadIdentity();
+ pmvMatrix.gluPerspective(angle, ratio, near, far);
+
+ if(null==st) {
+ if(DEBUG){
+ System.err.println("HWTextRenderer: Shader State is null, or not");
+ }
+ return false;
+ }
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ st.glUseProgram(gl, true);
+ GLUniformData ud = st.getUniform("mgl_PMVMatrix");
+ if(null!=ud) {
+ st.glUniform(gl, ud);
+ }
+ st.glUseProgram(gl, false);
+ return true;
+ }
+
+ private void initShader(GL2ES2 gl) {
+ ShaderCode rsVp = ShaderCode.create(gl, GL2ES2.GL_VERTEX_SHADER, 1, HwTextRenderer.class,
+ "../shader", "../shader/bin", "curverenderer");
+ ShaderCode rsFp = ShaderCode.create(gl, GL2ES2.GL_FRAGMENT_SHADER, 1, HwTextRenderer.class,
+ "../shader", "../shader/bin", "curverenderer");
+
+ ShaderProgram sp = new ShaderProgram();
+ sp.add(rsVp);
+ sp.add(rsFp);
+
+ if(!sp.link(gl, System.err)) {
+ throw new GLException("HWTextRenderer: Couldn't link program: "+sp);
+ }
+
+ st = new ShaderState();
+ st.attachShaderProgram(gl, sp);
+ gl.glBindAttribLocation(sp.id(), 0, "v_position");
+ gl.glBindAttribLocation(sp.id(), 1, "texCoord");
+ }
+
+ private GlyphString createString(Font font, String str) {
+ AffineTransform affineTransform = new AffineTransform(pointFactory);
+
+ Path2D[] paths = new Path2D[str.length()];
+ font.getOutline(str, affineTransform, paths);
+
+ GlyphString glyphString = new GlyphString(pointFactory, font.getName(), str);
+ glyphString.createfromFontPath(paths, affineTransform);
+
+ glyphString.generateRegion(context, sharpness, st, regionType);
+ return glyphString;
+ }
+
+
+ /** Render the String in 3D space wrt to the font provided at the position provided
+ * the outlines will be generated, if not yet generated
+ * @param font font to be used
+ * @param str text to be rendered
+ * @param position the lower left corner of the string
+ * @param size texture size for multipass render
+ * @throws Exception if TextRenderer not initialized
+ */
+ public void renderString3D(Font font, String str, float[] position, int size) throws Exception{
+ if(!initialized){
+ throw new Exception("HWTextRenderer: not initialized!");
+ }
+ String fontStrHash = getTextHashCode(font, str);
+ GlyphString glyphString = strings.get(fontStrHash);
+ if(null == glyphString) {
+ glyphString = createString(font, str);
+ strings.put(fontStrHash, glyphString);
+ }
+
+ GL2ES2 gl = context.getGL().getGL2ES2();
+ st.glUseProgram(gl, true);
+ GLUniformData ud = st.getUniform("mgl_PMVMatrix");
+ if(null!=ud) {
+ st.glUniform(gl, ud);
+ }
+ if(!st.glUniform(gl, new GLUniformData("g_alpha", alpha))) {
+ System.err.println("Error setting global alpha in shader: "+st);
+ }
+ GLUniformData gcolorUD = st.getUniform("g_color");
+ if(null!=gcolorUD) {
+ st.glUniform(gl, gcolorUD);
+ }
+
+ if(!st.glUniform(gl, new GLUniformData("a_strength", strength))) {
+ System.err.println("Error setting antialias strength in shader: "+st);
+ }
+ glyphString.renderString3D(pmvMatrix, win_width, win_height, size);
+ st.glUseProgram(gl, false);
+ }
+
+ private String getTextHashCode(Font font, String str){
+ return "" + str.hashCode() + font.getSize();
+ }
+
+ /** Clears the cached string curves
+ * and destorys underlying buffers
+ */
+ public void clearCached() {
+ Iterator<GlyphString> iterator = strings.values().iterator();
+ while(iterator.hasNext()){
+ GlyphString glyphString = iterator.next();
+ glyphString.destroy();
+ }
+ strings.clear();
+ }
+}
diff --git a/src/com/jogamp/graph/math/Quaternion.java b/src/com/jogamp/graph/math/Quaternion.java
new file mode 100755
index 000000000..b77a5fa08
--- /dev/null
+++ b/src/com/jogamp/graph/math/Quaternion.java
@@ -0,0 +1,382 @@
+/**
+ * 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 com.jogamp.graph.math;
+
+import jogamp.graph.math.MathFloat;
+
+public class Quaternion {
+ protected float x,y,z,w;
+
+ public Quaternion(){
+
+ }
+
+ public Quaternion(float x, float y, float z, float w) {
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ }
+
+ /** Constructor to create a rotation based quaternion from two vectors
+ * @param vector1
+ * @param vector2
+ */
+ public Quaternion(float[] vector1, float[] vector2)
+ {
+ float theta = (float)MathFloat.acos(dot(vector1, vector2));
+ float[] cross = cross(vector1,vector2);
+ cross = normalizeVec(cross);
+
+ this.x = (float)MathFloat.sin(theta/2)*cross[0];
+ this.y = (float)MathFloat.sin(theta/2)*cross[1];
+ this.z = (float)MathFloat.sin(theta/2)*cross[2];
+ this.w = (float)MathFloat.cos(theta/2);
+ this.normalize();
+ }
+
+ /** Transform the rotational quaternion to axis based rotation angles
+ * @return new float[4] with ,theta,Rx,Ry,Rz
+ */
+ public float[] toAxis()
+ {
+ float[] vec = new float[4];
+ float scale = (float)MathFloat.sqrt(x * x + y * y + z * z);
+ vec[0] =(float) MathFloat.acos(w) * 2.0f;
+ vec[1] = x / scale;
+ vec[2] = y / scale;
+ vec[3] = z / scale;
+ return vec;
+ }
+
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ private float[] normalizeVec(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ private float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ private float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+ public float getW() {
+ return w;
+ }
+ public void setW(float w) {
+ this.w = w;
+ }
+ public float getX() {
+ return x;
+ }
+ public void setX(float x) {
+ this.x = x;
+ }
+ public float getY() {
+ return y;
+ }
+ public void setY(float y) {
+ this.y = y;
+ }
+ public float getZ() {
+ return z;
+ }
+ public void setZ(float z) {
+ this.z = z;
+ }
+
+ /** Add a quaternion
+ * @param q quaternion
+ */
+ public void add(Quaternion q)
+ {
+ x+=q.x;
+ y+=q.y;
+ z+=q.z;
+ }
+
+ /** Subtract a quaternion
+ * @param q quaternion
+ */
+ public void subtract(Quaternion q)
+ {
+ x-=q.x;
+ y-=q.y;
+ z-=q.z;
+ }
+
+ /** Divide a quaternion by a constant
+ * @param n a float to divide by
+ */
+ public void divide(float n)
+ {
+ x/=n;
+ y/=n;
+ z/=n;
+ }
+
+ /** Multiply this quaternion by
+ * the param quaternion
+ * @param q a quaternion to multiply with
+ */
+ public void mult(Quaternion q)
+ {
+ float w1 = w*q.w - (x*q.x + y*q.y + z*q.z);
+
+ float x1 = w*q.z + q.w*z + y*q.z - z*q.y;
+ float y1 = w*q.x + q.w*x + z*q.x - x*q.z;
+ float z1 = w*q.y + q.w*y + x*q.y - y*q.x;
+
+ w = w1;
+ x = x1;
+ y = y1;
+ z = z1;
+ }
+
+ /** Multiply a quaternion by a constant
+ * @param n a float constant
+ */
+ public void mult(float n)
+ {
+ x*=n;
+ y*=n;
+ z*=n;
+ }
+
+ /** Normalize a quaternion required if
+ * to be used as a rotational quaternion
+ */
+ public void normalize()
+ {
+ float norme = (float)MathFloat.sqrt(w*w + x*x + y*y + z*z);
+ if (norme == 0.0f)
+ {
+ w = 1.0f;
+ x = y = z = 0.0f;
+ }
+ else
+ {
+ float recip = 1.0f/norme;
+
+ w *= recip;
+ x *= recip;
+ y *= recip;
+ z *= recip;
+ }
+ }
+
+ /** Invert the quaternion If rotational,
+ * will produce a the inverse rotation
+ */
+ public void inverse()
+ {
+ float norm = w*w + x*x + y*y + z*z;
+
+ float recip = 1.0f/norm;
+
+ w *= recip;
+ x = -1*x*recip;
+ y = -1*y*recip;
+ z = -1*z*recip;
+ }
+
+ /** Transform this quaternion to a
+ * 4x4 column matrix representing the rotation
+ * @return new float[16] column matrix 4x4
+ */
+ public float[] toMatrix()
+ {
+ float[] matrix = new float[16];
+ matrix[0] = 1.0f - 2*y*y - 2*z*z;
+ matrix[1] = 2*x*y + 2*w*z;
+ matrix[2] = 2*x*z - 2*w*y;
+ matrix[3] = 0;
+
+ matrix[4] = 2*x*y - 2*w*z;
+ matrix[5] = 1.0f - 2*x*x - 2*z*z;
+ matrix[6] = 2*y*z + 2*w*x;
+ matrix[7] = 0;
+
+ matrix[8] = 2*x*z + 2*w*y;
+ matrix[9] = 2*y*z - 2*w*x;
+ matrix[10] = 1.0f - 2*x*x - 2*y*y;
+ matrix[11] = 0;
+
+ matrix[12] = 0;
+ matrix[13] = 0;
+ matrix[14] = 0;
+ matrix[15] = 1;
+ return matrix;
+ }
+
+ /** Set this quaternion from a Sphereical interpolation
+ * of two param quaternion, used mostly for rotational animation
+ * @param a initial quaternion
+ * @param b target quaternion
+ * @param t float between 0 and 1 representing interp.
+ */
+ public void slerp(Quaternion a,Quaternion b, float t)
+ {
+ float omega, cosom, sinom, sclp, sclq;
+ cosom = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
+ if ((1.0f+cosom) > MathFloat.E) {
+ if ((1.0f-cosom) > MathFloat.E) {
+ omega = (float)MathFloat.acos(cosom);
+ sinom = (float)MathFloat.sin(omega);
+ sclp = (float)MathFloat.sin((1.0f-t)*omega) / sinom;
+ sclq = (float)MathFloat.sin(t*omega) / sinom;
+ }
+ else {
+ sclp = 1.0f - t;
+ sclq = t;
+ }
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ w = sclp*a.w + sclq*b.w;
+ }
+ else {
+ x =-a.y;
+ y = a.x;
+ z =-a.w;
+ w = a.z;
+ sclp = MathFloat.sin((1.0f-t) * MathFloat.PI * 0.5f);
+ sclq = MathFloat.sin(t * MathFloat.PI * 0.5f);
+ x = sclp*a.x + sclq*b.x;
+ y = sclp*a.y + sclq*b.y;
+ z = sclp*a.z + sclq*b.z;
+ }
+ }
+
+ /** Check if this quaternion is empty, ie (0,0,0,1)
+ * @return true if empty, false otherwise
+ */
+ public boolean isEmpty()
+ {
+ if (w==1 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** Check if this quaternion represents an identity
+ * matrix, for rotation.
+ * @return true if it is an identity rep., false otherwise
+ */
+ public boolean isIdentity()
+ {
+ if (w==0 && x==0 && y==0 && z==0)
+ return true;
+ return false;
+ }
+
+ /** compute the quaternion from a 3x3 column matrix
+ * @param m 3x3 column matrix
+ */
+ public void setFromMatrix(float[] m) {
+ float T= m[0] + m[4] + m[8] + 1;
+ if (T>0){
+ float S = 0.5f / (float)MathFloat.sqrt(T);
+ w = 0.25f / S;
+ x = ( m[5] - m[7]) * S;
+ y = ( m[6] - m[2]) * S;
+ z = ( m[1] - m[3] ) * S;
+ }
+ else{
+ if ((m[0] > m[4])&(m[0] > m[8])) {
+ float S = MathFloat.sqrt( 1.0f + m[0] - m[4] - m[8] ) * 2f; // S=4*qx
+ w = (m[7] - m[5]) / S;
+ x = 0.25f * S;
+ y = (m[3] + m[1]) / S;
+ z = (m[6] + m[2]) / S;
+ }
+ else if (m[4] > m[8]) {
+ float S = MathFloat.sqrt( 1.0f + m[4] - m[0] - m[8] ) * 2f; // S=4*qy
+ w = (m[6] - m[2]) / S;
+ x = (m[3] + m[1]) / S;
+ y = 0.25f * S;
+ z = (m[7] + m[5]) / S;
+ }
+ else {
+ float S = MathFloat.sqrt( 1.0f + m[8] - m[0] - m[4] ) * 2f; // S=4*qz
+ w = (m[3] - m[1]) / S;
+ x = (m[6] + m[2]) / S;
+ y = (m[7] + m[5]) / S;
+ z = 0.25f * S;
+ }
+ }
+ }
+
+ /** Check if the the 3x3 matrix (param) is in fact
+ * an affine rotational matrix
+ * @param m 3x3 column matrix
+ * @return true if representing a rotational matrix, false otherwise
+ */
+ public boolean isRotationMatrix(float[] m) {
+ double epsilon = 0.01; // margin to allow for rounding errors
+ if (MathFloat.abs(m[0]*m[3] + m[3]*m[4] + m[6]*m[7]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[2] + m[3]*m[5] + m[6]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[2] + m[4]*m[5] + m[7]*m[8]) > epsilon) return false;
+ if (MathFloat.abs(m[0]*m[0] + m[3]*m[3] + m[6]*m[6] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[1]*m[1] + m[4]*m[4] + m[7]*m[7] - 1) > epsilon) return false;
+ if (MathFloat.abs(m[2]*m[2] + m[5]*m[5] + m[8]*m[8] - 1) > epsilon) return false;
+ return (MathFloat.abs(determinant(m)-1) < epsilon);
+ }
+ private float determinant(float[] m) {
+ return m[0]*m[4]*m[8] + m[3]*m[7]*m[2] + m[6]*m[1]*m[5] - m[0]*m[7]*m[5] - m[3]*m[1]*m[8] - m[6]*m[4]*m[2];
+ }
+}
diff --git a/src/demo/GPURegionNewtDemo01.java b/src/demo/GPURegionNewtDemo01.java
new file mode 100755
index 000000000..c728e74e5
--- /dev/null
+++ b/src/demo/GPURegionNewtDemo01.java
@@ -0,0 +1,230 @@
+/**
+ * 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 demo;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.HwRegionRenderer;
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.geom.opengl.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.FPSAnimator;
+
+/** Demonstrate the rendering of multiple outlines into one region/OutlineShape
+ * These Outlines are not necessary connected or contained.
+ * The output of this demo shows two identical shapes but the left one
+ * has some vertices with off-curve flag set to true, and the right allt he vertices
+ * are on the curve. Demos the Res. Independent Nurbs based Curve rendering
+ *
+ */
+public class GPURegionNewtDemo01 {
+ private static void create(){
+ new RegionNewtWindow();
+ }
+ public static void main(String[] args) {
+ create();
+ }
+}
+
+class RegionNewtWindow {
+ RegionGLListener regionGLListener = null;
+
+ public RegionNewtWindow(){
+ createWindow();
+ }
+ private void createWindow() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setDoubleBuffered(true);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ System.out.println(caps);
+ final GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(500, 500);
+
+ window.setTitle("GPU Curve Region Newt Demo 01");
+ regionGLListener = new RegionGLListener();
+ window.addGLEventListener(regionGLListener);
+
+ window.setVisible(true);
+
+ window.addKeyListener(new KeyListener() {
+ public void keyPressed(KeyEvent arg0) {
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ regionGLListener.zoomIn();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ regionGLListener.zoomOut();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ regionGLListener.move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ regionGLListener.move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ regionGLListener.move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ regionGLListener.move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ regionGLListener.rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ regionGLListener.rotate(-1);
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ });
+
+ FPSAnimator animator = new FPSAnimator(60);
+ animator.add(window);
+ window.addWindowListener(new WindowAdapter() {
+ public void windowDestroyNotify(WindowEvent arg0) {
+ System.exit(0);
+ };
+ });
+ animator.start();
+ }
+ private class RegionGLListener implements GLEventListener{
+ HwRegionRenderer regionRenderer = null;
+
+ OutlineShape outlineShape = null;
+
+ public RegionGLListener() {}
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShape = new OutlineShape(Vertex.factory());
+ outlineShape.addVertex(0.0f,-10.0f, true);
+ outlineShape.addVertex(15.0f,-10.0f, true);
+ outlineShape.addVertex(10.0f,5.0f, false);
+ outlineShape.addVertex(15.0f,10.0f, true);
+ outlineShape.addVertex(6.0f,15.0f, false);
+ outlineShape.addVertex(5.0f,8.0f, false);
+ outlineShape.addVertex(0.0f,10.0f,true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(5.0f,-5.0f,true);
+ outlineShape.addVertex(10.0f,-5.0f, false);
+ outlineShape.addVertex(10.0f,0.0f, true);
+ outlineShape.addVertex(5.0f,0.0f, false);
+ outlineShape.closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShape.addEmptyOutline();
+ offset = 30;
+ outlineShape.addVertex(offset+0.0f,-10.0f, true);
+ outlineShape.addVertex(offset+17.0f,-10.0f, true);
+ outlineShape.addVertex(offset+11.0f,5.0f, true);
+ outlineShape.addVertex(offset+16.0f,10.0f, true);
+ outlineShape.addVertex(offset+7.0f,15.0f, true);
+ outlineShape.addVertex(offset+6.0f,8.0f, true);
+ outlineShape.addVertex(offset+0.0f,10.0f, true);
+ outlineShape.closeLastOutline();
+ outlineShape.addEmptyOutline();
+ outlineShape.addVertex(offset+5.0f,0.0f, true);
+ outlineShape.addVertex(offset+5.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,-5.0f, true);
+ outlineShape.addVertex(offset+10.0f,0.0f, true);
+ outlineShape.closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer = new HwRegionRenderer(drawable.getContext());
+ createTestOutline();
+ }
+
+ float ang = 0;
+ float zoom = -70;
+ float xTran = -20;
+ float yTran = 5;
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ regionRenderer.resetMatrix();
+ regionRenderer.translate(xTran, yTran, zoom);
+ regionRenderer.rotate(ang, 0, 1, 0);
+
+ try {
+ regionRenderer.setAlpha(1.0f);
+ regionRenderer.setColor(0.0f, 0.0f, 1.0f);
+
+ regionRenderer.renderOutlineShape(outlineShape, new float[]{0,0,0});
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height){
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.glViewport(xstart, ystart, width, height);
+
+ regionRenderer.reshape(drawable, 45.0f, (float)width / (float)height, 0.1f, 7000.0f);
+ }
+
+ public void zoomIn(){
+ zoom++;
+ }
+ public void zoomOut(){
+ zoom--;
+ }
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ }
+ public void rotate(float delta){
+ ang+= delta;
+ ang%=360;
+ }
+ public void dispose(GLAutoDrawable arg0) {
+ regionRenderer.clearCached();
+
+ }
+ }
+}
diff --git a/src/demo/GPURegionNewtDemo02.java b/src/demo/GPURegionNewtDemo02.java
new file mode 100755
index 000000000..414b7942d
--- /dev/null
+++ b/src/demo/GPURegionNewtDemo02.java
@@ -0,0 +1,227 @@
+/**
+ * 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 demo;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.HwRegionRenderer;
+import com.jogamp.graph.curve.OutlineShape;
+import com.jogamp.graph.geom.opengl.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.FPSAnimator;
+
+/** Demonstrate the rendering of multiple OutlineShapes
+ * into one region
+ *
+ */
+public class GPURegionNewtDemo02 {
+ private static void create(){
+ new RegionsNewtWindow();
+ }
+ public static void main(String[] args) {
+ create();
+ }
+}
+
+class RegionsNewtWindow {
+ RegionGLListener regionGLListener = null;
+
+ public RegionsNewtWindow(){
+ createWindow();
+ }
+ private void createWindow() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setDoubleBuffered(true);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ System.out.println(caps);
+ final GLWindow window = GLWindow.create(caps);
+ window.setPosition(10, 10);
+ window.setSize(500, 500);
+
+ window.setTitle("GPU Curve Region Newt Demo 01");
+ regionGLListener = new RegionGLListener();
+ window.addGLEventListener(regionGLListener);
+
+ window.setVisible(true);
+
+ window.addKeyListener(new KeyListener() {
+ public void keyPressed(KeyEvent arg0) {
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ regionGLListener.zoomIn();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ regionGLListener.zoomOut();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ regionGLListener.move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ regionGLListener.move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ regionGLListener.move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ regionGLListener.move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ regionGLListener.rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ regionGLListener.rotate(-1);
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ });
+
+ FPSAnimator animator = new FPSAnimator(60);
+ animator.add(window);
+ window.addWindowListener(new WindowAdapter() {
+ public void windowDestroyNotify(WindowEvent arg0) {
+ System.exit(0);
+ };
+ });
+ animator.start();
+ }
+ private class RegionGLListener implements GLEventListener{
+ HwRegionRenderer regionRenderer = null;
+
+ OutlineShape[] outlineShapes = new OutlineShape[2];
+
+ public RegionGLListener() {}
+
+ private void createTestOutline(){
+ float offset = 0;
+ outlineShapes[0] = new OutlineShape(Vertex.factory());
+ outlineShapes[0].addVertex(0.0f,-10.0f,true);
+ outlineShapes[0].addVertex(15.0f,-10.0f, true);
+ outlineShapes[0].addVertex(10.0f,5.0f, false);
+ outlineShapes[0].addVertex(15.0f,10.0f, true);
+ outlineShapes[0].addVertex(6.0f,15.0f, false);
+ outlineShapes[0].addVertex(5.0f,8.0f, false);
+ outlineShapes[0].addVertex(0.0f,10.0f,true);
+ outlineShapes[0].closeLastOutline();
+ outlineShapes[0].addEmptyOutline();
+ outlineShapes[0].addVertex(5.0f,-5.0f,true);
+ outlineShapes[0].addVertex(10.0f,-5.0f, false);
+ outlineShapes[0].addVertex(10.0f,0.0f, true);
+ outlineShapes[0].addVertex(5.0f,0.0f, false);
+ outlineShapes[0].closeLastOutline();
+
+ /** Same shape as above but without any off-curve vertices */
+ outlineShapes[1] = new OutlineShape(Vertex.factory());
+ offset = 30;
+ outlineShapes[1].addVertex(offset+0.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+17.0f,-10.0f, true);
+ outlineShapes[1].addVertex(offset+11.0f,5.0f, true);
+ outlineShapes[1].addVertex(offset+16.0f,10.0f, true);
+ outlineShapes[1].addVertex(offset+7.0f,15.0f, true);
+ outlineShapes[1].addVertex(offset+6.0f,8.0f, true);
+ outlineShapes[1].addVertex(offset+0.0f,10.0f, true);
+ outlineShapes[1].closeLastOutline();
+ outlineShapes[1].addEmptyOutline();
+ outlineShapes[1].addVertex(offset+5.0f,0.0f, true);
+ outlineShapes[1].addVertex(offset+5.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,-5.0f, true);
+ outlineShapes[1].addVertex(offset+10.0f,0.0f, true);
+ outlineShapes[1].closeLastOutline();
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ regionRenderer = new HwRegionRenderer(drawable.getContext());
+ createTestOutline();
+ }
+
+ float ang = 0;
+ float zoom = -70;
+ float xTran = -20;
+ float yTran = 5;
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ regionRenderer.resetMatrix();
+ regionRenderer.translate(xTran, yTran, zoom);
+ regionRenderer.rotate(ang, 0, 1, 0);
+
+ try {
+ regionRenderer.setAlpha(1.0f);
+ regionRenderer.setColor(0.0f, 0.0f, 1.0f);
+
+ regionRenderer.renderOutlineShapes(outlineShapes, new float[]{0,0,0});
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height){
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.glViewport(xstart, ystart, width, height);
+
+ regionRenderer.reshape(drawable, 45.0f, (float)width / (float)height, 0.1f, 7000.0f);
+ }
+
+ public void zoomIn(){
+ zoom++;
+ }
+ public void zoomOut(){
+ zoom--;
+ }
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ }
+ public void rotate(float delta){
+ ang+= delta;
+ ang%=360;
+ }
+ public void dispose(GLAutoDrawable arg0) {
+ regionRenderer.clearCached();
+
+ }
+ }
+}
diff --git a/src/demo/GPUTextNewtDemo01.java b/src/demo/GPUTextNewtDemo01.java
new file mode 100644
index 000000000..fcd2134ae
--- /dev/null
+++ b/src/demo/GPUTextNewtDemo01.java
@@ -0,0 +1,198 @@
+/**
+ * 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 demo;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.text.HwTextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Point;
+import com.jogamp.graph.geom.opengl.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.FPSAnimator;
+
+public class GPUTextNewtDemo01 {
+ private static void create(){
+ new TextNewtWindow1();
+ }
+ public static void main(String[] args) {
+ create();
+ }
+}
+
+class TextNewtWindow1 {
+ Point.Factory<Vertex> pointFactory = Vertex.factory();
+
+ TextGLListener textGLListener = null;
+
+ public TextNewtWindow1(){
+ createWindow();
+ }
+ private void createWindow() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.getGL2ES2();
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true); // FIXME: sure ?
+ caps.setNumSamples(4); // FIXME: sure ?
+ System.out.println("Requested: "+caps);
+
+ final GLWindow window = GLWindow.create(caps);
+
+ window.setPosition(10, 10);
+ window.setSize(500, 500);
+
+ window.setTitle("GPU Text Newt Demo 01");
+ textGLListener = new TextGLListener();
+ window.addGLEventListener(textGLListener);
+
+ window.setVisible(true);
+
+ window.addKeyListener(new KeyListener() {
+ public void keyPressed(KeyEvent arg0) {
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ textGLListener.zoomIn();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ textGLListener.zoomOut();
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ textGLListener.move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ textGLListener.move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ textGLListener.move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ textGLListener.move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ textGLListener.rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ textGLListener.rotate(-1);
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ });
+
+ FPSAnimator animator = new FPSAnimator(60);
+ animator.add(window);
+ window.addWindowListener(new WindowAdapter() {
+ public void windowDestroyNotify(WindowEvent arg0) {
+ System.exit(0);
+ };
+ });
+ animator.start();
+ }
+ private class TextGLListener implements GLEventListener{
+ HwTextRenderer textRenderer = null;
+
+ public TextGLListener(){
+
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.setSwapInterval(1);
+ gl.glEnable(GL2ES2.GL_DEPTH_TEST);
+ textRenderer = new HwTextRenderer(drawable.getContext(), pointFactory, Region.SINGLE_PASS);
+
+ System.out.println("Realised: "+drawable.getChosenGLCapabilities());
+ System.out.println("MS: " + gl.glIsEnabled(GL2ES2.GL_MULTISAMPLE));
+ }
+
+ float ang = 0;
+ float zoom = -70;
+ float xTran = -10;
+ float yTran = 10;
+
+ public void display(GLAutoDrawable drawable) {
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ textRenderer.resetMatrix();
+ textRenderer.translate(xTran, yTran, zoom);
+ textRenderer.rotate(ang, 0, 1, 0);
+
+ String text1 = "abcdef\nghijklmn\nopqrstuv\nwxyz\n0123456789";
+ String text2 = text1.toUpperCase();
+
+ Font font = textRenderer.createFont(pointFactory, "Lucida Sans Regular",40);
+ float[] position = new float[]{0,0,0};
+
+ try {
+ textRenderer.setAlpha(1.0f);
+ textRenderer.setColor(0.0f, 0.0f, 1.0f);
+ gl.glSampleCoverage(0.75f, false);
+ textRenderer.renderString3D(font, text2, position, 0);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height){
+ GL2ES2 gl = drawable.getGL().getGL2ES2();
+ gl.glViewport(xstart, ystart, width, height);
+
+ textRenderer.reshape(drawable, 45.0f, width, height, 0.1f, 7000.0f);
+ }
+
+ public void zoomIn(){
+ zoom++;
+ }
+ public void zoomOut(){
+ zoom--;
+ }
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ }
+ public void rotate(float delta){
+ ang+= delta;
+ ang%=360;
+ }
+ public void dispose(GLAutoDrawable arg0) {
+ textRenderer.clearCached();
+ }
+ }
+}
diff --git a/src/demo/GPUTextNewtDemo02.java b/src/demo/GPUTextNewtDemo02.java
new file mode 100644
index 000000000..b0c7115ec
--- /dev/null
+++ b/src/demo/GPUTextNewtDemo02.java
@@ -0,0 +1,215 @@
+/**
+ * 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 demo;
+
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GL3;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLProfile;
+
+import com.jogamp.graph.curve.Region;
+import com.jogamp.graph.curve.text.HwTextRenderer;
+import com.jogamp.graph.font.Font;
+import com.jogamp.graph.geom.Point;
+import com.jogamp.graph.geom.opengl.Vertex;
+import com.jogamp.newt.event.KeyEvent;
+import com.jogamp.newt.event.KeyListener;
+import com.jogamp.newt.event.WindowAdapter;
+import com.jogamp.newt.event.WindowEvent;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.util.FPSAnimator;
+
+public class GPUTextNewtDemo02 {
+ private static void create(){
+ new TextNewtWindow();
+ }
+ public static void main(String[] args) {
+ create();
+ }
+}
+
+class TextNewtWindow {
+ Point.Factory<Vertex> pointFactory = Vertex.factory();
+ TextGLListener textGLListener = null;
+
+ public TextNewtWindow(){
+ createWindow();
+ }
+ private void createWindow() {
+ GLProfile.initSingleton(true);
+ GLProfile glp = GLProfile.get(GLProfile.GL3);
+
+ GLCapabilities caps = new GLCapabilities(glp);
+ caps.setAlphaBits(4);
+ caps.setSampleBuffers(true);
+ caps.setNumSamples(4);
+ System.out.println("Requested: "+caps);
+
+ final GLWindow window = GLWindow.create(caps);
+
+ window.setPosition(10, 10);
+ window.setSize(1000, 1000);
+
+ window.setTitle("GPU Text Newt Demo 02");
+ textGLListener = new TextGLListener();
+ window.addGLEventListener(textGLListener);
+
+ window.setVisible(true);
+
+ window.addKeyListener(new KeyListener() {
+ public void keyPressed(KeyEvent arg0) {
+ if(arg0.getKeyCode() == KeyEvent.VK_1){
+ textGLListener.zoomIn(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_2){
+ textGLListener.zoomOut(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_3){
+ textGLListener.zoomIn(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_4){
+ textGLListener.zoomOut(10);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_UP){
+ textGLListener.move(0, -1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_DOWN){
+ textGLListener.move(0, 1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_LEFT){
+ textGLListener.move(1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_RIGHT){
+ textGLListener.move(-1, 0);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_0){
+ textGLListener.rotate(1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_9){
+ textGLListener.rotate(-1);
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_6){
+ textGLListener.size -= 10;
+ }
+ else if(arg0.getKeyCode() == KeyEvent.VK_7){
+ textGLListener.size += 10;
+ }
+ }
+ public void keyTyped(KeyEvent arg0) {}
+ public void keyReleased(KeyEvent arg0) {}
+ });
+
+ FPSAnimator animator = new FPSAnimator(60);
+ animator.add(window);
+ window.addWindowListener(new WindowAdapter() {
+ public void windowDestroyNotify(WindowEvent arg0) {
+ System.exit(0);
+ };
+ });
+ animator.start();
+ }
+ private class TextGLListener implements GLEventListener{
+ HwTextRenderer textRenderer = null;
+
+ public TextGLListener(){
+
+ }
+
+ public void init(GLAutoDrawable drawable) {
+ GL3 gl = drawable.getGL().getGL3();
+ gl.setSwapInterval(1);
+ gl.glEnable(GL3.GL_DEPTH_TEST);
+
+ textRenderer = new HwTextRenderer(drawable.getContext(), pointFactory, Region.TWO_PASS);
+ gl.glHint(GL2.GL_PERSPECTIVE_CORRECTION_HINT, GL3.GL_NICEST);
+ System.out.println("Realised: "+drawable.getChosenGLCapabilities());
+ System.out.println("MS: " + gl.glIsEnabled(GL3.GL_MULTISAMPLE));
+ }
+
+ float ang = 0;
+ float zoom = -300;
+ float xTran = -100;
+ float yTran = 40;
+ int size = 200;
+
+ public void display(GLAutoDrawable drawable) {
+ GL3 gl = drawable.getGL().getGL3();
+
+ gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+
+ textRenderer.resetMatrix();
+ textRenderer.translate(xTran, yTran, zoom);
+ textRenderer.rotate(ang, 0, 1, 0);
+
+ String text1 = "abcdef\nghijklmn\nopqrstuv\nwxyz\n0123456789";
+ String text2 = text1.toUpperCase();
+
+ Font font = textRenderer.createFont(pointFactory, "Lucida Sans Regular",40);
+ float[] position = new float[]{0,0,0};
+
+ try {
+ textRenderer.setAlpha(1.0f);
+ textRenderer.setColor(0.0f, 0.0f, 0.0f);
+ gl.glSampleCoverage(0.75f, false);
+ textRenderer.renderString3D(font, text2, position, size);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ public void reshape(GLAutoDrawable drawable, int xstart, int ystart, int width, int height){
+ GL3 gl = drawable.getGL().getGL3();
+ gl.glViewport(xstart, ystart, width, height);
+
+ textRenderer.reshape(drawable, 45.0f, width , height, 0.1f, 7000.0f);
+ }
+
+ public void zoomIn(float f){
+ zoom+=f;
+ }
+ public void zoomOut(float f){
+ zoom-=f;
+ System.err.println("Zoom: " + zoom);
+ }
+ public void move(float x, float y){
+ xTran += x;
+ yTran += y;
+ }
+ public void rotate(float delta){
+ ang+= delta;
+ ang%=360;
+ }
+
+ public void dispose(GLAutoDrawable arg0) {
+ textRenderer.clearCached();
+ }
+ }
+}
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();
+ }
+}
diff --git a/src/jogamp/graph/math/VectorFloatUtil.java b/src/jogamp/graph/math/VectorFloatUtil.java
new file mode 100755
index 000000000..172cacd09
--- /dev/null
+++ b/src/jogamp/graph/math/VectorFloatUtil.java
@@ -0,0 +1,293 @@
+/**
+ * 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.math;
+
+import java.util.ArrayList;
+
+import com.jogamp.graph.geom.Point;
+
+public class VectorFloatUtil {
+
+ public static final int CW = -1;
+ public static final int CCW = 1;
+ public static final int COLLINEAR = 0;
+
+ /** compute the dot product of two points
+ * @param vec1 vector 1
+ * @param vec2 vector 2
+ * @return the dot product as float
+ */
+ public static float dot(float[] vec1, float[] vec2)
+ {
+ return (vec1[0]*vec2[0] + vec1[1]*vec2[1] + vec1[2]*vec2[2]);
+ }
+ /** Normalize a vector
+ * @param vector input vector
+ * @return normalized vector
+ */
+ public static float[] normalize(float[] vector)
+ {
+ float[] newVector = new float[3];
+
+ float d = MathFloat.sqrt(vector[0]*vector[0] + vector[1]*vector[1] + vector[2]*vector[2]);
+ if(d> 0.0f)
+ {
+ newVector[0] = vector[0]/d;
+ newVector[1] = vector[1]/d;
+ newVector[2] = vector[2]/d;
+ }
+ return newVector;
+ }
+
+ /** Scales a vector by param
+ * @param vector input vector
+ * @param scale constant to scale by
+ * @return scaled vector
+ */
+ public static float[] scale(float[] vector, float scale)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = vector[0]*scale;
+ newVector[1] = vector[1]*scale;
+ newVector[2] = vector[2]*scale;
+ return newVector;
+ }
+
+ /** Adds to vectors
+ * @param v1 vector 1
+ * @param v2 vector 2
+ * @return v1 + v2
+ */
+ public static float[] vectorAdd(float[] v1, float[] v2)
+ {
+ float[] newVector = new float[3];
+
+ newVector[0] = v1[0] + v2[0];
+ newVector[1] = v1[1] + v2[1];
+ newVector[2] = v1[2] + v2[2];
+ return newVector;
+ }
+
+ /** cross product vec1 x vec2
+ * @param vec1 vector 1
+ * @param vec2 vecttor 2
+ * @return the resulting vector
+ */
+ public static float[] cross(float[] vec1, float[] vec2)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec2[2]*vec1[1] - vec2[1]*vec1[2];
+ out[1] = vec2[0]*vec1[2] - vec2[2]*vec1[0];
+ out[2] = vec2[1]*vec1[0] - vec2[0]*vec1[1];
+
+ return out;
+ }
+
+ /** Column Matrix Vector multiplication
+ * @param colMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] colMatrixVectorMult(float[] colMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*colMatrix[0] + vec[1]*colMatrix[4] + vec[2]*colMatrix[8] + colMatrix[12];
+ out[1] = vec[0]*colMatrix[1] + vec[1]*colMatrix[5] + vec[2]*colMatrix[9] + colMatrix[13];
+ out[2] = vec[0]*colMatrix[2] + vec[1]*colMatrix[6] + vec[2]*colMatrix[10] + colMatrix[14];
+
+ return out;
+ }
+
+ /** Matrix Vector multiplication
+ * @param rawMatrix column matrix (4x4)
+ * @param vec vector(x,y,z)
+ * @return result new float[3]
+ */
+ public static float[] rowMatrixVectorMult(float[] rawMatrix, float[] vec)
+ {
+ float[] out = new float[3];
+
+ out[0] = vec[0]*rawMatrix[0] + vec[1]*rawMatrix[1] + vec[2]*rawMatrix[2] + rawMatrix[3];
+ out[1] = vec[0]*rawMatrix[4] + vec[1]*rawMatrix[5] + vec[2]*rawMatrix[6] + rawMatrix[7];
+ out[2] = vec[0]*rawMatrix[8] + vec[1]*rawMatrix[9] + vec[2]*rawMatrix[10] + rawMatrix[11];
+
+ return out;
+ }
+
+ /** Calculate the midpoint of two values
+ * @param p1 first value
+ * @param p2 second vale
+ * @return midpoint
+ */
+ public static float mid(float p1, float p2)
+ {
+ return (p1+p2)/2.0f;
+ }
+ /** Calculate the midpoint of two points
+ * @param p1 first point
+ * @param p2 second point
+ * @return midpoint
+ */
+ public static float[] mid(float[] p1, float[] p2)
+ {
+ float[] midPoint = new float[3];
+ midPoint[0] = (p1[0] + p2[0])/2.0f;
+ midPoint[1] = (p1[1] + p2[1])/2.0f;
+ midPoint[2] = (p1[2] + p2[2])/2.0f;
+
+ return midPoint;
+ }
+ /** Compute the norm of a vector
+ * @param vec vector
+ * @return vorm
+ */
+ public static float norm(float[] vec)
+ {
+ return MathFloat.sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
+ }
+ /** Compute distance between 2 points
+ * @param p0 a ref point on the line
+ * @param vec vector representing the direction of the line
+ * @param point the point to compute the relative distance of
+ * @return distance float
+ */
+ public static float computeLength(float[] p0, float[] point)
+ {
+ float[] w = new float[]{point[0]-p0[0],point[1]-p0[1],point[2]-p0[2]};
+
+ float distance = MathFloat.sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
+
+ return distance;
+ }
+
+ /**Check equality of 2 vec3 vectors
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @return
+ */
+ public static boolean checkEquality(float[] v1, float[] v2)
+ {
+ if(Float.compare(v1[0], v2[0]) == 0
+ && Float.compare(v1[1] , v2[1]) == 0
+ && Float.compare(v1[2], v2[2]) == 0 )
+ return true;
+ return false;
+ }
+
+ /** Compute the determinant of 3 vectors
+ * @param a vector 1
+ * @param b vector 2
+ * @param c vector 3
+ * @return the determinant value
+ */
+ public static float computeDeterminant(float[] a, float[] b, float[] c)
+ {
+ float area = a[0]*b[1]*c[2] + a[1]*b[2]*c[0] + a[2]*b[0]*c[1] - a[0]*b[2]*c[1] - a[1]*b[0]*c[2] - a[2]*b[1]*c[0];
+ return area;
+ }
+
+ /** Check if three vertices are colliniear
+ * @param v1 vertex 1
+ * @param v2 vertex 2
+ * @param v3 vertex 3
+ * @return true if collinear, false otherwise
+ */
+ public static boolean checkCollinear(float[] v1, float[] v2, float[] v3)
+ {
+ return (computeDeterminant(v1, v2, v3) == VectorFloatUtil.COLLINEAR);
+ }
+
+ /** Compute Vector
+ * @param v1 vertex 1
+ * @param v2 vertex2 2
+ * @return Vector V1V2
+ */
+ public static float[] computeVector(float[] v1, float[] v2)
+ {
+ float[] vector = new float[3];
+ vector[0] = v2[0] - v1[0];
+ vector[1] = v2[1] - v1[1];
+ vector[2] = v2[2] - v1[2];
+ return vector;
+ }
+
+ /** Check if vertices in triangle circumcircle
+ * @param a triangle vertex 1
+ * @param b triangle vertex 2
+ * @param c triangle vertex 3
+ * @param d vertex in question
+ * @return true if the vertex d is inside the circle defined by the
+ * vertices a, b, c. from paper by Guibas and Stolfi (1985).
+ */
+ public static boolean inCircle(Point a, Point b, Point c, Point d){
+ return (a.getX() * a.getX() + a.getY() * a.getY()) * triArea(b, c, d) -
+ (b.getX() * b.getX() + b.getY() * b.getY()) * triArea(a, c, d) +
+ (c.getX() * c.getX() + c.getY() * c.getY()) * triArea(a, b, d) -
+ (d.getX() * d.getX() + d.getY() * d.getY()) * triArea(a, b, c) > 0;
+ }
+
+ /** Computes oriented area of a triangle
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return compute twice the area of the oriented triangle (a,b,c), the area
+ * is positive if the triangle is oriented counterclockwise.
+ */
+ public static float triArea(Point a, Point b, Point c){
+ return (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY())*(c.getX() - a.getX());
+ }
+
+ /** Check if points are in ccw order
+ * @param a first vertex
+ * @param b second vertex
+ * @param c third vertex
+ * @return true if the points a,b,c are in a ccw order
+ */
+ public static boolean ccw(Point a, Point b, Point c){
+ return triArea(a,b,c) > 0;
+ }
+
+ /** Computes the area of a list of vertices to check if ccw
+ * @param vertices
+ * @return positve area if ccw else negative area value
+ */
+ public static float area(ArrayList<Point> vertices) {
+ int n = vertices.size();
+ float area = 0.0f;
+ for (int p = n - 1, q = 0; q < n; p = q++)
+ {
+ float[] pCoord = vertices.get(p).getCoord();
+ float[] qCoord = vertices.get(q).getCoord();
+ area += pCoord[0] * qCoord[1] - qCoord[0] * pCoord[1];
+ }
+ return area;
+ }
+}