aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/OrientedShape3DRetained.java
diff options
context:
space:
mode:
authorHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
committerHarvey Harrison <[email protected]>2015-04-19 21:02:06 -0700
commit7a2e20caac9db6f789a7b3fab344b9758af45335 (patch)
treeb5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/OrientedShape3DRetained.java
parentf76ce302c4bb2a9f03bbee571ec5d05c29633023 (diff)
j3dcore: flatten the directory structure a bit
Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/javax/media/j3d/OrientedShape3DRetained.java')
-rw-r--r--src/javax/media/j3d/OrientedShape3DRetained.java610
1 files changed, 610 insertions, 0 deletions
diff --git a/src/javax/media/j3d/OrientedShape3DRetained.java b/src/javax/media/j3d/OrientedShape3DRetained.java
new file mode 100644
index 0000000..4fe4026
--- /dev/null
+++ b/src/javax/media/j3d/OrientedShape3DRetained.java
@@ -0,0 +1,610 @@
+/*
+ * Copyright 1999-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package javax.media.j3d;
+
+import javax.vecmath.AxisAngle4d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point3f;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector3f;
+import javax.vecmath.Vector4d;
+
+class OrientedShape3DRetained extends Shape3DRetained {
+
+ static final int ALIGNMENT_CHANGED = LAST_DEFINED_BIT << 1;
+ static final int AXIS_CHANGED = LAST_DEFINED_BIT << 2;
+ static final int ROTATION_CHANGED = LAST_DEFINED_BIT << 3;
+ static final int CONSTANT_SCALE_CHANGED = LAST_DEFINED_BIT << 4;
+ static final int SCALE_FACTOR_CHANGED = LAST_DEFINED_BIT << 5;
+
+
+ int mode = OrientedShape3D.ROTATE_ABOUT_AXIS;
+
+ // Axis about which to rotate.
+ Vector3f axis = new Vector3f(0.0f, 1.0f, 0.0f);
+ Point3f rotationPoint = new Point3f(0.0f, 0.0f, 1.0f);
+ private Vector3d nAxis = new Vector3d(0.0, 1.0, 0.0); // normalized axis
+
+ // reused temporaries
+ private Point3d viewPosition = new Point3d();
+ private Point3d yUpPoint = new Point3d();
+
+ private Vector3d eyeVec = new Vector3d();
+ private Vector3d yUp = new Vector3d();
+ private Vector3d zAxis = new Vector3d();
+ private Vector3d yAxis = new Vector3d();
+ private Vector3d vector = new Vector3d();
+
+ private AxisAngle4d aa = new AxisAngle4d();
+
+ private Transform3D xform = new Transform3D(); // used several times
+ private Transform3D zRotate = new Transform3D();
+
+ // For scale invariant mode
+ boolean constantScale = false;
+ double scaleFactor = 1.0;
+
+ // Frequently used variables for scale invariant computation
+ // Left and right Vworld to Clip coordinates transforms
+ private Transform3D left_xform = new Transform3D();
+ private Transform3D right_xform = new Transform3D();
+
+ // Transform for scaling the OrientedShape3D to correct for
+ // perspective foreshortening
+ Transform3D scaleXform = new Transform3D();
+
+ // Variables for converting between clip to local world coords
+ private Vector4d im_vec[] = {new Vector4d(), new Vector4d()};
+ private Vector4d lvec = new Vector4d();
+
+ boolean orientedTransformDirty = true;
+
+ private final Object transformLock = new Object();
+ private Transform3D[] orientedTransforms = new Transform3D[1];
+ static final double EPSILON = 1.0e-6;
+
+
+ /**
+ * Constructs a OrientedShape3D node with default parameters.
+ * The default values are as follows:
+ * <ul>
+ * alignment mode : ROTATE_ABOUT_AXIS<br>
+ * alignment axis : Y-axis (0,1,0)<br>
+ * rotation point : (0,0,1)<br>
+ *</ul>
+ */
+ public OrientedShape3DRetained() {
+ super();
+ this.nodeType = NodeRetained.ORIENTEDSHAPE3D;
+ }
+
+ // initializes alignment mode
+ void initAlignmentMode(int mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Sets the alignment mode.
+ * @param mode one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT
+ */
+ void setAlignmentMode(int mode) {
+ if (this.mode != mode) {
+ initAlignmentMode(mode);
+ sendChangedMessage(ALIGNMENT_CHANGED, new Integer(mode));
+ }
+ }
+
+ /**
+ * Retrieves the alignment mode.
+ * @return one of: ROTATE_ABOUT_AXIS or ROTATE_ABOUT_POINT
+ */
+ int getAlignmentMode() {
+ return(mode);
+ }
+
+ // initializes alignment axis
+ void initAlignmentAxis(Vector3f axis) {
+ initAlignmentAxis(axis.x, axis.y, axis.z);
+ }
+
+ // initializes alignment axis
+ void initAlignmentAxis(float x, float y, float z) {
+ this.axis.set(x,y,z);
+ double invMag;
+ invMag = 1.0/Math.sqrt(axis.x*axis.x + axis.y*axis.y + axis.z*axis.z);
+ nAxis.x = (double)axis.x*invMag;
+ nAxis.y = (double)axis.y*invMag;
+ nAxis.z = (double)axis.z*invMag;
+ }
+
+ /**
+ * Sets the new alignment axis. This is the ray about which this
+ * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS.
+ * @param axis the new alignment axis
+ */
+ void setAlignmentAxis(Vector3f axis) {
+ setAlignmentAxis(axis.x, axis.y, axis.z);
+ }
+
+ /**
+ * Sets the new alignment axis. This is the ray about which this
+ * OrientedShape3D rotates when the mode is ROTATE_ABOUT_AXIS.
+ * @param x the x component of the alignment axis
+ * @param y the y component of the alignment axis
+ * @param z the z component of the alignment axis
+ */
+ void setAlignmentAxis(float x, float y, float z) {
+ initAlignmentAxis(x,y,z);
+
+ if (mode == OrientedShape3D.ROTATE_ABOUT_AXIS) {
+ sendChangedMessage(AXIS_CHANGED, new Vector3f(x,y,z));
+ }
+ }
+
+ /**
+ * Retrieves the alignment axis of this OrientedShape3D node,
+ * and copies it into the specified vector.
+ * @param axis the vector that will contain the alignment axis
+ */
+ void getAlignmentAxis(Vector3f axis) {
+ axis.set(this.axis);
+ }
+
+ // initializes rotation point
+ void initRotationPoint(Point3f point) {
+ rotationPoint.set(point);
+ }
+
+ // initializes rotation point
+ void initRotationPoint(float x, float y, float z) {
+ rotationPoint.set(x,y,z);
+ }
+
+ /**
+ * Sets the new rotation point. This is the point about which the
+ * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT.
+ * @param point the new rotation point
+ */
+ void setRotationPoint(Point3f point) {
+ setRotationPoint(point.x, point.y, point.z);
+ }
+
+ /**
+ * Sets the new rotation point. This is the point about which the
+ * OrientedShape3D rotates when the mode is ROTATE_ABOUT_POINT.
+ * @param x the x component of the rotation point
+ * @param y the y component of the rotation point
+ * @param z the z component of the rotation point
+ */
+ void setRotationPoint(float x, float y, float z) {
+ initRotationPoint(x,y,z);
+
+ if (mode == OrientedShape3D.ROTATE_ABOUT_POINT) {
+ sendChangedMessage(ROTATION_CHANGED, new Point3f(x,y,z));
+ }
+ }
+
+ /**
+ * Retrieves the rotation point of this OrientedShape3D node,
+ * and copies it into the specified vector.
+ * @param axis the point that will contain the rotation point
+ */
+ void getRotationPoint(Point3f point) {
+ point.set(rotationPoint);
+ }
+
+ void setConstantScaleEnable(boolean enable) {
+ if(constantScale != enable) {
+ initConstantScaleEnable(enable);
+ sendChangedMessage(CONSTANT_SCALE_CHANGED, new Boolean(enable));
+ }
+ }
+
+ boolean getConstantScaleEnable() {
+ return constantScale;
+ }
+
+ void initConstantScaleEnable(boolean cons_scale) {
+ constantScale = cons_scale;
+ }
+
+ void setScale(double scale) {
+ initScale(scale);
+ if(constantScale)
+ sendChangedMessage(SCALE_FACTOR_CHANGED, new Double(scale));
+ }
+
+ void initScale(double scale) {
+ scaleFactor = scale;
+ }
+
+ double getScale() {
+ return scaleFactor;
+ }
+
+ void sendChangedMessage(int component, Object attr) {
+ J3dMessage changeMessage = new J3dMessage();
+ changeMessage.type = J3dMessage.ORIENTEDSHAPE3D_CHANGED;
+ changeMessage.threads = targetThreads ;
+ changeMessage.universe = universe;
+ changeMessage.args[0] = getGeomAtomsArray(mirrorShape3D);
+ changeMessage.args[1] = new Integer(component);
+ changeMessage.args[2] = attr;
+ OrientedShape3DRetained[] o3dArr =
+ new OrientedShape3DRetained[mirrorShape3D.size()];
+ mirrorShape3D.toArray(o3dArr);
+ changeMessage.args[3] = o3dArr;
+ changeMessage.args[4] = this;
+ VirtualUniverse.mc.processMessage(changeMessage);
+ }
+
+ @Override
+ void updateImmediateMirrorObject(Object[] args) {
+ int component = ((Integer)args[1]).intValue();
+ if ((component & (ALIGNMENT_CHANGED |
+ AXIS_CHANGED |
+ ROTATION_CHANGED |
+ CONSTANT_SCALE_CHANGED |
+ SCALE_FACTOR_CHANGED)) != 0) {
+ OrientedShape3DRetained[] msArr = (OrientedShape3DRetained[])args[3];
+ Object obj = args[2];
+ if ((component & ALIGNMENT_CHANGED) != 0) {
+ int mode = ((Integer)obj).intValue();
+ for (int i=0; i< msArr.length; i++) {
+ msArr[i].initAlignmentMode(mode);
+ }
+ }
+ else if ((component & AXIS_CHANGED) != 0) {
+ Vector3f axis =(Vector3f) obj;
+ for (int i=0; i< msArr.length; i++) {
+ msArr[i].initAlignmentAxis(axis);
+ }
+ }
+ else if ((component & ROTATION_CHANGED) != 0) {
+ Point3f point =(Point3f) obj;
+ for (int i=0; i< msArr.length; i++) {
+ msArr[i].initRotationPoint(point);
+ }
+ }
+ else if((component & CONSTANT_SCALE_CHANGED) != 0) {
+ boolean bool = ((Boolean)obj).booleanValue();
+ for (int i=0; i< msArr.length; i++) {
+ msArr[i].initConstantScaleEnable(bool);
+ }
+ }
+ else if((component & SCALE_FACTOR_CHANGED) != 0) {
+ double scale = ((Double)obj).doubleValue();
+ for (int i=0; i< msArr.length; i++) {
+ msArr[i].initScale(scale);
+ }
+ }
+ }
+ else {
+ super.updateImmediateMirrorObject(args);
+ }
+ }
+
+
+ Transform3D getOrientedTransform(int viewIndex) {
+ synchronized (transformLock) {
+ // check if the transforms list needs to be expanded
+ if (viewIndex >= orientedTransforms.length) {
+ Transform3D[] newList = new Transform3D[viewIndex + 1];
+ System.arraycopy(orientedTransforms, 0, newList, 0, orientedTransforms.length);
+ orientedTransforms = newList;
+ }
+
+ if (orientedTransforms[viewIndex] == null)
+ orientedTransforms[viewIndex] = new Transform3D();
+
+ return orientedTransforms[viewIndex];
+ }
+ }
+
+ // called on the parent object
+ // Should be synchronized so that the user thread does not modify the
+ // OrientedShape3D params while computing the transform
+ synchronized void updateOrientedTransform(Canvas3D canvas, int viewIndex) {
+ double angle = 0.0;
+ double sign;
+ boolean status;
+
+ Transform3D orientedxform = getOrientedTransform(viewIndex);
+ // get viewplatforms's location in virutal world
+ if (mode == OrientedShape3D.ROTATE_ABOUT_AXIS) { // rotate about axis
+ canvas.getCenterEyeInImagePlate(viewPosition);
+ canvas.getImagePlateToVworld(xform); // xform is imagePlateToLocal
+ xform.transform(viewPosition);
+
+ // get billboard's transform
+ xform.set(getCurrentLocalToVworld());
+ xform.invert(); // xform is now vWorldToLocal
+
+ // transform the eye position into the billboard's coordinate system
+ xform.transform(viewPosition);
+
+
+ // eyeVec is a vector from the local origin to the eye pt in local
+ eyeVec.set(viewPosition);
+ eyeVec.normalize();
+
+ // project the eye into the rotation plane
+ status = projectToPlane(eyeVec, nAxis);
+
+ if (status) {
+ // project the z axis into the rotation plane
+ zAxis.x = 0.0;
+ zAxis.y = 0.0;
+ zAxis.z = 1.0;
+ status = projectToPlane(zAxis, nAxis);
+ }
+ if (status) {
+
+ // compute the sign of the angle by checking if the cross product
+ // of the two vectors is in the same direction as the normal axis
+ vector.cross(eyeVec, zAxis);
+ if (vector.dot(nAxis) > 0.0) {
+ sign = 1.0;
+ } else {
+ sign = -1.0;
+ }
+
+ // compute the angle between the projected eye vector and the
+ // projected z
+
+ double dot = eyeVec.dot(zAxis);
+ if (dot > 1.0f) {
+ dot = 1.0f;
+ } else if (dot < -1.0f) {
+ dot = -1.0f;
+ }
+
+ angle = sign*Math.acos(dot);
+
+ // use -angle because xform is to *undo* rotation by angle
+ aa.x = nAxis.x;
+ aa.y = nAxis.y;
+ aa.z = nAxis.z;
+ aa.angle = -angle;
+ orientedxform.set(aa);
+ }
+ else {
+ orientedxform.setIdentity();
+ }
+
+ } else if(mode == OrientedShape3D.ROTATE_ABOUT_POINT ){ // rotate about point
+ // Need to rotate Z axis to point to eye, and Y axis to be
+ // parallel to view platform Y axis, rotating around rotation pt
+
+ // get the eye point
+ canvas.getCenterEyeInImagePlate(viewPosition);
+
+ // derive the yUp point
+ yUpPoint.set(viewPosition);
+ yUpPoint.y += 0.01; // one cm in Physical space
+
+ // transform the points to the Billboard's space
+ canvas.getImagePlateToVworld(xform); // xform is ImagePlateToVworld
+ xform.transform(viewPosition);
+ xform.transform(yUpPoint);
+
+ // get billboard's transform
+ xform.set(getCurrentLocalToVworld());
+ xform.invert(); // xform is vWorldToLocal
+
+ // transfom points to local coord sys
+ xform.transform(viewPosition);
+ xform.transform(yUpPoint);
+
+ // Make a vector from viewPostion to 0,0,0 in the BB coord sys
+ eyeVec.set(viewPosition);
+ eyeVec.normalize();
+
+ // create a yUp vector
+ yUp.set(yUpPoint);
+ yUp.sub(viewPosition);
+ yUp.normalize();
+
+
+ // find the plane to rotate z
+ zAxis.x = 0.0;
+ zAxis.y = 0.0;
+ zAxis.z = 1.0;
+
+ // rotation axis is cross product of eyeVec and zAxis
+ vector.cross(eyeVec, zAxis); // vector is cross product
+
+ // if cross product is non-zero, vector is rotation axis and
+ // rotation angle is acos(eyeVec.dot(zAxis)));
+ double length = vector.length();
+ if (length > 0.0001) {
+ double dot = eyeVec.dot(zAxis);
+ if (dot > 1.0f) {
+ dot = 1.0f;
+ } else if (dot < -1.0f) {
+ dot = -1.0f;
+ }
+ angle = Math.acos(dot);
+ aa.x = vector.x;
+ aa.y = vector.y;
+ aa.z = vector.z;
+ aa.angle = -angle;
+ zRotate.set(aa);
+ } else {
+ // no rotation needed, set to identity (scale = 1.0)
+ zRotate.set(1.0);
+ }
+
+ // Transform the yAxis by zRotate
+ yAxis.x = 0.0;
+ yAxis.y = 1.0;
+ yAxis.z = 0.0;
+ zRotate.transform(yAxis);
+
+ // project the yAxis onto the plane perp to the eyeVec
+ status = projectToPlane(yAxis, eyeVec);
+
+
+ if (status) {
+ // project the yUp onto the plane perp to the eyeVec
+ status = projectToPlane(yUp, eyeVec);
+ }
+
+ if (status) {
+ // rotation angle is acos(yUp.dot(yAxis));
+ double dot = yUp.dot(yAxis);
+
+ // Fix numerical error, otherwise acos return NULL
+ if (dot > 1.0f) {
+ dot = 1.0f;
+ } else if (dot < -1.0f) {
+ dot = -1.0f;
+ }
+
+ angle = Math.acos(dot);
+
+ // check the sign by looking a the cross product vs the eyeVec
+ vector.cross(yUp, yAxis); // vector is cross product
+ if (eyeVec.dot(vector) < 0) {
+ angle *= -1;
+ }
+ aa.x = eyeVec.x;
+ aa.y = eyeVec.y;
+ aa.z = eyeVec.z;
+ aa.angle = -angle;
+ xform.set(aa); // xform is now yRotate
+
+ // rotate around the rotation point
+ vector.x = rotationPoint.x;
+ vector.y = rotationPoint.y;
+ vector.z = rotationPoint.z; // vector to translate to RP
+ orientedxform.set(vector); // translate to RP
+ orientedxform.mul(xform); // yRotate
+ orientedxform.mul(zRotate); // zRotate
+ vector.scale(-1.0); // vector to translate back
+ xform.set(vector); // xform to translate back
+ orientedxform.mul(xform); // translate back
+ }
+ else {
+ orientedxform.setIdentity();
+ }
+
+ }
+ //Scale invariant computation
+ if(constantScale) {
+ // Back Xform a unit vector to local world coords
+ canvas.getInverseVworldProjection(left_xform, right_xform);
+
+ // the two endpts of the vector have to be transformed
+ // individually because the Xform is not affine
+ im_vec[0].set(0.0, 0.0, 0.0, 1.0);
+ im_vec[1].set(1.0, 0.0, 0.0, 1.0);
+ left_xform.transform(im_vec[0]);
+ left_xform.transform(im_vec[1]);
+
+ left_xform.set(getCurrentLocalToVworld());
+ left_xform.invert();
+ left_xform.transform(im_vec[0]);
+ left_xform.transform(im_vec[1]);
+ lvec.set(im_vec[1]);
+ lvec.sub(im_vec[0]);
+
+ // We simply need the direction of this vector
+ lvec.normalize();
+ im_vec[0].set(0.0, 0.0, 0.0, 1.0);
+ im_vec[1].set(lvec);
+ im_vec[1].w = 1.0;
+
+ // Forward Xfrom to clip coords
+ left_xform.set(getCurrentLocalToVworld());
+ left_xform.transform(im_vec[0]);
+ left_xform.transform(im_vec[1]);
+
+ canvas.getVworldProjection(left_xform, right_xform);
+ left_xform.transform(im_vec[0]);
+ left_xform.transform(im_vec[1]);
+
+ // Perspective division
+ im_vec[0].x /= im_vec[0].w;
+ im_vec[0].y /= im_vec[0].w;
+ im_vec[0].z /= im_vec[0].w;
+
+ im_vec[1].x /= im_vec[1].w;
+ im_vec[1].y /= im_vec[1].w;
+ im_vec[1].z /= im_vec[1].w;
+
+ lvec.set(im_vec[1]);
+ lvec.sub(im_vec[0]);
+
+ // Use the length of this vector to determine the scaling
+ // factor
+ double scale = 1/lvec.length();
+
+ // Convert to meters
+ scale *= scaleFactor*canvas.getPhysicalWidth()/2;
+
+ // Scale object so that it appears the same size
+ scaleXform.setScale(scale);
+ orientedxform.mul(scaleXform);
+ }
+
+ }
+
+
+ private boolean projectToPlane(Vector3d projVec, Vector3d planeVec) {
+ double dis = planeVec.dot(projVec);
+ projVec.x = projVec.x - planeVec.x*dis;
+ projVec.y = projVec.y - planeVec.y*dis;
+ projVec.z = projVec.z - planeVec.z*dis;
+
+ double length = projVec.length();
+ if (length < EPSILON) { // projVec is parallel to planeVec
+ return false;
+ }
+ projVec.scale(1 / length);
+ return true;
+ }
+
+ @Override
+ void compile(CompileState compState) {
+
+ super.compile(compState);
+
+ mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
+
+ // don't push the static transform to orientedShape3D
+ // because orientedShape3D is rendered using vertex array;
+ // it's not worth pushing the transform here
+
+ compState.keepTG = true;
+ }
+
+ @Override
+ void searchGeometryAtoms(UnorderList list) {
+ list.add(getGeomAtom(getMirrorShape(key)));
+ }
+}