diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp/graph/curve')
7 files changed, 1096 insertions, 0 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java new file mode 100755 index 000000000..827717aa5 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -0,0 +1,307 @@ +/**
+ * 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 com.jogamp.graph.geom.Outline;
+import com.jogamp.graph.geom.Triangle;
+import com.jogamp.graph.geom.Vertex;
+import com.jogamp.graph.math.VectorUtil;
+
+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 as a high-level representation of the Objects. For
+ * optimizations, flexibility requirements for future features.
+ *
+ * <br><br>
+ * Example to creating an Outline Shape:
+ * <pre>
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ addEnptyOutline()
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ * </pre>
+ *
+ * The above will create two outlines each with three vertices. By adding these two outlines to
+ * the OutlineShape, we are stating that the combination of the two outlines represent the shape.
+ * <br>
+ *
+ * To specify that the shape is curved at a region, the on-curve flag should be set to false
+ * for the vertex that is in the middle of the curved region (if the curved region is defined by 3
+ * vertices (quadratic curve).
+ * <br>
+ * In case the curved region is defined by 4 or more vertices the middle vertices should both have
+ * the on-curve flag set to false.
+ *
+ * <br>Example: <br>
+ * <pre>
+ addVertex(0,0, true);
+ addVertex(0,1, false);
+ addVertex(1,1, false);
+ addVertex(1,0, true);
+ * </pre>
+ *
+ * The above snippet defines a cubic nurbs curve where (0,1 and 1,1)
+ * do not belong to the final rendered shape.
+ *
+ * <i>Implementation Notes:</i><br>
+ * <ul>
+ * <li> The first vertex of any outline belonging to the shape should be on-curve</li>
+ * <li> Intersections between off-curved parts of the outline is not handled</li>
+ * </ul>
+ *
+ * @see Outline
+ * @see Region
+ */
+public class OutlineShape {
+
+ public static final int QUADRATIC_NURBS = 10;
+ private final Vertex.Factory<? extends Vertex> vertexFactory;
+
+ /** The list of {@link Outline}s that are part of this
+ * outline shape.
+ */
+ private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
+
+ /** Create a new Outline based Shape
+ */
+ public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
+ vertexFactory = factory;
+ outlines.add(new Outline());
+ }
+
+ /** Returns the associated vertex factory of this outline shape
+ * @return Vertex.Factory object
+ */
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
+
+ /** Add a new empty {@link Outline}
+ * to the shape, this new outline will
+ * be placed at the end of the outline list.
+ *
+ * After a call to this function all new vertices added
+ * will belong to the new outline
+ */
+ public void addEmptyOutline(){
+ outlines.add(new Outline());
+ }
+
+ /** Adds an {@link 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 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 v the vertex to be added to the OutlineShape
+ */
+ public final void addVertex(Vertex v){
+ getLastOutline().addVertex(v);
+ }
+
+ /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex. The 2D vertex will be represented as Z=0.
+ *
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, onCurve);
+ }
+
+ /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex.
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param z the z coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, float z, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
+ }
+
+ /** Add a vertex to the last outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, 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 getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+ /** Make sure that the outlines represent
+ * the specified destinationType, if not
+ * transform outlines to destination type.
+ * @param destinationType The curve type needed
+ */
+ public void transformOutlines(int destinationType){
+ if(destinationType == QUADRATIC_NURBS){
+ transformOutlinesQuadratic();
+ }
+ }
+
+ private void transformOutlinesQuadratic(){
+ ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
+
+ /**loop over the outlines and make sure no
+ * adj off-curve vertices
+ */
+ for(Outline outline:outlines){
+ Outline newOutline = new Outline();
+
+ ArrayList<Vertex> vertices = outline.getVertices();
+ int size =vertices.size()-1;
+ for(int i=0;i<size;i++){
+ Vertex currentVertex = vertices.get(i);
+ Vertex nextVertex = vertices.get((i+1)%size);
+ if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
+ newOutline.addVertex(currentVertex);
+
+ float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
+ }
+ else {
+ newOutline.addVertex(currentVertex);
+ }
+ }
+ newOutlines.add(newOutline);
+ }
+ outlines = newOutlines;
+ }
+
+ private void generateVertexIds(){
+ int maxVertexId = 0;
+ for(Outline outline:outlines){
+ ArrayList<Vertex> vertices = outline.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(maxVertexId);
+ maxVertexId++;
+ }
+ }
+ }
+
+ /** @return the list of vertices associated with the
+ * {@code Outline} list of this object
+ */
+ public ArrayList<Vertex> getVertices(){
+ ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ for(Outline polyline:outlines){
+ vertices.addAll(polyline.getVertices());
+ }
+ return vertices;
+ }
+
+ /** Triangulate the outline shape generating a list of triangles
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(){
+ return triangulate(0.5f);
+ }
+
+ /**Triangulate the {@link OutlineShape} generating a list of triangles
+ * @param sharpness defines the curvature strength around the off-curve vertices.
+ * defaults to 0.5f
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ if(outlines.size() == 0){
+ return null;
+ }
+ sortOutlines();
+ generateVertexIds();
+
+ CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness);
+ for(int index = 0; index< outlines.size();index++){
+ Outline outline = outlines.get(index);
+ triangulator2d.addCurve(outline);
+ }
+
+ ArrayList<Triangle> 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/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java new file mode 100755 index 000000000..051cb1c38 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java @@ -0,0 +1,128 @@ +/**
+ * 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.Vertex;
+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_ATTR_IDX = 0;
+
+ /** The Texture Coord index in an OGL object
+ */
+ public static int TEXCOORD_ATTR_IDX = 1;
+
+ /** single pass rendering, fast, but AA might not be perfect */
+ public static int SINGLE_PASS = 1;
+
+ /** two pass rendering, slower and more resource hungry (FBO), but AA is perfect */
+ public static int TWO_PASS = 2;
+
+ /** 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 {@link PMVMatrix}.
+ * @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 {@link 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> 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 {@link 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<Vertex> 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/jogl/classes/com/jogamp/graph/curve/RegionFactory.java b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java new file mode 100755 index 000000000..d3b978b8a --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java @@ -0,0 +1,62 @@ +/**
+ * 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 javax.media.opengl.GLException;
+
+import com.jogamp.opengl.util.glsl.ShaderState;
+
+import jogamp.graph.curve.opengl.VBORegionSPES2;
+import jogamp.graph.curve.opengl.VBORegion2PES2;
+
+
+/** 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 {@link GLContext}
+ * @param st the {@link ShaderState} 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( !context.isGL2ES2() ) {
+ throw new GLException("At least a GL2ES2 GL context is required. Given: " + context);
+ }
+ if( Region.TWO_PASS == type ){
+ return new VBORegion2PES2(context, st);
+ }
+ else{
+ return new VBORegionSPES2(context);
+ }
+ }
+}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java new file mode 100644 index 000000000..c1fec10b8 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java @@ -0,0 +1,113 @@ +package com.jogamp.graph.curve.opengl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.media.opengl.GL2ES2; + +import com.jogamp.graph.curve.OutlineShape; +import com.jogamp.graph.curve.Region; +import com.jogamp.graph.curve.RegionFactory; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.graph.geom.Vertex; + +public abstract class RegionRenderer extends Renderer { + + /** Create a Hardware accelerated Curve Region Renderer + */ + public static RegionRenderer create(Vertex.Factory<? extends Vertex> factory, int type) { + return new jogamp.graph.curve.opengl.RegionRendererImpl01(factory, type); + } + + public RegionRenderer(Vertex.Factory<? extends Vertex> factory, int type) { + super(factory, type); + } + + /** Render an array of {@link OutlineShape}s combined in one region + * at the position provided the triangles of the + * shapes will be generated, if not yet generated + * @param outlineShapes array of OutlineShapes to Render. + * @param position the initial translation of the outlineShapes. + * @param texSize texture size for multipass render * + * @throws Exception if HwRegionRenderer not initialized + */ + public abstract void renderOutlineShapes(GL2ES2 gl, OutlineShape[] outlineShapes, float[] position, int texSize); + + /** Render an {@link OutlineShape} 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. + * @param texSize texture size for multipass render + * @throws Exception if HwRegionRenderer not initialized + */ + public abstract void renderOutlineShape(GL2ES2 gl, OutlineShape outlineShape, float[] position, int texSize); + + protected HashMap<Integer, Region> regions = new HashMap<Integer, Region>(); + + public void flushCache() { + Iterator<Region> iterator = regions.values().iterator(); + while(iterator.hasNext()){ + Region region = iterator.next(); + region.destroy(); + } + regions.clear(); + } + + /** Create an ogl {@link Region} defining this {@link OutlineShape} + * @param sharpness parameter for Region generation + * @return the resulting Region. + */ + protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape, float sharpness) { + Region region = RegionFactory.create(gl.getContext(), st, renderType); + + outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); + + ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(sharpness); + ArrayList<Vertex> vertices = (ArrayList<Vertex>) outlineShape.getVertices(); + region.addVertices(vertices); + region.addTriangles(triangles); + + region.update(); + return region; + } + + /** Create an ogl {@link Region} defining the list of {@link OutlineShape}. + * Combining the Shapes into single buffers. + * @param sharpness parameter for Region generation + * @return the resulting Region inclusive the generated region + */ + protected Region createRegion(GL2ES2 gl, OutlineShape[] outlineShapes, float sharpness) { + Region region = RegionFactory.create(gl.getContext(), st, renderType); + + int numVertices = region.getNumVertices(); + + for(OutlineShape outlineShape:outlineShapes){ + outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); + + ArrayList<Triangle> triangles = outlineShape.triangulate(sharpness); + region.addTriangles(triangles); + + ArrayList<Vertex> vertices = outlineShape.getVertices(); + for(Vertex vert:vertices){ + vert.setId(numVertices++); + } + region.addVertices(vertices); + } + + region.update(); + return region; + } + + protected static int getHashCode(OutlineShape outlineShape){ + return outlineShape.hashCode(); + } + + protected static int getHashCode(OutlineShape[] outlineShapes){ + int hashcode = 0; + for(OutlineShape outlineShape:outlineShapes){ + hashcode += getHashCode(outlineShape); + } + return hashcode; + } +}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java new file mode 100644 index 000000000..863928ed4 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java @@ -0,0 +1,167 @@ +package com.jogamp.graph.curve.opengl; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLUniformData; +import javax.media.opengl.fixedfunc.GLMatrixFunc; + +import jogamp.opengl.Debug; + +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.geom.opengl.SVertex; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +public abstract class Renderer { + protected static final boolean DEBUG = Debug.debug("CurveRenderer"); + + protected abstract boolean initImpl(GL2ES2 gl); + + protected abstract void disposeImpl(GL2ES2 gl); + + /** + * Flushes all cached data + */ + public abstract void flushCache(); + + public abstract float getAlpha(); + + public abstract void setAlpha(GL2ES2 gl, float alpha_t); + + public abstract void setColor(GL2ES2 gl, float r, float g, float b); + + protected final Vertex.Factory<? extends Vertex> pointFactory; + protected ShaderState st = new ShaderState(); + protected PMVMatrix pmvMatrix = new PMVMatrix(); + protected GLUniformData mgl_PMVMatrix; + protected int renderType; + protected int vp_width = 0; + protected int vp_height = 0; + + private boolean vboSupported = false; + private boolean initialized = false; + + /** + * + * @param factory + * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS} + */ + protected Renderer(Vertex.Factory<? extends Vertex> factory, int renderType) { + this.renderType = renderType; + this.pointFactory = (null != factory) ? factory : SVertex.factory(); + } + + public Vertex.Factory<? extends Vertex> getFactory() { return pointFactory; } + + public final boolean isInitialized() { return initialized; } + + public final boolean isVBOSupported() { return vboSupported; } + + public final int getRenderType() { return renderType; } + + public final int getWidth() { return vp_width; } + public final int getHeight() { return vp_height; } + + /** + * Initialize shaders and bindings for GPU based rendering. + * Leaves the renderer enabled, ie ShaderState on. + * + * @param gl the current GL state + * @return true if succeeded, false otherwise + */ + public boolean init(GL2ES2 gl) { + if(initialized){ + if(DEBUG) { + System.err.println("TextRenderer: Already initialized!"); + } + return true; + } + vboSupported = gl.isFunctionAvailable("glGenBuffers") && + gl.isFunctionAvailable("glBindBuffer") && + gl.isFunctionAvailable("glBufferData") && + gl.isFunctionAvailable("glDrawElements") && + gl.isFunctionAvailable("glVertexAttribPointer") && + gl.isFunctionAvailable("glDeleteBuffers"); + + if(DEBUG) { + System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported()); + } + + initialized = initImpl(gl); + return initialized; + } + + public void dispose(GL2ES2 gl) { + if(!initialized){ + if(DEBUG) { + System.err.println("TextRenderer: Not initialized!"); + } + return; + } + disposeImpl(gl); + st.destroy(gl); + flushCache(); + initialized = false; + } + + public final ShaderState getShaderState() { return st; } + + public final PMVMatrix getMatrix() { return pmvMatrix; } + + public void rotate(GL2ES2 gl, float angle, float x, float y, float z) { + pmvMatrix.glRotatef(angle, x, y, z); + if(initialized && null != gl && st.inUse()) { + st.glUniform(gl, mgl_PMVMatrix); + } + } + + public void translate(GL2ES2 gl, float x, float y, float z) { + pmvMatrix.glTranslatef(x, y, z); + if(initialized && null != gl && st.inUse()) { + st.glUniform(gl, mgl_PMVMatrix); + } + } + + public void resetModelview(GL2ES2 gl) { + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + pmvMatrix.glLoadIdentity(); + if(initialized && null != gl && st.inUse()) { + st.glUniform(gl, mgl_PMVMatrix); + } + } + + public void updateMatrix(GL2ES2 gl) { + if(initialized && null != gl && st.inUse()) { + st.glUniform(gl, mgl_PMVMatrix); + } + } + + public boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) { + this.vp_width = width; + this.vp_height = height; + float ratio = (float)width/(float)height; + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.gluPerspective(angle, ratio, near, far); + + if(initialized && null != gl) { + st.glUniform(gl, mgl_PMVMatrix); + } + + return true; + } + + public boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) { + this.vp_width = width; + this.vp_height = height; + pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + pmvMatrix.glLoadIdentity(); + pmvMatrix.glOrthof(0, width, 0, height, near, far); + + if(initialized && null != gl) { + st.glUniform(gl, mgl_PMVMatrix); + } + + return true; + } + +}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java new file mode 100644 index 000000000..2bb99d27c --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java @@ -0,0 +1,103 @@ +package com.jogamp.graph.curve.opengl; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; + +import javax.media.opengl.GL2ES2; + +import jogamp.graph.curve.text.GlyphString; +import jogamp.graph.font.FontInt; +import jogamp.graph.geom.plane.AffineTransform; +import jogamp.graph.geom.plane.Path2D; + +import com.jogamp.graph.font.Font; +import com.jogamp.graph.geom.Vertex; + +public abstract class TextRenderer extends Renderer { + + /** + * Create a Hardware accelerated Text Renderer. + * @param factory optional Point.Factory for Vertex construction. Default is Vertex.Factory. + */ + public static TextRenderer create(Vertex.Factory<? extends Vertex> factory, int type) { + return new jogamp.graph.curve.opengl.TextRendererImpl01(factory, type); + } + + protected TextRenderer(Vertex.Factory<? extends Vertex> factory, int type) { + super(factory, type); + } + + /** 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 gl the current GL state + * @param font {@link Font} to be used + * @param str text to be rendered + * @param position the lower left corner of the string + * @param fontSize font size + * @param texSize texture size for multipass render + * @throws Exception if TextRenderer not initialized + */ + public abstract void renderString3D(GL2ES2 gl, Font font, + String str, float[] position, int fontSize, int texSize); + + /**Create the resulting {@link GlyphString} that represents + * the String wrt to the font. + * @param font {@link Font} to be used + * @param size font size + * @param str {@link String} to be created + * @param sharpness parameter for Region generation of the resulting GlyphString + * @return the resulting GlyphString inclusive the generated region + */ + protected GlyphString createString(GL2ES2 gl, Font font, int size, String str, float sharpness) { + AffineTransform affineTransform = new AffineTransform(pointFactory); + + Path2D[] paths = new Path2D[str.length()]; + ((FontInt)font).getOutline(str, size, affineTransform, paths); + + GlyphString glyphString = new GlyphString(pointFactory, font.getName(), str); + glyphString.createfromFontPath(paths, affineTransform); + glyphString.generateRegion(gl.getContext(), sharpness, st, renderType); + + return glyphString; + } + + public void flushCache() { + Iterator<GlyphString> iterator = stringCacheMap.values().iterator(); + while(iterator.hasNext()){ + GlyphString glyphString = iterator.next(); + glyphString.destroy(); + } + stringCacheMap.clear(); + stringCacheArray.clear(); + } + + public final void setCacheMaxSize(int newSize ) { stringCacheMaxSize = newSize; validateCache(0); } + public final int getCacheMaxSize() { return stringCacheMaxSize; } + public final int getCacheSize() { return stringCacheArray.size(); } + + protected void validateCache(int space) { + while ( getCacheSize() + space > getCacheMaxSize() ) { + String key = stringCacheArray.remove(0); + stringCacheMap.remove(key); + } + } + + protected GlyphString getCachedGlyphString(Font font, String str, int fontSize) { + final String key = font.getName() + "." + str.hashCode() + "." + fontSize; + return stringCacheMap.get(key); + } + + protected void addCachedGlyphString(Font font, String str, int fontSize, GlyphString glyphString) { + final String key = font.getName() + "." + str.hashCode() + "." + fontSize; + validateCache(1); + stringCacheMap.put(key, glyphString); + stringCacheArray.add(stringCacheArray.size(), key); + } + + // Cache is adding at the end of the array + public static final int DEFAULT_CACHE_SIZE = 32; + private HashMap<String, GlyphString> stringCacheMap = new HashMap<String, GlyphString>(DEFAULT_CACHE_SIZE); + private ArrayList<String> stringCacheArray = new ArrayList<String>(DEFAULT_CACHE_SIZE); + private int stringCacheMaxSize = DEFAULT_CACHE_SIZE; // -1 unlimited, 0 off, >0 limited +}
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java new file mode 100644 index 000000000..a2e4ca50f --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java @@ -0,0 +1,216 @@ +/** + * 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.GraphVertex; +import jogamp.graph.curve.tess.Loop; + +import com.jogamp.graph.geom.Outline; +import com.jogamp.graph.geom.Triangle; +import com.jogamp.graph.geom.Vertex; +import com.jogamp.graph.math.VectorUtil; + +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 { + + protected static final boolean DEBUG = Debug.debug("Triangulation"); + + private float sharpness = 0.5f; + private ArrayList<Loop> loops; + private ArrayList<Vertex> vertices; + + private ArrayList<Triangle> 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<Vertex>(); + triangles = new ArrayList<Triangle>(3); + loops = new ArrayList<Loop>(); + } + + /** Add a curve to the list of profiles provided + * @param polyline a bounding {@link Outline} + */ + public void addCurve(Outline polyline){ + Loop loop = null; + + if(!loops.isEmpty()){ + loop = getContainerLoop(polyline); + } + + if(loop == null) { + GraphOutline outline = new GraphOutline(polyline); + GraphOutline innerPoly = extractBoundaryTriangles(outline, false); + vertices.addAll(polyline.getVertices()); + loop = new Loop(innerPoly, VectorUtil.CCW); + loops.add(loop); + } + else { + GraphOutline outline = new GraphOutline(polyline); + GraphOutline innerPoly = extractBoundaryTriangles(outline, true); + vertices.addAll(innerPoly.getPoints()); + loop.addConstraintCurve(innerPoly); + } + } + + /** Generate the triangulation of the provided + * List of {@link Outline}s + */ + public ArrayList<Triangle> generateTriangulation(){ + for(int i=0;i<loops.size();i++) { + Loop loop = loops.get(i); + int numTries = 0; + int size = loop.computeLoopSize(); + while(!loop.isSimplex()){ + Triangle 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 tri = loop.cut(true); + if(tri != null) + triangles.add(tri); + } + return triangles; + } + + private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole){ + GraphOutline innerOutline = new GraphOutline(); + ArrayList<GraphVertex> outVertices = outline.getGraphPoint(); + int size = outVertices.size(); + for(int i=0; i < size; i++) { + GraphVertex currentVertex = outVertices.get(i); + GraphVertex gv0 = outVertices.get((i+size-1)%size); + GraphVertex gv2 = outVertices.get((i+1)%size); + GraphVertex gv1 = currentVertex; + + if(!currentVertex.getPoint().isOnCurve()) { + Vertex v0 = gv0.getPoint().clone(); + Vertex v2 = gv2.getPoint().clone(); + Vertex v1 = gv1.getPoint().clone(); + + gv0.setBoundaryContained(true); + gv1.setBoundaryContained(true); + gv2.setBoundaryContained(true); + + Triangle t= null; + boolean holeLike = false; + if(VectorUtil.ccw(v0,v1,v2)){ + t = new Triangle(v0, v1, v2); + } + else { + holeLike = true; + t = new Triangle(v2, v1, v0); + } + t.setId(maxTriID++); + triangles.add(t); + if(DEBUG){ + System.err.println(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 getContainerLoop(Outline polyline){ + ArrayList<Vertex> vertices = polyline.getVertices(); + for(Vertex vert: vertices){ + for (Loop loop:loops){ + if(loop.checkInside(vert)){ + return loop; + } + } + } + return null; + } +} |