diff options
Diffstat (limited to 'src/jogl/classes/com/jogamp')
41 files changed, 3846 insertions, 2859 deletions
diff --git a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java index 827717aa5..724380f4a 100755 --- a/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java +++ b/src/jogl/classes/com/jogamp/graph/curve/OutlineShape.java @@ -50,13 +50,13 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; * <br><br>
* Example to creating an Outline Shape:
* <pre>
- addVertex(...)
- addVertex(...)
- addVertex(...)
- addEnptyOutline()
- addVertex(...)
- addVertex(...)
- addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
+ addEnptyOutline()
+ addVertex(...)
+ addVertex(...)
+ addVertex(...)
* </pre>
*
* The above will create two outlines each with three vertices. By adding these two outlines to
@@ -72,10 +72,10 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; *
* <br>Example: <br>
* <pre>
- addVertex(0,0, true);
- addVertex(0,1, false);
- addVertex(1,1, false);
- addVertex(1,0, true);
+ addVertex(0,0, true);
+ addVertex(0,1, false);
+ addVertex(1,1, false);
+ addVertex(1,0, true);
* </pre>
*
* The above snippet defines a cubic nurbs curve where (0,1 and 1,1)
@@ -83,8 +83,8 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; *
* <i>Implementation Notes:</i><br>
* <ul>
- * <li> The first vertex of any outline belonging to the shape should be on-curve</li>
- * <li> Intersections between off-curved parts of the outline is not handled</li>
+ * <li> The first vertex of any outline belonging to the shape should be on-curve</li>
+ * <li> Intersections between off-curved parts of the outline is not handled</li>
* </ul>
*
* @see Outline
@@ -92,216 +92,216 @@ import com.jogamp.graph.curve.tess.CDTriangulator2D; */
public class OutlineShape {
- public static final int QUADRATIC_NURBS = 10;
- private final Vertex.Factory<? extends Vertex> vertexFactory;
+ public static final int QUADRATIC_NURBS = 10;
+ private final Vertex.Factory<? extends Vertex> vertexFactory;
- /** The list of {@link Outline}s that are part of this
- * outline shape.
- */
- private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
+ /** The list of {@link Outline}s that are part of this
+ * outline shape.
+ */
+ private ArrayList<Outline> outlines = new ArrayList<Outline>(3);
- /** Create a new Outline based Shape
- */
- public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
- vertexFactory = factory;
- outlines.add(new Outline());
- }
+ /** Create a new Outline based Shape
+ */
+ public OutlineShape(Vertex.Factory<? extends Vertex> factory) {
+ vertexFactory = factory;
+ outlines.add(new Outline());
+ }
- /** Returns the associated vertex factory of this outline shape
- * @return Vertex.Factory object
- */
- public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
+ /** Returns the associated vertex factory of this outline shape
+ * @return Vertex.Factory object
+ */
+ public final Vertex.Factory<? extends Vertex> vertexFactory() { return vertexFactory; }
- /** Add a new empty {@link Outline}
- * to the shape, this new outline will
- * be placed at the end of the outline list.
- *
- * After a call to this function all new vertices added
- * will belong to the new outline
- */
- public void addEmptyOutline(){
- outlines.add(new Outline());
- }
+ /** Add a new empty {@link Outline}
+ * to the shape, this new outline will
+ * be placed at the end of the outline list.
+ *
+ * After a call to this function all new vertices added
+ * will belong to the new outline
+ */
+ public void addEmptyOutline(){
+ outlines.add(new Outline());
+ }
- /** Adds an {@link Outline} to the OutlineShape object
- * if last outline of the shape is empty, it will replace
- * that last Outline with the new one. If outline is empty,
- * it will do nothing.
- * @param outline an Outline object
- */
- public void addOutline(Outline outline){
- if(outline.isEmpty()){
- return;
- }
- if(getLastOutline().isEmpty()){
- outlines.remove(getLastOutline());
- }
- outlines.add(outline);
- }
+ /** Adds an {@link Outline} to the OutlineShape object
+ * if last outline of the shape is empty, it will replace
+ * that last Outline with the new one. If outline is empty,
+ * it will do nothing.
+ * @param outline an Outline object
+ */
+ public void addOutline(Outline outline){
+ if(outline.isEmpty()){
+ return;
+ }
+ if(getLastOutline().isEmpty()){
+ outlines.remove(getLastOutline());
+ }
+ outlines.add(outline);
+ }
- /** Adds a vertex to the last open outline in the
- * shape.
- * @param v the vertex to be added to the OutlineShape
- */
- public final void addVertex(Vertex v){
- getLastOutline().addVertex(v);
- }
+ /** Adds a vertex to the last open outline in the
+ * shape.
+ * @param v the vertex to be added to the OutlineShape
+ */
+ public final void addVertex(Vertex v){
+ getLastOutline().addVertex(v);
+ }
- /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
- * of the vertex. The 2D vertex will be represented as Z=0.
- *
- * @param x the x coordinate
- * @param y the y coordniate
- * @param onCurve flag if this vertex is on the final curve or defines a curved region
- * of the shape around this vertex.
- */
- public final void addVertex(float x, float y, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, x, y, onCurve);
- }
+ /** Add a 2D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex. The 2D vertex will be represented as Z=0.
+ *
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, onCurve);
+ }
- /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
- * of the vertex.
- * @param x the x coordinate
- * @param y the y coordniate
- * @param z the z coordniate
- * @param onCurve flag if this vertex is on the final curve or defines a curved region
- * of the shape around this vertex.
- */
- public final void addVertex(float x, float y, float z, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
- }
+ /** Add a 3D {@link Vertex} to the last outline by defining the coordniate attribute
+ * of the vertex.
+ * @param x the x coordinate
+ * @param y the y coordniate
+ * @param z the z coordniate
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float x, float y, float z, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, x, y, z, onCurve);
+ }
- /** Add a vertex to the last outline by passing a float array and specifying the
- * offset and length in which. The attributes of the vertex are located.
- * The attributes should be continuous (stride = 0).
- * Attributes which value are not set (when length less than 3)
- * are set implicitly to zero.
- * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
- * @param offset the offset in the buffer to the x coordinate
- * @param length the number of attributes to pick from the buffer (maximum 3)
- * @param onCurve flag if this vertex is on the final curve or defines a curved region
- * of the shape around this vertex.
- */
- public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
- getLastOutline().addVertex(vertexFactory, coordsBuffer, offset, length, onCurve);
- }
+ /** Add a vertex to the last outline by passing a float array and specifying the
+ * offset and length in which. The attributes of the vertex are located.
+ * The attributes should be continuous (stride = 0).
+ * Attributes which value are not set (when length less than 3)
+ * are set implicitly to zero.
+ * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from
+ * @param offset the offset in the buffer to the x coordinate
+ * @param length the number of attributes to pick from the buffer (maximum 3)
+ * @param onCurve flag if this vertex is on the final curve or defines a curved region
+ * of the shape around this vertex.
+ */
+ public final void addVertex(float[] coordsBuffer, int offset, int length, boolean onCurve) {
+ getLastOutline().addVertex(vertexFactory, coordsBuffer, offset, length, onCurve);
+ }
- /** Closes the last outline in the shape
- * if last vertex is not equal to first vertex.
- * A new temp vertex is added at the end which
- * is equal to the first.
- */
- public void closeLastOutline(){
- getLastOutline().setClosed(true);
- }
+ /** Closes the last outline in the shape
+ * if last vertex is not equal to first vertex.
+ * A new temp vertex is added at the end which
+ * is equal to the first.
+ */
+ public void closeLastOutline(){
+ getLastOutline().setClosed(true);
+ }
- /** Get the last added outline to the list
- * of outlines that define the shape
- * @return the last outline
- */
- public final Outline getLastOutline(){
- return outlines.get(outlines.size()-1);
- }
- /** Make sure that the outlines represent
- * the specified destinationType, if not
- * transform outlines to destination type.
- * @param destinationType The curve type needed
- */
- public void transformOutlines(int destinationType){
- if(destinationType == QUADRATIC_NURBS){
- transformOutlinesQuadratic();
- }
- }
+ /** Get the last added outline to the list
+ * of outlines that define the shape
+ * @return the last outline
+ */
+ public final Outline getLastOutline(){
+ return outlines.get(outlines.size()-1);
+ }
+ /** Make sure that the outlines represent
+ * the specified destinationType, if not
+ * transform outlines to destination type.
+ * @param destinationType The curve type needed
+ */
+ public void transformOutlines(int destinationType){
+ if(destinationType == QUADRATIC_NURBS){
+ transformOutlinesQuadratic();
+ }
+ }
- private void transformOutlinesQuadratic(){
- ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
+ private void transformOutlinesQuadratic(){
+ ArrayList<Outline> newOutlines = new ArrayList<Outline>(3);
- /**loop over the outlines and make sure no
- * adj off-curve vertices
- */
- for(Outline outline:outlines){
- Outline newOutline = new Outline();
+ /**loop over the outlines and make sure no
+ * adj off-curve vertices
+ */
+ for(Outline outline:outlines){
+ Outline newOutline = new Outline();
- ArrayList<Vertex> vertices = outline.getVertices();
- int size =vertices.size()-1;
- for(int i=0;i<size;i++){
- Vertex currentVertex = vertices.get(i);
- Vertex nextVertex = vertices.get((i+1)%size);
- if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
- newOutline.addVertex(currentVertex);
+ ArrayList<Vertex> vertices = outline.getVertices();
+ int size =vertices.size()-1;
+ for(int i=0;i<size;i++){
+ Vertex currentVertex = vertices.get(i);
+ Vertex nextVertex = vertices.get((i+1)%size);
+ if(!(currentVertex.isOnCurve()) && !(nextVertex.isOnCurve())) {
+ newOutline.addVertex(currentVertex);
- float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
- newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
- }
- else {
- newOutline.addVertex(currentVertex);
- }
- }
- newOutlines.add(newOutline);
- }
- outlines = newOutlines;
- }
+ float[] newCoords = VectorUtil.mid(currentVertex.getCoord(), nextVertex.getCoord());
+ newOutline.addVertex(vertexFactory, newCoords, 0, 3, true);
+ }
+ else {
+ newOutline.addVertex(currentVertex);
+ }
+ }
+ newOutlines.add(newOutline);
+ }
+ outlines = newOutlines;
+ }
- private void generateVertexIds(){
- int maxVertexId = 0;
- for(Outline outline:outlines){
- ArrayList<Vertex> vertices = outline.getVertices();
- for(Vertex vert:vertices){
- vert.setId(maxVertexId);
- maxVertexId++;
- }
- }
- }
+ private void generateVertexIds(){
+ int maxVertexId = 0;
+ for(Outline outline:outlines){
+ ArrayList<Vertex> vertices = outline.getVertices();
+ for(Vertex vert:vertices){
+ vert.setId(maxVertexId);
+ maxVertexId++;
+ }
+ }
+ }
- /** @return the list of vertices associated with the
- * {@code Outline} list of this object
- */
- public ArrayList<Vertex> getVertices(){
- ArrayList<Vertex> vertices = new ArrayList<Vertex>();
- for(Outline polyline:outlines){
- vertices.addAll(polyline.getVertices());
- }
- return vertices;
- }
+ /** @return the list of vertices associated with the
+ * {@code Outline} list of this object
+ */
+ public ArrayList<Vertex> getVertices(){
+ ArrayList<Vertex> vertices = new ArrayList<Vertex>();
+ for(Outline polyline:outlines){
+ vertices.addAll(polyline.getVertices());
+ }
+ return vertices;
+ }
- /** Triangulate the outline shape generating a list of triangles
- * @return an arraylist of triangles representing the filled region
- * which is produced by the combination of the outlines
- */
- public ArrayList<Triangle> triangulate(){
- return triangulate(0.5f);
- }
+ /** Triangulate the outline shape generating a list of triangles
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(){
+ return triangulate(0.5f);
+ }
- /**Triangulate the {@link OutlineShape} generating a list of triangles
- * @param sharpness defines the curvature strength around the off-curve vertices.
- * defaults to 0.5f
- * @return an arraylist of triangles representing the filled region
- * which is produced by the combination of the outlines
- */
- public ArrayList<Triangle> triangulate(float sharpness){
- if(outlines.size() == 0){
- return null;
- }
- sortOutlines();
- generateVertexIds();
-
- CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness);
- for(int index = 0; index< outlines.size();index++){
- Outline outline = outlines.get(index);
- triangulator2d.addCurve(outline);
- }
-
- ArrayList<Triangle> triangles = triangulator2d.generateTriangulation();
- triangulator2d.reset();
+ /**Triangulate the {@link OutlineShape} generating a list of triangles
+ * @param sharpness defines the curvature strength around the off-curve vertices.
+ * defaults to 0.5f
+ * @return an arraylist of triangles representing the filled region
+ * which is produced by the combination of the outlines
+ */
+ public ArrayList<Triangle> triangulate(float sharpness){
+ if(outlines.size() == 0){
+ return null;
+ }
+ sortOutlines();
+ generateVertexIds();
+
+ CDTriangulator2D triangulator2d = new CDTriangulator2D(sharpness);
+ for(int index = 0; index< outlines.size();index++){
+ Outline outline = outlines.get(index);
+ triangulator2d.addCurve(outline);
+ }
+
+ ArrayList<Triangle> triangles = triangulator2d.generateTriangulation();
+ triangulator2d.reset();
- return triangles;
- }
+ return triangles;
+ }
- /** Sort the outlines from large
- * to small depending on the AABox
- */
- private void sortOutlines() {
- Collections.sort(outlines);
- Collections.reverse(outlines);
- }
+ /** Sort the outlines from large
+ * to small depending on the AABox
+ */
+ private void sortOutlines() {
+ Collections.sort(outlines);
+ Collections.reverse(outlines);
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java index 051cb1c38..eb88b787c 100755 --- a/src/jogl/classes/com/jogamp/graph/curve/Region.java +++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java @@ -29,6 +29,12 @@ package com.jogamp.graph.curve; import java.util.ArrayList;
+import javax.media.opengl.GL2ES2;
+
+import com.jogamp.graph.curve.opengl.RenderState;
+import com.jogamp.graph.geom.AABBox;
+import jogamp.opengl.Debug;
+
import com.jogamp.graph.geom.Triangle;
import com.jogamp.graph.geom.Vertex;
import com.jogamp.opengl.util.PMVMatrix;
@@ -44,85 +50,83 @@ import com.jogamp.opengl.util.PMVMatrix; * @see RegionFactory, OutlineShape
*/
public interface Region {
- /** The vertices index in an OGL object
- */
- public static int VERTEX_ATTR_IDX = 0;
-
- /** The Texture Coord index in an OGL object
- */
- public static int TEXCOORD_ATTR_IDX = 1;
-
- /** single pass rendering, fast, but AA might not be perfect */
- public static int SINGLE_PASS = 1;
-
- /** two pass rendering, slower and more resource hungry (FBO), but AA is perfect */
- public static int TWO_PASS = 2;
-
- /** Updates a graph region by updating the ogl related
- * objects for use in rendering. if called for the first time
- * it initialize the objects.
- */
- public void update();
-
- /** Renders the associated OGL objects specifying
- * current width/hight of window for multi pass rendering
- * of the region.
- * @param matrix current {@link PMVMatrix}.
- * @param vp_width current screen width
- * @param vp_height current screen height
- * @param width texture width for mp rendering
- *
- * @see update()
- */
- public void render(PMVMatrix matrix, int vp_width, int vp_height, int width);
-
- /** Adds a list of {@link Triangle} objects to the Region
- * These triangles are to be binded to OGL objects
- * on the next call to {@code update}
- * @param tris an arraylist of triangle objects
- *
- * @see update()
- */
- public void addTriangles(ArrayList<Triangle> tris);
-
- /** Get the current number of vertices associated
- * with this region. This number is not necessary equal to
- * the OGL binded number of vertices.
- * @return vertices count
- *
- * @see isDirty()
- */
- public int getNumVertices();
-
- /** Adds a list of {@link Vertex} objects to the Region
- * These vertices are to be binded to OGL objects
- * on the next call to {@code update}
- * @param verts an arraylist of vertex objects
- *
- * @see update()
- */
- public void addVertices(ArrayList<Vertex> verts);
-
- /** Check if this region is dirty. A region is marked dirty
- * when new Vertices, Triangles, and or Lines are added after a
- * call to update()
- * @return true if region is Dirty, false otherwise
- *
- * @see update();
- */
- public boolean isDirty();
-
- /** Delete and clean the associated OGL
- * objects
- */
- public void destroy();
-
- public boolean isFlipped();
-
- /** Set if the y coordinate of the region should be flipped
- * {@code y=-y} used mainly for fonts since they use opposite vertex
- * as origion
- * @param flipped flag if the coordinate is flipped defaults to false.
- */
- public void setFlipped(boolean flipped);
+ public static final boolean DEBUG = Debug.debug("graph.curve");
+ public static final boolean DEBUG_INSTANCE = false;
+
+ /** single pass rendering, fast, but AA might not be perfect */
+ public static int SINGLE_PASS = 1;
+
+ /** two pass rendering, slower and more resource hungry (FBO), but AA is perfect */
+ public static int TWO_PASS = 2;
+ public static int TWO_PASS_DEFAULT_TEXTURE_UNIT = 0;
+
+ /** 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(GL2ES2 gl);
+
+ /** Renders the associated OGL objects specifying
+ * current width/hight of window for multi pass rendering
+ * of the region.
+ * @param matrix current {@link PMVMatrix}.
+ * @param vp_width current screen width
+ * @param vp_height current screen height
+ * @param width texture width for mp rendering
+ *
+ * @see update()
+ */
+ public void render(GL2ES2 gl, RenderState rs, int vp_width, int vp_height, int width);
+
+ /** Adds a list of {@link Triangle} objects to the Region
+ * These triangles are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param tris an arraylist of triangle objects
+ *
+ * @see update()
+ */
+ public void addTriangles(ArrayList<Triangle> tris);
+
+ /** Get the current number of vertices associated
+ * with this region. This number is not necessary equal to
+ * the OGL binded number of vertices.
+ * @return vertices count
+ *
+ * @see isDirty()
+ */
+ public int getNumVertices();
+
+ /** Adds a list of {@link Vertex} objects to the Region
+ * These vertices are to be binded to OGL objects
+ * on the next call to {@code update}
+ * @param verts an arraylist of vertex objects
+ *
+ * @see update()
+ */
+ public void addVertices(ArrayList<Vertex> verts);
+
+ /** Check if this region is dirty. A region is marked dirty
+ * when new Vertices, Triangles, and or Lines are added after a
+ * call to update()
+ * @return true if region is Dirty, false otherwise
+ *
+ * @see update();
+ */
+ public boolean isDirty();
+
+ /** Delete and clean the associated OGL
+ * objects
+ */
+ public void destroy(GL2ES2 gl, RenderState rs);
+
+ public AABBox getBounds();
+
+ public boolean isFlipped();
+
+ /** Set if the y coordinate of the region should be flipped
+ * {@code y=-y} used mainly for fonts since they use opposite vertex
+ * as origion
+ * @param flipped flag if the coordinate is flipped defaults to false.
+ */
+ public void setFlipped(boolean flipped);
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java index d3b978b8a..23b318e8a 100755 --- a/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java +++ b/src/jogl/classes/com/jogamp/graph/curve/RegionFactory.java @@ -27,36 +27,43 @@ */
package com.jogamp.graph.curve;
-import javax.media.opengl.GLContext;
-import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
-import com.jogamp.opengl.util.glsl.ShaderState;
+import com.jogamp.graph.curve.opengl.RenderState;
import jogamp.graph.curve.opengl.VBORegionSPES2;
import jogamp.graph.curve.opengl.VBORegion2PES2;
-
/** RegionFactory to create a Context specific Region implementation.
*
* @see Region
*/
public class RegionFactory {
-
- /**Create a Region based on the GLContext attached
- * @param context the current {@link GLContext}
- * @param st the {@link ShaderState} object
- * @param type can be one of Region.SINGLE_PASS or Region.TWO_PASS
- * @return region
- */
- public static Region create(GLContext context, ShaderState st, int type){
- if( !context.isGL2ES2() ) {
- throw new GLException("At least a GL2ES2 GL context is required. Given: " + context);
- }
- if( Region.TWO_PASS == type ){
- return new VBORegion2PES2(context, st);
- }
- else{
- return new VBORegionSPES2(context);
- }
- }
+
+ /**
+ * Create a Region using the passed curren GL object.
+ *
+ * <p> In case {@link Region#TWO_PASS} is being requested the default texture unit
+ * {@link Region#TWO_PASS_DEFAULT_TEXTURE_UNIT} is being used.</p>
+ * @param rs TODO
+ * @param type can be one of {@link Region#SINGLE_PASS} or {@link Region#TWO_PASS}
+ *
+ * @return region
+ */
+ public static Region create(RenderState rs, int type) {
+ if( Region.TWO_PASS == type ){
+ return new VBORegion2PES2(rs, Region.TWO_PASS_DEFAULT_TEXTURE_UNIT);
+ }
+ else{
+ return new VBORegionSPES2(rs);
+ }
+ }
+
+ public static Region createSinglePass(RenderState rs) {
+ return new VBORegionSPES2(rs);
+ }
+
+ public static Region createTwoPass(RenderState rs, int textureUnit) {
+ return new VBORegion2PES2(rs, textureUnit);
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java index c6e03cad6..69fdd5c4a 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RegionRenderer.java @@ -1,3 +1,30 @@ +/** + * 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.opengl; import java.util.ArrayList; @@ -13,15 +40,18 @@ import com.jogamp.graph.geom.Triangle; import com.jogamp.graph.geom.Vertex; public abstract class RegionRenderer extends Renderer { - - /** Create a Hardware accelerated Curve Region Renderer + + /** + * Create a Hardware accelerated Text Renderer. + * @param rs the used {@link RenderState} + * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS} */ - public static RegionRenderer create(Vertex.Factory<? extends Vertex> factory, int type) { - return new jogamp.graph.curve.opengl.RegionRendererImpl01(factory, type); + public static RegionRenderer create(RenderState rs, int type) { + return new jogamp.graph.curve.opengl.RegionRendererImpl01(rs, type); } - public RegionRenderer(Vertex.Factory<? extends Vertex> factory, int type) { - super(factory, type); + protected RegionRenderer(RenderState rs, int type) { + super(rs, type); } /** Render an array of {@link OutlineShape}s combined in one region @@ -45,52 +75,50 @@ public abstract class RegionRenderer extends Renderer { protected HashMap<Integer, Region> regions = new HashMap<Integer, Region>(); - public void flushCache() { + public void flushCache(GL2ES2 gl) { Iterator<Region> iterator = regions.values().iterator(); while(iterator.hasNext()){ Region region = iterator.next(); - region.destroy(); + region.destroy(gl, rs); } regions.clear(); } @Override protected void disposeImpl(GL2ES2 gl) { - flushCache(); + // fluchCache(gl) already called } - /** Create an ogl {@link Region} defining this {@link OutlineShape} - * @param sharpness parameter for Region generation + /** + * Create an ogl {@link Region} defining this {@link OutlineShape} * @return the resulting Region. */ - protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape, float sharpness) { - Region region = RegionFactory.create(gl.getContext(), st, renderType); + protected Region createRegion(GL2ES2 gl, OutlineShape outlineShape) { + Region region = RegionFactory.create(rs, renderType); outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); - - ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(sharpness); + ArrayList<Triangle> triangles = (ArrayList<Triangle>) outlineShape.triangulate(rs.getSharpness().floatValue()); ArrayList<Vertex> vertices = (ArrayList<Vertex>) outlineShape.getVertices(); region.addVertices(vertices); region.addTriangles(triangles); - region.update(); + region.update(gl); return region; } /** Create an ogl {@link Region} defining the list of {@link OutlineShape}. * Combining the Shapes into single buffers. - * @param sharpness parameter for Region generation * @return the resulting Region inclusive the generated region */ - protected Region createRegion(GL2ES2 gl, OutlineShape[] outlineShapes, float sharpness) { - Region region = RegionFactory.create(gl.getContext(), st, renderType); + protected Region createRegion(GL2ES2 gl, OutlineShape[] outlineShapes) { + Region region = RegionFactory.create(rs, renderType); int numVertices = region.getNumVertices(); for(OutlineShape outlineShape:outlineShapes){ outlineShape.transformOutlines(OutlineShape.QUADRATIC_NURBS); - ArrayList<Triangle> triangles = outlineShape.triangulate(sharpness); + ArrayList<Triangle> triangles = outlineShape.triangulate(rs.getSharpness().floatValue()); region.addTriangles(triangles); ArrayList<Vertex> vertices = outlineShape.getVertices(); @@ -100,7 +128,7 @@ public abstract class RegionRenderer extends Renderer { region.addVertices(vertices); } - region.update(); + region.update(gl); return region; } diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java new file mode 100644 index 000000000..84323f6e5 --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/RenderState.java @@ -0,0 +1,55 @@ +/** + * Copyright 2011 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.opengl; + +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLUniformData; + +import com.jogamp.graph.geom.Vertex; +import com.jogamp.opengl.util.PMVMatrix; +import com.jogamp.opengl.util.glsl.ShaderState; + +public interface RenderState { + + void destroy(GL2ES2 gl); + + ShaderState getShaderState(); + Vertex.Factory<? extends Vertex> getPointFactory(); + PMVMatrix pmvMatrix(); + GLUniformData getPMVMatrix(); + GLUniformData getSharpness(); + GLUniformData getAlpha(); + GLUniformData getColorStatic(); + GLUniformData getStrength(); + + RenderState attachTo(GL2ES2 gl); + boolean detachFrom(GL2ES2 gl); + + StringBuilder toString(StringBuilder sb); + String toString(); +} diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java index 57eeb016f..35022f769 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/Renderer.java @@ -1,39 +1,75 @@ +/** + * 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.opengl; +import java.nio.FloatBuffer; + import javax.media.opengl.GL2ES2; import javax.media.opengl.GLUniformData; import javax.media.opengl.fixedfunc.GLMatrixFunc; -import jogamp.opengl.Debug; +import jogamp.graph.curve.opengl.RenderStateImpl; +import com.jogamp.graph.curve.Region; import com.jogamp.graph.geom.Vertex; -import com.jogamp.graph.geom.opengl.SVertex; import com.jogamp.opengl.util.PMVMatrix; import com.jogamp.opengl.util.glsl.ShaderState; public abstract class Renderer { - protected static final boolean DEBUG = Debug.debug("CurveRenderer"); + protected static final boolean DEBUG = Region.DEBUG; + protected static final boolean DEBUG_INSTANCE = Region.DEBUG_INSTANCE; + + public static RenderState createRenderState(ShaderState st, Vertex.Factory<? extends Vertex> pointFactory, PMVMatrix pmvMatrix) { + return new RenderStateImpl(st, pointFactory, pmvMatrix); + } - protected abstract boolean initImpl(GL2ES2 gl); + public static RenderState createRenderState(ShaderState st, Vertex.Factory<? extends Vertex> pointFactory) { + return new RenderStateImpl(st, pointFactory); + } + + /** + * Implementation shall load, compile and link the shader program and leave it active. + * @param gl + * @return + */ + protected abstract boolean initShaderProgram(GL2ES2 gl); protected abstract void disposeImpl(GL2ES2 gl); /** * Flushes all cached data + * @see #destroy(GL2ES2) */ - public abstract void flushCache(); + public abstract void flushCache(GL2ES2 gl); + + protected final RenderState rs; + public final int renderType; - public abstract float getAlpha(); - - public abstract void setAlpha(GL2ES2 gl, float alpha_t); - - public abstract void setColor(GL2ES2 gl, float r, float g, float b); - - protected final Vertex.Factory<? extends Vertex> pointFactory; - protected ShaderState st = new ShaderState(); - protected PMVMatrix pmvMatrix = new PMVMatrix(); - protected GLUniformData mgl_PMVMatrix; - protected int renderType; protected int vp_width = 0; protected int vp_height = 0; @@ -41,16 +77,15 @@ public abstract class Renderer { private boolean initialized = false; /** - * - * @param factory + * @param rs the used {@link RenderState} * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS} */ - protected Renderer(Vertex.Factory<? extends Vertex> factory, int renderType) { + protected Renderer(RenderState rs, int renderType) { + this.rs = rs; this.renderType = renderType; - this.pointFactory = (null != factory) ? factory : SVertex.factory(); } - public Vertex.Factory<? extends Vertex> getFactory() { return pointFactory; } + public Vertex.Factory<? extends Vertex> getFactory() { return rs.getPointFactory(); } public final boolean isInitialized() { return initialized; } @@ -62,10 +97,12 @@ public abstract class Renderer { public final int getHeight() { return vp_height; } /** - * Initialize shaders and bindings for GPU based rendering. - * Leaves the renderer enabled, ie ShaderState on. + * Initialize shader and bindings for GPU based rendering bound to the given GL object's GLContext. * - * @param gl the current GL state + * Leaves the renderer enabled, ie ShaderState. + * + * @param gl referencing the current GLContext to which the ShaderState is bound to + * * @return true if succeeded, false otherwise */ public boolean init(GL2ES2 gl) { @@ -86,85 +123,176 @@ public abstract class Renderer { System.err.println("TextRendererImpl01: VBO Supported = " + isVBOSupported()); } - initialized = initImpl(gl); + if(!vboSupported){ + return false; + } + + rs.attachTo(gl); + + gl.glEnable(GL2ES2.GL_BLEND); + gl.glBlendFunc(GL2ES2.GL_SRC_ALPHA, GL2ES2.GL_ONE_MINUS_SRC_ALPHA); // FIXME: alpha blending stage ? + + initialized = initShaderProgram(gl); + if(!initialized) { + return false; + } + + if(!rs.getShaderState().uniform(gl, rs.getPMVMatrix())) { + if(DEBUG){ + System.err.println("Error setting PMVMatrix in shader: "+rs.getShaderState()); + } + return false; + } + + if(!rs.getShaderState().uniform(gl, rs.getSharpness())) { + if(DEBUG){ + System.err.println("Error setting sharpness in shader: "+rs.getShaderState()); + } + return false; + } + + if(!rs.getShaderState().uniform(gl, rs.getAlpha())) { + if(DEBUG){ + System.err.println("Error setting global alpha in shader: "+rs.getShaderState()); + } + return false; + } + + if(!rs.getShaderState().uniform(gl, rs.getColorStatic())) { + if(DEBUG){ + System.err.println("Error setting global color in shader: "+rs.getShaderState()); + } + return false; + } + + if(!rs.getShaderState().uniform(gl, rs.getStrength())) { + System.err.println("Error setting antialias strength in shader: "+rs.getShaderState()); + } + return initialized; } - public void dispose(GL2ES2 gl) { + public void destroy(GL2ES2 gl) { if(!initialized){ - if(DEBUG) { + if(DEBUG_INSTANCE) { System.err.println("TextRenderer: Not initialized!"); } return; } + rs.getShaderState().useProgram(gl, false); + flushCache(gl); disposeImpl(gl); - st.destroy(gl); - flushCache(); + rs.destroy(gl); initialized = false; } - public final ShaderState getShaderState() { return st; } + public final RenderState getRenderState() { return rs; } + public final ShaderState getShaderState() { return rs.getShaderState(); } public final void enable(GL2ES2 gl, boolean enable) { - st.glUseProgram(gl, enable); + rs.getShaderState().useProgram(gl, enable); } - public final PMVMatrix getMatrix() { return pmvMatrix; } + public float getSharpness() { + return rs.getSharpness().floatValue(); + } + + public void setSharpness(GL2ES2 gl, float v) { + rs.getSharpness().setData(v); + if(null != gl && rs.getShaderState().inUse()) { + rs.getShaderState().uniform(gl, rs.getSharpness()); + } + } - public void rotate(GL2ES2 gl, float angle, float x, float y, float z) { - pmvMatrix.glRotatef(angle, x, y, z); - if(initialized && null != gl && st.inUse()) { - st.glUniform(gl, mgl_PMVMatrix); + public float getStrength() { + return rs.getStrength().floatValue(); + } + + public void setStrength(GL2ES2 gl, float v) { + rs.getStrength().setData(v); + if(null != gl && rs.getShaderState().inUse()) { + rs.getShaderState().uniform(gl, rs.getStrength()); } } + + public float getAlpha() { + return rs.getAlpha().floatValue(); + } - public void translate(GL2ES2 gl, float x, float y, float z) { - pmvMatrix.glTranslatef(x, y, z); - if(initialized && null != gl && st.inUse()) { - st.glUniform(gl, mgl_PMVMatrix); + public void setAlpha(GL2ES2 gl, float alpha_t) { + rs.getAlpha().setData(alpha_t); + if(null != gl && rs.getShaderState().inUse()) { + rs.getShaderState().uniform(gl, rs.getAlpha()); } + } - public void resetModelview(GL2ES2 gl) { - pmvMatrix.glMatrixMode(GLMatrixFunc.GL_MODELVIEW); - pmvMatrix.glLoadIdentity(); - if(initialized && null != gl && st.inUse()) { - st.glUniform(gl, mgl_PMVMatrix); + public void getColorStatic(GL2ES2 gl, float[] rgb) { + FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer(); + rgb[0] = fb.get(0); + rgb[1] = fb.get(1); + rgb[2] = fb.get(2); + } + + public void setColorStatic(GL2ES2 gl, float r, float g, float b){ + FloatBuffer fb = (FloatBuffer) rs.getColorStatic().getBuffer(); + fb.put(0, r); + fb.put(1, g); + fb.put(2, b); + if(null != gl && rs.getShaderState().inUse()) { + rs.getShaderState().uniform(gl, rs.getColorStatic()); } } + + public final PMVMatrix getMatrix() { return rs.pmvMatrix(); } + + public void rotate(GL2ES2 gl, float angle, float x, float y, float z) { + rs.pmvMatrix().glRotatef(angle, x, y, z); + updateMatrix(gl); + } + + public void translate(GL2ES2 gl, float x, float y, float z) { + rs.pmvMatrix().glTranslatef(x, y, z); + updateMatrix(gl); + } + + public void scale(GL2ES2 gl, float x, float y, float z) { + rs.pmvMatrix().glScalef(x, y, z); + updateMatrix(gl); + } + + public void resetModelview(GL2ES2 gl) { + rs.pmvMatrix().glMatrixMode(GLMatrixFunc.GL_MODELVIEW); + rs.pmvMatrix().glLoadIdentity(); + updateMatrix(gl); + } public void updateMatrix(GL2ES2 gl) { - if(initialized && null != gl && st.inUse()) { - st.glUniform(gl, mgl_PMVMatrix); + if(initialized && null != gl && rs.getShaderState().inUse()) { + rs.getShaderState().uniform(gl, rs.getPMVMatrix()); } } public boolean reshapePerspective(GL2ES2 gl, float angle, int width, int height, float near, float far) { this.vp_width = width; this.vp_height = height; - float ratio = (float)width/(float)height; - pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - pmvMatrix.glLoadIdentity(); - pmvMatrix.gluPerspective(angle, ratio, near, far); - - if(initialized && null != gl) { - st.glUniform(gl, mgl_PMVMatrix); - } - + final float ratio = (float)width/(float)height; + final PMVMatrix p = rs.pmvMatrix(); + p.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + p.glLoadIdentity(); + p.gluPerspective(angle, ratio, near, far); + updateMatrix(gl); return true; } public boolean reshapeOrtho(GL2ES2 gl, int width, int height, float near, float far) { this.vp_width = width; this.vp_height = height; - pmvMatrix.glMatrixMode(GLMatrixFunc.GL_PROJECTION); - pmvMatrix.glLoadIdentity(); - pmvMatrix.glOrthof(0, width, 0, height, near, far); - - if(initialized && null != gl) { - st.glUniform(gl, mgl_PMVMatrix); - } - + final PMVMatrix p = rs.pmvMatrix(); + p.glMatrixMode(GLMatrixFunc.GL_PROJECTION); + p.glLoadIdentity(); + p.glOrthof(0, width, 0, height, near, far); + updateMatrix(gl); return true; } diff --git a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java index 45f78fc23..deaa1dfad 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java +++ b/src/jogl/classes/com/jogamp/graph/curve/opengl/TextRenderer.java @@ -1,9 +1,37 @@ +/** + * 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.opengl; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import javax.media.opengl.GL; import javax.media.opengl.GL2ES2; import jogamp.graph.curve.text.GlyphString; @@ -12,21 +40,21 @@ import jogamp.graph.geom.plane.AffineTransform; import jogamp.graph.geom.plane.Path2D; import com.jogamp.graph.font.Font; -import com.jogamp.graph.geom.Vertex; public abstract class TextRenderer extends Renderer { - /** * Create a Hardware accelerated Text Renderer. - * @param factory optional Point.Factory for Vertex construction. Default is Vertex.Factory. + * @param rs the used {@link RenderState} + * @param renderType either {@link com.jogamp.graph.curve.Region#SINGLE_PASS} or {@link com.jogamp.graph.curve.Region#TWO_PASS} */ - public static TextRenderer create(Vertex.Factory<? extends Vertex> factory, int type) { - return new jogamp.graph.curve.opengl.TextRendererImpl01(factory, type); + public static TextRenderer create(RenderState rs, int type) { + return new jogamp.graph.curve.opengl.TextRendererImpl01(rs, type); } - protected TextRenderer(Vertex.Factory<? extends Vertex> factory, int type) { - super(factory, type); + protected TextRenderer(RenderState rs, int type) { + super(rs, type); } + /** Render the String in 3D space wrt to the font provided at the position provided * the outlines will be generated, if not yet generated @@ -46,27 +74,29 @@ public abstract class TextRenderer extends Renderer { * @param font {@link Font} to be used * @param size font size * @param str {@link String} to be created - * @param sharpness parameter for Region generation of the resulting GlyphString * @return the resulting GlyphString inclusive the generated region */ - protected GlyphString createString(GL2ES2 gl, Font font, int size, String str, float sharpness) { - AffineTransform affineTransform = new AffineTransform(pointFactory); + public GlyphString createString(GL2ES2 gl, Font font, int size, String str) { + if(DEBUG_INSTANCE) { + System.err.println("createString: "+getCacheSize()+"/"+getCacheLimit()+" - "+Font.NAME_UNIQUNAME + " - " + str + " - " + size); + } + AffineTransform affineTransform = new AffineTransform(rs.getPointFactory()); Path2D[] paths = new Path2D[str.length()]; ((FontInt)font).getOutline(str, size, affineTransform, paths); - GlyphString glyphString = new GlyphString(pointFactory, font.getName(Font.NAME_UNIQUNAME), str); - glyphString.createfromFontPath(paths, affineTransform); - glyphString.generateRegion(gl.getContext(), sharpness, st, renderType); + GlyphString glyphString = new GlyphString(font.getName(Font.NAME_UNIQUNAME), str); + glyphString.createfromFontPath(rs.getPointFactory(), paths, affineTransform); + glyphString.generateRegion(gl, rs, renderType); return glyphString; } - public void flushCache() { + public void flushCache(GL2ES2 gl) { Iterator<GlyphString> iterator = stringCacheMap.values().iterator(); while(iterator.hasNext()){ GlyphString glyphString = iterator.next(); - glyphString.destroy(); + glyphString.destroy(gl, rs); } stringCacheMap.clear(); stringCacheArray.clear(); @@ -74,35 +104,90 @@ public abstract class TextRenderer extends Renderer { @Override protected void disposeImpl(GL2ES2 gl) { - flushCache(); + // fluchCache(gl) already called } - public final void setCacheMaxSize(int newSize ) { stringCacheMaxSize = newSize; validateCache(0); } - public final int getCacheMaxSize() { return stringCacheMaxSize; } + /** + * <p>Sets the cache limit for reusing GlyphString's and their Region. + * Default is {@link #DEFAULT_CACHE_LIMIT}, -1 unlimited, 0 turns cache off, >0 limited </p> + * + * <p>The cache will be validate when the next string rendering happens.</p> + * + * @param newLimit new cache size + * + * @see #DEFAULT_CACHE_LIMIT + */ + public final void setCacheLimit(int newLimit ) { stringCacheLimit = newLimit; } + + /** + * Sets the cache limit, see {@link #setCacheLimit(int)} and validates the cache. + * + * @see #setCacheLimit(int) + * + * @param gl current GL used to remove cached objects if required + * @param newLimit new cache size + */ + public final void setCacheLimit(GL2ES2 gl, int newLimit ) { stringCacheLimit = newLimit; validateCache(gl, 0); } + + /** + * @return the current cache limit + */ + public final int getCacheLimit() { return stringCacheLimit; } + + /** + * @return the current utilized cache size, <= {@link #getCacheLimit()} + */ public final int getCacheSize() { return stringCacheArray.size(); } - protected void validateCache(int space) { - while ( getCacheSize() + space > getCacheMaxSize() ) { - String key = stringCacheArray.remove(0); - stringCacheMap.remove(key); + protected final void validateCache(GL2ES2 gl, int space) { + if ( getCacheLimit() > 0 ) { + while ( getCacheSize() + space > getCacheLimit() ) { + removeCachedGlyphString(gl, 0); + } } } - protected GlyphString getCachedGlyphString(Font font, String str, int fontSize) { - final String key = font.getName(Font.NAME_UNIQUNAME) + "." + str.hashCode() + "." + fontSize; - return stringCacheMap.get(key); + protected final GlyphString getCachedGlyphString(Font font, String str, int fontSize) { + return stringCacheMap.get(getKey(font, str, fontSize)); } - protected void addCachedGlyphString(Font font, String str, int fontSize, GlyphString glyphString) { - final String key = font.getName(Font.NAME_UNIQUNAME) + "." + str.hashCode() + "." + fontSize; - validateCache(1); - stringCacheMap.put(key, glyphString); - stringCacheArray.add(stringCacheArray.size(), key); + protected final void addCachedGlyphString(GL2ES2 gl, Font font, String str, int fontSize, GlyphString glyphString) { + if ( 0 != getCacheLimit() ) { + final String key = getKey(font, str, fontSize); + GlyphString oldGlyphString = stringCacheMap.put(key, glyphString); + if ( null == oldGlyphString ) { + // new entry .. + validateCache(gl, 1); + stringCacheArray.add(stringCacheArray.size(), key); + } /// else overwrite is nop .. + } + } + + protected final void removeCachedGlyphString(GL2ES2 gl, Font font, String str, int fontSize) { + final String key = getKey(font, str, fontSize); + GlyphString glyphString = stringCacheMap.remove(key); + if(null != glyphString) { + glyphString.destroy(gl, rs); + } + stringCacheArray.remove(key); + } + + protected final void removeCachedGlyphString(GL2ES2 gl, int idx) { + final String key = stringCacheArray.remove(idx); + final GlyphString glyphString = stringCacheMap.remove(key); + if(null != glyphString) { + glyphString.destroy(gl, rs); + } + } + + protected final String getKey(Font font, String str, int fontSize) { + return font.getName(Font.NAME_UNIQUNAME) + "." + str.hashCode() + "." + fontSize; } - // Cache is adding at the end of the array - public static final int DEFAULT_CACHE_SIZE = 32; - private HashMap<String, GlyphString> stringCacheMap = new HashMap<String, GlyphString>(DEFAULT_CACHE_SIZE); - private ArrayList<String> stringCacheArray = new ArrayList<String>(DEFAULT_CACHE_SIZE); - private int stringCacheMaxSize = DEFAULT_CACHE_SIZE; // -1 unlimited, 0 off, >0 limited + /** Default cache limit, see {@link #setCacheLimit(int)} */ + public static final int DEFAULT_CACHE_LIMIT = 256; + + private HashMap<String, GlyphString> stringCacheMap = new HashMap<String, GlyphString>(DEFAULT_CACHE_LIMIT); + private ArrayList<String> stringCacheArray = new ArrayList<String>(DEFAULT_CACHE_LIMIT); + private int stringCacheLimit = DEFAULT_CACHE_LIMIT; }
\ No newline at end of file diff --git a/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java index a2e4ca50f..42eebf7a8 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java +++ b/src/jogl/classes/com/jogamp/graph/curve/tess/CDTriangulator2D.java @@ -48,169 +48,169 @@ import jogamp.opengl.Debug; */ public class CDTriangulator2D { - protected static final boolean DEBUG = Debug.debug("Triangulation"); - - private float sharpness = 0.5f; - private ArrayList<Loop> loops; - private ArrayList<Vertex> vertices; - - private ArrayList<Triangle> triangles; - private int maxTriID = 0; + protected static final boolean DEBUG = Debug.debug("Triangulation"); + + private float sharpness = 0.5f; + private ArrayList<Loop> loops; + private ArrayList<Vertex> vertices; + + private ArrayList<Triangle> triangles; + private int maxTriID = 0; - - public CDTriangulator2D() { - this(0.5f); - } - - /** Constructor for a new Delaunay triangulator - * @param curveSharpness the curvature around - * the off-curve vertices - */ - public CDTriangulator2D(float curveSharpness) { - this.sharpness = curveSharpness; - reset(); - } - - /** Reset the triangulation to initial state - * Clearing cached data - */ - public void reset() { - maxTriID = 0; - vertices = new ArrayList<Vertex>(); - triangles = new ArrayList<Triangle>(3); - loops = new ArrayList<Loop>(); - } - - /** Add a curve to the list of profiles provided - * @param polyline a bounding {@link Outline} - */ - public void addCurve(Outline polyline){ - Loop loop = null; - - if(!loops.isEmpty()){ - loop = getContainerLoop(polyline); - } - - if(loop == null) { - GraphOutline outline = new GraphOutline(polyline); - GraphOutline innerPoly = extractBoundaryTriangles(outline, false); - vertices.addAll(polyline.getVertices()); - loop = new Loop(innerPoly, VectorUtil.CCW); - loops.add(loop); - } - else { - GraphOutline outline = new GraphOutline(polyline); - GraphOutline innerPoly = extractBoundaryTriangles(outline, true); - vertices.addAll(innerPoly.getPoints()); - loop.addConstraintCurve(innerPoly); - } - } - - /** Generate the triangulation of the provided - * List of {@link Outline}s - */ - public ArrayList<Triangle> generateTriangulation(){ - for(int i=0;i<loops.size();i++) { - Loop loop = loops.get(i); - int numTries = 0; - int size = loop.computeLoopSize(); - while(!loop.isSimplex()){ - Triangle tri = null; - if(numTries > size){ - tri = loop.cut(false); - } - else{ - tri = loop.cut(true); - } - numTries++; + + public CDTriangulator2D() { + this(0.5f); + } + + /** Constructor for a new Delaunay triangulator + * @param curveSharpness the curvature around + * the off-curve vertices + */ + public CDTriangulator2D(float curveSharpness) { + this.sharpness = curveSharpness; + reset(); + } + + /** Reset the triangulation to initial state + * Clearing cached data + */ + public void reset() { + maxTriID = 0; + vertices = new ArrayList<Vertex>(); + triangles = new ArrayList<Triangle>(3); + loops = new ArrayList<Loop>(); + } + + /** Add a curve to the list of profiles provided + * @param polyline a bounding {@link Outline} + */ + public void addCurve(Outline polyline){ + Loop loop = null; + + if(!loops.isEmpty()){ + loop = getContainerLoop(polyline); + } + + if(loop == null) { + GraphOutline outline = new GraphOutline(polyline); + GraphOutline innerPoly = extractBoundaryTriangles(outline, false); + vertices.addAll(polyline.getVertices()); + loop = new Loop(innerPoly, VectorUtil.CCW); + loops.add(loop); + } + else { + GraphOutline outline = new GraphOutline(polyline); + GraphOutline innerPoly = extractBoundaryTriangles(outline, true); + vertices.addAll(innerPoly.getPoints()); + loop.addConstraintCurve(innerPoly); + } + } + + /** Generate the triangulation of the provided + * List of {@link Outline}s + */ + public ArrayList<Triangle> generateTriangulation(){ + for(int i=0;i<loops.size();i++) { + Loop loop = loops.get(i); + int numTries = 0; + int size = loop.computeLoopSize(); + while(!loop.isSimplex()){ + Triangle tri = null; + if(numTries > size){ + tri = loop.cut(false); + } + else{ + tri = loop.cut(true); + } + numTries++; - if(tri != null) { - numTries = 0; - size--; - tri.setId(maxTriID++); - triangles.add(tri); - if(DEBUG){ - System.err.println(tri); - } - } - if(numTries > size*2){ - if(DEBUG){ - System.err.println("Triangulation not complete!"); - } - break; - } - } - Triangle tri = loop.cut(true); - if(tri != null) - triangles.add(tri); - } - return triangles; - } + if(tri != null) { + numTries = 0; + size--; + tri.setId(maxTriID++); + triangles.add(tri); + if(DEBUG){ + System.err.println(tri); + } + } + if(numTries > size*2){ + if(DEBUG){ + System.err.println("Triangulation not complete!"); + } + break; + } + } + Triangle tri = loop.cut(true); + if(tri != null) + triangles.add(tri); + } + return triangles; + } - private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole){ - GraphOutline innerOutline = new GraphOutline(); - ArrayList<GraphVertex> outVertices = outline.getGraphPoint(); - int size = outVertices.size(); - for(int i=0; i < size; i++) { - GraphVertex currentVertex = outVertices.get(i); - GraphVertex gv0 = outVertices.get((i+size-1)%size); - GraphVertex gv2 = outVertices.get((i+1)%size); - GraphVertex gv1 = currentVertex; - - if(!currentVertex.getPoint().isOnCurve()) { - Vertex v0 = gv0.getPoint().clone(); - Vertex v2 = gv2.getPoint().clone(); - Vertex v1 = gv1.getPoint().clone(); - - gv0.setBoundaryContained(true); - gv1.setBoundaryContained(true); - gv2.setBoundaryContained(true); - - Triangle t= null; - boolean holeLike = false; - if(VectorUtil.ccw(v0,v1,v2)){ - t = new Triangle(v0, v1, v2); - } - else { - holeLike = true; - t = new Triangle(v2, v1, v0); - } - t.setId(maxTriID++); - triangles.add(t); - if(DEBUG){ - System.err.println(t); - } - if(hole || holeLike) { - v0.setTexCoord(0, -0.1f); - v2.setTexCoord(1, -0.1f); - v1.setTexCoord(0.5f, -1*sharpness -0.1f); - innerOutline.addVertex(currentVertex); - } - else { - v0.setTexCoord(0, 0.1f); - v2.setTexCoord(1, 0.1f); - v1.setTexCoord(0.5f, sharpness+0.1f); - } - } - else { - if(!gv2.getPoint().isOnCurve() || !gv0.getPoint().isOnCurve()){ - currentVertex.setBoundaryContained(true); - } - innerOutline.addVertex(currentVertex); - } - } - return innerOutline; - } - - private Loop getContainerLoop(Outline polyline){ - ArrayList<Vertex> vertices = polyline.getVertices(); - for(Vertex vert: vertices){ - for (Loop loop:loops){ - if(loop.checkInside(vert)){ - return loop; - } - } - } - return null; - } + private GraphOutline extractBoundaryTriangles(GraphOutline outline, boolean hole){ + GraphOutline innerOutline = new GraphOutline(); + ArrayList<GraphVertex> outVertices = outline.getGraphPoint(); + int size = outVertices.size(); + for(int i=0; i < size; i++) { + GraphVertex currentVertex = outVertices.get(i); + GraphVertex gv0 = outVertices.get((i+size-1)%size); + GraphVertex gv2 = outVertices.get((i+1)%size); + GraphVertex gv1 = currentVertex; + + if(!currentVertex.getPoint().isOnCurve()) { + Vertex v0 = gv0.getPoint().clone(); + Vertex v2 = gv2.getPoint().clone(); + Vertex v1 = gv1.getPoint().clone(); + + gv0.setBoundaryContained(true); + gv1.setBoundaryContained(true); + gv2.setBoundaryContained(true); + + Triangle t= null; + boolean holeLike = false; + if(VectorUtil.ccw(v0,v1,v2)){ + t = new Triangle(v0, v1, v2); + } + else { + holeLike = true; + t = new Triangle(v2, v1, v0); + } + t.setId(maxTriID++); + triangles.add(t); + if(DEBUG){ + System.err.println(t); + } + if(hole || holeLike) { + v0.setTexCoord(0, -0.1f); + v2.setTexCoord(1, -0.1f); + v1.setTexCoord(0.5f, -1*sharpness -0.1f); + innerOutline.addVertex(currentVertex); + } + else { + v0.setTexCoord(0, 0.1f); + v2.setTexCoord(1, 0.1f); + v1.setTexCoord(0.5f, sharpness+0.1f); + } + } + else { + if(!gv2.getPoint().isOnCurve() || !gv0.getPoint().isOnCurve()){ + currentVertex.setBoundaryContained(true); + } + innerOutline.addVertex(currentVertex); + } + } + return innerOutline; + } + + private Loop getContainerLoop(Outline polyline){ + ArrayList<Vertex> vertices = polyline.getVertices(); + for(Vertex vert: vertices){ + for (Loop loop:loops){ + if(loop.checkInside(vert)){ + return loop; + } + } + } + return null; + } } diff --git a/src/jogl/classes/com/jogamp/graph/font/Font.java b/src/jogl/classes/com/jogamp/graph/font/Font.java index d8c30c61b..1010d4f1a 100644 --- a/src/jogl/classes/com/jogamp/graph/font/Font.java +++ b/src/jogl/classes/com/jogamp/graph/font/Font.java @@ -52,27 +52,27 @@ public interface Font { public static final int NAME_DESIGNER = 9; - /** - * Metrics for font - * - * Depending on the font's direction, horizontal or vertical, - * the following tables shall be used: - * - * Vertical http://developer.apple.com/fonts/TTRefMan/RM06/Chap6vhea.html + /** + * Metrics for font + * + * Depending on the font's direction, horizontal or vertical, + * the following tables shall be used: + * + * Vertical http://developer.apple.com/fonts/TTRefMan/RM06/Chap6vhea.html * Horizontal http://developer.apple.com/fonts/TTRefMan/RM06/Chap6hhea.html - */ + */ public interface Metrics { - float getAscent(float pixelSize); - float getDescent(float pixelSize); - float getLineGap(float pixelSize); - float getMaxExtend(float pixelSize); - float getScale(float pixelSize); - AABBox getBBox(float pixelSize); + float getAscent(float pixelSize); + float getDescent(float pixelSize); + float getLineGap(float pixelSize); + float getMaxExtend(float pixelSize); + float getScale(float pixelSize); + AABBox getBBox(float pixelSize); } - /** - * Glyph for font - */ + /** + * Glyph for font + */ public interface Glyph { public Font getFont(); public char getSymbol(); diff --git a/src/jogl/classes/com/jogamp/graph/geom/AABBox.java b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java index 8cd06329e..7051e9110 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/AABBox.java +++ b/src/jogl/classes/com/jogamp/graph/geom/AABBox.java @@ -36,176 +36,181 @@ import com.jogamp.graph.math.VectorUtil; * */ public class AABBox { - private float[] low = {Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE}; - private float[] high = {-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE}; - private float[] center = new float[3]; + private float[] low = new float[3]; + private float[] high = new float[3]; + private float[] center = new float[3]; - /** Create a Axis Aligned bounding box (AABBox) - * where the low and and high MAX float Values. - */ - public AABBox() {} + /** Create a Axis Aligned bounding box (AABBox) + * where the low and and high MAX float Values. + */ + public AABBox() { + reset(); + } - /** Create an AABBox specifying the coordinates - * of the low and high - * @param lx min x-coordinate - * @param ly min y-coordnate - * @param lz min z-coordinate - * @param hx max x-coordinate - * @param hy max y-coordinate - * @param hz max z-coordinate - */ - public AABBox(float lx, float ly, float lz, - float hx, float hy, float hz) - { - setLow(lx, ly, lz); - setHigh(hx, hy, hz); + /** Create an AABBox specifying the coordinates + * of the low and high + * @param lx min x-coordinate + * @param ly min y-coordnate + * @param lz min z-coordinate + * @param hx max x-coordinate + * @param hy max y-coordinate + * @param hz max z-coordinate + */ + public AABBox(float lx, float ly, float lz, + float hx, float hy, float hz) + { + reset(); + resize(lx, ly, lz); + resize(hx, hy, hz); - computeCenter(); - } - - /** Create a AABBox defining the low and high - * @param low min xyz-coordinates - * @param high max xyz-coordinates - */ - public AABBox(float[] low, float[] high) - { - this.low = low; - this.high = high; + computeCenter(); + } + + /** Create a AABBox defining the low and high + * @param low min xyz-coordinates + * @param high max xyz-coordinates + */ + public AABBox(float[] low, float[] high) { + reset(); + resize(low[0],low[1],low[2]); + resize(high[0],high[1],high[2]); - computeCenter(); - } - - /** Get the max xyz-coordinates - * @return a float array containing the max xyz coordinates - */ - public float[] getHigh() - { - return high; - } - - private void setHigh(float hx, float hy, float hz) - { - this.high[0] = hx; - this.high[1] = hy; - this.high[2] = hz; - } - - /** Get the min xyz-coordinates - * @return a float array containing the min xyz coordinates - */ - public float[] getLow() - { - return low; - } - - private void setLow(float lx, float ly, float lz) - { - this.low[0] = lx; - this.low[1] = ly; - this.low[2] = lz; - } + computeCenter(); + } + + /** resets this box to the inverse low/high, allowing the next {@link #resize(float, float, float)} command to hit. */ + public void reset() { + setLow(Float.MAX_VALUE,Float.MAX_VALUE,Float.MAX_VALUE); + setHigh(-1*Float.MAX_VALUE,-1*Float.MAX_VALUE,-1*Float.MAX_VALUE); + center[0] = 0f; + center[1] = 0f; + center[2] = 0f; + } + + /** Get the max xyz-coordinates + * @return a float array containing the max xyz coordinates + */ + public float[] getHigh() { + return high; + } + + private void setHigh(float hx, float hy, float hz) { + this.high[0] = hx; + this.high[1] = hy; + this.high[2] = hz; + } + + /** Get the min xyz-coordinates + * @return a float array containing the min xyz coordinates + */ + public float[] getLow() { + return low; + } + + private void setLow(float lx, float ly, float lz) { + this.low[0] = lx; + this.low[1] = ly; + this.low[2] = lz; + } - /** Resize the AABBox to encapsulate another AABox - * @param newBox AABBox to be encapsulated in - */ - public void resize(AABBox newBox) - { - float[] newLow = newBox.getLow(); - float[] newHigh = newBox.getHigh(); + /** Resize the AABBox to encapsulate another AABox + * @param newBox AABBox to be encapsulated in + */ + public void resize(AABBox newBox) { + float[] newLow = newBox.getLow(); + float[] newHigh = newBox.getHigh(); - /** test low */ - if (newLow[0] < low[0]) - low[0] = newLow[0]; - if (newLow[1] < low[1]) - low[1] = newLow[1]; - if (newLow[2] < low[2]) - low[2] = newLow[2]; + /** test low */ + if (newLow[0] < low[0]) + low[0] = newLow[0]; + if (newLow[1] < low[1]) + low[1] = newLow[1]; + if (newLow[2] < low[2]) + low[2] = newLow[2]; - /** test high */ - if (newHigh[0] > high[0]) - high[0] = newHigh[0]; - if (newHigh[1] > high[1]) - high[1] = newHigh[1]; - if (newHigh[2] > high[2]) - high[2] = newHigh[2]; + /** test high */ + if (newHigh[0] > high[0]) + high[0] = newHigh[0]; + if (newHigh[1] > high[1]) + high[1] = newHigh[1]; + if (newHigh[2] > high[2]) + high[2] = newHigh[2]; - computeCenter(); - } + computeCenter(); + } - private void computeCenter() - { - center[0] = (high[0] + low[0])/2; - center[1] = (high[1] + low[1])/2; - center[2] = (high[2] + low[2])/2; - } + private void computeCenter() { + center[0] = (high[0] + low[0])/2; + center[1] = (high[1] + low[1])/2; + center[2] = (high[2] + low[2])/2; + } - /** Resize the AABBox to encapsulate the passed - * xyz-coordinates. - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @param z z-axis coordinate value - */ - public void resize(float x, float y, float z) - { - /** test low */ - if (x < low[0]) - low[0] = x; - if (y < low[1]) - low[1] = y; - if (z < low[2]) - low[2] = z; + /** Resize the AABBox to encapsulate the passed + * xyz-coordinates. + * @param x x-axis coordinate value + * @param y y-axis coordinate value + * @param z z-axis coordinate value + */ + public void resize(float x, float y, float z) { + /** test low */ + if (x < low[0]) + low[0] = x; + if (y < low[1]) + low[1] = y; + if (z < low[2]) + low[2] = z; - /** test high */ - if (x > high[0]) - high[0] = x; - if (y > high[1]) - high[1] = y; - if (z > high[2]) - high[2] = z; - - computeCenter(); - } + /** test high */ + if (x > high[0]) + high[0] = x; + if (y > high[1]) + high[1] = y; + if (z > high[2]) + high[2] = z; + + computeCenter(); + } - /** Check if the x & y coordinates are bounded/contained - * by this AABBox - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @return true if x belong to (low.x, high.x) and - * y belong to (low.y, high.y) - */ - public boolean contains(float x, float y){ - if(x<low[0] || x>high[0]){ - return false; - } - if(y<low[1]|| y>high[1]){ - return false; - } - return true; - } - - /** Check if the xyz coordinates are bounded/contained - * by this AABBox. - * @param x x-axis coordinate value - * @param y y-axis coordinate value - * @param z z-axis coordinate value - * @return true if x belong to (low.x, high.x) and - * y belong to (low.y, high.y) and z belong to (low.z, high.z) - */ - public boolean contains(float x, float y, float z){ - if(x<low[0] || x>high[0]){ - return false; - } - if(y<low[1]|| y>high[1]){ - return false; - } - if(z<low[2] || z>high[2]){ - return false; - } - return true; - } - + /** Check if the x & y coordinates are bounded/contained + * by this AABBox + * @param x x-axis coordinate value + * @param y y-axis coordinate value + * @return true if x belong to (low.x, high.x) and + * y belong to (low.y, high.y) + */ + public boolean contains(float x, float y) { + if(x<low[0] || x>high[0]){ + return false; + } + if(y<low[1]|| y>high[1]){ + return false; + } + return true; + } + + /** Check if the xyz coordinates are bounded/contained + * by this AABBox. + * @param x x-axis coordinate value + * @param y y-axis coordinate value + * @param z z-axis coordinate value + * @return true if x belong to (low.x, high.x) and + * y belong to (low.y, high.y) and z belong to (low.z, high.z) + */ + public boolean contains(float x, float y, float z) { + if(x<low[0] || x>high[0]){ + return false; + } + if(y<low[1]|| y>high[1]){ + return false; + } + if(z<low[2] || z>high[2]){ + return false; + } + return true; + } + /** Check if there is a common region between this AABBox and the passed - * 2D region irrespective of z range + * 2D region irrespective of z range * @param x lower left x-coord * @param y lower left y-coord * @param w width @@ -213,87 +218,87 @@ public class AABBox { * @return true if this AABBox might have a common region with this 2D region */ public boolean intersects(float x, float y, float w, float h) { - if (w <= 0 || h <= 0) { - return false; - } - - final float _w = getWidth(); - final float _h = getHeight(); - if (_w <= 0 || _h <= 0) { - return false; - } - - final float x0 = getMinX(); - final float y0 = getMinY(); - return (x + w > x0 && - y + h > y0 && - x < x0 + _w && - y < y0 + _h); + if (w <= 0 || h <= 0) { + return false; + } + + final float _w = getWidth(); + final float _h = getHeight(); + if (_w <= 0 || _h <= 0) { + return false; + } + + final float x0 = getMinX(); + final float y0 = getMinY(); + return (x + w > x0 && + y + h > y0 && + x < x0 + _w && + y < y0 + _h); } - - /** Get the size of the Box where the size is represented by the - * length of the vector between low and high. - * @return a float representing the size of the AABBox - */ - public float getSize(){ - return VectorUtil.computeLength(low, high); - } + + /** Get the size of the Box where the size is represented by the + * length of the vector between low and high. + * @return a float representing the size of the AABBox + */ + public float getSize() { + return VectorUtil.computeLength(low, high); + } - /**Get the Center of the AABBox - * @return the xyz-coordinates of the center of the AABBox - */ - public float[] getCenter() { - return center; - } + /**Get the Center of the AABBox + * @return the xyz-coordinates of the center of the AABBox + */ + public float[] getCenter() { + return center; + } - /** Scale the AABBox by a constant - * @param size a constant float value - */ - public void scale(float size) { - float[] diffH = new float[3]; - diffH[0] = high[0] - center[0]; - diffH[1] = high[1] - center[1]; - diffH[2] = high[2] - center[2]; - - diffH = VectorUtil.scale(diffH, size); - - float[] diffL = new float[3]; - diffL[0] = low[0] - center[0]; - diffL[1] = low[1] - center[1]; - diffL[2] = low[2] - center[2]; - - diffL = VectorUtil.scale(diffL, size); - - high = VectorUtil.vectorAdd(center, diffH); - low = VectorUtil.vectorAdd(center, diffL); - } + /** Scale the AABBox by a constant + * @param size a constant float value + */ + public void scale(float size) { + float[] diffH = new float[3]; + diffH[0] = high[0] - center[0]; + diffH[1] = high[1] - center[1]; + diffH[2] = high[2] - center[2]; + + diffH = VectorUtil.scale(diffH, size); + + float[] diffL = new float[3]; + diffL[0] = low[0] - center[0]; + diffL[1] = low[1] - center[1]; + diffL[2] = low[2] - center[2]; + + diffL = VectorUtil.scale(diffL, size); + + high = VectorUtil.vectorAdd(center, diffH); + low = VectorUtil.vectorAdd(center, diffL); + } - public float getMinX() { - return low[0]; - } - - public float getMinY() { - return low[1]; - } - - public float getWidth(){ - return high[0] - low[0]; - } - - public float getHeight() { - return high[1] - low[1]; - } - - public float getDepth() { - return high[2] - low[2]; - } - public AABBox clone(){ - return new AABBox(this.low, this.high); - } - - public String toString() { - return "[ "+low[0]+"/"+low[1]+"/"+low[1]+" .. "+high[0]+"/"+high[0]+"/"+high[0]+", ctr "+ - center[0]+"/"+center[1]+"/"+center[1]+" ]"; - } + public float getMinX() { + return low[0]; + } + + public float getMinY() { + return low[1]; + } + + public float getWidth(){ + return high[0] - low[0]; + } + + public float getHeight() { + return high[1] - low[1]; + } + + public float getDepth() { + return high[2] - low[2]; + } + public AABBox clone() { + return new AABBox(this.low, this.high); + } + + public String toString() { + return "[ "+low[0]+"/"+low[1]+"/"+low[1]+" .. "+high[0]+"/"+high[0]+"/"+high[0]+", ctr "+ + center[0]+"/"+center[1]+"/"+center[1]+" ]"; + } } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Outline.java b/src/jogl/classes/com/jogamp/graph/geom/Outline.java index a805adf6c..315be002f 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Outline.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Outline.java @@ -44,133 +44,133 @@ import com.jogamp.graph.math.VectorUtil; * @see OutlineShape, Region */ public class Outline implements Comparable<Outline> { - - private ArrayList<Vertex> vertices = new ArrayList<Vertex>(3); - private boolean closed = false; - private AABBox box = new AABBox(); - - /**Create an outline defined by control vertices. - * An outline can contain off Curve vertices which define curved - * regions in the outline. - */ - public Outline(){ - - } - - /** Add a vertex to the outline. The {@link Vertex} is added at the - * end of the outline loop/strip. - * @param vertex Vertex to be added - */ - public final void addVertex(Vertex vertex) { - vertices.add(vertex); - box.resize(vertex.getX(), vertex.getY(), vertex.getZ()); - } - - /** Add a {@link Vertex} by specifying its 2D attributes to the outline. - * The {@link Vertex} is added at the - * end of the outline loop/strip. - * @param factory a {@link Factory} to get the required Vertex impl - * @param x the x coordinate - * @param y the y coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. - */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, boolean onCurve) { - addVertex(factory, x, y, 0f, onCurve); - } - - /** Add a {@link Vertex} by specifying its 3D attributes to the outline. - * The {@link Vertex} is added at the - * end of the outline loop/strip. - * @param factory a {@link Factory} to get the required Vertex impl - * @param x the x coordinate - * @param y the y coordinate - * @param z the z coordinate - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. - */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, float z, boolean onCurve) { - Vertex v = factory.create(x, y, z); - v.setOnCurve(onCurve); - addVertex(v); - } - - /** Add a vertex to the outline by passing a float array and specifying the - * offset and length in which. The attributes of the vertex are located. - * The attributes should be continuous (stride = 0). - * Attributes which value are not set (when length less than 3) - * are set implicitly to zero. - * @param factory a {@link Factory} to get the required Vertex impl - * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from - * @param offset the offset in the buffer to the x coordinate - * @param length the number of attributes to pick from the buffer (maximum 3) - * @param onCurve flag if this vertex is on the final curve or defines a curved region - * of the shape around this vertex. - */ - public final void addVertex(Vertex.Factory<? extends Vertex> factory, float[] coordsBuffer, int offset, int length, boolean onCurve) { - Vertex v = factory.create(coordsBuffer, offset, length); - v.setOnCurve(onCurve); - addVertex(v); - } - - public Vertex getVertex(int index){ - return vertices.get(index); - } - - public boolean isEmpty(){ - return (vertices.size() == 0); - } - public Vertex getLastVertex(){ - if(isEmpty()){ - return null; - } - return vertices.get(vertices.size()-1); - } - - public ArrayList<Vertex> getVertices() { - return vertices; - } - public void setVertices(ArrayList<Vertex> vertices) { - this.vertices = vertices; - } - public AABBox getBox() { - return box; - } - public boolean isClosed() { - return closed; - } - - /** define if this outline is closed or not. - * if set to closed, checks if the last vertex is - * equal to the first vertex. If not Equal adds a - * vertex at the end to the list. - * @param closed - */ - public void setClosed(boolean closed) { - this.closed = closed; - if(closed){ - Vertex first = vertices.get(0); - Vertex last = getLastVertex(); - if(!VectorUtil.checkEquality(first.getCoord(), last.getCoord())){ - Vertex v = first.clone(); - vertices.add(v); - } - } - } - - /** Compare two outlines with Bounding Box area - * as criteria. - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - public int compareTo(Outline outline) { - float size = box.getSize(); - float newSize = outline.getBox().getSize(); - if(size < newSize){ - return -1; - } - else if(size > newSize){ - return 1; - } - return 0; - } + + private ArrayList<Vertex> vertices = new ArrayList<Vertex>(3); + private boolean closed = false; + private AABBox box = new AABBox(); + + /**Create an outline defined by control vertices. + * An outline can contain off Curve vertices which define curved + * regions in the outline. + */ + public Outline(){ + + } + + /** Add a vertex to the outline. The {@link Vertex} is added at the + * end of the outline loop/strip. + * @param vertex Vertex to be added + */ + public final void addVertex(Vertex vertex) { + vertices.add(vertex); + box.resize(vertex.getX(), vertex.getY(), vertex.getZ()); + } + + /** Add a {@link Vertex} by specifying its 2D attributes to the outline. + * The {@link Vertex} is added at the + * end of the outline loop/strip. + * @param factory a {@link Factory} to get the required Vertex impl + * @param x the x coordinate + * @param y the y coordinate + * @param onCurve flag if this vertex is on the final curve or defines a curved region + * of the shape around this vertex. + */ + public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, boolean onCurve) { + addVertex(factory, x, y, 0f, onCurve); + } + + /** Add a {@link Vertex} by specifying its 3D attributes to the outline. + * The {@link Vertex} is added at the + * end of the outline loop/strip. + * @param factory a {@link Factory} to get the required Vertex impl + * @param x the x coordinate + * @param y the y coordinate + * @param z the z coordinate + * @param onCurve flag if this vertex is on the final curve or defines a curved region + * of the shape around this vertex. + */ + public final void addVertex(Vertex.Factory<? extends Vertex> factory, float x, float y, float z, boolean onCurve) { + Vertex v = factory.create(x, y, z); + v.setOnCurve(onCurve); + addVertex(v); + } + + /** Add a vertex to the outline by passing a float array and specifying the + * offset and length in which. The attributes of the vertex are located. + * The attributes should be continuous (stride = 0). + * Attributes which value are not set (when length less than 3) + * are set implicitly to zero. + * @param factory a {@link Factory} to get the required Vertex impl + * @param coordsBuffer the coordinate array where the vertex attributes are to be picked from + * @param offset the offset in the buffer to the x coordinate + * @param length the number of attributes to pick from the buffer (maximum 3) + * @param onCurve flag if this vertex is on the final curve or defines a curved region + * of the shape around this vertex. + */ + public final void addVertex(Vertex.Factory<? extends Vertex> factory, float[] coordsBuffer, int offset, int length, boolean onCurve) { + Vertex v = factory.create(coordsBuffer, offset, length); + v.setOnCurve(onCurve); + addVertex(v); + } + + public Vertex getVertex(int index){ + return vertices.get(index); + } + + public boolean isEmpty(){ + return (vertices.size() == 0); + } + public Vertex getLastVertex(){ + if(isEmpty()){ + return null; + } + return vertices.get(vertices.size()-1); + } + + public ArrayList<Vertex> getVertices() { + return vertices; + } + public void setVertices(ArrayList<Vertex> vertices) { + this.vertices = vertices; + } + public AABBox getBox() { + return box; + } + public boolean isClosed() { + return closed; + } + + /** define if this outline is closed or not. + * if set to closed, checks if the last vertex is + * equal to the first vertex. If not Equal adds a + * vertex at the end to the list. + * @param closed + */ + public void setClosed(boolean closed) { + this.closed = closed; + if(closed){ + Vertex first = vertices.get(0); + Vertex last = getLastVertex(); + if(!VectorUtil.checkEquality(first.getCoord(), last.getCoord())){ + Vertex v = first.clone(); + vertices.add(v); + } + } + } + + /** Compare two outlines with Bounding Box area + * as criteria. + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public int compareTo(Outline outline) { + float size = box.getSize(); + float newSize = outline.getBox().getSize(); + if(size < newSize){ + return -1; + } + else if(size > newSize){ + return 1; + } + return 0; + } } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java index d13e8ddb1..fb34de221 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Triangle.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Triangle.java @@ -28,52 +28,52 @@ package com.jogamp.graph.geom; public class Triangle { - private int id = Integer.MAX_VALUE; - final private Vertex[] vertices; - private boolean[] boundaryEdges = new boolean[3]; - private boolean[] boundaryVertices = null; + private int id = Integer.MAX_VALUE; + final private Vertex[] vertices; + private boolean[] boundaryEdges = new boolean[3]; + private boolean[] boundaryVertices = null; - public Triangle(Vertex ... v123){ - vertices = v123; - } + public Triangle(Vertex ... v123){ + vertices = v123; + } - public int getId() { - return id; - } + public int getId() { + return id; + } - public void setId(int id) { - this.id = id; - } + public void setId(int id) { + this.id = id; + } - public Vertex[] getVertices() { - return vertices; - } - - public boolean isEdgesBoundary() { - return boundaryEdges[0] || boundaryEdges[1] || boundaryEdges[2]; - } - - public boolean isVerticesBoundary() { - return boundaryVertices[0] || boundaryVertices[1] || boundaryVertices[2]; - } + public Vertex[] getVertices() { + return vertices; + } + + public boolean isEdgesBoundary() { + return boundaryEdges[0] || boundaryEdges[1] || boundaryEdges[2]; + } + + public boolean isVerticesBoundary() { + return boundaryVertices[0] || boundaryVertices[1] || boundaryVertices[2]; + } - public void setEdgesBoundary(boolean[] boundary) { - this.boundaryEdges = boundary; - } - - public boolean[] getEdgeBoundary() { - return boundaryEdges; - } - - public boolean[] getVerticesBoundary() { - return boundaryVertices; - } + public void setEdgesBoundary(boolean[] boundary) { + this.boundaryEdges = boundary; + } + + public boolean[] getEdgeBoundary() { + return boundaryEdges; + } + + public boolean[] getVerticesBoundary() { + return boundaryVertices; + } - public void setVerticesBoundary(boolean[] boundaryVertices) { - this.boundaryVertices = boundaryVertices; - } - - public String toString() { - return "Tri ID: " + id + "\n" + vertices[0] + "\n" + vertices[1] + "\n" + vertices[2]; - } + public void setVerticesBoundary(boolean[] boundaryVertices) { + this.boundaryVertices = boundaryVertices; + } + + public String toString() { + return "Tri ID: " + id + "\n" + vertices[0] + "\n" + vertices[1] + "\n" + vertices[2]; + } } diff --git a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java index 0e4e5e8df..859add943 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/Vertex.java +++ b/src/jogl/classes/com/jogamp/graph/geom/Vertex.java @@ -32,49 +32,49 @@ package com.jogamp.graph.geom; */ public interface Vertex extends Comparable<Vertex>, Cloneable { - public static interface Factory <T extends Vertex> { - T create(); + public static interface Factory <T extends Vertex> { + T create(); - T create(float x, float y); + T create(float x, float y); - T create(float x, float y, float z); + T create(float x, float y, float z); - T create(float[] coordsBuffer, int offset, int length); - } - - void setCoord(float x, float y); + T create(float[] coordsBuffer, int offset, int length); + } + + void setCoord(float x, float y); - void setCoord(float x, float y, float z); + void setCoord(float x, float y, float z); - void setCoord(float[] coordsBuffer, int offset, int length); - - float[] getCoord(); + void setCoord(float[] coordsBuffer, int offset, int length); + + float[] getCoord(); - void setX(float x); + void setX(float x); - void setY(float y); + void setY(float y); - void setZ(float z); + void setZ(float z); - float getX(); + float getX(); - float getY(); + float getY(); - float getZ(); + float getZ(); - boolean isOnCurve(); + boolean isOnCurve(); - void setOnCurve(boolean onCurve); + void setOnCurve(boolean onCurve); - int getId(); - - void setId(int id); - - int compareTo(Vertex p); - - float[] getTexCoord(); - - void setTexCoord(float s, float t); - - Vertex clone(); + int getId(); + + void setId(int id); + + int compareTo(Vertex p); + + float[] getTexCoord(); + + void setTexCoord(float s, float t); + + Vertex clone(); } diff --git a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java index 681067e40..6241d60df 100644 --- a/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java +++ b/src/jogl/classes/com/jogamp/graph/geom/opengl/SVertex.java @@ -36,143 +36,143 @@ import com.jogamp.graph.math.VectorUtil; * */ public class SVertex implements Vertex { - private int id = Integer.MAX_VALUE; - protected float[] coord = new float[3]; - protected boolean onCurve = true; - private float[] texCoord = new float[2]; - - static final Factory factory = new Factory(); - - public static Factory factory() { return factory; } - - public static class Factory implements Vertex.Factory<SVertex> { - @Override - public SVertex create() { - return new SVertex(); - } - - @Override - public SVertex create(float x, float y) { - return new SVertex(x, y); - } - - @Override - public SVertex create(float x, float y, float z) { - return new SVertex(x, y, z); - } - - @Override - public SVertex create(float[] coordsBuffer, int offset, int length) { - return new SVertex(coordsBuffer, offset, length); - } - } - - public SVertex() { - } - - public SVertex(float x, float y) { - setCoord(x, y); - } - public SVertex(float x, float y, float z) { - setCoord(x, y, z); - } - public SVertex(float[] coordsBuffer, int offset, int length) { - setCoord(coordsBuffer, offset, length); - } - - public void setCoord(float x, float y) { - this.coord[0] = x; - this.coord[1] = y; - this.coord[2] = 0f; - } - - public void setCoord(float x, float y, float z) { - this.coord[0] = x; - this.coord[1] = y; - this.coord[2] = z; - } - - public void setCoord(float[] coordsBuffer, int offset, int length) { - if(length > coordsBuffer.length - offset) { - throw new IndexOutOfBoundsException("coordsBuffer too small: "+coordsBuffer.length+" - "+offset+" < "+length); - } - if(length > 3) { - throw new IndexOutOfBoundsException("length too big: "+length+" > "+3); - } - int i=0; - while(i<length) { - this.coord[i++] = coordsBuffer[offset++]; - } - } - - public float[] getCoord() { - return coord; - } - - public void setX(float x) { - this.coord[0] = x; - } - - public void setY(float y) { - this.coord[1] = y; - } - - public void setZ(float z) { - this.coord[2] = z; - } - - public float getX() { - return this.coord[0]; - } - - public float getY() { - return this.coord[1]; - } - - public float getZ() { - return this.coord[2]; - } - - public boolean isOnCurve() { - return onCurve; - } - - public void setOnCurve(boolean onCurve) { - this.onCurve = onCurve; - } - - public int getId(){ - return id; - } - - public void setId(int id){ - this.id = id; - } - - public int compareTo(Vertex p) { - if(VectorUtil.checkEquality(coord, p.getCoord())) { - return 0; - } - return -1; - } - - public float[] getTexCoord() { - return texCoord; - } - - public void setTexCoord(float s, float t) { - this.texCoord[0] = s; - this.texCoord[1] = t; - } - - public SVertex clone(){ - SVertex v = new SVertex(this.coord, 0, 3); - v.setOnCurve(this.onCurve); - return v; - } - - public String toString() { - return "[ID: " + id + " X: " + coord[0] - + " Y: " + coord[1] + " Z: " + coord[2] + "]"; - } + private int id = Integer.MAX_VALUE; + protected float[] coord = new float[3]; + protected boolean onCurve = true; + private float[] texCoord = new float[2]; + + static final Factory factory = new Factory(); + + public static Factory factory() { return factory; } + + public static class Factory implements Vertex.Factory<SVertex> { + @Override + public SVertex create() { + return new SVertex(); + } + + @Override + public SVertex create(float x, float y) { + return new SVertex(x, y); + } + + @Override + public SVertex create(float x, float y, float z) { + return new SVertex(x, y, z); + } + + @Override + public SVertex create(float[] coordsBuffer, int offset, int length) { + return new SVertex(coordsBuffer, offset, length); + } + } + + public SVertex() { + } + + public SVertex(float x, float y) { + setCoord(x, y); + } + public SVertex(float x, float y, float z) { + setCoord(x, y, z); + } + public SVertex(float[] coordsBuffer, int offset, int length) { + setCoord(coordsBuffer, offset, length); + } + + public void setCoord(float x, float y) { + this.coord[0] = x; + this.coord[1] = y; + this.coord[2] = 0f; + } + + public void setCoord(float x, float y, float z) { + this.coord[0] = x; + this.coord[1] = y; + this.coord[2] = z; + } + + public void setCoord(float[] coordsBuffer, int offset, int length) { + if(length > coordsBuffer.length - offset) { + throw new IndexOutOfBoundsException("coordsBuffer too small: "+coordsBuffer.length+" - "+offset+" < "+length); + } + if(length > 3) { + throw new IndexOutOfBoundsException("length too big: "+length+" > "+3); + } + int i=0; + while(i<length) { + this.coord[i++] = coordsBuffer[offset++]; + } + } + + public float[] getCoord() { + return coord; + } + + public void setX(float x) { + this.coord[0] = x; + } + + public void setY(float y) { + this.coord[1] = y; + } + + public void setZ(float z) { + this.coord[2] = z; + } + + public float getX() { + return this.coord[0]; + } + + public float getY() { + return this.coord[1]; + } + + public float getZ() { + return this.coord[2]; + } + + public boolean isOnCurve() { + return onCurve; + } + + public void setOnCurve(boolean onCurve) { + this.onCurve = onCurve; + } + + public int getId(){ + return id; + } + + public void setId(int id){ + this.id = id; + } + + public int compareTo(Vertex p) { + if(VectorUtil.checkEquality(coord, p.getCoord())) { + return 0; + } + return -1; + } + + public float[] getTexCoord() { + return texCoord; + } + + public void setTexCoord(float s, float t) { + this.texCoord[0] = s; + this.texCoord[1] = t; + } + + public SVertex clone(){ + SVertex v = new SVertex(this.coord, 0, 3); + v.setOnCurve(this.onCurve); + return v; + } + + public String toString() { + return "[ID: " + id + " X: " + coord[0] + + " Y: " + coord[1] + " Z: " + coord[2] + "]"; + } } diff --git a/src/jogl/classes/com/jogamp/graph/math/Quaternion.java b/src/jogl/classes/com/jogamp/graph/math/Quaternion.java index b77a5fa08..38638dc5a 100755 --- a/src/jogl/classes/com/jogamp/graph/math/Quaternion.java +++ b/src/jogl/classes/com/jogamp/graph/math/Quaternion.java @@ -30,353 +30,353 @@ package com.jogamp.graph.math; import jogamp.graph.math.MathFloat;
public class Quaternion {
- protected float x,y,z,w;
+ protected float x,y,z,w;
- public Quaternion(){
+ 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);
+ }
+
+ 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];
+ 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];
+ 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];
+ 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;
- }
+ 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);
+ /** 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;
+ 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 = 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;
+ 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;
+ 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;
+ 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[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[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];
- }
+ 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/jogl/classes/com/jogamp/graph/math/VectorUtil.java b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java index cca9a454f..7cbb742e5 100755 --- a/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java +++ b/src/jogl/classes/com/jogamp/graph/math/VectorUtil.java @@ -35,261 +35,261 @@ import com.jogamp.graph.geom.Vertex; public class VectorUtil {
- public static final int CW = -1;
- public static final int CCW = 1;
- public static final int COLLINEAR = 0;
+ 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];
+ /** 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;
- }
+ 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];
+ /** 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] = 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;
- }
+ 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];
+ /** 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];
+ 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;
- }
+ 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];
+ /** 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];
+ 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];
+ 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];
+ 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 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]};
+ 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]);
+ float distance = MathFloat.sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
- return distance;
- }
+ 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;
- }
+ /**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;
- }
+ /** 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) == VectorUtil.COLLINEAR);
- }
+ /** 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) == VectorUtil.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;
- }
+ /** 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(Vertex a, Vertex b, Vertex c, Vertex 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;
- }
+ /** 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(Vertex a, Vertex b, Vertex c, Vertex 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(Vertex a, Vertex b, Vertex c){
- return (b.getX() - a.getX()) * (c.getY() - a.getY()) - (b.getY() - a.getY())*(c.getX() - a.getX());
- }
+ /** 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(Vertex a, Vertex b, Vertex 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(Vertex a, Vertex b, Vertex c){
- return triArea(a,b,c) > 0;
- }
+ /** 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(Vertex a, Vertex b, Vertex 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<Vertex> 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;
- }
+ /** 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<Vertex> 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;
+ }
}
diff --git a/src/jogl/classes/com/jogamp/graph/package.html b/src/jogl/classes/com/jogamp/graph/package.html new file mode 100644 index 000000000..f696020ab --- /dev/null +++ b/src/jogl/classes/com/jogamp/graph/package.html @@ -0,0 +1,33 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> +<head> + <title>Public Graph Utility Package</title> +</head> + <body> + +<h2>Public <i>Graph</i> Utility Package</h2> + +<h3>Disclaimer</h3> + <p> + The API of the namespace <i>com.jogamp.graph.**</i> + is experimental and subject to change until further notice. + </p> + <p> + It's implementation <i>jogamp.graph.**</i> may change at any time + as it is natural with all other API implementations. + </p> + <p> + We are currently refining and completing this new API and it's implementation. + Feel free to comment and help using our public channels. + </p> +<h3>Revision History<br> + </h3> + +<ul> +<li> Early Draft Review, April 1st 2011</li> +</ul> + <br> + <br> + <br> +</body> +</html> diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 4fbd0e478..e7fbc4d58 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -125,7 +125,7 @@ public class Animator extends AnimatorBase { class MainLoop implements Runnable { public String toString() { - return "[started "+isStartedImpl()+", animating "+isAnimatingImpl()+", paused "+isPausedImpl()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]"; + return "[started "+isStartedImpl()+", animating "+isAnimatingImpl()+", paused "+isPausedImpl()+", drawable "+drawables.size()+"]"; } public void run() { @@ -134,11 +134,7 @@ public class Animator extends AnimatorBase { if(DEBUG) { System.err.println("Animator start:" + Thread.currentThread() + ": " + toString()); } - - startTime = System.currentTimeMillis(); - curTime = startTime; - totalFrames = 0; - + fpsCounter.resetFPSCounter(); animThread = Thread.currentThread(); setIsAnimatingSynced(false); // barrier Animator.this.notifyAll(); @@ -161,9 +157,7 @@ public class Animator extends AnimatorBase { if (wasPaused) { // resume from pause -> reset counter - startTime = System.currentTimeMillis(); - curTime = startTime; - totalFrames = 0; + fpsCounter.resetFPSCounter(); if (DEBUG) { System.err.println("Animator resume:" + Thread.currentThread() + ": " + toString()); } @@ -269,7 +263,7 @@ public class Animator extends AnimatorBase { if (runnable == null) { runnable = new MainLoop(); } - resetCounter(); + fpsCounter.resetFPSCounter(); String threadName = Thread.currentThread().getName()+"-"+baseName; Thread thread; if(null==threadGroup) { diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index 01c2ea664..a6ba74665 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -30,7 +30,12 @@ package com.jogamp.opengl.util; import com.jogamp.common.util.locks.RecursiveLock; import jogamp.opengl.Debug; +import jogamp.opengl.FPSCounterImpl; + +import java.io.PrintStream; import java.util.ArrayList; + +import javax.media.opengl.FPSCounter; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; import javax.media.opengl.GLProfile; @@ -61,9 +66,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { protected Thread animThread; protected boolean ignoreExceptions; protected boolean printExceptions; - protected long startTime; - protected long curTime; - protected int totalFrames; + protected FPSCounterImpl fpsCounter = new FPSCounterImpl(); protected RecursiveLock stateSync = new RecursiveLock(); /** Creates a new, empty Animator. */ @@ -83,7 +86,6 @@ public abstract class AnimatorBase implements GLAnimatorControl { baseName = baseName.concat("-"+animatorCount); drawablesEmpty = true; } - resetCounter(); } protected abstract String getBaseName(String prefix); @@ -138,25 +140,48 @@ public abstract class AnimatorBase implements GLAnimatorControl { lightweight widgets are continually being redrawn. */ protected void display() { impl.display(drawables, ignoreExceptions, printExceptions); - curTime = System.currentTimeMillis(); - totalFrames++; + fpsCounter.tickFPS(); + } + + public final void setUpdateFPSFrames(int frames, PrintStream out) { + fpsCounter.setUpdateFPSFrames(frames, out); + } + + public final void resetFPSCounter() { + fpsCounter.resetFPSCounter(); } - public long getCurrentTime() { - return curTime; + public final int getUpdateFPSFrames() { + return fpsCounter.getUpdateFPSFrames(); + } + + public final long getFPSStartTime() { + return fpsCounter.getFPSStartTime(); } - public long getDuration() { - return curTime - startTime; + public final long getLastFPSUpdateTime() { + return fpsCounter.getLastFPSUpdateTime(); } - public long getStartTime() { - return startTime; + public final long getLastFPSPeriod() { + return fpsCounter.getLastFPSPeriod(); + } + + public final float getLastFPS() { + return fpsCounter.getLastFPS(); + } + + public final int getTotalFPSFrames() { + return fpsCounter.getTotalFPSFrames(); } - public int getTotalFrames() { - return totalFrames; + public final long getTotalFPSDuration() { + return fpsCounter.getTotalFPSDuration(); } + + public final float getTotalFPS() { + return fpsCounter.getTotalFPS(); + } public final Thread getThread() { stateSync.lock(); @@ -167,12 +192,6 @@ public abstract class AnimatorBase implements GLAnimatorControl { } } - public synchronized void resetCounter() { - startTime = System.currentTimeMillis(); // overwrite startTime to real init one - curTime = startTime; - totalFrames = 0; - } - /** Sets a flag causing this Animator to ignore exceptions produced while redrawing the drawables. By default this flag is set to false, causing any exception thrown to halt the Animator. */ @@ -189,6 +208,6 @@ public abstract class AnimatorBase implements GLAnimatorControl { } public String toString() { - return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", frames "+getTotalFrames()+", drawable "+drawables.size()+"]"; + return getClass().getName()+"[started "+isStarted()+", animating "+isAnimating()+", paused "+isPaused()+", drawable "+drawables.size()+"]"; } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/FBObject.java b/src/jogl/classes/com/jogamp/opengl/util/FBObject.java index ad32b4ffe..c57d4b057 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/util/FBObject.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2011 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 @@ -39,21 +40,23 @@ public class FBObject { private int width, height; private int fb, fbo_tex, depth_rb, stencil_rb, vStatus; private int texInternalFormat, texDataFormat, texDataType; - - public static final int ATTR_DEPTH = 1 << 0; - public static final int ATTR_STENCIL = 1 << 1; - + private boolean bound; + public FBObject(int width, int height) { this.width = width; this.height = height; this.fb = 0; this.fbo_tex = 0; this.depth_rb = 0; - this.stencil_rb = 0; + this.stencil_rb = 0; + this.bound = false; } - - public boolean validateStatus(GL gl) { - /* vStatus = */ getStatus(gl); + + /** + * @return true if the FB status is valid, otherwise false + * @see #getStatus() + */ + public boolean isStatusValid() { switch(vStatus) { case GL.GL_FRAMEBUFFER_COMPLETE: return true; @@ -73,48 +76,40 @@ public class FBObject { } } - /** @return {@link GL.GL_FRAMEBUFFER_COMPLETE} if ok, otherwise return GL FBO error state or -1 */ + /** + * @return The FB status. {@link GL.GL_FRAMEBUFFER_COMPLETE} if ok, otherwise return GL FBO error state or -1 + * @see #validateStatus() + */ public int getStatus() { return vStatus; } - public int getStatus(GL gl) { - if(!gl.glIsFramebuffer(fb)) { - vStatus = -1; - } else { - vStatus = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); - } - return vStatus; - } - public String getStatusString() { return getStatusString(vStatus); } - public static String getStatusString(int fbStatus) { + public static final String getStatusString(int fbStatus) { switch(fbStatus) { case -1: return "NOT A FBO"; case GL.GL_FRAMEBUFFER_COMPLETE: return "OK"; - case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - return("GL FBO: incomplete,incomplete attachment\n"); case GL.GL_FRAMEBUFFER_UNSUPPORTED: return("GL FBO: Unsupported framebuffer format"); + case GL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + return("GL FBO: incomplete, incomplete attachment\n"); case GL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - return("GL FBO: incomplete,missing attachment"); + return("GL FBO: incomplete, missing attachment"); case GL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - return("GL FBO: incomplete,attached images must have same dimensions"); + return("GL FBO: incomplete, attached images must have same dimensions"); case GL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - return("GL FBO: incomplete,attached images must have same format"); - /* + return("GL FBO: incomplete, attached images must have same format"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - return("GL FBO: incomplete,missing draw buffer"); + return("GL FBO: incomplete, missing draw buffer"); case GL2.GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - return("GL FBO: incomplete,missing read buffer"); - case GL2.GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: - return("GL FBO: incomplete, duplicate attachment"); - */ + return("GL FBO: incomplete, missing read buffer"); + case GL2.GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: + return("GL FBO: incomplete, missing multisample buffer"); case 0: return("GL FBO: incomplete, implementation fault"); default: @@ -154,6 +149,19 @@ public class FBObject { return init(gl, textureInternalFormat, textureDataFormat, textureDataType, magFilter, minFilter, wrapS, wrapT); } + private boolean checkNoError(GL gl, int err, String exceptionMessage) { + if(GL.GL_NO_ERROR != err) { + if(null != gl) { + destroy(gl); + } + if(null != exceptionMessage) { + throw new GLException(exceptionMessage+" GL Error 0x"+Integer.toHexString(err)); + } + return false; + } + return true; + } + /** * Initializes this FBO's instance with it's texture. * @@ -176,6 +184,8 @@ public class FBObject { throw new GLException("FBO already initialized (fb "+fb+", tex "+fbo_tex+")"); } + checkNoError(null, gl.glGetError(), "FBObject Init.pre"); // throws GLException if error + texInternalFormat=textureInternalFormat; texDataFormat=textureDataFormat; texDataType=textureDataType; @@ -189,24 +199,24 @@ public class FBObject { throw new GLException("null generated framebuffer"); } - gl.glGenTextures(1, name, 0); - fbo_tex = name[0]; - if(fbo_tex==0) { - throw new GLException("null generated texture"); - } - // bind fbo .. - gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, fb); + gl.glBindFramebuffer(GL.GL_FRAMEBUFFER, fb); + checkNoError(gl, gl.glGetError(), "FBObject Init.bindFB"); // throws GLException if error if(!gl.glIsFramebuffer(fb)) { - destroy(gl); - System.err.println("not a framebuffer: "+ fb); - return false; + checkNoError(gl, GL.GL_INVALID_VALUE, "FBObject Init.isFB"); // throws GLException } bound = true; + gl.glGenTextures(1, name, 0); + fbo_tex = name[0]; + if(fbo_tex==0) { + throw new GLException("null generated texture"); + } gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); + checkNoError(gl, gl.glGetError(), "FBObject Init.bindTex"); // throws GLException if error gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, texInternalFormat, width, height, 0, texDataFormat, texDataType, null); + checkNoError(gl, gl.glGetError(), "FBObject Init.texImage2D"); // throws GLException if error if( 0 < magFilter ) { gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, magFilter); } @@ -225,7 +235,8 @@ public class FBObject { GL.GL_COLOR_ATTACHMENT0, GL.GL_TEXTURE_2D, fbo_tex, 0); - return validateStatus(gl); + updateStatus(gl); + return isStatusValid(); } /** @@ -264,7 +275,8 @@ public class FBObject { gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_DEPTH_ATTACHMENT, GL.GL_RENDERBUFFER, depth_rb); - return validateStatus(gl); + updateStatus(gl); + return isStatusValid(); } /** @@ -283,7 +295,6 @@ public class FBObject { checkBound(true); int name[] = new int[1]; gl.glGenRenderbuffers(1, name, 0); - gl.glGenRenderbuffers(1, name, 0); stencil_rb = name[0]; if(stencil_rb==0) { throw new GLException("null generated stencilbuffer"); @@ -299,7 +310,8 @@ public class FBObject { gl.glFramebufferRenderbuffer(GL.GL_FRAMEBUFFER, GL.GL_STENCIL_ATTACHMENT, GL.GL_RENDERBUFFER, stencil_rb); - return validateStatus(gl); + updateStatus(gl); + return isStatusValid(); } public void destroy(GL gl) { @@ -331,8 +343,6 @@ public class FBObject { } } - boolean bound = false; - private final void checkBound(boolean shallBeBound) { if(bound != shallBeBound) { final String s0 = shallBeBound ? "not" : "already" ; @@ -355,16 +365,31 @@ public class FBObject { } public void use(GL gl) { - if(bound) { - unbind(gl); - } - gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); // to use it .. + checkBound(false); + gl.glBindTexture(GL.GL_TEXTURE_2D, fbo_tex); // use it .. } - public int getFBName() { - return fb; + public void unuse(GL gl) { + checkBound(false); + gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // don't use it } - public int getTextureName() { - return fbo_tex; + + public final boolean isBound() { return bound; } + public final int getWidth() { return width; } + public final int getHeight() { return height; } + public final int getFBName() { return fb; } + public final int getTextureName() { return fbo_tex; } + public final int getStencilBuffer() { return stencil_rb; } + public final int getDepthBuffer() { return depth_rb; } + public final String toString() { + return "FBO[name "+fb+", size "+width+"x"+height+", tex "+fbo_tex+", depth "+depth_rb+", stencil "+stencil_rb+"]"; } + + private void updateStatus(GL gl) { + if(!gl.glIsFramebuffer(fb)) { + vStatus = -1; + } else { + vStatus = gl.glCheckFramebufferStatus(GL.GL_FRAMEBUFFER); + } + } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java index fc364b67a..f7fc58160 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/FPSAnimator.java @@ -116,9 +116,9 @@ public class FPSAnimator extends AnimatorBase { } private void startTask() { - if(null != task) { - return; - } + if(null != task) { + return; + } long delay = (long) (1000.0f / (float) fps); task = new TimerTask() { public void run() { @@ -130,7 +130,7 @@ public class FPSAnimator extends AnimatorBase { } }; - resetCounter(); + fpsCounter.resetFPSCounter(); shouldRun = true; if (scheduleAtFixedRate) { @@ -165,12 +165,12 @@ public class FPSAnimator extends AnimatorBase { try { shouldRun = false; if(null != task) { - task.cancel(); - task = null; + task.cancel(); + task = null; } if(null != timer) { - timer.cancel(); - timer = null; + timer.cancel(); + timer = null; } animThread = null; try { @@ -190,8 +190,8 @@ public class FPSAnimator extends AnimatorBase { try { shouldRun = false; if(null != task) { - task.cancel(); - task = null; + task.cancel(); + task = null; } animThread = null; try { diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java index 4586d1df5..d80d398aa 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataClient.java @@ -28,65 +28,106 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData }) != null; /** + * Create a client side buffer object, using a predefined fixed function array index + * and starting with a new created Buffer object with initialSize size + * + * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. + * On profile ES2 the fixed function emulation will transform these calls to + * EnableVertexAttribArray and VertexAttribPointer calls, + * and a predefined vertex attribute variable name will be chosen. + * * @param index The GL array index * @param name The optional custom name for the GL array index, maybe null. * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. * This name might be used as the shader attribute name. * @param comps The array component number * @param dataType The array index GL data type - * @param normalized Wheather the data shall be normalized + * @param normalized Whether the data shall be normalized + * @param initialSize * * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) - */ - public static GLArrayDataClient createFixed(GL gl, int index, String name, int comps, int dataType, boolean normalized, - int initialSize) + */ + public static GLArrayDataClient createFixed(int index, String name, int comps, int dataType, boolean normalized, int initialSize) throws GLException { - gl.getGLProfile().isValidArrayDataType(index, comps, dataType, false, true); GLArrayDataClient adc = new GLArrayDataClient(); GLArrayHandler glArrayHandler = new GLFixedArrayHandler(adc); - adc.init(name, index, comps, dataType, normalized, 0, null, initialSize, false, glArrayHandler, 0, 0); + adc.init(name, index, comps, dataType, normalized, 0, null, initialSize, false, glArrayHandler, -1, -1, -1, -1); return adc; } - public static GLArrayDataClient createFixed(GL gl, int index, String name, int comps, int dataType, boolean normalized, - int stride, Buffer buffer) + /** + * Create a client side buffer object, using a predefined fixed function array index + * and starting with a given Buffer object incl it's stride + * + * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. + * On profile ES2 the fixed function emulation will transform these calls to + * EnableVertexAttribArray and VertexAttribPointer calls, + * and a predefined vertex attribute variable name will be chosen. + * + * @param index The GL array index + * @param name The optional custom name for the GL array index, maybe null. + * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. + * This name might be used as the shader attribute name. + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + * + * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + */ + public static GLArrayDataClient createFixed(int index, String name, int comps, int dataType, boolean normalized, int stride, + Buffer buffer) throws GLException { - gl.getGLProfile().isValidArrayDataType(index, comps, dataType, false, true); GLArrayDataClient adc = new GLArrayDataClient(); GLArrayHandler glArrayHandler = new GLFixedArrayHandler(adc); - adc.init(name, index, comps, dataType, normalized, stride, buffer, comps*comps, false, glArrayHandler, 0, 0); + adc.init(name, index, comps, dataType, normalized, stride, buffer, comps*comps, false, glArrayHandler, -1, -1, -1, -1); return adc; } - public static GLArrayDataClient createGLSL(GL gl, String name, int comps, int dataType, boolean normalized, - int initialSize) + /** + * Create a client side buffer object, using a custom GLSL array attribute name + * and starting with a new created Buffer object with initialSize size + * + * @param st The ShaderState managing the state of the used shader program, vertex attributes and uniforms + * @param name The custom name for the GL attribute. + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param initialSize + */ + public static GLArrayDataClient createGLSL(ShaderState st, String name, + int comps, int dataType, boolean normalized, int initialSize) throws GLException { - if(!gl.hasGLSL()) { - throw new GLException("GLArrayDataClient.GLSL not supported: "+gl); - } - gl.getGLProfile().isValidArrayDataType(-1, comps, dataType, true, true); - GLArrayDataClient adc = new GLArrayDataClient(); - GLArrayHandler glArrayHandler = new GLSLArrayHandler(adc); - adc.init(name, -1, comps, dataType, normalized, 0, null, initialSize, true, glArrayHandler, 0, 0); + GLArrayHandler glArrayHandler = new GLSLArrayHandler(st, adc); + adc.init(name, -1, comps, dataType, normalized, 0, null, initialSize, true, glArrayHandler, -1, -1, -1, -1); return adc; } - public static GLArrayDataClient createGLSL(GL gl, String name, int comps, int dataType, boolean normalized, - int stride, Buffer buffer) + /** + * Create a client side buffer object, using a custom GLSL array attribute name + * and starting with a given Buffer object incl it's stride + * + * @param st The ShaderState managing the state of the used shader program, vertex attributes and uniforms + * @param name The custom name for the GL attribute. + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + */ + public static GLArrayDataClient createGLSL(ShaderState st, String name, + int comps, int dataType, boolean normalized, int stride, + Buffer buffer) throws GLException { - if(!gl.hasGLSL()) { - throw new GLException("GLArrayDataClient.GLSL not supported: "+gl); - } - gl.getGLProfile().isValidArrayDataType(-1, comps, dataType, true, true); - GLArrayDataClient adc = new GLArrayDataClient(); - GLArrayHandler glArrayHandler = new GLSLArrayHandler(adc); - adc.init(name, -1, comps, dataType, normalized, stride, buffer, comps*comps, true, glArrayHandler, 0, 0); + GLArrayHandler glArrayHandler = new GLSLArrayHandler(st, adc); + adc.init(name, -1, comps, dataType, normalized, stride, buffer, comps*comps, true, glArrayHandler, -1, -1, -1, -1); return adc; } @@ -94,21 +135,21 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData // Data read access // - public final boolean isBufferWritten() { return bufferWritten; } + public final boolean isVBOWritten() { return bufferWritten; } public final boolean sealed() { return sealed; } - - public int getBufferUsage() { return -1; } + + public final boolean enabled() { return bufferEnabled; } // // Data and GL state modification .. // - public final void setBufferWritten(boolean written) { bufferWritten=written; } + public final void setVBOWritten(boolean written) { bufferWritten=written; } public void destroy(GL gl) { reset(gl); - buffer=null; + super.destroy(gl); } public void reset(GL gl) { @@ -116,30 +157,17 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData reset(); } - public void seal(GL gl, boolean seal) - { + public void seal(GL gl, boolean seal) { seal(seal); - if(sealedGL==seal) return; - sealedGL = seal; - if(seal) { - init_vbo(gl); - - enableBuffer(gl, true); - } else { - enableBuffer(gl, false); - } + enableBuffer(gl, seal); } public void enableBuffer(GL gl, boolean enable) { - if(enableBufferAlways && enable) { - bufferEnabled = false; - } - if( bufferEnabled != enable && components>0 ) { + if( enableBufferAlways || bufferEnabled != enable ) { if(enable) { checkSeal(true); - if(null!=buffer) { - buffer.rewind(); - } + // init/generate VBO name if not done yet + init_vbo(gl); } glArrayHandler.enableBuffer(gl, enable); bufferEnabled = enable; @@ -167,16 +195,14 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData { if(sealed==seal) return; sealed = seal; + bufferWritten=false; if(seal) { - bufferWritten=false; if (null!=buffer) { buffer.flip(); } - } else { - if (null!=buffer) { - buffer.position(buffer.limit()); - buffer.limit(buffer.capacity()); - } + } else if (null!=buffer) { + buffer.position(buffer.limit()); + buffer.limit(buffer.capacity()); } } @@ -202,7 +228,7 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData * The arguments remaining elements must be a multiple of this arrays element stride. */ public void put(Buffer v) { - if ( buffer==null || sealed ) return; + if ( sealed ) return; if(0!=(v.remaining() % strideL)) { throw new GLException("Buffer length ("+v.remaining()+") is not a multiple of component-stride:\n\t"+this); } @@ -211,19 +237,19 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData } public void putb(byte v) { - if ( buffer==null || sealed ) return; + if ( sealed ) return; growBufferIfNecessary(1); Buffers.putb(buffer, v); } public void puts(short v) { - if ( buffer==null || sealed ) return; + if ( sealed ) return; growBufferIfNecessary(1); Buffers.puts(buffer, v); } public void puti(int v) { - if ( buffer==null || sealed ) return; + if ( sealed ) return; growBufferIfNecessary(1); Buffers.puti(buffer, v); } @@ -233,7 +259,7 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData } public void putf(float v) { - if ( buffer==null || sealed ) return; + if ( sealed ) return; growBufferIfNecessary(1); Buffers.putf(buffer, v); } @@ -243,8 +269,8 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData ", index "+index+ ", location "+location+ ", isVertexAttribute "+isVertexAttribute+ - ", dataType "+dataType+ - ", bufferClazz "+clazz+ + ", dataType "+componentType+ + ", bufferClazz "+componentClazz+ ", elements "+getElementNumber()+ ", components "+components+ ", stride "+stride+"u "+strideB+"b "+strideL+"c"+ @@ -252,7 +278,8 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData ", sealed "+sealed+ ", bufferEnabled "+bufferEnabled+ ", bufferWritten "+bufferWritten+ - ", buffer "+buffer+ + ", buffer "+buffer+ + ", alive "+alive+ "]"; } @@ -260,55 +287,58 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData protected final boolean growBufferIfNecessary(int spare) { if(buffer==null || buffer.remaining()<spare) { - growBuffer(initialSize); + growBuffer(Math.max(initialSize, spare)); return true; } return false; } - protected final void growBuffer(int additional) { - if(sealed || 0==additional || 0==components) return; + protected final void growBuffer(int additional) { + if(!alive || sealed) { + throw new GLException("Invalid state: "+this); + } // add the stride delta additional += (additional/components)*(strideL-components); - if(components>0) { - int osize = (buffer!=null)?buffer.capacity():0; - if(clazz==ByteBuffer.class) { - ByteBuffer newBBuffer = Buffers.newDirectByteBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newBBuffer.put((ByteBuffer)buffer); - } - buffer = newBBuffer; - } else if(clazz==ShortBuffer.class) { - ShortBuffer newSBuffer = Buffers.newDirectShortBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newSBuffer.put((ShortBuffer)buffer); - } - buffer = newSBuffer; - } else if(clazz==IntBuffer.class) { - IntBuffer newIBuffer = Buffers.newDirectIntBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newIBuffer.put((IntBuffer)buffer); - } - buffer = newIBuffer; - } else if(clazz==FloatBuffer.class) { - FloatBuffer newFBuffer = Buffers.newDirectFloatBuffer( (osize+additional) * components ); - if(buffer!=null) { - buffer.flip(); - newFBuffer.put((FloatBuffer)buffer); - } - buffer = newFBuffer; - } else { - throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); + int osize = (buffer!=null)?buffer.capacity():0; + if(componentClazz==ByteBuffer.class) { + ByteBuffer newBBuffer = Buffers.newDirectByteBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newBBuffer.put((ByteBuffer)buffer); + } + buffer = newBBuffer; + } else if(componentClazz==ShortBuffer.class) { + ShortBuffer newSBuffer = Buffers.newDirectShortBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newSBuffer.put((ShortBuffer)buffer); } + buffer = newSBuffer; + } else if(componentClazz==IntBuffer.class) { + IntBuffer newIBuffer = Buffers.newDirectIntBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newIBuffer.put((IntBuffer)buffer); + } + buffer = newIBuffer; + } else if(componentClazz==FloatBuffer.class) { + FloatBuffer newFBuffer = Buffers.newDirectFloatBuffer( (osize+additional) * components ); + if(buffer!=null) { + buffer.flip(); + newFBuffer.put((FloatBuffer)buffer); + } + buffer = newFBuffer; + } else { + throw new GLException("Given Buffer Class not supported: "+componentClazz+":\n\t"+this); } } protected final void checkSeal(boolean test) throws GLException { + if(!alive) { + throw new GLException("Invalid state: "+this); + } if(sealed!=test) { if(test) { throw new GLException("Not Sealed yet, seal first:\n\t"+this); @@ -320,29 +350,35 @@ public class GLArrayDataClient extends GLArrayDataWrapper implements GLArrayData protected void init(String name, int index, int comps, int dataType, boolean normalized, int stride, Buffer data, int initialSize, boolean isVertexAttribute, GLArrayHandler handler, - int vboName, long bufferOffset) + int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { super.init(name, index, comps, dataType, normalized, stride, data, isVertexAttribute, - vboName, bufferOffset); + vboName, vboOffset, vboUsage, vboTarget); this.initialSize = initialSize; this.glArrayHandler = handler; this.sealed=false; - this.sealedGL=false; this.bufferEnabled=false; this.enableBufferAlways=false; this.bufferWritten=false; - if(null==buffer) { + if(null==buffer && initialSize>0) { growBuffer(initialSize); } } - protected void init_vbo(GL gl) {} + private boolean isValidated = false; + + protected void init_vbo(GL gl) { + if(!isValidated ) { + isValidated = true; + validate(gl.getGLProfile(), true); + } + } protected GLArrayDataClient() { } - protected boolean sealed, sealedGL; + protected boolean sealed; protected boolean bufferEnabled; protected boolean bufferWritten; protected boolean enableBufferAlways; diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataEditable.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataEditable.java index 0f8ed27be..0da7d1171 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataEditable.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataEditable.java @@ -14,21 +14,18 @@ import java.nio.*; public interface GLArrayDataEditable extends GLArrayData { public boolean sealed(); + + public boolean enabled(); /** - * The VBO buffer usage, if it's an VBO, otherwise -1 + * Is the buffer written to the VBO ? */ - public int getBufferUsage(); + public boolean isVBOWritten(); /** - * Is the buffer written to the GPU ? + * Marks the buffer written to the VBO */ - public boolean isBufferWritten(); - - /** - * Marks the buffer written to the GPU - */ - public void setBufferWritten(boolean written); + public void setVBOWritten(boolean written); // // Data and GL state modification .. @@ -39,29 +36,27 @@ public interface GLArrayDataEditable extends GLArrayData { public void reset(GL gl); /** - * If seal is true, it - * disable write operations to the buffer. - * Calls flip, ie limit:=position and position:=0. - * Also enables the buffer for OpenGL, and passes the data. - * - * If seal is false, it - * enable write operations continuing - * at the buffer position, where you left off at seal(true), - * ie position:=limit and limit:=capacity. - * Also disables the buffer for OpenGL. + * Convenience method calling {@link #seal(boolean)} and {@link #enableBuffer(GL, boolean)}. * * @see #seal(boolean) + * @see #enableBuffer(GL, boolean) + * */ public void seal(GL gl, boolean seal); /** - * Enables/disables the buffer, which implies - * the client state, binding the VBO - * and transfering the data if not done yet. + * <p>Enables/disables the buffer, + * sets the client state, binds the VBO if used + * and transfers the data if necessary.</p> + * + * <p>The action will only be executed, + * if the internal enable state differs, + * or 'setEnableAlways' was called with 'true'.</b> * - * The above will only be executed, - * if the buffer is disabled, - * or 'setEnableAlways' was called with 'true'. + * <p>It is up to the user to enable/disable the array properly, + * ie in case of multiple data sets for the same vertex attribute (VA). + * Meaning in such case usage of one set while expecting another one + * to be used for the same VA implies decorating each usage with enable/disable.</p> * * @see #setEnableAlways(boolean) */ @@ -72,8 +67,9 @@ public interface GLArrayDataEditable extends GLArrayData { * * The default is 'false' * - * This is usefull when you mix up - * GLArrayData usage with conventional GL array calls. + * This is useful when you mix up + * GLArrayData usage with conventional GL array calls + * or in case of a buggy GL VBO implementation. * * @see #enableBuffer(GL, boolean) */ @@ -86,16 +82,17 @@ public interface GLArrayDataEditable extends GLArrayData { public void reset(); /** - * If seal is true, it - * disable write operations to the buffer. - * Calls flip, ie limit:=position and position:=0. + * <p>If <i>seal</i> is true, it + * disables write operations to the buffer. + * Calls flip, ie limit:=position and position:=0.</p> * - * If seal is false, it + * <p>If <i>seal</i> is false, it * enable write operations continuing * at the buffer position, where you left off at seal(true), - * ie position:=limit and limit:=capacity. + * ie position:=limit and limit:=capacity.</p> * - */ + * @see #seal(boolean) + */ public void seal(boolean seal); public void rewind(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java index c061e212a..23c237909 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataServer.java @@ -2,6 +2,7 @@ package com.jogamp.opengl.util; import javax.media.opengl.*; + import java.nio.*; import com.jogamp.opengl.util.glsl.*; @@ -13,111 +14,170 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE // /** - * Create a VBOBuffer object, using a predefined fixed function array index + * Create a VBO, using a predefined fixed function array index * and starting with a given Buffer object incl it's stride * * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. * On profile ES2 the fixed function emulation will transform these calls to * EnableVertexAttribArray and VertexAttribPointer calls, - * and a predefined vertex attribute variable name will be choosen. - * + * and a predefined vertex attribute variable name will be chosen. + * * @param index The GL array index * @param name The optional custom name for the GL array index, maybe null. - * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. - * This name might be used as the shader attribute name. + * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. + * This name might be used as the shader attribute name. * @param comps The array component number * @param dataType The array index GL data type - * @param normalized Wheather the data shall be normalized + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) */ - public static GLArrayDataServer createFixed(GL gl, int index, String name, int comps, int dataType, boolean normalized, - int stride, Buffer buffer, int vboBufferUsage) + public static GLArrayDataServer createFixed(int index, String name, int comps, int dataType, boolean normalized, int stride, + Buffer buffer, int vboUsage) throws GLException { - gl.getGLProfile().isValidArrayDataType(index, comps, dataType, false, true); - GLArrayDataServer ads = new GLArrayDataServer(); GLArrayHandler glArrayHandler = new GLFixedArrayHandler(ads); - ads.init(gl, name, index, comps, dataType, normalized, stride, buffer, buffer.limit(), false, glArrayHandler, - 0, 0, vboBufferUsage); + ads.init(name, index, comps, dataType, normalized, stride, buffer, buffer.limit(), false, glArrayHandler, + 0, 0, vboUsage, GL.GL_ARRAY_BUFFER); return ads; } /** - * Create a VBOBuffer object, using a predefined fixed function array index + * Create a VBO, using a predefined fixed function array index * and starting with a new created Buffer object with initialSize size * * On profiles GL2 and ES1 the fixed function pipeline behavior is as expected. * On profile ES2 the fixed function emulation will transform these calls to * EnableVertexAttribArray and VertexAttribPointer calls, - * and a predefined vertex attribute variable name will be choosen. + * and a predefined vertex attribute variable name will be chosen. + * + * @param index The GL array index + * @param name The optional custom name for the GL array index, maybe null. + * If null, the default name mapping will be used, see 'getPredefinedArrayIndexName(int)'. + * This name might be used as the shader attribute name. + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param initialSize + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} * * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) */ - public static GLArrayDataServer createFixed(GL gl, int index, String name, int comps, int dataType, boolean normalized, - int initialSize, int vboBufferUsage) + public static GLArrayDataServer createFixed(int index, String name, int comps, int dataType, boolean normalized, int initialSize, + int vboUsage) throws GLException { - gl.getGLProfile().isValidArrayDataType(index, comps, dataType, false, true); - - GLArrayDataServer ads = new GLArrayDataServer(); - GLArrayHandler glArrayHandler = new GLFixedArrayHandler(ads); - ads.init(gl, name, index, comps, dataType, normalized, 0, null, initialSize, false, glArrayHandler, - 0, 0, vboBufferUsage); + GLArrayDataServer ads = new GLArrayDataServer(); + GLArrayHandler glArrayHandler = new GLFixedArrayHandler(ads); + ads.init(name, index, comps, dataType, normalized, 0, null, initialSize, false, glArrayHandler, + 0, 0, vboUsage, GL.GL_ARRAY_BUFFER); return ads; } /** - * Create a VBOBuffer object, using a custom GLSL array attribute name + * Create a VBO, using a custom GLSL array attribute name * and starting with a new created Buffer object with initialSize size - * - * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + * + * @param st The ShaderState managing the state of the used shader program, vertex attributes and uniforms + * @param name The custom name for the GL attribute, maybe null if gpuBufferTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER} + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param initialSize + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + */ + public static GLArrayDataServer createGLSL(ShaderState st, String name, + int comps, int dataType, boolean normalized, int initialSize, + int vboUsage) + throws GLException + { + GLArrayDataServer ads = new GLArrayDataServer(); + GLArrayHandler glArrayHandler = new GLSLArrayHandler(st, ads); + ads.init(name, -1, comps, dataType, normalized, 0, null, initialSize, + true, glArrayHandler, 0, 0, vboUsage, GL.GL_ARRAY_BUFFER); + return ads; + } + + /** + * Create a VBO, using a custom GLSL array attribute name + * and starting with a given Buffer object incl it's stride + * + * @param st The ShaderState managing the state of the used shader program, vertex attributes and uniforms + * @param name The custom name for the GL attribute, maybe null if gpuBufferTarget is + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} */ - public static GLArrayDataServer createGLSL(GL gl, String name, int comps, int dataType, boolean normalized, - int initialSize, int vboBufferUsage) + public static GLArrayDataServer createGLSL(ShaderState st, String name, + int comps, int dataType, boolean normalized, int stride, + Buffer buffer, int vboUsage) throws GLException { - if(!gl.hasGLSL()) { - throw new GLException("GLArrayDataServer.GLSL not supported: "+gl); - } - gl.getGLProfile().isValidArrayDataType(-1, comps, dataType, true, true); - GLArrayDataServer ads = new GLArrayDataServer(); - GLArrayHandler glArrayHandler = new GLSLArrayHandler(ads); - ads.init(gl, name, -1, comps, dataType, normalized, 0, null, initialSize, true, glArrayHandler, - 0, 0, vboBufferUsage); + GLArrayHandler glArrayHandler = new GLSLArrayHandler(st, ads); + ads.init(name, -1, comps, dataType, normalized, stride, buffer, buffer.limit(), true, glArrayHandler, + 0, 0, vboUsage, GL.GL_ARRAY_BUFFER); return ads; } /** - * Create a VBOBuffer object, using a custom GLSL array attribute name - * and starting with a given Buffer object incl it's stride - * - * @see javax.media.opengl.GLContext#getPredefinedArrayIndexName(int) + * Create a VBO data object for any target w/o render pipeline association, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}. + * + * Hence no index, name for a fixed function pipeline nor vertex attribute is given. + * + * @param comps The array component number + * @param dataType The array index GL data type + * @param stride + * @param buffer the user define data + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + * @param vboTarget {@link GL#GL_ELEMENT_ARRAY_BUFFER}, .. + * {@link GL#glGenBuffers(int, int[], int) */ - public static GLArrayDataServer createGLSL(GL gl, String name, int comps, int dataType, boolean normalized, - int stride, Buffer buffer, int vboBufferUsage) + public static GLArrayDataServer createData(int comps, int dataType, int stride, + Buffer buffer, int vboUsage, int vboTarget) throws GLException { - if(!gl.hasGLSL()) { - throw new GLException("GLArrayDataServer.GLSL not supported: "+gl); - } - gl.getGLProfile().isValidArrayDataType(-1, comps, dataType, true, true); + GLArrayDataServer ads = new GLArrayDataServer(); + GLArrayHandler glArrayHandler = new GLDataArrayHandler(ads); + ads.init(null, -1, comps, dataType, false, stride, buffer, buffer.limit(), false, glArrayHandler, + 0, 0, vboUsage, vboTarget); + return ads; + } + /** + * Create a VBO data object for any target w/o render pipeline association, ie {@link GL#GL_ELEMENT_ARRAY_BUFFER}. + * + * Hence no index, name for a fixed function pipeline nor vertex attribute is given. + * + * @param comps The array component number + * @param dataType The array index GL data type + * @param initialSize + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + * @param vboTarget {@link GL#GL_ELEMENT_ARRAY_BUFFER}, .. + */ + public static GLArrayDataServer createData(int comps, int dataType, int initialSize, + int vboUsage, int vboTarget) + throws GLException + { GLArrayDataServer ads = new GLArrayDataServer(); - GLArrayHandler glArrayHandler = new GLSLArrayHandler(ads); - ads.init(gl, name, -1, comps, dataType, normalized, stride, buffer, buffer.limit(), true, glArrayHandler, - 0, 0, vboBufferUsage); + GLArrayHandler glArrayHandler = new GLDataArrayHandler(ads); + ads.init(null, -1, comps, dataType, false, 0, null, initialSize, false, glArrayHandler, + 0, 0, vboUsage, vboTarget); return ads; } + // // Data matters GLArrayData // - public int getBufferUsage() { return vboBufferUsage; } - // // Data and GL state modification .. // @@ -141,9 +201,9 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE * switch to client side data one * Only possible if buffer is defined. */ - public void setVBOUsage(boolean vboUsage) { + public void setVBOEnabled(boolean vboUsage) { checkSeal(false); - super.setVBOUsage(vboUsage); + super.setVBOEnabled(vboUsage); } public String toString() { @@ -151,20 +211,22 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE ", index "+index+ ", location "+location+ ", isVertexAttribute "+isVertexAttribute+ - ", dataType "+dataType+ - ", bufferClazz "+clazz+ + ", dataType "+componentType+ + ", bufferClazz "+componentClazz+ ", elements "+getElementNumber()+ ", components "+components+ ", stride "+stride+"u "+strideB+"b "+strideL+"c"+ ", initialSize "+initialSize+ - ", vboBufferUsage "+vboBufferUsage+ - ", vboUsage "+vboUsage+ + ", vboUsage 0x"+Integer.toHexString(vboUsage)+ + ", vboTarget 0x"+Integer.toHexString(vboTarget)+ + ", vboEnabled "+vboEnabled+ ", vboName "+vboName+ ", sealed "+sealed+ ", bufferEnabled "+bufferEnabled+ ", bufferWritten "+bufferWritten+ ", buffer "+buffer+ - ", offset "+bufferOffset+ + ", offset "+vboOffset+ + ", alive "+alive+ "]"; } @@ -172,38 +234,25 @@ public class GLArrayDataServer extends GLArrayDataClient implements GLArrayDataE // non public matters .. // - protected void init(GL gl, String name, int index, int comps, int dataType, boolean normalized, + protected void init(String name, int index, int comps, int dataType, boolean normalized, int stride, Buffer data, int initialSize, boolean isVertexAttribute, GLArrayHandler glArrayHandler, - int vboName, long bufferOffset, int vboBufferUsage) + int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { super.init(name, index, comps, dataType, normalized, stride, data, initialSize, isVertexAttribute, glArrayHandler, - vboName, bufferOffset); - - vboUsage=true; - - if( ! (gl.isGL2ES2() && vboBufferUsage==GL2ES2.GL_STREAM_DRAW) ) { - switch(vboBufferUsage) { - case -1: // nop - case GL.GL_STATIC_DRAW: - case GL.GL_DYNAMIC_DRAW: - break; - default: - throw new GLException("invalid vboBufferUsage: "+vboBufferUsage+":\n\t"+this); - } - } - this.vboBufferUsage=vboBufferUsage; + vboName, vboOffset, vboUsage, vboTarget); + + vboEnabled=true; } protected void init_vbo(GL gl) { - if(vboUsage && vboName==0) { + super.init_vbo(gl); + if(vboEnabled && vboName==0) { int[] tmp = new int[1]; gl.glGenBuffers(1, tmp, 0); vboName = tmp[0]; } } - - protected int vboBufferUsage; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java index 88a8603f9..735bd11f7 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLArrayDataWrapper.java @@ -9,34 +9,85 @@ import java.nio.*; public class GLArrayDataWrapper implements GLArrayData { - public static GLArrayDataWrapper createFixed(GL gl, int index, int comps, int dataType, boolean normalized, - int stride, Buffer buffer, - int vboName, long bufferOffset) + /** + * Create a VBO, using a predefined fixed function array index, wrapping the given data. + * + * @param index The GL array index + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + * @param vboName + * @param vboOffset + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + * + * @return the new create instance + * + * @throws GLException + */ + public static GLArrayDataWrapper createFixed(int index, int comps, int dataType, boolean normalized, int stride, + Buffer buffer, int vboName, + long vboOffset, int vboUsage) throws GLException { - gl.getGLProfile().isValidArrayDataType(index, comps, dataType, false, true); GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(null, index, comps, dataType, normalized, stride, buffer, false, - vboName, bufferOffset); + vboName, vboOffset, vboUsage, GL.GL_ARRAY_BUFFER); return adc; } - public static GLArrayDataWrapper createGLSL(GL gl, String name, int comps, int dataType, boolean normalized, - int stride, Buffer buffer, - int vboName, long bufferOffset) + /** + * Create a VBO, using a custom GLSL array attribute name, wrapping the given data. + * + * @param name The custom name for the GL attribute, maybe null if gpuBufferTarget is {@link GL#GL_ELEMENT_ARRAY_BUFFER} + * @param comps The array component number + * @param dataType The array index GL data type + * @param normalized Whether the data shall be normalized + * @param stride + * @param buffer the user define data + * @param vboName + * @param vboOffset + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + * + * @return the new create instance + * @throws GLException + */ + public static GLArrayDataWrapper createGLSL(String name, int comps, int dataType, boolean normalized, int stride, + Buffer buffer, int vboName, + long vboOffset, int vboUsage) throws GLException { - if(!gl.hasGLSL()) { - throw new GLException("GLArrayDataWrapper.GLSL not supported: "+gl); - } - gl.getGLProfile().isValidArrayDataType(-1, comps, dataType, true, true); - GLArrayDataWrapper adc = new GLArrayDataWrapper(); adc.init(name, -1, comps, dataType, normalized, stride, buffer, true, - vboName, bufferOffset); + vboName, vboOffset, vboUsage, GL.GL_ARRAY_BUFFER); return adc; } + /** + * Validates this instance's parameter. Called automatically by {@link GLArrayDataClient} and {@link GLArrayDataServer}. + * {@link GLArrayDataWrapper} does not validate it's instance by itself. + * + * @param glp the GLProfile to use + * @param throwException whether to throw an exception if this instance has invalid parameter or not + * @return true if this instance has invalid parameter, otherwise false + */ + public final boolean validate(GLProfile glp, boolean throwException) { + if(!alive) { + if(throwException) { + throw new GLException("Instance !alive "+this); + } + return false; + } + if(this.isVertexAttribute() && !glp.hasGLSL()) { + if(throwException) { + throw new GLException("GLSL not supported on "+glp+", "+this); + } + return false; + } + return glp.isValidArrayDataType(getIndex(), getComponentNumber(), getComponentType(), isVertexAttribute(), throwException); + } + // // Data read access // @@ -51,54 +102,45 @@ public class GLArrayDataWrapper implements GLArrayData { public final String getName() { return name; } - public final long getOffset() { return vboUsage?bufferOffset:-1; } + public final long getVBOOffset() { return vboEnabled?vboOffset:-1; } - public final int getVBOName() { return vboUsage?vboName:-1; } + public final int getVBOName() { return vboEnabled?vboName:-1; } - public final boolean isVBO() { return vboUsage; } + public final boolean isVBO() { return vboEnabled; } + public final int getVBOUsage() { return vboEnabled?vboUsage:-1; } + + public final int getVBOTarget() { return vboEnabled?vboTarget:-1; } + public final Buffer getBuffer() { return buffer; } public final int getComponentNumber() { return components; } - public final int getComponentType() { return dataType; } - - public final int getComponentSize() { - if(clazz==ByteBuffer.class) { - return GLBuffers.SIZEOF_BYTE; - } - if(clazz==ShortBuffer.class) { - return GLBuffers.SIZEOF_SHORT; - } - if(clazz==IntBuffer.class) { - return GLBuffers.SIZEOF_INT; - } - if(clazz==FloatBuffer.class) { - return GLBuffers.SIZEOF_FLOAT; - } - throw new GLException("Given Buffer Class not supported: "+clazz+":\n\t"+this); - } + public final int getComponentType() { return componentType; } + public final int getComponentSize() { return componentSize; } + public final int getElementNumber() { if(null==buffer) return 0; return ( buffer.position()==0 ) ? ( buffer.limit() / components ) : ( buffer.position() / components ) ; } - + public final int getByteSize() { + if(null==buffer) return 0; + return ( buffer.position()==0 ) ? ( buffer.limit() * componentSize ) : ( buffer.position() * componentSize ) ; + } + public final boolean getNormalized() { return normalized; } public final int getStride() { return stride; } - public final Class getBufferClass() { return clazz; } + public final Class getBufferClass() { return componentClazz; } public void destroy(GL gl) { - this.buffer = null; - this.components = 0; - this.stride=0; - this.strideB=0; - this.strideL=0; - this.vboName=0; - this.vboUsage=false; - this.bufferOffset=0; + buffer = null; + vboName=0; + vboEnabled=false; + vboOffset=-1; + alive = false; } public String toString() { @@ -106,15 +148,18 @@ public class GLArrayDataWrapper implements GLArrayData { ", index "+index+ ", location "+location+ ", isVertexAttribute "+isVertexAttribute+ - ", dataType "+dataType+ - ", bufferClazz "+clazz+ + ", dataType "+componentType+ + ", bufferClazz "+componentClazz+ ", elements "+getElementNumber()+ ", components "+components+ ", stride "+stride+"u "+strideB+"b "+strideL+"c"+ ", buffer "+buffer+ - ", offset "+bufferOffset+ - ", vboUsage "+vboUsage+ + ", offset "+vboOffset+ + ", vboUsage 0x"+Integer.toHexString(vboUsage)+ + ", vboTarget 0x"+Integer.toHexString(vboTarget)+ + ", vboEnabled "+vboEnabled+ ", vboName "+vboName+ + ", alive "+alive+ "]"; } @@ -140,76 +185,140 @@ public class GLArrayDataWrapper implements GLArrayData { name = newName; } - public void setVBOUsage(boolean vboUsage) { - this.vboUsage=vboUsage; + /** + * Enable or disable use of VBO. + * Only possible if a VBO buffer name is defined. + * @see #setVBOName(int) + */ + public void setVBOEnabled(boolean vboEnabled) { + this.vboEnabled=vboEnabled; } + /** + * Set the VBO buffer name, if valid (>0) enable use of VBO + * @see #setVBOEnabled(boolean) + */ public void setVBOName(int vboName) { this.vboName=vboName; - setVBOUsage(vboName>0); + setVBOEnabled(vboName>0); } - protected void init(String name, int index, int comps, int dataType, boolean normalized, int stride, Buffer data, + /** + * @param vboUsage {@link GL2ES2#GL_STREAM_DRAW}, {@link GL#GL_STATIC_DRAW} or {@link GL#GL_DYNAMIC_DRAW} + */ + public void setVBOUsage(int vboUsage) { + this.vboUsage = vboUsage; + } + + /** + * @param vboTarget either {@link GL#GL_ARRAY_BUFFER} or {@link GL#GL_ELEMENT_ARRAY_BUFFER} + */ + public void setVBOTarget(int vboTarget) { + this.vboTarget = vboTarget; + } + + protected void init(String name, int index, int components, int componentType, + boolean normalized, int stride, Buffer data, boolean isVertexAttribute, - int vboName, long bufferOffset) + int vboName, long vboOffset, int vboUsage, int vboTarget) throws GLException { this.isVertexAttribute = isVertexAttribute; this.index = index; this.location = -1; // We can't have any dependence on the FixedFuncUtil class here for build bootstrapping reasons - this.name = (null==name)?FixedFuncPipeline.getPredefinedArrayIndexName(index):name; - if(null==this.name) { - throw new GLException("Not a valid GL array index: "+index); + + if( GL.GL_ELEMENT_ARRAY_BUFFER == vboTarget ) { + // ok .. + } else if( GL.GL_ARRAY_BUFFER == vboTarget ) { + // check name .. + this.name = ( null == name ) ? FixedFuncPipeline.getPredefinedArrayIndexName(index) : name ; + if(null == this.name ) { + throw new GLException("Not a valid array buffer index: "+index); + } + } else if( 0 <= vboTarget ) { + throw new GLException("Invalid GPUBuffer target: 0x"+Integer.toHexString(vboTarget)); } - this.dataType = dataType; - this.clazz = getBufferClass(dataType); - switch(dataType) { + + this.componentType = componentType; + componentClazz = getBufferClass(componentType); + switch(componentType) { case GL.GL_BYTE: case GL.GL_UNSIGNED_BYTE: case GL.GL_SHORT: case GL.GL_UNSIGNED_SHORT: - case GL2ES1.GL_FIXED: + case GL.GL_FIXED: this.normalized = normalized; break; default: this.normalized = false; } + componentSize = GLBuffers.sizeOfGLType(componentType); + if(0 > componentSize) { + throw new GLException("Given componentType not supported: "+componentType+":\n\t"+this); + } + if(0 >= components) { + throw new GLException("Invalid number of components: " + components); + } + this.components = components; - int bpc = getComponentSize(); - if(0<stride && stride<comps*bpc) { - throw new GLException("stride ("+stride+") lower than component bytes, "+comps+" * "+bpc); + if(0<stride && stride<components*componentSize) { + throw new GLException("stride ("+stride+") lower than component bytes, "+components+" * "+componentSize); } - if(0<stride && stride%bpc!=0) { - throw new GLException("stride ("+stride+") not a multiple of bpc "+bpc); + if(0<stride && stride%componentSize!=0) { + throw new GLException("stride ("+stride+") not a multiple of bpc "+componentSize); } this.buffer = data; - this.components = comps; this.stride=stride; - this.strideB=(0==stride)?comps*bpc:stride; - this.strideL=(0==stride)?comps:strideB/bpc; + this.strideB=(0==stride)?components*componentSize:stride; + this.strideL=(0==stride)?components:strideB/componentSize; this.vboName=vboName; - this.vboUsage=vboName>0; - this.bufferOffset=bufferOffset; + this.vboEnabled=vboName>0; + this.vboOffset=vboOffset; + + switch(vboUsage) { + case -1: // nop + case GL.GL_STATIC_DRAW: + case GL.GL_DYNAMIC_DRAW: + case GL2ES2.GL_STREAM_DRAW: + break; + default: + throw new GLException("invalid gpuBufferUsage: "+vboUsage+":\n\t"+this); + } + switch(vboTarget) { + case -1: // nop + case GL.GL_ARRAY_BUFFER: + case GL.GL_ELEMENT_ARRAY_BUFFER: + break; + default: + throw new GLException("invalid gpuBufferTarget: "+vboTarget+":\n\t"+this); + } + this.vboUsage=vboUsage; + this.vboTarget=vboTarget; + this.alive=true; } protected GLArrayDataWrapper() { } + protected boolean alive; protected int index; protected int location; protected String name; protected int components; - protected int dataType; + protected int componentType; + protected Class componentClazz; + protected int componentSize; protected boolean normalized; protected int stride; // user given stride protected int strideB; // stride in bytes protected int strideL; // stride in logical components - protected Class clazz; protected Buffer buffer; protected boolean isVertexAttribute; - protected long bufferOffset; + protected long vboOffset; protected int vboName; - protected boolean vboUsage; + protected boolean vboEnabled; + protected int vboUsage; + protected int vboTarget; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLDataArrayHandler.java b/src/jogl/classes/com/jogamp/opengl/util/GLDataArrayHandler.java new file mode 100644 index 000000000..74d49aa6c --- /dev/null +++ b/src/jogl/classes/com/jogamp/opengl/util/GLDataArrayHandler.java @@ -0,0 +1,41 @@ + +package com.jogamp.opengl.util; + +import javax.media.opengl.*; +import javax.media.opengl.fixedfunc.*; +import com.jogamp.opengl.util.*; +import java.nio.*; + +public class GLDataArrayHandler implements GLArrayHandler { + private GLArrayDataEditable ad; + + public GLDataArrayHandler(GLArrayDataEditable ad) { + this.ad = ad; + } + + public void enableBuffer(GL gl, boolean enable) { + GLPointerFunc glp = gl.getGL2ES1(); + if(enable) { + Buffer buffer = ad.getBuffer(); + + if(ad.isVBO()) { + // always bind and refresh the VBO mgr, + // in case more than one gl*Pointer objects are in use + gl.glBindBuffer(ad.getVBOTarget(), ad.getVBOName()); + if(!ad.isVBOWritten()) { + if(null!=buffer) { + gl.glBufferData(ad.getVBOTarget(), buffer.limit() * ad.getComponentSize(), buffer, ad.getVBOUsage()); + } + ad.setVBOWritten(true); + } + } else if(null!=buffer) { + ad.setVBOWritten(true); + } + } else { + if(ad.isVBO()) { + gl.glBindBuffer(ad.getVBOTarget(), 0); + } + } + } +} + diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLFixedArrayHandler.java b/src/jogl/classes/com/jogamp/opengl/util/GLFixedArrayHandler.java index f0f5ea896..a825ca690 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLFixedArrayHandler.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLFixedArrayHandler.java @@ -13,7 +13,7 @@ public class GLFixedArrayHandler implements GLArrayHandler { this.ad = ad; } - protected final void passArrayPointer(GLPointerFunc gl) { + private final void passArrayPointer(GLPointerFunc gl) { switch(ad.getIndex()) { case GLPointerFunc.GL_VERTEX_ARRAY: gl.glVertexPointer(ad); @@ -42,21 +42,21 @@ public class GLFixedArrayHandler implements GLArrayHandler { if(ad.isVBO()) { // always bind and refresh the VBO mgr, // in case more than one gl*Pointer objects are in use - gl.glBindBuffer(GL.GL_ARRAY_BUFFER, ad.getVBOName()); - if(!ad.isBufferWritten()) { + gl.glBindBuffer(ad.getVBOTarget(), ad.getVBOName()); + if(!ad.isVBOWritten()) { if(null!=buffer) { - gl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit() * ad.getComponentSize(), buffer, ad.getBufferUsage()); + gl.glBufferData(ad.getVBOTarget(), buffer.limit() * ad.getComponentSize(), buffer, ad.getVBOUsage()); } - ad.setBufferWritten(true); + ad.setVBOWritten(true); } passArrayPointer(glp); } else if(null!=buffer) { passArrayPointer(glp); - ad.setBufferWritten(true); + ad.setVBOWritten(true); } } else { if(ad.isVBO()) { - gl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + gl.glBindBuffer(ad.getVBOTarget(), 0); } glp.glDisableClientState(ad.getIndex()); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java index d9fce6e6a..9e92a9a1d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java +++ b/src/jogl/classes/com/jogamp/opengl/util/ImmModeSink.java @@ -2,6 +2,8 @@ package com.jogamp.opengl.util; import com.jogamp.common.util.*; +import com.jogamp.opengl.util.glsl.ShaderState; + import javax.media.opengl.*; import javax.media.opengl.fixedfunc.*; import java.nio.*; @@ -35,8 +37,8 @@ public class ImmModeSink { * a ShaderState must be current, using ShaderState.glUseProgram(). * * @see #draw(GL, boolean) - * @see com.jogamp.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) - * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrent() + * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean) + * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState() */ public static ImmModeSink createGLSL(GL gl, int glBufferUsage, int initialSize, int vComps, int vDataType, @@ -745,11 +747,11 @@ public class ImmModeSink { } public void enableBufferGLSL(GL gl, boolean enable) { - GL2ES2 glsl = gl.getGL2ES2(); - com.jogamp.opengl.util.glsl.ShaderState st = com.jogamp.opengl.util.glsl.ShaderState.getCurrent(); + ShaderState st = ShaderState.getShaderState(gl); if(null==st) { - throw new GLException("No ShaderState current"); - } + throw new GLException("No ShaderState in "+gl); + } + GL2ES2 glsl = gl.getGL2ES2(); if(enable) { glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, vboName); @@ -760,35 +762,35 @@ public class ImmModeSink { } if(vComps>0) { - st.glEnableVertexAttribArray(glsl, vArrayData.getName()); - st.glVertexAttribPointer(glsl, vArrayData); + st.enableVertexAttribArray(glsl, vArrayData); + st.vertexAttribPointer(glsl, vArrayData); } if(cComps>0) { - st.glEnableVertexAttribArray(glsl, cArrayData.getName()); - st.glVertexAttribPointer(glsl, cArrayData); + st.enableVertexAttribArray(glsl, cArrayData); + st.vertexAttribPointer(glsl, cArrayData); } if(nComps>0) { - st.glEnableVertexAttribArray(glsl, nArrayData.getName()); - st.glVertexAttribPointer(glsl, nArrayData); + st.enableVertexAttribArray(glsl, nArrayData); + st.vertexAttribPointer(glsl, nArrayData); } if(tComps>0) { - st.glEnableVertexAttribArray(glsl, tArrayData.getName()); - st.glVertexAttribPointer(glsl, tArrayData); + st.enableVertexAttribArray(glsl, tArrayData); + st.vertexAttribPointer(glsl, tArrayData); } glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); } else { if(vComps>0) { - st.glDisableVertexAttribArray(glsl, vArrayData.getName()); + st.disableVertexAttribArray(glsl, vArrayData); } if(cComps>0) { - st.glDisableVertexAttribArray(glsl, cArrayData.getName()); + st.disableVertexAttribArray(glsl, cArrayData); } if(nComps>0) { - st.glDisableVertexAttribArray(glsl, nArrayData.getName()); + st.disableVertexAttribArray(glsl, nArrayData); } if(tComps>0) { - st.glDisableVertexAttribArray(glsl, tArrayData.getName()); + st.disableVertexAttribArray(glsl, tArrayData); } } } @@ -860,26 +862,26 @@ public class ImmModeSink { buffer.flip(); if(vComps>0) { - vArrayData = GLArrayDataWrapper.createFixed(gl, GLPointerFunc.GL_VERTEX_ARRAY, vComps, vDataType, false, - 0, vertexArray, 0, vOffset); + vArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_VERTEX_ARRAY, vComps, vDataType, false, 0, + vertexArray, 0, vOffset, GL.GL_STATIC_DRAW); } else { vArrayData = null; } if(cComps>0) { - cArrayData = GLArrayDataWrapper.createFixed(gl, GLPointerFunc.GL_COLOR_ARRAY, cComps, cDataType, false, - 0, colorArray, 0, cOffset); + cArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_COLOR_ARRAY, cComps, cDataType, false, 0, + colorArray, 0, cOffset, GL.GL_STATIC_DRAW); } else { cArrayData = null; } if(nComps>0) { - nArrayData = GLArrayDataWrapper.createFixed(gl, GLPointerFunc.GL_NORMAL_ARRAY, nComps, nDataType, false, - 0, normalArray, 0, nOffset); + nArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_NORMAL_ARRAY, nComps, nDataType, false, 0, + normalArray, 0, nOffset, GL.GL_STATIC_DRAW); } else { nArrayData = null; } if(tComps>0) { - tArrayData = GLArrayDataWrapper.createFixed(gl, GLPointerFunc.GL_TEXTURE_COORD_ARRAY, tComps, tDataType, false, - 0, textCoordArray, 0, tOffset); + tArrayData = GLArrayDataWrapper.createFixed(GLPointerFunc.GL_TEXTURE_COORD_ARRAY, tComps, tDataType, false, 0, + textCoordArray, 0, tOffset, GL.GL_STATIC_DRAW); } else { tArrayData = null; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/Locator.java b/src/jogl/classes/com/jogamp/opengl/util/Locator.java index 8dbd7cd93..0176b575a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Locator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Locator.java @@ -49,6 +49,9 @@ public class Locator { * @see #getResource(String, ClassLoader) */ public static URL getResource(Class context, String path) { + if(null == path) { + return null; + } ClassLoader contextCL = (null!=context)?context.getClassLoader():null; URL url = getResource(path, contextCL); if (url == null && null!=context) { @@ -73,24 +76,36 @@ public class Locator { * @see File#File(String) */ public static URL getResource(String path, ClassLoader cl) { + if(null == path) { + return null; + } URL url = null; if (cl != null) { url = cl.getResource(path); - } else { + if(!urlExists(url)) { + url = null; + } + } + if(null == url) { url = ClassLoader.getSystemResource(path); + if(!urlExists(url)) { + url = null; + } } - if(!urlExists(url)) { - url = null; + if(null == url) { try { url = new URL(path); + if(!urlExists(url)) { + url = null; + } } catch (MalformedURLException e) { } } - if(!urlExists(url)) { - url = null; + if(null == url) { try { File file = new File(path); if(file.exists()) { url = file.toURL(); + } else { } } catch (MalformedURLException e) {} } @@ -98,25 +113,53 @@ public class Locator { } /** - * Generates a path for the 'relativeFile' relative to the 'absoluteFileLocation' + * Generates a path for the 'relativeFile' relative to the 'baseLocation'. + * + * @param baseLocation denotes a directory + * @param relativeFile denotes a relative file to the baseLocation */ - public static String getRelativeOf(String absoluteFileLocation, String relativeFile) { - File file = new File(absoluteFileLocation); - file = file.getParentFile(); - while (file != null && relativeFile.startsWith("../")) { - file = file.getParentFile(); + public static String getRelativeOf(File baseLocation, String relativeFile) { + if(null == relativeFile) { + return null; + } + + while (baseLocation != null && relativeFile.startsWith("../")) { + baseLocation = baseLocation.getParentFile(); relativeFile = relativeFile.substring(3); } - if (file != null) { - String res = new File(file, relativeFile).getPath(); - // Handle things on Windows - return res.replace('\\', '/'); - } else { - return relativeFile; + if (baseLocation != null) { + final File file = new File(baseLocation, relativeFile); + // Handle things on Windows + return file.getPath().replace('\\', '/'); } + return null; } /** + * Generates a path for the 'relativeFile' relative to the 'baseLocation'. + * + * @param baseLocation denotes a URL to a file + * @param relativeFile denotes a relative file to the baseLocation's parent directory + */ + public static String getRelativeOf(URL baseLocation, String relativeFile) { + String urlPath = baseLocation.getPath(); + + if ( baseLocation.toString().startsWith("jar") ) { + JarURLConnection jarConnection; + try { + jarConnection = (JarURLConnection) baseLocation.openConnection(); + urlPath = jarConnection.getEntryName(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + // Try relative path first + return getRelativeOf(new File(urlPath).getParentFile(), relativeFile); + } + + /** * Returns true, if the url exists, * trying to open a connection. */ diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java index 86882176a..de28dc70a 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextRenderer.java @@ -1590,7 +1590,7 @@ public class TextRenderer { int lengthInGlyphs = fullRunGlyphVector.getNumGlyphs(); int i = 0; while (i < lengthInGlyphs) { - Character letter = CharacterCache.valueOf(inString.charAt(i)); + Character letter = CharacterCache.valueOf(inString.charAt(i)); GlyphMetrics metrics = (GlyphMetrics) glyphMetricsCache.get(letter); if (metrics == null) { metrics = fullRunGlyphVector.getGlyphMetrics(i); @@ -1656,7 +1656,7 @@ public class TextRenderer { // if the unicode or glyph ID would be out of bounds of the // glyph cache. private Glyph getGlyph(CharSequence inString, - GlyphMetrics glyphMetrics, + GlyphMetrics glyphMetrics, int index) { char unicodeID = inString.charAt(index); diff --git a/src/jogl/classes/com/jogamp/opengl/util/awt/TextureRenderer.java b/src/jogl/classes/com/jogamp/opengl/util/awt/TextureRenderer.java index 86dca59f4..922fc69c1 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/awt/TextureRenderer.java +++ b/src/jogl/classes/com/jogamp/opengl/util/awt/TextureRenderer.java @@ -307,7 +307,7 @@ public class TextureRenderer { */ public void dispose() throws GLException { if (texture != null) { - texture.dispose(); + texture.destroy(GLContext.getCurrentGL()); texture = null; } if (image != null) { @@ -576,23 +576,23 @@ public class TextureRenderer { gl.glEnable(GL2.GL_BLEND); gl.glBlendFunc(GL2.GL_ONE, GL2.GL_ONE_MINUS_SRC_ALPHA); Texture texture = getTexture(); - texture.enable(); - texture.bind(); + texture.enable(gl); + texture.bind(gl); gl.glTexEnvi(GL2.GL_TEXTURE_ENV, GL2.GL_TEXTURE_ENV_MODE, GL2.GL_MODULATE); // Change polygon color to last saved gl.glColor4f(r, g, b, a); if (smoothingChanged) { smoothingChanged = false; if (smoothing) { - texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_LINEAR); if (mipmap) { - texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR_MIPMAP_LINEAR); } else { - texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_LINEAR); } } else { - texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); - texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); } } } @@ -600,7 +600,7 @@ public class TextureRenderer { private void endRendering(boolean ortho) { GL2 gl = GLContext.getCurrentGL().getGL2(); Texture texture = getTexture(); - texture.disable(); + texture.disable(gl); if (ortho) { gl.glMatrixMode(GL2.GL_PROJECTION); gl.glPopMatrix(); @@ -661,15 +661,16 @@ public class TextureRenderer { // OpenGL and Java 2D actually line up correctly for // updateSubImage calls, so we don't need to do any argument // conversion here (i.e., flipping the Y coordinate). - texture.updateSubImage(textureData, 0, x, y, x, y, width, height); + texture.updateSubImage(GLContext.getCurrentGL(), textureData, 0, x, y, x, y, width, height); } } // Returns true if the texture was newly allocated, false if not private boolean ensureTexture() { + GL gl = GLContext.getCurrentGL(); if (mustReallocateTexture) { if (texture != null) { - texture.dispose(); + texture.destroy(gl); texture = null; } mustReallocateTexture = false; @@ -679,7 +680,7 @@ public class TextureRenderer { texture = TextureIO.newTexture(textureData); if (mipmap && !texture.isUsingAutoMipmapGeneration()) { // Only try this once - texture.dispose(); + texture.destroy(gl); mipmap = false; textureData.setMipmap(false); texture = TextureIO.newTexture(textureData); @@ -687,8 +688,8 @@ public class TextureRenderer { if (!smoothing) { // The TextureIO classes default to GL_LINEAR filtering - texture.setTexParameteri(GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); - texture.setTexParameteri(GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MIN_FILTER, GL2.GL_NEAREST); + texture.setTexParameteri(gl, GL2.GL_TEXTURE_MAG_FILTER, GL2.GL_NEAREST); } return true; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/gl2/GLUT.java b/src/jogl/classes/com/jogamp/opengl/util/gl2/GLUT.java index 8befc13ba..010ce6699 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/gl2/GLUT.java +++ b/src/jogl/classes/com/jogamp/opengl/util/gl2/GLUT.java @@ -163,7 +163,7 @@ public class GLUT { public void glutSolidCylinder(double radius, double height, int slices, int stacks) { GL2 gl = GLUgl2.getCurrentGL2(); - + // Prepare table of points for drawing end caps double [] x = new double[slices]; double [] y = new double[slices]; @@ -174,7 +174,7 @@ public class GLUT { x[i] = Math.cos(angle) * radius; y[i] = Math.sin(angle) * radius; } - + // Draw bottom cap gl.glBegin(GL2.GL_TRIANGLE_FAN); gl.glNormal3d(0,0,-1); @@ -184,7 +184,7 @@ public class GLUT { } gl.glVertex3d(x[0], y[0], 0); gl.glEnd(); - + // Draw top cap gl.glBegin(GL2.GL_TRIANGLE_FAN); gl.glNormal3d(0,0,1); @@ -194,7 +194,7 @@ public class GLUT { } gl.glVertex3d(x[0], y[0], height); gl.glEnd(); - + // Draw walls quadObjInit(glu); glu.gluQuadricDrawStyle(quadObj, GLU.GLU_FILL); diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/GLSLArrayHandler.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/GLSLArrayHandler.java index 95a550ab6..73a1c2721 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/GLSLArrayHandler.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/GLSLArrayHandler.java @@ -28,56 +28,68 @@ package com.jogamp.opengl.util.glsl; -import javax.media.opengl.*; -import com.jogamp.opengl.util.*; -import java.nio.*; +import java.nio.Buffer; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLException; +import com.jogamp.opengl.util.GLArrayDataEditable; +import com.jogamp.opengl.util.GLArrayHandler; public class GLSLArrayHandler implements GLArrayHandler { + private static final boolean DEBUG = ShaderState.DEBUG; private GLArrayDataEditable ad; + private ShaderState st; - public GLSLArrayHandler(GLArrayDataEditable ad) { + public GLSLArrayHandler(ShaderState st, GLArrayDataEditable ad) { + this.st = st; this.ad = ad; } - protected final void passVertexAttribPointer(GL2ES2 gl, ShaderState st) { - st.glVertexAttribPointer(gl, ad); - } - public void enableBuffer(GL gl, boolean enable) { if(!gl.isGL2ES2()) { throw new GLException("GLSLArrayHandler expects a GL2ES2 implementation"); } GL2ES2 glsl = gl.getGL2ES2(); - ShaderState st = ShaderState.getCurrent(); - if(null==st) { - throw new GLException("No ShaderState current"); - } if(enable) { - st.glEnableVertexAttribArray(glsl, ad.getName()); + st.enableVertexAttribArray(glsl, ad); Buffer buffer = ad.getBuffer(); if(ad.isVBO()) { - // always bind and refresh the VBO mgr, - // in case more than one gl*Pointer objects are in use - glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, ad.getVBOName()); - if(!ad.isBufferWritten()) { + // bind and refresh the VBO / vertex-attr only if necessary + if(!ad.isVBOWritten()) { + if(DEBUG) { + System.err.println("XXX VA "+ad.getName()+" VBO write: "+ad.getVBOName()); + } + glsl.glBindBuffer(ad.getVBOTarget(), ad.getVBOName()); if(null!=buffer) { - glsl.glBufferData(GL.GL_ARRAY_BUFFER, buffer.limit() * ad.getComponentSize(), buffer, ad.getBufferUsage()); + glsl.glBufferData(ad.getVBOTarget(), ad.getByteSize(), buffer, ad.getVBOUsage()); + } + ad.setVBOWritten(true); + st.vertexAttribPointer(glsl, ad); + } else { + // didn't experience a performance hit on this query .. + int[] qi = new int[1]; + glsl.glGetVertexAttribiv(ad.getLocation(), GL2ES2.GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, qi, 0); + if(ad.getVBOName() != qi[0]) { + if(DEBUG) { + System.err.println("XXX VA "+ad.getName()+" VBO rebind: "+qi[0]+" -> "+ad.getVBOName()); + } + glsl.glBindBuffer(ad.getVBOTarget(), ad.getVBOName()); + st.vertexAttribPointer(glsl, ad); } - ad.setBufferWritten(true); } - passVertexAttribPointer(glsl, st); } else if(null!=buffer) { - passVertexAttribPointer(glsl, st); - ad.setBufferWritten(true); + st.vertexAttribPointer(glsl, ad); + ad.setVBOWritten(true); } } else { if(ad.isVBO()) { - glsl.glBindBuffer(GL.GL_ARRAY_BUFFER, 0); + glsl.glBindBuffer(ad.getVBOTarget(), 0); } - st.glDisableVertexAttribArray(glsl, ad.getName()); + st.disableVertexAttribArray(glsl, ad); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java index 1f59318f2..20b032a41 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderCode.java @@ -155,9 +155,9 @@ public class ShaderCode { return res; } } - Set binFmts = ShaderUtil.getShaderBinaryFormats(gl); - for(Iterator iter=binFmts.iterator(); null==res && iter.hasNext(); ) { - int bFmt = ((Integer)(iter.next())).intValue(); + Set<Integer> binFmts = ShaderUtil.getShaderBinaryFormats(gl); + for(Iterator<Integer> iter=binFmts.iterator(); null==res && iter.hasNext(); ) { + int bFmt = iter.next().intValue(); String bFmtPath = getBinarySubPath(bFmt); if(null==bFmtPath) continue; binFileName = binRoot + '/' + bFmtPath + '/' + basename + "." + getFileSuffix(true, type); @@ -174,16 +174,8 @@ public class ShaderCode { /** * returns the uniq shader id as an integer - * @see #key() */ - public int id() { return id.intValue(); } - - /** - * returns the uniq shader id as an Integer - * - * @see #id() - */ - public Integer key() { return id; } + public int id() { return id; } public int shaderType() { return shaderType; } public String shaderTypeStr() { return shaderTypeStr(shaderType); } @@ -239,7 +231,7 @@ public class ShaderCode { shaderSource=null; shaderBinaryFormat=-1; shaderType=-1; - id=null; + id=-1; } public boolean equals(Object obj) { @@ -250,7 +242,7 @@ public class ShaderCode { return false; } public int hashCode() { - return id.intValue(); + return id; } public String toString() { StringBuffer buf = new StringBuffer("ShaderCode [id="+id+", type="+shaderTypeStr()+", valid="+valid+", shader: "); @@ -290,26 +282,35 @@ public class ShaderCode { } } - public static void readShaderSource(ClassLoader context, String path, URL url, StringBuffer result) { + public static void readShaderSource(Class context, URL url, StringBuffer result) { try { + if(DEBUG_CODE) { + System.err.println("ShaderCode.readShaderSource<0>: "+url); + } BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream())); String line = null; while ((line = reader.readLine()) != null) { if (line.startsWith("#include ")) { String includeFile = line.substring(9).trim(); + URL nextURL = null; + // Try relative path first - String next = Locator.getRelativeOf(path, includeFile); - URL nextURL = Locator.getResource(next, context); + String next = Locator.getRelativeOf(url, includeFile); + if(null != next) { + nextURL = Locator.getResource(context, next); + } if (nextURL == null) { // Try absolute path - next = includeFile; - nextURL = Locator.getResource(next, context); + nextURL = Locator.getResource(context, includeFile); } if (nextURL == null) { // Fail throw new FileNotFoundException("Can't find include file " + includeFile); } - readShaderSource(context, next, nextURL, result); + if(DEBUG_CODE) { + System.err.println("ShaderCode.readShaderSource<I>: "+url+" + "+includeFile+" := "+nextURL); + } + readShaderSource(context, nextURL, result); } else { result.append(line + "\n"); } @@ -320,16 +321,12 @@ public class ShaderCode { } public static String readShaderSource(Class context, String path) { - ClassLoader contextCL = (null!=context)?context.getClassLoader():null; URL url = Locator.getResource(context, path); if (url == null) { return null; - } - File pf = new File(url.getPath()); - path = pf.getParent() + "/" ; - + } StringBuffer result = new StringBuffer(); - readShaderSource(contextCL, path, url, result); + readShaderSource(context, url, result); return result.toString(); } @@ -354,12 +351,12 @@ public class ShaderCode { protected int shaderBinaryFormat = -1; protected IntBuffer shader = null; protected int shaderType = -1; - protected Integer id = null; + protected int id = -1; protected boolean valid=false; - private static synchronized Integer getNextID() { - return new Integer(nextID++); + private static synchronized int getNextID() { + return nextID++; } protected static int nextID = 1; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java index b6908c1a1..b622571e7 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderProgram.java @@ -30,11 +30,12 @@ package com.jogamp.opengl.util.glsl; import javax.media.opengl.*; -import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.io.PrintStream; public class ShaderProgram { + public ShaderProgram() { id = getNextID(); } @@ -51,16 +52,8 @@ public class ShaderProgram { /** * returns the uniq shader id as an integer - * @see #key() - */ - public int id() { return id.intValue(); } - - /** - * returns the uniq shader id as an Integer - * - * @see #id() */ - public Integer key() { return id; } + public int id() { return id; } /** * Detaches all shader codes and deletes the program. @@ -88,15 +81,18 @@ public class ShaderProgram { * If releaseShaderToo is true, destroys the shader codes as well. */ public synchronized void release(GL2ES2 gl, boolean releaseShaderToo) { - glUseProgram(gl, false); - for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { - ShaderCode shaderCode = (ShaderCode) iter.next(); - ShaderUtil.detachShader(gl, shaderProgram, shaderCode.shader()); + useProgram(gl, false); + for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) { + ShaderCode shaderCode = iter.next(); + if(attachedShaderCode.remove(shaderCode)) { + ShaderUtil.detachShader(gl, shaderProgram, shaderCode.shader()); + } if(releaseShaderToo) { shaderCode.destroy(gl); } } - shaderMap.clear(); + allShaderCode.clear(); + attachedShaderCode.clear(); gl.glDeleteProgram(shaderProgram); shaderProgram=-1; } @@ -106,35 +102,78 @@ public class ShaderProgram { // /** - * Adds a new shader to a this non running program. - * - * @return false if the program is in use, or the shader already exist, - * otherwise true. + * Adds a new shader to this program. + * + * <p>This command does not compile and attach the shader, + * use {@link #add(GL2ES2, ShaderCode)} for this purpose.</p> */ - public synchronized boolean add(ShaderCode shaderCode) { - if(shaderMap.containsKey(shaderCode.key())) return false; - shaderMap.put(shaderCode.key(), shaderCode); - return true; + public synchronized void add(ShaderCode shaderCode) throws GLException { + allShaderCode.add(shaderCode); } + public synchronized boolean contains(ShaderCode shaderCode) { + return allShaderCode.contains(shaderCode); + } + + /** + * Warning slow O(n) operation .. + * @param id + * @return + */ public synchronized ShaderCode getShader(int id) { - return (ShaderCode) shaderMap.get(new Integer(id)); + for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) { + ShaderCode shaderCode = iter.next(); + if(shaderCode.id() == id) { + return shaderCode; + } + } + return null; } // - // Program handling + // ShaderCode / Program handling // /** - * Replace a shader in a 'running' program. - * Refetches all previously bin/get attribute names - * and resets all attribute data as well + * Creates the empty GL program object using {@link GL2ES2#glCreateProgram()} + * + * @param gl + */ + public synchronized final void init(GL2ES2 gl) { + if(0>shaderProgram) { + shaderProgram = gl.glCreateProgram(); + } + } + + /** + * Adds a new shader to a this non running program. + * + * <p>Compiles and attaches the shader, if not done yet.</p> + * + * @return true if the shader was successfully added, false if compilation failed. + */ + public synchronized boolean add(GL2ES2 gl, ShaderCode shaderCode, PrintStream verboseOut) { + init(gl); + if( allShaderCode.add(shaderCode) ) { + if(!shaderCode.compile(gl, verboseOut)) { + return false; + } + if(attachedShaderCode.add(shaderCode)) { + ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader()); + } + } + return true; + } + + /** + * Replace a shader in a program and re-links the program. * * @param gl - * @param oldShaderID the to be replace Shader + * @param oldShader the to be replace Shader * @param newShader the new ShaderCode - * @param verboseOut the optional verbose outputstream - * @throws GLException is the program is not linked + * @param verboseOut the optional verbose output stream + * + * @return true if all steps are valid, shader compilation, attachment and linking; otherwise false. * * @see ShaderState#glEnableVertexAttribArray * @see ShaderState#glDisableVertexAttribArray @@ -145,47 +184,44 @@ public class ShaderProgram { * @see ShaderState#glResetAllVertexAttributes * @see ShaderState#glResetAllVertexAttributes */ - public synchronized boolean glReplaceShader(GL2ES2 gl, int oldShaderID, ShaderCode newShader, PrintStream verboseOut) { - if(!programLinked) throw new GLException("Program is not linked"); - boolean shaderWasInUse = programInUse; - glUseProgram(gl, false); + public synchronized boolean replaceShader(GL2ES2 gl, ShaderCode oldShader, ShaderCode newShader, PrintStream verboseOut) { + init(gl); + if(!newShader.compile(gl, verboseOut)) { return false; - } - if(oldShaderID>=0) { - ShaderCode oldShader = (ShaderCode) shaderMap.remove(new Integer(oldShaderID)); - if(null!=oldShader) { + } + + boolean shaderWasInUse = inUse(); + if(shaderWasInUse) { + useProgram(gl, false); + } + + if(null != oldShader && allShaderCode.remove(oldShader)) { + if(attachedShaderCode.remove(oldShader)) { ShaderUtil.detachShader(gl, shaderProgram, oldShader.shader()); } } + add(newShader); - - ShaderUtil.attachShader(gl, shaderProgram, newShader.shader()); - gl.glLinkProgram(shaderProgram); - if ( ! ShaderUtil.isProgramValid(gl, shaderProgram, System.err) ) { - return false; + if(attachedShaderCode.add(newShader)) { + ShaderUtil.attachShader(gl, shaderProgram, newShader.shader()); } - - if(shaderWasInUse) { - glUseProgram(gl, true); + + gl.glLinkProgram(shaderProgram); + + programLinked = ShaderUtil.isProgramValid(gl, shaderProgram, System.err); + if ( programLinked && shaderWasInUse ) { + useProgram(gl, true); } - return true; + return programLinked; } /** - * Creates the empty GL program object using {@link GL2ES2#glCreateProgram()} - * - * @param gl - */ - public final void init(GL2ES2 gl) { - if(0>shaderProgram) { - shaderProgram = gl.glCreateProgram(); - } - } - - /** - * Compiles and links the shader code to the program. - * Within this process, all GL resources (shader and program objects) are created if necessary. + * Links the shader code to the program. + * + * <p>Compiles and attaches the shader code to the program if not done by yet</p> + * + * <p>Within this process, all GL resources (shader and program objects) are created if necessary.</p> * * @param gl * @param verboseOut @@ -194,18 +230,16 @@ public class ShaderProgram { * @see #init(GL2ES2) */ public synchronized boolean link(GL2ES2 gl, PrintStream verboseOut) { - if(programLinked) throw new GLException("Program is already linked"); + init(gl); - if(0>shaderProgram) { - shaderProgram = gl.glCreateProgram(); - } - - for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { - ShaderCode shaderCode = (ShaderCode) iter.next(); + for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) { + final ShaderCode shaderCode = iter.next(); if(!shaderCode.compile(gl, verboseOut)) { return false; } - ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader()); + if(attachedShaderCode.add(shaderCode)) { + ShaderUtil.attachShader(gl, shaderProgram, shaderCode.shader()); + } } // Link the program @@ -225,40 +259,37 @@ public class ShaderProgram { } public int hashCode() { - return id.intValue(); + return id; } public String toString() { StringBuffer buf = new StringBuffer(); buf.append("ShaderProgram[id="+id); buf.append(", linked="+programLinked+", inUse="+programInUse+", program: "+shaderProgram+", ["); - for(Iterator iter=shaderMap.values().iterator(); iter.hasNext(); ) { - buf.append((ShaderCode) iter.next()); + for(Iterator<ShaderCode> iter=allShaderCode.iterator(); iter.hasNext(); ) { + buf.append(iter.next()); buf.append(" "); } buf.append("]"); return buf.toString(); } - protected synchronized void glUseProgram(GL2ES2 gl, boolean on) { + protected synchronized void useProgram(GL2ES2 gl, boolean on) { if(!programLinked) throw new GLException("Program is not linked"); if(programInUse==on) return; gl.glUseProgram(on?shaderProgram:0); programInUse = on; - - //Throwable tX = new Throwable("Info: ShaderProgram.glUseProgram: "+on); - //tX.printStackTrace(); - } protected boolean programLinked = false; protected boolean programInUse = false; protected int shaderProgram=-1; - protected HashMap shaderMap = new HashMap(); - protected Integer id = null; + protected HashSet<ShaderCode> allShaderCode = new HashSet<ShaderCode>(); + protected HashSet<ShaderCode> attachedShaderCode = new HashSet<ShaderCode>(); + protected int id = -1; - private static synchronized Integer getNextID() { - return new Integer(nextID++); + private static synchronized int getNextID() { + return nextID++; } protected static int nextID = 1; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java index 57ae6cfda..f8fe987d7 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderState.java @@ -28,13 +28,23 @@ package com.jogamp.opengl.util.glsl; -import javax.media.opengl.*; -import jogamp.opengl.Debug; - +import java.security.AccessController; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; -import java.security.*; + +import javax.media.opengl.GL; +import javax.media.opengl.GL2ES2; +import javax.media.opengl.GLArrayData; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLException; +import javax.media.opengl.GLUniformData; + +import jogamp.opengl.Debug; + +import com.jogamp.common.util.IntObjectHashMap; +import com.jogamp.opengl.util.GLArrayDataEditable; public class ShaderState { public static final boolean DEBUG = Debug.isPropertyDefined("jogl.debug.GLSLState", true, AccessController.getContext()); @@ -47,38 +57,107 @@ public class ShaderState { public void setVerbose(boolean v) { verbose=v; } /** - * Fetches the current shader state from the thread local storage (TLS) + * Fetches the current shader state from this thread (TLS) current GLContext * - * @see com.jogamp.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) - * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrent() + * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean) + * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL) + * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState() */ - public static synchronized ShaderState getCurrent() { - GLContext current = GLContext.getCurrent(); - if(null==current) { - throw new GLException("No context is current on this thread"); - } - return (ShaderState) current.getAttachedObject(ShaderState.class.getName()); + public static synchronized ShaderState getCurrentShaderState() { + return getShaderState(GLContext.getCurrentGL()); + } + + /** + * Fetches the shader state from the GL object's GLContext + * + * @param gl the GL object referencing the GLContext + * + * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean) + * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL) + * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState() + */ + public static synchronized ShaderState getShaderState(GL gl) { + return (ShaderState) gl.getContext().getAttachedObject(ShaderState.class.getName()); + } + + /** + * Returns the attached user object for the given name to this ShaderState. + */ + public final Object getAttachedObject(String name) { + return attachedObjectsByString.get(name); } /** + * Attach user object for the given name to this ShaderState. + * Returns the previously set object or null. + * + * @return the previous mapped object or null if none + */ + public final Object attachObject(String name, Object obj) { + return attachedObjectsByString.put(name, obj); + } + + /** + * @param name name of the mapped object to detach + * + * @return the previous mapped object or null if none + */ + public final Object detachObject(String name) { + return attachedObjectsByString.remove(name); + } + + /** + * Returns the attached user object for the given name to this ShaderState. + */ + public final Object getAttachedObject(int name) { + return attachedObjectsByInt.get(name); + } + + /** + * Attach user object for the given name to this ShaderState. + * Returns the previously set object or null. + */ + public final Object attachObject(int name, Object obj) { + return attachedObjectsByInt.put(name, obj); + } + + public final Object detachObject(int name) { + return attachedObjectsByInt.remove(name); + } + + /** * Turns the shader program on or off.<br> * Puts this ShaderState to to the thread local storage (TLS), * if <code>on</code> is <code>true</code>. * - * @see com.jogamp.opengl.util.glsl.ShaderState#glUseProgram(GL2ES2, boolean) - * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrent() + * @throws GLException if no program is attached + * + * @see com.jogamp.opengl.util.glsl.ShaderState#useProgram(GL2ES2, boolean) + * @see com.jogamp.opengl.util.glsl.ShaderState#getShaderState(GL) + * @see com.jogamp.opengl.util.glsl.ShaderState#getCurrentShaderState() */ - public synchronized void glUseProgram(GL2ES2 gl, boolean on) { + public synchronized void useProgram(GL2ES2 gl, boolean on) throws GLException { + if(null==shaderProgram) { throw new GLException("No program is attached"); } if(on) { - if(null!=shaderProgram) { - shaderProgram.glUseProgram(gl, true); - } else { - throw new GLException("No program is attached"); - } // update the current ShaderState to the TLS .. - gl.getContext().putAttachedObject(ShaderState.class.getName(), this); - } else if(null!=shaderProgram) { - shaderProgram.glUseProgram(gl, false); + gl.getContext().attachObject(ShaderState.class.getName(), this); + if(shaderProgram.linked()) { + shaderProgram.useProgram(gl, true); + if(resetAllShaderData) { + resetAllAttributes(gl); + resetAllUniforms(gl); + } + } else if(resetAllShaderData) { + setAllAttributes(gl); + if(!shaderProgram.link(gl, System.err)) { + throw new GLException("could not link program: "+shaderProgram); + } + shaderProgram.useProgram(gl, true); + resetAllUniforms(gl); + } + resetAllShaderData = false; + } else { + shaderProgram.useProgram(gl, false); } } @@ -93,11 +172,16 @@ public class ShaderState { /** * Attach or switch a shader program * - * Attaching a shader program the first time, + * <p>Attaching a shader program the first time, * as well as switching to another program on the fly, - * while managing all attribute and uniform data. + * while managing all attribute and uniform data.</p> + * + * <p>[Re]sets all data and use program in case of a program switch.<br> + * Use program if linked in case of a 1st time attachment.</p> + * + * @throws GLException if program was not linked and linking fails */ - public synchronized void attachShaderProgram(GL2ES2 gl, ShaderProgram prog) { + public synchronized void attachShaderProgram(GL2ES2 gl, ShaderProgram prog) throws GLException { boolean prgInUse = false; // earmarked state if(DEBUG) { @@ -118,19 +202,21 @@ public class ShaderState { return; } prgInUse = shaderProgram.inUse(); - shaderProgram.glUseProgram(gl, false); + useProgram(gl, false); + resetAllShaderData = true; } // register new one shaderProgram = prog; if(null!=shaderProgram) { - // reinstall all data .. - shaderProgram.glUseProgram(gl, true); - glResetAllVertexAttributes(gl); - glResetAllUniforms(gl); - if(!prgInUse) { - shaderProgram.glUseProgram(gl, false); + // [re]set all data and use program if switching program, + // or use program if program is linked + if(shaderProgram.linked() || resetAllShaderData) { + useProgram(gl, true); + if(!prgInUse) { + shaderProgram.useProgram(gl, false); + } } } if(DEBUG) { @@ -141,25 +227,27 @@ public class ShaderState { public ShaderProgram shaderProgram() { return shaderProgram; } /** - * Calls release(gl, true, true) + * Calls {@link #release(GL2ES2, boolean, boolean, boolean) release(gl, true, true, true)} * * @see #glReleaseAllVertexAttributes * @see #glReleaseAllUniforms - * @see #release(GL2ES2, boolean, boolean) + * @see #release(GL2ES2, boolean, boolean, boolean) */ public synchronized void destroy(GL2ES2 gl) { - release(gl, true, true); + release(gl, true, true, true); + attachedObjectsByString.clear(); + attachedObjectsByInt.clear(); } /** - * Calls release(gl, false, false) + * Calls {@link #release(GL2ES2, boolean, boolean, boolean) release(gl, false, false, false)} * * @see #glReleaseAllVertexAttributes * @see #glReleaseAllUniforms - * @see #release(GL2ES2, boolean, boolean) + * @see #release(GL2ES2, boolean, boolean, boolean) */ public synchronized void releaseAllData(GL2ES2 gl) { - release(gl, false, false); + release(gl, false, false, false); } /** @@ -167,22 +255,21 @@ public class ShaderState { * @see #glReleaseAllUniforms * @see ShaderProgram#release(GL2ES2, boolean) */ - public synchronized void release(GL2ES2 gl, boolean releaseProgramToo, boolean releaseShaderToo) { - boolean prgInUse = false; - if(null!=shaderProgram) { - prgInUse = shaderProgram.inUse(); - if(!prgInUse) { - shaderProgram.glUseProgram(gl, true); - } + public synchronized void release(GL2ES2 gl, boolean destroyBoundAttributes, boolean releaseProgramToo, boolean releaseShaderToo) { + if(null!=shaderProgram) { + shaderProgram.useProgram(gl, false); } - glReleaseAllVertexAttributes(gl); - glReleaseAllUniforms(gl); + if(destroyBoundAttributes) { + for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) { + iter.next().destroy(gl); + } + } + releaseAllAttributes(gl); + releaseAllUniforms(gl); if(null!=shaderProgram) { if(releaseProgramToo) { shaderProgram.release(gl, releaseShaderToo); - } else if(!prgInUse) { - shaderProgram.glUseProgram(gl, false); - } + } } } @@ -191,226 +278,379 @@ public class ShaderState { // /** - * Binds an attribute to the shader. - * This must be done before the program is linked ! - * n name - 1 idx, where name is a uniq key + * Gets the cached location of a shader attribute. + * + * @return -1 if there is no such attribute available, + * otherwise >= 0 + * + * @see #bindAttribLocation(GL2ES2, int, String) + * @see #bindAttribLocation(GL2ES2, int, GLArrayData) + * @see #getAttribLocation(GL2ES2, String) + * @see GL2ES2#glGetAttribLocation(int, String) + */ + public int getAttribLocation(String name) { + Integer idx = (Integer) activeAttribLocationMap.get(name); + return (null!=idx)?idx.intValue():-1; + } + + /** + * Get the previous cached vertex attribute data. * - * @throws GLException is the program is already linked + * @return the GLArrayData object, null if not previously set. + * + * @see #ownAttribute(GLArrayData, boolean) * - * @see #glBindAttribLocation - * @see javax.media.opengl.GL2ES2#glBindAttribLocation - * @see #glGetAttribLocation - * @see javax.media.opengl.GL2ES2#glGetAttribLocation - * @see #getAttribLocation + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttribPointer + * @see #glReleaseAllVertexAttributes + * @see #glResetAllVertexAttributes * @see ShaderProgram#glReplaceShader */ - public void glBindAttribLocation(GL2ES2 gl, int index, String name) { - if(null==shaderProgram) throw new GLException("No program is attached"); - if(shaderProgram.linked()) throw new GLException("Program is already linked"); - Integer idx = new Integer(index); - if(!attribMap2Idx.containsKey(name)) { - attribMap2Idx.put(name, idx); - gl.glBindAttribLocation(shaderProgram.program(), index, name); + public GLArrayData getAttribute(String name) { + return (GLArrayData) activeAttribDataMap.get(name); + } + + /** + * Binds or unbinds the {@link GLArrayData} lifecycle to this ShaderState. + * + * <p>If an attribute location is cached (ie {@link #bindAttribLocation(GL2ES2, int, String)}) + * it is promoted to the {@link GLArrayData} instance.</p> + * + * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)} + * and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p> + * + * <p>The data will not be transfered to the GPU, use {@link #vertexAttribPointer(GL2ES2, GLArrayData)} additionally.</p> + * + * @param attribute the {@link GLArrayData} which lifecycle shall be managed + * @param own true if <i>owning</i> shall be performs, false if <i>disowning</i>. + * + * @see #bindAttribLocation(GL2ES2, int, String) + * @see #getAttribute(String) + */ + public void ownAttribute(GLArrayData attribute, boolean own) { + if(own) { + final int location = getAttribLocation(attribute.getName()); + if(0<=location) { + attribute.setLocation(location); + } + managedAttributes.add(managedAttributes.size(), attribute); + } else { + managedAttributes.remove(attribute); } } + + public boolean ownsAttribute(GLArrayData attribute) { + return managedAttributes.contains(attribute); + } + + /** + * Binds a shader attribute to a location. + * Multiple names can be bound to one location. + * The value will be cached and can be retrieved via {@link #getAttribLocation(String)} + * before or after linking. + * + * @throws GLException if no program is attached + * @throws GLException if the program is already linked + * + * @see javax.media.opengl.GL2ES2#glBindAttribLocation(int, int, String) + * @see #getAttribLocation(GL2ES2, String) + * @see #getAttribLocation(String) + */ + public void bindAttribLocation(GL2ES2 gl, int location, String name) { + if(null==shaderProgram) throw new GLException("No program is attached"); + if(shaderProgram.linked()) throw new GLException("Program is already linked"); + final Integer loc = new Integer(location); + activeAttribLocationMap.put(name, loc); + gl.glBindAttribLocation(shaderProgram.program(), location, name); + } + + /** + * Binds a shader {@link GLArrayData} attribute to a location. + * Multiple names can be bound to one location. + * The value will be cached and can be retrieved via {@link #getAttribLocation(String)} + * and {@link #getAttribute(String)}before or after linking. + * The {@link GLArrayData}'s location will be set as well. + * + * @throws GLException if no program is attached + * @throws GLException if the program is already linked + * + * @see javax.media.opengl.GL2ES2#glBindAttribLocation(int, int, String) + * @see #getAttribLocation(GL2ES2, String) + * @see #getAttribLocation(String) + * @see #getAttribute(String) + */ + public void bindAttribLocation(GL2ES2 gl, int location, GLArrayData data) { + bindAttribLocation(gl, location, data.getName()); + data.setLocation(location); + activeAttribDataMap.put(data.getName(), data); + } /** - * Gets the index of a shader attribute. - * This must be done after the program is linked ! + * Gets the location of a shader attribute, + * either the cached value {@link #getAttribLocation(String)} if valid or + * the retrieved one {@link GL2ES2#glGetAttribLocation(int, String)}. + * In the latter case the value will be cached. * * @return -1 if there is no such attribute available, * otherwise >= 0 - * @throws GLException is the program is not linked + * @throws GLException if no program is attached + * @throws GLException if the program is not linked and no location was cached. * - * @see #glBindAttribLocation - * @see javax.media.opengl.GL2ES2#glBindAttribLocation - * @see #glGetAttribLocation - * @see javax.media.opengl.GL2ES2#glGetAttribLocation - * @see #getAttribLocation - * @see ShaderProgram#glReplaceShader + * @see #getAttribLocation(String) + * @see #bindAttribLocation(GL2ES2, int, GLArrayData) + * @see #bindAttribLocation(GL2ES2, int, String) + * @see GL2ES2#glGetAttribLocation(int, String) */ - public int glGetAttribLocation(GL2ES2 gl, String name) { - if(!shaderProgram.linked()) throw new GLException("Program is not linked"); - int index = getAttribLocation(name); - if(0>index) { - index = gl.glGetAttribLocation(shaderProgram.program(), name); - if(0<=index) { - Integer idx = new Integer(index); - attribMap2Idx.put(name, idx); + public int getAttribLocation(GL2ES2 gl, String name) { + if(null==shaderProgram) throw new GLException("No program is attached"); + int location = getAttribLocation(name); + if(0>location) { + if(!shaderProgram.linked()) throw new GLException("Program is not linked"); + location = gl.glGetAttribLocation(shaderProgram.program(), name); + if(0<=location) { + Integer idx = new Integer(location); + activeAttribLocationMap.put(name, idx); if(DEBUG) { - System.err.println("Info: glGetAttribLocation: "+name+", loc: "+index); + System.err.println("Info: glGetAttribLocation: "+name+", loc: "+location); } } else if(verbose) { - Throwable tX = new Throwable("Info: glGetAttribLocation failed, no location for: "+name+", index: "+index); + Throwable tX = new Throwable("Info: glGetAttribLocation failed, no location for: "+name+", loc: "+location); tX.printStackTrace(); } } - return index; + return location; } - protected int getAttribLocation(String name) { - Integer idx = (Integer) attribMap2Idx.get(name); - return (null!=idx)?idx.intValue():-1; + /** + * Gets the location of a shader attribute, + * either the cached value {@link #getAttribLocation(String)} if valid or + * the retrieved one {@link GL2ES2#glGetAttribLocation(int, String)}. + * In the latter case the value will be cached. + * The {@link GLArrayData}'s location will be set as well. + * + * @return -1 if there is no such attribute available, + * otherwise >= 0 + * + * @throws GLException if no program is attached + * @throws GLException if the program is not linked and no location was cached. + * + * @see #getAttribLocation(String) + * @see #bindAttribLocation(GL2ES2, int, GLArrayData) + * @see #bindAttribLocation(GL2ES2, int, String) + * @see GL2ES2#glGetAttribLocation(int, String) + * @see #getAttribute(String) + */ + public int getAttribLocation(GL2ES2 gl, GLArrayData data) { + int location = getAttribLocation(gl, data.getName()); + data.setLocation(location); + activeAttribDataMap.put(data.getName(), data); + return location; } - - + // // Enabled Vertex Arrays and its data // /** - * Enable a vertex attribute array + * @return true if the named attribute is enable + */ + public final boolean isVertexAttribArrayEnabled(String name) { + return enabledAttributes.contains(name); + } + + /** + * @return true if the {@link GLArrayData} attribute is enable + */ + public final boolean isVertexAttribArrayEnabled(GLArrayData data) { + return isVertexAttribArrayEnabled(data.getName()); + } + + private boolean enableVertexAttribArray(GL2ES2 gl, String name, int location) { + enabledAttributes.add(name); + if(0>location) { + location = getAttribLocation(gl, name); + if(0>location) { + if(verbose) { + Throwable tX = new Throwable("Info: glEnableVertexAttribArray failed, no index for: "+name); + tX.printStackTrace(); + } + return false; + } + } + if(DEBUG) { + System.err.println("Info: glEnableVertexAttribArray: "+name+", loc: "+location); + } + gl.glEnableVertexAttribArray(location); + return true; + } + + /** + * Enables a vertex attribute array. + * + * This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)} + * hence {@link #enableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred. * * Even if the attribute is not found in the current shader, - * it is stored in this state. + * it is marked enabled in this state. * * @return false, if the name is not found, otherwise true * - * @throws GLException if the program is not in use - * + * @throws GLException if the program is not linked and no location was cached. + * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer * @see #getVertexAttribPointer - * @see #glReleaseAllVertexAttributes - * @see #glResetAllVertexAttributes - * @see ShaderProgram#glReplaceShader */ - public boolean glEnableVertexAttribArray(GL2ES2 gl, String name) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - enabledVertexAttribArraySet.add(name); - int index = glGetAttribLocation(gl, name); - if(0>index) { - if(verbose) { - Throwable tX = new Throwable("Info: glEnableVertexAttribArray failed, no index for: "+name); - tX.printStackTrace(); - } - return false; - } - if(DEBUG) { - System.err.println("Info: glEnableVertexAttribArray: "+name+", loc: "+index); - } - gl.glEnableVertexAttribArray(index); - return true; - } - - public boolean isVertexAttribArrayEnabled(String name) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - return enabledVertexAttribArraySet.contains(name); + public boolean enableVertexAttribArray(GL2ES2 gl, String name) { + return enableVertexAttribArray(gl, name, -1); } + /** - * Disables a vertex attribute array + * Enables a vertex attribute array, usually invoked by {@link GLArrayDataEditable#enableBuffer(GL, boolean)}. * + * This method uses the {@link GLArrayData}'s location if set + * and is the preferred alternative to {@link #enableVertexAttribArray(GL2ES2, String)}. + * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set + * and cached in this state. + * * Even if the attribute is not found in the current shader, - * it is removed from this state. + * it is marked enabled in this state. * * @return false, if the name is not found, otherwise true * - * @throws GLException if the program is not in use + * @throws GLException if the program is not linked and no location was cached. * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer * @see #getVertexAttribPointer - * @see #glReleaseAllVertexAttributes - * @see #glResetAllVertexAttributes - * @see ShaderProgram#glReplaceShader + * @see GLArrayDataEditable#enableBuffer(GL, boolean) */ - public boolean glDisableVertexAttribArray(GL2ES2 gl, String name) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - enabledVertexAttribArraySet.remove(name); - int index = glGetAttribLocation(gl, name); - if(0>index) { - if(verbose) { - Throwable tX = new Throwable("Info: glDisableVertexAttribArray failed, no index for: "+name); - tX.printStackTrace(); + public boolean enableVertexAttribArray(GL2ES2 gl, GLArrayData data) { + if(0 > data.getLocation()) { + getAttribLocation(gl, data); + } else { + // ensure data is the current bound one + activeAttribDataMap.put(data.getName(), data); + } + return enableVertexAttribArray(gl, data.getName(), data.getLocation()); + } + + private boolean disableVertexAttribArray(GL2ES2 gl, String name, int location) { + enabledAttributes.remove(name); + if(0>location) { + location = getAttribLocation(gl, name); + if(0>location) { + if(verbose) { + Throwable tX = new Throwable("Info: glDisableVertexAttribArray failed, no index for: "+name); + tX.printStackTrace(); + } + return false; } - return false; } if(DEBUG) { System.err.println("Info: glDisableVertexAttribArray: "+name); } - gl.glDisableVertexAttribArray(index); + gl.glDisableVertexAttribArray(location); return true; } - + /** - * Set the vertex attribute data. - * Enable the attribute, if it is not enabled yet. + * Disables a vertex attribute array * + * This method retrieves the the location via {@link #getAttribLocation(GL2ES2, GLArrayData)} + * hence {@link #disableVertexAttribArray(GL2ES2, GLArrayData)} shall be preferred. + * * Even if the attribute is not found in the current shader, - * it is stored in this state. - * - * @param data the GLArrayData's name must match the attributes one, - * it's index will be set with the attribute's location, - * if found. + * it is removed from this state enabled list. * * @return false, if the name is not found, otherwise true * - * @throws GLException if the program is not in use + * @throws GLException if no program is attached + * @throws GLException if the program is not linked and no location was cached. * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer * @see #getVertexAttribPointer - * @see #glReleaseAllVertexAttributes - * @see #glResetAllVertexAttributes - * @see ShaderProgram#glReplaceShader */ - public boolean glVertexAttribPointer(GL2ES2 gl, GLArrayData data) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - if(!enabledVertexAttribArraySet.contains(data.getName())) { - if(!glEnableVertexAttribArray(gl, data.getName())) { - if(verbose) { - Throwable tX = new Throwable("Info: glVertexAttribPointer: couldn't enable: "+data); - tX.printStackTrace(); - } - } - } - int index = getAttribLocation(data.getName()); - if(0>index) { - if(verbose) { - Throwable tX = new Throwable("Info: glVertexAttribPointer failed, no index for: "+data); - tX.printStackTrace(); - } - } - data.setLocation(index); - vertexAttribMap2Data.put(data.getName(), data); - if(0<=index) { - // only pass the data, if the attribute exists in the current shader - if(DEBUG) { - System.err.println("Info: glVertexAttribPointer: "+data); - } - gl.glVertexAttribPointer(data); - return true; - } - return false; + public boolean disableVertexAttribArray(GL2ES2 gl, String name) { + return disableVertexAttribArray(gl, name, -1); } /** - * Get the vertex attribute data, previously set. + * Disables a vertex attribute array * - * @return the GLArrayData object, null if not previously set. + * This method uses the {@link GLArrayData}'s location if set + * and is the preferred alternative to {@link #disableVertexAttribArray(GL2ES2, String)}. + * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)} set + * and cached in this state. + * + * Even if the attribute is not found in the current shader, + * it is removed from this state enabled list. + * + * @return false, if the name is not found, otherwise true + * + * @throws GLException if no program is attached + * @throws GLException if the program is not linked and no location was cached. * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer * @see #getVertexAttribPointer - * @see #glReleaseAllVertexAttributes - * @see #glResetAllVertexAttributes - * @see ShaderProgram#glReplaceShader */ - public GLArrayData getVertexAttribPointer(String name) { - return (GLArrayData) vertexAttribMap2Data.get(name); + public boolean disableVertexAttribArray(GL2ES2 gl, GLArrayData data) { + if(0 > data.getLocation()) { + getAttribLocation(gl, data); + } + return disableVertexAttribArray(gl, data.getName(), data.getLocation()); + } + + /** + * Set the {@link GLArrayData} vertex attribute data. + * + * This method uses the {@link GLArrayData}'s location if set. + * If data location is unset it will be retrieved via {@link #getAttribLocation(GL2ES2, GLArrayData)}, set + * and cached in this state. + * + * @return false, if the location could not be determined, otherwise true + * + * @throws GLException if no program is attached + * @throws GLException if the program is not linked and no location was cached. + * + * @see #glEnableVertexAttribArray + * @see #glDisableVertexAttribArray + * @see #glVertexAttribPointer + * @see #getVertexAttribPointer + */ + public boolean vertexAttribPointer(GL2ES2 gl, GLArrayData data) { + int location = data.getLocation(); + if(0 > location) { + location = getAttribLocation(gl, data); + } /* else { + done via enable .. + // ensure data is the current bound one + activeAttribDataMap.put(data.getName(), data); + } */ + if(0 <= location) { + // only pass the data, if the attribute exists in the current shader + if(DEBUG) { + System.err.println("Info: glVertexAttribPointer: "+data); + } + gl.glVertexAttribPointer(data); + return true; + } + return false; } /** * Releases all mapped vertex attribute data, * disables all enabled attributes and loses all indices * - * @throws GLException is the program is not in use but the shaderProgram is set - * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer @@ -420,23 +660,23 @@ public class ShaderState { * @see #glResetAllVertexAttributes * @see ShaderProgram#glReplaceShader */ - public void glReleaseAllVertexAttributes(GL2ES2 gl) { + public void releaseAllAttributes(GL2ES2 gl) { if(null!=shaderProgram) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - for(Iterator iter = vertexAttribMap2Data.keySet().iterator(); iter.hasNext(); ) { - if(!glDisableVertexAttribArray(gl, (String) iter.next())) { + for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) { + if(!disableVertexAttribArray(gl, iter.next())) { throw new GLException("Internal Error: mapped vertex attribute couldn't be disabled"); } } - for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { - if(!glDisableVertexAttribArray(gl, (String) iter.next())) { + for(Iterator<String> iter = enabledAttributes.iterator(); iter.hasNext(); ) { + if(!disableVertexAttribArray(gl, iter.next())) { throw new GLException("Internal Error: prev enabled vertex attribute couldn't be disabled"); } } } - vertexAttribMap2Data.clear(); - enabledVertexAttribArraySet.clear(); - attribMap2Idx.clear(); + activeAttribDataMap.clear(); + enabledAttributes.clear(); + activeAttribLocationMap.clear(); + managedAttributes.clear(); } /** @@ -447,8 +687,6 @@ public class ShaderState { * * This method purpose is more for debugging. * - * @throws GLException is the program is not in use but the shaderProgram is set - * * @see #glEnableVertexAttribArray * @see #glDisableVertexAttribArray * @see #glVertexAttribPointer @@ -458,73 +696,92 @@ public class ShaderState { * @see #glResetAllVertexAttributes * @see ShaderProgram#glReplaceShader */ - public void glDisableAllVertexAttributeArrays(GL2ES2 gl, boolean removeFromState) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - - for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { - String name = (String) iter.next(); + public void disableAllVertexAttributeArrays(GL2ES2 gl, boolean removeFromState) { + for(Iterator<String> iter = enabledAttributes.iterator(); iter.hasNext(); ) { + String name = iter.next(); if(removeFromState) { - enabledVertexAttribArraySet.remove(name); + enabledAttributes.remove(name); } - int index = glGetAttribLocation(gl, name); + int index = getAttribLocation(gl, name); if(0<=index) { gl.glDisableVertexAttribArray(index); } } } + private final void relocateAttribute(GL2ES2 gl, GLArrayData attribute) { + // get new location .. + String name = attribute.getName(); + int loc = getAttribLocation(gl, name); + attribute.setLocation(loc); + + if(0<=loc) { + if(enabledAttributes.contains(name)) { + // enable attrib, VBO and pass location/data + gl.glEnableVertexAttribArray(loc); + } + + if( attribute.isVBO() ) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName()); + } + + gl.glVertexAttribPointer(attribute); + } + } + /** - * Reset all previously enabled mapped vertex attribute data, - * incl enabling them + * Reset all previously enabled mapped vertex attribute data. + * + * <p>Attribute data is bound to the GL state</p> + * <p>Attribute location is bound to the program</p> + * + * <p>However, since binding an attribute to a location via {@link #bindAttribLocation(GL2ES2, int, GLArrayData)} + * <i>must</i> happen before linking <b>and</b> we try to promote the attributes to the new program, + * we have to gather the probably new location etc.</p> * - * @throws GLException is the program is not in use + * @throws GLException is the program is not linked * - * @see #glEnableVertexAttribArray - * @see #glDisableVertexAttribArray - * @see #glVertexAttribPointer - * @see #getVertexAttribPointer - * @see #glReleaseAllVertexAttributes - * @see #glResetAllVertexAttributes - * @see ShaderProgram#glReplaceShader + * @see #attachShaderProgram(GL2ES2, ShaderProgram) */ - public void glResetAllVertexAttributes(GL2ES2 gl) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - attribMap2Idx.clear(); - - /** - * - for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { - glEnableVertexAttribArray(gl, (String) iter.next()); + private final void resetAllAttributes(GL2ES2 gl) { + if(!shaderProgram.linked()) throw new GLException("Program is not linked"); + activeAttribLocationMap.clear(); + + for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) { + iter.next().setLocation(-1); } - for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) { - GLArrayData data = (GLArrayData) iter.next(); - - ... - } */ - - for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { - // get new location .. - String name = (String) iter.next(); - int loc = glGetAttribLocation(gl, name); - - // get & update data .. - GLArrayData data = getVertexAttribPointer(name); - data.setLocation(loc); - vertexAttribMap2Data.put(name, data); + for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) { + relocateAttribute(gl, iter.next()); + } + } - if(0>loc) { - // not used in shader - continue; + private final void setAttribute(GL2ES2 gl, GLArrayData attribute) { + // get new location .. + final String name = attribute.getName(); + final int loc = attribute.getLocation(); + + if(0<=loc) { + this.bindAttribLocation(gl, loc, name); + + if(enabledAttributes.contains(name)) { + // enable attrib, VBO and pass location/data + gl.glEnableVertexAttribArray(loc); } - - // enable attrib, VBO and pass location/data - gl.glEnableVertexAttribArray(loc); - - if( data.isVBO() ) { - gl.glBindBuffer(GL.GL_ARRAY_BUFFER, data.getVBOName()); + + if( attribute.isVBO() ) { + gl.glBindBuffer(GL.GL_ARRAY_BUFFER, attribute.getVBOName()); } - - gl.glVertexAttribPointer(data); + + gl.glVertexAttribPointer(attribute); + } + } + + /** + * preserves the attribute location .. (program not linked) + */ + private final void setAllAttributes(GL2ES2 gl) { + for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) { + setAttribute(gl, iter.next()); } } @@ -533,6 +790,33 @@ public class ShaderState { // /** + * Bind the {@link GLUniform} lifecycle to this ShaderState. + * + * <p>If a uniform location is cached it is promoted to the {@link GLUniformData} instance.</p> + * + * <p>The attribute will be destroyed with {@link #destroy(GL2ES2)} + * and it's location will be reset when switching shader with {@link #attachShaderProgram(GL2ES2, ShaderProgram)}.</p> + * + * <p>The data will not be transfered to the GPU, use {@link #uniform(GL2ES2, GLUniformData)} additionally.</p> + * + * @param uniform the {@link GLUniformData} which lifecycle shall be managed + * + * @see #getUniform(String) + */ + public void ownUniform(GLUniformData uniform) { + final int location = getUniformLocation(uniform.getName()); + if(0<=location) { + uniform.setLocation(location); + } + activeUniformDataMap.put(uniform.getName(), uniform); + managedUniforms.add(uniform); + } + + public boolean ownsUniform(GLUniformData uniform) { + return managedUniforms.contains(uniform); + } + + /** * Gets the index of a shader uniform. * This must be done when the program is in use ! * @@ -546,24 +830,24 @@ public class ShaderState { * @see #getUniformLocation * @see ShaderProgram#glReplaceShader */ - protected int glGetUniformLocation(GL2ES2 gl, String name) { + protected final int getUniformLocation(GL2ES2 gl, String name) { if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - int index = getUniformLocation(name); - if(0>index) { - index = gl.glGetUniformLocation(shaderProgram.program(), name); - if(0<=index) { - Integer idx = new Integer(index); - uniformMap2Idx.put(name, idx); + int location = getUniformLocation(name); + if(0>location) { + location = gl.glGetUniformLocation(shaderProgram.program(), name); + if(0<=location) { + Integer idx = new Integer(location); + activeUniformLocationMap.put(name, idx); } else if(verbose) { - Throwable tX = new Throwable("Info: glUniform failed, no location for: "+name+", index: "+index); + Throwable tX = new Throwable("Info: glUniform failed, no location for: "+name+", index: "+location); tX.printStackTrace(); } } - return index; + return location; } - protected int getUniformLocation(String name) { - Integer idx = (Integer) uniformMap2Idx.get(name); + protected final int getUniformLocation(String name) { + Integer idx = (Integer) activeUniformLocationMap.get(name); return (null!=idx)?idx.intValue():-1; } @@ -587,11 +871,14 @@ public class ShaderState { * @see #getUniformLocation * @see ShaderProgram#glReplaceShader */ - public boolean glUniform(GL2ES2 gl, GLUniformData data) { + public boolean uniform(GL2ES2 gl, GLUniformData data) { if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - int location = glGetUniformLocation(gl, data.getName()); - data.setLocation(location); - uniformMap2Data.put(data.getName(), data); + int location = data.getLocation(); + if(0>location) { + location = getUniformLocation(gl, data.getName()); + data.setLocation(location); + } + activeUniformDataMap.put(data.getName(), data); if(0<=location) { // only pass the data, if the uniform exists in the current shader if(DEBUG) { @@ -608,69 +895,97 @@ public class ShaderState { * @return the GLUniformData object, null if not previously set. */ public GLUniformData getUniform(String name) { - return (GLUniformData) uniformMap2Data.get(name); + return activeUniformDataMap.get(name); } /** * Releases all mapped uniform data * and loses all indices - * - * @throws GLException is the program is not in use */ - public void glReleaseAllUniforms(GL2ES2 gl) { - uniformMap2Data.clear(); - uniformMap2Idx.clear(); + public void releaseAllUniforms(GL2ES2 gl) { + activeUniformDataMap.clear(); + activeUniformLocationMap.clear(); + managedUniforms.clear(); } /** * Reset all previously mapped uniform data + * + * Uniform data and location is bound to the program, + * hence both are updated here * * @throws GLException is the program is not in use + * + * @see #attachShaderProgram(GL2ES2, ShaderProgram) */ - public void glResetAllUniforms(GL2ES2 gl) { - if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); - uniformMap2Idx.clear(); - for(Iterator iter = uniformMap2Data.values().iterator(); iter.hasNext(); ) { - glUniform(gl, (GLUniformData) iter.next()); + private final void resetAllUniforms(GL2ES2 gl) { + if(!shaderProgram.inUse()) throw new GLException("Program is not in use"); + activeUniformLocationMap.clear(); + for(Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) { + iter.next().setLocation(-1); + } + for(Iterator<GLUniformData> iter = activeUniformDataMap.values().iterator(); iter.hasNext(); ) { + final GLUniformData uniform = iter.next(); + uniform.setLocation(-1); + uniform(gl, uniform); } } - public String toString() { - StringBuffer buf = new StringBuffer(); - buf.append("ShaderState["); - buf.append(shaderProgram.toString()); - buf.append(",EnabledStates: ["); - for(Iterator iter = enabledVertexAttribArraySet.iterator(); iter.hasNext(); ) { - buf.append("\n "); - buf.append((String)iter.next()); - } - buf.append("], ["); - for(Iterator iter = vertexAttribMap2Data.values().iterator(); iter.hasNext(); ) { - GLArrayData data = (GLArrayData) iter.next(); - if(data.getLocation()>=0) { - buf.append("\n "); - buf.append(data); - } + public StringBuilder toString(StringBuilder sb) { + if(null==sb) { + sb = new StringBuilder(); } - buf.append("], ["); - for(Iterator iter=uniformMap2Data.values().iterator(); iter.hasNext(); ) { - GLUniformData data = (GLUniformData) iter.next(); - if(data.getLocation()>=0) { - buf.append("\n "); - buf.append(data); - } + + sb.append("ShaderState["); + sb.append(shaderProgram.toString()); + sb.append(", enabledAttributes: ["); + for(Iterator<String> iter = enabledAttributes.iterator(); iter.hasNext(); ) { + sb.append("\n "); + sb.append((String)iter.next()); + } + sb.append("], activeAttributes ["); + for(Iterator<GLArrayData> iter = activeAttribDataMap.values().iterator(); iter.hasNext(); ) { + sb.append("\n "); + sb.append(iter.next()); } - buf.append("]"); - return buf.toString(); + sb.append("], managedAttributes ["); + for(Iterator<GLArrayData> iter = managedAttributes.iterator(); iter.hasNext(); ) { + sb.append("\n "); + sb.append(iter.next()); + } + sb.append("], activeUniforms ["); + for(Iterator<GLUniformData> iter=activeUniformDataMap.values().iterator(); iter.hasNext(); ) { + sb.append("\n "); + sb.append(iter.next()); + } + sb.append("], managedUniforms ["); + for(Iterator<GLUniformData> iter = managedUniforms.iterator(); iter.hasNext(); ) { + sb.append("\n "); + sb.append(iter.next()); + } + sb.append("]"); + return sb; } - - protected boolean verbose = false; - protected ShaderProgram shaderProgram=null; - protected HashMap attribMap2Idx = new HashMap(); - protected HashSet enabledVertexAttribArraySet = new HashSet(); - protected HashMap vertexAttribMap2Data = new HashMap(); - protected HashMap uniformMap2Idx = new HashMap(); - protected HashMap uniformMap2Data = new HashMap(); - + + @Override + public String toString() { + return toString(null).toString(); + } + + private boolean verbose = false; + private ShaderProgram shaderProgram=null; + + private HashSet<String> enabledAttributes = new HashSet<String>(); + private HashMap<String, Integer> activeAttribLocationMap = new HashMap<String, Integer>(); + private HashMap<String, GLArrayData> activeAttribDataMap = new HashMap<String, GLArrayData>(); + private ArrayList<GLArrayData> managedAttributes = new ArrayList<GLArrayData>(); + + private HashMap<String, Integer> activeUniformLocationMap = new HashMap<String, Integer>(); + private HashMap<String, GLUniformData> activeUniformDataMap = new HashMap<String, GLUniformData>(); + private ArrayList<GLUniformData> managedUniforms = new ArrayList<GLUniformData>(); + + private HashMap<String, Object> attachedObjectsByString = new HashMap<String, Object>(); + private IntObjectHashMap attachedObjectsByInt = new IntObjectHashMap(); + private boolean resetAllShaderData = false; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java index c7e845953..c81e1f961 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java +++ b/src/jogl/classes/com/jogamp/opengl/util/glsl/ShaderUtil.java @@ -51,7 +51,7 @@ public class ShaderUtil { public abstract boolean isProgramValid(GL gl, int programObj); public abstract boolean isProgramValid(GL gl, int programObj, PrintStream verboseOut); public abstract void createShader(GL gl, int type, IntBuffer shaders); - public abstract Set getShaderBinaryFormats(GL gl); + public abstract Set<Integer> getShaderBinaryFormats(GL gl); public abstract boolean isShaderCompilerAvailable(GL gl); public abstract void shaderSource(GL gl, int shader, java.lang.String[] source); public abstract void shaderSource(GL gl, IntBuffer shaders, java.lang.String[][] sources); @@ -74,7 +74,7 @@ public class ShaderUtil { public String getShaderInfoLog(GL _gl, int shaderObj) { GL2ES2 gl = _gl.getGL2ES2(); int[] infoLogLength=new int[1]; - gl.glGetShaderiv(shaderObj, gl.GL_INFO_LOG_LENGTH, infoLogLength, 0); + gl.glGetShaderiv(shaderObj, GL2ES2.GL_INFO_LOG_LENGTH, infoLogLength, 0); if(infoLogLength[0]==0) { return "(no info log)"; @@ -89,7 +89,7 @@ public class ShaderUtil { public String getProgramInfoLog(GL _gl, int programObj) { GL2ES2 gl = _gl.getGL2ES2(); int[] infoLogLength=new int[1]; - gl.glGetProgramiv(programObj, gl.GL_INFO_LOG_LENGTH, infoLogLength, 0); + gl.glGetProgramiv(programObj, GL2ES2.GL_INFO_LOG_LENGTH, infoLogLength, 0); if(infoLogLength[0]==0) { return "(no info log)"; @@ -143,14 +143,13 @@ public class ShaderUtil { public boolean isProgramValid(GL _gl, int programObj, PrintStream verboseOut) { GL2ES2 gl = _gl.getGL2ES2(); - int[] ires = new int[1]; if(!gl.glIsProgram(programObj)) { if(null!=verboseOut) { verboseOut.println("Program name invalid: "+programObj); } return false; } - if(!isProgramStatusValid(gl, programObj, gl.GL_LINK_STATUS)) { + if(!isProgramStatusValid(gl, programObj, GL2ES2.GL_LINK_STATUS)) { if(null!=verboseOut) { verboseOut.println("Program link failed: "+programObj+"\n\t"+ getProgramInfoLog(gl, programObj)); } @@ -159,7 +158,7 @@ public class ShaderUtil { if ( !gl.isGLES2() || isShaderCompilerAvailable(gl) ) { // failed on APX2500 (ES2.0, no compiler) for valid programs gl.glValidateProgram(programObj); - if(!isProgramStatusValid(gl, programObj, gl.GL_VALIDATE_STATUS)) { + if(!isProgramStatusValid(gl, programObj, GL2ES2.GL_VALIDATE_STATUS)) { if(null!=verboseOut) { verboseOut.println("Program validation failed: "+programObj+"\n\t"+ getProgramInfoLog(gl, programObj)); } @@ -177,17 +176,15 @@ public class ShaderUtil { } private Boolean shaderCompilerAvailable = null; - private Set shaderBinaryFormats = null; + private Set<Integer> shaderBinaryFormats = null; - public Set getShaderBinaryFormats(GL _gl) { + public Set<Integer> getShaderBinaryFormats(GL _gl) { GL2ES2 gl = _gl.getGL2ES2(); if(null==shaderBinaryFormats) { - if(gl.getContext()!=GLContext.getCurrent()) { - return new HashSet(0); // bail out - } + gl.getContext().validateCurrent(); int[] param = new int[1]; - shaderBinaryFormats = new HashSet(); + shaderBinaryFormats = new HashSet<Integer>(); if (gl.isGLES2()) { gl.glGetIntegerv(GL2ES2.GL_NUM_SHADER_BINARY_FORMATS, param, 0); @@ -208,10 +205,8 @@ public class ShaderUtil { public boolean isShaderCompilerAvailable(GL _gl) { GL2ES2 gl = _gl.getGL2ES2(); if(null==shaderCompilerAvailable) { - if(gl.getContext()!=GLContext.getCurrent()) { - return false; // bail out - } - Set bfs = getShaderBinaryFormats(gl); + gl.getContext().validateCurrent(); + Set<Integer> bfs = getShaderBinaryFormats(gl); if(gl.isGLES2()) { byte[] param = new byte[1]; gl.glGetBooleanv(GL2ES2.GL_SHADER_COMPILER, param, 0); @@ -370,7 +365,7 @@ public class ShaderUtil { verboseOut.println("createAndCompileShader: CompileShader failed, GL Error: 0x"+Integer.toHexString(err)); } - return isShaderStatusValid(gl, shader, gl.GL_COMPILE_STATUS, verboseOut) && err == GL.GL_NO_ERROR; + return isShaderStatusValid(gl, shader, GL2ES2.GL_COMPILE_STATUS, verboseOut) && err == GL.GL_NO_ERROR; } } @@ -415,7 +410,7 @@ public class ShaderUtil { getImpl(gl).createShader(gl, type, shaders); } - public static Set getShaderBinaryFormats(GL gl) { + public static Set<Integer> getShaderBinaryFormats(GL gl) { return getImpl(gl).getShaderBinaryFormats(gl); } @@ -469,7 +464,7 @@ public class ShaderUtil { Impl impl = (Impl) context.getAttachedObject(ShaderUtil.class.getName()); if (impl == null) { impl = new GL2ES2Impl(); - context.putAttachedObject(ShaderUtil.class.getName(), impl); + context.attachObject(ShaderUtil.class.getName(), impl); } return impl; } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java index 38f8ff974..35604ba30 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java @@ -178,38 +178,33 @@ public class Texture { private static final boolean disableNPOT = Debug.isPropertyDefined("jogl.texture.nonpot", true, localACC); private static final boolean disableTexRect = Debug.isPropertyDefined("jogl.texture.notexrect", true, localACC); - public Texture(TextureData data) throws GLException { + public Texture(GL gl, TextureData data) throws GLException { texID = 0; - updateImage(data); + updateImage(gl, data); } // Constructor for use when creating e.g. cube maps, where there is // no initial texture data - public Texture(int target) throws GLException { + public Texture(int target) { texID = 0; this.target = target; } // Package-private constructor for creating a texture object which wraps // an existing texture ID from another package - Texture(int textureID, - int target, - int texWidth, - int texHeight, - int imgWidth, - int imgHeight, - boolean mustFlipVertically) { - this.texID = textureID; - this.target = target; - this.mustFlipVertically = mustFlipVertically; - this.texWidth = texWidth; - this.texHeight = texHeight; - setImageSize(imgWidth, imgHeight, target); + Texture(int textureID, int target, int texWidth, int texHeight, int imgWidth, int imgHeight, + boolean mustFlipVertically) { + this.texID = textureID; + this.target = target; + this.mustFlipVertically = mustFlipVertically; + this.texWidth = texWidth; + this.texHeight = texHeight; + setImageSize(imgWidth, imgHeight, target); } /** * Enables this texture's target (e.g., GL_TEXTURE_2D) in the - * current GL context's state. This method is a shorthand equivalent + * given GL context's state. This method is a shorthand equivalent * of the following OpenGL code: <pre> gl.glEnable(texture.getTarget()); @@ -221,13 +216,13 @@ public class Texture { * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void enable() throws GLException { - GLContext.getCurrentGL().glEnable(target); + public void enable(GL gl) throws GLException { + gl.glEnable(target); } - + /** * Disables this texture's target (e.g., GL_TEXTURE_2D) in the - * current GL context's state. This method is a shorthand equivalent + * given GL state. This method is a shorthand equivalent * of the following OpenGL code: <pre> gl.glDisable(texture.getTarget()); @@ -235,16 +230,17 @@ public class Texture { * * See the <a href="#perftips">performance tips</a> above for hints * on how to maximize performance when using many Texture objects. + * @param gl TODO * * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void disable() throws GLException { - GLContext.getCurrentGL().glDisable(target); + public void disable(GL gl) throws GLException { + gl.glDisable(target); } - + /** - * Binds this texture to the current GL context. This method is a + * Binds this texture to the given GL context. This method is a * shorthand equivalent of the following OpenGL code: <pre> gl.glBindTexture(texture.getTarget(), texture.getTextureObject()); @@ -252,36 +248,22 @@ public class Texture { * * See the <a href="#perftips">performance tips</a> above for hints * on how to maximize performance when using many Texture objects. + * @param gl TODO * * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void bind() throws GLException { - validateTexID(null, true); - GLContext.getCurrentGL().glBindTexture(target, texID); - } - - /** - * Disposes the native resources used by this texture object. - * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred - * @deprecated use destroy(GL) - */ - public void dispose() throws GLException { - destroy(GLContext.getCurrentGL()); + public void bind(GL gl) throws GLException { + validateTexID(gl, true); + gl.glBindTexture(target, texID); } - + /** - * Disposes the native resources used by this texture object. - * - * @throws GLException if any OpenGL-related errors occurred - * @deprecated use destroy(GL) + * @deprecated use {@link #destroy(GL)} */ - public void dispose(GL gl) throws GLException { + public final void dispose(GL gl) throws GLException { destroy(gl); } - /** * Destroys the native resources used by this texture object. * @@ -414,11 +396,10 @@ public class Texture { * Updates the entire content area of this texture using the data in * the given image. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void updateImage(TextureData data) throws GLException { - updateImage(data, 0); + public void updateImage(GL gl, TextureData data) throws GLException { + updateImage(gl, data, 0); } /** @@ -438,11 +419,9 @@ public class Texture { * using the data in the given image. In general this is intended * for construction of cube maps. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void updateImage(TextureData data, int target) throws GLException { - GL gl = GLContext.getCurrentGL(); + public void updateImage(GL gl, TextureData data, int target) throws GLException { validateTexID(gl, true); imgWidth = data.getWidth(); @@ -593,7 +572,7 @@ public class Texture { gl.glPixelStorei(GL.GL_UNPACK_ALIGNMENT, align[0]); // restore alignment } } else { - checkCompressedTextureExtensions(data); + checkCompressedTextureExtensions(gl, data); Buffer[] mipmapData = data.getMipmapData(); if (mipmapData != null) { int width = texWidth; @@ -610,7 +589,7 @@ public class Texture { gl.glTexImage2D(texTarget, i, data.getInternalFormat(), width, height, data.getBorder(), data.getPixelFormat(), data.getPixelType(), null); - updateSubImageImpl(data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight()); + updateSubImageImpl(gl, data, texTarget, i, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } width = Math.max(width / 2, 1); @@ -631,7 +610,7 @@ public class Texture { gl.glCompressedTexImage2D(texTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), buf.capacity(), buf); - updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); + updateSubImageImpl(gl, data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } } else { if (data.getMipmap() && haveAutoMipmapGeneration && gl.isGL2ES1()) { @@ -646,7 +625,7 @@ public class Texture { gl.glTexImage2D(texTarget, 0, data.getInternalFormat(), texWidth, texHeight, data.getBorder(), data.getPixelFormat(), data.getPixelType(), null); - updateSubImageImpl(data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); + updateSubImageImpl(gl, data, texTarget, 0, 0, 0, 0, 0, data.getWidth(), data.getHeight()); } } } @@ -697,17 +676,16 @@ public class Texture { * @param y the y offset (in pixels) relative to the lower-left corner * of this texture * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void updateSubImage(TextureData data, int mipmapLevel, int x, int y) throws GLException { + public void updateSubImage(GL gl, TextureData data, int mipmapLevel, int x, int y) throws GLException { if (usingAutoMipmapGeneration && mipmapLevel != 0) { // When we're using mipmap generation via GL_GENERATE_MIPMAP, we // don't need to update other mipmap levels return; } - bind(); - updateSubImageImpl(data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight()); + bind(gl); + updateSubImageImpl(gl, data, target, mipmapLevel, x, y, 0, 0, data.getWidth(), data.getHeight()); } /** @@ -740,7 +718,7 @@ public class Texture { * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void updateSubImage(TextureData data, int mipmapLevel, + public void updateSubImage(GL gl, TextureData data, int mipmapLevel, int dstx, int dsty, int srcx, int srcy, int width, int height) throws GLException { @@ -752,8 +730,8 @@ public class Texture { // don't need to update other mipmap levels return; } - bind(); - updateSubImageImpl(data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height); + bind(gl); + updateSubImageImpl(gl, data, target, mipmapLevel, dstx, dsty, srcx, srcy, width, height); } /** @@ -765,10 +743,9 @@ public class Texture { * @throws GLException if no OpenGL context was current or if any * OpenGL-related errors occurred */ - public void setTexParameterf(int parameterName, + public void setTexParameterf(GL gl, int parameterName, float value) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameterf(target, parameterName, value); } @@ -777,13 +754,11 @@ public class Texture { * texture's target. Causes this texture to be bound to the current * texture state. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void setTexParameterfv(int parameterName, + public void setTexParameterfv(GL gl, int parameterName, FloatBuffer params) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameterfv(target, parameterName, params); } @@ -792,13 +767,11 @@ public class Texture { * texture's target. Causes this texture to be bound to the current * texture state. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void setTexParameterfv(int parameterName, + public void setTexParameterfv(GL gl, int parameterName, float[] params, int params_offset) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameterfv(target, parameterName, params, params_offset); } @@ -810,13 +783,11 @@ public class Texture { * platform and GL_CLAMP if not. Causes this texture to be bound to * the current texture state. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void setTexParameteri(int parameterName, + public void setTexParameteri(GL gl, int parameterName, int value) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameteri(target, parameterName, value); } @@ -825,13 +796,11 @@ public class Texture { * target. Causes this texture to be bound to the current texture * state. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void setTexParameteriv(int parameterName, + public void setTexParameteriv(GL gl, int parameterName, IntBuffer params) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameteriv(target, parameterName, params); } @@ -840,23 +809,21 @@ public class Texture { * target. Causes this texture to be bound to the current texture * state. * - * @throws GLException if no OpenGL context was current or if any - * OpenGL-related errors occurred + * @throws GLException if any OpenGL-related errors occurred */ - public void setTexParameteriv(int parameterName, + public void setTexParameteriv(GL gl, int parameterName, int[] params, int params_offset) { - bind(); - GL gl = GLContext.getCurrentGL(); + bind(gl); gl.glTexParameteriv(target, parameterName, params, params_offset); } /** * Returns the underlying OpenGL texture object for this texture. * Most applications will not need to access this, since it is - * handled automatically by the bind() and dispose() APIs. + * handled automatically by the bind(GL) and destroy(GL) APIs. */ - public int getTextureObject() { - validateTexID(null, false); + public int getTextureObject(GL gl) { + validateTexID(gl, false); return texID; } @@ -936,10 +903,9 @@ public class Texture { } } - private void updateSubImageImpl(TextureData data, int newTarget, int mipmapLevel, + private void updateSubImageImpl(GL gl, TextureData data, int newTarget, int mipmapLevel, int dstx, int dsty, int srcx, int srcy, int width, int height) throws GLException { - GL gl = GLContext.getCurrentGL(); data.setHaveEXTABGR(gl.isExtensionAvailable("GL_EXT_abgr")); data.setHaveGL12(gl.isExtensionAvailable("GL_VERSION_1_2")); @@ -1000,7 +966,7 @@ public class Texture { height = texHeight - dsty; } - checkCompressedTextureExtensions(data); + checkCompressedTextureExtensions(gl, data); if (data.isDataCompressed()) { gl.glCompressedTexSubImage2D(newTarget, mipmapLevel, @@ -1052,8 +1018,7 @@ public class Texture { } } - private void checkCompressedTextureExtensions(TextureData data) { - GL gl = GLContext.getCurrentGL(); + private void checkCompressedTextureExtensions(GL gl, TextureData data) { if (data.isDataCompressed()) { switch (data.getInternalFormat()) { case GL.GL_COMPRESSED_RGB_S3TC_DXT1_EXT: @@ -1073,22 +1038,20 @@ public class Texture { } } - private void validateTexID(GL gl, boolean throwException) { - if( 0 < texID ) return; - if(null==gl) { - GLContext ctx = GLContext.getCurrent(); - if(null!=ctx) { - gl = ctx.getGL(); - } else if(throwException) { - throw new GLException("No context current, can't create texture ID"); + private boolean validateTexID(GL gl, boolean throwException) { + if( 0 >= texID ) { + if( null != gl ) { + int[] tmp = new int[1]; + gl.glGenTextures(1, tmp, 0); + texID = tmp[0]; + if ( 0 >= texID && throwException ) { + throw new GLException("Create texture ID invalid: texID "+texID+", glerr 0x"+Integer.toHexString(gl.glGetError())); + } + } else if ( throwException ) { + throw new GLException("No GL context given, can't create texture ID"); } } - - if(null!=gl) { - int[] tmp = new int[1]; - gl.glGenTextures(1, tmp, 0); - texID = tmp[0]; - } + return 0 < texID; } // Helper routines for disabling certain codepaths diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java index e86ff161b..792f80ff8 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/TextureIO.java @@ -400,12 +400,25 @@ public class TextureIO { * @throws IllegalArgumentException if the passed TextureData was null */ public static Texture newTexture(TextureData data) throws GLException, IllegalArgumentException { + return newTexture(GLContext.getCurrentGL(), data); + } + + /** + * Creates an OpenGL texture object from the specified TextureData + * using the current OpenGL context. + * + * @param data the texture data to turn into an OpenGL texture + * @throws GLException if no OpenGL context is current or if an + * OpenGL error occurred + * @throws IllegalArgumentException if the passed TextureData was null + */ + public static Texture newTexture(GL gl, TextureData data) throws GLException, IllegalArgumentException { if (data == null) { throw new IllegalArgumentException("Null TextureData"); } - return new Texture(data); + return new Texture(gl, data); } - + /** * Creates an OpenGL texture object from the specified file using * the current OpenGL context. @@ -422,9 +435,10 @@ public class TextureIO { * OpenGL error occurred */ public static Texture newTexture(File file, boolean mipmap) throws IOException, GLException { - GLProfile glp = GLContext.getCurrentGL().getGLProfile(); + GL gl = GLContext.getCurrentGL(); + GLProfile glp = gl.getGLProfile(); TextureData data = newTextureData(glp, file, mipmap, FileUtil.getFileSuffix(file)); - Texture texture = newTexture(data); + Texture texture = newTexture(gl, data); data.flush(); return texture; } @@ -450,9 +464,10 @@ public class TextureIO { * OpenGL error occurred */ public static Texture newTexture(InputStream stream, boolean mipmap, String fileSuffix) throws IOException, GLException { - GLProfile glp = GLContext.getCurrentGL().getGLProfile(); + GL gl = GLContext.getCurrentGL(); + GLProfile glp = gl.getGLProfile(); TextureData data = newTextureData(glp, stream, mipmap, fileSuffix); - Texture texture = newTexture(data); + Texture texture = newTexture(gl, data); data.flush(); return texture; } @@ -481,26 +496,24 @@ public class TextureIO { if (fileSuffix == null) { fileSuffix = FileUtil.getFileSuffix(url.getPath()); } - GLProfile glp = GLContext.getCurrentGL().getGLProfile(); + GL gl = GLContext.getCurrentGL(); + GLProfile glp = gl.getGLProfile(); TextureData data = newTextureData(glp, url, mipmap, fileSuffix); - Texture texture = newTexture(data); + Texture texture = newTexture(gl, data); data.flush(); return texture; } /** * Creates an OpenGL texture object associated with the given OpenGL - * texture target using the current OpenGL context. The texture has + * texture target. The texture has * no initial data. This is used, for example, to construct cube * maps out of multiple TextureData objects. * * @param target the OpenGL target type, eg GL.GL_TEXTURE_2D, * GL.GL_TEXTURE_RECTANGLE_ARB - * - * @throws GLException if no OpenGL context is current or if an - * OpenGL error occurred */ - public static Texture newTexture(int target) throws GLException { + public static Texture newTexture(int target) { return new Texture(target); } @@ -528,19 +541,19 @@ public class TextureIO { * texture */ public static Texture newTexture(int textureID, - int target, - int texWidth, - int texHeight, - int imgWidth, - int imgHeight, - boolean mustFlipVertically) { - return new Texture(textureID, - target, - texWidth, - texHeight, - imgWidth, - imgHeight, - mustFlipVertically); + int target, + int texWidth, + int texHeight, + int imgWidth, + int imgHeight, + boolean mustFlipVertically) { + return new Texture(textureID, + target, + texWidth, + texHeight, + imgWidth, + imgHeight, + mustFlipVertically); } /** @@ -581,7 +594,7 @@ public class TextureIO { } GL2 gl = _gl.getGL2(); - texture.bind(); + texture.bind(gl); int internalFormat = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_INTERNAL_FORMAT); int width = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_WIDTH); int height = glGetTexLevelParameteri(gl, GL.GL_TEXTURE_2D, 0, GL2.GL_TEXTURE_HEIGHT); diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/LEDataInputStream.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/LEDataInputStream.java index d5f49599c..37dbc54df 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/LEDataInputStream.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/LEDataInputStream.java @@ -37,7 +37,7 @@ * and developed by Kenneth Bradley Russell and Christopher John Kline. */ -package com.jogamp.opengl.util.texture.spi; +package com.jogamp.opengl.util.texture.spi; import java.io.DataInput; import java.io.DataInputStream; @@ -65,16 +65,16 @@ import java.io.IOException; * for that functionality. It is not clear if it is ever going to be * functionally required to be able to read UTF data in a LittleEndianManner<p> * - * @author Robin Luiten - * @version 1.1 15/Dec/1997 + * @author Robin Luiten + * @version 1.1 15/Dec/1997 */ public class LEDataInputStream extends FilterInputStream implements DataInput { /** - * To reuse some of the non endian dependent methods from - * DataInputStreams methods. + * To reuse some of the non endian dependent methods from + * DataInputStreams methods. */ - DataInputStream dataIn; + DataInputStream dataIn; public LEDataInputStream(InputStream in) { @@ -84,29 +84,29 @@ public class LEDataInputStream extends FilterInputStream implements DataInput public void close() throws IOException { - dataIn.close(); // better close as we create it. + dataIn.close(); // better close as we create it. // this will close underlying as well. } - public synchronized final int read(byte b[]) throws IOException + public synchronized final int read(byte b[]) throws IOException { return dataIn.read(b, 0, b.length); } - public synchronized final int read(byte b[], int off, int len) throws IOException + public synchronized final int read(byte b[], int off, int len) throws IOException { - int rl = dataIn.read(b, off, len); + int rl = dataIn.read(b, off, len); return rl; } public final void readFully(byte b[]) throws IOException { - dataIn.readFully(b, 0, b.length); + dataIn.readFully(b, 0, b.length); } - public final void readFully(byte b[], int off, int len) throws IOException + public final void readFully(byte b[], int off, int len) throws IOException { - dataIn.readFully(b, off, len); + dataIn.readFully(b, off, len); } public final int skipBytes(int n) throws IOException @@ -116,23 +116,23 @@ public class LEDataInputStream extends FilterInputStream implements DataInput public final boolean readBoolean() throws IOException { - int ch = dataIn.read(); + int ch = dataIn.read(); if (ch < 0) throw new EOFException(); return (ch != 0); } - public final byte readByte() throws IOException + public final byte readByte() throws IOException { - int ch = dataIn.read(); + int ch = dataIn.read(); if (ch < 0) throw new EOFException(); return (byte)(ch); } - public final int readUnsignedByte() throws IOException + public final int readUnsignedByte() throws IOException { - int ch = dataIn.read(); + int ch = dataIn.read(); if (ch < 0) throw new EOFException(); return ch; @@ -140,47 +140,47 @@ public class LEDataInputStream extends FilterInputStream implements DataInput public final short readShort() throws IOException { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) throw new EOFException(); - return (short)((ch1 << 0) + (ch2 << 8)); + return (short)((ch1 << 0) + (ch2 << 8)); } - public final int readUnsignedShort() throws IOException + public final int readUnsignedShort() throws IOException { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) throw new EOFException(); - return (ch1 << 0) + (ch2 << 8); + return (ch1 << 0) + (ch2 << 8); } - public final char readChar() throws IOException + public final char readChar() throws IOException { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - if ((ch1 | ch2) < 0) + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + if ((ch1 | ch2) < 0) throw new EOFException(); - return (char)((ch1 << 0) + (ch2 << 8)); + return (char)((ch1 << 0) + (ch2 << 8)); } public final int readInt() throws IOException { - int ch1 = dataIn.read(); - int ch2 = dataIn.read(); - int ch3 = dataIn.read(); - int ch4 = dataIn.read(); - if ((ch1 | ch2 | ch3 | ch4) < 0) + int ch1 = dataIn.read(); + int ch2 = dataIn.read(); + int ch3 = dataIn.read(); + int ch4 = dataIn.read(); + if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); - return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24)); + return ((ch1 << 0) + (ch2 << 8) + (ch3 << 16) + (ch4 << 24)); } - public final long readLong() throws IOException + public final long readLong() throws IOException { - int i1 = readInt(); - int i2 = readInt(); - return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32); + int i1 = readInt(); + int i2 = readInt(); + return ((long)(i1) & 0xFFFFFFFFL) + (i2 << 32); } public final float readFloat() throws IOException @@ -188,7 +188,7 @@ public class LEDataInputStream extends FilterInputStream implements DataInput return Float.intBitsToFloat(readInt()); } - public final double readDouble() throws IOException + public final double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } @@ -197,7 +197,7 @@ public class LEDataInputStream extends FilterInputStream implements DataInput * dont call this it is not implemented. * @return empty new string **/ - public final String readLine() throws IOException + public final String readLine() throws IOException { return new String(); } @@ -206,7 +206,7 @@ public class LEDataInputStream extends FilterInputStream implements DataInput * dont call this it is not implemented * @return empty new string **/ - public final String readUTF() throws IOException + public final String readUTF() throws IOException { return new String(); } @@ -215,7 +215,7 @@ public class LEDataInputStream extends FilterInputStream implements DataInput * dont call this it is not implemented * @return empty new string **/ - public final static String readUTF(DataInput in) throws IOException + public final static String readUTF(DataInput in) throws IOException { return new String(); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java index bb5040a31..c60c91bda 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/spi/SGIImage.java @@ -477,7 +477,7 @@ public class SGIImage { for (int z = 0; z < zsize; z++) { for (int y = ystart; y != yend; y += yincr) { // RLE-compress each row. - + int x = 0; byte count = 0; boolean repeat_mode = false; @@ -485,7 +485,7 @@ public class SGIImage { int start_ptr = ptr; int num_ptr = ptr++; byte repeat_val = 0; - + while (x < xsize) { // see if we should switch modes should_switch = false; @@ -502,7 +502,7 @@ public class SGIImage { if (DEBUG) System.err.println("left side was " + ((int) imgref(data, x, y, z, xsize, ysize, zsize)) + ", right side was " + (int)imgref(data, x+i, y, z, xsize, ysize, zsize)); - + if (imgref(data, x, y, z, xsize, ysize, zsize) != imgref(data, x+i, y, z, xsize, ysize, zsize)) should_switch = false; @@ -530,7 +530,7 @@ public class SGIImage { repeat_mode = true; repeat_val = imgref(data, x, y, z, xsize, ysize, zsize); } - + if (x > 0) { // reset the number pointer num_ptr = ptr++; @@ -538,7 +538,7 @@ public class SGIImage { count = 0; } } - + // if not in repeat mode, copy element to ptr if (!repeat_mode) { rlebuf[ptr++] = imgref(data, x, y, z, xsize, ysize, zsize); |