diff options
23 files changed, 4637 insertions, 0 deletions
diff --git a/doc/alt-algorithm-rsantina-01.pdf b/doc/alt-algorithm-rsantina-01.pdf Binary files differnew file mode 100644 index 000000000..969b3a7ae --- /dev/null +++ b/doc/alt-algorithm-rsantina-01.pdf 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;
+ }
+}
|