summaryrefslogtreecommitdiffstats
path: root/src/gleem/HandleBoxManip.java
diff options
context:
space:
mode:
authorKenneth Russel <[email protected]>2003-06-25 09:05:29 +0000
committerKenneth Russel <[email protected]>2003-06-25 09:05:29 +0000
commit2179980ed660ef66a9c064d153c5de7994d431ab (patch)
tree926fa0ccc31737ad9753a64bf0451dd818652d1b /src/gleem/HandleBoxManip.java
parent1a1ad3a33b2932187410bc8bb4bf44362a26c8b0 (diff)
Split up net.java.games.util; moved GLUT and BufferUtils into
net.java.games.jogl.util, and moved demo-specific utility classes into jogl-demos project under demos.util. Added nearly all JavaOne demos into jogl-demos project; rewrote where necessary to use ClassLoader.getResourceAsStream() instead of flat files, put into packages and added to Makefile. Added gleem to jogl-demos project. Added jogl.jar build rule. git-svn-id: file:///usr/local/projects/SUN/JOGL/git-svn/../svn-server-sync/jogl-demos/trunk@3 3298f667-5e0e-4b4a-8ed4-a3559d26a5f4
Diffstat (limited to 'src/gleem/HandleBoxManip.java')
-rw-r--r--src/gleem/HandleBoxManip.java948
1 files changed, 948 insertions, 0 deletions
diff --git a/src/gleem/HandleBoxManip.java b/src/gleem/HandleBoxManip.java
new file mode 100644
index 0000000..bedde65
--- /dev/null
+++ b/src/gleem/HandleBoxManip.java
@@ -0,0 +1,948 @@
+/*
+ * gleem -- OpenGL Extremely Easy-To-Use Manipulators.
+ * Copyright (C) 1998-2003 Kenneth B. Russell ([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 net.java.games.jogl.*;
+
+/** Patterned after Inventor's HandleBoxManip (by Paul Isaacs and
+ David Mott) and TransformerManip (by Paul Isaacs). Center box
+ allows 3-D translation. Outer six handles allow rotation about the
+ box's six axes. When a handle is clicked, the axis of rotation is
+ immediately chosen as that which is most parallel to the viewing
+ direction (note there are at most two possibilities for the axis
+ of each handle's rotation). Eight corner handles allow aspect
+ ratio-preserving scaling; shift-dragging these handles allows
+ non-uniform scaling in one of two possible directions using a
+ "snap-to-axis" paradigm. These two directions are chosen as the
+ axes of the adjacent face to the handle whose normal most directly
+ faces the viewing direction. */
+
+public class HandleBoxManip extends Manip {
+ private ManipPart parts;
+ private Vec3f translation;
+ private Vec3f scale;
+ private Vec3f geometryScale;
+ private Rotf rotation;
+ /** Cumulative transform of this object */
+ private Mat4f xform;
+
+ /** Dragging state */
+ private static final int INACTIVE = 0;
+ private static final int TRANSLATE = 1;
+ private static final int ROTATE = 2;
+ // Scaling based on all three axes, preserving current aspect ratio
+ private static final int SCALE_XYZ = 3;
+ // Scaling along one of two axes (shift key + drag scale handle)
+ private static final int SCALE_SINGLE_AXIS = 4;
+
+ private int dragState;
+ private Plane dragPlane;
+ private Vec3f dragOffset;
+
+ /** Scale axes */
+ private static final int SCALE_XY = 0;
+ private static final int SCALE_YZ = 1;
+ private static final int SCALE_ZX = 2;
+
+ /** All of the line segments comprising the faces */
+ private ManipPart[] lineSegs;
+
+ static class FaceInfo {
+ ManipPart[] lineSegs;
+ /** The invisible square comprising this face's invisible, but
+ pickable, geometry */
+ ManipPart centerSquare;
+ Vec3f origNormal;
+ Vec3f normal;
+ int scaleAxes;
+
+ FaceInfo() {
+ lineSegs = new ManipPart[4];
+ origNormal = new Vec3f();
+ normal = new Vec3f();
+ }
+ }
+ /** List<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(GL gl) {
+ int i;
+ for (i = 0; i < 12; i++)
+ lineSegs[i].render(gl);
+ for (i = 0; i < rotateHandles.size(); i++)
+ ((RotateHandleInfo) rotateHandles.get(i)).geometry.render(gl);
+ for (i = 0; i < scaleHandles.size(); i++)
+ ((ScaleHandleInfo) scaleHandles.get(i)).geometry.render(gl);
+ }
+
+ public void intersectRay(Vec3f rayStart,
+ Vec3f rayDirection,
+ List results) {
+ for (Iterator iter = faces.iterator(); iter.hasNext(); ) {
+ ((FaceInfo) iter.next()).centerSquare.intersectRay(rayStart, rayDirection,
+ results, this);
+ }
+ for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) {
+ ((RotateHandleInfo) iter.next()).geometry.intersectRay(rayStart, rayDirection,
+ results, this);
+ }
+ for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) {
+ ((ScaleHandleInfo) iter.next()).geometry.intersectRay(rayStart, rayDirection,
+ results, this);
+ }
+ }
+
+ public void highlight(HitPoint hit) {
+ ManipPart part = hit.manipPart;
+ // Search for this part in the FaceInfo array
+ for (Iterator iter = faces.iterator(); iter.hasNext(); ) {
+ FaceInfo info = (FaceInfo) iter.next();
+ if (info.centerSquare == part) {
+ for (int j = 0; j < 4; j++) {
+ info.lineSegs[j].highlight();
+ highlightedGeometry.add(info.lineSegs[j]);
+ }
+ return;
+ }
+ }
+
+ // Otherwise, was a rotation or scale handle
+ part.highlight();
+ highlightedGeometry.add(part);
+ }
+
+ public void clearHighlight() {
+ for (Iterator iter = highlightedGeometry.iterator(); iter.hasNext(); ) {
+ ((ManipPart) iter.next()).clearHighlight();
+ }
+ highlightedGeometry.clear();
+ }
+
+ public void makeActive(HitPoint hit) {
+ // Find which piece of geometry it is
+ for (Iterator iter = faces.iterator(); iter.hasNext(); ) {
+ FaceInfo face = (FaceInfo) iter.next();
+ if (face.centerSquare == hit.manipPart) {
+ dragState = TRANSLATE;
+ dragPlane.setPoint(hit.intPt.getIntersectionPoint());
+ dragPlane.setNormal(face.normal);
+ dragOffset.sub(translation, hit.intPt.getIntersectionPoint());
+ for (int j = 0; j < 4; j++) {
+ face.lineSegs[j].highlight();
+ draggedGeometry.add(face.lineSegs[j]);
+ }
+ return;
+ }
+ }
+
+ for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) {
+ RotateHandleInfo rotInfo = (RotateHandleInfo) iter.next();
+ if (rotInfo.geometry == hit.manipPart) {
+ dragState = ROTATE;
+ // Determine which direction we're rotating by taking dot
+ // products of the ray direction with the rotating planes'
+ // normals
+ float dotp0 =
+ Math.abs(hit.rayDirection.dot(((FaceInfo) faces.get(rotInfo.faceIdx0)).normal));
+ float dotp1 =
+ Math.abs(hit.rayDirection.dot(((FaceInfo) faces.get(rotInfo.faceIdx1)).normal));
+ int faceIdx;
+ if (dotp0 > dotp1)
+ faceIdx = rotInfo.faceIdx0;
+ else
+ faceIdx = rotInfo.faceIdx1;
+ FaceInfo face = (FaceInfo) faces.get(faceIdx);
+ // Set up the rotation plane
+ rotatePlane.setOrigin(translation);
+ rotatePlane.setNormal(face.normal);
+ Vec3f dummy = new Vec3f();
+ Vec2f startUV = new Vec2f();
+ rotatePlane.projectPoint(hit.intPt.getIntersectionPoint(), dummy, startUV);
+ startAngle = (float) Math.atan2(startUV.y(), startUV.x());
+ startRot.set(rotation);
+ rotInfo.geometry.highlight();
+ draggedGeometry.add(rotInfo.geometry);
+ return;
+ }
+ }
+
+ for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) {
+ ScaleHandleInfo info = (ScaleHandleInfo) iter.next();
+ if (info.geometry == hit.manipPart) {
+ if (hit.shiftDown) {
+ dragState = SCALE_SINGLE_AXIS;
+ // Figure out which are the two axes along which we're
+ // going to allow scaling by taking dot products of the
+ // ray direction with the normals of the adjacent faces
+ // to the scale handle.
+ float dotp = 0.0f;
+ float tmpDotp;
+ int faceIdx = 0;
+ for (int i = 0; i < 3; i++) {
+ FaceInfo faceInfo = (FaceInfo) faces.get(info.faceIndices[i]);
+ tmpDotp = faceInfo.normal.dot(hit.rayDirection);
+ if ((i == 0) || (tmpDotp < dotp)) {
+ dotp = tmpDotp;
+ faceIdx = info.faceIndices[i];
+ }
+ }
+ scaleAxes = ((FaceInfo) faces.get(faceIdx)).scaleAxes;
+ Vec3f uAxisOrig = new Vec3f();
+ Vec3f vAxisOrig = new Vec3f();
+ if (scaleAxes == SCALE_XY) {
+ uAxisOrig.set(1, 0, 0);
+ vAxisOrig.set(0, 1, 0);
+ } else if (scaleAxes == SCALE_YZ) {
+ uAxisOrig.set(0, 1, 0);
+ vAxisOrig.set(0, 0, 1);
+ } else {
+ uAxisOrig.set(0, 0, 1);
+ vAxisOrig.set(1, 0, 0);
+ }
+ Vec3f uAxis = new Vec3f();
+ Vec3f vAxis = new Vec3f();
+ Mat4f rotationTmpMat = new Mat4f();
+ rotationTmpMat.makeIdent();
+ rotationTmpMat.setRotation(rotation);
+ rotationTmpMat.xformDir(uAxisOrig, uAxis);
+ rotationTmpMat.xformDir(vAxisOrig, vAxis);
+ Vec3f normal = new Vec3f();
+ normal.cross(uAxis, vAxis);
+ scaleAxisPlane.setNormalAndUV(normal, uAxis, vAxis);
+ // We need to be able to constrain the scaling to be
+ // nonnegative.
+ Vec3f newOrigin = new Vec3f();
+ Vec2f foo = new Vec2f();
+ scaleAxisPlane.projectPoint(translation, newOrigin, foo);
+ scaleAxisPlane.setOrigin(newOrigin);
+ scaleAxisOffset.sub(hit.intPt.getIntersectionPoint(), newOrigin);
+ // Now project intersection point onto plane
+ Vec3f bar = new Vec3f();
+ scaleAxisPlane.projectPoint(hit.intPt.getIntersectionPoint(),
+ bar, scaleAxisOrigUV);
+ // Put the plane back where it was
+ scaleAxisPlane.setOrigin(hit.intPt.getIntersectionPoint());
+ origScale.set(scale);
+ } else {
+ dragState = SCALE_XYZ;
+ scaleXYZLine.setPoint(hit.intPt.getIntersectionPoint());
+ Vec3f scaleDiffVec = new Vec3f();
+ scaleDiffVec.sub(hit.intPt.getIntersectionPoint(), translation);
+ scaleXYZLine.setDirection(scaleDiffVec);
+ origScale.set(scale);
+ origScaleLen = scaleDiffVec.length();
+ }
+ info.geometry.highlight();
+ draggedGeometry.add(info.geometry);
+ return;
+ }
+ }
+
+ throw new RuntimeException("Couldn't find intersected piece of geometry");
+ }
+
+ public void drag(Vec3f rayStart,
+ Vec3f rayDirection) {
+ if (dragState == TRANSLATE) {
+ // Algorithm: Find intersection of ray with dragPlane. Add
+ // dragOffset to this point to get new translation.
+ IntersectionPoint intPt = new IntersectionPoint();
+ if (dragPlane.intersectRay(rayStart,
+ rayDirection,
+ intPt) == false) {
+ // Ray is parallel to plane. Punt.
+ return;
+ }
+ translation.add(intPt.getIntersectionPoint(), dragOffset);
+ recalc();
+ } else if (dragState == ROTATE) {
+ IntersectionPoint intPt = new IntersectionPoint();
+ Vec2f uvCoords = new Vec2f();
+ if (rotatePlane.intersectRay(rayStart,
+ rayDirection,
+ intPt,
+ uvCoords) == false) {
+ // Ray is parallel to plane. Punt.
+ return;
+ }
+ // Compute offset rotation angle
+ Rotf offsetRot = new Rotf();
+ offsetRot.set(rotatePlane.getNormal(),
+ (float) Math.atan2(uvCoords.y(), uvCoords.x()) - startAngle);
+ rotation.mul(offsetRot, startRot);
+ recalc();
+ } else if (dragState == SCALE_XYZ) {
+ Vec3f closestPt = new Vec3f();
+ boolean gotPt = scaleXYZLine.closestPointToRay(rayStart,
+ rayDirection,
+ closestPt);
+ if (gotPt) {
+ // How far have we moved?
+ // Clamp scale to be positive.
+ Vec3f newDiffVec = new Vec3f();
+ newDiffVec.sub(closestPt, translation);
+ if (newDiffVec.dot(scaleXYZLine.getDirection()) < 0) {
+ scale.set(0, 0, 0);
+ } else {
+ float scaleChange = newDiffVec.length() / origScaleLen;
+ scale.set(origScale);
+ scale.scale(scaleChange);
+ }
+ recalc();
+ }
+ } else if (dragState == SCALE_SINGLE_AXIS) {
+ IntersectionPoint intPt = new IntersectionPoint();
+ Vec2f uvCoords = new Vec2f();
+ if (scaleAxisPlane.intersectRay(rayStart, rayDirection, intPt, uvCoords)) {
+ Vec2f faceCenteredUVCoords = new Vec2f();
+ Vec3f foo = new Vec3f();
+ Vec3f tmp = new Vec3f();
+ tmp.set(intPt.getIntersectionPoint());
+ tmp.add(scaleAxisOffset);
+ scaleAxisPlane.projectPoint(tmp, foo, faceCenteredUVCoords);
+ if ((MathUtil.sgn(faceCenteredUVCoords.x()) ==
+ MathUtil.sgn(scaleAxisOrigUV.x())) &&
+ (MathUtil.sgn(faceCenteredUVCoords.y()) ==
+ MathUtil.sgn(scaleAxisOrigUV.y()))) {
+ if (faceCenteredUVCoords.x() < 0)
+ uvCoords.setX(uvCoords.x() * -1);
+ if (faceCenteredUVCoords.y() < 0)
+ uvCoords.setY(uvCoords.y() * -1);
+ Vec3f scaleVec = new Vec3f();
+ if (Math.abs(uvCoords.x()) > Math.abs(uvCoords.y())) {
+ if (scaleAxes == SCALE_XY)
+ scaleVec.setX(uvCoords.x());
+ else if (scaleAxes == SCALE_YZ)
+ scaleVec.setY(uvCoords.x());
+ else
+ scaleVec.setZ(uvCoords.x());
+ } else {
+ if (scaleAxes == SCALE_XY)
+ scaleVec.setY(uvCoords.y());
+ else if (scaleAxes == SCALE_YZ)
+ scaleVec.setZ(uvCoords.y());
+ else
+ scaleVec.setX(uvCoords.y());
+ }
+ scaleVec.setX(scaleVec.x() / geometryScale.x());
+ scaleVec.setY(scaleVec.y() / geometryScale.y());
+ scaleVec.setZ(scaleVec.z() / geometryScale.z());
+ scale.add(origScale, scaleVec);
+ // This shouldn't be necessary anymore
+ /*
+ if (scale.x() < 0)
+ scale.setX(0);
+ if (scale.y() < 0)
+ scale.setY(0);
+ if (scale.z() < 0)
+ scale.setZ(0);
+ */
+ } else {
+ if (Math.abs(uvCoords.x()) > Math.abs(uvCoords.y())) {
+ if (scaleAxes == SCALE_XY)
+ scale.setX(0);
+ else if (scaleAxes == SCALE_YZ)
+ scale.setY(0);
+ else
+ scale.setZ(0);
+ } else {
+ if (scaleAxes == SCALE_XY)
+ scale.setY(0);
+ else if (scaleAxes == SCALE_YZ)
+ scale.setZ(0);
+ else
+ scale.setX(0);
+ }
+ }
+ recalc();
+ }
+ } else {
+ throw new RuntimeException("HandleBoxManip::drag: ERROR: Unexpected drag state");
+ }
+ super.drag(rayStart, rayDirection);
+ }
+
+ public void makeInactive() {
+ dragState = INACTIVE;
+ for (Iterator iter = draggedGeometry.iterator(); iter.hasNext(); ) {
+ ((ManipPart) iter.next()).clearHighlight();
+ }
+ draggedGeometry.clear();
+ }
+
+ //----------------------------------------------------------------------
+ // Internals only below this point
+ //
+
+ private void createGeometry() {
+ ManipPartGroup group = new ManipPartGroup();
+
+ //
+ // Lines
+ //
+
+ // Top face:
+ // Front line
+ lineSegs[0] = createLineSeg(new Vec3f(0, 1, 1),
+ new Vec3f(1, 0, 0),
+ new Vec3f(0, 1, 0));
+ // Left line
+ lineSegs[1] = createLineSeg(new Vec3f(-1, 1, 0),
+ new Vec3f(0, 0, 1),
+ new Vec3f(0, 1, 0));
+ // Back line
+ lineSegs[2] = createLineSeg(new Vec3f(0, 1, -1),
+ new Vec3f(1, 0, 0),
+ new Vec3f(0, 1, 0));
+ // Right line
+ lineSegs[3] = createLineSeg(new Vec3f(1, 1, 0),
+ new Vec3f(0, 0, 1),
+ new Vec3f(0, 1, 0));
+ // Middle segments:
+ // Front left
+ lineSegs[4] = createLineSeg(new Vec3f(-1, 0, 1),
+ new Vec3f(0, -1, 0),
+ new Vec3f(1, 0, 0));
+ // Back left
+ lineSegs[5] = createLineSeg(new Vec3f(-1, 0, -1),
+ new Vec3f(0, -1, 0),
+ new Vec3f(1, 0, 0));
+ // Back right
+ lineSegs[6] = createLineSeg(new Vec3f(1, 0, -1),
+ new Vec3f(0, -1, 0),
+ new Vec3f(1, 0, 0));
+ // Front right
+ lineSegs[7] = createLineSeg(new Vec3f(1, 0, 1),
+ new Vec3f(0, -1, 0),
+ new Vec3f(1, 0, 0));
+ // Bottom face:
+ // Front line
+ lineSegs[8] = createLineSeg(new Vec3f(0, -1, 1),
+ new Vec3f(1, 0, 0),
+ new Vec3f(0, 1, 0));
+ // Left line
+ lineSegs[9] = createLineSeg(new Vec3f(-1, -1, 0),
+ new Vec3f(0, 0, 1),
+ new Vec3f(0, 1, 0));
+ // Back line
+ lineSegs[10] = createLineSeg(new Vec3f(0, -1, -1),
+ new Vec3f(1, 0, 0),
+ new Vec3f(0, 1, 0));
+ // Right line
+ lineSegs[11] = createLineSeg(new Vec3f(1, -1, 0),
+ new Vec3f(0, 0, 1),
+ new Vec3f(0, 1, 0));
+
+ for (int i = 0; i < 12; i++) {
+ group.addChild(lineSegs[i]);
+ }
+
+ //
+ // Faces
+ //
+
+ // Front face (index 0)
+ FaceInfo info = new FaceInfo();
+ info.origNormal.set(0, 0, 1);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0));
+ info.lineSegs[0] = lineSegs[0];
+ info.lineSegs[1] = lineSegs[4];
+ info.lineSegs[2] = lineSegs[7];
+ info.lineSegs[3] = lineSegs[8];
+ info.scaleAxes = SCALE_XY;
+ faces.add(info);
+ // Right face (index 1)
+ info = new FaceInfo();
+ info.origNormal.set(1, 0, 0);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0));
+ info.lineSegs[0] = lineSegs[3];
+ info.lineSegs[1] = lineSegs[6];
+ info.lineSegs[2] = lineSegs[7];
+ info.lineSegs[3] = lineSegs[11];
+ info.scaleAxes = SCALE_YZ;
+ faces.add(info);
+ // Back face (index 2)
+ info = new FaceInfo();
+ info.origNormal.set(0, 0, -1);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0));
+ info.lineSegs[0] = lineSegs[2];
+ info.lineSegs[1] = lineSegs[5];
+ info.lineSegs[2] = lineSegs[6];
+ info.lineSegs[3] = lineSegs[10];
+ info.scaleAxes = SCALE_XY;
+ faces.add(info);
+ // Left face (index 3)
+ info = new FaceInfo();
+ info.origNormal.set(-1, 0, 0);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 1, 0));
+ info.lineSegs[0] = lineSegs[1];
+ info.lineSegs[1] = lineSegs[4];
+ info.lineSegs[2] = lineSegs[5];
+ info.lineSegs[3] = lineSegs[9];
+ info.scaleAxes = SCALE_YZ;
+ faces.add(info);
+ // Top face (index 4)
+ info = new FaceInfo();
+ info.origNormal.set(0, 1, 0);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 0, -1));
+ info.lineSegs[0] = lineSegs[0];
+ info.lineSegs[1] = lineSegs[1];
+ info.lineSegs[2] = lineSegs[2];
+ info.lineSegs[3] = lineSegs[3];
+ info.scaleAxes = SCALE_ZX;
+ faces.add(info);
+ // Bottom face (index 5)
+ info = new FaceInfo();
+ info.origNormal.set(0, -1, 0);
+ info.centerSquare =
+ createFace(info.origNormal, info.origNormal, new Vec3f(0, 0, 1));
+ info.lineSegs[0] = lineSegs[8];
+ info.lineSegs[1] = lineSegs[9];
+ info.lineSegs[2] = lineSegs[10];
+ info.lineSegs[3] = lineSegs[11];
+ info.scaleAxes = SCALE_ZX;
+ faces.add(info);
+
+ for (Iterator iter = faces.iterator(); iter.hasNext(); ) {
+ group.addChild(((FaceInfo) iter.next()).centerSquare);
+ }
+
+ //
+ // Rotation handles
+ //
+
+ // Front handle. Rotates about top/bottom and left/right faces.
+ // Maintain references to top and right faces.
+ RotateHandleInfo rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 4;
+ rotInfo.faceIdx1 = 1;
+ rotInfo.geometry = createRotateHandle(new Vec3f(0, 0, 1));
+ rotateHandles.add(rotInfo);
+ // Right handle. Rotates about top/bottom and front/back faces.
+ // Maintain references to top and front faces.
+ rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 4;
+ rotInfo.faceIdx1 = 0;
+ rotInfo.geometry = createRotateHandle(new Vec3f(1, 0, 0));
+ rotateHandles.add(rotInfo);
+ // Back handle. Rotates about top/bottom and left/right faces.
+ // Maintain references to top and right faces.
+ rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 4;
+ rotInfo.faceIdx1 = 1;
+ rotInfo.geometry = createRotateHandle(new Vec3f(0, 0, -1));
+ rotateHandles.add(rotInfo);
+ // Left handle. Rotates about top/bottom and front/back faces.
+ // Maintain references to top and front faces.
+ rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 4;
+ rotInfo.faceIdx1 = 0;
+ rotInfo.geometry = createRotateHandle(new Vec3f(-1, 0, 0));
+ rotateHandles.add(rotInfo);
+ // Top handle. Rotates about front/back and left/right faces.
+ // Maintain references to front and right faces.
+ rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 0;
+ rotInfo.faceIdx1 = 1;
+ rotInfo.geometry = createRotateHandle(new Vec3f(0, 1, 0));
+ rotateHandles.add(rotInfo);
+ // Bottom handle. Rotates about front/back and left/right faces.
+ // Maintain references to front and right faces.
+ rotInfo = new RotateHandleInfo();
+ rotInfo.faceIdx0 = 0;
+ rotInfo.faceIdx1 = 1;
+ rotInfo.geometry = createRotateHandle(new Vec3f(0, -1, 0));
+ rotateHandles.add(rotInfo);
+
+ for (Iterator iter = rotateHandles.iterator(); iter.hasNext(); ) {
+ group.addChild(((RotateHandleInfo) iter.next()).geometry);
+ }
+
+ // Scale handles
+ // Top right front (order: front right top)
+ ScaleHandleInfo scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(1, 1, 1));
+ scaleInfo.faceIndices[0] = 0;
+ scaleInfo.faceIndices[1] = 1;
+ scaleInfo.faceIndices[2] = 4;
+ scaleHandles.add(scaleInfo);
+ // Top right back (order: right back top)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(1, 1, -1));
+ scaleInfo.faceIndices[0] = 1;
+ scaleInfo.faceIndices[1] = 2;
+ scaleInfo.faceIndices[2] = 4;
+ scaleHandles.add(scaleInfo);
+ // Bottom right front (order: front right bottom)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(1, -1, 1));
+ scaleInfo.faceIndices[0] = 0;
+ scaleInfo.faceIndices[1] = 1;
+ scaleInfo.faceIndices[2] = 5;
+ scaleHandles.add(scaleInfo);
+ // Bottom right back (order: right back bottom)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(1, -1, -1));
+ scaleInfo.faceIndices[0] = 1;
+ scaleInfo.faceIndices[1] = 2;
+ scaleInfo.faceIndices[2] = 5;
+ scaleHandles.add(scaleInfo);
+ // Top left front (order: front left top)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(-1, 1, 1));
+ scaleInfo.faceIndices[0] = 0;
+ scaleInfo.faceIndices[1] = 3;
+ scaleInfo.faceIndices[2] = 4;
+ scaleHandles.add(scaleInfo);
+ // Top left back (order: back left top)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(-1, 1, -1));
+ scaleInfo.faceIndices[0] = 2;
+ scaleInfo.faceIndices[1] = 3;
+ scaleInfo.faceIndices[2] = 4;
+ scaleHandles.add(scaleInfo);
+ // Bottom left front (order: front left bottom)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(-1, -1, 1));
+ scaleInfo.faceIndices[0] = 0;
+ scaleInfo.faceIndices[1] = 3;
+ scaleInfo.faceIndices[2] = 5;
+ scaleHandles.add(scaleInfo);
+ // Bottom left back (order: back left bottom)
+ scaleInfo = new ScaleHandleInfo();
+ scaleInfo.geometry = createScaleHandle(new Vec3f(-1, -1, -1));
+ scaleInfo.faceIndices[0] = 2;
+ scaleInfo.faceIndices[1] = 3;
+ scaleInfo.faceIndices[2] = 5;
+ scaleHandles.add(scaleInfo);
+
+ for (Iterator iter = scaleHandles.iterator(); iter.hasNext(); ) {
+ group.addChild(((ScaleHandleInfo) iter.next()).geometry);
+ }
+
+ parts = group;
+ }
+
+ private ManipPart createLineSeg(Vec3f translation,
+ Vec3f xAxis,
+ Vec3f yAxis) {
+ ManipPartTransform xform = new ManipPartTransform();
+ ManipPartLineSeg lineSeg = new ManipPartLineSeg();
+ xform.addChild(lineSeg);
+ Mat4f offset = new Mat4f();
+ offset.makeIdent();
+ Vec3f zAxis = new Vec3f();
+ zAxis.cross(xAxis, yAxis);
+ offset.set(0, 0, xAxis.x());
+ offset.set(1, 0, xAxis.y());
+ offset.set(2, 0, xAxis.z());
+ offset.set(0, 1, yAxis.x());
+ offset.set(1, 1, yAxis.y());
+ offset.set(2, 1, yAxis.z());
+ offset.set(0, 2, zAxis.x());
+ offset.set(1, 2, zAxis.y());
+ offset.set(2, 2, zAxis.z());
+ offset.set(0, 3, translation.x());
+ offset.set(1, 3, translation.y());
+ offset.set(2, 3, translation.z());
+ xform.setOffsetTransform(offset);
+ return xform;
+ }
+
+ private ManipPart createFace(Vec3f translation,
+ Vec3f normal,
+ Vec3f up) {
+ ManipPartTransform xform = new ManipPartTransform();
+ ManipPartSquare square = new ManipPartSquare();
+ square.setVisible(false);
+ xform.addChild(square);
+ Mat4f offset = new Mat4f();
+ offset.makeIdent();
+ Vec3f right = new Vec3f();
+ right.cross(up, normal);
+ offset.set(0, 0, right.x());
+ offset.set(1, 0, right.y());
+ offset.set(2, 0, right.z());
+ offset.set(0, 1, up.x());
+ offset.set(1, 1, up.y());
+ offset.set(2, 1, up.z());
+ offset.set(0, 2, normal.x());
+ offset.set(1, 2, normal.y());
+ offset.set(2, 2, normal.z());
+ offset.set(0, 3, translation.x());
+ offset.set(1, 3, translation.y());
+ offset.set(2, 3, translation.z());
+ xform.setOffsetTransform(offset);
+ return xform;
+ }
+
+ private ManipPart createRotateHandle(Vec3f direction) {
+ ManipPartCube handle = new ManipPartCube();
+ Mat4f offset = new Mat4f();
+ offset.makeIdent();
+ offset.set(0, 0, 0.1f);
+ offset.set(1, 1, 0.1f);
+ offset.set(2, 2, 0.1f);
+ Vec3f scaledDirection = new Vec3f(direction);
+ scaledDirection.scale(2.0f);
+ offset.setTranslation(scaledDirection);
+ ManipPartTransform xform = new ManipPartTransform();
+ xform.addChild(handle);
+ xform.setOffsetTransform(offset);
+ return xform;
+ }
+
+ private ManipPart createScaleHandle(Vec3f position) {
+ ManipPartCube handle = new ManipPartCube();
+ Mat4f offset = new Mat4f();
+ offset.makeIdent();
+ offset.set(0, 0, 0.1f);
+ offset.set(1, 1, 0.1f);
+ offset.set(2, 2, 0.1f);
+ offset.setTranslation(position);
+ ManipPartTransform xform = new ManipPartTransform();
+ xform.addChild(handle);
+ xform.setOffsetTransform(offset);
+ return xform;
+ }
+
+ private void recalc() {
+ // Construct local to world transform for geometry.
+ // Scale, Rotation, Translation. Since we're right multiplying
+ // column vectors, the actual matrix composed is TRS.
+ Mat4f scaleMat = new Mat4f();
+ Mat4f rotMat = new Mat4f();
+ Mat4f xlateMat = new Mat4f();
+ Mat4f tmpMat = new Mat4f();
+ scaleMat.makeIdent();
+ scaleMat.set(0, 0, scale.x() * geometryScale.x());
+ scaleMat.set(1, 1, scale.y() * geometryScale.y());
+ scaleMat.set(2, 2, scale.z() * geometryScale.z());
+ rotMat.makeIdent();
+ rotMat.setRotation(rotation);
+ xlateMat.makeIdent();
+ xlateMat.set(0, 3, translation.x());
+ xlateMat.set(1, 3, translation.y());
+ xlateMat.set(2, 3, translation.z());
+ tmpMat.mul(xlateMat, rotMat);
+ xform.mul(tmpMat, scaleMat);
+ int i;
+ for (i = 0; i < 12; i++) {
+ lineSegs[i].setTransform(xform);
+ }
+ for (i = 0; i < faces.size(); i++) {
+ FaceInfo face = (FaceInfo) faces.get(i);
+ face.centerSquare.setTransform(xform);
+ xform.xformDir(face.origNormal, face.normal);
+ face.normal.normalize();
+
+ RotateHandleInfo rotInfo = (RotateHandleInfo) rotateHandles.get(i);
+ rotInfo.geometry.setTransform(xform);
+ }
+ for (i = 0; i < scaleHandles.size(); i++) {
+ ((ScaleHandleInfo) scaleHandles.get(i)).geometry.setTransform(xform);
+ }
+ }
+}