summaryrefslogtreecommitdiffstats
path: root/src/gleem
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2009-06-15 23:12:27 +0000
committerKenneth Russel <[email protected]>2009-06-15 23:12:27 +0000
commit41cd6c47b23975098cd155517790e018670785e7 (patch)
tree247333528ad674d427ba96b1e05810f7961d609e /src/gleem
parent935d2596c13371bb745d921dbcb9f05b0c11a010 (diff)
Copied JOGL_2_SANDBOX r350 on to trunk; JOGL_2_SANDBOX branch is now closed
git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@352 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4
Diffstat (limited to 'src/gleem')
-rw-r--r--src/gleem/BSphere.java166
-rw-r--r--src/gleem/BSphereProvider.java46
-rw-r--r--src/gleem/CameraParameters.java170
-rw-r--r--src/gleem/ExaminerViewer.java622
-rw-r--r--src/gleem/HandleBoxManip.java948
-rw-r--r--src/gleem/HitPoint.java73
-rw-r--r--src/gleem/Manip.java120
-rw-r--r--src/gleem/ManipManager.java409
-rw-r--r--src/gleem/ManipMotionListener.java47
-rw-r--r--src/gleem/ManipPart.java94
-rw-r--r--src/gleem/ManipPartCube.java102
-rw-r--r--src/gleem/ManipPartGroup.java133
-rw-r--r--src/gleem/ManipPartLineSeg.java163
-rw-r--r--src/gleem/ManipPartSquare.java82
-rw-r--r--src/gleem/ManipPartTransform.java72
-rw-r--r--src/gleem/ManipPartTriBased.java292
-rw-r--r--src/gleem/ManipPartTwoWayArrow.java124
-rw-r--r--src/gleem/MouseButtonHelper.java75
-rw-r--r--src/gleem/NormalCalc.java116
-rw-r--r--src/gleem/RayTriangleIntersection.java226
-rw-r--r--src/gleem/RightTruncPyrMapping.java64
-rw-r--r--src/gleem/ScreenToRayMapping.java73
-rw-r--r--src/gleem/TestExaminerViewer.java166
-rw-r--r--src/gleem/TestHandleBox.java155
-rw-r--r--src/gleem/TestMultiWin.java175
-rw-r--r--src/gleem/TestTranslate1.java156
-rw-r--r--src/gleem/TestTranslate2.java156
-rw-r--r--src/gleem/Translate1Manip.java208
-rw-r--r--src/gleem/Translate2Manip.java230
-rw-r--r--src/gleem/WindowUpdateListener.java52
-rw-r--r--src/gleem/linalg/DimensionMismatchException.java53
-rw-r--r--src/gleem/linalg/IntersectionPoint.java63
-rw-r--r--src/gleem/linalg/Line.java152
-rw-r--r--src/gleem/linalg/Mat2f.java169
-rw-r--r--src/gleem/linalg/Mat3f.java194
-rw-r--r--src/gleem/linalg/Mat4f.java265
-rw-r--r--src/gleem/linalg/Matf.java168
-rw-r--r--src/gleem/linalg/MathUtil.java90
-rw-r--r--src/gleem/linalg/NonSquareMatrixException.java53
-rw-r--r--src/gleem/linalg/Plane.java121
-rw-r--r--src/gleem/linalg/PlaneUV.java203
-rw-r--r--src/gleem/linalg/Rotf.java309
-rw-r--r--src/gleem/linalg/SingularMatrixException.java53
-rw-r--r--src/gleem/linalg/Vec2f.java186
-rw-r--r--src/gleem/linalg/Vec3d.java175
-rw-r--r--src/gleem/linalg/Vec3f.java232
-rw-r--r--src/gleem/linalg/Vec4f.java216
-rw-r--r--src/gleem/linalg/Vecf.java96
-rw-r--r--src/gleem/linalg/Veci.java96
-rw-r--r--src/gleem/linalg/package.html13
-rw-r--r--src/gleem/package.html13
51 files changed, 8435 insertions, 0 deletions
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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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..c406cda
--- /dev/null
+++ b/src/gleem/CameraParameters.java
@@ -0,0 +1,170 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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,
+ Mat4f modelviewMatrix,
+ Mat4f projectionMatrix,
+ float vertFOV,
+ float imagePlaneAspectRatio,
+ int xSize,
+ int ySize) {
+ setPosition(position);
+ setForwardDirection(forwardDirection);
+ setUpDirection(upDirection);
+ setOrientation(orientation);
+ setModelviewMatrix(modelviewMatrix);
+ setProjectionMatrix(projectionMatrix);
+ setVertFOV(vertFOV);
+ setImagePlaneAspectRatio(imagePlaneAspectRatio);
+ setXSize(xSize);
+ setYSize(ySize);
+ }
+
+ public void set(CameraParameters params) {
+ setPosition(params.getPosition());
+ setForwardDirection(params.getForwardDirection());
+ setUpDirection(params.getUpDirection());
+ setOrientation(params.getOrientation());
+ setModelviewMatrix(params.getModelviewMatrix());
+ setProjectionMatrix(params.getProjectionMatrix());
+ setVertFOV(params.getVertFOV());
+ setImagePlaneAspectRatio(params.getImagePlaneAspectRatio());
+ setXSize(params.getXSize());
+ setYSize(params.getYSize());
+ }
+
+ public Object clone() {
+ CameraParameters params = new CameraParameters();
+ params.set(this);
+ return params;
+ }
+
+ public CameraParameters copy() {
+ return (CameraParameters) clone();
+ }
+
+ /** 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 <b>fovy</b> 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..d21579a
--- /dev/null
+++ b/src/gleem/ExaminerViewer.java
@@ -0,0 +1,622 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+import javax.media.opengl.awt.*;
+
+/** <P> 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. </P>
+
+ <P> For the given GLAutoDrawable, 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. </P>
+
+ <P> 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
+ <code>setNoAltKeyMode</code> 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. </P>
+
+ <P>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. </P> */
+
+public class ExaminerViewer {
+ private AWTGLAutoDrawable window;
+ /** Simple state machine for figuring out whether we are grabbing
+ events */
+ private boolean interactionUnderway;
+ private boolean iOwnInteraction;
+
+ private boolean noAltKeyMode;
+ private boolean autoRedrawMode = true;
+
+ /** 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(GLAutoDrawable drawable) {}
+ public void display(GLAutoDrawable drawable) {}
+ public void dispose(GLAutoDrawable drawable) { }
+ public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
+ reshapeMethod(width, height);
+ }
+ public void displayChanged(GLAutoDrawable 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;
+ }
+
+ /** <P> Attaches this ExaminerViewer to the given GLAutoDrawable. This
+ causes the ManipManager's mouse routines to be removed from the
+ window (using ManipManager.removeMouseListeners) and the
+ ExaminerViewer's to be installed. The GLAutoDrawable should be
+ registered with the ManipManager before the ExaminerViewer is
+ attached to it. </P>
+
+ <P> In order for the viewer to do anything useful, you need to
+ provide a BSphereProvider to it to allow "view all"
+ functionality. </P> */
+ public void attach(AWTGLAutoDrawable 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 GLAutoDrawable 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(GL2 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(GL2 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(GL2 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 <b>fovy</b> 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;
+ }
+
+ /** Enables or disables the automatic redrawing of the
+ GLAutoDrawable to which this ExaminerViewer is attached. If the
+ GLAutoDrawable is already being animated, disabling auto redraw
+ mode may provide better performance. Defaults to on. */
+ public void setAutoRedrawMode(boolean onOrOff) {
+ autoRedrawMode = onOrOff;
+ }
+
+ /** Returns whether this ExaminerViewer automatically redraws the
+ GLAutoDrawable to which it is attached upon updates. */
+ public boolean getAutoRedrawMode() {
+ return autoRedrawMode;
+ }
+
+ /** 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() {
+ if (window != null) {
+ 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;
+
+ int xSize = window.getWidth();
+ int ySize = window.getHeight();
+ 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);
+
+ }
+
+ if (autoRedrawMode) {
+ // Force redraw
+ window.repaint();
+ }
+ }
+ }
+
+ 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;
+ }
+
+ if (autoRedrawMode) {
+ // Force redraw
+ window.repaint();
+ }
+ }
+ }
+
+ 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(GL2 gl) {
+ recalc();
+
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ float[] data = new float[16];
+ params.getModelviewMatrix().getColumnMajorData(data);
+ gl.glLoadMatrixf(data, 0);
+
+ gl.glMatrixMode(GL2ES1.GL_PROJECTION);
+ params.getProjectionMatrix().getColumnMajorData(data);
+ gl.glLoadMatrixf(data, 0);
+ }
+
+ private void recalcInverseRotation(GL2 gl) {
+ Rotf oriInv = orientation.inverse();
+ Vec3f tmp = new Vec3f();
+ float ang = orientation.get(tmp);
+ 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..a0e55d7
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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<FaceInfo> */
+ private List faces;
+ /** List<ManipPart> */
+ private List highlightedGeometry;
+ /** List<ManipPart> */
+ 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<RotateHandleInfo> */
+ 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<ScaleHandleInfo> */
+ 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(GL2 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 ([email protected])
+ *
+ * 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..d498534
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 gl);
+}
diff --git a/src/gleem/ManipManager.java b/src/gleem/ManipManager.java
new file mode 100644
index 0000000..2fabd1e
--- /dev/null
+++ b/src/gleem/ManipManager.java
@@ -0,0 +1,409 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+import javax.media.opengl.awt.*;
+
+/** 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<AWTGLAutoDrawable>
+ 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(AWTGLAutoDrawable window) {
+ window.repaint();
+ }
+ };
+ private WindowUpdateListener windowListener;
+
+ class WindowInfo {
+ /** Set<Manip> */
+ 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(AWTGLAutoDrawable 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(AWTGLAutoDrawable window) {
+ if (window == null) {
+ return;
+ }
+ WindowInfo info = (WindowInfo) windowToInfoMap.get(window);
+ if (info != null) {
+ Object[] manips = info.manips.toArray();
+ for (int i = 0; i < manips.length; i++) {
+ removeManipFromWindow((Manip) manips[i], 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, AWTGLAutoDrawable 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, AWTGLAutoDrawable 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(AWTGLAutoDrawable 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
+ AWTGLAutoDrawable 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(AWTGLAutoDrawable window, GL2 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(AWTGLAutoDrawable 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(AWTGLAutoDrawable 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((AWTGLAutoDrawable) 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((AWTGLAutoDrawable) 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((AWTGLAutoDrawable) 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((AWTGLAutoDrawable) e.getComponent(), e.getModifiers(),
+ false, e.getX(), e.getY());
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private ManipManager() {
+ mapping = new RightTruncPyrMapping();
+ setWindowUpdateListener(null);
+ }
+
+ private void motionMethod(AWTGLAutoDrawable 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(AWTGLAutoDrawable 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(AWTGLAutoDrawable 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((AWTGLAutoDrawable) 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 ([email protected])
+ *
+ * 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..936f755
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 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 ([email protected])
+ *
+ * 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..5cf8f71
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 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..e243c62
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 gl) {
+ if (!visible)
+ return;
+ // FIXME: probably too slow
+ boolean reenable = gl.glIsEnabled(GL2ES1.GL_LIGHTING);
+ gl.glDisable(GL2ES1.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(GL2ES1.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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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..195f613
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 gl) {
+ if (!visible)
+ return;
+ boolean lightingOn = true;
+ // FIXME: this is too expensive; figure out another way
+ // if (glIsEnabled(GL2ES1.GL_LIGHTING))
+ // lightingOn = true;
+
+ if (lightingOn) {
+ gl.glEnable(GL2ES1.GL_COLOR_MATERIAL);
+ gl.glColorMaterial(GL.GL_FRONT_AND_BACK, GL2ES1.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(GL2ES1.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..179bbc7
--- /dev/null
+++ b/src/gleem/ManipPartTwoWayArrow.java
@@ -0,0 +1,124 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.*;
+
+/** 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 ([email protected])
+ *
+ * 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..004eb76
--- /dev/null
+++ b/src/gleem/NormalCalc.java
@@ -0,0 +1,116 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.*;
+
+/** 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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.*;
+
+/** <P> 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. </P>
+
+ <P> The "normalized" screen coordinates must have the following
+ properties: </P>
+
+ <P>
+ upper left corner = (-1, 1) <BR>
+ lower left corner = (-1, -1) <BR>
+ lower right corner = (1, -1) <BR>
+ upper right corner = (1, 1) <BR>
+ center = (0, 0)
+ </P>
+
+ <P> The application is responsible for specifying the window size
+ to allow the ManipManager to compute these coordinates. </P>
+*/
+
+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..03f4a00
--- /dev/null
+++ b/src/gleem/TestExaminerViewer.java
@@ -0,0 +1,166 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+
+
+
+/** 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 GLU glu = new GLU();
+ private CameraParameters params = new CameraParameters();
+ private ExaminerViewer viewer;
+
+ public void init(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ 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(GL2ES1.GL_LIGHT0, GL2ES1.GL_AMBIENT, ambient, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_DIFFUSE, diffuse, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_POSITION, lightPosition, 0);
+
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+ gl.glEnable(GL2ES1.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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(45, 1, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) drawable);
+
+ // Instantiate a HandleBoxManip
+ HandleBoxManip manip = new HandleBoxManip();
+ manip.setTranslation(new Vec3f(0, 0, -10));
+ manager.showManipInWindow(manip, (AWTGLAutoDrawable) drawable);
+
+ // Instantiate ExaminerViewer
+ viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons());
+ viewer.attach((AWTGLAutoDrawable) drawable, new HandleBoxManipBSphereProvider(manip));
+ viewer.viewAll(gl);
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+ viewer.update(gl);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, viewer.getCameraParameters());
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ // Unused routines
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {}
+ public void displayChanged(GLAutoDrawable 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 = new GLCanvas();
+ canvas.setSize(400, 400);
+ canvas.addGLEventListener(new Listener());
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ }
+}
diff --git a/src/gleem/TestHandleBox.java b/src/gleem/TestHandleBox.java
new file mode 100644
index 0000000..8be4a7d
--- /dev/null
+++ b/src/gleem/TestHandleBox.java
@@ -0,0 +1,155 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+
+
+/** 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 GLU glu = new GLU();
+ private CameraParameters params = new CameraParameters();
+
+ public void init(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ 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(GL2ES1.GL_LIGHT0, GL2ES1.GL_AMBIENT, ambient, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_DIFFUSE, diffuse, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_POSITION, lightPosition, 0);
+
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+ gl.glEnable(GL2ES1.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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(45, 1, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) drawable);
+
+ // Instantiate a HandleBoxManip
+ HandleBoxManip manip = new HandleBoxManip();
+ manip.setTranslation(new Vec3f(0, 0, -10));
+ manager.showManipInWindow(manip, (AWTGLAutoDrawable) drawable);
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, params);
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
+ GL2 gl = drawable.getGL().getGL2();
+ 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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(theta, aspect, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ }
+
+ // Unused routines
+ public void displayChanged(GLAutoDrawable 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 = new GLCanvas();
+ canvas.setSize(400, 400);
+ canvas.addGLEventListener(new Listener());
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ }
+}
diff --git a/src/gleem/TestMultiWin.java b/src/gleem/TestMultiWin.java
new file mode 100644
index 0000000..ae78828
--- /dev/null
+++ b/src/gleem/TestMultiWin.java
@@ -0,0 +1,175 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.Point;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+
+
+
+/** 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 GLU glu = new GLU();
+ private CameraParameters params = new CameraParameters();
+ private ExaminerViewer viewer;
+
+ public void init(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ 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(GL2ES1.GL_LIGHT0, GL2ES1.GL_AMBIENT, ambient, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_DIFFUSE, diffuse, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_POSITION, lightPosition, 0);
+
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+ gl.glEnable(GL2ES1.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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(45, 1, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) drawable);
+
+ manager.showManipInWindow(manip, (AWTGLAutoDrawable) drawable);
+
+ // Instantiate ExaminerViewer
+ viewer = new ExaminerViewer(MouseButtonHelper.numMouseButtons());
+ viewer.attach((AWTGLAutoDrawable) drawable, new HandleBoxManipBSphereProvider(manip));
+ viewer.viewAll(gl);
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+ viewer.update(gl);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, viewer.getCameraParameters());
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ // Unused routines
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {}
+ public void displayChanged(GLAutoDrawable 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 = new GLCanvas();
+ canvas.setSize(400, 400);
+ canvas.addGLEventListener(new Listener());
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setLocation(location);
+ frame.setVisible(true);
+ }
+
+ 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..fae4366
--- /dev/null
+++ b/src/gleem/TestTranslate1.java
@@ -0,0 +1,156 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+
+
+
+/** 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 GLU glu = new GLU();
+ private CameraParameters params = new CameraParameters();
+
+ public void init(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ 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(GL2ES1.GL_LIGHT0, GL2ES1.GL_AMBIENT, ambient, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_DIFFUSE, diffuse, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_POSITION, lightPosition, 0);
+
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+ gl.glEnable(GL2ES1.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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(45, 1, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) 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, (AWTGLAutoDrawable) drawable);
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, params);
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
+ GL2 gl = drawable.getGL().getGL2();
+ 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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(theta, aspect, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ }
+
+ // Unused routines
+ public void displayChanged(GLAutoDrawable 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 = new GLCanvas();
+ canvas.setSize(400, 400);
+ canvas.addGLEventListener(new Listener());
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ }
+}
diff --git a/src/gleem/TestTranslate2.java b/src/gleem/TestTranslate2.java
new file mode 100644
index 0000000..ea1ae0e
--- /dev/null
+++ b/src/gleem/TestTranslate2.java
@@ -0,0 +1,156 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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.Vec3f;
+import java.awt.BorderLayout;
+import java.awt.Frame;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import javax.media.opengl.GL;
+import javax.media.opengl.GL2ES1;
+import javax.media.opengl.GL2;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.awt.AWTGLAutoDrawable;
+import javax.media.opengl.awt.GLCanvas;
+import javax.media.opengl.glu.GLU;
+
+
+
+/** 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 GLU glu = new GLU();
+ private CameraParameters params = new CameraParameters();
+
+ public void init(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+
+ 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(GL2ES1.GL_LIGHT0, GL2ES1.GL_AMBIENT, ambient, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_DIFFUSE, diffuse, 0);
+ gl.glLightfv(GL2ES1.GL_LIGHT0, GL2ES1.GL_POSITION, lightPosition, 0);
+
+ gl.glEnable(GL2ES1.GL_LIGHTING);
+ gl.glEnable(GL2ES1.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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(45, 1, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+
+ // Register the window with the ManipManager
+ ManipManager manager = ManipManager.getManipManager();
+ manager.registerWindow((AWTGLAutoDrawable) 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, (AWTGLAutoDrawable) drawable);
+ }
+
+ public void dispose(GLAutoDrawable drawable) {
+ }
+
+ public void display(GLAutoDrawable drawable) {
+ GL2 gl = drawable.getGL().getGL2();
+ gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
+ ManipManager.getManipManager().updateCameraParameters((AWTGLAutoDrawable) drawable, params);
+ ManipManager.getManipManager().render((AWTGLAutoDrawable) drawable, gl);
+ }
+
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
+ GL2 gl = drawable.getGL().getGL2();
+ 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(GL2ES1.GL_PROJECTION);
+ gl.glLoadIdentity();
+ glu.gluPerspective(theta, aspect, 1, 100);
+ gl.glMatrixMode(GL2ES1.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ }
+
+ // Unused routines
+ public void displayChanged(GLAutoDrawable 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 = new GLCanvas();
+ canvas.setSize(400, 400);
+ canvas.addGLEventListener(new Listener());
+ frame.add(canvas, BorderLayout.CENTER);
+ frame.pack();
+ frame.setVisible(true);
+ }
+}
diff --git a/src/gleem/Translate1Manip.java b/src/gleem/Translate1Manip.java
new file mode 100644
index 0000000..15af612
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 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..fc2011c
--- /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 ([email protected])
+ *
+ * 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 javax.media.opengl.*;
+
+/** 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(GL2 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..8eff015
--- /dev/null
+++ b/src/gleem/WindowUpdateListener.java
@@ -0,0 +1,52 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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 javax.media.opengl.awt.AWTGLAutoDrawable;
+
+
+/** 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
+ GLAutoDrawables in which that Manip is shown. */
+
+public interface WindowUpdateListener {
+ public void update(AWTGLAutoDrawable 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 <b>direction</b> through the point
+ <b>point</b>. <b>direction</b> does not need to be normalized but must
+ not be the zero vector. */
+ public Line(Vec3f direction, Vec3f point) {
+ direction = new Vec3f(direction);
+ direction.normalize();
+ point = new Vec3f(point);
+ alongVec = new Vec3f();
+ recalc();
+ }
+
+ /** Setter does some work to maintain internal caches.
+ <b>direction</b> 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 <b>direction</b> is not
+ necessarily equal to <code>plane.setDirection(direction);
+ plane.getDirection();</code> */
+ 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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
+ <code>mul</code> 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 <B>src</B> and
+ inserts it into <B>dest</B>. 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 ([email protected])
+ *
+ * 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..d387806
--- /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 ([email protected])
+ *
+ * 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 <b>normal</b> and
+ goes through the point <b>point</b>. Normal does not need to be
+ unit length but must not be the zero vector. */
+ public Plane(Vec3f normal, Vec3f point) {
+ this.normal = new Vec3f(normal);
+ this.normal.normalize();
+ this.point = new Vec3f(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 <b>normal</b> is not
+ necessarily equal to <code>plane.setNormal(normal);
+ plane.getNormal();</code> */
+ 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 ([email protected])
+ *
+ * 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,
+ <b>normal</b> is not necessarily equal to
+ <code>plane.setNormal(normal); plane.getNormal();</code> */
+ 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 ([email protected])
+ *
+ * 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 <u>Robot Vision</u> 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, <u>Advanced Animation and
+ Rendering Techniques</u>.
+ @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 <u>Robot Vision</u>. 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 ([email protected])
+ *
+ * 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..4c02b61
--- /dev/null
+++ b/src/gleem/linalg/Vec2f.java
@@ -0,0 +1,186 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([email protected])
+ *
+ * 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(Vec2f arg) {
+ set(arg.x, arg.y);
+ }
+
+ 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 ([email protected])
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 ([email protected])
+ *
+ * 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<body>
+
+Linear algebra and classes implementing basic 3D operations.
+
+<P>
+
+See the <a href = "http://www.media.mit.edu/~kbrussel/gleem/"> gleem
+home page </a> for more information.
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<body>
+
+Widgets and auxiliary classes for interaction with a 3D scene.
+
+<P>
+
+See the <a href = "http://www.media.mit.edu/~kbrussel/gleem/"> gleem
+home page </a> for more information.
+
+</body>
+</html>