aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/CanvasViewCache.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/CanvasViewCache.java')
-rw-r--r--src/javax/media/j3d/CanvasViewCache.java2044
1 files changed, 2044 insertions, 0 deletions
diff --git a/src/javax/media/j3d/CanvasViewCache.java b/src/javax/media/j3d/CanvasViewCache.java
new file mode 100644
index 0000000..0360d3c
--- /dev/null
+++ b/src/javax/media/j3d/CanvasViewCache.java
@@ -0,0 +1,2044 @@
+/*
+ * Copyright 1997-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 java.awt.Rectangle;
+
+import javax.vecmath.Matrix4d;
+import javax.vecmath.Point2d;
+import javax.vecmath.Point3d;
+import javax.vecmath.Point4d;
+import javax.vecmath.SingularMatrixException;
+import javax.vecmath.Vector3d;
+import javax.vecmath.Vector4d;
+
+/**
+ * The CanvasViewCache class is used to cache all data, both API data
+ * and derived data, that is dependent on the Canvas3D or Screen3D.
+ * The final view and projection matrices are stored here.
+ */
+
+class CanvasViewCache extends Object {
+ // Used for debugging only
+ private static Object debugLock = new Object();
+
+ // The canvas associated with this canvas view cache
+ private Canvas3D canvas;
+
+ // Mask that indicates this CanvasViewCache view dependence info. has changed,
+ // and CanvasViewCache may need to recompute the final view matries.
+ int cvcDirtyMask = 0;
+
+ // The screen view cache associated with this canvas view cache
+ private ScreenViewCache screenViewCache;
+
+ // The view cache associated with this canvas view cache
+ private ViewCache viewCache;
+
+ // *************
+ // API/INPUT DATA
+ // *************
+
+ // The position and size of the canvas (in pixels)
+ private int awtCanvasX;
+ private int awtCanvasY;
+ private int awtCanvasWidth;
+ private int awtCanvasHeight;
+
+ // The current RenderBin used for rendering during the frame
+ // associated with this snapshot.
+ private RenderBin renderBin;
+
+ // Flag indicating whether or not stereo will be used. Computed by
+ // Canvas3D as: useStereo = stereoEnable && stereoAvailable
+ private boolean useStereo;
+
+ // Current monoscopic view policy from canvas
+ private int monoscopicViewPolicy;
+
+ // The manual positions of the left and right eyes in image-plate
+ // coordinates.
+ // Note that these values are only used in non-head-tracked mode
+ // when the view's window eyepoint policy is one of RELATIVE_TO_SCREEN
+ // or RELATIVE_TO_WINDOW.
+ private Point3d leftManualEyeInImagePlate = new Point3d();
+ private Point3d rightManualEyeInImagePlate = new Point3d();
+
+ // *************
+ // DERIVED DATA
+ // *************
+
+ // The width and height of the screen in meters (from ScreenViewCache)
+ double physicalScreenWidth;
+ double physicalScreenHeight;
+
+ // The width and height of the screen in pixels (from ScreenViewCache)
+ int screenWidth;
+ int screenHeight;
+
+ // Meters per pixel in the X and Y dimension (from ScreenViewCache)
+ double metersPerPixelX;
+ double metersPerPixelY;
+
+ // The position and size of the canvas (in pixels)
+ private int canvasX;
+ private int canvasY;
+ private int canvasWidth;
+ private int canvasHeight;
+
+ // Either the Canvas' or the View's monoscopicViewPolicy
+ private int effectiveMonoscopicViewPolicy;
+
+ // The current cached projection transforms.
+ private Transform3D leftProjection = new Transform3D();
+ private Transform3D rightProjection = new Transform3D();
+ private Transform3D infLeftProjection = new Transform3D();
+ private Transform3D infRightProjection = new Transform3D();
+
+ // The current cached viewing transforms.
+ private Transform3D leftVpcToEc = new Transform3D();
+ private Transform3D rightVpcToEc = new Transform3D();
+ private Transform3D infLeftVpcToEc = new Transform3D();
+ private Transform3D infRightVpcToEc = new Transform3D();
+
+ // The current cached inverse viewing transforms.
+ private Transform3D leftEcToVpc = new Transform3D();
+ private Transform3D rightEcToVpc = new Transform3D();
+ private Transform3D infLeftEcToVpc = new Transform3D();
+ private Transform3D infRightEcToVpc = new Transform3D();
+
+ // Arrays of Vector4d objects that represent the plane equations for
+ // the 6 planes in the viewing frustum in ViewPlatform coordinates.
+ private Vector4d[] leftFrustumPlanes = new Vector4d[6];
+ private Vector4d[] rightFrustumPlanes = new Vector4d[6];
+
+ // Arrays of Vector4d objects that represent the volume of viewing frustum
+ private Point4d leftFrustumPoints[] = new Point4d[8];
+ private Point4d rightFrustumPoints[] = new Point4d[8];
+
+ // Calibration matrix from Screen object for HMD mode using
+ // non-field-sequential stereo
+
+ private Transform3D headTrackerToLeftImagePlate = new Transform3D();
+ private Transform3D headTrackerToRightImagePlate = new Transform3D();
+
+ // Head tracked version of eye in imageplate
+ private Point3d leftTrackedEyeInImagePlate = new Point3d();
+ private Point3d rightTrackedEyeInImagePlate = new Point3d();
+
+ // Derived version of eye in image plate coordinates
+ private Point3d leftEyeInImagePlate = new Point3d();
+ private Point3d rightEyeInImagePlate = new Point3d();
+ private Point3d centerEyeInImagePlate = new Point3d();
+
+ // Derived version of nominalEyeOffsetFromNominalScreen
+ private double nominalEyeOffset;
+
+ // Physical window position,size and center (in image plate coordinates)
+ private double physicalWindowXLeft;
+ private double physicalWindowYBottom;
+ private double physicalWindowXRight;
+ private double physicalWindowYTop;
+ private double physicalWindowWidth;
+ private double physicalWindowHeight;
+ private Point3d physicalWindowCenter = new Point3d();
+
+ // Screen scale value from viewCache or from screen size.
+ private double screenScale;
+
+ // Window scale value that compensates for window size if
+ // the window resize policy is PHYSICAL_WORLD.
+ private double windowScale;
+
+ // ViewPlatform scale that takes coordinates from view platform
+ // coordinates and scales them to physical coordinates
+ private double viewPlatformScale;
+
+ // Various derived transforms
+
+ private Transform3D leftCcToVworld = new Transform3D();
+ private Transform3D rightCcToVworld = new Transform3D();
+
+ private Transform3D coexistenceToLeftPlate = new Transform3D();
+ private Transform3D coexistenceToRightPlate = new Transform3D();
+
+ private Transform3D vpcToCoexistence = new Transform3D();
+
+ private Transform3D vpcToLeftPlate = new Transform3D();
+ private Transform3D vpcToRightPlate = new Transform3D();
+ private Transform3D leftPlateToVpc = new Transform3D();
+ private Transform3D rightPlateToVpc = new Transform3D();
+ private Transform3D vworldToLeftPlate = new Transform3D();
+ private Transform3D lastVworldToLeftPlate = new Transform3D();
+ private Transform3D vworldToRightPlate = new Transform3D();
+ private Transform3D leftPlateToVworld = new Transform3D();
+ private Transform3D rightPlateToVworld = new Transform3D();
+ private Transform3D headToLeftImagePlate = new Transform3D();
+ private Transform3D headToRightImagePlate = new Transform3D();
+
+ private Transform3D vworldToTrackerBase = new Transform3D();
+ private Transform3D tempTrans = new Transform3D();
+ private Transform3D headToVworld = new Transform3D();
+ private Vector3d coexistenceCenter = new Vector3d();
+
+ // scale for transformimg clip and fog distances
+ private double vworldToCoexistenceScale;
+ private double infVworldToCoexistenceScale;
+
+ //
+ // Temporary matrices and vectors, so we dont generate garbage
+ //
+ private Transform3D tMat1 = new Transform3D();
+ private Transform3D tMat2 = new Transform3D();
+ private Vector3d tVec1 = new Vector3d();
+ private Vector3d tVec2 = new Vector3d();
+ private Vector3d tVec3 = new Vector3d();
+ private Point3d tPnt1 = new Point3d();
+ private Point3d tPnt2 = new Point3d();
+
+ private Matrix4d tMatrix = new Matrix4d();
+
+ /**
+ * The view platform transforms.
+ */
+ private Transform3D vworldToVpc = new Transform3D();
+ private Transform3D vpcToVworld = new Transform3D();
+ private Transform3D infVworldToVpc = new Transform3D();
+
+ // This flag is used to remember the last time doInfinite flag
+ // is true or not.
+ // If this cache is updated twice, the first time in RenderBin
+ // updateViewCache() and the second time in Renderer with
+ // geometryBackground. The first time will reset the vcDirtyMask
+ // to 0 so that geometry background will not get updated the
+ // second time doComputeDerivedData() is invoked when view change.
+ private boolean lastDoInfinite = false;
+ private boolean updateLastTime = false;
+
+ void getCanvasPositionAndSize() {
+ if(J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2) {
+ System.err.println("Get canvas position and size");
+ System.err.println("Before");
+ System.err.println("Canvas pos = (" + awtCanvasX + ", " +
+ awtCanvasY + "), size = " + awtCanvasWidth +
+ "x" + awtCanvasHeight);
+ System.err.println("After");
+ }
+ awtCanvasX = canvas.newPosition.x;
+ awtCanvasY = canvas.newPosition.y;
+ awtCanvasWidth = canvas.newSize.width;
+ awtCanvasHeight = canvas.newSize.height;
+
+ // The following works around problem when awt creates 0-size
+ // window at startup
+ if ((awtCanvasWidth <= 0) || (awtCanvasHeight <= 0)) {
+ awtCanvasWidth = 1;
+ awtCanvasHeight = 1;
+ }
+
+ if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) {
+ System.err.println("Canvas pos = (" + awtCanvasX + ", " +
+ awtCanvasY + "), size = " + awtCanvasWidth +
+ "x" + awtCanvasHeight);
+ }
+ }
+
+ void computefrustumBBox(BoundingBox frustumBBox) {
+ int i;
+
+ for(i = 0; i < leftFrustumPoints.length; i++) {
+ if(frustumBBox.lower.x > leftFrustumPoints[i].x)
+ frustumBBox.lower.x = leftFrustumPoints[i].x;
+ if(frustumBBox.lower.y > leftFrustumPoints[i].y)
+ frustumBBox.lower.y = leftFrustumPoints[i].y;
+ if(frustumBBox.lower.z > leftFrustumPoints[i].z)
+ frustumBBox.lower.z = leftFrustumPoints[i].z;
+
+ if(frustumBBox.upper.x < leftFrustumPoints[i].x)
+ frustumBBox.upper.x = leftFrustumPoints[i].x;
+ if(frustumBBox.upper.y < leftFrustumPoints[i].y)
+ frustumBBox.upper.y = leftFrustumPoints[i].y;
+ if(frustumBBox.upper.z < leftFrustumPoints[i].z)
+ frustumBBox.upper.z = leftFrustumPoints[i].z;
+ }
+
+ if(useStereo) {
+
+ for(i = 0; i< rightFrustumPoints.length; i++) {
+ if(frustumBBox.lower.x > rightFrustumPoints[i].x)
+ frustumBBox.lower.x = rightFrustumPoints[i].x;
+ if(frustumBBox.lower.y > rightFrustumPoints[i].y)
+ frustumBBox.lower.y = rightFrustumPoints[i].y;
+ if(frustumBBox.lower.z > rightFrustumPoints[i].z)
+ frustumBBox.lower.z = rightFrustumPoints[i].z;
+
+ if(frustumBBox.upper.x < rightFrustumPoints[i].x)
+ frustumBBox.upper.x = rightFrustumPoints[i].x;
+ if(frustumBBox.upper.y < rightFrustumPoints[i].y)
+ frustumBBox.upper.y = rightFrustumPoints[i].y;
+ if(frustumBBox.upper.z < rightFrustumPoints[i].z)
+ frustumBBox.upper.z = rightFrustumPoints[i].z;
+ }
+
+ }
+ }
+
+
+ void copyComputedCanvasViewCache(CanvasViewCache cvc, boolean doInfinite) {
+ // For performance reason, only data needed by renderer are copied.
+ // useStereo,
+ // canvasWidth,
+ // canvasHeight,
+ // leftProjection,
+ // rightProjection,
+ // leftVpcToEc,
+ // rightVpcToEc,
+ // leftFrustumPlanes,
+ // rightFrustumPlanes,
+ // vpcToVworld,
+ // vworldToVpc.
+
+ cvc.useStereo = useStereo;
+ cvc.canvasWidth = canvasWidth;
+ cvc.canvasHeight = canvasHeight;
+ cvc.leftProjection.set(leftProjection);
+ cvc.rightProjection.set(rightProjection);
+ cvc.leftVpcToEc.set(leftVpcToEc) ;
+ cvc.rightVpcToEc.set(rightVpcToEc) ;
+
+ cvc.vpcToVworld = vpcToVworld;
+ cvc.vworldToVpc.set(vworldToVpc);
+
+ if (doInfinite) {
+ cvc.infLeftProjection.set(infLeftProjection);
+ cvc.infRightProjection.set(infRightProjection);
+ cvc.infLeftVpcToEc.set(infLeftVpcToEc) ;
+ cvc.infRightVpcToEc.set(infRightVpcToEc) ;
+ cvc.infVworldToVpc.set(infVworldToVpc);
+ }
+
+ for (int i = 0; i < leftFrustumPlanes.length; i++) {
+ cvc.leftFrustumPlanes[i].x = leftFrustumPlanes[i].x;
+ cvc.leftFrustumPlanes[i].y = leftFrustumPlanes[i].y;
+ cvc.leftFrustumPlanes[i].z = leftFrustumPlanes[i].z;
+ cvc.leftFrustumPlanes[i].w = leftFrustumPlanes[i].w;
+
+ cvc.rightFrustumPlanes[i].x = rightFrustumPlanes[i].x;
+ cvc.rightFrustumPlanes[i].y = rightFrustumPlanes[i].y;
+ cvc.rightFrustumPlanes[i].z = rightFrustumPlanes[i].z;
+ cvc.rightFrustumPlanes[i].w = rightFrustumPlanes[i].w;
+ }
+ }
+
+
+ /**
+ * Take snapshot of all per-canvas API parameters and input values.
+ * NOTE: This is probably not needed, but we'll do it for symmetry
+ * with the ScreenViewCache and ViewCache objects.
+ */
+ synchronized void snapshot(boolean computeFrustum) {
+ // Issue 109 : determine the the correct index to use -- either the
+ // Renderer or RenderBin
+ int dirtyIndex = computeFrustum ?
+ Canvas3D.RENDER_BIN_DIRTY_IDX : Canvas3D.RENDERER_DIRTY_IDX;
+
+ synchronized (canvas.dirtyMaskLock) {
+ // Issue 109 : read/clear the dirty bits for the correct index
+ cvcDirtyMask = canvas.cvDirtyMask[dirtyIndex];
+ canvas.cvDirtyMask[dirtyIndex] = 0;
+ }
+
+ useStereo = canvas.useStereo;
+ monoscopicViewPolicy = canvas.monoscopicViewPolicy;
+ leftManualEyeInImagePlate.set(canvas.leftManualEyeInImagePlate);
+ rightManualEyeInImagePlate.set(canvas.rightManualEyeInImagePlate);
+
+ if(( cvcDirtyMask & Canvas3D.MOVED_OR_RESIZED_DIRTY) != 0) {
+ getCanvasPositionAndSize();
+ }
+
+ renderBin = canvas.view.renderBin;
+
+ }
+
+ /**
+ * Compute derived data using the snapshot of the per-canvas,
+ * per-screen and per-view data.
+ */
+ synchronized void computeDerivedData(boolean currentFlag,
+ CanvasViewCache cvc, BoundingBox frustumBBox, boolean doInfinite) {
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
+ synchronized(debugLock) {
+ System.err.println("------------------------------");
+ doComputeDerivedData(currentFlag,cvc,frustumBBox,doInfinite);
+ }
+ }
+ else {
+ doComputeDerivedData(currentFlag,cvc,frustumBBox,doInfinite);
+ }
+ }
+
+ /**
+ * Compute derived data using the snapshot of the per-canvas,
+ * per-screen and per-view data. Caller must synchronize before
+ * calling this method.
+ */
+ private void doComputeDerivedData(boolean currentFlag,
+ CanvasViewCache cvc, BoundingBox frustumBBox, boolean doInfinite) {
+
+ // Issue 109 : determine the the correct index to use -- either the
+ // Renderer or RenderBin
+ int dirtyIndex = (frustumBBox != null) ?
+ Canvas3D.RENDER_BIN_DIRTY_IDX : Canvas3D.RENDERER_DIRTY_IDX;
+ int scrvcDirtyMask;
+
+ // Issue 109 : read/clear the dirty bits for the correct index
+ synchronized (screenViewCache) {
+ scrvcDirtyMask = screenViewCache.scrvcDirtyMask[dirtyIndex];
+ // reset screen view dirty mask if canvas is offScreen. Note:
+ // there is only one canvas per offscreen, so it is ok to
+ // do the reset here.
+ if (canvas.offScreen) {
+ screenViewCache.scrvcDirtyMask[dirtyIndex] = 0;
+ }
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ if(cvcDirtyMask != 0)
+ System.err.println("cvcDirtyMask : " + cvcDirtyMask);
+
+ if(scrvcDirtyMask != 0)
+ System.err.println("scrvcDirtyMask : "+ scrvcDirtyMask);
+
+ if(viewCache.vcDirtyMask != 0)
+ System.err.println("vcDirtyMask : " + viewCache.vcDirtyMask);
+ }
+
+
+ // NOTE: This fix is only fixing the symptoms, but not the
+ // root of the bug. We shouldn't have to check for null here.
+ if(viewCache.vpRetained == null) {
+ System.err.println("CanvasViewCache : Error! viewCache.vpRetained is null");
+ return;
+ }
+
+ // This flag is use to force a computation when a ViewPlatformTransform
+ // is detected. No sync. needed. We're doing a read of t/f.
+ // XXXX: Peeking at the dirty flag is a hack. Need to revisit this.
+ boolean vprNotDirty = (viewCache.vpRetained.vprDirtyMask == 0);
+
+ // Issue 131: If not manual, it has to be considered as an onscreen canvas.
+ if(!canvas.manualRendering &&
+ (vprNotDirty) &&
+ (cvcDirtyMask == 0) &&
+ (scrvcDirtyMask == 0) &&
+ (viewCache.vcDirtyMask == 0) &&
+ !(updateLastTime && (doInfinite != lastDoInfinite))) {
+ if(frustumBBox != null)
+ computefrustumBBox(frustumBBox);
+
+ // Copy the computed data into cvc.
+ if(cvc != null) {
+ copyComputedCanvasViewCache(cvc, doInfinite);
+ }
+ lastDoInfinite = doInfinite;
+ updateLastTime = false;
+ return;
+ }
+
+ lastDoInfinite = doInfinite;
+ updateLastTime = true;
+
+ if(currentFlag) {
+ vpcToVworld.set(viewCache.vpRetained.getCurrentLocalToVworld(null));
+ }
+ else {
+ vpcToVworld.set(viewCache.vpRetained.getLastLocalToVworld(null));
+ }
+
+ // System.err.println("vpcToVworld is \n" + vpcToVworld);
+
+ try {
+ vworldToVpc.invert(vpcToVworld);
+ }
+ catch (SingularMatrixException e) {
+ vworldToVpc.setIdentity();
+ //System.err.println("SingularMatrixException encountered when doing vworldToVpc invert");
+ }
+ if (doInfinite) {
+ vworldToVpc.getRotation(infVworldToVpc);
+ }
+
+ // Compute global flags
+ if (monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW)
+ effectiveMonoscopicViewPolicy = viewCache.monoscopicViewPolicy;
+ else
+ effectiveMonoscopicViewPolicy = monoscopicViewPolicy;
+
+ // Recompute info about current canvas window
+ computeCanvasInfo();
+
+ // Compute coexistence center (in plate coordinates)
+ computeCoexistenceCenter();
+
+ // Get Eye position in image-plate coordinates
+ cacheEyePosition();
+
+ // Compute VPC to COE and COE to PLATE transforms
+ computeVpcToCoexistence();
+ computeCoexistenceToPlate();
+
+ // Compute view and projection matrices
+ computeView(doInfinite);
+
+
+ computePlateToVworld();
+
+ if (!currentFlag) {
+ // save the result for use in RasterRetained computeWinCoord
+ lastVworldToLeftPlate.set(vworldToLeftPlate);
+ }
+ computeHeadToVworld();
+
+ if (frustumBBox != null)
+ computefrustumBBox(frustumBBox);
+
+ // Issue 109: cvc should *always* be null
+ assert cvc == null;
+ if(cvc != null)
+ copyComputedCanvasViewCache(cvc, doInfinite);
+
+ canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY;
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
+ // Print some data :
+ System.err.println("useStereo = " + useStereo);
+ System.err.println("leftProjection:\n" + leftProjection);
+ System.err.println("rightProjection:\n " + rightProjection);
+ System.err.println("leftVpcToEc:\n" + leftVpcToEc);
+ System.err.println("rightVpcToEc:\n" + rightVpcToEc);
+ System.err.println("vpcToVworld:\n" + vpcToVworld);
+ System.err.println("vworldToVpc:\n" + vworldToVpc);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ int i;
+ for (i = 0; i < leftFrustumPlanes.length; i++) {
+ System.err.println("leftFrustumPlanes " + i + " is " +
+ leftFrustumPlanes[i]);
+ }
+
+ for (i = 0; i < rightFrustumPlanes.length; i++) {
+ System.err.println("rightFrustumPlanes " + i + " is " +
+ rightFrustumPlanes[i]);
+ }
+ }
+ }
+
+ }
+
+ private void computeCanvasInfo() {
+ // Copy the screen width and height info into derived parameters
+ physicalScreenWidth = screenViewCache.physicalScreenWidth;
+ physicalScreenHeight = screenViewCache.physicalScreenHeight;
+
+ screenWidth = screenViewCache.screenWidth;
+ screenHeight = screenViewCache.screenHeight;
+
+ metersPerPixelX = screenViewCache.metersPerPixelX;
+ metersPerPixelY = screenViewCache.metersPerPixelY;
+
+ // If a multi-screen virtual device (e.g. Xinerama) is being used,
+ // then awtCanvasX and awtCanvasY are relative to the origin of that
+ // virtual screen. Subtract the origin of the physical screen to
+ // compute the origin in physical (image plate) coordinates.
+ Rectangle screenBounds = canvas.graphicsConfiguration.getBounds();
+ canvasX = awtCanvasX - screenBounds.x;
+ canvasY = awtCanvasY - screenBounds.y;
+
+ // Use awtCanvasWidth and awtCanvasHeight as reported.
+ canvasWidth = awtCanvasWidth;
+ canvasHeight = awtCanvasHeight;
+
+ // Convert the window system ``pixel'' coordinate location and size
+ // of the window into physical units (meters) and coordinate system.
+
+ // Window width and Height in meters
+ physicalWindowWidth = canvasWidth * metersPerPixelX;
+ physicalWindowHeight = canvasHeight * metersPerPixelY;
+
+ // Compute the 4 corners of the window in physical units
+ physicalWindowXLeft = metersPerPixelX *
+ (double) canvasX;
+ physicalWindowYBottom = metersPerPixelY *
+ (double)(screenHeight - canvasHeight - canvasY);
+
+ physicalWindowXRight = physicalWindowXLeft + physicalWindowWidth;
+ physicalWindowYTop = physicalWindowYBottom + physicalWindowHeight;
+
+ // Cache the physical location of the center of the window
+ physicalWindowCenter.x =
+ physicalWindowXLeft + physicalWindowWidth / 2.0;
+ physicalWindowCenter.y =
+ physicalWindowYBottom + physicalWindowHeight / 2.0;
+ physicalWindowCenter.z = 0.0;
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("Canvas pos = (" + awtCanvasX + ", " +
+ awtCanvasY + "), size = " + awtCanvasWidth +
+ "x" + awtCanvasHeight);
+
+ System.err.println("Window LL corner (in plate coordinates): " +
+ "(" + physicalWindowXLeft + "," + physicalWindowYBottom + ")");
+
+ System.err.println("Window size (in plate coordinates): " +
+ "(" + physicalWindowWidth + "," + physicalWindowHeight + ")");
+
+ System.err.println("Window center (in plate coordinates): " +
+ physicalWindowCenter);
+
+ System.err.println();
+ }
+
+ // Compute the view platform scale. This combines
+ // the screen scale and the window scale.
+ computeViewPlatformScale();
+
+ if (!viewCache.compatibilityModeEnable &&
+ viewCache.viewPolicy == View.HMD_VIEW) {
+ if (!useStereo) {
+ switch(effectiveMonoscopicViewPolicy) {
+ case View.CYCLOPEAN_EYE_VIEW:
+ if(J3dDebug.devPhase) {
+ System.err.println("CanvasViewCache : Should never reach here.\n" +
+ "HMD_VIEW with CYCLOPEAN_EYE_VIEW is not allowed");
+ }
+ break;
+
+ case View.LEFT_EYE_VIEW:
+ headTrackerToLeftImagePlate.set(screenViewCache.
+ headTrackerToLeftImagePlate);
+ break;
+
+ case View.RIGHT_EYE_VIEW:
+ headTrackerToLeftImagePlate.set(screenViewCache.
+ headTrackerToRightImagePlate);
+ break;
+ }
+ }
+ else {
+ headTrackerToLeftImagePlate.set(screenViewCache.
+ headTrackerToLeftImagePlate);
+
+ headTrackerToRightImagePlate.set(screenViewCache.
+ headTrackerToRightImagePlate);
+ }
+
+ }
+ }
+
+ // Routine to compute the center of coexistence coordinates in
+ // imageplate coordinates. Also compute the scale from Vpc
+ private void computeViewPlatformScale() {
+ windowScale = screenScale = 1.0;
+
+ if (!viewCache.compatibilityModeEnable) {
+ switch (viewCache.screenScalePolicy) {
+ case View.SCALE_SCREEN_SIZE:
+ screenScale = physicalScreenWidth / 2.0;
+ break;
+ case View.SCALE_EXPLICIT:
+ screenScale = viewCache.screenScale;
+ break;
+ }
+
+ if (viewCache.windowResizePolicy == View.PHYSICAL_WORLD) {
+ windowScale = physicalWindowWidth / physicalScreenWidth;
+ }
+ }
+
+ viewPlatformScale = windowScale * screenScale;
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("viewCache.windowResizePolicy = " +
+ viewCache.windowResizePolicy);
+ System.err.println("physicalWindowWidth = " + physicalWindowWidth);
+ System.err.println("physicalScreenWidth = " + physicalScreenWidth);
+ System.err.println("windowScale = " + windowScale);
+ System.err.println("screenScale = " + screenScale);
+ System.err.println("viewPlatformScale = " + viewPlatformScale);
+ }
+ }
+
+ private void cacheEyePosFixedField() {
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
+ System.err.println("cacheEyePosFixedField:");
+
+ // y is always the window center
+ rightEyeInImagePlate.y =
+ leftEyeInImagePlate.y =
+ physicalWindowCenter.y;
+
+ if (!useStereo) {
+ switch(effectiveMonoscopicViewPolicy) {
+ case View.CYCLOPEAN_EYE_VIEW:
+ leftEyeInImagePlate.x = physicalWindowCenter.x;
+ break;
+
+ case View.LEFT_EYE_VIEW:
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x + viewCache.leftEyePosInHead.x;
+ break;
+
+ case View.RIGHT_EYE_VIEW:
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x + viewCache.rightEyePosInHead.x;
+ break;
+ }
+
+ // Set right as well just in case
+ rightEyeInImagePlate.x = leftEyeInImagePlate.x;
+ }
+ else {
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x + viewCache.leftEyePosInHead.x;
+
+ rightEyeInImagePlate.x =
+ physicalWindowCenter.x + viewCache.rightEyePosInHead.x;
+ }
+
+ //
+ // Derive the z distance by constraining the field of view of the
+ // window width to be constant.
+ //
+ rightEyeInImagePlate.z =
+ leftEyeInImagePlate.z =
+ physicalWindowWidth /
+ (2.0 * Math.tan(viewCache.fieldOfView / 2.0));
+
+ // Denote that eyes-in-ImagePlate fields have changed so that
+ // these new values can be sent to the AudioDevice
+ if (this.viewCache.view.soundScheduler != null)
+ this.viewCache.view.soundScheduler.setListenerFlag(
+ SoundScheduler.EYE_POSITIONS_CHANGED);
+ }
+
+ /**
+ * Case of view eye position contrainted to center of window, but
+ * with z distance from plate eye pos.
+ */
+ private void cacheEyePosWindowRelative() {
+
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
+ System.err.println("cacheEyePosWindowRelative:");
+
+ // y is always the window center
+ rightEyeInImagePlate.y =
+ leftEyeInImagePlate.y =
+ physicalWindowCenter.y;
+
+ // z is always from the existing eye pos
+ rightEyeInImagePlate.z =
+ leftEyeInImagePlate.z =
+ leftManualEyeInImagePlate.z;
+
+ if (!useStereo) {
+
+ switch(effectiveMonoscopicViewPolicy) {
+
+ case View.CYCLOPEAN_EYE_VIEW:
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x;
+ break;
+
+ case View.LEFT_EYE_VIEW:
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x +
+ viewCache.leftEyePosInHead.x;
+ break;
+
+ case View.RIGHT_EYE_VIEW:
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x +
+ viewCache.rightEyePosInHead.x;
+ break;
+
+ }
+
+ // Set right as well just in case
+ rightEyeInImagePlate.x =
+ leftEyeInImagePlate.x;
+
+ }
+ else {
+
+ leftEyeInImagePlate.x =
+ physicalWindowCenter.x +
+ viewCache.leftEyePosInHead.x;
+
+ rightEyeInImagePlate.x =
+ physicalWindowCenter.x +
+ viewCache.rightEyePosInHead.x;
+
+ // Right z gets its own value
+ rightEyeInImagePlate.z =
+ rightManualEyeInImagePlate.z;
+ }
+
+ // Denote that eyes-in-ImagePlate fields have changed so that
+ // these new values can be sent to the AudioDevice
+ if (this.viewCache.view.soundScheduler != null)
+ this.viewCache.view.soundScheduler.setListenerFlag(
+ SoundScheduler.EYE_POSITIONS_CHANGED);
+ }
+
+ /**
+ * Common routine used when head tracking and when using manual
+ * relative_to_screen eyepoint policy.
+ */
+ private void cacheEyePosScreenRelative(Point3d leftEye, Point3d rightEye) {
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
+ System.err.println("cacheEyePosScreenRelative:");
+
+ if (!useStereo) {
+ switch(effectiveMonoscopicViewPolicy) {
+
+ case View.CYCLOPEAN_EYE_VIEW:
+ leftEyeInImagePlate.x = (leftEye.x + rightEye.x) / 2.0;
+ leftEyeInImagePlate.y = (leftEye.y + rightEye.y) / 2.0;
+ leftEyeInImagePlate.z = (leftEye.z + rightEye.z) / 2.0;
+ break;
+
+ case View.LEFT_EYE_VIEW:
+ leftEyeInImagePlate.set(leftEye);
+ break;
+
+ case View.RIGHT_EYE_VIEW:
+ leftEyeInImagePlate.set(rightEye);
+ break;
+
+ }
+
+ // Set right as well just in case
+ rightEyeInImagePlate.set(leftEyeInImagePlate);
+ }
+ else {
+ leftEyeInImagePlate.set(leftEye);
+ rightEyeInImagePlate.set(rightEye);
+ }
+
+ // Denote that eyes-in-ImagePlate fields have changed so that
+ // these new values can be sent to the AudioDevice
+ if (this.viewCache.view.soundScheduler != null)
+ this.viewCache.view.soundScheduler.setListenerFlag(
+ SoundScheduler.EYE_POSITIONS_CHANGED);
+ }
+
+ private void cacheEyePosCoexistenceRelative(Point3d leftManualEyeInCoexistence,
+ Point3d rightManualEyeInCoexistence) {
+
+ tPnt1.set(leftManualEyeInCoexistence);
+ viewCache.coexistenceToTrackerBase.transform(tPnt1);
+ screenViewCache.trackerBaseToImagePlate.transform(tPnt1);
+ tPnt1.add(coexistenceCenter);
+
+ tPnt2.set(rightManualEyeInCoexistence);
+ viewCache.coexistenceToTrackerBase.transform(tPnt2);
+ screenViewCache.trackerBaseToImagePlate.transform(tPnt2);
+ tPnt2.add(coexistenceCenter);
+
+ cacheEyePosScreenRelative(tPnt1, tPnt2);
+
+ }
+
+ /**
+ * Compute the head-tracked eye position for the right and
+ * left eyes.
+ */
+ private void computeTrackedEyePosition() {
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("computeTrackedEyePosition:");
+ System.err.println("viewCache.headTrackerToTrackerBase:");
+ System.err.println(viewCache.headTrackerToTrackerBase);
+
+ System.err.println("viewCache.headToHeadTracker:");
+ System.err.println(viewCache.headToHeadTracker);
+ }
+
+ if (viewCache.viewPolicy != View.HMD_VIEW) {
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("screenViewCache.trackerBaseToImagePlate:");
+ System.err.println(screenViewCache.trackerBaseToImagePlate);
+ }
+
+ headToLeftImagePlate.set(coexistenceCenter);
+ headToLeftImagePlate.mul(screenViewCache.trackerBaseToImagePlate);
+ headToLeftImagePlate.mul(viewCache.headTrackerToTrackerBase);
+ headToLeftImagePlate.mul(viewCache.headToHeadTracker);
+
+ headToLeftImagePlate.transform(viewCache.leftEyePosInHead,
+ leftTrackedEyeInImagePlate);
+
+ headToLeftImagePlate.transform(viewCache.rightEyePosInHead,
+ rightTrackedEyeInImagePlate);
+ }
+ else {
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("headTrackerToLeftImagePlate:");
+ System.err.println(headTrackerToLeftImagePlate);
+ }
+
+ headToLeftImagePlate.mul(headTrackerToLeftImagePlate,
+ viewCache.headToHeadTracker);
+
+ headToLeftImagePlate.transform(viewCache.leftEyePosInHead,
+ leftTrackedEyeInImagePlate);
+
+ if(useStereo) {
+ headToRightImagePlate.mul(headTrackerToRightImagePlate,
+ viewCache.headToHeadTracker);
+
+ headToRightImagePlate.transform(viewCache.rightEyePosInHead,
+ rightTrackedEyeInImagePlate);
+ }
+ else { // HMD_VIEW with no stereo.
+ headToLeftImagePlate.transform(viewCache.rightEyePosInHead,
+ rightTrackedEyeInImagePlate);
+ }
+
+ }
+
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("headToLeftImagePlate:");
+ System.err.println(headToLeftImagePlate);
+ System.err.println("headToRightImagePlate:");
+ System.err.println(headToRightImagePlate);
+
+ }
+ }
+
+ /**
+ * Routine to cache the current eye position in image plate
+ * coordinates.
+ */
+ private void cacheEyePosition() {
+ if (viewCache.compatibilityModeEnable) {
+ // XXXX: Compute compatibility mode eye position in ImagePlate???
+ cacheEyePosScreenRelative(leftManualEyeInImagePlate,
+ rightManualEyeInImagePlate);
+ }
+ else if (viewCache.getDoHeadTracking()) {
+ computeTrackedEyePosition();
+ cacheEyePosScreenRelative(leftTrackedEyeInImagePlate,
+ rightTrackedEyeInImagePlate);
+ }
+ else {
+ switch (viewCache.windowEyepointPolicy) {
+
+ case View.RELATIVE_TO_FIELD_OF_VIEW:
+ cacheEyePosFixedField();
+ break;
+
+ case View.RELATIVE_TO_WINDOW:
+ cacheEyePosWindowRelative();
+ break;
+
+ case View.RELATIVE_TO_SCREEN:
+ cacheEyePosScreenRelative(leftManualEyeInImagePlate,
+ rightManualEyeInImagePlate);
+ break;
+
+ case View.RELATIVE_TO_COEXISTENCE:
+ cacheEyePosCoexistenceRelative(viewCache.leftManualEyeInCoexistence,
+ viewCache.rightManualEyeInCoexistence);
+ break;
+ }
+ }
+
+ // Compute center eye
+ centerEyeInImagePlate.add(leftEyeInImagePlate, rightEyeInImagePlate);
+ centerEyeInImagePlate.scale(0.5);
+
+ // Compute derived value of nominalEyeOffsetFromNominalScreen
+ if (viewCache.windowEyepointPolicy == View.RELATIVE_TO_FIELD_OF_VIEW)
+ nominalEyeOffset = centerEyeInImagePlate.z;
+ else
+ nominalEyeOffset = viewCache.nominalEyeOffsetFromNominalScreen;
+
+ if ((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
+ System.err.println("leftEyeInImagePlate = " +
+ leftEyeInImagePlate);
+ System.err.println("rightEyeInImagePlate = " +
+ rightEyeInImagePlate);
+ System.err.println("centerEyeInImagePlate = " +
+ centerEyeInImagePlate);
+ System.err.println("nominalEyeOffset = " +
+ nominalEyeOffset);
+ System.err.println();
+ }
+ }
+
+ private void computePlateToVworld() {
+ if (viewCache.compatibilityModeEnable) {
+ // XXXX: implement this correctly for compat mode
+ leftPlateToVworld.setIdentity();
+ vworldToLeftPlate.setIdentity();
+ }
+ else {
+ try {
+ leftPlateToVpc.invert(vpcToLeftPlate);
+ }
+ catch (SingularMatrixException e) {
+ leftPlateToVpc.setIdentity();
+ /*
+ System.err.println("SingularMatrixException encountered when doing" +
+ " leftPlateToVpc invert");
+ */
+ }
+
+ leftPlateToVworld.mul(vpcToVworld, leftPlateToVpc);
+ vworldToLeftPlate.mul(vpcToLeftPlate, vworldToVpc);
+
+ if(useStereo) {
+ try {
+ rightPlateToVpc.invert(vpcToRightPlate);
+ }
+ catch (SingularMatrixException e) {
+ rightPlateToVpc.setIdentity();
+ /*
+ System.err.println("SingularMatrixException encountered when doing" +
+ " rightPlateToVpc invert");
+ */
+ }
+
+ rightPlateToVworld.mul(vpcToVworld, rightPlateToVpc);
+ vworldToRightPlate.mul(vpcToRightPlate, vworldToVpc);
+
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("vpcToVworld:");
+ System.err.println(vpcToVworld);
+ System.err.println("vpcToLeftPlate:");
+ System.err.println(vpcToLeftPlate);
+ if(useStereo) {
+ System.err.println("vpcToRightPlate:");
+ System.err.println(vpcToRightPlate);
+
+ }
+
+ }
+ }
+
+ // Denote that eyes-in-ImagePlate fields have changed so that
+ // these new values can be sent to the AudioDevice
+ if (this.viewCache.view.soundScheduler != null)
+ this.viewCache.view.soundScheduler.setListenerFlag(
+ SoundScheduler.IMAGE_PLATE_TO_VWORLD_CHANGED);
+ }
+
+
+ private void computeHeadToVworld() {
+ // Concatenate headToLeftImagePlate with leftPlateToVworld
+
+ if (viewCache.compatibilityModeEnable) {
+ // XXXX: implement this correctly for compat mode
+ headToVworld.setIdentity();
+ }
+ else {
+ headToVworld.mul(leftPlateToVworld, headToLeftImagePlate);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("leftPlateToVworld:");
+ System.err.println(leftPlateToVworld);
+ System.err.println("headToLeftImagePlate:");
+ System.err.println(headToLeftImagePlate);
+ System.err.println("...gives -> headToVworld:");
+ System.err.println(headToVworld);
+ }
+ }
+
+ // Denote that eyes-in-ImagePlate fields have changed so that
+ // these new values can be sent to the AudioDevice
+ if (this.viewCache.view.soundScheduler != null)
+ this.viewCache.view.soundScheduler.setListenerFlag(
+ SoundScheduler.HEAD_TO_VWORLD_CHANGED);
+ }
+
+ private void computeVpcToCoexistence() {
+ // Create a transform with the view platform to coexistence scale
+ tMat1.set(viewPlatformScale);
+
+ // XXXX: Is this really correct to ignore HMD?
+
+ if (viewCache.viewPolicy != View.HMD_VIEW) {
+ switch (viewCache.coexistenceCenterInPworldPolicy) {
+ case View.NOMINAL_SCREEN :
+ switch (viewCache.viewAttachPolicy) {
+ case View.NOMINAL_SCREEN:
+ tMat2.setIdentity();
+ break;
+ case View.NOMINAL_HEAD:
+ tVec1.set(0.0, 0.0, nominalEyeOffset);
+ tMat2.set(tVec1);
+ break;
+ case View.NOMINAL_FEET:
+ tVec1.set(0.0, -viewCache.nominalEyeHeightFromGround,
+ nominalEyeOffset);
+ tMat2.set(tVec1);
+ break;
+ }
+
+ break;
+ case View.NOMINAL_HEAD :
+ switch (viewCache.viewAttachPolicy) {
+ case View.NOMINAL_SCREEN:
+ tVec1.set(0.0, 0.0, -nominalEyeOffset);
+ tMat2.set(tVec1);
+ break;
+ case View.NOMINAL_HEAD:
+ tMat2.setIdentity();
+ break;
+ case View.NOMINAL_FEET:
+ tVec1.set(0.0, -viewCache.nominalEyeHeightFromGround,
+ 0.0);
+ tMat2.set(tVec1);
+ break;
+ }
+ break;
+ case View.NOMINAL_FEET:
+ switch (viewCache.viewAttachPolicy) {
+ case View.NOMINAL_SCREEN:
+ tVec1.set(0.0,
+ viewCache.nominalEyeHeightFromGround, -nominalEyeOffset);
+ tMat2.set(tVec1);
+ break;
+ case View.NOMINAL_HEAD:
+ tVec1.set(0.0, viewCache.nominalEyeHeightFromGround,
+ 0.0);
+ tMat2.set(tVec1);
+
+ break;
+ case View.NOMINAL_FEET:
+ tMat2.setIdentity();
+ break;
+ }
+ break;
+ }
+
+ vpcToCoexistence.mul(tMat2, tMat1);
+ }
+ else {
+ vpcToCoexistence.set(tMat1);
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("vpcToCoexistence:");
+ System.err.println(vpcToCoexistence);
+ }
+ }
+
+ private void computeCoexistenceCenter() {
+
+ if ((!viewCache.compatibilityModeEnable) &&
+ (viewCache.viewPolicy != View.HMD_VIEW) &&
+ (viewCache.coexistenceCenteringEnable) &&
+ (viewCache.coexistenceCenterInPworldPolicy == View.NOMINAL_SCREEN)) {
+
+ // Compute the coexistence center in image plate coordinates
+
+ // Image plate cordinates have their orgin in the lower
+ // left hand corner of the CRT visiable raster.
+ // The nominal coexistence center is at the *center* of
+ // targeted area: either the window or screen, depending
+ // on policy.
+ if (viewCache.windowMovementPolicy == View.VIRTUAL_WORLD) {
+ coexistenceCenter.x = physicalScreenWidth / 2.0;
+ coexistenceCenter.y = physicalScreenHeight / 2.0;
+ coexistenceCenter.z = 0.0;
+ }
+ else { // windowMovementPolicy == PHYSICAL_WORLD
+ coexistenceCenter.x = physicalWindowCenter.x;
+ coexistenceCenter.y = physicalWindowCenter.y;
+ coexistenceCenter.z = 0.0;
+ }
+ }
+ else {
+ coexistenceCenter.set(0.0, 0.0, 0.0);
+ }
+
+ if(J3dDebug.devPhase) {
+ if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) {
+ System.err.println("coexistenceCenter = " + coexistenceCenter);
+ }
+ }
+ }
+
+ private void computeCoexistenceToPlate() {
+ if (viewCache.compatibilityModeEnable) {
+ // XXXX: implement this correctly
+ coexistenceToLeftPlate.setIdentity();
+ return;
+ }
+
+ if (viewCache.viewPolicy != View.HMD_VIEW) {
+ coexistenceToLeftPlate.set(coexistenceCenter);
+ coexistenceToLeftPlate.mul(screenViewCache.trackerBaseToImagePlate);
+ coexistenceToLeftPlate.mul(viewCache.coexistenceToTrackerBase);
+
+ if(useStereo) {
+ coexistenceToRightPlate.set(coexistenceToLeftPlate);
+ }
+ }
+ else {
+ coexistenceToLeftPlate.mul(headTrackerToLeftImagePlate,
+ viewCache.trackerBaseToHeadTracker);
+ coexistenceToLeftPlate.mul(viewCache.coexistenceToTrackerBase);
+
+ if(useStereo) {
+ coexistenceToRightPlate.mul(headTrackerToRightImagePlate,
+ viewCache.trackerBaseToHeadTracker);
+ coexistenceToRightPlate.mul(viewCache.coexistenceToTrackerBase);
+ }
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("coexistenceToLeftPlate:");
+ System.err.println(coexistenceToLeftPlate);
+ if(useStereo) {
+ System.err.println("coexistenceToRightPlate:");
+ System.err.println(coexistenceToRightPlate);
+
+ }
+ }
+ }
+
+ /**
+ * Computes the viewing matrices.
+ *
+ * computeView computes the following:
+ *
+ * <ul>
+ * left (& right) eye viewing matrices (only left is valid for mono view)
+ * </ul>
+ *
+ * This call works for both fixed screen and HMD displays.
+ */
+ private void computeView(boolean doInfinite) {
+ int backClipPolicy;
+ double Fl, Fr, B, scale, backClipDistance;
+
+ // compute scale used for transforming clip and fog distances
+ vworldToCoexistenceScale = vworldToVpc.getDistanceScale()
+ * vpcToCoexistence.getDistanceScale();
+ if(doInfinite) {
+ infVworldToCoexistenceScale = infVworldToVpc.getDistanceScale()
+ * vpcToCoexistence.getDistanceScale();
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("vworldToCoexistenceScale = " +
+ vworldToCoexistenceScale);
+ }
+
+ // compute coexistenceToVworld transform -- dirty bit candidate!!
+ tempTrans.mul(viewCache.coexistenceToTrackerBase, vpcToCoexistence);
+ vworldToTrackerBase.mul(tempTrans, vworldToVpc);
+
+ // If we are in compatibility mode, compute the view and
+ // projection matrices accordingly
+ if (viewCache.compatibilityModeEnable) {
+ leftProjection.set(viewCache.compatLeftProjection);
+ leftVpcToEc.set(viewCache.compatVpcToEc);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
+ System.err.println("Left projection and view matrices");
+ System.err.println("ecToCc (leftProjection) :");
+ System.err.println(leftProjection);
+ System.err.println("vpcToEc:");
+ System.err.println(leftVpcToEc);
+ }
+
+ computeFrustumPlanes(leftProjection, leftVpcToEc,
+ leftFrustumPlanes, leftFrustumPoints,
+ leftCcToVworld);
+
+ if(useStereo) {
+ rightProjection.set(viewCache.compatRightProjection);
+ rightVpcToEc.set(viewCache.compatVpcToEc);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
+ System.err.println("Right projection and view matrices");
+ System.err.println("ecToCc:");
+ System.err.println("vpcToEc:");
+ System.err.println(rightVpcToEc);
+ }
+
+ computeFrustumPlanes(rightProjection, rightVpcToEc,
+ rightFrustumPlanes, rightFrustumPoints,
+ rightCcToVworld);
+ }
+
+ return;
+ }
+
+ //
+ // The clipping plane distances are set from the internal policy.
+ //
+ // Note that the plane distance follows the standard Z axis
+ // convention, e.g. negative numbers further away.
+ // Note that for policy from eye, the distance is negative in
+ // the direction of z in front of the eye.
+ // Note that for policy from screen, the distance is negative for
+ // locations behind the screen, and positive in front.
+ //
+ // The distance attributes are measured either in physical (plate)
+ // units, or vworld units.
+ //
+
+ // Compute scale factor for front clip plane computation
+ if (viewCache.frontClipPolicy == View.VIRTUAL_EYE ||
+ viewCache.frontClipPolicy == View.VIRTUAL_SCREEN) {
+ scale = vworldToCoexistenceScale;
+ }
+ else {
+ scale = windowScale;
+ }
+
+ // Set left and right front clipping plane distances.
+ if(viewCache.frontClipPolicy == View.PHYSICAL_EYE ||
+ viewCache.frontClipPolicy == View.VIRTUAL_EYE) {
+ Fl = leftEyeInImagePlate.z +
+ scale * -viewCache.frontClipDistance;
+ Fr = rightEyeInImagePlate.z +
+ scale * -viewCache.frontClipDistance;
+ }
+ else {
+ Fl = scale * -viewCache.frontClipDistance;
+ Fr = scale * -viewCache.frontClipDistance;
+ }
+
+ // if there is an active clip node, use it and ignore the view's
+ // backclip
+ if ((renderBin != null) && (renderBin.backClipActive)) {
+ backClipPolicy = View.VIRTUAL_EYE;
+ backClipDistance = renderBin.backClipDistanceInVworld;
+ } else {
+ backClipPolicy = viewCache.backClipPolicy;
+ backClipDistance = viewCache.backClipDistance;
+ }
+
+ // Compute scale factor for rear clip plane computation
+ if (backClipPolicy == View.VIRTUAL_EYE ||
+ backClipPolicy == View.VIRTUAL_SCREEN) {
+ scale = vworldToCoexistenceScale;
+ }
+ else {
+ scale = windowScale;
+ }
+
+ // Set left and right rear clipping plane distnaces.
+ if(backClipPolicy == View.PHYSICAL_EYE ||
+ backClipPolicy == View.VIRTUAL_EYE) {
+ // Yes, left for both left and right rear.
+ B = leftEyeInImagePlate.z +
+ scale * -backClipDistance;
+ }
+ else {
+ B = scale * -backClipDistance;
+ }
+
+ // XXXX: Can optimize for HMD case.
+ if (true /*viewCache.viewPolicy != View.HMD_VIEW*/) {
+
+ // Call buildProjView to build the projection and view matrices.
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("Left projection and view matrices");
+ System.err.println("Fl " + Fl + " B " + B);
+ System.err.println("leftEyeInImagePlate\n" + leftEyeInImagePlate);
+ System.err.println("Before : leftProjection\n" + leftProjection);
+ System.err.println("Before leftVpcToEc\n" + leftVpcToEc);
+ }
+
+ buildProjView(leftEyeInImagePlate, coexistenceToLeftPlate,
+ vpcToLeftPlate, Fl, B, leftProjection, leftVpcToEc, false);
+
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("After : leftProjection\n" + leftProjection);
+ System.err.println("After leftVpcToEc\n" + leftVpcToEc);
+ }
+
+ computeFrustumPlanes(leftProjection, leftVpcToEc,
+ leftFrustumPlanes, leftFrustumPoints,
+ leftCcToVworld);
+
+ if(useStereo) {
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2))
+ System.err.println("Right projection and view matrices");
+
+ buildProjView(rightEyeInImagePlate, coexistenceToRightPlate,
+ vpcToRightPlate, Fr, B, rightProjection,
+ rightVpcToEc, false);
+
+ computeFrustumPlanes(rightProjection, rightVpcToEc,
+ rightFrustumPlanes, rightFrustumPoints,
+ rightCcToVworld);
+ }
+
+ //
+ // Now to compute the left (& right) eye (and infinite)
+ // viewing matrices.
+ if(doInfinite) {
+ // Call buildProjView separately for infinite view
+ buildProjView(leftEyeInImagePlate, coexistenceToLeftPlate,
+ vpcToLeftPlate, leftEyeInImagePlate.z - 0.05,
+ leftEyeInImagePlate.z - 1.5,
+ infLeftProjection, infLeftVpcToEc, true);
+
+ if(useStereo) {
+ buildProjView(rightEyeInImagePlate, coexistenceToRightPlate,
+ vpcToRightPlate, rightEyeInImagePlate.z - 0.05,
+ rightEyeInImagePlate.z - 1.5,
+ infRightProjection, infRightVpcToEc, true);
+
+ }
+ }
+ }
+ // XXXX: The following code has never been ported
+// else {
+// Point3d cen_eye;
+//
+// // HMD case. Just concatenate the approprate matrices together.
+// // Additional work just for now
+//
+// compute_lr_plate_to_cc( &cen_eye, Fl, B, 0, &vb, 0);
+//
+// if(useStereo) {
+// mat_mul_dpt(&right_eye_pos_in_head,
+// head_to_right_plate, &cen_eye);
+// compute_lr_plate_to_cc( &cen_eye, Fr, B,
+// 1, &vb, 0);
+// }
+//
+// // Make sure that coexistence_to_plate is current.
+// // (It is usually constant for fixed plates, always varies for HMDs.)
+// // For HMD case, computes finial matrices that will be used.
+// //
+// computeCoexistenceToPlate();
+// }
+
+ }
+
+ /**
+ * Debugging routine to analyze the projection matrix.
+ */
+ private void analyzeProjection(Transform3D p, double xMax) {
+ if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION)
+ System.err.println("PARALLEL_PROJECTION =");
+ else
+ System.err.println("PERSPECTIVE_PROJECTION =");
+
+ System.err.println(p);
+
+ double projectionPlaneZ = ((p.mat[0] * xMax + p.mat[3] - p.mat[15]) /
+ (p.mat[14] - p.mat[2]));
+
+ System.err.println("projection plane at z = " + projectionPlaneZ);
+ }
+
+ /**
+ * buildProjView creates a projection and viewing matrix.
+ *
+ * Inputs:
+ * ep : eye point, in plate coordinates
+ * coe2Plate : matrix from coexistence to image plate.
+ * F, B : front, back clipping planes, in plate coordinates
+ * doInfinite : flag to indicate ``at infinity'' view desired
+ *
+ * Output:
+ * vpc2Plate : matric from vpc to image plate.
+ * ecToCc : projection matrix from Eye Coordinates (EC)
+ * to Clipping Coordinates (CC)
+ * vpcToEc : view matrix from ViewPlatform Coordinates (VPC)
+ * to Eye Coordinates (EC)
+ */
+ private void buildProjView(Point3d ep,
+ Transform3D coe2Plate,
+ Transform3D vpc2Plate,
+ double F,
+ double B,
+ Transform3D ecToCc,
+ Transform3D vpcToEc,
+ boolean doInfinite) {
+
+ // Lx,Ly Hx,Hy will be adjusted window boundaries
+ double Lx, Hx, Ly, Hy;
+ Lx = physicalWindowXLeft; Hx = physicalWindowXRight;
+ Ly = physicalWindowYBottom; Hy = physicalWindowYTop;
+
+ ecToCc.setIdentity();
+
+
+ // XXXX: we have no concept of glass correction in the Java 3D API
+ //
+ // Correction in apparent 3D position of window due to glass/CRT
+ // and spherical/cylinderical curvarure of CRT.
+ // This boils down to producing modified values of Lx Ly Hx Hy
+ // and is different for hot spot vs. window center corrections.
+ //
+ /* XXXX:
+ double cx, cy;
+ if(viewPolicy != HMD_VIEW && enable_crt_glass_correction) {
+ if (correction_point == CORRECTION_POINT_WINDOW_CENTER) {
+ correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy;
+ correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy;
+ }
+ else { // must be hot spot correction
+ // Not real code yet, for now just do same as above.
+ correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy;
+ correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy;
+ }
+ }
+ */
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("ep = " + ep);
+ System.err.println("Lx = " + Lx + ", Hx = " + Hx);
+ System.err.println("Ly = " + Ly + ", Hy = " + Hy);
+ System.err.println("F = " + F + ", B = " + B);
+ }
+
+ // Compute the proper projection equation. Note that we
+ // do this in two steps: first we generate ImagePlateToCc,
+ // then we translate this by EcToPlate, resulting in a
+ // projection from EctoCc.
+ //
+ // A more efficient (and more accurate) approach would be to
+ // modify the equations below to directly project from EcToCc.
+
+ if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION) {
+ double inv_dx, inv_dy, inv_dz;
+ inv_dx = 1.0 / (Hx - Lx);
+ inv_dy = 1.0 / (Hy - Ly);
+ inv_dz = 1.0 / (F - B);
+
+ ecToCc.mat[0] = 2.0 * inv_dx;
+ ecToCc.mat[3] = -(Hx + Lx) * inv_dx;
+ ecToCc.mat[5] = 2.0 * inv_dy;
+ ecToCc.mat[7] = -(Hy + Ly) * inv_dy;
+ ecToCc.mat[10] = 2.0 * inv_dz;
+ ecToCc.mat[11] = -(F + B) * inv_dz;
+ }
+ else {
+ double sxy, rzb, inv_dx, inv_dy;
+
+ inv_dx = 1.0 / (Hx - Lx);
+ inv_dy = 1.0 / (Hy - Ly);
+ rzb = 1.0/(ep.z - B);
+ sxy = ep.z*rzb;
+
+ ecToCc.mat[0] = sxy*2.0*inv_dx;
+ ecToCc.mat[5] = sxy*2.0*inv_dy;
+
+ ecToCc.mat[2] = rzb*(Hx+Lx - 2.0*ep.x)*inv_dx;
+ ecToCc.mat[6] = rzb*(Hy+Ly - 2.0*ep.y)*inv_dy;
+ ecToCc.mat[10] = rzb*(B+F-2*ep.z)/(B-F);
+ ecToCc.mat[14] = -rzb;
+
+ ecToCc.mat[3] = sxy*(-Hx-Lx)*inv_dx;
+ ecToCc.mat[7] = sxy*(-Hy-Ly)*inv_dy;
+ ecToCc.mat[11] = rzb*(B - ep.z - B*(B+F - 2*ep.z)/(B-F));
+ ecToCc.mat[15] = sxy;
+ }
+
+ // Since we set the matrix elements ourselves, we need to set the
+ // type field. A value of 0 means a non-affine matrix.
+ ecToCc.setOrthoDirtyBit();
+
+ // EC to ImagePlate matrix is a simple translation.
+ tVec1.set(ep.x, ep.y, ep.z);
+ tMat1.set(tVec1);
+ ecToCc.mul(tMat1);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("ecToCc:");
+ analyzeProjection(ecToCc, Hx);
+ }
+
+ if(!doInfinite) {
+ // View matrix is:
+ // [plateToEc] [coexistence_to_plate] [vpc_to_coexistence]
+ // where vpc_to_coexistence includes the viewPlatformScale
+
+ // First compute ViewPlatform to Plate
+ vpc2Plate.mul(coe2Plate, vpcToCoexistence);
+
+ // ImagePlate to EC matrix is a simple translation.
+ tVec1.set(-ep.x, -ep.y, -ep.z);
+ tMat1.set(tVec1);
+ vpcToEc.mul(tMat1, vpc2Plate);
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ System.err.println("vpcToEc:");
+ System.err.println(vpcToEc);
+ }
+ }
+ else {
+ // Final infinite composite is:
+ // [coexistence_to_eye] [vpc_to_coexistence (vom)]
+ // (does vworld_to_coe_scale_factor get used here??? )
+ //
+ // The method is to relocate the coexistence org centered on
+ // the eye rather than the window center (via coexistence_to_eye).
+ // Computationaly simpler simplifed equation form may exist.
+
+ // coexistence to eye is a simple translation.
+/*
+ tVec1.set(ep.x, ep.y, ep.z);
+ tMat1.set(tVec1);
+ vpcToEc.mul(tMat1, vpcToCoexistence);
+ // First compute ViewPlatform to Plate
+ vpcToPlate.mul(coexistenceToPlatevpcToPlate, vpcToCoexistence);
+*/
+
+ // ImagePlate to EC matrix is a simple translation.
+ tVec1.set(-ep.x, -ep.y, -ep.z);
+ tMat1.set(tVec1);
+ tMat1.mul(tMat1, vpc2Plate);
+ tMat1.getRotation(vpcToEc); // use only rotation component of transform
+
+ }
+
+ }
+
+ /**
+ * Compute the plane equations for the frustum in ViewPlatform
+ * coordinates, plus its viewing frustum points. ccToVworld will
+ * be cached - used by Canavs3D.getInverseVworldProjection().
+ */
+ private void computeFrustumPlanes(Transform3D ecToCc,
+ Transform3D vpcToEc,
+ Vector4d [] frustumPlanes,
+ Point4d [] frustumPoints,
+ Transform3D ccToVworld) {
+
+ // Compute the inverse of the Vworld to Cc transform. This
+ // gives us the Cc to Vworld transform.
+ tMat2.mul(ecToCc, vpcToEc);
+ ccToVworld.mul(tMat2, vworldToVpc);
+ // System.err.println("ccToVworld = " + ccToVworld);
+ try {
+ ccToVworld.invert();
+ }
+ catch (SingularMatrixException e) {
+ ccToVworld.setIdentity();
+ // System.err.println("SingularMatrixException encountered when doing invert in computeFrustumPlanes");
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
+ Transform3D t = new Transform3D();
+ t.mul(ecToCc, vpcToEc);
+ t.mul(vworldToVpc);
+ System.err.println("\nvworldToCc = " + t);
+ System.err.println("ccToVworld = " + ccToVworld);
+ t.mul(ccToVworld);
+ System.err.println("vworldToCc * ccToVworld = " + t);
+ }
+
+ // Transform the 8 corners of the viewing frustum into Vpc
+ frustumPoints[0].set(-1.0, -1.0, 1.0, 1.0); // lower-left-front
+ frustumPoints[1].set(-1.0, 1.0, 1.0, 1.0); // upper-left-front
+ frustumPoints[2].set( 1.0, 1.0, 1.0, 1.0); // upper-right-front
+ frustumPoints[3].set( 1.0, -1.0, 1.0, 1.0); // lower-right-front
+ frustumPoints[4].set(-1.0, -1.0, -1.0, 1.0); // lower-left-back
+ frustumPoints[5].set(-1.0, 1.0, -1.0, 1.0); // upper-left-back
+ frustumPoints[6].set( 1.0, 1.0, -1.0, 1.0); // upper-right-back
+ frustumPoints[7].set( 1.0, -1.0, -1.0, 1.0); // lower-right-back
+
+ ccToVworld.get(tMatrix);
+ int i;
+ for (i = 0; i < frustumPoints.length; i++) {
+ tMatrix.transform(frustumPoints[i]);
+ double w_inv = 1.0 / frustumPoints[i].w;
+ frustumPoints[i].x *= w_inv;
+ frustumPoints[i].y *= w_inv;
+ frustumPoints[i].z *= w_inv;
+ }
+
+ // Now compute the 6 plane equations
+ // left
+ computePlaneEq(frustumPoints[0], frustumPoints[4],
+ frustumPoints[5], frustumPoints[1],
+ frustumPlanes[0]);
+
+ // right
+ computePlaneEq(frustumPoints[3], frustumPoints[2],
+ frustumPoints[6], frustumPoints[7],
+ frustumPlanes[1]);
+
+ // top
+ computePlaneEq(frustumPoints[1], frustumPoints[5],
+ frustumPoints[6], frustumPoints[2],
+ frustumPlanes[2]);
+
+ // bottom
+ computePlaneEq(frustumPoints[0], frustumPoints[3],
+ frustumPoints[7], frustumPoints[4],
+ frustumPlanes[3]);
+
+ // front
+ computePlaneEq(frustumPoints[0], frustumPoints[1],
+ frustumPoints[2], frustumPoints[3],
+ frustumPlanes[4]);
+
+ // back
+ computePlaneEq(frustumPoints[4], frustumPoints[7],
+ frustumPoints[6], frustumPoints[5],
+ frustumPlanes[5]);
+
+ //System.err.println("left plane = " + frustumPlanes[0]);
+ //System.err.println("right plane = " + frustumPlanes[1]);
+ //System.err.println("top plane = " + frustumPlanes[2]);
+ //System.err.println("bottom plane = " + frustumPlanes[3]);
+ //System.err.println("front plane = " + frustumPlanes[4]);
+ //System.err.println("back plane = " + frustumPlanes[5]);
+ }
+
+ private void computePlaneEq(Point4d p1, Point4d p2, Point4d p3, Point4d p4,
+ Vector4d planeEq) {
+ tVec1.x = p3.x - p1.x;
+ tVec1.y = p3.y - p1.y;
+ tVec1.z = p3.z - p1.z;
+
+ tVec2.x = p2.x - p1.x;
+ tVec2.y = p2.y - p1.y;
+ tVec2.z = p2.z - p1.z;
+
+ tVec3.cross(tVec2, tVec1);
+ tVec3.normalize();
+ planeEq.x = tVec3.x;
+ planeEq.y = tVec3.y;
+ planeEq.z = tVec3.z;
+ planeEq.w = -(planeEq.x * p1.x + planeEq.y * p1.y + planeEq.z * p1.z);
+ }
+
+ // Get methods for returning derived data values.
+ // Eventually, these get functions will cause some of the parameters
+ // to be lazily evaluated.
+ //
+ // NOTE: in the case of Transform3D, and Tuple objects, a reference
+ // to the actual derived data is returned. In these cases, the caller
+ // must ensure that the returned data is not modified.
+ //
+ // NOTE: the snapshot and computeDerivedData methods are synchronized.
+ // Callers of the following methods that can run asynchronously with
+ // the renderer must call these methods and copy the data from within
+ // a synchronized block on the canvas view cache object.
+
+ int getCanvasX() {
+ return canvasX;
+ }
+
+ int getCanvasY() {
+ return canvasY;
+ }
+
+ int getCanvasWidth() {
+ return canvasWidth;
+ }
+
+ int getCanvasHeight() {
+ return canvasHeight;
+ }
+
+ double getPhysicalWindowWidth() {
+ return physicalWindowWidth;
+ }
+
+ double getPhysicalWindowHeight() {
+ return physicalWindowHeight;
+ }
+
+ boolean getUseStereo() {
+ return useStereo;
+ }
+
+ Transform3D getLeftProjection() {
+ return leftProjection;
+ }
+
+ Transform3D getRightProjection() {
+ return rightProjection;
+ }
+
+ Transform3D getLeftVpcToEc() {
+ return leftVpcToEc;
+ }
+
+ Transform3D getRightVpcToEc() {
+ return rightVpcToEc;
+ }
+
+ Transform3D getLeftEcToVpc() {
+ return leftEcToVpc;
+ }
+
+ Transform3D getRightEcToVpc() {
+ return rightEcToVpc;
+ }
+
+ Transform3D getInfLeftProjection() {
+ return infLeftProjection;
+ }
+
+ Transform3D getInfRightProjection() {
+ return infLeftProjection;
+ }
+
+ Transform3D getInfLeftVpcToEc() {
+ return infLeftVpcToEc;
+ }
+
+ Transform3D getInfRightVpcToEc() {
+ return infRightVpcToEc;
+ }
+
+ Transform3D getInfLeftEcToVpc() {
+ return infLeftEcToVpc;
+ }
+
+ Transform3D getInfgRightEcToVpc() {
+ return infRightEcToVpc;
+ }
+
+ Transform3D getInfVworldToVpc() {
+ return infVworldToVpc;
+ }
+
+ Transform3D getLeftCcToVworld() {
+ return leftCcToVworld;
+ }
+
+ Transform3D getRightCcToVworld() {
+ return rightCcToVworld;
+ }
+
+ Transform3D getImagePlateToVworld() {
+ // XXXX: Document -- This will return the transform of left plate.
+ return leftPlateToVworld;
+ }
+
+
+
+ Transform3D getLastVworldToImagePlate() {
+ // XXXX: Document -- This will return the transform of left plate.
+ return lastVworldToLeftPlate;
+
+ }
+
+ Transform3D getVworldToImagePlate() {
+ // XXXX: Document -- This will return the transform of left plate.
+ return vworldToLeftPlate;
+ }
+
+ Transform3D getVworldToTrackerBase() {
+ return vworldToTrackerBase;
+ }
+
+ double getVworldToCoexistenceScale() {
+ return vworldToCoexistenceScale;
+ }
+
+ double getInfVworldToCoexistenceScale() {
+ return infVworldToCoexistenceScale;
+ }
+
+ Point3d getLeftEyeInImagePlate() {
+ return leftEyeInImagePlate;
+ }
+
+ Point3d getRightEyeInImagePlate() {
+ return rightEyeInImagePlate;
+ }
+
+ Point3d getCenterEyeInImagePlate() {
+ return centerEyeInImagePlate;
+ }
+
+ Transform3D getHeadToVworld() {
+ return headToVworld;
+ }
+
+ Transform3D getVpcToVworld() {
+ return vpcToVworld;
+ }
+
+ Transform3D getVworldToVpc() {
+ return vworldToVpc;
+ }
+
+
+ // Transform the specified X point in AWT window-relative coordinates
+ // to image plate coordinates
+ double getWindowXInImagePlate(double x) {
+ double xScreen = x + (double)canvasX;
+ return metersPerPixelX * xScreen;
+ }
+
+ // Transform the specified Y point in AWT window-relative coordinates
+ // to image plate coordinates
+ double getWindowYInImagePlate(double y) {
+ double yScreen = y + (double)canvasY;
+ return metersPerPixelY * ((double)(screenHeight - 1) - yScreen);
+ }
+
+ Vector4d[] getLeftFrustumPlanesInVworld() {
+ return leftFrustumPlanes;
+ }
+
+ Vector4d[] getRightFrustumPlanesInVworld() {
+ return rightFrustumPlanes;
+ }
+
+
+ void getPixelLocationInImagePlate(double x, double y, double z,
+ Point3d imagePlatePoint) {
+
+ double screenx = (x + canvasX)*metersPerPixelX;
+ double screeny = (screenHeight - 1 - canvasY - y)*metersPerPixelY;
+
+ if ((viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION) &&
+ (centerEyeInImagePlate.z != 0)) {
+ double zScale = 1.0 - z/centerEyeInImagePlate.z;
+ imagePlatePoint.x = (screenx - centerEyeInImagePlate.x)*zScale
+ + centerEyeInImagePlate.x;
+ imagePlatePoint.y = (screeny - centerEyeInImagePlate.y)*zScale
+ + centerEyeInImagePlate.y;
+ } else {
+ imagePlatePoint.x = screenx;
+ imagePlatePoint.y = screeny;
+ }
+ imagePlatePoint.z = z;
+ }
+
+ /**
+ * Projects the specified point from image plate coordinates
+ * into AWT pixel coordinates.
+ */
+ void getPixelLocationFromImagePlate(Point3d imagePlatePoint,
+ Point2d pixelLocation) {
+
+ double screenX, screenY;
+
+ if(viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION) {
+ // get the vector from centerEyeInImagePlate to imagePlatePoint
+ tVec1.sub(imagePlatePoint, centerEyeInImagePlate);
+
+ // Scale this vector to make it end at the projection plane.
+ // Scale is ratio :
+ // eye->imagePlate Plane dist / eye->imagePlatePt dist
+ // eye dist to plane is eyePos.z (eye is in +z space)
+ // image->eye dist is -tVec1.z (image->eye is in -z dir)
+ //System.err.println("eye dist = " + (centerEyeInImagePlate.z));
+ //System.err.println("image dist = " + (-tVec1.z));
+ if (tVec1.z != 0) {
+ double zScale = centerEyeInImagePlate.z / (-tVec1.z);
+ screenX = centerEyeInImagePlate.x + tVec1.x * zScale;
+ screenY = centerEyeInImagePlate.y + tVec1.y * zScale;
+
+ } else {
+ screenX = imagePlatePoint.x;
+ screenY = imagePlatePoint.y;
+ }
+
+ } else {
+ screenX = imagePlatePoint.x;
+ screenY = imagePlatePoint.y;
+ }
+
+ //System.err.println("screenX = " + screenX + " screenY = " + screenY);
+ // Note: screenPt is in image plate coords, at z=0
+
+ // Transform from image plate coords to screen coords
+ pixelLocation.x = (screenX / screenViewCache.metersPerPixelX) - canvasX;
+ pixelLocation.y = screenViewCache.screenHeight - 1 -
+ (screenY / screenViewCache.metersPerPixelY) - canvasY;
+ //System.err.println("pixelLocation = " + pixelLocation);
+ }
+
+ /**
+ * Constructs and initializes a CanvasViewCache object.
+ * Note that the canvas, screen, screenCache, view, and
+ * viewCache parameters are all fixed at construction time
+ * and must be non-null.
+ */
+ CanvasViewCache(Canvas3D canvas,
+ ScreenViewCache screenViewCache,
+ ViewCache viewCache) {
+
+ this.canvas = canvas;
+ this.screenViewCache = screenViewCache;
+ this.viewCache = viewCache;
+
+ // Set up the initial plane equations
+ int i;
+ for (i = 0; i < leftFrustumPlanes.length; i++) {
+ leftFrustumPlanes[i] = new Vector4d();
+ rightFrustumPlanes[i] = new Vector4d();
+ }
+
+ for (i = 0; i < leftFrustumPoints.length; i++) {
+ leftFrustumPoints[i] = new Point4d();
+ rightFrustumPoints[i] = new Point4d();
+ }
+
+ // canvas is null in Renderer copyOfCvCache
+ if (canvas != null) {
+ leftEyeInImagePlate.set(canvas.leftManualEyeInImagePlate);
+ rightEyeInImagePlate.set(canvas.rightManualEyeInImagePlate);
+ centerEyeInImagePlate.add(leftEyeInImagePlate,
+ rightEyeInImagePlate);
+ centerEyeInImagePlate.scale(0.5);
+ }
+
+ if((J3dDebug.devPhase) && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
+ System.err.println("Constructed a CanvasViewCache");
+ }
+
+ synchronized void setCanvas(Canvas3D c) {
+ canvas = c;
+ }
+
+ synchronized void setScreenViewCache(ScreenViewCache svc) {
+ screenViewCache = svc;
+ }
+
+ synchronized void setViewCache(ViewCache vc) {
+ viewCache = vc;
+ }
+}