From 2179980ed660ef66a9c064d153c5de7994d431ab Mon Sep 17 00:00:00 2001 From: Kenneth Russel Date: Wed, 25 Jun 2003 09:05:29 +0000 Subject: Split up net.java.games.util; moved GLUT and BufferUtils into net.java.games.jogl.util, and moved demo-specific utility classes into jogl-demos project under demos.util. Added nearly all JavaOne demos into jogl-demos project; rewrote where necessary to use ClassLoader.getResourceAsStream() instead of flat files, put into packages and added to Makefile. Added gleem to jogl-demos project. Added jogl.jar build rule. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@3 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4 --- src/gleem/BSphere.java | 166 ++++ src/gleem/BSphereProvider.java | 46 ++ src/gleem/CameraParameters.java | 153 ++++ src/gleem/ExaminerViewer.java | 605 +++++++++++++++ src/gleem/HandleBoxManip.java | 948 +++++++++++++++++++++++ src/gleem/HitPoint.java | 73 ++ src/gleem/Manip.java | 120 +++ src/gleem/ManipManager.java | 404 ++++++++++ src/gleem/ManipMotionListener.java | 47 ++ src/gleem/ManipPart.java | 94 +++ src/gleem/ManipPartCube.java | 102 +++ src/gleem/ManipPartGroup.java | 133 ++++ src/gleem/ManipPartLineSeg.java | 163 ++++ src/gleem/ManipPartSquare.java | 82 ++ src/gleem/ManipPartTransform.java | 72 ++ src/gleem/ManipPartTriBased.java | 292 +++++++ src/gleem/ManipPartTwoWayArrow.java | 126 +++ src/gleem/MouseButtonHelper.java | 75 ++ src/gleem/NormalCalc.java | 118 +++ src/gleem/RayTriangleIntersection.java | 226 ++++++ src/gleem/RightTruncPyrMapping.java | 64 ++ src/gleem/ScreenToRayMapping.java | 73 ++ src/gleem/TestExaminerViewer.java | 153 ++++ src/gleem/TestHandleBox.java | 142 ++++ src/gleem/TestMultiWin.java | 162 ++++ src/gleem/TestTranslate1.java | 143 ++++ src/gleem/TestTranslate2.java | 143 ++++ src/gleem/Translate1Manip.java | 208 +++++ src/gleem/Translate2Manip.java | 230 ++++++ src/gleem/WindowUpdateListener.java | 51 ++ src/gleem/linalg/DimensionMismatchException.java | 53 ++ src/gleem/linalg/IntersectionPoint.java | 63 ++ src/gleem/linalg/Line.java | 152 ++++ src/gleem/linalg/Mat2f.java | 169 ++++ src/gleem/linalg/Mat3f.java | 194 +++++ src/gleem/linalg/Mat4f.java | 265 +++++++ src/gleem/linalg/Matf.java | 168 ++++ src/gleem/linalg/MathUtil.java | 90 +++ src/gleem/linalg/NonSquareMatrixException.java | 53 ++ src/gleem/linalg/Plane.java | 121 +++ src/gleem/linalg/PlaneUV.java | 203 +++++ src/gleem/linalg/Rotf.java | 309 ++++++++ src/gleem/linalg/SingularMatrixException.java | 53 ++ src/gleem/linalg/Vec2f.java | 182 +++++ src/gleem/linalg/Vec3d.java | 175 +++++ src/gleem/linalg/Vec3f.java | 232 ++++++ src/gleem/linalg/Vec4f.java | 216 ++++++ src/gleem/linalg/Vecf.java | 96 +++ src/gleem/linalg/Veci.java | 96 +++ src/gleem/linalg/package.html | 13 + src/gleem/package.html | 13 + 51 files changed, 8330 insertions(+) create mode 100644 src/gleem/BSphere.java create mode 100644 src/gleem/BSphereProvider.java create mode 100644 src/gleem/CameraParameters.java create mode 100644 src/gleem/ExaminerViewer.java create mode 100644 src/gleem/HandleBoxManip.java create mode 100644 src/gleem/HitPoint.java create mode 100644 src/gleem/Manip.java create mode 100644 src/gleem/ManipManager.java create mode 100644 src/gleem/ManipMotionListener.java create mode 100644 src/gleem/ManipPart.java create mode 100644 src/gleem/ManipPartCube.java create mode 100644 src/gleem/ManipPartGroup.java create mode 100644 src/gleem/ManipPartLineSeg.java create mode 100644 src/gleem/ManipPartSquare.java create mode 100644 src/gleem/ManipPartTransform.java create mode 100644 src/gleem/ManipPartTriBased.java create mode 100644 src/gleem/ManipPartTwoWayArrow.java create mode 100644 src/gleem/MouseButtonHelper.java create mode 100644 src/gleem/NormalCalc.java create mode 100644 src/gleem/RayTriangleIntersection.java create mode 100644 src/gleem/RightTruncPyrMapping.java create mode 100644 src/gleem/ScreenToRayMapping.java create mode 100644 src/gleem/TestExaminerViewer.java create mode 100644 src/gleem/TestHandleBox.java create mode 100644 src/gleem/TestMultiWin.java create mode 100644 src/gleem/TestTranslate1.java create mode 100644 src/gleem/TestTranslate2.java create mode 100644 src/gleem/Translate1Manip.java create mode 100644 src/gleem/Translate2Manip.java create mode 100644 src/gleem/WindowUpdateListener.java create mode 100644 src/gleem/linalg/DimensionMismatchException.java create mode 100644 src/gleem/linalg/IntersectionPoint.java create mode 100644 src/gleem/linalg/Line.java create mode 100644 src/gleem/linalg/Mat2f.java create mode 100644 src/gleem/linalg/Mat3f.java create mode 100644 src/gleem/linalg/Mat4f.java create mode 100644 src/gleem/linalg/Matf.java create mode 100644 src/gleem/linalg/MathUtil.java create mode 100644 src/gleem/linalg/NonSquareMatrixException.java create mode 100644 src/gleem/linalg/Plane.java create mode 100644 src/gleem/linalg/PlaneUV.java create mode 100644 src/gleem/linalg/Rotf.java create mode 100644 src/gleem/linalg/SingularMatrixException.java create mode 100644 src/gleem/linalg/Vec2f.java create mode 100644 src/gleem/linalg/Vec3d.java create mode 100644 src/gleem/linalg/Vec3f.java create mode 100644 src/gleem/linalg/Vec4f.java create mode 100644 src/gleem/linalg/Vecf.java create mode 100644 src/gleem/linalg/Veci.java create mode 100644 src/gleem/linalg/package.html create mode 100644 src/gleem/package.html (limited to 'src/gleem') diff --git a/src/gleem/BSphere.java b/src/gleem/BSphere.java new file mode 100644 index 0000000..c628bc9 --- /dev/null +++ b/src/gleem/BSphere.java @@ -0,0 +1,166 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/** Represents a bounding sphere. */ + +public class BSphere { + private Vec3f center = new Vec3f(); + private float radius; + private float radSq; + + /** Default constructor creates a sphere with center (0, 0, 0) and + radius 0 */ + public BSphere() { + makeEmpty(); + } + + public BSphere(Vec3f center, float radius) { + set(center, radius); + } + + /** Re-initialize this sphere to center (0, 0, 0) and radius 0 */ + public void makeEmpty() { + center.set(0, 0, 0); + radius = radSq = 0; + } + + public void setCenter(Vec3f center) { this.center.set(center); } + public Vec3f getCenter() { return center; } + + public void setRadius(float radius) { this.radius = radius; + radSq = radius * radius; } + public float getRadius() { return radius; } + + public void set(Vec3f center, float radius) { + setCenter(center); setRadius(radius); + } + /** Returns radius and mutates passed "center" vector */ + float get(Vec3f center) { + center.set(this.center); return radius; + } + + /** Mutate this sphere to encompass both itself and the argument. + Ignores zero-size arguments. */ + public void extendBy(BSphere arg) { + if ((radius == 0.0f) || (arg.radius == 0.0f)) + return; + // FIXME: This algorithm is a quick hack -- minimum bounding + // sphere of a set of other spheres is a well studied problem, but + // not by me + Vec3f diff = arg.center.minus(center); + if (diff.lengthSquared() == 0.0f) { + setRadius(Math.max(radius, arg.radius)); + return; + } + IntersectionPoint[] intPt = new IntersectionPoint[4]; + for (int i = 0; i < intPt.length; i++) { + intPt[i] = new IntersectionPoint(); + } + int numIntersections; + numIntersections = intersectRay(center, diff, intPt[0], intPt[1]); + assert numIntersections == 2; + numIntersections = intersectRay(center, diff, intPt[2], intPt[3]); + assert numIntersections == 2; + IntersectionPoint minIntPt = intPt[0]; + IntersectionPoint maxIntPt = intPt[0]; + // Find minimum and maximum t values, take associated intersection + // points, find midpoint and half length of line segment --> + // center and radius. + for (int i = 0; i < 4; i++) { + if (intPt[i].getT() < minIntPt.getT()) { + minIntPt = intPt[i]; + } else if (intPt[i].getT() > maxIntPt.getT()) { + maxIntPt = intPt[i]; + } + } + // Compute the average -- this is the new center + center.add(minIntPt.getIntersectionPoint(), + maxIntPt.getIntersectionPoint()); + center.scale(0.5f); + // Compute half the length -- this is the radius + setRadius( + 0.5f * + minIntPt.getIntersectionPoint(). + minus(maxIntPt.getIntersectionPoint()). + length() + ); + } + + /** Intersect a ray with the sphere. This is a one-sided ray + cast. Mutates one or both of intPt0 and intPt1. Returns number + of intersections which occurred. */ + int intersectRay(Vec3f rayStart, + Vec3f rayDirection, + IntersectionPoint intPt0, + IntersectionPoint intPt1) { + // Solve quadratic equation + float a = rayDirection.lengthSquared(); + if (a == 0.0) + return 0; + float b = 2.0f * (rayStart.dot(rayDirection) - rayDirection.dot(center)); + Vec3f tempDiff = center.minus(rayStart); + float c = tempDiff.lengthSquared() - radSq; + float disc = b * b - 4 * a * c; + if (disc < 0.0f) + return 0; + int numIntersections; + if (disc == 0.0f) + numIntersections = 1; + else + numIntersections = 2; + intPt0.setT((0.5f * (-1.0f * b + (float) Math.sqrt(disc))) / a); + if (numIntersections == 2) + intPt1.setT((0.5f * (-1.0f * b - (float) Math.sqrt(disc))) / a); + Vec3f tmp = new Vec3f(rayDirection); + tmp.scale(intPt0.getT()); + tmp.add(tmp, rayStart); + intPt0.setIntersectionPoint(tmp); + if (numIntersections == 2) { + tmp.set(rayDirection); + tmp.scale(intPt1.getT()); + tmp.add(tmp, rayStart); + intPt1.setIntersectionPoint(tmp); + } + return numIntersections; + } +} diff --git a/src/gleem/BSphereProvider.java b/src/gleem/BSphereProvider.java new file mode 100644 index 0000000..17b130c --- /dev/null +++ b/src/gleem/BSphereProvider.java @@ -0,0 +1,46 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +/** Provides a bounding sphere to an arbitrary client. */ + +public interface BSphereProvider { + public BSphere getBoundingSphere(); +} diff --git a/src/gleem/CameraParameters.java b/src/gleem/CameraParameters.java new file mode 100644 index 0000000..658820d --- /dev/null +++ b/src/gleem/CameraParameters.java @@ -0,0 +1,153 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/** Container class for camera's parameters. */ + +public class CameraParameters { + private Vec3f position = new Vec3f(); + private Vec3f forwardDirection = new Vec3f(); + private Vec3f upDirection = new Vec3f(); + private Rotf orientation = new Rotf(); + private Mat4f modelviewMatrix = new Mat4f(); + private Mat4f projectionMatrix = new Mat4f(); + float vertFOV; + float imagePlaneAspectRatio; + int xSize; + int ySize; + + public CameraParameters() {} + + public CameraParameters(Vec3f position, + Vec3f forwardDirection, + Vec3f upDirection, + Rotf orientation, + float vertFOV, + float imagePlaneAspectRatio, + int xSize, + int ySize) { + setPosition(position); + setForwardDirection(forwardDirection); + setUpDirection(upDirection); + setOrientation(orientation); + setVertFOV(vertFOV); + setImagePlaneAspectRatio(imagePlaneAspectRatio); + setXSize(xSize); + setYSize(ySize); + } + + public void set(CameraParameters params) { + setPosition(params.getPosition()); + setForwardDirection(params.getForwardDirection()); + setUpDirection(params.getUpDirection()); + setVertFOV(params.getVertFOV()); + setImagePlaneAspectRatio(params.getImagePlaneAspectRatio()); + setXSize(params.getXSize()); + setYSize(params.getYSize()); + } + + /** Sets 3-space origin of camera */ + public void setPosition(Vec3f position) { this.position.set(position); } + /** Gets 3-space origin of camera */ + public Vec3f getPosition() { return position; } + /** Sets 3-space forward direction of camera. Does not need to be + normalized. */ + public void setForwardDirection(Vec3f fwd) { forwardDirection.set(fwd); } + /** Gets 3-space forward direction of camera. */ + public Vec3f getForwardDirection() { return forwardDirection; } + /** Sets 3-space upward direction of camera. This must be orthogonal + to the viewing direction, but does not need to be normalized. */ + public void setUpDirection(Vec3f up) { upDirection.set(up); } + /** Gets 3-space upward direction of camera. */ + public Vec3f getUpDirection() { return upDirection; } + /** Sets orientation of camera. NOTE: user is responsible for + ensuring this corresponds with the up and forward vectors. */ + public void setOrientation(Rotf orientation) { this.orientation.set(orientation); } + /** Gets orientation of camera. */ + public Rotf getOrientation() { return orientation; } + /** Sets the modelview matrix corresponding to the orientation and + position of the camera. NOTE: user is responsible for ensuring + this corresponds to the rest of the camera parameters. */ + public void setModelviewMatrix(Mat4f matrix) { + modelviewMatrix.set(matrix); + } + /** Gets the modelview matrix corresponding to the orientation and + position of the camera. */ + public Mat4f getModelviewMatrix() { + return modelviewMatrix; + } + /** Sets the projection matrix corresponding to the camera's + field-of-view and aspect ratio parameters. NOTE: user is + responsible for ensuring this matrix corresponds to these + parameters.*/ + public void setProjectionMatrix(Mat4f matrix) { + projectionMatrix.set(matrix); + } + /** Gets the projection matrix corresponding to the camera's + field-of-view and aspect ratio parameters. */ + public Mat4f getProjectionMatrix() { + return projectionMatrix; + } + + /** Takes HALF of the vertical angular span of the frustum, + specified in radians. For example, if your fovy argument + to gluPerspective() is 90, then this would be Math.PI / 4. */ + public void setVertFOV(float vertFOV) { this.vertFOV = vertFOV; } + /** Returns HALF of the vertical angular span of the frustum, + specified in radians. */ + public float getVertFOV() { return vertFOV; } + /** Sets the aspect ratio of the image plane. Note that this does not + necessarily have to correspond to the aspect ratio of the + window. */ + public void setImagePlaneAspectRatio(float ratio) { imagePlaneAspectRatio = ratio; } + /** Gets the aspect ratio of the image plane. */ + public float getImagePlaneAspectRatio() { return imagePlaneAspectRatio; } + + /** Sets the horizontal size of the window, in pixels */ + public void setXSize(int xSize) { this.xSize = xSize; } + /** Gets the horizontal size of the window, in pixels */ + public int getXSize() { return xSize; } + /** Sets the vertical size of the window, in pixels */ + public void setYSize(int ySize) { this.ySize = ySize; } + /** Gets the vertical size of the window, in pixels */ + public int getYSize() { return ySize; } +} diff --git a/src/gleem/ExaminerViewer.java b/src/gleem/ExaminerViewer.java new file mode 100644 index 0000000..2cb2f05 --- /dev/null +++ b/src/gleem/ExaminerViewer.java @@ -0,0 +1,605 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.Dimension; +import java.awt.event.*; +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/**

This is an application-level class, not part of the + manipulator hierarchy. It is an example of how you might integrate + gleem with another application which uses the mouse.

+ +

For the given GLDrawable, the ExaminerViewer takes over the + setting of the view position. It passes along mouse events it is + not interested in to the ManipManager's mouse routines.

+ +

The ExaminerViewer's controls are similar to those of Open + Inventor's Examiner Viewer. Alt + Left mouse button causes + rotation about the focal point. Alt + Right mouse button causes + translation parallel to the image plane. Alt + both mouse buttons, + combined with up/down mouse motion, causes zooming out and in + along the view vector. (On platforms with a "Meta" key, that key + can be substituted in place of the Alt key.) The method + setNoAltKeyMode can be used to cause the + ExaminerViewer to take control of all mouse interactions in the + window, avoiding the need to hold down the Alt key.

+ +

NOTE: the current ExaminerViewer implementation assumes a + minimum of two mouse buttons. For the Mac OS, the code needs to be + adjusted to use e.g., the Control key as the "right" mouse + button.

*/ + +public class ExaminerViewer { + private GLDrawable window; + /** Simple state machine for figuring out whether we are grabbing + events */ + private boolean interactionUnderway; + private boolean iOwnInteraction; + + private boolean noAltKeyMode; + + /** Simple state machine for computing distance dragged */ + private boolean button1Down; + private boolean button2Down; + private int numMouseButtons; + private int oldNumMouseButtons; + private int lastX; + private int lastY; + + /** Camera parameters */ + private float minFocalDist = 1.0f; + private Vec3f dolly = new Vec3f(0, 0, 10); // Amount we have "backed up" from focal point + private Vec3f center = new Vec3f(0, 0, 0); // Position of focal point in world coordinates + private Rotf orientation = new Rotf(); + private float rotateSpeed = 1.0f; + private float minRotateSpeed = 0.0001f; + private float dollySpeed = 2.0f; + private float minDollySpeed = 0.0001f; + private float zNear = 1.0f; + private float zFar = 100.0f; + private float vertFOVScale = 1.0f; + private CameraParameters params = new CameraParameters(); + + /** Our bounding sphere provider (for viewAll()) */ + private BSphereProvider provider; + + private MouseMotionAdapter mouseMotionListener = new MouseMotionAdapter() { + public void mouseDragged(MouseEvent e) { + motionMethod(e, e.getX(), e.getY()); + } + + public void mouseMoved(MouseEvent e) { + passiveMotionMethod(e); + } + }; + + private MouseAdapter mouseListener = new MouseAdapter() { + public void mousePressed(MouseEvent e) { + mouseMethod(e, e.getModifiers(), true, e.getX(), e.getY()); + } + + public void mouseReleased(MouseEvent e) { + mouseMethod(e, e.getModifiers(), false, e.getX(), e.getY()); + } + }; + + private GLEventListener glListener = new GLEventListener() { + public void init(GLDrawable drawable) {} + public void display(GLDrawable drawable) {} + public void reshape(GLDrawable drawable, int x, int y, int width, int height) { + reshapeMethod(width, height); + } + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + }; + + /** The constructor takes the number of mouse buttons on this system + (couldn't figure out how to determine this internally) */ + public ExaminerViewer(int numMouseButtons) { + this.numMouseButtons = numMouseButtons; + oldNumMouseButtons = numMouseButtons; + } + + /**

Attaches this ExaminerViewer to the given GLDrawable. This + causes the ManipManager's mouse routines to be removed from the + window (using ManipManager.removeMouseListeners) and the + ExaminerViewer's to be installed. The GLDrawable should be + registered with the ManipManager before the ExaminerViewer is + attached to it.

+ +

In order for the viewer to do anything useful, you need to + provide a BSphereProvider to it to allow "view all" + functionality.

*/ + public void attach(GLDrawable window, BSphereProvider provider) { + this.window = window; + this.provider = provider; + init(); + setupListeners(); + } + + /** Detaches from the given window. This causes the ManipManager's + mouse listeners to be reinstalled on the GLDrawable and the + ExaminerViewer's to be removed. */ + public void detach() { + removeListeners(); + this.window = null; + this.provider = null; + } + + /** Call this at the end of your display() method to cause the + Modelview matrix to be recomputed for the next frame. */ + public void update(GL gl) { + recalc(gl); + } + + /** Call this to apply the inverse rotation matrix of the camera to + the current matrix. This is useful for drawing a skybox. Does + not update which OpenGL matrix is currently being modified or + the ExaminerViewer's camera parameters. */ + public void updateInverseRotation(GL gl) { + recalcInverseRotation(gl); + } + + /** Call this to force the ExaminerViewer to update its + CameraParameters without touching the OpenGL state. */ + public void update() { + recalc(); + } + + /** Call this from within your display() method to cause the + ExaminerViewer to recompute its position based on the visible + geometry. A BSphereProvider must have already been set or this + method has no effect. */ + public void viewAll(GL gl) { + if (provider == null) { + return; + } + // Figure out how far to move + float vertFOV, horizFOV, minFOV; + float adjustedVertFOV = params.getVertFOV() * vertFOVScale; + vertFOV = 2.0f * adjustedVertFOV; + horizFOV = 2.0f * (float) Math.atan(params.getImagePlaneAspectRatio() * + Math.tan(adjustedVertFOV)); + if (vertFOV < horizFOV) + minFOV = vertFOV; + else + minFOV = horizFOV; + if (minFOV == 0.0f) { + throw new RuntimeException("Minimum field of view was zero"); + } + BSphere bsph = provider.getBoundingSphere(); + float dist = bsph.getRadius() / (float) Math.sin(minFOV / 2.0f); + dolly.setZ(dist); + center.set(bsph.getCenter()); + recalc(gl); + } + + /** Get the camera parameters out of this Examiner Viewer (for + example, to pass to ManipManager.updateCameraParameters()). Note + that mutating the returned object is not recommended but + regardless will have no effect on the ExaminerViewer. */ + public CameraParameters getCameraParameters() { + return params; + } + + /** These routines can be hooked into a GUI by calling them from + ActionEvent listeners for buttons elsewhere in the application. */ + public void rotateFaster() { + rotateSpeed *= 2.0f; + } + + public void rotateSlower() { + if (rotateSpeed < minRotateSpeed) + return; + else + rotateSpeed /= 2.0f; + } + + public void dollyFaster() { + dollySpeed *= 2.0f; + } + + public void dollySlower() { + if (dollySpeed < minDollySpeed) + return; + else + dollySpeed /= 2.0f; + } + + public float getZNear() { + return zNear; + } + + public void setZNear(float zNear) { + this.zNear = zNear; + } + + public float getZFar() { + return zFar; + } + + public void setZFar(float zFar) { + this.zFar = zFar; + } + + /** Takes HALF of the vertical angular span of the frustum, + specified in radians. For example, if your fovy argument + to gluPerspective() is 90, then this would be Math.PI / 4. Note + that the ExaminerViewer's algorithms break down if the vertical + field of view approaches or exceeds 180 degrees, or Math.PI / + 2. */ + public void setVertFOV(float vertFOV) { + vertFOVScale = (float) (vertFOV / (Math.PI / 4)); + } + + /** Sets the position of this ExaminerViewer. */ + public void setPosition(Vec3f position) { + Vec3f tmp = orientation.rotateVector(Vec3f.NEG_Z_AXIS); + tmp.scale(dolly.z()); + center.add(position, tmp); + } + + /** Sets the orientation of this ExaminerViewer. */ + public void setOrientation(Rotf orientation) { + this.orientation.set(orientation); + } + + public void setNoAltKeyMode(boolean noAltKeyMode) { + this.noAltKeyMode = noAltKeyMode; + if (noAltKeyMode) { + // FIXME: this is a hack to work around Windows' apparently + // conflating the alt/meta key with one of the mouse buttons + oldNumMouseButtons = numMouseButtons; + numMouseButtons = 3; + } else { + numMouseButtons = oldNumMouseButtons; + } + } + + public boolean getNoAltKeyMode() { + return noAltKeyMode; + } + + /** Rotates this ExaminerViewer about the focal point by the + specified incremental rotation; performs postmultiplication, + i.e. the incremental rotation is applied after the current + orientation. */ + public void rotateAboutFocalPoint(Rotf rot) { + orientation = rot.times(orientation); + orientation.normalize(); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private static final float EPSILON = 0.0001f; + + private void setupListeners() { + ManipManager.getManipManager().removeMouseListeners(window); + window.addMouseMotionListener(mouseMotionListener); + window.addMouseListener(mouseListener); + window.addGLEventListener(glListener); + } + + private void removeListeners() { + window.removeMouseMotionListener(mouseMotionListener); + window.removeMouseListener(mouseListener); + window.removeGLEventListener(glListener); + ManipManager.getManipManager().setupMouseListeners(window); + } + + private void passiveMotionMethod(MouseEvent e) { + ManipManager.getManipManager().mouseMoved(e); + } + + private boolean modifiersMatch(MouseEvent e, int mods) { + if (noAltKeyMode) { + if ((mods & MouseEvent.BUTTON1_MASK) != 0 && + (mods & MouseEvent.BUTTON2_MASK) == 0 && + (mods & MouseEvent.BUTTON3_MASK) == 0) { + return (!e.isAltDown() && !e.isMetaDown() && !e.isControlDown() && !e.isShiftDown()); + } else { + // At least on Windows, meta seems to be declared to be down on right button presses + return !e.isControlDown() && !e.isShiftDown(); + } + } else { + return ((e.isAltDown() || e.isMetaDown()) && + (!e.isControlDown() && !e.isShiftDown())); + } + } + + private void init() { + interactionUnderway = false; + iOwnInteraction = false; + button1Down = false; + button2Down = false; + + Dimension size = window.getSize(); + int xSize = size.width; + int ySize = size.height; + params.setOrientation(orientation); + params.setPosition(computePosition(new Vec3f())); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) Math.PI / 8.0f); + params.setImagePlaneAspectRatio((float) xSize / (float) ySize); + params.setXSize(xSize); + params.setYSize(ySize); + } + + private void motionMethod(MouseEvent e, int x, int y) { + if (interactionUnderway && !iOwnInteraction) { + ManipManager.getManipManager().mouseDragged(e); + } else { + int dx = x - lastX; + int dy = y - lastY; + + lastX = x; + lastY = y; + + if ((button1Down && (!button2Down))) { + + // Rotation functionality + float xRads = (float) Math.PI * -1.0f * dy * rotateSpeed / 1000.0f; + float yRads = (float) Math.PI * -1.0f * dx * rotateSpeed / 1000.0f; + Rotf xRot = new Rotf(Vec3f.X_AXIS, xRads); + Rotf yRot = new Rotf(Vec3f.Y_AXIS, yRads); + Rotf newRot = yRot.times(xRot); + orientation = orientation.times(newRot); + + } else if (button2Down && (!button1Down)) { + + // Translate functionality + // Compute the local coordinate system's difference vector + Vec3f localDiff = new Vec3f(dollySpeed * -1.0f * dx / 100.0f, + dollySpeed * dy / 100.0f, + 0.0f); + // Rotate this by camera's orientation + Vec3f worldDiff = orientation.rotateVector(localDiff); + // Add on to center + center.add(worldDiff); + + } else if (button1Down && button2Down) { + + float diff = dollySpeed * -1.0f * dy / 100.0f; + float newDolly = dolly.z() + diff; + if (newDolly < minFocalDist) { + newDolly = minFocalDist; + } + dolly.setZ(newDolly); + + } + + // Force redraw if window will not do it automatically + if (!window.getNoAutoRedrawMode()) { + window.display(); + } + } + } + + private void mouseMethod(MouseEvent e, int mods, boolean press, + int x, int y) { + if ((interactionUnderway && !iOwnInteraction) || + (!modifiersMatch(e, mods))) { + // Update state and pass this event along to the ManipManager + if (press) { + interactionUnderway = true; + iOwnInteraction = false; + ManipManager.getManipManager().mousePressed(e); + } else { + interactionUnderway = false; + iOwnInteraction = false; + ManipManager.getManipManager().mouseReleased(e); + } + } else { + if ((mods & MouseEvent.BUTTON1_MASK) != 0) { + if (press) { + button1Down = true; + } else { + button1Down = false; + } + } else { + if (numMouseButtons != 3) { + if ((mods & MouseEvent.BUTTON2_MASK) != 0) { + if (press) { + button2Down = true; + } else { + button2Down = false; + } + } + } else { + // FIXME: must test this on 3-button system + if ((mods & MouseEvent.BUTTON3_MASK) != 0) { + if (press) { + button2Down = true; + } else { + button2Down = false; + } + } + } + } + + lastX = x; + lastY = y; + + if (button1Down || button2Down) { + interactionUnderway = true; + iOwnInteraction = true; + } else { + interactionUnderway = false; + iOwnInteraction = false; + } + + // Force redraw if window will not do it automatically + if (!window.getNoAutoRedrawMode()) { + window.display(); + } + } + } + + private void reshapeMethod(int w, int h) { + float aspect, theta; + aspect = (float) w / (float) h; + if (w >= h) + theta = 45; + else + theta = (float) Math.toDegrees(Math.atan(1 / aspect)); + theta *= vertFOVScale; + params.setVertFOV((float) (Math.toRadians(theta) / 2.0)); + params.setImagePlaneAspectRatio(aspect); + params.setXSize(w); + params.setYSize(h); + } + + private void recalc() { + // Recompute position, forward and up vectors + Vec3f tmp = new Vec3f(); + params.setPosition(computePosition(tmp)); + orientation.rotateVector(Vec3f.NEG_Z_AXIS, tmp); + params.setForwardDirection(tmp); + orientation.rotateVector(Vec3f.Y_AXIS, tmp); + params.setUpDirection(tmp); + params.setOrientation(orientation); + + // Compute modelview matrix based on camera parameters, position and + // orientation + Mat4f tmpMat = new Mat4f(); + tmpMat.makeIdent(); + tmpMat.setRotation(orientation); + tmpMat.setTranslation(params.getPosition()); + tmpMat.invertRigid(); + params.setModelviewMatrix(tmpMat); + + // Compute perspective matrix given camera parameters + float deltaZ = zFar - zNear; + float aspect = params.getImagePlaneAspectRatio(); + float radians = params.getVertFOV(); + float sine = (float) Math.sin(radians); + if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { + tmpMat.makeIdent(); + params.setProjectionMatrix(tmpMat); + return; + } + float cotangent = (float) Math.cos(radians) / sine; + tmpMat.makeIdent(); + tmpMat.set(0, 0, cotangent / aspect); + tmpMat.set(1, 1, cotangent); + tmpMat.set(2, 2, -(zFar + zNear) / deltaZ); + tmpMat.set(3, 2, -1); + tmpMat.set(2, 3, -2 * zNear * zFar / deltaZ); + tmpMat.set(3, 3, 0); + params.setProjectionMatrix(tmpMat); + + + /******************** + + // Recompute position, forward and up vectors + params.setPosition(position); + Vec3f tmp = new Vec3f(); + orientation.rotateVector(Vec3f.NEG_Z_AXIS, tmp); + params.setForwardDirection(tmp); + orientation.rotateVector(Vec3f.Y_AXIS, tmp); + params.setUpDirection(tmp); + params.setOrientation(orientation); + + // Compute modelview matrix based on camera parameters, position and + // orientation + Mat4f tmpMat = new Mat4f(); + tmpMat.makeIdent(); + tmpMat.setRotation(orientation); + tmpMat.setTranslation(position); + tmpMat.invertRigid(); + params.setModelviewMatrix(tmpMat); + + // Compute perspective matrix given camera parameters + float deltaZ = zFar - zNear; + float aspect = params.getImagePlaneAspectRatio(); + float radians = params.getVertFOV(); + float sine = (float) Math.sin(radians); + if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) { + tmpMat.makeIdent(); + params.setProjectionMatrix(tmpMat); + return; + } + float cotangent = (float) Math.cos(radians) / sine; + tmpMat.makeIdent(); + tmpMat.set(0, 0, cotangent / aspect); + tmpMat.set(1, 1, cotangent); + tmpMat.set(2, 2, -(zFar + zNear) / deltaZ); + tmpMat.set(3, 2, -1); + tmpMat.set(2, 3, -2 * zNear * zFar / deltaZ); + tmpMat.set(3, 3, 0); + params.setProjectionMatrix(tmpMat); + + **********************/ + } + + private void recalc(GL gl) { + recalc(); + + gl.glMatrixMode(GL.GL_MODELVIEW); + float[] data = new float[16]; + params.getModelviewMatrix().getColumnMajorData(data); + gl.glLoadMatrixf(data); + + gl.glMatrixMode(GL.GL_PROJECTION); + params.getProjectionMatrix().getColumnMajorData(data); + gl.glLoadMatrixf(data); + } + + private void recalcInverseRotation(GL gl) { + Rotf oriInv = orientation.inverse(); + Vec3f tmp = new Vec3f(); + float ang = orientation.get(tmp); + gl.glLoadIdentity(); + if (tmp.lengthSquared() > EPSILON) + gl.glRotatef((float) Math.toDegrees(ang), tmp.x(), tmp.y(), tmp.z()); + } + + private Vec3f computePosition(Vec3f tmp) { + orientation.rotateVector(dolly, tmp); + tmp.add(center); + return tmp; + } +} diff --git a/src/gleem/HandleBoxManip.java b/src/gleem/HandleBoxManip.java new file mode 100644 index 0000000..bedde65 --- /dev/null +++ b/src/gleem/HandleBoxManip.java @@ -0,0 +1,948 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** Patterned after Inventor's HandleBoxManip (by Paul Isaacs and + David Mott) and TransformerManip (by Paul Isaacs). Center box + allows 3-D translation. Outer six handles allow rotation about the + box's six axes. When a handle is clicked, the axis of rotation is + immediately chosen as that which is most parallel to the viewing + direction (note there are at most two possibilities for the axis + of each handle's rotation). Eight corner handles allow aspect + ratio-preserving scaling; shift-dragging these handles allows + non-uniform scaling in one of two possible directions using a + "snap-to-axis" paradigm. These two directions are chosen as the + axes of the adjacent face to the handle whose normal most directly + faces the viewing direction. */ + +public class HandleBoxManip extends Manip { + private ManipPart parts; + private Vec3f translation; + private Vec3f scale; + private Vec3f geometryScale; + private Rotf rotation; + /** Cumulative transform of this object */ + private Mat4f xform; + + /** Dragging state */ + private static final int INACTIVE = 0; + private static final int TRANSLATE = 1; + private static final int ROTATE = 2; + // Scaling based on all three axes, preserving current aspect ratio + private static final int SCALE_XYZ = 3; + // Scaling along one of two axes (shift key + drag scale handle) + private static final int SCALE_SINGLE_AXIS = 4; + + private int dragState; + private Plane dragPlane; + private Vec3f dragOffset; + + /** Scale axes */ + private static final int SCALE_XY = 0; + private static final int SCALE_YZ = 1; + private static final int SCALE_ZX = 2; + + /** All of the line segments comprising the faces */ + private ManipPart[] lineSegs; + + static class FaceInfo { + ManipPart[] lineSegs; + /** The invisible square comprising this face's invisible, but + pickable, geometry */ + ManipPart centerSquare; + Vec3f origNormal; + Vec3f normal; + int scaleAxes; + + FaceInfo() { + lineSegs = new ManipPart[4]; + origNormal = new Vec3f(); + normal = new Vec3f(); + } + } + /** List */ + private List faces; + /** List */ + private List highlightedGeometry; + /** List */ + private List draggedGeometry; + + /** Each rotation handle points off to two faces corresponding to + the planes in which that handle can rotate. It also points to + two circles which appear during dragging to indicate to the user + in which plane the manipulator is being rotated. */ + static class RotateHandleInfo { + ManipPart geometry; + int faceIdx0; + int faceIdx1; + } + /** List */ + private List rotateHandles; + private PlaneUV rotatePlane; + private float startAngle; + private Rotf startRot; + + private int scaleAxes; + /** Each scale handle points off to its three adjacent faces. */ + static class ScaleHandleInfo { + ManipPart geometry; + /** The indices of the three adjacent faces */ + int[] faceIndices; + + ScaleHandleInfo() { + faceIndices = new int[3]; + } + } + /** List */ + private List scaleHandles; + // State variables for XYZ scaling + /** This line's direction must point outward from the center of the + cube. */ + private Line scaleXYZLine; + private float origScaleLen; + private Vec3f origScale; + // State variables for single-axis scaling + private PlaneUV scaleAxisPlane; + private Vec3f scaleAxisOffset; + private Vec2f scaleAxisOrigUV; + + /** Default HandleBoxManip has translation (0, 0, 0) and the + identity orientation */ + public HandleBoxManip() { + parts = new ManipPartTwoWayArrow(); + translation = new Vec3f(0, 0, 0); + scale = new Vec3f(1, 1, 1); + geometryScale = new Vec3f(1, 1, 1); + // Rotf should have a makeIdent() or at least initialize + // itself to the unit quaternion (see NOTES.txt) + rotation = new Rotf(); + xform = new Mat4f(); + + dragState = INACTIVE; + dragPlane = new Plane(); + dragOffset = new Vec3f(); + + lineSegs = new ManipPart[12]; + + faces = new ArrayList(); + highlightedGeometry = new ArrayList(); + draggedGeometry = new ArrayList(); + + rotateHandles = new ArrayList(); + rotatePlane = new PlaneUV(); + startRot = new Rotf(); + + scaleHandles = new ArrayList(); + scaleXYZLine = new Line(); + origScale = new Vec3f(); + scaleAxisPlane = new PlaneUV(); + scaleAxisOffset = new Vec3f(); + scaleAxisOrigUV = new Vec2f(); + + createGeometry(); + recalc(); + } + + /** Set the translation of this HandleBoxManip. This moves its + on-screen representation. Manipulations cause the translation to + be modified, not overwritten. */ + public void setTranslation(Vec3f translation) { + this.translation.set(translation); + recalc(); + } + + /** Get the translation of this Translate1Manip. This corresponds to + the center of its body. */ + public Vec3f getTranslation() { + return new Vec3f(translation); + } + + /** Set the rotation of this HandleBoxManip. */ + public void setRotation(Rotf rotation) { + this.rotation.set(rotation); + recalc(); + } + + /** Get the rotation of this HandleBoxManip. */ + public Rotf getRotation() { + return new Rotf(rotation); + } + + /** Set the scale of the HandleBoxManip. This corresponds to the + scaling the user has performed. */ + public void setScale(Vec3f scale) { + this.scale.set(scale); + recalc(); + } + + public Vec3f getScale() { + return new Vec3f(scale); + } + + /** Set the scale of the HandleBoxManip's geometry. This only + affects its on-screen representation. It is probably a bad idea + to use a non-uniform scale here, because it'd be very confusing + to the user. None of the components of the geometryScale vector + may be negative. */ + public void setGeometryScale(Vec3f geometryScale) { + this.geometryScale.set(geometryScale); + recalc(); + } + + public Vec3f getGeometryScale() { + return new Vec3f(geometryScale); + } + + /** Get the cumulative transformation matrix of this + HandleBoxManip. */ + public Mat4f getTransform() { + // Transform is Scale, Rotation, Translation applied to incoming + // column vectors in that order (SRT, or TRS since column vectors + // are right-multiplied) + Mat4f dest = new Mat4f(); + getTransform(dest); + return dest; + } + + /** Get the cumulative transformation matrix of this HandleBoxManip + into the passed matrix. */ + public void getTransform(Mat4f dest) { + Mat4f tmp1 = new Mat4f(); + Mat4f tmp2 = new Mat4f(); + tmp1.makeIdent(); + tmp2.makeIdent(); + tmp1.setScale(scale); + dest.makeIdent(); + dest.setRotation(rotation); + tmp2.mul(dest, tmp1); + tmp1.makeIdent(); + tmp1.setTranslation(translation); + dest.mul(tmp1, tmp2); + } + + public void render(GL gl) { + int i; + for (i = 0; i < 12; i++) + lineSegs[i].render(gl); + for (i = 0; i < rotateHandles.size(); i++) + ((RotateHandleInfo) rotateHandles.get(i)).geometry.render(gl); + for (i = 0; i < scaleHandles.size(); i++) + ((ScaleHandleInfo) scaleHandles.get(i)).geometry.render(gl); + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results) { + for (Iterator iter = faces.iterator(); iter.hasNext(); ) { + ((FaceInfo) iter.next()).centerSquare.intersectRay(rayStart, rayDirection, + results, this); + } + for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) { + ((RotateHandleInfo) iter.next()).geometry.intersectRay(rayStart, rayDirection, + results, this); + } + for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) { + ((ScaleHandleInfo) iter.next()).geometry.intersectRay(rayStart, rayDirection, + results, this); + } + } + + public void highlight(HitPoint hit) { + ManipPart part = hit.manipPart; + // Search for this part in the FaceInfo array + for (Iterator iter = faces.iterator(); iter.hasNext(); ) { + FaceInfo info = (FaceInfo) iter.next(); + if (info.centerSquare == part) { + for (int j = 0; j < 4; j++) { + info.lineSegs[j].highlight(); + highlightedGeometry.add(info.lineSegs[j]); + } + return; + } + } + + // Otherwise, was a rotation or scale handle + part.highlight(); + highlightedGeometry.add(part); + } + + public void clearHighlight() { + for (Iterator iter = highlightedGeometry.iterator(); iter.hasNext(); ) { + ((ManipPart) iter.next()).clearHighlight(); + } + highlightedGeometry.clear(); + } + + public void makeActive(HitPoint hit) { + // Find which piece of geometry it is + for (Iterator iter = faces.iterator(); iter.hasNext(); ) { + FaceInfo face = (FaceInfo) iter.next(); + if (face.centerSquare == hit.manipPart) { + dragState = TRANSLATE; + dragPlane.setPoint(hit.intPt.getIntersectionPoint()); + dragPlane.setNormal(face.normal); + dragOffset.sub(translation, hit.intPt.getIntersectionPoint()); + for (int j = 0; j < 4; j++) { + face.lineSegs[j].highlight(); + draggedGeometry.add(face.lineSegs[j]); + } + return; + } + } + + for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) { + RotateHandleInfo rotInfo = (RotateHandleInfo) iter.next(); + if (rotInfo.geometry == hit.manipPart) { + dragState = ROTATE; + // Determine which direction we're rotating by taking dot + // products of the ray direction with the rotating planes' + // normals + float dotp0 = + Math.abs(hit.rayDirection.dot(((FaceInfo) faces.get(rotInfo.faceIdx0)).normal)); + float dotp1 = + Math.abs(hit.rayDirection.dot(((FaceInfo) faces.get(rotInfo.faceIdx1)).normal)); + int faceIdx; + if (dotp0 > dotp1) + faceIdx = rotInfo.faceIdx0; + else + faceIdx = rotInfo.faceIdx1; + FaceInfo face = (FaceInfo) faces.get(faceIdx); + // Set up the rotation plane + rotatePlane.setOrigin(translation); + rotatePlane.setNormal(face.normal); + Vec3f dummy = new Vec3f(); + Vec2f startUV = new Vec2f(); + rotatePlane.projectPoint(hit.intPt.getIntersectionPoint(), dummy, startUV); + startAngle = (float) Math.atan2(startUV.y(), startUV.x()); + startRot.set(rotation); + rotInfo.geometry.highlight(); + draggedGeometry.add(rotInfo.geometry); + return; + } + } + + for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) { + ScaleHandleInfo info = (ScaleHandleInfo) iter.next(); + if (info.geometry == hit.manipPart) { + if (hit.shiftDown) { + dragState = SCALE_SINGLE_AXIS; + // Figure out which are the two axes along which we're + // going to allow scaling by taking dot products of the + // ray direction with the normals of the adjacent faces + // to the scale handle. + float dotp = 0.0f; + float tmpDotp; + int faceIdx = 0; + for (int i = 0; i < 3; i++) { + FaceInfo faceInfo = (FaceInfo) faces.get(info.faceIndices[i]); + tmpDotp = faceInfo.normal.dot(hit.rayDirection); + if ((i == 0) || (tmpDotp < dotp)) { + dotp = tmpDotp; + faceIdx = info.faceIndices[i]; + } + } + scaleAxes = ((FaceInfo) faces.get(faceIdx)).scaleAxes; + Vec3f uAxisOrig = new Vec3f(); + Vec3f vAxisOrig = new Vec3f(); + if (scaleAxes == SCALE_XY) { + uAxisOrig.set(1, 0, 0); + vAxisOrig.set(0, 1, 0); + } else if (scaleAxes == SCALE_YZ) { + uAxisOrig.set(0, 1, 0); + vAxisOrig.set(0, 0, 1); + } else { + uAxisOrig.set(0, 0, 1); + vAxisOrig.set(1, 0, 0); + } + Vec3f uAxis = new Vec3f(); + Vec3f vAxis = new Vec3f(); + Mat4f rotationTmpMat = new Mat4f(); + rotationTmpMat.makeIdent(); + rotationTmpMat.setRotation(rotation); + rotationTmpMat.xformDir(uAxisOrig, uAxis); + rotationTmpMat.xformDir(vAxisOrig, vAxis); + Vec3f normal = new Vec3f(); + normal.cross(uAxis, vAxis); + scaleAxisPlane.setNormalAndUV(normal, uAxis, vAxis); + // We need to be able to constrain the scaling to be + // nonnegative. + Vec3f newOrigin = new Vec3f(); + Vec2f foo = new Vec2f(); + scaleAxisPlane.projectPoint(translation, newOrigin, foo); + scaleAxisPlane.setOrigin(newOrigin); + scaleAxisOffset.sub(hit.intPt.getIntersectionPoint(), newOrigin); + // Now project intersection point onto plane + Vec3f bar = new Vec3f(); + scaleAxisPlane.projectPoint(hit.intPt.getIntersectionPoint(), + bar, scaleAxisOrigUV); + // Put the plane back where it was + scaleAxisPlane.setOrigin(hit.intPt.getIntersectionPoint()); + origScale.set(scale); + } else { + dragState = SCALE_XYZ; + scaleXYZLine.setPoint(hit.intPt.getIntersectionPoint()); + Vec3f scaleDiffVec = new Vec3f(); + scaleDiffVec.sub(hit.intPt.getIntersectionPoint(), translation); + scaleXYZLine.setDirection(scaleDiffVec); + origScale.set(scale); + origScaleLen = scaleDiffVec.length(); + } + info.geometry.highlight(); + draggedGeometry.add(info.geometry); + return; + } + } + + throw new RuntimeException("Couldn't find intersected piece of geometry"); + } + + public void drag(Vec3f rayStart, + Vec3f rayDirection) { + if (dragState == TRANSLATE) { + // Algorithm: Find intersection of ray with dragPlane. Add + // dragOffset to this point to get new translation. + IntersectionPoint intPt = new IntersectionPoint(); + if (dragPlane.intersectRay(rayStart, + rayDirection, + intPt) == false) { + // Ray is parallel to plane. Punt. + return; + } + translation.add(intPt.getIntersectionPoint(), dragOffset); + recalc(); + } else if (dragState == ROTATE) { + IntersectionPoint intPt = new IntersectionPoint(); + Vec2f uvCoords = new Vec2f(); + if (rotatePlane.intersectRay(rayStart, + rayDirection, + intPt, + uvCoords) == false) { + // Ray is parallel to plane. Punt. + return; + } + // Compute offset rotation angle + Rotf offsetRot = new Rotf(); + offsetRot.set(rotatePlane.getNormal(), + (float) Math.atan2(uvCoords.y(), uvCoords.x()) - startAngle); + rotation.mul(offsetRot, startRot); + recalc(); + } else if (dragState == SCALE_XYZ) { + Vec3f closestPt = new Vec3f(); + boolean gotPt = scaleXYZLine.closestPointToRay(rayStart, + rayDirection, + closestPt); + if (gotPt) { + // How far have we moved? + // Clamp scale to be positive. + Vec3f newDiffVec = new Vec3f(); + newDiffVec.sub(closestPt, translation); + if (newDiffVec.dot(scaleXYZLine.getDirection()) < 0) { + scale.set(0, 0, 0); + } else { + float scaleChange = newDiffVec.length() / origScaleLen; + scale.set(origScale); + scale.scale(scaleChange); + } + recalc(); + } + } else if (dragState == SCALE_SINGLE_AXIS) { + IntersectionPoint intPt = new IntersectionPoint(); + Vec2f uvCoords = new Vec2f(); + if (scaleAxisPlane.intersectRay(rayStart, rayDirection, intPt, uvCoords)) { + Vec2f faceCenteredUVCoords = new Vec2f(); + Vec3f foo = new Vec3f(); + Vec3f tmp = new Vec3f(); + tmp.set(intPt.getIntersectionPoint()); + tmp.add(scaleAxisOffset); + scaleAxisPlane.projectPoint(tmp, foo, faceCenteredUVCoords); + if ((MathUtil.sgn(faceCenteredUVCoords.x()) == + MathUtil.sgn(scaleAxisOrigUV.x())) && + (MathUtil.sgn(faceCenteredUVCoords.y()) == + MathUtil.sgn(scaleAxisOrigUV.y()))) { + if (faceCenteredUVCoords.x() < 0) + uvCoords.setX(uvCoords.x() * -1); + if (faceCenteredUVCoords.y() < 0) + uvCoords.setY(uvCoords.y() * -1); + Vec3f scaleVec = new Vec3f(); + if (Math.abs(uvCoords.x()) > Math.abs(uvCoords.y())) { + if (scaleAxes == SCALE_XY) + scaleVec.setX(uvCoords.x()); + else if (scaleAxes == SCALE_YZ) + scaleVec.setY(uvCoords.x()); + else + scaleVec.setZ(uvCoords.x()); + } else { + if (scaleAxes == SCALE_XY) + scaleVec.setY(uvCoords.y()); + else if (scaleAxes == SCALE_YZ) + scaleVec.setZ(uvCoords.y()); + else + scaleVec.setX(uvCoords.y()); + } + scaleVec.setX(scaleVec.x() / geometryScale.x()); + scaleVec.setY(scaleVec.y() / geometryScale.y()); + scaleVec.setZ(scaleVec.z() / geometryScale.z()); + scale.add(origScale, scaleVec); + // This shouldn't be necessary anymore + /* + if (scale.x() < 0) + scale.setX(0); + if (scale.y() < 0) + scale.setY(0); + if (scale.z() < 0) + scale.setZ(0); + */ + } else { + if (Math.abs(uvCoords.x()) > Math.abs(uvCoords.y())) { + if (scaleAxes == SCALE_XY) + scale.setX(0); + else if (scaleAxes == SCALE_YZ) + scale.setY(0); + else + scale.setZ(0); + } else { + if (scaleAxes == SCALE_XY) + scale.setY(0); + else if (scaleAxes == SCALE_YZ) + scale.setZ(0); + else + scale.setX(0); + } + } + recalc(); + } + } else { + throw new RuntimeException("HandleBoxManip::drag: ERROR: Unexpected drag state"); + } + super.drag(rayStart, rayDirection); + } + + public void makeInactive() { + dragState = INACTIVE; + for (Iterator iter = draggedGeometry.iterator(); iter.hasNext(); ) { + ((ManipPart) iter.next()).clearHighlight(); + } + draggedGeometry.clear(); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void createGeometry() { + ManipPartGroup group = new ManipPartGroup(); + + // + // Lines + // + + // Top face: + // Front line + lineSegs[0] = createLineSeg(new Vec3f(0, 1, 1), + new Vec3f(1, 0, 0), + new Vec3f(0, 1, 0)); + // Left line + lineSegs[1] = createLineSeg(new Vec3f(-1, 1, 0), + new Vec3f(0, 0, 1), + new Vec3f(0, 1, 0)); + // Back line + lineSegs[2] = createLineSeg(new Vec3f(0, 1, -1), + new Vec3f(1, 0, 0), + new Vec3f(0, 1, 0)); + // Right line + lineSegs[3] = createLineSeg(new Vec3f(1, 1, 0), + new Vec3f(0, 0, 1), + new Vec3f(0, 1, 0)); + // Middle segments: + // Front left + lineSegs[4] = createLineSeg(new Vec3f(-1, 0, 1), + new Vec3f(0, -1, 0), + new Vec3f(1, 0, 0)); + // Back left + lineSegs[5] = createLineSeg(new Vec3f(-1, 0, -1), + new Vec3f(0, -1, 0), + new Vec3f(1, 0, 0)); + // Back right + lineSegs[6] = createLineSeg(new Vec3f(1, 0, -1), + new Vec3f(0, -1, 0), + new Vec3f(1, 0, 0)); + // Front right + lineSegs[7] = createLineSeg(new Vec3f(1, 0, 1), + new Vec3f(0, -1, 0), + new Vec3f(1, 0, 0)); + // Bottom face: + // Front line + lineSegs[8] = createLineSeg(new Vec3f(0, -1, 1), + new Vec3f(1, 0, 0), + new Vec3f(0, 1, 0)); + // Left line + lineSegs[9] = createLineSeg(new Vec3f(-1, -1, 0), + new Vec3f(0, 0, 1), + new Vec3f(0, 1, 0)); + // Back line + lineSegs[10] = createLineSeg(new Vec3f(0, -1, -1), + new Vec3f(1, 0, 0), + new Vec3f(0, 1, 0)); + // Right line + lineSegs[11] = createLineSeg(new Vec3f(1, -1, 0), + new Vec3f(0, 0, 1), + new Vec3f(0, 1, 0)); + + for (int i = 0; i < 12; i++) { + group.addChild(lineSegs[i]); + } + + // + // Faces + // + + // Front face (index 0) + FaceInfo info = new FaceInfo(); + info.origNormal.set(0, 0, 1); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0)); + info.lineSegs[0] = lineSegs[0]; + info.lineSegs[1] = lineSegs[4]; + info.lineSegs[2] = lineSegs[7]; + info.lineSegs[3] = lineSegs[8]; + info.scaleAxes = SCALE_XY; + faces.add(info); + // Right face (index 1) + info = new FaceInfo(); + info.origNormal.set(1, 0, 0); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0)); + info.lineSegs[0] = lineSegs[3]; + info.lineSegs[1] = lineSegs[6]; + info.lineSegs[2] = lineSegs[7]; + info.lineSegs[3] = lineSegs[11]; + info.scaleAxes = SCALE_YZ; + faces.add(info); + // Back face (index 2) + info = new FaceInfo(); + info.origNormal.set(0, 0, -1); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0)); + info.lineSegs[0] = lineSegs[2]; + info.lineSegs[1] = lineSegs[5]; + info.lineSegs[2] = lineSegs[6]; + info.lineSegs[3] = lineSegs[10]; + info.scaleAxes = SCALE_XY; + faces.add(info); + // Left face (index 3) + info = new FaceInfo(); + info.origNormal.set(-1, 0, 0); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0)); + info.lineSegs[0] = lineSegs[1]; + info.lineSegs[1] = lineSegs[4]; + info.lineSegs[2] = lineSegs[5]; + info.lineSegs[3] = lineSegs[9]; + info.scaleAxes = SCALE_YZ; + faces.add(info); + // Top face (index 4) + info = new FaceInfo(); + info.origNormal.set(0, 1, 0); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 0, -1)); + info.lineSegs[0] = lineSegs[0]; + info.lineSegs[1] = lineSegs[1]; + info.lineSegs[2] = lineSegs[2]; + info.lineSegs[3] = lineSegs[3]; + info.scaleAxes = SCALE_ZX; + faces.add(info); + // Bottom face (index 5) + info = new FaceInfo(); + info.origNormal.set(0, -1, 0); + info.centerSquare = + createFace(info.origNormal, info.origNormal, new Vec3f(0, 0, 1)); + info.lineSegs[0] = lineSegs[8]; + info.lineSegs[1] = lineSegs[9]; + info.lineSegs[2] = lineSegs[10]; + info.lineSegs[3] = lineSegs[11]; + info.scaleAxes = SCALE_ZX; + faces.add(info); + + for (Iterator iter = faces.iterator(); iter.hasNext(); ) { + group.addChild(((FaceInfo) iter.next()).centerSquare); + } + + // + // Rotation handles + // + + // Front handle. Rotates about top/bottom and left/right faces. + // Maintain references to top and right faces. + RotateHandleInfo rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 4; + rotInfo.faceIdx1 = 1; + rotInfo.geometry = createRotateHandle(new Vec3f(0, 0, 1)); + rotateHandles.add(rotInfo); + // Right handle. Rotates about top/bottom and front/back faces. + // Maintain references to top and front faces. + rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 4; + rotInfo.faceIdx1 = 0; + rotInfo.geometry = createRotateHandle(new Vec3f(1, 0, 0)); + rotateHandles.add(rotInfo); + // Back handle. Rotates about top/bottom and left/right faces. + // Maintain references to top and right faces. + rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 4; + rotInfo.faceIdx1 = 1; + rotInfo.geometry = createRotateHandle(new Vec3f(0, 0, -1)); + rotateHandles.add(rotInfo); + // Left handle. Rotates about top/bottom and front/back faces. + // Maintain references to top and front faces. + rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 4; + rotInfo.faceIdx1 = 0; + rotInfo.geometry = createRotateHandle(new Vec3f(-1, 0, 0)); + rotateHandles.add(rotInfo); + // Top handle. Rotates about front/back and left/right faces. + // Maintain references to front and right faces. + rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 0; + rotInfo.faceIdx1 = 1; + rotInfo.geometry = createRotateHandle(new Vec3f(0, 1, 0)); + rotateHandles.add(rotInfo); + // Bottom handle. Rotates about front/back and left/right faces. + // Maintain references to front and right faces. + rotInfo = new RotateHandleInfo(); + rotInfo.faceIdx0 = 0; + rotInfo.faceIdx1 = 1; + rotInfo.geometry = createRotateHandle(new Vec3f(0, -1, 0)); + rotateHandles.add(rotInfo); + + for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) { + group.addChild(((RotateHandleInfo) iter.next()).geometry); + } + + // Scale handles + // Top right front (order: front right top) + ScaleHandleInfo scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(1, 1, 1)); + scaleInfo.faceIndices[0] = 0; + scaleInfo.faceIndices[1] = 1; + scaleInfo.faceIndices[2] = 4; + scaleHandles.add(scaleInfo); + // Top right back (order: right back top) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(1, 1, -1)); + scaleInfo.faceIndices[0] = 1; + scaleInfo.faceIndices[1] = 2; + scaleInfo.faceIndices[2] = 4; + scaleHandles.add(scaleInfo); + // Bottom right front (order: front right bottom) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(1, -1, 1)); + scaleInfo.faceIndices[0] = 0; + scaleInfo.faceIndices[1] = 1; + scaleInfo.faceIndices[2] = 5; + scaleHandles.add(scaleInfo); + // Bottom right back (order: right back bottom) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(1, -1, -1)); + scaleInfo.faceIndices[0] = 1; + scaleInfo.faceIndices[1] = 2; + scaleInfo.faceIndices[2] = 5; + scaleHandles.add(scaleInfo); + // Top left front (order: front left top) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(-1, 1, 1)); + scaleInfo.faceIndices[0] = 0; + scaleInfo.faceIndices[1] = 3; + scaleInfo.faceIndices[2] = 4; + scaleHandles.add(scaleInfo); + // Top left back (order: back left top) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(-1, 1, -1)); + scaleInfo.faceIndices[0] = 2; + scaleInfo.faceIndices[1] = 3; + scaleInfo.faceIndices[2] = 4; + scaleHandles.add(scaleInfo); + // Bottom left front (order: front left bottom) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(-1, -1, 1)); + scaleInfo.faceIndices[0] = 0; + scaleInfo.faceIndices[1] = 3; + scaleInfo.faceIndices[2] = 5; + scaleHandles.add(scaleInfo); + // Bottom left back (order: back left bottom) + scaleInfo = new ScaleHandleInfo(); + scaleInfo.geometry = createScaleHandle(new Vec3f(-1, -1, -1)); + scaleInfo.faceIndices[0] = 2; + scaleInfo.faceIndices[1] = 3; + scaleInfo.faceIndices[2] = 5; + scaleHandles.add(scaleInfo); + + for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) { + group.addChild(((ScaleHandleInfo) iter.next()).geometry); + } + + parts = group; + } + + private ManipPart createLineSeg(Vec3f translation, + Vec3f xAxis, + Vec3f yAxis) { + ManipPartTransform xform = new ManipPartTransform(); + ManipPartLineSeg lineSeg = new ManipPartLineSeg(); + xform.addChild(lineSeg); + Mat4f offset = new Mat4f(); + offset.makeIdent(); + Vec3f zAxis = new Vec3f(); + zAxis.cross(xAxis, yAxis); + offset.set(0, 0, xAxis.x()); + offset.set(1, 0, xAxis.y()); + offset.set(2, 0, xAxis.z()); + offset.set(0, 1, yAxis.x()); + offset.set(1, 1, yAxis.y()); + offset.set(2, 1, yAxis.z()); + offset.set(0, 2, zAxis.x()); + offset.set(1, 2, zAxis.y()); + offset.set(2, 2, zAxis.z()); + offset.set(0, 3, translation.x()); + offset.set(1, 3, translation.y()); + offset.set(2, 3, translation.z()); + xform.setOffsetTransform(offset); + return xform; + } + + private ManipPart createFace(Vec3f translation, + Vec3f normal, + Vec3f up) { + ManipPartTransform xform = new ManipPartTransform(); + ManipPartSquare square = new ManipPartSquare(); + square.setVisible(false); + xform.addChild(square); + Mat4f offset = new Mat4f(); + offset.makeIdent(); + Vec3f right = new Vec3f(); + right.cross(up, normal); + offset.set(0, 0, right.x()); + offset.set(1, 0, right.y()); + offset.set(2, 0, right.z()); + offset.set(0, 1, up.x()); + offset.set(1, 1, up.y()); + offset.set(2, 1, up.z()); + offset.set(0, 2, normal.x()); + offset.set(1, 2, normal.y()); + offset.set(2, 2, normal.z()); + offset.set(0, 3, translation.x()); + offset.set(1, 3, translation.y()); + offset.set(2, 3, translation.z()); + xform.setOffsetTransform(offset); + return xform; + } + + private ManipPart createRotateHandle(Vec3f direction) { + ManipPartCube handle = new ManipPartCube(); + Mat4f offset = new Mat4f(); + offset.makeIdent(); + offset.set(0, 0, 0.1f); + offset.set(1, 1, 0.1f); + offset.set(2, 2, 0.1f); + Vec3f scaledDirection = new Vec3f(direction); + scaledDirection.scale(2.0f); + offset.setTranslation(scaledDirection); + ManipPartTransform xform = new ManipPartTransform(); + xform.addChild(handle); + xform.setOffsetTransform(offset); + return xform; + } + + private ManipPart createScaleHandle(Vec3f position) { + ManipPartCube handle = new ManipPartCube(); + Mat4f offset = new Mat4f(); + offset.makeIdent(); + offset.set(0, 0, 0.1f); + offset.set(1, 1, 0.1f); + offset.set(2, 2, 0.1f); + offset.setTranslation(position); + ManipPartTransform xform = new ManipPartTransform(); + xform.addChild(handle); + xform.setOffsetTransform(offset); + return xform; + } + + private void recalc() { + // Construct local to world transform for geometry. + // Scale, Rotation, Translation. Since we're right multiplying + // column vectors, the actual matrix composed is TRS. + Mat4f scaleMat = new Mat4f(); + Mat4f rotMat = new Mat4f(); + Mat4f xlateMat = new Mat4f(); + Mat4f tmpMat = new Mat4f(); + scaleMat.makeIdent(); + scaleMat.set(0, 0, scale.x() * geometryScale.x()); + scaleMat.set(1, 1, scale.y() * geometryScale.y()); + scaleMat.set(2, 2, scale.z() * geometryScale.z()); + rotMat.makeIdent(); + rotMat.setRotation(rotation); + xlateMat.makeIdent(); + xlateMat.set(0, 3, translation.x()); + xlateMat.set(1, 3, translation.y()); + xlateMat.set(2, 3, translation.z()); + tmpMat.mul(xlateMat, rotMat); + xform.mul(tmpMat, scaleMat); + int i; + for (i = 0; i < 12; i++) { + lineSegs[i].setTransform(xform); + } + for (i = 0; i < faces.size(); i++) { + FaceInfo face = (FaceInfo) faces.get(i); + face.centerSquare.setTransform(xform); + xform.xformDir(face.origNormal, face.normal); + face.normal.normalize(); + + RotateHandleInfo rotInfo = (RotateHandleInfo) rotateHandles.get(i); + rotInfo.geometry.setTransform(xform); + } + for (i = 0; i < scaleHandles.size(); i++) { + ((ScaleHandleInfo) scaleHandles.get(i)).geometry.setTransform(xform); + } + } +} diff --git a/src/gleem/HitPoint.java b/src/gleem/HitPoint.java new file mode 100644 index 0000000..1eb7151 --- /dev/null +++ b/src/gleem/HitPoint.java @@ -0,0 +1,73 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/** Defines an intersection of a ray with a piece of a manipulator */ + +public class HitPoint { + /** Was the shift key down while this HitPoint was computed? */ + public boolean shiftDown; + + /** The manipulator which was intersected */ + public Manip manipulator; + + /** The sub-piece of the manipulator which was actually intersected */ + public ManipPart manipPart; + + /** Start of the ray which was cast. The manipulator part must set + this when an intersection is detected. */ + public Vec3f rayStart; + /** Direction of the ray which was cast. The manipulator part must + set this when an intersection is detected. */ + public Vec3f rayDirection; + + // Not all ManipParts supply all of these pieces of information. + + /** The combination of 3D point and t parameter at which the + intersection occurred. It's important to supply the t parameter + because the ManipManager needs it to disambiguate between + intersections with multiple manipulators. */ + public IntersectionPoint intPt; + + /** Arbitrary user data for extended functionality */ + public Object userData; +} diff --git a/src/gleem/Manip.java b/src/gleem/Manip.java new file mode 100644 index 0000000..b037430 --- /dev/null +++ b/src/gleem/Manip.java @@ -0,0 +1,120 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** The base class for all manipulators. Fundamentally a manipulator + must support a ray cast operation with itself and logic to + understand what to do when that ray cast actually made the + manipulator active. */ + +public abstract class Manip { + private List motionListeners; + + public Manip() { + motionListeners = new LinkedList(); + + // FIXME: The ManipManager's list should probably be maintained + // with weak references + // ManipManager.getManipManager().registerManip(this); + } + + /** Returns true if the addition was successful, false otherwise */ + public boolean addMotionListener(ManipMotionListener l) { + return motionListeners.add(l); + } + + /** Returns true if the removal was successful, false otherwise */ + public boolean removeMotionListener(ManipMotionListener l) { + return motionListeners.remove(l); + } + + /** Cast a ray in 3-space from the camera start position in the + specified direction and test for intersections against all live + portions of this manipulator. Add all hits, in arbitrary order, + to the end of the given list in the form of HitPoints. Must not + modify the results vector in any other way (i.e., must not + remove any existing HitPoints from the results vector). */ + public abstract void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results); + + /** Tell the manipulator to highlight the current portion of itself. + This is merely visual feedback to the user. */ + public abstract void highlight(HitPoint hit); + + /** Tell the manipulator to clear the current highlight */ + public abstract void clearHighlight(); + + /** If the ManipManager decides that this manipulator is to become + active, it will pass back the HitPoint which made it make its + decision. The manipulator can then change its state to look for + drags of this portion of the manipulator. */ + public abstract void makeActive(HitPoint hit); + + /** When a manipulator is active, drags of the live portion cause + motion of the manipulator. The ManipManager keeps track of which + manipulator (if any) is active and takes care of calling the + drag() method with the current ray start and direction. The + manipulator must keep enough state to understand how it should + position and/or rotate itself. NOTE that the base class provides + an implementation for this method which you must call at the end + of your overriding method. */ + public void drag(Vec3f rayStart, + Vec3f rayDirection) { + for (Iterator iter = motionListeners.iterator(); iter.hasNext(); ) { + ManipMotionListener m = (ManipMotionListener) iter.next(); + m.manipMoved(this); + } + } + + /** When the mouse button is released, makeInactive() is called. The + manipulator should reset its state in preparation for the next + drag. */ + public abstract void makeInactive(); + + /** Render this Manipulator now using the given OpenGL routines and + assuming an OpenGL context is current. */ + public abstract void render(GL gl); +} diff --git a/src/gleem/ManipManager.java b/src/gleem/ManipManager.java new file mode 100644 index 0000000..0a0d86d --- /dev/null +++ b/src/gleem/ManipManager.java @@ -0,0 +1,404 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.event.*; +import java.util.*; + +import gleem.linalg.*; + +import net.java.games.jogl.*; + +/** The ManipManager handles making manipulators visible in a + window. */ + +public class ManipManager { + // Screen-to-ray mapping + private ScreenToRayMapping mapping; + private static ManipManager soleInstance; + // Maps GLDrawables to WindowInfos + private Map windowToInfoMap = new HashMap(); + // Maps Manips to Set + private Map manipToWindowMap = new HashMap(); + + // MouseAdapter for this + private MouseAdapter mouseListener = new MouseAdapter() { + public void mousePressed(MouseEvent e) { + ManipManager.this.mousePressed(e); + } + + public void mouseReleased(MouseEvent e) { + ManipManager.this.mouseReleased(e); + } + }; + private MouseMotionAdapter mouseMotionListener = new MouseMotionAdapter() { + public void mouseDragged(MouseEvent e) { + ManipManager.this.mouseDragged(e); + } + + public void mouseMoved(MouseEvent e) { + ManipManager.this.mouseMoved(e); + } + }; + private WindowUpdateListener defaultWindowListener = new WindowUpdateListener() { + public void update(GLDrawable window) { + if (!window.getNoAutoRedrawMode()) { + window.display(); + } + } + }; + private WindowUpdateListener windowListener; + + class WindowInfo { + /** Set */ + Set manips = new HashSet(); + CameraParameters params = new CameraParameters(); + Manip curHighlightedManip; + ManipPart curHighlightedManipPart; + // Current manip + Manip curManip; + // Dragging? + boolean dragging; + } + + /** This class is a singleton. Get the sole instance of the + ManipManager. */ + public static synchronized ManipManager getManipManager() { + if (soleInstance == null) { + soleInstance = new ManipManager(); + } + return soleInstance; + } + + /** Make the ManipManager aware of the existence of a given + window. This causes mouse and mouse motion listeners to be + installed on this window; see setupMouseListeners, below. */ + public synchronized void registerWindow(GLDrawable window) { + windowToInfoMap.put(window, new WindowInfo()); + setupMouseListeners(window); + } + + /** Remove all references to a given window, including removing all + manipulators from it. */ + public synchronized void unregisterWindow(GLDrawable window) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + for (Iterator iter = info.manips.iterator(); iter.hasNext(); ) { + removeManipFromWindow((Manip) iter.next(), window); + } + windowToInfoMap.remove(window); + removeMouseListeners(window); + } + + /** Make a given manipulator visible and active in a given + window. The window must be registered. */ + public synchronized void showManipInWindow(Manip manip, GLDrawable window) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + if (info == null) { + throw new RuntimeException("Window not registered"); + } + info.manips.add(manip); + Set windows = (Set) manipToWindowMap.get(manip); + if (windows == null) { + windows = new HashSet(); + manipToWindowMap.put(manip, windows); + } + windows.add(window); + } + + /** Remove a given manipulator from a given window. The window must + be registered. */ + public synchronized void removeManipFromWindow(Manip manip, GLDrawable window) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + if (info == null) { + throw new RuntimeException("Window not registered"); + } + if (!info.manips.remove(manip)) { + throw new RuntimeException("Manip not registered in window"); + } + Set windows = (Set) manipToWindowMap.get(manip); + assert windows != null; + windows.remove(window); + } + + /** This must be called for a registered window every time the + camera parameters of the window change. */ + public synchronized void updateCameraParameters(GLDrawable window, CameraParameters params) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + if (info == null) { + throw new RuntimeException("Window not registered"); + } + info.params.set(params); + } + + /** Allows changing of the screen-to-ray mapping. Default is a + RightTruncPyrMapping. */ + public synchronized void setScreenToRayMapping(ScreenToRayMapping mapping) { + this.mapping = mapping; + } + + /** Returns the current screen-to-ray mapping. */ + public synchronized ScreenToRayMapping getScreenToRayMapping() { + return mapping; + } + + /** Sets the WindowUpdateListener the ManipManager uses to force + repainting of windows in which manipulators have moved. The + default implementation, which can be restored by passing a null + listener argument to this method, calls repaint() on the + GLDrawable if it is not a GLRunnable instance (i.e., a + GLAnimCanvas or GLAnimJPanel, which redraw themselves + automatically). */ + public synchronized void setWindowUpdateListener(WindowUpdateListener listener) { + if (listener != null) { + windowListener = listener; + } else { + windowListener = defaultWindowListener; + } + } + + /** Cause the manipulators for a given window to be drawn. The + drawing occurs immediately; this routine must be called when an + OpenGL context is valid, i.e., from within the display() method + of a GLEventListener. */ + public synchronized void render(GLDrawable window, GL gl) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + if (info == null) { + throw new RuntimeException("Window not registered"); + } + for (Iterator iter = info.manips.iterator(); iter.hasNext(); ) { + ((Manip) iter.next()).render(gl); + } + } + + /** Sets up a MouseListener and MouseMotionListener for the given + window. Since an application-level MouseListener or + MouseMotionListener might want to intercept events and not pass + them on to the ManipManager without relying on the ordering of + listeners for the canvas (see the ExaminerViewer class), the + setupMouseListeners and removeMouseListeners routines, as well + as the appropriate delegate routines, are made public here. */ + public synchronized void setupMouseListeners(GLDrawable window) { + window.addMouseMotionListener(mouseMotionListener); + window.addMouseListener(mouseListener); + } + + /** Removes the automatically-installed mouse listeners for the + given window. This allows application code to determine the + policy for intercepting mouse events. */ + public synchronized void removeMouseListeners(GLDrawable window) { + window.removeMouseMotionListener(mouseMotionListener); + window.removeMouseListener(mouseListener); + } + + /** The ManipManager watches for the following events: mouseMoved, + mouseDragged, mousePressed, and mouseReleased. These routines + are exposed so application-level code can intercept events when + certain modifier keys are depressed. */ + public synchronized void mouseMoved(MouseEvent e) { + passiveMotionMethod((GLDrawable) e.getComponent(), e.getX(), e.getY()); + } + + /** The ManipManager watches for the following events: mouseMoved, + mouseDragged, mousePressed, and mouseReleased. These routines + are exposed so application-level code can intercept events when + certain modifier keys are depressed. */ + public synchronized void mouseDragged(MouseEvent e) { + motionMethod((GLDrawable) e.getComponent(), e.getX(), e.getY()); + } + + /** The ManipManager watches for the following events: mouseMoved, + mouseDragged, mousePressed, and mouseReleased. These routines + are exposed so application-level code can intercept events when + certain modifier keys are depressed. */ + public synchronized void mousePressed(MouseEvent e) { + mouseMethod((GLDrawable) e.getComponent(), e.getModifiers(), + true, e.getX(), e.getY()); + } + + /** The ManipManager watches for the following events: mouseMoved, + mouseDragged, mousePressed, and mouseReleased. These routines + are exposed so application-level code can intercept events when + certain modifier keys are depressed. */ + public synchronized void mouseReleased(MouseEvent e) { + mouseMethod((GLDrawable) e.getComponent(), e.getModifiers(), + false, e.getX(), e.getY()); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private ManipManager() { + mapping = new RightTruncPyrMapping(); + setWindowUpdateListener(null); + } + + private void motionMethod(GLDrawable window, int x, int y) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + if (info.dragging) { + // Compute ray in 3D + Vec3f rayStart = new Vec3f(); + Vec3f rayDirection = new Vec3f(); + computeRay(info.params, x, y, rayStart, rayDirection); + info.curManip.drag(rayStart, rayDirection); + fireUpdate(info.curManip); + } + } + + private void passiveMotionMethod(GLDrawable window, int x, int y) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + // Compute ray in 3D + Vec3f rayStart = new Vec3f(); + Vec3f rayDirection = new Vec3f(); + computeRay(info.params, x, y, rayStart, rayDirection); + // Compute all hits + List hits = new ArrayList(); + for (Iterator iter = info.manips.iterator(); iter.hasNext(); ) { + ((Manip) iter.next()).intersectRay(rayStart, rayDirection, hits); + } + // Find closest one + HitPoint hp = null; + for (Iterator iter = hits.iterator(); iter.hasNext(); ) { + HitPoint cur = (HitPoint) iter.next(); + if ((hp == null) || (cur.intPt.getT() < hp.intPt.getT())) { + hp = cur; + } + } + if (info.curHighlightedManip != null && + (hp == null || + hp.manipulator != info.curHighlightedManip || + hp.manipPart != info.curHighlightedManipPart)) { + info.curHighlightedManip.clearHighlight(); + fireUpdate(info.curHighlightedManip); + } + if (hp != null) { + if (hp.manipulator != info.curHighlightedManip || + hp.manipPart != info.curHighlightedManipPart) { + // Highlight manip + info.curHighlightedManip = hp.manipulator; + info.curHighlightedManipPart = hp.manipPart; + info.curHighlightedManip.highlight(hp); + fireUpdate(info.curHighlightedManip); + } + } else { + info.curHighlightedManip = null; + } + } + + private void mouseMethod(GLDrawable window, int modifiers, + boolean isPress, int x, int y) { + if ((modifiers & InputEvent.BUTTON1_MASK) != 0) { + WindowInfo info = (WindowInfo) windowToInfoMap.get(window); + + if (isPress) { + // Compute ray in 3D + Vec3f rayStart = new Vec3f(); + Vec3f rayDirection = new Vec3f(); + computeRay(info.params, x, y, rayStart, rayDirection); + // Compute all hits + List hits = new ArrayList(); + for (Iterator iter = info.manips.iterator(); iter.hasNext(); ) { + ((Manip) iter.next()).intersectRay(rayStart, rayDirection, hits); + } + // Find closest one + HitPoint hp = null; + for (Iterator iter = hits.iterator(); iter.hasNext(); ) { + HitPoint cur = (HitPoint) iter.next(); + if ((hp == null) || (cur.intPt.getT() < hp.intPt.getT())) { + hp = cur; + } + } + if (hp != null) { + if (info.curHighlightedManip != null) { + info.curHighlightedManip.clearHighlight(); + fireUpdate(info.curHighlightedManip); + info.curHighlightedManip = null; + } + + if ((modifiers & InputEvent.SHIFT_MASK) != 0) { + hp.shiftDown = true; + } + + hp.manipulator.makeActive(hp); + info.curManip = hp.manipulator; + info.dragging = true; + fireUpdate(info.curManip); + } + } else { + if (info.curManip != null) { + info.curManip.makeInactive(); + info.dragging = false; + fireUpdate(info.curManip); + info.curManip = null; + // Check to see where mouse is + passiveMotionMethod(window, x, y); + } + } + } + } + + private Vec2f screenToNormalizedCoordinates(CameraParameters params, + int x, int y) { + // AWT's origin is upper left + return new Vec2f( + (((float) x / (float) (params.xSize - 1)) - 0.5f) * 2.0f, + (0.5f - ((float) y / (float) (params.ySize - 1))) * 2.0f + ); + } + + private void computeRay(CameraParameters params, int x, int y, + Vec3f raySource, Vec3f rayDirection) { + if (mapping == null) { + throw new RuntimeException("Screen to ray mapping was unspecified"); + } + mapping.mapScreenToRay(screenToNormalizedCoordinates(params, x, y), + params, + raySource, + rayDirection); + } + + private void fireUpdate(Manip manip) { + Set windows = (Set) manipToWindowMap.get(manip); + assert windows != null; + for (Iterator iter = windows.iterator(); iter.hasNext(); ) { + windowListener.update((GLDrawable) iter.next()); + } + } +} diff --git a/src/gleem/ManipMotionListener.java b/src/gleem/ManipMotionListener.java new file mode 100644 index 0000000..45059a7 --- /dev/null +++ b/src/gleem/ManipMotionListener.java @@ -0,0 +1,47 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +/** The interface which clients to the gleem library implement to + receive notification that a manipulator has moved. */ + +public interface ManipMotionListener { + public void manipMoved(Manip manip); +} diff --git a/src/gleem/ManipPart.java b/src/gleem/ManipPart.java new file mode 100644 index 0000000..50fbe61 --- /dev/null +++ b/src/gleem/ManipPart.java @@ -0,0 +1,94 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** A ManipPart is a visible or invisible sub-part of a manipulator. + ManipParts are organized into trees. */ + +public abstract class ManipPart { + private ManipPartGroup parent; + + /** Get the parent ManipPartGroup, or null if none (NOTE that this + differs from the C++ API) */ + public ManipPartGroup getParent() { + return parent; + } + + /** Set the parent ManipPartGroup of this ManipPart (NOTE that this + differs from the C++ API) */ + public void setParent(ManipPartGroup parent) { + this.parent = parent; + } + + /** Intersect a ray with this part, returning all intersected points + as HitPoints in the result list. The same rules as + Manip.intersectRay() apply. */ + public abstract void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results, + Manip caller); + + /** Sets the transform of this part. */ + public abstract void setTransform(Mat4f xform); + + /** Highlight this part */ + public abstract void highlight(); + + /** Unhighlight this part */ + public abstract void clearHighlight(); + + /** Is this part pickable, or just decorative? Not pickable implies + that intersectRay() will return immediately. */ + public abstract void setPickable(boolean pickable); + public abstract boolean getPickable(); + + /** Is this part visible? */ + public abstract void setVisible(boolean visible); + public abstract boolean getVisible(); + + /** Render this ManipPart now using the given OpenGL routines and + assuming an OpenGL context is current. */ + public abstract void render(GL gl); +} diff --git a/src/gleem/ManipPartCube.java b/src/gleem/ManipPartCube.java new file mode 100644 index 0000000..8e4a2f7 --- /dev/null +++ b/src/gleem/ManipPartCube.java @@ -0,0 +1,102 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; + +/** A cube of width, height, and depth 2, centered about the origin + and aligned with the X, Y, and Z axes. */ + +public class ManipPartCube extends ManipPartTriBased { + private static final Vec3f[] vertices = { + // Front side + new Vec3f(-1, 1, 1), + new Vec3f(-1, -1, 1), + new Vec3f(1, -1, 1), + new Vec3f(1, 1, 1), + // Back side + new Vec3f(-1, 1, -1), + new Vec3f(-1, -1, -1), + new Vec3f(1, -1, -1), + new Vec3f(1, 1, -1), + }; + + private static final int[] vertexIndices = { + // Front face + 0, 1, 2, + 0, 2, 3, + // Right face + 3, 2, 6, + 3, 6, 7, + // Back face + 7, 6, 5, + 7, 5, 4, + // Left face + 4, 5, 1, + 4, 1, 0, + // Top face + 4, 0, 3, + 4, 3, 7, + // Bottom face + 1, 5, 6, + 1, 6, 2 + }; + + private static Vec3f[] normals = null; + private static int[] normalIndices = null; + + public ManipPartCube() { + super(); + + if (normals == null) { + NormalCalc.NormalInfo normInfo = + NormalCalc.computeFacetedNormals(vertices, vertexIndices, true); + normals = normInfo.normals; + normalIndices = normInfo.normalIndices; + } + + setVertices(vertices); + setVertexIndices(vertexIndices); + setNormals(normals); + setNormalIndices(normalIndices); + } +} diff --git a/src/gleem/ManipPartGroup.java b/src/gleem/ManipPartGroup.java new file mode 100644 index 0000000..859a8a3 --- /dev/null +++ b/src/gleem/ManipPartGroup.java @@ -0,0 +1,133 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** This class groups a set of ManipParts. Makes a set of ManipParts + look like one. */ + +public class ManipPartGroup extends ManipPart { + private boolean pickable = true; + private boolean visible = true; + private List children = new ArrayList(); + + public void addChild(ManipPart child) { + children.add(child); + } + + public void removeChild(ManipPart child) { + children.remove(child); + } + + public int getNumChildren() { + return children.size(); + } + + public ManipPart getChild(int index) { + return (ManipPart) children.get(index); + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results, + Manip caller) { + if (!pickable) { + return; + } + + int topIdx = results.size(); + for (int i = 0; i < getNumChildren(); i++) { + getChild(i).intersectRay(rayStart, rayDirection, results, caller); + } + + // Fix up all HitPoints so we appear to be the manipulator part + // which caused the intersection + for (int i = topIdx; i < results.size(); i++) { + ((HitPoint) results.get(i)).manipPart = this; + } + } + + public void setTransform(Mat4f xform) { + for (int i = 0; i < getNumChildren(); i++) { + getChild(i).setTransform(xform); + } + } + + public void highlight() { + for (int i = 0; i < getNumChildren(); i++) { + getChild(i).highlight(); + } + } + + public void clearHighlight() { + for (int i = 0; i < getNumChildren(); i++) { + getChild(i).clearHighlight(); + } + } + + public void setPickable(boolean pickable) { + this.pickable = pickable; + } + + public boolean getPickable() { + return pickable; + } + + public void setVisible(boolean visible) { + this.visible = visible; + for (Iterator iter = children.iterator(); iter.hasNext(); ) { + ((ManipPart) iter.next()).setVisible(visible); + } + } + + public boolean getVisible() { + return visible; + } + + public void render(GL gl) { + for (Iterator iter = children.iterator(); iter.hasNext(); ) { + ((ManipPart) iter.next()).render(gl); + } + } +} diff --git a/src/gleem/ManipPartLineSeg.java b/src/gleem/ManipPartLineSeg.java new file mode 100644 index 0000000..8278533 --- /dev/null +++ b/src/gleem/ManipPartLineSeg.java @@ -0,0 +1,163 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** A line segment from (-1, 0, 0) to (1, 0, 0). */ + +public class ManipPartLineSeg extends ManipPart { + private Vec3f color; + private Vec3f highlightColor; + private boolean highlighted; + private boolean visible; + private static Vec3f[] vertices = new Vec3f[] { + new Vec3f(-1, 0, 0), + new Vec3f(1, 0, 0) + }; + /** Current transformation matrix */ + private Mat4f xform; + /** Transformed vertices */ + private Vec3f[] curVertices; + + public ManipPartLineSeg() { + color = new Vec3f(0.8f, 0.8f, 0.8f); + highlightColor = new Vec3f(0.8f, 0.8f, 0.2f); + highlighted = false; + visible = true; + xform = new Mat4f(); + xform.makeIdent(); + curVertices = null; + } + + /** Default color is (0.8, 0.8, 0.8) */ + public void setColor(Vec3f color) { + this.color.set(color); + } + + public Vec3f getColor() { + return new Vec3f(color); + } + + /** Default highlight color is (0.8, 0.8, 0) */ + public void setHighlightColor(Vec3f highlightColor) { + this.highlightColor.set(highlightColor); + } + + public Vec3f getHighlightColor() { + return new Vec3f(highlightColor); + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results, + Manip caller) { + } + + public void setTransform(Mat4f xform) { + this.xform.set(xform); + recalcVertices(); + } + + public void highlight() { + highlighted = true; + } + + public void clearHighlight() { + highlighted = false; + } + + public void setPickable(boolean pickable) { + } + + public boolean getPickable() { + return false; + } + + /** Default is visible */ + public void setVisible(boolean visible) { + this.visible = visible; + } + + public boolean getVisible() { + return visible; + } + + public void render(GL gl) { + if (!visible) + return; + // FIXME: probably too slow + boolean reenable = gl.glIsEnabled(GL.GL_LIGHTING); + gl.glDisable(GL.GL_LIGHTING); + gl.glBegin(GL.GL_LINES); + if (highlighted) + gl.glColor3f(highlightColor.x(), highlightColor.y(), highlightColor.z()); + else + gl.glColor3f(color.x(), color.y(), color.z()); + for (int i = 0; i < curVertices.length; i++) { + Vec3f v = curVertices[i]; + gl.glVertex3f(v.x(), v.y(), v.z()); + } + gl.glEnd(); + if (reenable) + gl.glEnable(GL.GL_LIGHTING); + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void recalcVertices() { + if ((curVertices == null) || + (curVertices.length != vertices.length)) { + curVertices = new Vec3f[vertices.length]; + for (int i = 0; i < vertices.length; i++) { + curVertices[i] = new Vec3f(); + } + } + + for (int i = 0; i < curVertices.length; i++) { + xform.xformPt(vertices[i], curVertices[i]); + } + } +} diff --git a/src/gleem/ManipPartSquare.java b/src/gleem/ManipPartSquare.java new file mode 100644 index 0000000..e639904 --- /dev/null +++ b/src/gleem/ManipPartSquare.java @@ -0,0 +1,82 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; + +/** A 2x2 square in the X-Y plane, centered about the origin, with the + normal pointing in the +Z direction. */ + +public class ManipPartSquare extends ManipPartTriBased { + private static final Vec3f[] vertices = { + // Counter-clockwise, starting from upper left + new Vec3f(-1, 1, 0), + new Vec3f(-1, -1, 0), + new Vec3f(1, -1, 0), + new Vec3f(1, 1, 0) + }; + + private static final int[] vertexIndices = { + // Just the front face + 0, 1, 2, + 0, 2, 3, + }; + + private static Vec3f[] normals = null; + private static int[] normalIndices = null; + + public ManipPartSquare() { + super(); + + if (normals == null) { + NormalCalc.NormalInfo normInfo = + NormalCalc.computeFacetedNormals(vertices, vertexIndices, true); + normals = normInfo.normals; + normalIndices = normInfo.normalIndices; + } + + setVertices(vertices); + setVertexIndices(vertexIndices); + setNormals(normals); + setNormalIndices(normalIndices); + } +} diff --git a/src/gleem/ManipPartTransform.java b/src/gleem/ManipPartTransform.java new file mode 100644 index 0000000..61a9bc5 --- /dev/null +++ b/src/gleem/ManipPartTransform.java @@ -0,0 +1,72 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; + +/** A Group which contains an offset transformation which is performed + before the one handed down in setTransform. */ + +public class ManipPartTransform extends ManipPartGroup { + private Mat4f offsetTransform; + + public ManipPartTransform() { + super(); + offsetTransform = new Mat4f(); + offsetTransform.makeIdent(); + } + + public void setTransform(Mat4f xform) { + Mat4f totalXform = xform.mul(offsetTransform); + for (int i = 0; i < getNumChildren(); i++) { + getChild(i).setTransform(totalXform); + } + } + + public void setOffsetTransform(Mat4f offsetTransform) { + this.offsetTransform.set(offsetTransform); + } + + public Mat4f getOffsetTransform() { + return offsetTransform; + } +} diff --git a/src/gleem/ManipPartTriBased.java b/src/gleem/ManipPartTriBased.java new file mode 100644 index 0000000..97f8ae3 --- /dev/null +++ b/src/gleem/ManipPartTriBased.java @@ -0,0 +1,292 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** Triangle-based manipulator part. This is the base class for most + of the ManipParts that GLEEM uses internally. You can feel free to + subclass this if you want to replace geometry in the manipulators, + or re-derive from ManipPart. See ManipPartLineSeg for an example. */ + +public class ManipPartTriBased extends ManipPart { + private Vec3f color; + private Vec3f highlightColor; + private boolean highlighted; + private boolean pickable; + private boolean visible; + /** Direct references down to subclass-specific data */ + private Vec3f[] vertices; + private Vec3f[] normals; + private int[] vertexIndices; + private int[] normalIndices; + /** Current transformation matrix */ + private Mat4f xform; + /** Transformed vertices and normals */ + private Vec3f[] curVertices; + private Vec3f[] curNormals; + + public ManipPartTriBased() { + color = new Vec3f(0.8f, 0.8f, 0.8f); + highlightColor = new Vec3f(0.8f, 0.8f, 0.2f); + highlighted = false; + pickable = true; + visible = true; + vertices = null; + normals = null; + vertexIndices = null; + normalIndices = null; + xform = new Mat4f(); + xform.makeIdent(); + curVertices = null; + } + + /** Default color is (0.8, 0.8, 0.8) */ + public void setColor(Vec3f color) { + this.color.set(color); + } + + public Vec3f getColor() { + return new Vec3f(color); + } + + /** Default highlight color is (0.8, 0.8, 0) */ + public void setHighlightColor(Vec3f highlightColor) { + this.highlightColor.set(highlightColor); + } + + public Vec3f getHighlightColor() { + return new Vec3f(highlightColor); + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results, + Manip caller) { + consistencyCheck(); + if (!pickable) { + return; + } + + IntersectionPoint intPt = new IntersectionPoint(); + HitPoint hitPt = new HitPoint(); + hitPt.manipulator = caller; + hitPt.manipPart = this; + for (int i = 0; i < vertexIndices.length; i+=3) { + int i0 = vertexIndices[i]; + int i1 = vertexIndices[i+1]; + int i2 = vertexIndices[i+2]; + if (RayTriangleIntersection.intersectRayWithTriangle(rayStart, + rayDirection, + curVertices[i0], + curVertices[i1], + curVertices[i2], + intPt) + == RayTriangleIntersection.INTERSECTION) { + // Check for intersections behind the ray + if (intPt.getT() >= 0) { + hitPt.rayStart = rayStart; + hitPt.rayDirection = rayDirection; + hitPt.intPt = intPt; + results.add(hitPt); + } + } + } + } + + public void setTransform(Mat4f xform) { + this.xform.set(xform); + recalcVertices(); + } + + public void highlight() { + highlighted = true; + } + + public void clearHighlight() { + highlighted = false; + } + + /** Default is pickable */ + public void setPickable(boolean pickable) { + this.pickable = pickable; + } + + public boolean getPickable() { + return pickable; + } + + /** Default is visible */ + public void setVisible(boolean visible) { + this.visible = visible; + } + + public boolean getVisible() { + return visible; + } + + public void render(GL gl) { + if (!visible) + return; + boolean lightingOn = true; + // FIXME: this is too expensive; figure out another way + // if (glIsEnabled(GL.GL_LIGHTING)) + // lightingOn = true; + + if (lightingOn) { + gl.glEnable(GL.GL_COLOR_MATERIAL); + gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT_AND_DIFFUSE); + } + gl.glBegin(GL.GL_TRIANGLES); + if (highlighted) + gl.glColor3f(highlightColor.x(), highlightColor.y(), highlightColor.z()); + else + gl.glColor3f(color.x(), color.y(), color.z()); + int i = 0; + while (i < vertexIndices.length) { + Vec3f n0 = curNormals[normalIndices[i]]; + Vec3f v0 = curVertices[vertexIndices[i]]; + gl.glNormal3f(n0.x(), n0.y(), n0.z()); + gl.glVertex3f(v0.x(), v0.y(), v0.z()); + i++; + + Vec3f n1 = curNormals[normalIndices[i]]; + Vec3f v1 = curVertices[vertexIndices[i]]; + gl.glNormal3f(n1.x(), n1.y(), n1.z()); + gl.glVertex3f(v1.x(), v1.y(), v1.z()); + i++; + + Vec3f n2 = curNormals[normalIndices[i]]; + Vec3f v2 = curVertices[vertexIndices[i]]; + gl.glNormal3f(n2.x(), n2.y(), n2.z()); + gl.glVertex3f(v2.x(), v2.y(), v2.z()); + i++; + } + gl.glEnd(); + if (lightingOn) + gl.glDisable(GL.GL_COLOR_MATERIAL); + } + + //---------------------------------------------------------------------- + // Used by subclasses to set up vertex, normals, and vertex and + // normal indices. + // + + protected void setVertices(Vec3f[] vertices) { + this.vertices = vertices; + } + + protected Vec3f[] getVertices() { + return vertices; + } + + protected void setNormals(Vec3f[] normals) { + this.normals = normals; + } + + protected Vec3f[] getNormals() { + return normals; + } + + protected void setVertexIndices(int[] vertexIndices) { + this.vertexIndices = vertexIndices; + } + + protected int[] getVertexIndices() { + return vertexIndices; + } + + protected void setNormalIndices(int[] normalIndices) { + this.normalIndices = normalIndices; + } + + protected int[] getNormalIndices() { + return normalIndices; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void consistencyCheck() { + if (vertexIndices.length != normalIndices.length) { + throw new RuntimeException("vertexIndices.length != normalIndices.length"); + } + + if ((vertexIndices.length % 3) != 0) { + throw new RuntimeException("(vertexIndices % 3) != 0"); + } + + if ((curVertices != null) && + (vertices.length != curVertices.length)) { + throw new RuntimeException("vertices.length != curVertices.length"); + } + } + + private void recalcVertices() { + if ((curVertices == null) || + (curVertices.length != vertices.length)) { + curVertices = new Vec3f[vertices.length]; + for (int i = 0; i < vertices.length; i++) { + curVertices[i] = new Vec3f(); + } + } + + for (int i = 0; i < vertices.length; i++) { + xform.xformPt(vertices[i], curVertices[i]); + } + + if ((curNormals == null) || + (curNormals.length != normals.length)) { + curNormals = new Vec3f[normals.length]; + for (int i = 0; i < normals.length; i++) { + curNormals[i] = new Vec3f(); + } + } + + for (int i = 0; i < normals.length; i++) { + xform.xformDir(normals[i], curNormals[i]); + curNormals[i].normalize(); + } + } +} diff --git a/src/gleem/ManipPartTwoWayArrow.java b/src/gleem/ManipPartTwoWayArrow.java new file mode 100644 index 0000000..77ba507 --- /dev/null +++ b/src/gleem/ManipPartTwoWayArrow.java @@ -0,0 +1,126 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; + +/** Piece of geometry defining a two-way arrow, used in Translate1 and + Translate2 manips. */ + +public class ManipPartTwoWayArrow extends ManipPartTriBased { + private static final Vec3f[] vertices = { + // Left tetrahedron + new Vec3f(-1.0f, 0.0f, 0.0f), + new Vec3f(-0.666666f, 0.166666f, 0.166666f), + new Vec3f(-0.666666f, -0.166666f, 0.166666f), + new Vec3f(-0.666666f, -0.166666f, -0.166666f), + new Vec3f(-0.666666f, 0.166666f, -0.166666f), + + // Box at center + new Vec3f(-0.666666f, 0.041666f, 0.0416666f), + new Vec3f(-0.666666f, -0.041666f, 0.0416666f), + new Vec3f(-0.666666f, -0.041666f, -0.0416666f), + new Vec3f(-0.666666f, 0.041666f, -0.0416666f), + new Vec3f(0.666666f, 0.041666f, 0.0416666f), + new Vec3f(0.666666f, -0.041666f, 0.0416666f), + new Vec3f(0.666666f, -0.041666f, -0.0416666f), + new Vec3f(0.666666f, 0.041666f, -0.0416666f), + + // Right tetrahedron + new Vec3f(0.666666f, 0.166666f, 0.166666f), + new Vec3f(0.666666f, 0.166666f, -0.166666f), + new Vec3f(0.666666f, -0.166666f, -0.166666f), + new Vec3f(0.666666f, -0.166666f, 0.166666f), + new Vec3f(1.0f, 0.0f, 0.0f), + }; + + private static final int[] vertexIndices = { + // Left tetrahedron + 1, 0, 2, + 2, 0, 3, + 3, 0, 4, + 4, 0, 1, + 1, 2, 3, + 1, 3, 4, + + // Box + 5, 7, 6, // left face + 5, 8, 7, + 5, 6, 10, // front face + 5, 10, 9, + 6, 7, 11, // bottom face + 6, 11, 10, + 7, 8, 12, // back face + 7, 12, 11, + 8, 5, 9, // top face + 8, 9, 12, + 9, 10, 11, // right face + 9, 11, 12, + + // Right tetrahedron + 13, 14, 15, + 13, 15, 16, + 17, 14, 13, + 17, 15, 14, + 17, 16, 15, + 17, 13, 16 + }; + + private static Vec3f[] normals = null; + private static int[] normalIndices = null; + + public ManipPartTwoWayArrow() { + super(); + + if (normals == null) { + NormalCalc.NormalInfo normInfo = + NormalCalc.computeFacetedNormals(vertices, vertexIndices, true); + normals = normInfo.normals; + normalIndices = normInfo.normalIndices; + } + + setVertices(vertices); + setVertexIndices(vertexIndices); + setNormals(normals); + setNormalIndices(normalIndices); + } +} diff --git a/src/gleem/MouseButtonHelper.java b/src/gleem/MouseButtonHelper.java new file mode 100644 index 0000000..f682c53 --- /dev/null +++ b/src/gleem/MouseButtonHelper.java @@ -0,0 +1,75 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.security.*; + +/** Helper class for figuring out how many mouse buttons are + available. (Does not seem to be a way of figuring this out with + the AWT.) */ + +public class MouseButtonHelper { + /** Returns the number of buttons on the mouse device. This is only + a guess and the implementation may need to be extended to + support other operating systems (in particular, Mac OS). */ + public static int numMouseButtons() { + String osName = null; + if (System.getSecurityManager() != null) { + osName = (String) + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return System.getProperty("os.name"); + } + }); + } else { + osName = System.getProperty("os.name"); + } + return mouseButtonsForOS(osName); + } + + private static int mouseButtonsForOS(String osName) { + if (osName.startsWith("Windows")) { + return 2; + } else { + // Assume X11 and a three-button mouse + return 3; + } + } +} diff --git a/src/gleem/NormalCalc.java b/src/gleem/NormalCalc.java new file mode 100644 index 0000000..635bd78 --- /dev/null +++ b/src/gleem/NormalCalc.java @@ -0,0 +1,118 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; + +/** Calculates normals for a set of polygons. */ + +public class NormalCalc { + + /** Set of normals computed using {@link gleem.NormalCalc}. */ + public static class NormalInfo { + public Vec3f[] normals; + public int[] normalIndices; + + NormalInfo(Vec3f[] normals, int[] normalIndices) { + this.normals = normals; + this.normalIndices = normalIndices; + } + } + + /** Returns null upon failure, or a set of Vec3fs and integers + which represent faceted (non-averaged) normals, but per-vertex. + Performs bounds checking on indices with respect to vertex list. + Index list must represent independent triangles; indices are + taken in groups of three. If index list doesn't represent + triangles or other error occurred then returns null. ccw flag + indicates whether triangles are specified counterclockwise when + viewed from top or not. */ + + public static NormalInfo computeFacetedNormals(Vec3f[] vertices, + int[] indices, + boolean ccw) { + if ((indices.length % 3) != 0) { + System.err.println("NormalCalc.computeFacetedNormals: numIndices wasn't " + + "divisible by 3, so it can't possibly " + + "represent a set of triangles"); + return null; + } + + Vec3f[] outputNormals = new Vec3f[indices.length / 3]; + int[] outputNormalIndices = new int[indices.length]; + + Vec3f d1 = new Vec3f(); + Vec3f d2 = new Vec3f(); + int curNormalIndex = 0; + for (int i = 0; i < indices.length; i += 3) { + int i0 = indices[i]; + int i1 = indices[i+1]; + int i2 = indices[i+2]; + if ((i0 < 0) || (i0 >= indices.length) || + (i1 < 0) || (i1 >= indices.length) || + (i2 < 0) || (i2 >= indices.length)) { + System.err.println("NormalCalc.computeFacetedNormals: ERROR: " + + "vertex index out of bounds or no end of triangle " + + "index found"); + return null; + } + Vec3f v0 = vertices[i0]; + Vec3f v1 = vertices[i1]; + Vec3f v2 = vertices[i2]; + d1.sub(v1, v0); + d2.sub(v2, v0); + Vec3f n = new Vec3f(); + if (ccw) { + n.cross(d1, d2); + } else { + n.cross(d2, d1); + } + n.normalize(); + outputNormals[curNormalIndex] = n; + outputNormalIndices[i] = curNormalIndex; + outputNormalIndices[i+1] = curNormalIndex; + outputNormalIndices[i+2] = curNormalIndex; + curNormalIndex++; + } + return new NormalInfo(outputNormals, outputNormalIndices); + } +} diff --git a/src/gleem/RayTriangleIntersection.java b/src/gleem/RayTriangleIntersection.java new file mode 100644 index 0000000..8b3417d --- /dev/null +++ b/src/gleem/RayTriangleIntersection.java @@ -0,0 +1,226 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/** Implements ray casting against a 3D triangle. */ + +public class RayTriangleIntersection { + public static final int ERROR = 0; + public static final int NO_INTERSECTION = 1; + public static final int INTERSECTION = 2; + + /** Allow roundoff error of this amount. Be very careful adjusting + this. Too big a value may cause valid triangles to be rejected. + Too small a value may trigger an assert in the code to create an + orthonormal basis in intersectRayWithTriangle. */ + private static final float epsilon = 1.0e-3f; + + /** Cast a ray starting at rayOrigin with rayDirection into the + triangle defined by vertices v0, v1, and v2. If intersection + occurred returns INTERSECTION and sets intersectionPoint + appropriately, including t parameter (scale factor for + rayDirection to reach intersection plane starting from + rayOrigin). Returns NO_INTERSECTION if no intersection, or ERROR + if triangle was degenerate or line was parallel to plane of + triangle. */ + public static int intersectRayWithTriangle(Vec3f rayOrigin, + Vec3f rayDirection, + Vec3f v0, + Vec3f v1, + Vec3f v2, + IntersectionPoint intersectionPoint) { + // Returns INTERSECTION if intersection computed, NO_INTERSECTION + // if no intersection with triangle, ERROR if triangle was + // degenerate or line did not intersect plane containing triangle. + + // NOTE these rays are TWO-SIDED. + + // Find point on line. P = ray origin, D = ray direction. + // P + tD = W + // Find point on plane. X, Y = orthonormal bases for plane; O = its origin. + // O + uX + vY = W + // Set equal + // O + uX + vY = tD + P + // uX + vY - tD = P - O = "B" + // [X0 Y0 -D0] [u] [B0] + // [X1 Y1 -D1] [v] = [B1] + // [X2 Y2 -D2] [t] [B2] + // Now we have u, v coordinates for the intersection point (if system + // wasn't degenerate). + // Find u, v coordinates for three points of triangle. (DON'T DUPLICATE + // WORK.) Now easy to do 2D inside/outside test. + // If point is inside, do some sort of interpolation to compute the + // 3D coordinates of the intersection point (may be unnecessary -- + // can reuse X, Y bases from above) and texture coordinates of this + // point (maybe compute "texture coordinate" bases using same algorithm + // and just use u, v coordinates??). + + Vec3f O = new Vec3f(v0); + Vec3f p2 = new Vec3f(); + p2.sub(v1, O); + Vec3f p3 = new Vec3f(); + p3.sub(v2, O); + + Vec3f X = new Vec3f(p2); + Vec3f Y = new Vec3f(p3); + + // Normalize X + if (X.length() < epsilon) + return ERROR; // coincident points in triangle + X.normalize(); + + // Use Gramm-Schmitt to orthogonalize X and Y + Vec3f tmp = new Vec3f(X); + tmp.scale(X.dot(Y)); + Y.sub(tmp); + if (Y.length() < epsilon) { + return ERROR; // coincident points in triangle + } + Y.normalize(); + + // X and Y are now orthonormal bases for the plane defined by the + // triangle. + + Vec3f Bv = new Vec3f(); + Bv.sub(rayOrigin, O); + + Mat3f A = new Mat3f(); + A.setCol(0, X); + A.setCol(1, Y); + Vec3f tmpRayDir = new Vec3f(rayDirection); + tmpRayDir.scale(-1.0f); + A.setCol(2, tmpRayDir); + if (!A.invert()) { + return ERROR; + } + Vec3f B = new Vec3f(); + A.xformVec(Bv, B); + + Vec2f W = new Vec2f(B.x(), B.y()); + + // Compute u,v coords of triangle + Vec2f[] uv = new Vec2f[3]; + uv[0] = new Vec2f(0,0); + uv[1] = new Vec2f(p2.dot(X), p2.dot(Y)); + uv[2] = new Vec2f(p3.dot(X), p3.dot(Y)); + + if (!(Math.abs(uv[1].y()) < epsilon)) { + throw new RuntimeException("Math.abs(uv[1].y()) >= epsilon"); + } + + // Test. For each of the sides of the triangle, is the intersection + // point on the same side as the third vertex of the triangle? + // If so, intersection point is inside triangle. + for (int i = 0; i < 3; i++) { + if (approxOnSameSide(uv[i], uv[(i+1)%3], + uv[(i+2)%3], W) == false) { + return NO_INTERSECTION; + } + } + + // Blend coordinates and texture coordinates according to + // distances from 3 points + // To do: find u,v coordinates of intersection point in coordinate + // system of axes defined by uv[1] and uv[2]. + // Blending coords == a, b. 0 <= a,b <= 1. + if (!(Math.abs(uv[2].y()) > epsilon)) { + throw new RuntimeException("Math.abs(uv[2].y()) <= epsilon"); + } + if (!(Math.abs(uv[1].x()) > epsilon)) { + throw new RuntimeException("Math.abs(uv[1].x()) <= epsilon"); + } + float a, b; + b = W.y() / uv[2].y(); + a = (W.x() - b * uv[2].x()) / uv[1].x(); + + p2.scale(a); + p3.scale(b); + O.add(p2); + O.add(p3); + intersectionPoint.setIntersectionPoint(O); + intersectionPoint.setT(B.z()); + return INTERSECTION; + } + + private static boolean approxOnSameSide(Vec2f linePt1, Vec2f linePt2, + Vec2f testPt1, Vec2f testPt2) { + // Evaluate line equation for testPt1 and testPt2 + + // ((y2 - y1) / (x2 - x1)) - ((y1 - y) / (x1 - x)) + // y - (mx + b) + float num0 = linePt2.y() - linePt1.y(); + float den0 = linePt2.x() - linePt1.x(); + float num1 = linePt1.y() - testPt1.y(); + float den1 = linePt1.x() - testPt1.x(); + float num2 = linePt1.y() - testPt2.y(); + float den2 = linePt1.x() - testPt2.x(); + + if (Math.abs(den0) < epsilon) { + // line goes vertically. + if ((Math.abs(den1) < epsilon) || + (Math.abs(den2) < epsilon)) { + return true; + } + + if (MathUtil.sgn(den1) == MathUtil.sgn(den2)) { + return true; + } + + return false; + } + + float m = num0 / den0; + // (y - y1) - m(x - x1) + float val1 = testPt1.y() - linePt1.y() - m * (testPt1.x() - linePt1.x()); + float val2 = testPt2.y() - linePt1.y() - m * (testPt2.x() - linePt1.x()); + if ((Math.abs(val1) < epsilon) || + (Math.abs(val2) < epsilon)) { + return true; + } + + if (MathUtil.sgn(val1) == MathUtil.sgn(val2)) { + return true; + } + + return false; + } +} diff --git a/src/gleem/RightTruncPyrMapping.java b/src/gleem/RightTruncPyrMapping.java new file mode 100644 index 0000000..d25c17a --- /dev/null +++ b/src/gleem/RightTruncPyrMapping.java @@ -0,0 +1,64 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/** The only mapping gleem supports right now -- a right truncated + pyramid. */ + +public class RightTruncPyrMapping implements ScreenToRayMapping { + public void mapScreenToRay(Vec2f screenCoords, + CameraParameters params, + Vec3f raySource, + Vec3f rayDirection) { + Vec3f fwd = new Vec3f(params.getForwardDirection()); + Vec3f up = new Vec3f(params.getUpDirection()); + Vec3f right = fwd.cross(up); + fwd.normalize(); + up.normalize(); + right.normalize(); + float horizFOV = (float) Math.atan(params.imagePlaneAspectRatio * Math.tan(params.vertFOV)); + right.scale((float) (Math.tan(horizFOV) * screenCoords.get(0))); + up .scale((float) (Math.tan(params.vertFOV) * screenCoords.get(1))); + raySource.set(params.getPosition()); + rayDirection.set(fwd.plus(up).plus(right)); + } +} diff --git a/src/gleem/ScreenToRayMapping.java b/src/gleem/ScreenToRayMapping.java new file mode 100644 index 0000000..f77da8b --- /dev/null +++ b/src/gleem/ScreenToRayMapping.java @@ -0,0 +1,73 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import gleem.linalg.*; + +/**

This interface defines the mapping from normalized screen + coordinates to a 3D ray based on the given camera parameters. You + could subclass it to allow for more types of camera frusta, but + would also have to modify the CameraParameters structure.

+ +

The "normalized" screen coordinates must have the following + properties:

+ +

+ upper left corner = (-1, 1)
+ lower left corner = (-1, -1)
+ lower right corner = (1, -1)
+ upper right corner = (1, 1)
+ center = (0, 0) +

+ +

The application is responsible for specifying the window size + to allow the ManipManager to compute these coordinates.

+*/ + +public interface ScreenToRayMapping { + /** Maps screen (x, y) to 3D point source and direction based on + given CameraParameters. screenCoords and params are incoming + arguments; raySource and rayDirection are mutated to contain the + result. */ + public void mapScreenToRay(Vec2f screenCoords, + CameraParameters params, + Vec3f raySource, + Vec3f rayDirection); +} diff --git a/src/gleem/TestExaminerViewer.java b/src/gleem/TestExaminerViewer.java new file mode 100644 index 0000000..55d0283 --- /dev/null +++ b/src/gleem/TestExaminerViewer.java @@ -0,0 +1,153 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.*; +import java.awt.event.*; +import net.java.games.jogl.*; +import gleem.linalg.*; + +/** Tests the Examiner Viewer. */ + +public class TestExaminerViewer { + private static final int X_SIZE = 400; + private static final int Y_SIZE = 400; + + static class HandleBoxManipBSphereProvider implements BSphereProvider { + private HandleBoxManip manip; + + private HandleBoxManipBSphereProvider(HandleBoxManip manip) { + this.manip = manip; + } + + public BSphere getBoundingSphere() { + BSphere bsph = new BSphere(); + bsph.setCenter(manip.getTranslation()); + Vec3f scale0 = manip.getScale(); + Vec3f scale1 = manip.getGeometryScale(); + Vec3f scale = new Vec3f(); + scale.setX(2.0f * scale0.x() * scale1.x()); + scale.setY(2.0f * scale0.y() * scale1.y()); + scale.setZ(2.0f * scale0.z() * scale1.z()); + bsph.setRadius(scale.length()); + return bsph; + } + } + + static class Listener implements GLEventListener { + private GL gl; + private GLU glu; + private CameraParameters params = new CameraParameters(); + private ExaminerViewer viewer; + + public void init(GLDrawable drawable) { + gl = drawable.getGL(); + glu = drawable.getGLU(); + + gl.glClearColor(0, 0, 0, 0); + float[] lightPosition = new float[] {1, 1, 1, 0}; + float[] ambient = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; + float[] diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; + gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition); + + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + params.setPosition(new Vec3f(0, 0, 0)); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) (Math.PI / 8.0)); + params.setImagePlaneAspectRatio(1); + params.xSize = X_SIZE; + params.ySize = Y_SIZE; + + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(45, 1, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + // Register the window with the ManipManager + ManipManager manager = ManipManager.getManipManager(); + manager.registerWindow(drawable); + + // Instantiate a HandleBoxManip + HandleBoxManip manip = new HandleBoxManip(); + manip.setTranslation(new Vec3f(0, 0, -10)); + manager.showManipInWindow(manip, drawable); + + // Instantiate ExaminerViewer + viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons()); + viewer.attach(drawable, new HandleBoxManipBSphereProvider(manip)); + viewer.viewAll(gl); + } + + public void display(GLDrawable drawable) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + viewer.update(gl); + ManipManager.getManipManager().updateCameraParameters(drawable, viewer.getCameraParameters()); + ManipManager.getManipManager().render(drawable, gl); + } + + // Unused routines + public void reshape(GLDrawable drawable, int x, int y, int w, int h) {} + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + } + + public static void main(String[] args) { + Frame frame = new Frame("ExaminerViewer Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + frame.setLayout(new BorderLayout()); + GLCanvas canvas = + GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); + canvas.setSize(400, 400); + canvas.addGLEventListener(new Listener()); + frame.add(canvas, BorderLayout.CENTER); + frame.pack(); + frame.show(); + } +} diff --git a/src/gleem/TestHandleBox.java b/src/gleem/TestHandleBox.java new file mode 100644 index 0000000..adf8e32 --- /dev/null +++ b/src/gleem/TestHandleBox.java @@ -0,0 +1,142 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.*; +import java.awt.event.*; +import net.java.games.jogl.*; +import gleem.linalg.*; + +/** Tests the HandleBox Manip. */ + +public class TestHandleBox { + private static final int X_SIZE = 400; + private static final int Y_SIZE = 400; + + static class Listener implements GLEventListener { + private GL gl; + private GLU glu; + private CameraParameters params = new CameraParameters(); + + public void init(GLDrawable drawable) { + gl = drawable.getGL(); + glu = drawable.getGLU(); + + gl.glClearColor(0, 0, 0, 0); + float[] lightPosition = new float[] {1, 1, 1, 0}; + float[] ambient = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; + float[] diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; + gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition); + + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + params.setPosition(new Vec3f(0, 0, 0)); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) (Math.PI / 8.0)); + params.setImagePlaneAspectRatio(1); + params.xSize = X_SIZE; + params.ySize = Y_SIZE; + + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(45, 1, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + // Register the window with the ManipManager + ManipManager manager = ManipManager.getManipManager(); + manager.registerWindow(drawable); + + // Instantiate a HandleBoxManip + HandleBoxManip manip = new HandleBoxManip(); + manip.setTranslation(new Vec3f(0, 0, -10)); + manager.showManipInWindow(manip, drawable); + } + + public void display(GLDrawable drawable) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + ManipManager.getManipManager().updateCameraParameters(drawable, params); + ManipManager.getManipManager().render(drawable, gl); + } + + public void reshape(GLDrawable drawable, int x, int y, int w, int h) { + float aspect, theta; + aspect = (float) w / (float) h; + if (w >= h) + theta = 45; + else + theta = (float) Math.toDegrees(Math.atan(1 / aspect)); + params.setVertFOV((float) Math.toRadians(theta) / 2.0f); + params.setImagePlaneAspectRatio(aspect); + params.setXSize(w); + params.setYSize(h); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(theta, aspect, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + } + + // Unused routines + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + } + + public static void main(String[] args) { + Frame frame = new Frame("HandleBox Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + frame.setLayout(new BorderLayout()); + GLCanvas canvas = + GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); + canvas.setSize(400, 400); + canvas.addGLEventListener(new Listener()); + frame.add(canvas, BorderLayout.CENTER); + frame.pack(); + frame.show(); + } +} diff --git a/src/gleem/TestMultiWin.java b/src/gleem/TestMultiWin.java new file mode 100644 index 0000000..ce2c257 --- /dev/null +++ b/src/gleem/TestMultiWin.java @@ -0,0 +1,162 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.*; +import java.awt.event.*; +import net.java.games.jogl.*; +import gleem.linalg.*; + +/** Tests viewing manipulators in multiple winodws. */ + +public class TestMultiWin { + private static final int X_SIZE = 400; + private static final int Y_SIZE = 400; + + private static HandleBoxManip manip; + + static class HandleBoxManipBSphereProvider implements BSphereProvider { + private HandleBoxManip manip; + + private HandleBoxManipBSphereProvider(HandleBoxManip manip) { + this.manip = manip; + } + + public BSphere getBoundingSphere() { + BSphere bsph = new BSphere(); + bsph.setCenter(manip.getTranslation()); + Vec3f scale0 = manip.getScale(); + Vec3f scale1 = manip.getGeometryScale(); + Vec3f scale = new Vec3f(); + scale.setX(2.0f * scale0.x() * scale1.x()); + scale.setY(2.0f * scale0.y() * scale1.y()); + scale.setZ(2.0f * scale0.z() * scale1.z()); + bsph.setRadius(scale.length()); + return bsph; + } + } + + static class Listener implements GLEventListener { + private GL gl; + private GLU glu; + private CameraParameters params = new CameraParameters(); + private ExaminerViewer viewer; + + public void init(GLDrawable drawable) { + gl = drawable.getGL(); + glu = drawable.getGLU(); + + gl.glClearColor(0, 0, 0, 0); + float[] lightPosition = new float[] {1, 1, 1, 0}; + float[] ambient = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; + float[] diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; + gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition); + + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + params.setPosition(new Vec3f(0, 0, 0)); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) (Math.PI / 8.0)); + params.setImagePlaneAspectRatio(1); + params.xSize = X_SIZE; + params.ySize = Y_SIZE; + + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(45, 1, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + // Register the window with the ManipManager + ManipManager manager = ManipManager.getManipManager(); + manager.registerWindow(drawable); + + manager.showManipInWindow(manip, drawable); + + // Instantiate ExaminerViewer + viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons()); + viewer.attach(drawable, new HandleBoxManipBSphereProvider(manip)); + viewer.viewAll(gl); + } + + public void display(GLDrawable drawable) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + viewer.update(gl); + ManipManager.getManipManager().updateCameraParameters(drawable, viewer.getCameraParameters()); + ManipManager.getManipManager().render(drawable, gl); + } + + // Unused routines + public void reshape(GLDrawable drawable, int x, int y, int w, int h) {} + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + } + + private static void showFrame(String name, Point location) { + Frame frame = new Frame(name); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + frame.setLayout(new BorderLayout()); + GLCanvas canvas = + GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); + canvas.setSize(400, 400); + canvas.addGLEventListener(new Listener()); + frame.add(canvas, BorderLayout.CENTER); + frame.pack(); + frame.setLocation(location); + frame.show(); + } + + public static void main(String[] args) { + // Instantiate HandleBoxManip + manip = new HandleBoxManip(); + manip.setTranslation(new Vec3f(0, 0, -10)); + + showFrame("MultiWin Test 1/2", new Point(0, 0)); + showFrame("MultiWin Test 2/2", new Point(400, 0)); + } +} diff --git a/src/gleem/TestTranslate1.java b/src/gleem/TestTranslate1.java new file mode 100644 index 0000000..131fa0c --- /dev/null +++ b/src/gleem/TestTranslate1.java @@ -0,0 +1,143 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.*; +import java.awt.event.*; +import net.java.games.jogl.*; +import gleem.linalg.*; + +/** Tests the Translate1 Manip. */ + +public class TestTranslate1 { + private static final int X_SIZE = 400; + private static final int Y_SIZE = 400; + + static class Listener implements GLEventListener { + private GL gl; + private GLU glu; + private CameraParameters params = new CameraParameters(); + + public void init(GLDrawable drawable) { + gl = drawable.getGL(); + glu = drawable.getGLU(); + + gl.glClearColor(0, 0, 0, 0); + float[] lightPosition = new float[] {1, 1, 1, 0}; + float[] ambient = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; + float[] diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; + gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition); + + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + params.setPosition(new Vec3f(0, 0, 0)); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) (Math.PI / 8.0)); + params.setImagePlaneAspectRatio(1); + params.xSize = X_SIZE; + params.ySize = Y_SIZE; + + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(45, 1, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + // Register the window with the ManipManager + ManipManager manager = ManipManager.getManipManager(); + manager.registerWindow(drawable); + + // Instantiate a Translate1Manip + Translate1Manip manip = new Translate1Manip(); + manip.setTranslation(new Vec3f(0, 0, -5)); + manip.setAxis(new Vec3f(-1, 0.5f, 1)); + manager.showManipInWindow(manip, drawable); + } + + public void display(GLDrawable drawable) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + ManipManager.getManipManager().updateCameraParameters(drawable, params); + ManipManager.getManipManager().render(drawable, gl); + } + + public void reshape(GLDrawable drawable, int x, int y, int w, int h) { + float aspect, theta; + aspect = (float) w / (float) h; + if (w >= h) + theta = 45; + else + theta = (float) Math.toDegrees(Math.atan(1 / aspect)); + params.setVertFOV((float) Math.toRadians(theta) / 2.0f); + params.setImagePlaneAspectRatio(aspect); + params.setXSize(w); + params.setYSize(h); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(theta, aspect, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + } + + // Unused routines + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + } + + public static void main(String[] args) { + Frame frame = new Frame("Translate1 Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + frame.setLayout(new BorderLayout()); + GLCanvas canvas = + GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); + canvas.setSize(400, 400); + canvas.addGLEventListener(new Listener()); + frame.add(canvas, BorderLayout.CENTER); + frame.pack(); + frame.show(); + } +} diff --git a/src/gleem/TestTranslate2.java b/src/gleem/TestTranslate2.java new file mode 100644 index 0000000..1789575 --- /dev/null +++ b/src/gleem/TestTranslate2.java @@ -0,0 +1,143 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.awt.*; +import java.awt.event.*; +import net.java.games.jogl.*; +import gleem.linalg.*; + +/** Tests the Translate2 Manip. */ + +public class TestTranslate2 { + private static final int X_SIZE = 400; + private static final int Y_SIZE = 400; + + static class Listener implements GLEventListener { + private GL gl; + private GLU glu; + private CameraParameters params = new CameraParameters(); + + public void init(GLDrawable drawable) { + gl = drawable.getGL(); + glu = drawable.getGLU(); + + gl.glClearColor(0, 0, 0, 0); + float[] lightPosition = new float[] {1, 1, 1, 0}; + float[] ambient = new float[] { 0.0f, 0.0f, 0.0f, 1.0f }; + float[] diffuse = new float[] { 1.0f, 1.0f, 1.0f, 1.0f }; + gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse); + gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition); + + gl.glEnable(GL.GL_LIGHTING); + gl.glEnable(GL.GL_LIGHT0); + gl.glEnable(GL.GL_DEPTH_TEST); + + params.setPosition(new Vec3f(0, 0, 0)); + params.setForwardDirection(Vec3f.NEG_Z_AXIS); + params.setUpDirection(Vec3f.Y_AXIS); + params.setVertFOV((float) (Math.PI / 8.0)); + params.setImagePlaneAspectRatio(1); + params.xSize = X_SIZE; + params.ySize = Y_SIZE; + + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(45, 1, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + + // Register the window with the ManipManager + ManipManager manager = ManipManager.getManipManager(); + manager.registerWindow(drawable); + + // Instantiate a Translate2Manip + Translate2Manip manip = new Translate2Manip(); + manip.setTranslation(new Vec3f(0, 0, -5)); + manip.setNormal(new Vec3f(-1, 1, 1)); + manager.showManipInWindow(manip, drawable); + } + + public void display(GLDrawable drawable) { + gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); + ManipManager.getManipManager().updateCameraParameters(drawable, params); + ManipManager.getManipManager().render(drawable, gl); + } + + public void reshape(GLDrawable drawable, int x, int y, int w, int h) { + float aspect, theta; + aspect = (float) w / (float) h; + if (w >= h) + theta = 45; + else + theta = (float) Math.toDegrees(Math.atan(1 / aspect)); + params.setVertFOV((float) Math.toRadians(theta) / 2.0f); + params.setImagePlaneAspectRatio(aspect); + params.setXSize(w); + params.setYSize(h); + gl.glMatrixMode(GL.GL_PROJECTION); + gl.glLoadIdentity(); + glu.gluPerspective(theta, aspect, 1, 100); + gl.glMatrixMode(GL.GL_MODELVIEW); + gl.glLoadIdentity(); + } + + // Unused routines + public void displayChanged(GLDrawable drawable, boolean modeChanged, boolean deviceChanged) {} + } + + public static void main(String[] args) { + Frame frame = new Frame("Translate2 Test"); + frame.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + frame.setLayout(new BorderLayout()); + GLCanvas canvas = + GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities()); + canvas.setSize(400, 400); + canvas.addGLEventListener(new Listener()); + frame.add(canvas, BorderLayout.CENTER); + frame.pack(); + frame.show(); + } +} diff --git a/src/gleem/Translate1Manip.java b/src/gleem/Translate1Manip.java new file mode 100644 index 0000000..541173f --- /dev/null +++ b/src/gleem/Translate1Manip.java @@ -0,0 +1,208 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** A Translate1Manip is a Manip which translates in only one + dimension and whose default representation is a two-way arrow. */ + +public class Translate1Manip extends Manip { + private ManipPart parts; + private Vec3f translation; + /** Normalized */ + private Vec3f axis; + private Vec3f scale; + /** Local-to-world transform for geometry */ + private Mat4f xform; + + /** Dragging state */ + private Line dragLine; + /** Dragging state */ + private Vec3f dragOffset; + + public Translate1Manip() { + parts = new ManipPartTwoWayArrow(); + translation = new Vec3f(0, 0, 0); + axis = new Vec3f(1, 0, 0); + scale = new Vec3f(1, 1, 1); + xform = new Mat4f(); + dragLine = new Line(); + dragOffset = new Vec3f(); + recalc(); + } + + /** Set the translation of this Translate1Manip. This moves its + on-screen representation. Manipulations cause the translation to + be modified, not overwritten, so if you want the default + Translate1Manip to go through the point (0, 1, 0) but still + translate along the X axis, then setTranslation(0, 1, 0). */ + public void setTranslation(Vec3f translation) { + this.translation.set(translation); + recalc(); + } + + /** Get the translation of this Translate1Manip. This corresponds to + the center of its body. */ + public Vec3f getTranslation() { + return new Vec3f(translation); + } + + /** Set the axis of this Translate1Manip. This is the direction + along which it will travel. Does not need to be normalized, but + must not be the zero vector. */ + public void setAxis(Vec3f axis) { + this.axis.set(axis); + recalc(); + } + + /** Get the axis of this Translate1Manip. */ + public Vec3f getAxis() { + return new Vec3f(axis); + } + + /** Set the scale of the Translate1Manip. This only affects the size + of the on-screen geometry. */ + public void setScale(Vec3f scale) { + this.scale.set(scale); + recalc(); + } + + public Vec3f getScale() { + return new Vec3f(scale); + } + + /** Change the geometry of this manipulator to be the user-defined + piece. */ + public void replaceGeometry(ManipPart geom) { + parts = geom; + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results) { + parts.intersectRay(rayStart, rayDirection, results, this); + } + + public void highlight(HitPoint hit) { + if (hit.manipPart != parts) { + throw new RuntimeException("My old geometry disappeared; how did this happen?"); + } + parts.highlight(); + } + + public void clearHighlight() { + parts.clearHighlight(); + } + + public void makeActive(HitPoint hit) { + parts.highlight(); + dragLine.setDirection(axis); + dragLine.setPoint(hit.intPt.getIntersectionPoint()); + dragOffset.sub(translation, hit.intPt.getIntersectionPoint()); + } + + public void drag(Vec3f rayStart, + Vec3f rayDirection) { + // Algorithm: Find closest point of ray to dragLine. Add dragOffset + // to this point to get new translation. + Vec3f closestPoint = new Vec3f(); + if (dragLine.closestPointToRay(rayStart, + rayDirection, + closestPoint) == false) { + // Drag axis is parallel to ray. Punt. + return; + } + translation.set(closestPoint); + translation.add(dragOffset); + recalc(); + super.drag(rayStart, rayDirection); + } + + public void makeInactive() { + parts.clearHighlight(); + } + + public void render(GL gl) { + parts.render(gl); + } + + private void recalc() { + // Construct local to world transform for geometry. + // Scale, Rotation, Translation. Since we're right multiplying + // column vectors, the actual matrix composed is TRS. + Mat4f scaleMat = new Mat4f(); + Mat4f rotMat = new Mat4f(); + Mat4f xlateMat = new Mat4f(); + Mat4f tmpMat = new Mat4f(); + scaleMat.makeIdent(); + scaleMat.set(0, 0, scale.x()); + scaleMat.set(1, 1, scale.y()); + scaleMat.set(2, 2, scale.z()); + // Perpendiculars + Vec3f p0 = new Vec3f(); + Vec3f p1 = new Vec3f(); + MathUtil.makePerpendicular(axis, p0); + p1.cross(axis, p0); + // axis, p0, p1 correspond to x, y, z + p0.normalize(); + p1.normalize(); + rotMat.makeIdent(); + rotMat.set(0, 0, axis.x()); + rotMat.set(1, 0, axis.y()); + rotMat.set(2, 0, axis.z()); + rotMat.set(0, 1, p0.x()); + rotMat.set(1, 1, p0.y()); + rotMat.set(2, 1, p0.z()); + rotMat.set(0, 2, p1.x()); + rotMat.set(1, 2, p1.y()); + rotMat.set(2, 2, p1.z()); + xlateMat.makeIdent(); + xlateMat.set(0, 3, translation.x()); + xlateMat.set(1, 3, translation.y()); + xlateMat.set(2, 3, translation.z()); + tmpMat.mul(xlateMat, rotMat); + xform.mul(tmpMat, scaleMat); + parts.setTransform(xform); + } +} diff --git a/src/gleem/Translate2Manip.java b/src/gleem/Translate2Manip.java new file mode 100644 index 0000000..a76df48 --- /dev/null +++ b/src/gleem/Translate2Manip.java @@ -0,0 +1,230 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import java.util.*; + +import gleem.linalg.*; +import net.java.games.jogl.*; + +/** A Translate2Manip is a Manip which translates in two dimensions and + whose default representation is two arrows. */ + +public class Translate2Manip extends Manip { + private ManipPart parts; + private Vec3f translation; + /** Normalized */ + private Vec3f normal; + private Vec3f scale; + /** Local-to-world transform for geometry */ + private Mat4f xform; + + /** Dragging state */ + private Plane dragPlane; + /** Dragging state */ + private Vec3f dragOffset; + + public Translate2Manip() { + parts = createGeometry(); + translation = new Vec3f(0, 0, 0); + normal = new Vec3f(0, 1, 0); + scale = new Vec3f(1, 1, 1); + xform = new Mat4f(); + dragPlane = new Plane(); + dragOffset = new Vec3f(); + recalc(); + } + + /** Set the translation of this Translate2Manip. This moves its + on-screen representation. Manipulations cause the translation to + be modified, not overwritten, so if you want the default + Translate2Manip to go through the point (0, 1, 0) but still + translate in the X-Z plane, then setTranslation(0, 1, 0). */ + public void setTranslation(Vec3f translation) { + this.translation.set(translation); + recalc(); + } + + /** Get the translation of this Translate2Manip. This corresponds to + the center of its body. */ + public Vec3f getTranslation() { + return new Vec3f(translation); + } + + /** Set the normal of this Translate2Manip. The manip moves in the + plane containing its current position and perpendicular to this + normal. Does not need to be normalized, but must not be the zero + vector. */ + public void setNormal(Vec3f normal) { + this.normal.set(normal); + this.normal.normalize(); + recalc(); + } + + /** Get the normal of this Translate2Manip. */ + public Vec3f getNormal() { + return new Vec3f(normal); + } + + /** Set the scale of the Translate2Manip. This only affects the size + of the on-screen geometry. */ + public void setScale(Vec3f scale) { + this.scale.set(scale); + recalc(); + } + + public Vec3f getScale() { + return new Vec3f(scale); + } + + /** Change the geometry of this manipulator to be the user-defined + piece. */ + public void replaceGeometry(ManipPart geom) { + parts = geom; + } + + public void intersectRay(Vec3f rayStart, + Vec3f rayDirection, + List results) { + parts.intersectRay(rayStart, rayDirection, results, this); + } + + public void highlight(HitPoint hit) { + if (hit.manipPart != parts) { + throw new RuntimeException("My old geometry disappeared; how did this happen?"); + } + parts.highlight(); + } + + public void clearHighlight() { + parts.clearHighlight(); + } + + public void makeActive(HitPoint hit) { + parts.highlight(); + dragPlane.setNormal(normal); + dragPlane.setPoint(hit.intPt.getIntersectionPoint()); + dragOffset.sub(translation, hit.intPt.getIntersectionPoint()); + } + + public void drag(Vec3f rayStart, + Vec3f rayDirection) { + // Algorithm: Find intersection of ray with dragPlane. Add + // dragOffset to this point to get new translation. + IntersectionPoint intPt = new IntersectionPoint(); + if (dragPlane.intersectRay(rayStart, + rayDirection, + intPt) == false) { + // Ray is parallel to plane. Punt. + return; + } + translation.set(intPt.getIntersectionPoint()); + translation.add(dragOffset); + recalc(); + super.drag(rayStart, rayDirection); + } + + public void makeInactive() { + parts.clearHighlight(); + } + + public void render(GL gl) { + parts.render(gl); + } + + private ManipPart createGeometry() { + ManipPartGroup group = new ManipPartGroup(); + ManipPartTwoWayArrow arrow1 = new ManipPartTwoWayArrow(); + group.addChild(arrow1); + ManipPartTransform xform = new ManipPartTransform(); + Mat4f rotMat = new Mat4f(); + rotMat.makeIdent(); + rotMat.set(0, 0, 0); + rotMat.set(1, 0, 0); + rotMat.set(2, 0, -1); + rotMat.set(0, 2, 1); + rotMat.set(1, 2, 0); + rotMat.set(2, 2, 0); + xform.setOffsetTransform(rotMat); + ManipPartTwoWayArrow arrow2 = new ManipPartTwoWayArrow(); + xform.addChild(arrow2); + group.addChild(xform); + return group; + } + + private void recalc() { + // Construct local to world transform for geometry. + // Scale, Rotation, Translation. Since we're right multiplying + // column vectors, the actual matrix composed is TRS. + Mat4f scaleMat = new Mat4f(); + Mat4f rotMat = new Mat4f(); + Mat4f xlateMat = new Mat4f(); + Mat4f tmpMat = new Mat4f(); + scaleMat.makeIdent(); + scaleMat.set(0, 0, scale.x()); + scaleMat.set(1, 1, scale.y()); + scaleMat.set(2, 2, scale.z()); + // Perpendiculars + Vec3f p0 = new Vec3f(); + Vec3f p1 = new Vec3f(); + MathUtil.makePerpendicular(normal, p0); + p1.cross(normal, p0); + // p1, normal, p0 correspond to x, y, z + p0.normalize(); + p1.normalize(); + rotMat.makeIdent(); + rotMat.set(0, 0, p1.x()); + rotMat.set(1, 0, p1.y()); + rotMat.set(2, 0, p1.z()); + rotMat.set(0, 1, normal.x()); + rotMat.set(1, 1, normal.y()); + rotMat.set(2, 1, normal.z()); + rotMat.set(0, 2, p0.x()); + rotMat.set(1, 2, p0.y()); + rotMat.set(2, 2, p0.z()); + xlateMat.makeIdent(); + xlateMat.set(0, 3, translation.x()); + xlateMat.set(1, 3, translation.y()); + xlateMat.set(2, 3, translation.z()); + tmpMat.mul(xlateMat, rotMat); + xform.mul(tmpMat, scaleMat); + parts.setTransform(xform); + } +} diff --git a/src/gleem/WindowUpdateListener.java b/src/gleem/WindowUpdateListener.java new file mode 100644 index 0000000..b91ee05 --- /dev/null +++ b/src/gleem/WindowUpdateListener.java @@ -0,0 +1,51 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem; + +import net.java.games.jogl.*; + +/** A WindowUpdateListener is used by the ManipManager to transmit + repaint() notifications to windows containing Manips. When a Manip + is moved, the ManipManager sends update notifications to all + GLDrawables in which that Manip is shown. */ + +public interface WindowUpdateListener { + public void update(GLDrawable window); +} diff --git a/src/gleem/linalg/DimensionMismatchException.java b/src/gleem/linalg/DimensionMismatchException.java new file mode 100644 index 0000000..612d49d --- /dev/null +++ b/src/gleem/linalg/DimensionMismatchException.java @@ -0,0 +1,53 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Thrown to indicate a mismatch of dimensionality of a matrix or + vector. */ + +public class DimensionMismatchException extends RuntimeException { + public DimensionMismatchException() { + super(); + } + + public DimensionMismatchException(String msg) { + super(msg); + } +} diff --git a/src/gleem/linalg/IntersectionPoint.java b/src/gleem/linalg/IntersectionPoint.java new file mode 100644 index 0000000..486be06 --- /dev/null +++ b/src/gleem/linalg/IntersectionPoint.java @@ -0,0 +1,63 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Wraps a 3D point and parametric time value. */ + +public class IntersectionPoint { + private Vec3f intPt = new Vec3f(); + private float t; + + public Vec3f getIntersectionPoint() { + return intPt; + } + + public void setIntersectionPoint(Vec3f newPt) { + intPt.set(newPt); + } + + public float getT() { + return t; + } + + public void setT(float t) { + this.t = t; + } +} diff --git a/src/gleem/linalg/Line.java b/src/gleem/linalg/Line.java new file mode 100644 index 0000000..cbf8efd --- /dev/null +++ b/src/gleem/linalg/Line.java @@ -0,0 +1,152 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Represents a line in 3D space. */ + +public class Line { + private Vec3f point; + /** Normalized */ + private Vec3f direction; + /** For computing projections along line */ + private Vec3f alongVec; + + /** Default constructor initializes line to point (0, 0, 0) and + direction (1, 0, 0) */ + public Line() { + point = new Vec3f(0, 0, 0); + direction = new Vec3f(1, 0, 0); + alongVec = new Vec3f(); + recalc(); + } + + /** Line goes in direction direction through the point + point. direction 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); + alongVec = new Vec3f(); + recalc(); + } + + /** Setter does some work to maintain internal caches. + direction does not need to be normalized but must not be + the zero vector. */ + public void setDirection(Vec3f direction) { + this.direction.set(direction); + this.direction.normalize(); + recalc(); + } + + /** Direction is normalized internally, so direction is not + necessarily equal to plane.setDirection(direction); + plane.getDirection(); */ + public Vec3f getDirection() { + return direction; + } + + /** Setter does some work to maintain internal caches. */ + public void setPoint(Vec3f point) { + this.point.set(point); + recalc(); + } + + public Vec3f getPoint() { + return point; + } + + /** Project a point onto the line */ + public void projectPoint(Vec3f pt, + Vec3f projPt) { + float dotp = direction.dot(pt); + projPt.set(direction); + projPt.scale(dotp); + projPt.add(alongVec); + } + + /** Find closest point on this line to the given ray, specified by + start point and direction. If ray is parallel to this line, + returns false and closestPoint is not modified. */ + public boolean closestPointToRay(Vec3f rayStart, + Vec3f rayDirection, + Vec3f closestPoint) { + // Line 1 is this one. Line 2 is the incoming one. + Mat2f A = new Mat2f(); + A.set(0, 0, -direction.lengthSquared()); + A.set(1, 1, -rayDirection.lengthSquared()); + A.set(0, 1, direction.dot(rayDirection)); + A.set(1, 0, A.get(0, 1)); + if (Math.abs(A.determinant()) == 0.0f) { + return false; + } + if (!A.invert()) { + return false; + } + Vec2f b = new Vec2f(); + b.setX(point.dot(direction) - rayStart.dot(direction)); + b.setY(rayStart.dot(rayDirection) - point.dot(rayDirection)); + Vec2f x = new Vec2f(); + A.xformVec(b, x); + if (x.y() < 0) { + // Means that ray start is closest point to this line + closestPoint.set(rayStart); + } else { + closestPoint.set(direction); + closestPoint.scale(x.x()); + closestPoint.add(point); + } + return true; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void recalc() { + float denom = direction.lengthSquared(); + if (denom == 0.0f) { + throw new RuntimeException("Line.recalc: ERROR: direction was the zero vector " + + "(not allowed)"); + } + alongVec.set(point.minus(direction.times(point.dot(direction)))); + } +} diff --git a/src/gleem/linalg/Mat2f.java b/src/gleem/linalg/Mat2f.java new file mode 100644 index 0000000..6852dbc --- /dev/null +++ b/src/gleem/linalg/Mat2f.java @@ -0,0 +1,169 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** 2x2 matrix class useful for simple linear algebra. Representation + is (as Mat4f) in row major order and assumes multiplication by + column vectors on the right. */ + +public class Mat2f { + private float[] data; + + /** Creates new matrix initialized to the zero matrix */ + public Mat2f() { + data = new float[4]; + } + + /** Initialize to the identity matrix. */ + public void makeIdent() { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + if (i == j) { + set(i, j, 1.0f); + } else { + set(i, j, 0.0f); + } + } + } + } + + /** Gets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public float get(int i, int j) { + return data[2 * i + j]; + } + + /** Sets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public void set(int i, int j, float val) { + data[2 * i + j] = val; + } + + /** Set column i (i=[0..1]) to vector v. */ + public void setCol(int i, Vec2f v) { + set(0, i, v.x()); + set(1, i, v.y()); + } + + /** Set row i (i=[0..1]) to vector v. */ + public void setRow(int i, Vec2f v) { + set(i, 0, v.x()); + set(i, 1, v.y()); + } + + /** Transpose this matrix in place. */ + public void transpose() { + float t = get(0, 1); + set(0, 1, get(1, 0)); + set(1, 0, t); + } + + /** Return the determinant. */ + public float determinant() { + return (get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1)); + } + + /** Full matrix inversion in place. If matrix is singular, returns + false and matrix contents are untouched. If you know the matrix + is orthonormal, you can call transpose() instead. */ + public boolean invert() { + float det = determinant(); + if (det == 0.0f) + return false; + + // Create transpose of cofactor matrix in place + float t = get(0, 0); + set(0, 0, get(1, 1)); + set(1, 1, t); + set(0, 1, -get(0, 1)); + set(1, 0, -get(1, 0)); + + // Now divide by determinant + for (int i = 0; i < 4; i++) { + data[i] /= det; + } + return true; + } + + /** Multiply a 2D vector by this matrix. NOTE: src and dest must be + different vectors. */ + public void xformVec(Vec2f src, Vec2f dest) { + dest.set(get(0, 0) * src.x() + + get(0, 1) * src.y(), + + get(1, 0) * src.x() + + get(1, 1) * src.y()); + } + + /** Returns this * b; creates new matrix */ + public Mat2f mul(Mat2f b) { + Mat2f tmp = new Mat2f(); + tmp.mul(this, b); + return tmp; + } + + /** this = a * b */ + public void mul(Mat2f a, Mat2f b) { + for (int rc = 0; rc < 2; rc++) + for (int cc = 0; cc < 2; cc++) { + float tmp = 0.0f; + for (int i = 0; i < 2; i++) + tmp += a.get(rc, i) * b.get(i, cc); + set(rc, cc, tmp); + } + } + + public Matf toMatf() { + Matf out = new Matf(2, 2); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + out.set(i, j, get(i, j)); + } + } + return out; + } + + public String toString() { + String endl = System.getProperty("line.separator"); + return "(" + + get(0, 0) + ", " + get(0, 1) + endl + + get(1, 0) + ", " + get(1, 1) + ")"; + } +} diff --git a/src/gleem/linalg/Mat3f.java b/src/gleem/linalg/Mat3f.java new file mode 100644 index 0000000..024df82 --- /dev/null +++ b/src/gleem/linalg/Mat3f.java @@ -0,0 +1,194 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** 3x3 matrix class useful for simple linear algebra. Representation + is (as Mat4f) in row major order and assumes multiplication by + column vectors on the right. */ + +public class Mat3f { + private float[] data; + + /** Creates new matrix initialized to the zero matrix */ + public Mat3f() { + data = new float[9]; + } + + /** Initialize to the identity matrix. */ + public void makeIdent() { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if (i == j) { + set(i, j, 1.0f); + } else { + set(i, j, 0.0f); + } + } + } + } + + /** Gets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public float get(int i, int j) { + return data[3 * i + j]; + } + + /** Sets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public void set(int i, int j, float val) { + data[3 * i + j] = val; + } + + /** Set column i (i=[0..2]) to vector v. */ + public void setCol(int i, Vec3f v) { + set(0, i, v.x()); + set(1, i, v.y()); + set(2, i, v.z()); + } + + /** Set row i (i=[0..2]) to vector v. */ + public void setRow(int i, Vec3f v) { + set(i, 0, v.x()); + set(i, 1, v.y()); + set(i, 2, v.z()); + } + + /** Transpose this matrix in place. */ + public void transpose() { + float t; + t = get(0, 1); + set(0, 1, get(1, 0)); + set(1, 0, t); + + t = get(0, 2); + set(0, 2, get(2, 0)); + set(2, 0, t); + + t = get(1, 2); + set(1, 2, get(2, 1)); + set(2, 1, t); + } + + /** Return the determinant. Computed across the zeroth row. */ + public float determinant() { + return (get(0, 0) * (get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)) + + get(0, 1) * (get(2, 0) * get(1, 2) - get(1, 0) * get(2, 2)) + + get(0, 2) * (get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1))); + } + + /** Full matrix inversion in place. If matrix is singular, returns + false and matrix contents are untouched. If you know the matrix + is orthonormal, you can call transpose() instead. */ + public boolean invert() { + float det = determinant(); + if (det == 0.0f) + return false; + + // Form cofactor matrix + Mat3f cf = new Mat3f(); + cf.set(0, 0, get(1, 1) * get(2, 2) - get(2, 1) * get(1, 2)); + cf.set(0, 1, get(2, 0) * get(1, 2) - get(1, 0) * get(2, 2)); + cf.set(0, 2, get(1, 0) * get(2, 1) - get(2, 0) * get(1, 1)); + cf.set(1, 0, get(2, 1) * get(0, 2) - get(0, 1) * get(2, 2)); + cf.set(1, 1, get(0, 0) * get(2, 2) - get(2, 0) * get(0, 2)); + cf.set(1, 2, get(2, 0) * get(0, 1) - get(0, 0) * get(2, 1)); + cf.set(2, 0, get(0, 1) * get(1, 2) - get(1, 1) * get(0, 2)); + cf.set(2, 1, get(1, 0) * get(0, 2) - get(0, 0) * get(1, 2)); + cf.set(2, 2, get(0, 0) * get(1, 1) - get(1, 0) * get(0, 1)); + + // Now copy back transposed + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + set(i, j, cf.get(j, i) / det); + return true; + } + + /** Multiply a 3D vector by this matrix. NOTE: src and dest must be + different vectors. */ + public void xformVec(Vec3f src, Vec3f dest) { + dest.set(get(0, 0) * src.x() + + get(0, 1) * src.y() + + get(0, 2) * src.z(), + + get(1, 0) * src.x() + + get(1, 1) * src.y() + + get(1, 2) * src.z(), + + get(2, 0) * src.x() + + get(2, 1) * src.y() + + get(2, 2) * src.z()); + } + + /** Returns this * b; creates new matrix */ + public Mat3f mul(Mat3f b) { + Mat3f tmp = new Mat3f(); + tmp.mul(this, b); + return tmp; + } + + /** this = a * b */ + public void mul(Mat3f a, Mat3f b) { + for (int rc = 0; rc < 3; rc++) + for (int cc = 0; cc < 3; cc++) { + float tmp = 0.0f; + for (int i = 0; i < 3; i++) + tmp += a.get(rc, i) * b.get(i, cc); + set(rc, cc, tmp); + } + } + + public Matf toMatf() { + Matf out = new Matf(3, 3); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + out.set(i, j, get(i, j)); + } + } + return out; + } + + public String toString() { + String endl = System.getProperty("line.separator"); + return "(" + + get(0, 0) + ", " + get(0, 1) + ", " + get(0, 2) + endl + + get(1, 0) + ", " + get(1, 1) + ", " + get(1, 2) + endl + + get(2, 0) + ", " + get(2, 1) + ", " + get(2, 2) + ")"; + } +} diff --git a/src/gleem/linalg/Mat4f.java b/src/gleem/linalg/Mat4f.java new file mode 100644 index 0000000..ed16cc6 --- /dev/null +++ b/src/gleem/linalg/Mat4f.java @@ -0,0 +1,265 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** A (very incomplete) 4x4 matrix class. Representation assumes + multiplication by column vectors on the right. */ + +public class Mat4f { + private float[] data; + + /** Creates new matrix initialized to the zero matrix */ + public Mat4f() { + data = new float[16]; + } + + /** Creates new matrix initialized to argument's contents */ + public Mat4f(Mat4f arg) { + this(); + set(arg); + } + + /** Sets this matrix to the identity matrix */ + public void makeIdent() { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + if (i == j) { + set(i, j, 1.0f); + } else { + set(i, j, 0.0f); + } + } + } + } + + /** Sets this matrix to be equivalent to the given one */ + public void set(Mat4f arg) { + float[] mine = data; + float[] yours = arg.data; + for (int i = 0; i < mine.length; i++) { + mine[i] = yours[i]; + } + } + + /** Gets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public float get(int i, int j) { + return data[4 * i + j]; + } + + /** Sets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public void set(int i, int j, float val) { + data[4 * i + j] = val; + } + + /** Sets the translation component of this matrix (i.e., the three + top elements of the third column) without touching any of the + other parts of the matrix */ + public void setTranslation(Vec3f trans) { + set(0, 3, trans.x()); + set(1, 3, trans.y()); + set(2, 3, trans.z()); + } + + /** Sets the rotation component of this matrix (i.e., the upper left + 3x3) without touching any of the other parts of the matrix */ + public void setRotation(Rotf rot) { + rot.toMatrix(this); + } + + /** Sets the upper-left 3x3 of this matrix assuming that the given + x, y, and z vectors form an orthonormal basis */ + public void setRotation(Vec3f x, Vec3f y, Vec3f z) { + set(0, 0, x.x()); + set(1, 0, x.y()); + set(2, 0, x.z()); + + set(0, 1, y.x()); + set(1, 1, y.y()); + set(2, 1, y.z()); + + set(0, 2, z.x()); + set(1, 2, z.y()); + set(2, 2, z.z()); + } + + /** Gets the upper left 3x3 of this matrix as a rotation. Currently + does not work if there are scales. Ignores translation + component. */ + public void getRotation(Rotf rot) { + rot.fromMatrix(this); + } + + /** Sets the elements (0, 0), (1, 1), and (2, 2) with the + appropriate elements of the given three-dimensional scale + vector. Does not perform a full multiplication of the upper-left + 3x3; use this with an identity matrix in conjunction with + mul for that. */ + public void setScale(Vec3f scale) { + set(0, 0, scale.x()); + set(1, 1, scale.y()); + set(2, 2, scale.z()); + } + + /** Inverts this matrix assuming that it represents a rigid + transform (i.e., some combination of rotations and + translations). Assumes column vectors. Algorithm: transposes + upper left 3x3; negates translation in rightmost column and + transforms by inverted rotation. */ + public void invertRigid() { + float t; + // Transpose upper left 3x3 + t = get(0, 1); + set(0, 1, get(1, 0)); + set(1, 0, t); + t = get(0, 2); + set(0, 2, get(2, 0)); + set(2, 0, t); + t = get(1, 2); + set(1, 2, get(2, 1)); + set(2, 1, t); + // Transform negative translation by this + Vec3f negTrans = new Vec3f(-get(0, 3), -get(1, 3), -get(2, 3)); + Vec3f trans = new Vec3f(); + xformDir(negTrans, trans); + set(0, 3, trans.x()); + set(1, 3, trans.y()); + set(2, 3, trans.z()); + } + + /** Returns this * b; creates new matrix */ + public Mat4f mul(Mat4f b) { + Mat4f tmp = new Mat4f(); + tmp.mul(this, b); + return tmp; + } + + /** this = a * b */ + public void mul(Mat4f a, Mat4f b) { + for (int rc = 0; rc < 4; rc++) + for (int cc = 0; cc < 4; cc++) { + float tmp = 0.0f; + for (int i = 0; i < 4; i++) + tmp += a.get(rc, i) * b.get(i, cc); + set(rc, cc, tmp); + } + } + + /** Transpose this matrix in place. */ + public void transpose() { + float t; + for (int i = 0; i < 4; i++) { + for (int j = 0; j < i; j++) { + t = get(i, j); + set(i, j, get(j, i)); + set(j, i, t); + } + } + } + + /** Multiply a 4D vector by this matrix. NOTE: src and dest must be + different vectors. */ + public void xformVec(Vec4f src, Vec4f dest) { + for (int rc = 0; rc < 4; rc++) { + float tmp = 0.0f; + for (int cc = 0; cc < 4; cc++) { + tmp += get(rc, cc) * src.get(cc); + } + dest.set(rc, tmp); + } + } + + /** Transforms a 3D vector as though it had a homogeneous coordinate + and assuming that this matrix represents only rigid + transformations; i.e., is not a full transformation. NOTE: src + and dest must be different vectors. */ + public void xformPt(Vec3f src, Vec3f dest) { + for (int rc = 0; rc < 3; rc++) { + float tmp = 0.0f; + for (int cc = 0; cc < 3; cc++) { + tmp += get(rc, cc) * src.get(cc); + } + tmp += get(rc, 3); + dest.set(rc, tmp); + } + } + + /** Transforms src using only the upper left 3x3. NOTE: src and dest + must be different vectors. */ + public void xformDir(Vec3f src, Vec3f dest) { + for (int rc = 0; rc < 3; rc++) { + float tmp = 0.0f; + for (int cc = 0; cc < 3; cc++) { + tmp += get(rc, cc) * src.get(cc); + } + dest.set(rc, tmp); + } + } + + /** Copies data in column-major (OpenGL format) order into passed + float array, which must have length 16 or greater. */ + public void getColumnMajorData(float[] out) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + out[4 * j + i] = get(i, j); + } + } + } + + public Matf toMatf() { + Matf out = new Matf(4, 4); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + out.set(i, j, get(i, j)); + } + } + return out; + } + + public String toString() { + String endl = System.getProperty("line.separator"); + return "(" + + get(0, 0) + ", " + get(0, 1) + ", " + get(0, 2) + ", " + get(0, 3) + endl + + get(1, 0) + ", " + get(1, 1) + ", " + get(1, 2) + ", " + get(1, 3) + endl + + get(2, 0) + ", " + get(2, 1) + ", " + get(2, 2) + ", " + get(2, 3) + endl + + get(3, 0) + ", " + get(3, 1) + ", " + get(3, 2) + ", " + get(3, 3) + ")"; + } +} diff --git a/src/gleem/linalg/Matf.java b/src/gleem/linalg/Matf.java new file mode 100644 index 0000000..ae4ef92 --- /dev/null +++ b/src/gleem/linalg/Matf.java @@ -0,0 +1,168 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Arbitrary-size single-precision matrix class. Currently very + simple and only supports a few needed operations. */ + +public class Matf { + private float[] data; + private int nCol; // number of columns + private int nRow; // number of columns + + public Matf(int nRow, int nCol) { + data = new float[nRow * nCol]; + this.nCol = nCol; + this.nRow = nRow; + } + + public Matf(Matf arg) { + nRow = arg.nRow; + nCol = arg.nCol; + data = new float[nRow * nCol]; + System.arraycopy(arg.data, 0, data, 0, data.length); + } + + public int nRow() { + return nRow; + } + + public int nCol() { + return nCol; + } + + /** Gets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public float get(int i, int j) { + return data[nCol * i + j]; + } + + /** Sets the (i,j)th element of this matrix, where i is the row + index and j is the column index */ + public void set(int i, int j, float val) { + data[nCol * i + j] = val; + } + + /** Returns transpose of this matrix; creates new matrix */ + public Matf transpose() { + Matf tmp = new Matf(nCol, nRow); + for (int i = 0; i < nRow; i++) { + for (int j = 0; j < nCol; j++) { + tmp.set(j, i, get(i, j)); + } + } + return tmp; + } + + /** Returns this * b; creates new matrix */ + public Matf mul(Matf b) throws DimensionMismatchException { + if (nCol() != b.nRow()) + throw new DimensionMismatchException(); + Matf tmp = new Matf(nRow(), b.nCol()); + for (int i = 0; i < nRow(); i++) { + for (int j = 0; j < b.nCol(); j++) { + float val = 0; + for (int t = 0; t < nCol(); t++) { + val += get(i, t) * b.get(t, j); + } + tmp.set(i, j, val); + } + } + return tmp; + } + + /** Returns this * v, assuming v is a column vector. */ + public Vecf mul(Vecf v) throws DimensionMismatchException { + if (nCol() != v.length()) { + throw new DimensionMismatchException(); + } + Vecf out = new Vecf(nRow()); + for (int i = 0; i < nRow(); i++) { + float tmp = 0; + for (int j = 0; j < nCol(); j++) { + tmp += get(i, j) * v.get(j); + } + out.set(i, tmp); + } + return out; + } + + /** If this is a 2x2 matrix, returns it as a Mat2f. */ + public Mat2f toMat2f() throws DimensionMismatchException { + if (nRow() != 2 || nCol() != 2) { + throw new DimensionMismatchException(); + } + Mat2f tmp = new Mat2f(); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + tmp.set(i, j, get(i, j)); + } + } + return tmp; + } + + /** If this is a 3x3 matrix, returns it as a Mat3f. */ + public Mat3f toMat3f() throws DimensionMismatchException { + if (nRow() != 3 || nCol() != 3) { + throw new DimensionMismatchException(); + } + Mat3f tmp = new Mat3f(); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + tmp.set(i, j, get(i, j)); + } + } + return tmp; + } + + /** If this is a 4x4 matrix, returns it as a Mat4f. */ + public Mat4f toMat4f() throws DimensionMismatchException { + if (nRow() != 4 || nCol() != 4) { + throw new DimensionMismatchException(); + } + Mat4f tmp = new Mat4f(); + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + tmp.set(i, j, get(i, j)); + } + } + return tmp; + } +} diff --git a/src/gleem/linalg/MathUtil.java b/src/gleem/linalg/MathUtil.java new file mode 100644 index 0000000..7415953 --- /dev/null +++ b/src/gleem/linalg/MathUtil.java @@ -0,0 +1,90 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Utility math routines. */ + +public class MathUtil { + /** Makes an arbitrary vector perpendicular to src and + inserts it into dest. Returns false if the source vector + was equal to (0, 0, 0). */ + public static boolean makePerpendicular(Vec3f src, + Vec3f dest) { + if ((src.x() == 0.0f) && (src.y() == 0.0f) && (src.z() == 0.0f)) { + return false; + } + + if (src.x() != 0.0f) { + if (src.y() != 0.0f) { + dest.set(-src.y(), src.x(), 0.0f); + } else { + dest.set(-src.z(), 0.0f, src.x()); + } + } else { + dest.set(1.0f, 0.0f, 0.0f); + } + return true; + } + + /** Returns 1 if the sign of the given argument is positive; -1 if + negative; 0 if 0. */ + public static int sgn(float f) { + if (f > 0) { + return 1; + } else if (f < 0) { + return -1; + } + return 0; + } + + /** Clamps argument between min and max values. */ + public static float clamp(float val, float min, float max) { + if (val < min) return min; + if (val > max) return max; + return val; + } + + /** Clamps argument between min and max values. */ + public static int clamp(int val, int min, int max) { + if (val < min) return min; + if (val > max) return max; + return val; + } +} diff --git a/src/gleem/linalg/NonSquareMatrixException.java b/src/gleem/linalg/NonSquareMatrixException.java new file mode 100644 index 0000000..efc0c6a --- /dev/null +++ b/src/gleem/linalg/NonSquareMatrixException.java @@ -0,0 +1,53 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Thrown to indicate a non-square matrix during an operation + requiring one. */ + +public class NonSquareMatrixException extends RuntimeException { + public NonSquareMatrixException() { + super(); + } + + public NonSquareMatrixException(String msg) { + super(msg); + } +} diff --git a/src/gleem/linalg/Plane.java b/src/gleem/linalg/Plane.java new file mode 100644 index 0000000..fa58259 --- /dev/null +++ b/src/gleem/linalg/Plane.java @@ -0,0 +1,121 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Represents a plane in 3D space. */ + +public class Plane { + /** Normalized */ + private Vec3f normal; + private Vec3f point; + /** Constant for faster projection and intersection */ + float c; + + /** Default constructor initializes normal to (0, 1, 0) and point to + (0, 0, 0) */ + public Plane() { + normal = new Vec3f(0, 1, 0); + point = new Vec3f(0, 0, 0); + recalc(); + } + + /** Sets all parameters of plane. Plane has normal normal and + goes through the point point. Normal does not need to be + unit length but must not be the zero vector. */ + public Plane(Vec3f normal, Vec3f point) { + this.normal.set(normal); + this.normal.normalize(); + this.point.set(point); + recalc(); + } + + /** Setter does some work to maintain internal caches. Normal does + not need to be unit length but must not be the zero vector. */ + public void setNormal(Vec3f normal) { + this.normal.set(normal); + this.normal.normalize(); + recalc(); + } + + /** Normal is normalized internally, so normal is not + necessarily equal to plane.setNormal(normal); + plane.getNormal(); */ + public Vec3f getNormal() { + return normal; + } + + /** Setter does some work to maintain internal caches */ + public void setPoint(Vec3f point) { + this.point.set(point); + recalc(); + } + + public Vec3f getPoint() { + return point; + } + + /** Project a point onto the plane */ + public void projectPoint(Vec3f pt, + Vec3f projPt) { + float scale = normal.dot(pt) - c; + projPt.set(pt.minus(normal.times(normal.dot(point) - c))); + } + + /** Intersect a ray with the plane. Returns true if intersection occurred, false + otherwise. This is a two-sided ray cast. */ + public boolean intersectRay(Vec3f rayStart, + Vec3f rayDirection, + IntersectionPoint intPt) { + float denom = normal.dot(rayDirection); + if (denom == 0) + return false; + intPt.setT((c - normal.dot(rayStart)) / denom); + intPt.setIntersectionPoint(rayStart.plus(rayDirection.times(intPt.getT()))); + return true; + } + + //---------------------------------------------------------------------- + // Internals only below this point + // + + private void recalc() { + c = normal.dot(point); + } +} diff --git a/src/gleem/linalg/PlaneUV.java b/src/gleem/linalg/PlaneUV.java new file mode 100644 index 0000000..ff1baad --- /dev/null +++ b/src/gleem/linalg/PlaneUV.java @@ -0,0 +1,203 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** This differs from the Plane class in that it maintains an origin + and orthonormal U, V axes in the plane so that it can project a 3D + point to a 2D one. U cross V = normal. U and V coordinates are + computed with respect to the origin. */ + +public class PlaneUV { + private Vec3f origin = new Vec3f(); + /** Normalized */ + private Vec3f normal = new Vec3f(); + private Vec3f uAxis = new Vec3f(); + private Vec3f vAxis = new Vec3f(); + + /** Default constructor initializes normal to (0, 1, 0), origin to + (0, 0, 0), U axis to (1, 0, 0) and V axis to (0, 0, -1). */ + public PlaneUV() { + setEverything(new Vec3f(0, 1, 0), + new Vec3f(0, 0, 0), + new Vec3f(1, 0, 0), + new Vec3f(0, 0, -1)); + } + + /** Takes normal vector and a point which the plane goes through + (which becomes the plane's "origin"). Normal does NOT have to be + normalized, but may not be zero vector. U and V axes are + initialized to arbitrary values. */ + public PlaneUV(Vec3f normal, Vec3f origin) { + setOrigin(origin); + setNormal(normal); + } + + /** Takes normal vector, point which plane goes through, and the "u" + axis in the plane. Computes the "v" axis by taking the cross + product of the normal and the u axis. Axis must be perpendicular + to normal. Normal and uAxis do NOT have to be normalized, but + neither may be the zero vector. */ + public PlaneUV(Vec3f normal, + Vec3f origin, + Vec3f uAxis) { + setOrigin(origin); + setNormalAndU(normal, uAxis); + } + + /** Takes normal vector, point which plane goes through, and both + the u and v axes. u axis cross v axis = normal. Normal, uAxis, and + vAxis do NOT have to be normalized, but none may be the zero + vector. */ + public PlaneUV(Vec3f normal, + Vec3f origin, + Vec3f uAxis, + Vec3f vAxis) { + setEverything(normal, origin, uAxis, vAxis); + } + + /** Set the origin, through which this plane goes and with respect + to which U and V coordinates are computed */ + public void setOrigin(Vec3f origin) { + this.origin.set(origin); + } + + public Vec3f getOrigin() { + return new Vec3f(origin); + } + + /** Normal, U and V axes must be orthogonal and satisfy U cross V = + normal, do not need to be unit length but must not be the zero + vector. */ + public void setNormalAndUV(Vec3f normal, + Vec3f uAxis, + Vec3f vAxis) { + setEverything(normal, origin, uAxis, vAxis); + } + + /** This version sets the normal vector and generates new U and V + axes. */ + public void setNormal(Vec3f normal) { + Vec3f uAxis = new Vec3f(); + MathUtil.makePerpendicular(normal, uAxis); + Vec3f vAxis = normal.cross(uAxis); + setEverything(normal, origin, uAxis, vAxis); + } + + /** This version computes the V axis from (normal cross U). */ + public void setNormalAndU(Vec3f normal, + Vec3f uAxis) { + Vec3f vAxis = normal.cross(uAxis); + setEverything(normal, origin, uAxis, vAxis); + } + + /** Normal, U and V axes are normalized internally, so, for example, + normal is not necessarily equal to + plane.setNormal(normal); plane.getNormal(); */ + public Vec3f getNormal() { + return normal; + } + + public Vec3f getUAxis() { + return uAxis; + } + + public Vec3f getVAxis() { + return vAxis; + } + + /** Project a point onto the plane */ + public void projectPoint(Vec3f point, + Vec3f projPt, + Vec2f uvCoords) { + // Using projPt as a temporary + projPt.sub(point, origin); + float dotp = normal.dot(projPt); + // Component perpendicular to plane + Vec3f tmpDir = new Vec3f(); + tmpDir.set(normal); + tmpDir.scale(dotp); + projPt.sub(projPt, tmpDir); + // Take dot products with basis vectors + uvCoords.set(projPt.dot(uAxis), + projPt.dot(vAxis)); + // Add on center to intersection point + projPt.add(origin); + } + + /** Intersect a ray with this plane, outputting not only the 3D + intersection point but also the U, V coordinates of the + intersection. Returns true if intersection occurred, false + otherwise. This is a two-sided ray cast. */ + public boolean intersectRay(Vec3f rayStart, + Vec3f rayDirection, + IntersectionPoint intPt, + Vec2f uvCoords) { + float denom = rayDirection.dot(normal); + if (denom == 0.0f) + return false; + Vec3f tmpDir = new Vec3f(); + tmpDir.sub(origin, rayStart); + float t = tmpDir.dot(normal) / denom; + // Find intersection point + Vec3f tmpPt = new Vec3f(); + tmpPt.set(rayDirection); + tmpPt.scale(t); + tmpPt.add(rayStart); + intPt.setIntersectionPoint(tmpPt); + intPt.setT(t); + // Find UV coords + tmpDir.sub(intPt.getIntersectionPoint(), origin); + uvCoords.set(tmpDir.dot(uAxis), tmpDir.dot(vAxis)); + return true; + } + + private void setEverything(Vec3f normal, + Vec3f origin, + Vec3f uAxis, + Vec3f vAxis) { + this.normal.set(normal); + this.origin.set(origin); + this.uAxis.set(uAxis); + this.vAxis.set(vAxis); + this.normal.normalize(); + this.uAxis.normalize(); + this.vAxis.normalize(); + } +} diff --git a/src/gleem/linalg/Rotf.java b/src/gleem/linalg/Rotf.java new file mode 100644 index 0000000..4e39c21 --- /dev/null +++ b/src/gleem/linalg/Rotf.java @@ -0,0 +1,309 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Represents a rotation with single-precision components */ + +public class Rotf { + private static float EPSILON = 1.0e-7f; + + // Representation is a quaternion. Element 0 is the scalar part (= + // cos(theta/2)), elements 1..3 the imaginary/"vector" part (= + // sin(theta/2) * axis). + private float q0; + private float q1; + private float q2; + private float q3; + + /** Default constructor initializes to the identity quaternion */ + public Rotf() { + init(); + } + + public Rotf(Rotf arg) { + set(arg); + } + + /** Axis does not need to be normalized but must not be the zero + vector. Angle is in radians. */ + public Rotf(Vec3f axis, float angle) { + set(axis, angle); + } + + /** Creates a rotation which will rotate vector "from" into vector + "to". */ + public Rotf(Vec3f from, Vec3f to) { + set(from, to); + } + + /** Re-initialize this quaternion to be the identity quaternion "e" + (i.e., no rotation) */ + public void init() { + q0 = 1; + q1 = q2 = q3 = 0; + } + + /** Test for "approximate equality" -- performs componentwise test + to see whether difference between all components is less than + epsilon. */ + public boolean withinEpsilon(Rotf arg, float epsilon) { + return ((Math.abs(q0 - arg.q0) < epsilon) && + (Math.abs(q1 - arg.q1) < epsilon) && + (Math.abs(q2 - arg.q2) < epsilon) && + (Math.abs(q3 - arg.q3) < epsilon)); + } + + /** Axis does not need to be normalized but must not be the zero + vector. Angle is in radians. */ + public void set(Vec3f axis, float angle) { + float halfTheta = angle / 2.0f; + q0 = (float) Math.cos(halfTheta); + float sinHalfTheta = (float) Math.sin(halfTheta); + Vec3f realAxis = new Vec3f(axis); + realAxis.normalize(); + q1 = realAxis.x() * sinHalfTheta; + q2 = realAxis.y() * sinHalfTheta; + q3 = realAxis.z() * sinHalfTheta; + } + + public void set(Rotf arg) { + q0 = arg.q0; + q1 = arg.q1; + q2 = arg.q2; + q3 = arg.q3; + } + + /** Sets this rotation to that which will rotate vector "from" into + vector "to". from and to do not have to be the same length. */ + public void set(Vec3f from, Vec3f to) { + Vec3f axis = from.cross(to); + if (axis.lengthSquared() < EPSILON) { + init(); + return; + } + float dotp = from.dot(to); + float denom = from.length() * to.length(); + if (denom < EPSILON) { + init(); + return; + } + dotp /= denom; + set(axis, (float) Math.acos(dotp)); + } + + /** Returns angle (in radians) and mutates the given vector to be + the axis. */ + public float get(Vec3f axis) { + // FIXME: Is this numerically stable? Is there a better way to + // extract the angle from a quaternion? + // NOTE: remove (float) to illustrate compiler bug + float retval = (float) (2.0f * Math.acos(q0)); + axis.set(q1, q2, q3); + float len = axis.length(); + if (len == 0.0f) { + axis.set(0, 0, 1); + } else { + axis.scale(1.0f / len); + } + return retval; + } + + /** Returns inverse of this rotation; creates new rotation */ + public Rotf inverse() { + Rotf tmp = new Rotf(this); + tmp.invert(); + return tmp; + } + + /** Mutate this quaternion to be its inverse. This is equivalent to + the conjugate of the quaternion. */ + public void invert() { + q1 = -q1; + q2 = -q2; + q3 = -q3; + } + + /** Length of this quaternion in four-space */ + public float length() { + return (float) Math.sqrt(lengthSquared()); + } + + /** This dotted with this */ + public float lengthSquared() { + return (q0 * q0 + + q1 * q1 + + q2 * q2 + + q3 * q3); + } + + /** Make this quaternion a unit quaternion again. If you are + composing dozens of quaternions you probably should call this + periodically to ensure that you have a valid rotation. */ + public void normalize() { + float len = length(); + q0 /= len; + q1 /= len; + q2 /= len; + q3 /= len; + } + + /** Returns this * b, in that order; creates new rotation */ + public Rotf times(Rotf b) { + Rotf tmp = new Rotf(); + tmp.mul(this, b); + return tmp; + } + + /** Compose two rotations: this = A * B in that order. NOTE that + because we assume a column vector representation that this + implies that a vector rotated by the cumulative rotation will be + rotated first by B, then A. NOTE: "this" must be different than + both a and b. */ + public void mul(Rotf a, Rotf b) { + q0 = (a.q0 * b.q0 - a.q1 * b.q1 - + a.q2 * b.q2 - a.q3 * b.q3); + q1 = (a.q0 * b.q1 + a.q1 * b.q0 + + a.q2 * b.q3 - a.q3 * b.q2); + q2 = (a.q0 * b.q2 + a.q2 * b.q0 - + a.q1 * b.q3 + a.q3 * b.q1); + q3 = (a.q0 * b.q3 + a.q3 * b.q0 + + a.q1 * b.q2 - a.q2 * b.q1); + } + + /** Turns this rotation into a 3x3 rotation matrix. NOTE: only + mutates the upper-left 3x3 of the passed Mat4f. Implementation + from B. K. P. Horn's Robot Vision textbook. */ + public void toMatrix(Mat4f mat) { + float q00 = q0 * q0; + float q11 = q1 * q1; + float q22 = q2 * q2; + float q33 = q3 * q3; + // Diagonal elements + mat.set(0, 0, q00 + q11 - q22 - q33); + mat.set(1, 1, q00 - q11 + q22 - q33); + mat.set(2, 2, q00 - q11 - q22 + q33); + // 0,1 and 1,0 elements + float q03 = q0 * q3; + float q12 = q1 * q2; + mat.set(0, 1, 2.0f * (q12 - q03)); + mat.set(1, 0, 2.0f * (q03 + q12)); + // 0,2 and 2,0 elements + float q02 = q0 * q2; + float q13 = q1 * q3; + mat.set(0, 2, 2.0f * (q02 + q13)); + mat.set(2, 0, 2.0f * (q13 - q02)); + // 1,2 and 2,1 elements + float q01 = q0 * q1; + float q23 = q2 * q3; + mat.set(1, 2, 2.0f * (q23 - q01)); + mat.set(2, 1, 2.0f * (q01 + q23)); + } + + /** Turns the upper left 3x3 of the passed matrix into a rotation. + Implementation from Watt and Watt, Advanced Animation and + Rendering Techniques. + @see gleem.linalg.Mat4f#getRotation */ + public void fromMatrix(Mat4f mat) { + // FIXME: Should reimplement to follow Horn's advice of using + // eigenvector decomposition to handle roundoff error in given + // matrix. + + float tr, s; + int i, j, k; + + tr = mat.get(0, 0) + mat.get(1, 1) + mat.get(2, 2); + if (tr > 0.0) { + s = (float) Math.sqrt(tr + 1.0f); + q0 = s * 0.5f; + s = 0.5f / s; + q1 = (mat.get(2, 1) - mat.get(1, 2)) * s; + q2 = (mat.get(0, 2) - mat.get(2, 0)) * s; + q3 = (mat.get(1, 0) - mat.get(0, 1)) * s; + } else { + i = 0; + if (mat.get(1, 1) > mat.get(0, 0)) + i = 1; + if (mat.get(2, 2) > mat.get(i, i)) + i = 2; + j = (i+1)%3; + k = (j+1)%3; + s = (float) Math.sqrt( (mat.get(i, i) - (mat.get(j, j) + mat.get(k, k))) + 1.0f); + setQ(i+1, s * 0.5f); + s = 0.5f / s; + q0 = (mat.get(k, j) - mat.get(j, k)) * s; + setQ(j+1, (mat.get(j, i) + mat.get(i, j)) * s); + setQ(k+1, (mat.get(k, i) + mat.get(i, k)) * s); + } + } + + /** Rotate a vector by this quaternion. Implementation is from + Horn's Robot Vision. NOTE: src and dest must be different + vectors. */ + public void rotateVector(Vec3f src, Vec3f dest) { + Vec3f qVec = new Vec3f(q1, q2, q3); + Vec3f qCrossX = qVec.cross(src); + Vec3f qCrossXCrossQ = qCrossX.cross(qVec); + qCrossX.scale(2.0f * q0); + qCrossXCrossQ.scale(-2.0f); + dest.add(src, qCrossX); + dest.add(dest, qCrossXCrossQ); + } + + /** Rotate a vector by this quaternion, returning newly-allocated result. */ + public Vec3f rotateVector(Vec3f src) { + Vec3f tmp = new Vec3f(); + rotateVector(src, tmp); + return tmp; + } + + public String toString() { + return "(" + q0 + ", " + q1 + ", " + q2 + ", " + q3 + ")"; + } + + private void setQ(int i, float val) { + switch (i) { + case 0: q0 = val; break; + case 1: q1 = val; break; + case 2: q2 = val; break; + case 3: q3 = val; break; + default: throw new IndexOutOfBoundsException(); + } + } +} diff --git a/src/gleem/linalg/SingularMatrixException.java b/src/gleem/linalg/SingularMatrixException.java new file mode 100644 index 0000000..fa6ef32 --- /dev/null +++ b/src/gleem/linalg/SingularMatrixException.java @@ -0,0 +1,53 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Thrown to indicate a singular matrix during an inversion or + related operation. */ + +public class SingularMatrixException extends RuntimeException { + public SingularMatrixException() { + super(); + } + + public SingularMatrixException(String msg) { + super(msg); + } +} diff --git a/src/gleem/linalg/Vec2f.java b/src/gleem/linalg/Vec2f.java new file mode 100644 index 0000000..2e02701 --- /dev/null +++ b/src/gleem/linalg/Vec2f.java @@ -0,0 +1,182 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** 2-element single-precision vector */ + +public class Vec2f { + private float x; + private float y; + + public Vec2f() {} + + public Vec2f(Vec2f arg) { + this(arg.x, arg.y); + } + + public Vec2f(float x, float y) { + set(x, y); + } + + public Vec2f copy() { + return new Vec2f(this); + } + + public void set(float x, float y) { + this.x = x; + this.y = y; + } + + /** Sets the ith component, 0 <= i < 2 */ + public void set(int i, float val) { + switch (i) { + case 0: x = val; break; + case 1: y = val; break; + default: throw new IndexOutOfBoundsException(); + } + } + + /** Gets the ith component, 0 <= i < 2 */ + public float get(int i) { + switch (i) { + case 0: return x; + case 1: return y; + default: throw new IndexOutOfBoundsException(); + } + } + + public float x() { return x; } + public float y() { return y; } + + public void setX(float x) { this.x = x; } + public void setY(float y) { this.y = y; } + + public float dot(Vec2f arg) { + return x * arg.x + y * arg.y; + } + + public float length() { + return (float) Math.sqrt(lengthSquared()); + } + + public float lengthSquared() { + return this.dot(this); + } + + public void normalize() { + float len = length(); + if (len == 0.0f) return; + scale(1.0f / len); + } + + /** Returns this * val; creates new vector */ + public Vec2f times(float val) { + Vec2f tmp = new Vec2f(this); + tmp.scale(val); + return tmp; + } + + /** this = this * val */ + public void scale(float val) { + x *= val; + y *= val; + } + + /** Returns this + arg; creates new vector */ + public Vec2f plus(Vec2f arg) { + Vec2f tmp = new Vec2f(); + tmp.add(this, arg); + return tmp; + } + + /** this = this + b */ + public void add(Vec2f b) { + add(this, b); + } + + /** this = a + b */ + public void add(Vec2f a, Vec2f b) { + x = a.x + b.x; + y = a.y + b.y; + } + + /** Returns this + s * arg; creates new vector */ + public Vec2f addScaled(float s, Vec2f arg) { + Vec2f tmp = new Vec2f(); + tmp.addScaled(this, s, arg); + return tmp; + } + + /** this = a + s * b */ + public void addScaled(Vec2f a, float s, Vec2f b) { + x = a.x + s * b.x; + y = a.y + s * b.y; + } + + /** Returns this - arg; creates new vector */ + public Vec2f minus(Vec2f arg) { + Vec2f tmp = new Vec2f(); + tmp.sub(this, arg); + return tmp; + } + + /** this = this - b */ + public void sub(Vec2f b) { + sub(this, b); + } + + /** this = a - b */ + public void sub(Vec2f a, Vec2f b) { + x = a.x - b.x; + y = a.y - b.y; + } + + public Vecf toVecf() { + Vecf out = new Vecf(2); + for (int i = 0; i < 2; i++) { + out.set(i, get(i)); + } + return out; + } + + public String toString() { + return "(" + x + ", " + y + ")"; + } +} diff --git a/src/gleem/linalg/Vec3d.java b/src/gleem/linalg/Vec3d.java new file mode 100644 index 0000000..7a7a907 --- /dev/null +++ b/src/gleem/linalg/Vec3d.java @@ -0,0 +1,175 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * See the file GLEEM-LICENSE.txt in the doc/ directory for licensing terms. + */ + +package gleem.linalg; + +/** 3-element double-precision vector */ + +public class Vec3d { + private double x; + private double y; + private double z; + + public Vec3d() {} + + public Vec3d(Vec3d arg) { + set(arg); + } + + public Vec3d(double x, double y, double z) { + set(x, y, z); + } + + public Vec3d copy() { + return new Vec3d(this); + } + + /** Convert to single-precision */ + public Vec3f toFloat() { + return new Vec3f((float) x, (float) y, (float) z); + } + + public void set(Vec3d arg) { + set(arg.x, arg.y, arg.z); + } + + public void set(double x, double y, double z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** Sets the ith component, 0 <= i < 3 */ + public void set(int i, double val) { + switch (i) { + case 0: x = val; break; + case 1: y = val; break; + case 2: z = val; break; + default: throw new IndexOutOfBoundsException(); + } + } + + /** Gets the ith component, 0 <= i < 3 */ + public double get(int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + default: throw new IndexOutOfBoundsException(); + } + } + + public double x() { return x; } + public double y() { return y; } + public double z() { return z; } + + public void setX(double x) { this.x = x; } + public void setY(double y) { this.y = y; } + public void setZ(double z) { this.z = z; } + + public double dot(Vec3d arg) { + return x * arg.x + y * arg.y + z * arg.z; + } + + public double length() { + return Math.sqrt(lengthSquared()); + } + + public double lengthSquared() { + return this.dot(this); + } + + public void normalize() { + double len = length(); + if (len == 0.0) return; + scale(1.0f / len); + } + + /** Returns this * val; creates new vector */ + public Vec3d times(double val) { + Vec3d tmp = new Vec3d(this); + tmp.scale(val); + return tmp; + } + + /** this = this * val */ + public void scale(double val) { + x *= val; + y *= val; + z *= val; + } + + /** Returns this + arg; creates new vector */ + public Vec3d plus(Vec3d arg) { + Vec3d tmp = new Vec3d(); + tmp.add(this, arg); + return tmp; + } + + /** this = this + b */ + public void add(Vec3d b) { + add(this, b); + } + + /** this = a + b */ + public void add(Vec3d a, Vec3d b) { + x = a.x + b.x; + y = a.y + b.y; + z = a.z + b.z; + } + + /** Returns this + s * arg; creates new vector */ + public Vec3d addScaled(double s, Vec3d arg) { + Vec3d tmp = new Vec3d(); + tmp.addScaled(this, s, arg); + return tmp; + } + + /** this = a + s * b */ + public void addScaled(Vec3d a, double s, Vec3d b) { + x = a.x + s * b.x; + y = a.y + s * b.y; + z = a.z + s * b.z; + } + + /** Returns this - arg; creates new vector */ + public Vec3d minus(Vec3d arg) { + Vec3d tmp = new Vec3d(); + tmp.sub(this, arg); + return tmp; + } + + /** this = this - b */ + public void sub(Vec3d b) { + sub(this, b); + } + + /** this = a - b */ + public void sub(Vec3d a, Vec3d b) { + x = a.x - b.x; + y = a.y - b.y; + z = a.z - b.z; + } + + /** Returns this cross arg; creates new vector */ + public Vec3d cross(Vec3d arg) { + Vec3d tmp = new Vec3d(); + tmp.cross(this, arg); + return tmp; + } + + /** this = a cross b. NOTE: "this" must be a different vector than + both a and b. */ + public void cross(Vec3d a, Vec3d b) { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + } + + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/src/gleem/linalg/Vec3f.java b/src/gleem/linalg/Vec3f.java new file mode 100644 index 0000000..5468f3e --- /dev/null +++ b/src/gleem/linalg/Vec3f.java @@ -0,0 +1,232 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** 3-element single-precision vector */ + +public class Vec3f { + public static final Vec3f X_AXIS = new Vec3f( 1, 0, 0); + public static final Vec3f Y_AXIS = new Vec3f( 0, 1, 0); + public static final Vec3f Z_AXIS = new Vec3f( 0, 0, 1); + public static final Vec3f NEG_X_AXIS = new Vec3f(-1, 0, 0); + public static final Vec3f NEG_Y_AXIS = new Vec3f( 0, -1, 0); + public static final Vec3f NEG_Z_AXIS = new Vec3f( 0, 0, -1); + + private float x; + private float y; + private float z; + + public Vec3f() {} + + public Vec3f(Vec3f arg) { + set(arg); + } + + public Vec3f(float x, float y, float z) { + set(x, y, z); + } + + public Vec3f copy() { + return new Vec3f(this); + } + + /** Convert to double-precision */ + public Vec3d toDouble() { + return new Vec3d(x, y, z); + } + + public void set(Vec3f arg) { + set(arg.x, arg.y, arg.z); + } + + public void set(float x, float y, float z) { + this.x = x; + this.y = y; + this.z = z; + } + + /** Sets the ith component, 0 <= i < 3 */ + public void set(int i, float val) { + switch (i) { + case 0: x = val; break; + case 1: y = val; break; + case 2: z = val; break; + default: throw new IndexOutOfBoundsException(); + } + } + + /** Gets the ith component, 0 <= i < 3 */ + public float get(int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + default: throw new IndexOutOfBoundsException(); + } + } + + public float x() { return x; } + public float y() { return y; } + public float z() { return z; } + + public void setX(float x) { this.x = x; } + public void setY(float y) { this.y = y; } + public void setZ(float z) { this.z = z; } + + public float dot(Vec3f arg) { + return x * arg.x + y * arg.y + z * arg.z; + } + + public float length() { + return (float) Math.sqrt(lengthSquared()); + } + + public float lengthSquared() { + return this.dot(this); + } + + public void normalize() { + float len = length(); + if (len == 0.0f) return; + scale(1.0f / len); + } + + /** Returns this * val; creates new vector */ + public Vec3f times(float val) { + Vec3f tmp = new Vec3f(this); + tmp.scale(val); + return tmp; + } + + /** this = this * val */ + public void scale(float val) { + x *= val; + y *= val; + z *= val; + } + + /** Returns this + arg; creates new vector */ + public Vec3f plus(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.add(this, arg); + return tmp; + } + + /** this = this + b */ + public void add(Vec3f b) { + add(this, b); + } + + /** this = a + b */ + public void add(Vec3f a, Vec3f b) { + x = a.x + b.x; + y = a.y + b.y; + z = a.z + b.z; + } + + /** Returns this + s * arg; creates new vector */ + public Vec3f addScaled(float s, Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.addScaled(this, s, arg); + return tmp; + } + + /** this = a + s * b */ + public void addScaled(Vec3f a, float s, Vec3f b) { + x = a.x + s * b.x; + y = a.y + s * b.y; + z = a.z + s * b.z; + } + + /** Returns this - arg; creates new vector */ + public Vec3f minus(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.sub(this, arg); + return tmp; + } + + /** this = this - b */ + public void sub(Vec3f b) { + sub(this, b); + } + + /** this = a - b */ + public void sub(Vec3f a, Vec3f b) { + x = a.x - b.x; + y = a.y - b.y; + z = a.z - b.z; + } + + /** Returns this cross arg; creates new vector */ + public Vec3f cross(Vec3f arg) { + Vec3f tmp = new Vec3f(); + tmp.cross(this, arg); + return tmp; + } + + /** this = a cross b. NOTE: "this" must be a different vector than + both a and b. */ + public void cross(Vec3f a, Vec3f b) { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + } + + /** Sets each component of this vector to the product of the + component with the corresponding component of the argument + vector. */ + public void componentMul(Vec3f arg) { + x *= arg.x; + y *= arg.y; + z *= arg.z; + } + + public Vecf toVecf() { + Vecf out = new Vecf(3); + for (int i = 0; i < 3; i++) { + out.set(i, get(i)); + } + return out; + } + + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/src/gleem/linalg/Vec4f.java b/src/gleem/linalg/Vec4f.java new file mode 100644 index 0000000..bfb53ab --- /dev/null +++ b/src/gleem/linalg/Vec4f.java @@ -0,0 +1,216 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** 4-element single-precision vector */ + +public class Vec4f { + private float x; + private float y; + private float z; + private float w; + + public Vec4f() {} + + public Vec4f(Vec4f arg) { + set(arg); + } + + public Vec4f(float x, float y, float z, float w) { + set(x, y, z, w); + } + + public Vec4f copy() { + return new Vec4f(this); + } + + public void set(Vec4f arg) { + set(arg.x, arg.y, arg.z, arg.w); + } + + public void set(float x, float y, float z, float w) { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /** Sets the ith component, 0 <= i < 4 */ + public void set(int i, float val) { + switch (i) { + case 0: x = val; break; + case 1: y = val; break; + case 2: z = val; break; + case 3: w = val; break; + default: throw new IndexOutOfBoundsException(); + } + } + + /** Gets the ith component, 0 <= i < 4 */ + public float get(int i) { + switch (i) { + case 0: return x; + case 1: return y; + case 2: return z; + case 3: return w; + default: throw new IndexOutOfBoundsException(); + } + } + + public float x() { return x; } + public float y() { return y; } + public float z() { return z; } + public float w() { return w; } + + public void setX(float x) { this.x = x; } + public void setY(float y) { this.y = y; } + public void setZ(float z) { this.z = z; } + public void setW(float w) { this.w = w; } + + public float dot(Vec4f arg) { + return x * arg.x + y * arg.y + z * arg.z + w * arg.w; + } + + public float length() { + return (float) Math.sqrt(lengthSquared()); + } + + public float lengthSquared() { + return this.dot(this); + } + + public void normalize() { + float len = length(); + if (len == 0.0f) return; + scale(1.0f / len); + } + + /** Returns this * val; creates new vector */ + public Vec4f times(float val) { + Vec4f tmp = new Vec4f(this); + tmp.scale(val); + return tmp; + } + + /** this = this * val */ + public void scale(float val) { + x *= val; + y *= val; + z *= val; + w *= val; + } + + /** Returns this + arg; creates new vector */ + public Vec4f plus(Vec4f arg) { + Vec4f tmp = new Vec4f(); + tmp.add(this, arg); + return tmp; + } + + /** this = this + b */ + public void add(Vec4f b) { + add(this, b); + } + + /** this = a + b */ + public void add(Vec4f a, Vec4f b) { + x = a.x + b.x; + y = a.y + b.y; + z = a.z + b.z; + w = a.w + b.w; + } + + /** Returns this + s * arg; creates new vector */ + public Vec4f addScaled(float s, Vec4f arg) { + Vec4f tmp = new Vec4f(); + tmp.addScaled(this, s, arg); + return tmp; + } + + /** this = a + s * b */ + public void addScaled(Vec4f a, float s, Vec4f b) { + x = a.x + s * b.x; + y = a.y + s * b.y; + z = a.z + s * b.z; + w = a.w + s * b.w; + } + + /** Returns this - arg; creates new vector */ + public Vec4f minus(Vec4f arg) { + Vec4f tmp = new Vec4f(); + tmp.sub(this, arg); + return tmp; + } + + /** this = this - b */ + public void sub(Vec4f b) { + sub(this, b); + } + + /** this = a - b */ + public void sub(Vec4f a, Vec4f b) { + x = a.x - b.x; + y = a.y - b.y; + z = a.z - b.z; + w = a.w - b.w; + } + + /** Sets each component of this vector to the product of the + component with the corresponding component of the argument + vector. */ + public void componentMul(Vec4f arg) { + x *= arg.x; + y *= arg.y; + z *= arg.z; + w *= arg.w; + } + + public Vecf toVecf() { + Vecf out = new Vecf(4); + for (int i = 0; i < 4; i++) { + out.set(i, get(i)); + } + return out; + } + + public String toString() { + return "(" + x + ", " + y + ", " + z + ")"; + } +} diff --git a/src/gleem/linalg/Vecf.java b/src/gleem/linalg/Vecf.java new file mode 100644 index 0000000..1249695 --- /dev/null +++ b/src/gleem/linalg/Vecf.java @@ -0,0 +1,96 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Arbitrary-length single-precision vector class. Currently very + simple and only supports a few needed operations. */ + +public class Vecf { + private float[] data; + + public Vecf(int n) { + data = new float[n]; + } + + public Vecf(Vecf arg) { + data = new float[arg.data.length]; + System.arraycopy(arg.data, 0, data, 0, data.length); + } + + public int length() { + return data.length; + } + + public float get(int i) { + return data[i]; + } + + public void set(int i, float val) { + data[i] = val; + } + + public Vec2f toVec2f() throws DimensionMismatchException { + if (length() != 2) + throw new DimensionMismatchException(); + Vec2f out = new Vec2f(); + for (int i = 0; i < 2; i++) { + out.set(i, get(i)); + } + return out; + } + + public Vec3f toVec3f() throws DimensionMismatchException { + if (length() != 3) + throw new DimensionMismatchException(); + Vec3f out = new Vec3f(); + for (int i = 0; i < 3; i++) { + out.set(i, get(i)); + } + return out; + } + + public Veci toInt() { + Veci out = new Veci(length()); + for (int i = 0; i < length(); i++) { + out.set(i, (int) get(i)); + } + return out; + } +} diff --git a/src/gleem/linalg/Veci.java b/src/gleem/linalg/Veci.java new file mode 100644 index 0000000..d7705e7 --- /dev/null +++ b/src/gleem/linalg/Veci.java @@ -0,0 +1,96 @@ +/* + * gleem -- OpenGL Extremely Easy-To-Use Manipulators. + * Copyright (C) 1998-2003 Kenneth B. Russell (kbrussel@alum.mit.edu) + * + * Copying, distribution and use of this software in source and binary + * forms, with or without modification, is permitted provided that the + * following conditions are met: + * + * Distributions of source code must reproduce the copyright notice, + * this list of conditions and the following disclaimer in the source + * code header files; and Distributions of binary code must reproduce + * the copyright notice, this list of conditions and the following + * disclaimer in the documentation, Read me file, license file and/or + * other materials provided with the software distribution. + * + * The names of Sun Microsystems, Inc. ("Sun") and/or the copyright + * holder may not 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, NON-INTERFERENCE, ACCURACY OF + * INFORMATIONAL CONTENT OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. THE + * COPYRIGHT HOLDER, SUN AND SUN'S 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 THE + * COPYRIGHT HOLDER, SUN OR SUN'S 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 ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGES. YOU ACKNOWLEDGE THAT THIS SOFTWARE IS NOT + * DESIGNED, LICENSED OR INTENDED FOR USE IN THE DESIGN, CONSTRUCTION, + * OPERATION OR MAINTENANCE OF ANY NUCLEAR FACILITY. THE COPYRIGHT + * HOLDER, SUN AND SUN'S LICENSORS DISCLAIM ANY EXPRESS OR IMPLIED + * WARRANTY OF FITNESS FOR SUCH USES. + */ + +package gleem.linalg; + +/** Arbitrary-length integer vector class. Currently very simple and + only supports a few needed operations. */ + +public class Veci { + private int[] data; + + public Veci(int n) { + data = new int[n]; + } + + public Veci(Veci arg) { + data = new int[arg.data.length]; + System.arraycopy(arg.data, 0, data, 0, data.length); + } + + public int length() { + return data.length; + } + + public int get(int i) { + return data[i]; + } + + public void set(int i, int val) { + data[i] = val; + } + + public Vec2f toVec2f() throws DimensionMismatchException { + if (length() != 2) + throw new DimensionMismatchException(); + Vec2f out = new Vec2f(); + for (int i = 0; i < 2; i++) { + out.set(i, get(i)); + } + return out; + } + + public Vec3f toVec3f() throws DimensionMismatchException { + if (length() != 3) + throw new DimensionMismatchException(); + Vec3f out = new Vec3f(); + for (int i = 0; i < 3; i++) { + out.set(i, get(i)); + } + return out; + } + + public Vecf toVecf() { + Vecf out = new Vecf(length()); + for (int i = 0; i < length(); i++) { + out.set(i, get(i)); + } + return out; + } +} diff --git a/src/gleem/linalg/package.html b/src/gleem/linalg/package.html new file mode 100644 index 0000000..bc1e60f --- /dev/null +++ b/src/gleem/linalg/package.html @@ -0,0 +1,13 @@ + + + + +Linear algebra and classes implementing basic 3D operations. + +

+ +See the gleem +home page for more information. + + + diff --git a/src/gleem/package.html b/src/gleem/package.html new file mode 100644 index 0000000..2dc6d32 --- /dev/null +++ b/src/gleem/package.html @@ -0,0 +1,13 @@ + + + + +Widgets and auxiliary classes for interaction with a 3D scene. + +

+ +See the gleem +home page for more information. + + + -- cgit v1.2.3