diff options
23 files changed, 1162 insertions, 56 deletions
diff --git a/build/joglutils.jar b/build/joglutils.jar Binary files differindex 33d954e..e46dd2a 100644 --- a/build/joglutils.jar +++ b/build/joglutils.jar diff --git a/src/net/java/joglutils/msg/actions/Action.java b/src/net/java/joglutils/msg/actions/Action.java index 34f14ea..b206cdb 100644 --- a/src/net/java/joglutils/msg/actions/Action.java +++ b/src/net/java/joglutils/msg/actions/Action.java @@ -70,6 +70,13 @@ public abstract class Action { altered by the nodes the action traverses. */ public abstract State getState(); + /** Returns the path to the node currently being traversed. The + caller should make a copy of this path if it is desired to keep + it around. */ + public Path getPath() { + return path; + } + private Object[] argTmp = new Object[2]; /** Invokes the appropriate action method for the given Node. */ protected void apply(ActionTable table, Node node) { @@ -78,10 +85,28 @@ public abstract class Action { if (m != null) { argTmp[0] = this; argTmp[1] = node; - m.invoke(null, argTmp); + push(node); + try { + m.invoke(null, argTmp); + } finally { + pop(); + } } } catch (Exception e) { throw new RuntimeException(e); } } + + private Path path = new Path(); + /** Pushes the given Node onto the internal Path this Action + maintains during traversal. */ + private void push(Node node) { + path.add(node); + } + + /** Pops the given Node off the internal Path this Action maintains + during traversal. */ + private void pop() { + path.remove(path.size() - 1); + } } diff --git a/src/net/java/joglutils/msg/actions/GLRenderAction.java b/src/net/java/joglutils/msg/actions/GLRenderAction.java index 7b2fb56..b058e13 100644 --- a/src/net/java/joglutils/msg/actions/GLRenderAction.java +++ b/src/net/java/joglutils/msg/actions/GLRenderAction.java @@ -42,7 +42,6 @@ import java.lang.reflect.*; import javax.media.opengl.*; import javax.media.opengl.glu.*; -import net.java.joglutils.msg.elements.*; import net.java.joglutils.msg.misc.*; import net.java.joglutils.msg.nodes.*; diff --git a/src/net/java/joglutils/msg/actions/RayPickAction.java b/src/net/java/joglutils/msg/actions/RayPickAction.java new file mode 100644 index 0000000..633d7c4 --- /dev/null +++ b/src/net/java/joglutils/msg/actions/RayPickAction.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.actions; + +import java.awt.Component; +import java.lang.reflect.*; +import java.util.*; + +import net.java.joglutils.msg.math.*; +import net.java.joglutils.msg.misc.*; +import net.java.joglutils.msg.nodes.*; + +public class RayPickAction extends Action { + // Boilerplate + private static State defaults = new State(); + /** Returns the default state all instances of this class are initialized with. */ + public static State getDefaultState() { + return defaults; + } + private static ActionTable table = new ActionTable(RayPickAction.class); + + /** Adds an action method for the given node type to this action. + This should only be called by developers adding new node types + and not desiring to use the standard overriding mechanisms. */ + public static void addActionMethod(Class<? extends Node> nodeType, Method m) { + table.addActionMethod(nodeType, m); + } + + private State state = new State(defaults); + public State getState() { + return state; + } + + static { + // Set up action methods + // Note that because this action is built-in, we use virtual + // method dispatch to allow overriding of rendering functionality. + // We could optionally pull in all of the action methods into this + // class. However, factoring the setting of the elements into the + // nodes provides for more sharing of common functionality among + // actions. + try { + addActionMethod(Node.class, RayPickAction.class.getMethod("rayPick", RayPickAction.class, Node.class)); + } catch (Exception e) { + throw new RuntimeException("Error initializing action method for RayPickAction class", e); + } + } + + private int applyDepth = 0; + private Vec2f normalizedPoint; + private Line ray; + + private Line computedRay; + + static class RayPickedPoint implements Comparable<RayPickedPoint> { + float t; + PickedPoint point; + + RayPickedPoint(float t, PickedPoint point) { + this.t = t; + this.point = point; + } + + public boolean equals(Object o) { + return (o == this); + } + + public int compareTo(RayPickedPoint p) { + return (int) Math.signum(t - p.t); + } + } + + // While we're in the process of traversing the scene graph, we + // memorize both the paths to intersected geometry as well as the + // t parameter indicating the distance to the geometry. + private List<RayPickedPoint> tempPickedPoints = new ArrayList<RayPickedPoint>(); + + // The list of picked points, sorted by increasing distance from the camera + private List<PickedPoint> pickedPoints = new ArrayList<PickedPoint>(); + + public void apply(Node node) { + int depth = applyDepth++; + try { + if (depth == 0) { + reset(); + } + apply(table, node); + } finally { + --applyDepth; + if (depth == 0) { + tabulate(); + } + } + } + + /** Sets the point for this RayPickAction based on x and y + coordinates relative to the specified AWT Component. */ + public void setPoint(int x, int y, Component component) { + setNormalizedPoint(new Vec2f((float) x / (float) component.getWidth(), + 1.0f - ((float) y / (float) component.getHeight()))); + } + + /** Sets the normalized point for this RayPickAction, where x and y + are relative to the lower-left of the viewport and range from + [0..1]. */ + public void setNormalizedPoint(Vec2f normalizedPoint) { + this.normalizedPoint = normalizedPoint; + ray = null; + computedRay = null; + } + + /** Sets the ray in world coordinates that this RayPickAction should + use for its computation. */ + public void setRay(Line ray) { + this.ray = ray; + computedRay = ray; + normalizedPoint = null; + } + + /** Returns the list of points this action selected during the last + traversal, sorted in increasing order of distance from the + origin. Typically applications will only need to deal with the + first point in the returned list. */ + public List<PickedPoint> getPickedPoints() { + return pickedPoints; + } + + /** Returns the computed 3D ray in world coordinates that this + RayPickAction is using for its picking. If the action is + configured with on-screen coordinates instead of with a 3D ray, + then this is automatically updated every time the action + traverses a Camera node. May return null if this has not been + computed yet. End users should not need to call this method. */ + public Line getComputedRay() { + return computedRay; + } + + /** Called during scene graph traversal to update the 3D ray + associated with this action if it was configured with on-screen + coordinates. End users should not need to call this method. */ + public void recomputeRay(Camera camera) { + if (normalizedPoint != null && ray == null) { + if (computedRay == null) { + computedRay = new Line(); + } + camera.unproject(normalizedPoint, computedRay); + } + } + + /** Registers a picked point with the RayPickAction during scene + graph traversal. The t argument is the time parameter indicating + the distance from the camera. A reference to the PickedPoint is + maintained internally so the caller should add a copy if the + original is still mutable. End users should not need to call + this method. */ + public void addPickedPoint(PickedPoint p, float t) { + tempPickedPoints.add(new RayPickedPoint(t, p)); + } + + private void reset() { + tempPickedPoints.clear(); + pickedPoints.clear(); + } + + private void tabulate() { + Collections.sort(tempPickedPoints); + for (RayPickedPoint p : tempPickedPoints) { + pickedPoints.add(p.point); + } + } + + /** Action method which dispatches to per-node rendering functionality. */ + public static void rayPick(RayPickAction action, Node node) { + node.rayPick(action); + } +} diff --git a/src/net/java/joglutils/msg/impl/RayTriangleIntersection.java b/src/net/java/joglutils/msg/impl/RayTriangleIntersection.java new file mode 100644 index 0000000..13d49e9 --- /dev/null +++ b/src/net/java/joglutils/msg/impl/RayTriangleIntersection.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.impl; + +import net.java.joglutils.msg.math.*; + +/** Intersection of ray with triangle. Computes parameteric t along + with barycentric coordinates (u, v) indicating weight of vert1 and + vert2 (weight of vert0 = 1 - u - v) which can be used to + interpolate normals and texture coordinates. Two versions, one for + two-sided triangle casts and one including backface + culling. Algorithm from Moller, Trumbore, "Fast, Minimum Storage + Ray / Triangle Intersection", Journal of Graphics Tools, Volume 2, + Number 1, 1997, pp. 21-28. */ + +public class RayTriangleIntersection { + private Vec3f edge1 = new Vec3f(); + private Vec3f edge2 = new Vec3f(); + private Vec3f tvec = new Vec3f(); + private Vec3f pvec = new Vec3f(); + private Vec3f qvec = new Vec3f(); + + private static final float EPSILON = 0.000001f; + + public boolean intersectTriangle(Line ray, + Vec3f vert0, + Vec3f vert1, + Vec3f vert2, + Vec3f tuv) { + // Find vectors for two edges sharing vert0 + edge1.sub(vert1, vert0); + edge2.sub(vert2, vert0); + + // Begin calculating determinant -- also used to calculate U parameter + pvec.cross(ray.getDirection(), edge2); + + // If determinant is near zero, ray lies in plane of triangle + float det = edge1.dot(pvec); + + if (det > -EPSILON && det < EPSILON) + return false; + + float invDet = 1.0f / det; + + // Calculate distance from vert0 to ray origin + tvec.sub(ray.getPoint(), vert0); + + // Calculate U parameter and test bounds + float u = tvec.dot(pvec) * invDet; + if (u < 0.0f || u > 1.0f) + return false; + + // Prepare to test V parameter + qvec.cross(tvec, edge1); + + // Calculate V parameter and test bounds + float v = ray.getDirection().dot(qvec) * invDet; + if (v < 0.0f || (u + v) > 1.0f) + return false; + + // Calculate t, ray intersects triangle + float t = edge2.dot(qvec) * invDet; + + tuv.set(t, u, v); + return true; + } + + public boolean intersectTriangleBackfaceCulling(Line ray, + Vec3f vert0, + Vec3f vert1, + Vec3f vert2, + Vec3f tuv) { + // Find vectors for two edges sharing vert0 + edge1.sub(vert1, vert0); + edge2.sub(vert2, vert0); + + // Begin calculating determinant -- also used to calculate U parameter + pvec.cross(ray.getDirection(), edge2); + + // If determinant is near zero, ray lies in plane of triangle + float det = edge1.dot(pvec); + + if (det < EPSILON) + return false; + + // Calculate distance from vert0 to ray origin + tvec.sub(ray.getPoint(), vert0); + + // Calculate U parameter and test bounds + float u = tvec.dot(pvec); + if (u < 0.0f || u > det) + return false; + + // Prepare to test V parameter + qvec.cross(tvec, edge1); + + // Calculate V parameter and test bounds + float v = ray.getDirection().dot(qvec); + if (v < 0.0f || (u + v) > det) + return false; + + // Calculate t, scale parameters, ray intersects triangle + float t = edge2.dot(qvec); + float invDet = 1.0f / det; + t *= invDet; + u *= invDet; + v *= invDet; + tuv.set(t, u, v); + return true; + } +} diff --git a/src/net/java/joglutils/msg/math/Line.java b/src/net/java/joglutils/msg/math/Line.java index 2004c08..c599e60 100644 --- a/src/net/java/joglutils/msg/math/Line.java +++ b/src/net/java/joglutils/msg/math/Line.java @@ -59,9 +59,9 @@ public class Line { <b>point</b>. <b>direction</b> does not need to be normalized but must not be the zero vector. */ public Line(Vec3f direction, Vec3f point) { - direction = new Vec3f(direction); - direction.normalize(); - point = new Vec3f(point); + this.direction = new Vec3f(direction); + this.direction.normalize(); + this.point = new Vec3f(point); alongVec = new Vec3f(); recalc(); } diff --git a/src/net/java/joglutils/msg/math/Mat4f.java b/src/net/java/joglutils/msg/math/Mat4f.java index b0cc67e..fc4d955 100644 --- a/src/net/java/joglutils/msg/math/Mat4f.java +++ b/src/net/java/joglutils/msg/math/Mat4f.java @@ -239,6 +239,16 @@ public class Mat4f { dest.set(rc, tmp); } } + + /** Transforms the given line (origin plus direction) by this + matrix. */ + public Line xformLine(Line line) { + Vec3f pt = new Vec3f(); + Vec3f dir = new Vec3f(); + xformPt(line.getPoint(), pt); + xformDir(line.getDirection(), dir); + return new Line(dir, pt); + } /** Copies data in column-major (OpenGL format) order into passed float array, which must have length 16 or greater. */ diff --git a/src/net/java/joglutils/msg/misc/Path.java b/src/net/java/joglutils/msg/misc/Path.java new file mode 100644 index 0000000..0743e86 --- /dev/null +++ b/src/net/java/joglutils/msg/misc/Path.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.misc; + +import java.util.*; + +import net.java.joglutils.msg.nodes.*; + +/** Represents a path through the scene graph. The topmost node is at + index 0 and subsequent child nodes are at later indices. */ + +public class Path extends ArrayList<Node> { + /** Returns a copy of this path. */ + public Path copy() { + return (Path) clone(); + } +} diff --git a/src/net/java/joglutils/msg/misc/PickedPoint.java b/src/net/java/joglutils/msg/misc/PickedPoint.java new file mode 100644 index 0000000..20874b4 --- /dev/null +++ b/src/net/java/joglutils/msg/misc/PickedPoint.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.misc; + +/** Represents a point on a piece of geometry picked for example by a + RayPickAction. */ + +public class PickedPoint extends PrimitiveVertex { + private Path path; + + public Object clone() { + PickedPoint point = (PickedPoint) super.clone(); + if (path != null) { + point.path = path.copy(); + } + return point; + } + + /** Performs a "deep copy" of this PickedPoint so that it shares + none of its contents with this one. */ + public PickedPoint copy() { + return (PickedPoint) clone(); + } + + /** Sets the path to the picked geometry. Note that this simply + retains a reference to the given Path, so the Path should be + copied if it can later be changed (for example, if it the + internal Path in an Action). */ + public void setPath(Path path) { + this.path = path; + } + + /** Returns the path to the picked geometry. */ + public Path getPath() { + return path; + } +} diff --git a/src/net/java/joglutils/msg/misc/PrimitiveVertex.java b/src/net/java/joglutils/msg/misc/PrimitiveVertex.java new file mode 100644 index 0000000..24b9e46 --- /dev/null +++ b/src/net/java/joglutils/msg/misc/PrimitiveVertex.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.misc; + +import net.java.joglutils.msg.math.*; + +/** Represents a vertex on a primitive, including pieces of relevant + information such as location, surface normal and texture + coordinates. */ + +public class PrimitiveVertex implements Cloneable { + private Vec3f coord; + private Vec2f texCoord; + private Vec4f color; + private Vec3f normal; + + public PrimitiveVertex() {} + + public Object clone() { + try { + PrimitiveVertex vtx = (PrimitiveVertex) super.clone(); + if (coord != null) { + vtx.setCoord(new Vec3f(coord)); + } + if (texCoord != null) { + vtx.setTexCoord(new Vec2f(texCoord)); + } + if (color != null) { + vtx.setColor(new Vec4f(color)); + } + if (normal != null) { + vtx.setNormal(new Vec3f(normal)); + } + return vtx; + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e); + } + } + + /** Performs a "deep copy" of this PrimitiveVertex so that it shares + none of its contents with this one. */ + public PrimitiveVertex copy() { + return (PrimitiveVertex) clone(); + } + + /** Sets the coordinate in this PrimitiveVertex. Refers to the passed vector by reference. */ + public void setCoord(Vec3f coord) { this.coord = coord; } + /** Returns the coordinate in this PrimitiveVertex, or null if it is not known. */ + public Vec3f getCoord() { return coord; } + + /** Sets the texture coordinate in this PrimitiveVertex. Refers to the passed vector by reference. */ + public void setTexCoord(Vec2f texCoord) { this.texCoord = texCoord; } + /** Returns the texture coordinate in this PrimitiveVertex, or null if it is not known. */ + public Vec2f getTexCoord() { return texCoord; } + + /** Sets the color in this PrimitiveVertex. Refers to the passed vector by reference. */ + public void setColor(Vec4f color) { this.color = color; } + /** Returns the color in this PrimitiveVertex, or null if it is not known. */ + public Vec4f getColor() { return color; } + + /** Sets the normal in this PrimitiveVertex. Refers to the passed vector by reference. */ + public void setNormal(Vec3f normal) { this.normal = normal; } + /** Returns the normal in this PrimitiveVertex, or null if it is not known. */ + public Vec3f getNormal() { return normal; } +} diff --git a/src/net/java/joglutils/msg/misc/TriangleCallback.java b/src/net/java/joglutils/msg/misc/TriangleCallback.java new file mode 100644 index 0000000..61140e2 --- /dev/null +++ b/src/net/java/joglutils/msg/misc/TriangleCallback.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.misc; + +/** Supports iteration over the triangles inside shapes. */ + +public interface TriangleCallback { + /** Called for each triangle generated during enumeration of the + triangles in a particular shape. Certain elements of the + PrimitiveVertex objects may be null if not set, such as normals + or texture coordinates. Note that the PrimitiveVertex objects + may be reused between calls, so users should copy them if + necessary. + + @param triangleIndex the index within the set of triangles [0..num tris - 1] + @param v0 primitive vertex 0 + @param i0 index of primitive vertex 0 in the current coordinates + @param v1 primitive vertex 1 + @param i1 index of primitive vertex 1 in the current coordinates + @param v2 primitive vertex 2 + @param i2 index of primitive vertex 2 in the current coordinates + */ + public void triangleCB(int triangleIndex, + PrimitiveVertex v0, + int i0, + PrimitiveVertex v1, + int i1, + PrimitiveVertex v2, + int i2); +} diff --git a/src/net/java/joglutils/msg/nodes/Camera.java b/src/net/java/joglutils/msg/nodes/Camera.java index 5d405fe..5333f81 100644 --- a/src/net/java/joglutils/msg/nodes/Camera.java +++ b/src/net/java/joglutils/msg/nodes/Camera.java @@ -70,6 +70,10 @@ public abstract class Camera extends Node { GLModelMatrixElement .enable(GLRenderAction.getDefaultState()); GLProjectionMatrixElement .enable(GLRenderAction.getDefaultState()); GLViewingMatrixElement .enable(GLRenderAction.getDefaultState()); + + ModelMatrixElement .enable(RayPickAction.getDefaultState()); + ProjectionMatrixElement.enable(RayPickAction.getDefaultState()); + ViewingMatrixElement .enable(RayPickAction.getDefaultState()); } public Camera() { @@ -84,38 +88,74 @@ public abstract class Camera extends Node { } /** Sets the position of the camera. */ - public void setPosition(Vec3f position) { this.position.set(position); viewDirty = true; } + public void setPosition(Vec3f position) { + this.position.set(position); + viewDirty = true; + } + /** Returns the position of the camera. */ - public Vec3f getPosition() { return position; } + public Vec3f getPosition() { + return position; + } /** Sets the orientation of the camera. */ - public void setOrientation(Rotf orientation) { this.orientation.set(orientation); viewDirty = true; } + public void setOrientation(Rotf orientation) { + this.orientation.set(orientation); + viewDirty = true; + } + /** Returns the orientation of the camera. */ - public Rotf getOrientation() { return orientation; } + public Rotf getOrientation() { + return orientation; + } /** Sets the aspect ratio of the camera. */ - public void setAspectRatio(float aspectRatio) { this.aspectRatio = aspectRatio; projDirty = true; } + public void setAspectRatio(float aspectRatio) { + this.aspectRatio = aspectRatio; + projDirty = true; + } + /** Returns the aspect ratio of the camera. */ - public float getAspectRatio() { return aspectRatio; } + public float getAspectRatio() { + return aspectRatio; + } /** Sets the distance from the eye point to the near clipping plane. */ - public void setNearDistance(float nearDistance) { this.nearDistance = nearDistance; projDirty = true; } + public void setNearDistance(float nearDistance) { + this.nearDistance = nearDistance; + projDirty = true; + } + /** Returns the distance from the eye point to the near clipping plane. */ - public float getNearDistance() { return nearDistance; } + public float getNearDistance() { + return nearDistance; + } /** Sets the distance from the eye point to the far clipping plane. */ - public void setFarDistance(float farDistance) { this.farDistance = farDistance; projDirty = true; } + public void setFarDistance(float farDistance) { + this.farDistance = farDistance; + projDirty = true; + } + /** Returns the distance from the eye point to the far clipping plane. */ - public float getFarDistance() { return farDistance; } + public float getFarDistance() { + return farDistance; + } /** Sets the distance from the eye point to the focal point of the scene. This is only used for mouse-based interaction with the scene and is not factored in to the rendering process. */ - public void setFocalDistance(float focalDistance) { this.focalDistance = focalDistance; projDirty = true; } + public void setFocalDistance(float focalDistance) { + this.focalDistance = focalDistance; + projDirty = true; + } + /** Returns the distance from the eye point to the focal point of the scene. This is only used for mouse-based interaction with the scene and is not factored in to the rendering process. */ - public float getFocalDistance() { return focalDistance; } + public float getFocalDistance() { + return focalDistance; + } /** Returns the viewing matrix associated with this camera's parameters. */ public Mat4f getViewingMatrix() { @@ -134,6 +174,59 @@ public abstract class Camera extends Node { /** Returns the projection matrix associated with this camera's parameters. */ public abstract Mat4f getProjectionMatrix(); + /** Un-projects the given on-screen point to a line in 3D space + which can be used for picking or other operations. The x and y + coordinates of the point must be in normalized coordinates, + where (0, 0) is the lower-left corner of the viewport and (1, 1) + is the upper-right. Allocates new storage for the returned + Line. */ + public Line unproject(Vec2f point) { + Line line = new Line(); + unproject(point, line); + return line; + } + + /** Un-projects the given on-screen point in to the given line in 3D + space (in world coordinates) which can be used for picking or + other operations. The x and y coordinates of the point must be + in normalized coordinates, where (0, 0) is the lower-left corner + of the viewport and (1, 1) is the upper-right. */ + public void unproject(Vec2f point, Line line) throws SingularMatrixException { + // First, we are going to compute the 3D point which corresponds + // to the given point on the near plane. Map the screen + // coordinates to the (-1, 1) range. + Vec4f pt3d = new Vec4f(2 * point.x() - 1, + 2 * point.y() - 1, + getNearDistance(), + 1); + // Compute the cumulative view and projection matrices + Mat4f mat = new Mat4f(); + mat.mul(getProjectionMatrix(), getViewingMatrix()); + // Compute the inverse of this matrix + mat.invert(); + // Multiply + Vec4f unproj = new Vec4f(); + mat.xformVec(pt3d, unproj); + if (unproj.z() == 0) { + // FIXME: is this the right exception to throw in this case? + throw new SingularMatrixException(); + } + float ooZ = 1.0f / unproj.w(); + Vec3f to = new Vec3f(unproj.x() * ooZ, + unproj.y() * ooZ, + unproj.z() * ooZ); + // FIXME: for orthographic projections, need to do something + // different; can't just use the eye point + Vec3f from = getPosition(); + Vec3f dir = to.minus(from); + + // System.err.println("unprojected point: " + from); + // System.err.println("unprojected dir : " + dir); + + line.setPoint(from); + line.setDirection(dir); + } + public void doAction(Action action) { if (ViewingMatrixElement.isEnabled(action.getState())) { ViewingMatrixElement.set(action.getState(), getViewingMatrix()); @@ -142,4 +235,9 @@ public abstract class Camera extends Node { ProjectionMatrixElement.set(action.getState(), getProjectionMatrix()); } } + + public void rayPick(RayPickAction action) { + doAction(action); + action.recomputeRay(this); + } } diff --git a/src/net/java/joglutils/msg/nodes/Coordinate3.java b/src/net/java/joglutils/msg/nodes/Coordinate3.java index e8e2631..7cae14b 100644 --- a/src/net/java/joglutils/msg/nodes/Coordinate3.java +++ b/src/net/java/joglutils/msg/nodes/Coordinate3.java @@ -50,6 +50,8 @@ public class Coordinate3 extends Node { static { // Enable the elements this node affects for known actions GLCoordinateElement.enable(GLRenderAction.getDefaultState()); + + CoordinateElement .enable(RayPickAction.getDefaultState()); } /** Sets the coordinate data in this node. */ diff --git a/src/net/java/joglutils/msg/nodes/Group.java b/src/net/java/joglutils/msg/nodes/Group.java index f9a961b..df3232d 100644 --- a/src/net/java/joglutils/msg/nodes/Group.java +++ b/src/net/java/joglutils/msg/nodes/Group.java @@ -52,7 +52,7 @@ public class Group extends Node { } /** Adds a child so that it becomes the one with the given index. */ - public void insertChild(Node child, int index) { + public void insertChild(int index, Node child) { children.add(index, child); } @@ -103,7 +103,7 @@ public class Group extends Node { */ public void replaceChild(int index, Node newChild) throws IndexOutOfBoundsException { removeChild(index); - insertChild(newChild, index); + insertChild(index, newChild); } /** Replaces the old child with the new child. This is a convenience diff --git a/src/net/java/joglutils/msg/nodes/IndexedTriangleSet.java b/src/net/java/joglutils/msg/nodes/IndexedTriangleSet.java index 5e45367..e244f17 100644 --- a/src/net/java/joglutils/msg/nodes/IndexedTriangleSet.java +++ b/src/net/java/joglutils/msg/nodes/IndexedTriangleSet.java @@ -40,6 +40,7 @@ package net.java.joglutils.msg.nodes; import java.nio.*; import net.java.joglutils.msg.actions.*; +import net.java.joglutils.msg.misc.*; /** An IndexedTriangleSet assembles the coordinates specified by a Coordinate3 node, and any auxiliary nodes such as a @@ -48,7 +49,7 @@ import net.java.joglutils.msg.actions.*; (FIXME) rendering support for this node is not yet implemented.) */ -public class IndexedTriangleSet extends Node { +public class IndexedTriangleSet extends TriangleBasedShape { private IntBuffer indices; /** Sets the indices this node uses to group vertices into triangles. */ @@ -64,4 +65,8 @@ public class IndexedTriangleSet extends Node { public void doAction(Action action) { throw new RuntimeException("Not yet implemented"); } + + public void generateTriangles(Action action, TriangleCallback cb) { + throw new RuntimeException("Not yet implemented"); + } } diff --git a/src/net/java/joglutils/msg/nodes/Node.java b/src/net/java/joglutils/msg/nodes/Node.java index e9eefc4..f2ab658 100644 --- a/src/net/java/joglutils/msg/nodes/Node.java +++ b/src/net/java/joglutils/msg/nodes/Node.java @@ -51,4 +51,10 @@ public class Node { not required due to the framework supporting action methods, but for built-in actions it may make it simpler. */ public void render(GLRenderAction action) { doAction(action); } + + /** Support for the built-in RayPickAction. Note that supplying + virtual methods in Node subclasses to support various actions is + not required due to the framework supporting action methods, but + for built-in actions it may make it simpler. */ + public void rayPick(RayPickAction action) { doAction(action); } } diff --git a/src/net/java/joglutils/msg/nodes/Shape.java b/src/net/java/joglutils/msg/nodes/Shape.java new file mode 100644 index 0000000..9c88e9e --- /dev/null +++ b/src/net/java/joglutils/msg/nodes/Shape.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.nodes; + +/** The abstract base class for all shapes in the scene graph. */ + +public abstract class Shape extends Node { +} diff --git a/src/net/java/joglutils/msg/nodes/Texture2.java b/src/net/java/joglutils/msg/nodes/Texture2.java index fd1b82a..29ed969 100644 --- a/src/net/java/joglutils/msg/nodes/Texture2.java +++ b/src/net/java/joglutils/msg/nodes/Texture2.java @@ -58,6 +58,8 @@ public class Texture2 extends Node { static { // Enable the elements this node affects for known actions GLTextureElement.enable(GLRenderAction.getDefaultState()); + + TextureElement .enable(RayPickAction.getDefaultState()); } /** Represents the OpenGL MODULATE texture environment mode. */ @@ -144,4 +146,11 @@ public class Texture2 extends Node { TextureElement.set(action.getState(), getTexture(), getTexEnvMode()); } } + + public void rayPick(RayPickAction action) { + // FIXME: because of the issue of potentially not having an OpenGL + // context at the time this is called, the TextureElement should + // be updated to hold a reference to this node, and only the + // GLTextureElement should poll the texture + } } diff --git a/src/net/java/joglutils/msg/nodes/TextureCoordinate2.java b/src/net/java/joglutils/msg/nodes/TextureCoordinate2.java index f7720d2..2782da1 100644 --- a/src/net/java/joglutils/msg/nodes/TextureCoordinate2.java +++ b/src/net/java/joglutils/msg/nodes/TextureCoordinate2.java @@ -50,6 +50,8 @@ public class TextureCoordinate2 extends Node { static { // Enable the elements this node affects for known actions GLTextureCoordinateElement.enable(GLRenderAction.getDefaultState()); + + TextureCoordinateElement .enable(RayPickAction.getDefaultState()); } /** Sets the texture coordinate data in this node. */ diff --git a/src/net/java/joglutils/msg/nodes/Transform.java b/src/net/java/joglutils/msg/nodes/Transform.java index ad5e1bd..044c1b7 100644 --- a/src/net/java/joglutils/msg/nodes/Transform.java +++ b/src/net/java/joglutils/msg/nodes/Transform.java @@ -49,9 +49,13 @@ public class Transform extends Node { static { // Enable the elements this node affects for known actions // Note that all of these elements are interdependent - GLModelMatrixElement .enable(GLRenderAction.getDefaultState()); - GLProjectionMatrixElement .enable(GLRenderAction.getDefaultState()); - GLViewingMatrixElement .enable(GLRenderAction.getDefaultState()); + GLModelMatrixElement .enable(GLRenderAction.getDefaultState()); + GLProjectionMatrixElement.enable(GLRenderAction.getDefaultState()); + GLViewingMatrixElement .enable(GLRenderAction.getDefaultState()); + + ModelMatrixElement .enable(RayPickAction.getDefaultState()); + ProjectionMatrixElement.enable(RayPickAction.getDefaultState()); + ViewingMatrixElement .enable(RayPickAction.getDefaultState()); } public Transform() { diff --git a/src/net/java/joglutils/msg/nodes/TriangleBasedShape.java b/src/net/java/joglutils/msg/nodes/TriangleBasedShape.java new file mode 100644 index 0000000..c234695 --- /dev/null +++ b/src/net/java/joglutils/msg/nodes/TriangleBasedShape.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution 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. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + */ + +package net.java.joglutils.msg.nodes; + +import java.util.*; + +import net.java.joglutils.msg.actions.*; +import net.java.joglutils.msg.elements.*; +import net.java.joglutils.msg.impl.*; +import net.java.joglutils.msg.math.*; +import net.java.joglutils.msg.misc.*; + +/** The abstract base class for all shapes in the scene graph which + render themselves as a collection of triangles. */ + +public abstract class TriangleBasedShape extends Shape { + /** Based on the state in the given Action, calls the specified + triangle callback for each triangle in the shape. Coordinates + are specified in the local coordinate system of this shape; the + caller must transform them into the world coordinate system if + necessary. */ + public abstract void generateTriangles(Action action, + TriangleCallback cb); + + public void rayPick(final RayPickAction action) { + // The RayPickAction holds the picking ray in world coordinates. + // Transform this ray into local coordinates to do intersection testing + // Fetch the current local-to-world matrix + Mat4f mat = new Mat4f(ModelMatrixElement.getInstance(action.getState()).getMatrix()); + // Invert it to get the world-to-local matrix + mat.invert(); + // Transform the RayPickAction's ray by this matrix + final Line ray = mat.xformLine(action.getComputedRay()); + + // Temporaries + final RayTriangleIntersection rti = new RayTriangleIntersection(); + final Vec3f tuv = new Vec3f(); + + // OK, ready to test + generateTriangles(action, new TriangleCallback() { + public void triangleCB(int triangleIndex, + PrimitiveVertex v0, + int i0, + PrimitiveVertex v1, + int i1, + PrimitiveVertex v2, + int i2) { + if (rti.intersectTriangle(ray, + v0.getCoord(), + v1.getCoord(), + v2.getCoord(), + tuv)) { + // Compute at least the 3D coordinate of the intersection + // point for now + // FIXME: need to compute other things such as the texture + // coordinates + PickedPoint p = new PickedPoint(); + // Compute weights of three vertices + float a = 1.0f - tuv.y() - tuv.z(); + float b = tuv.y(); + float c = tuv.z(); + Vec3f loc = v0.getCoord().times(a).plus(v1.getCoord().times(b)).plus(v2.getCoord().times(c)); + p.setCoord(loc); + p.setPath(action.getPath().copy()); + action.addPickedPoint(p, tuv.x()); + } + } + }); + } +} diff --git a/src/net/java/joglutils/msg/nodes/TriangleSet.java b/src/net/java/joglutils/msg/nodes/TriangleSet.java index 0692738..8f708cb 100644 --- a/src/net/java/joglutils/msg/nodes/TriangleSet.java +++ b/src/net/java/joglutils/msg/nodes/TriangleSet.java @@ -37,6 +37,9 @@ package net.java.joglutils.msg.nodes; +import java.nio.*; +import java.util.*; + import javax.media.opengl.*; import com.sun.opengl.util.texture.*; @@ -49,7 +52,7 @@ import net.java.joglutils.msg.misc.*; node, and any auxiliary nodes such as a TextureCoordinate2 node, into a set of triangles. */ -public class TriangleSet extends Node { +public class TriangleSet extends TriangleBasedShape { private int numTriangles; /** Sets the number of triangles this TriangleSet references. */ @@ -110,6 +113,102 @@ public class TriangleSet extends Node { } } + public void generateTriangles(Action action, TriangleCallback cb) { + State state = action.getState(); + FloatBuffer coords = null; + FloatBuffer texCoords = null; + // FIXME: normals and lighting not supported yet + // FloatBuffer normals = null; + FloatBuffer colors = null; + if (CoordinateElement.isEnabled(state)) { + coords = CoordinateElement.get(state); + } + // No point in continuing if we don't have coordinates + if (coords == null) + return; + if (TextureCoordinateElement.isEnabled(state)) { + texCoords = TextureCoordinateElement.get(state); + } + // if (NormalElement.isEnabled(state)) { + // texCoords = NormalElement.get(state); + // } + if (ColorElement.isEnabled(state)) { + colors = ColorElement.get(state); + } + PrimitiveVertex v0 = new PrimitiveVertex(); + PrimitiveVertex v1 = new PrimitiveVertex(); + PrimitiveVertex v2 = new PrimitiveVertex(); + v0.setCoord(new Vec3f()); + v1.setCoord(new Vec3f()); + v2.setCoord(new Vec3f()); + if (texCoords != null) { + v0.setTexCoord(new Vec2f()); + v1.setTexCoord(new Vec2f()); + v2.setTexCoord(new Vec2f()); + } + if (colors != null) { + v0.setColor(new Vec4f()); + v1.setColor(new Vec4f()); + v2.setColor(new Vec4f()); + } + + int coordIdx = 0; + for (int i = 0; i < numTriangles; i++) { + // Vertex 0 + v0.getCoord().set(coords.get(3 * coordIdx + 0), + coords.get(3 * coordIdx + 1), + coords.get(3 * coordIdx + 2)); + if (texCoords != null) { + v0.getTexCoord().set(texCoords.get(2 * coordIdx + 0), + texCoords.get(2 * coordIdx + 1)); + } + if (colors != null) { + v0.getColor().set(colors.get(4 * coordIdx + 0), + colors.get(4 * coordIdx + 1), + colors.get(4 * coordIdx + 2), + colors.get(4 * coordIdx + 3)); + } + + // Vertex 1 + v1.getCoord().set(coords.get(3 * (coordIdx + 1) + 0), + coords.get(3 * (coordIdx + 1) + 1), + coords.get(3 * (coordIdx + 1) + 2)); + if (texCoords != null) { + v1.getTexCoord().set(texCoords.get(2 * (coordIdx + 1) + 0), + texCoords.get(2 * (coordIdx + 1) + 1)); + } + if (colors != null) { + v1.getColor().set(colors.get(4 * (coordIdx + 1) + 0), + colors.get(4 * (coordIdx + 1) + 1), + colors.get(4 * (coordIdx + 1) + 2), + colors.get(4 * (coordIdx + 1) + 3)); + } + + // Vertex 2 + v2.getCoord().set(coords.get(3 * (coordIdx + 2) + 0), + coords.get(3 * (coordIdx + 2) + 1), + coords.get(3 * (coordIdx + 2) + 2)); + if (texCoords != null) { + v2.getTexCoord().set(texCoords.get(2 * (coordIdx + 2) + 0), + texCoords.get(2 * (coordIdx + 2) + 1)); + } + if (colors != null) { + v2.getColor().set(colors.get(4 * (coordIdx + 2) + 0), + colors.get(4 * (coordIdx + 2) + 1), + colors.get(4 * (coordIdx + 2) + 2), + colors.get(4 * (coordIdx + 2) + 3)); + } + + // Call callback + cb.triangleCB(i, + v0, 3 * i + 0, + v1, 3 * i + 1, + v2, 3 * i + 2); + + coordIdx += 3; + } + } + // Helper routine for setting up a texture matrix to allow texture // coords in the scene graph to always be specified from (0..1) private Mat4f textureMatrix = new Mat4f(); diff --git a/src/net/java/joglutils/msg/test/DisplayShelf.java b/src/net/java/joglutils/msg/test/DisplayShelf.java index 73a63de..c6ae2b7 100644 --- a/src/net/java/joglutils/msg/test/DisplayShelf.java +++ b/src/net/java/joglutils/msg/test/DisplayShelf.java @@ -73,6 +73,7 @@ public class DisplayShelf extends Container { static class TitleGraph { String url; + Separator sep = new Separator(); Transform xform = new Transform(); Texture2 texture = new Texture2(); Coordinate3 coords = new Coordinate3(); @@ -83,9 +84,11 @@ public class DisplayShelf extends Container { } private Group root; + private Separator imageRoot; private String[] images; private List<TitleGraph> titles = new ArrayList<TitleGraph>(); private int targetIndex; + private JSlider slider; // This encodes both the current position and the animation alpha private float currentIndex; // If the difference between the current index and target index is > @@ -130,7 +133,7 @@ public class DisplayShelf extends Container { final List<TitleGraph> queuedGraphs = new ArrayList<TitleGraph>(); queuedGraphs.addAll(titles); - new Thread(new Runnable() { + Thread loaderThread = new Thread(new Runnable() { public void run() { while (queuedGraphs.size() > 0) { TitleGraph graph = queuedGraphs.remove(0); @@ -152,7 +155,10 @@ public class DisplayShelf extends Container { } } } - }).start(); + }); + // Avoid having the loader thread preempt the rendering thread + loaderThread.setPriority(Thread.MIN_PRIORITY + 1); + loaderThread.start(); } private void setTargetIndex(int index) { @@ -219,8 +225,9 @@ public class DisplayShelf extends Container { camera.setFarDistance(20.0f); canvas = new GLCanvas(); canvas.addGLEventListener(new Listener()); + canvas.addMouseListener(new MListener()); add(canvas, BorderLayout.CENTER); - final JSlider slider = new JSlider(0, images.length - 1, 0); + slider = new JSlider(0, images.length - 1, 0); slider.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { setTargetIndex(slider.getValue()); @@ -239,7 +246,7 @@ public class DisplayShelf extends Container { root.removeAllChildren(); // The images - Separator imageRoot = new Separator(); + imageRoot = new Separator(); // The mirrored images, under the floor Separator mirrorRoot = new Separator(); @@ -274,7 +281,7 @@ public class DisplayShelf extends Container { titles.add(graph); computeCoords(graph.coords, DEFAULT_ASPECT_RATIO); graph.xform.getTransform().setTranslation(new Vec3f(i, 0, 0)); - Separator sep = new Separator(); + Separator sep = graph.sep; sep.addChild(graph.xform); sep.addChild(graph.coords); sep.addChild(graph.texture); @@ -375,6 +382,27 @@ public class DisplayShelf extends Container { public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {} } + class MListener extends MouseAdapter { + RayPickAction ra = new RayPickAction(); + + public void mousePressed(MouseEvent e) { + ra.setPoint(e.getX(), e.getY(), e.getComponent()); + // Apply to the scene root + ra.apply(root); + List<PickedPoint> pickedPoints = ra.getPickedPoints(); + Path p = null; + if (!pickedPoints.isEmpty()) + p = pickedPoints.get(0).getPath(); + if (p != null && p.size() > 1) { + int idx = imageRoot.findChild(p.get(p.size() - 2)); + if (idx >= 0) { + // Need to keep the slider and this mechanism in sync + slider.setValue(idx); + } + } + } + } + public static void main(String[] args) { Frame f = new Frame("Display Shelf test"); f.setLayout(new BorderLayout()); @@ -390,33 +418,58 @@ public class DisplayShelf extends Container { // The images to configure the shelf with String[] images = { - "http://a1.phobos.apple.com/r10/Music/05/7d/c3/dj.umbuvrfe.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/cb/9a/b3/mzi.krksguze.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/94/8d/83/dj.jionwnuf.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/26/43/02/dj.dgnjindw.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/69/2a/63/mzi.wpfmtfzp.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/17/e1/88/dj.gcajwhco.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/21/f6/32/dj.glzycglj.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/d1/6b/3b/mzi.pajmxsmk.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/f6/a7/b2/dj.lamcsbwx.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/84/a5/4f/dj.nqvsikaq.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/7d/c3/23/dj.elyzoipc.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/80/a5/8c/dj.oidpsvzg.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/d1/b2/cf/dj.moyzjiht.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/49/a3/59/mzi.ssjpuxwt.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/9b/8f/7c/dj.qizpbris.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/b1/4f/c8/dj.uadqyjbr.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/d4/31/df/mzi.pqzeferc.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/4b/88/a7/dj.jhotijvb.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/a8/a9/36/dj.asztraij.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/d6/6b/c4/mzi.dricykdh.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Features/d4/81/a3/dj.tpysowpf.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/4f/2c/a6/dj.cawuddxy.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/d8/9c/8a/mzi.vmajyyha.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/00/5c/31/mzi.tuyoxwib.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/da/c8/e2/mzi.sanzeosx.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/43/cc/0e/dj.zfqfgoas.200x200-75.jpg", - "http://a1.phobos.apple.com/r10/Music/73/70/13/mzi.uswlslxx.200x200-75.jpg" + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.jsepedzf.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.wvbmknhn.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.oorrjicu.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.woofnkar.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.tapbaxpy.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.awlngumx.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.bpuzrjch.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.nqarjlzt.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.hgadlawz.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.sdfnrwzj.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.vtbicehh.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.lhgtckcs.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.tbwyqyqm.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.eimndamh.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.nxvdfcwt.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.njoydoqk.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.ikfbfqzh.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.niqwioqm.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.tqqldmqe.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.ynokefwv.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.jodjmgxs.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.yhdaeino.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.xmgrrxef.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.pahnmknr.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.sbkwhrik.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.hwbcjnfx.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.umbuvrfe.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.krksguze.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.jionwnuf.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.dgnjindw.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.wpfmtfzp.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.gcajwhco.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.glzycglj.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.pajmxsmk.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.lamcsbwx.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.nqvsikaq.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.elyzoipc.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.oidpsvzg.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.moyzjiht.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.qizpbris.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.uadqyjbr.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.pqzeferc.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.jhotijvb.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.asztraij.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.dricykdh.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.tpysowpf.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.cawuddxy.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.vmajyyha.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.tuyoxwib.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.sanzeosx.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/dj.zfqfgoas.200x200-75.jpg", + "http://download.java.net/media/jogl/builds/ds_tmp/mzi.uswlslxx.200x200-75.jpg" }; Separator root = new Separator(); |