0001: /*
0002: * $RCSfile: CanvasViewCache.java,v $
0003: *
0004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0006: *
0007: * This code is free software; you can redistribute it and/or modify it
0008: * under the terms of the GNU General Public License version 2 only, as
0009: * published by the Free Software Foundation. Sun designates this
0010: * particular file as subject to the "Classpath" exception as provided
0011: * by Sun in the LICENSE file that accompanied this code.
0012: *
0013: * This code is distributed in the hope that it will be useful, but WITHOUT
0014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0016: * version 2 for more details (a copy is included in the LICENSE file that
0017: * accompanied this code).
0018: *
0019: * You should have received a copy of the GNU General Public License version
0020: * 2 along with this work; if not, write to the Free Software Foundation,
0021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0022: *
0023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0024: * CA 95054 USA or visit www.sun.com if you need additional information or
0025: * have any questions.
0026: *
0027: * $Revision: 1.9 $
0028: * $Date: 2008/02/28 20:17:20 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.awt.Point;
0035: import java.awt.Dimension;
0036: import java.awt.Rectangle;
0037: import java.awt.IllegalComponentStateException;
0038: import javax.vecmath.*;
0039:
0040: /**
0041: * The CanvasViewCache class is used to cache all data, both API data
0042: * and derived data, that is dependent on the Canvas3D or Screen3D.
0043: * The final view and projection matrices are stored here.
0044: */
0045:
0046: class CanvasViewCache extends Object {
0047: // Used for debugging only
0048: private static Object debugLock = new Object();
0049:
0050: // The canvas associated with this canvas view cache
0051: private Canvas3D canvas;
0052:
0053: // Mask that indicates this CanvasViewCache view dependence info. has changed,
0054: // and CanvasViewCache may need to recompute the final view matries.
0055: int cvcDirtyMask = 0;
0056:
0057: // The screen view cache associated with this canvas view cache
0058: private ScreenViewCache screenViewCache;
0059:
0060: // The view cache associated with this canvas view cache
0061: private ViewCache viewCache;
0062:
0063: // *************
0064: // API/INPUT DATA
0065: // *************
0066:
0067: // The position and size of the canvas (in pixels)
0068: private int awtCanvasX;
0069: private int awtCanvasY;
0070: private int awtCanvasWidth;
0071: private int awtCanvasHeight;
0072:
0073: // The current RenderBin used for rendering during the frame
0074: // associated with this snapshot.
0075: private RenderBin renderBin;
0076:
0077: // Flag indicating whether or not stereo will be used. Computed by
0078: // Canvas3D as: useStereo = stereoEnable && stereoAvailable
0079: private boolean useStereo;
0080:
0081: // Current monoscopic view policy from canvas
0082: private int monoscopicViewPolicy;
0083:
0084: // The manual positions of the left and right eyes in image-plate
0085: // coordinates.
0086: // Note that these values are only used in non-head-tracked mode
0087: // when the view's window eyepoint policy is one of RELATIVE_TO_SCREEN
0088: // or RELATIVE_TO_WINDOW.
0089: private Point3d leftManualEyeInImagePlate = new Point3d();
0090: private Point3d rightManualEyeInImagePlate = new Point3d();
0091:
0092: // *************
0093: // DERIVED DATA
0094: // *************
0095:
0096: // The width and height of the screen in meters (from ScreenViewCache)
0097: double physicalScreenWidth;
0098: double physicalScreenHeight;
0099:
0100: // The width and height of the screen in pixels (from ScreenViewCache)
0101: int screenWidth;
0102: int screenHeight;
0103:
0104: // Meters per pixel in the X and Y dimension (from ScreenViewCache)
0105: double metersPerPixelX;
0106: double metersPerPixelY;
0107:
0108: // The position and size of the canvas (in pixels)
0109: private int canvasX;
0110: private int canvasY;
0111: private int canvasWidth;
0112: private int canvasHeight;
0113:
0114: // Either the Canvas' or the View's monoscopicViewPolicy
0115: private int effectiveMonoscopicViewPolicy;
0116:
0117: // The current cached projection transforms.
0118: private Transform3D leftProjection = new Transform3D();
0119: private Transform3D rightProjection = new Transform3D();
0120: private Transform3D infLeftProjection = new Transform3D();
0121: private Transform3D infRightProjection = new Transform3D();
0122:
0123: // The current cached viewing transforms.
0124: private Transform3D leftVpcToEc = new Transform3D();
0125: private Transform3D rightVpcToEc = new Transform3D();
0126: private Transform3D infLeftVpcToEc = new Transform3D();
0127: private Transform3D infRightVpcToEc = new Transform3D();
0128:
0129: // The current cached inverse viewing transforms.
0130: private Transform3D leftEcToVpc = new Transform3D();
0131: private Transform3D rightEcToVpc = new Transform3D();
0132: private Transform3D infLeftEcToVpc = new Transform3D();
0133: private Transform3D infRightEcToVpc = new Transform3D();
0134:
0135: // Arrays of Vector4d objects that represent the plane equations for
0136: // the 6 planes in the viewing frustum in ViewPlatform coordinates.
0137: private Vector4d[] leftFrustumPlanes = new Vector4d[6];
0138: private Vector4d[] rightFrustumPlanes = new Vector4d[6];
0139:
0140: // Arrays of Vector4d objects that represent the volume of viewing frustum
0141: private Point4d leftFrustumPoints[] = new Point4d[8];
0142: private Point4d rightFrustumPoints[] = new Point4d[8];
0143:
0144: // Calibration matrix from Screen object for HMD mode using
0145: // non-field-sequential stereo
0146:
0147: private Transform3D headTrackerToLeftImagePlate = new Transform3D();
0148: private Transform3D headTrackerToRightImagePlate = new Transform3D();
0149:
0150: // Head tracked version of eye in imageplate
0151: private Point3d leftTrackedEyeInImagePlate = new Point3d();
0152: private Point3d rightTrackedEyeInImagePlate = new Point3d();
0153:
0154: // Derived version of eye in image plate coordinates
0155: private Point3d leftEyeInImagePlate = new Point3d();
0156: private Point3d rightEyeInImagePlate = new Point3d();
0157: private Point3d centerEyeInImagePlate = new Point3d();
0158:
0159: // Derived version of nominalEyeOffsetFromNominalScreen
0160: private double nominalEyeOffset;
0161:
0162: // Physical window position,size and center (in image plate coordinates)
0163: private double physicalWindowXLeft;
0164: private double physicalWindowYBottom;
0165: private double physicalWindowXRight;
0166: private double physicalWindowYTop;
0167: private double physicalWindowWidth;
0168: private double physicalWindowHeight;
0169: private Point3d physicalWindowCenter = new Point3d();
0170:
0171: // Screen scale value from viewCache or from screen size.
0172: private double screenScale;
0173:
0174: // Window scale value that compensates for window size if
0175: // the window resize policy is PHYSICAL_WORLD.
0176: private double windowScale;
0177:
0178: // ViewPlatform scale that takes coordinates from view platform
0179: // coordinates and scales them to physical coordinates
0180: private double viewPlatformScale;
0181:
0182: // Various derived transforms
0183:
0184: private Transform3D leftCcToVworld = new Transform3D();
0185: private Transform3D rightCcToVworld = new Transform3D();
0186:
0187: private Transform3D coexistenceToLeftPlate = new Transform3D();
0188: private Transform3D coexistenceToRightPlate = new Transform3D();
0189:
0190: private Transform3D vpcToCoexistence = new Transform3D();
0191:
0192: private Transform3D vpcToLeftPlate = new Transform3D();
0193: private Transform3D vpcToRightPlate = new Transform3D();
0194: private Transform3D leftPlateToVpc = new Transform3D();
0195: private Transform3D rightPlateToVpc = new Transform3D();
0196: private Transform3D vworldToLeftPlate = new Transform3D();
0197: private Transform3D lastVworldToLeftPlate = new Transform3D();
0198: private Transform3D vworldToRightPlate = new Transform3D();
0199: private Transform3D leftPlateToVworld = new Transform3D();
0200: private Transform3D rightPlateToVworld = new Transform3D();
0201: private Transform3D headToLeftImagePlate = new Transform3D();
0202: private Transform3D headToRightImagePlate = new Transform3D();
0203:
0204: private Transform3D vworldToTrackerBase = new Transform3D();
0205: private Transform3D tempTrans = new Transform3D();
0206: private Transform3D headToVworld = new Transform3D();
0207: private Vector3d coexistenceCenter = new Vector3d();
0208:
0209: // scale for transformimg clip and fog distances
0210: private double vworldToCoexistenceScale;
0211: private double infVworldToCoexistenceScale;
0212:
0213: //
0214: // Temporary matrices and vectors, so we dont generate garbage
0215: //
0216: private Transform3D tMat1 = new Transform3D();
0217: private Transform3D tMat2 = new Transform3D();
0218: private Vector3d tVec1 = new Vector3d();
0219: private Vector3d tVec2 = new Vector3d();
0220: private Vector3d tVec3 = new Vector3d();
0221: private Point3d tPnt1 = new Point3d();
0222: private Point3d tPnt2 = new Point3d();
0223:
0224: private Matrix4d tMatrix = new Matrix4d();
0225:
0226: /**
0227: * The view platform transforms.
0228: */
0229: private Transform3D vworldToVpc = new Transform3D();
0230: private Transform3D vpcToVworld = new Transform3D();
0231: private Transform3D infVworldToVpc = new Transform3D();
0232:
0233: // This flag is used to remember the last time doInfinite flag
0234: // is true or not.
0235: // If this cache is updated twice, the first time in RenderBin
0236: // updateViewCache() and the second time in Renderer with
0237: // geometryBackground. The first time will reset the vcDirtyMask
0238: // to 0 so that geometry background will not get updated the
0239: // second time doComputeDerivedData() is invoked when view change.
0240: private boolean lastDoInfinite = false;
0241: private boolean updateLastTime = false;
0242:
0243: void getCanvasPositionAndSize() {
0244: if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2) {
0245: System.err.println("Get canvas position and size");
0246: System.err.println("Before");
0247: System.err.println("Canvas pos = (" + awtCanvasX + ", "
0248: + awtCanvasY + "), size = " + awtCanvasWidth + "x"
0249: + awtCanvasHeight);
0250: System.err.println("After");
0251: }
0252: awtCanvasX = canvas.newPosition.x;
0253: awtCanvasY = canvas.newPosition.y;
0254: awtCanvasWidth = canvas.newSize.width;
0255: awtCanvasHeight = canvas.newSize.height;
0256:
0257: // The following works around problem when awt creates 0-size
0258: // window at startup
0259: if ((awtCanvasWidth <= 0) || (awtCanvasHeight <= 0)) {
0260: awtCanvasWidth = 1;
0261: awtCanvasHeight = 1;
0262: }
0263:
0264: if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) {
0265: System.err.println("Canvas pos = (" + awtCanvasX + ", "
0266: + awtCanvasY + "), size = " + awtCanvasWidth + "x"
0267: + awtCanvasHeight);
0268: }
0269: }
0270:
0271: void computefrustumBBox(BoundingBox frustumBBox) {
0272: int i;
0273:
0274: for (i = 0; i < leftFrustumPoints.length; i++) {
0275: if (frustumBBox.lower.x > leftFrustumPoints[i].x)
0276: frustumBBox.lower.x = leftFrustumPoints[i].x;
0277: if (frustumBBox.lower.y > leftFrustumPoints[i].y)
0278: frustumBBox.lower.y = leftFrustumPoints[i].y;
0279: if (frustumBBox.lower.z > leftFrustumPoints[i].z)
0280: frustumBBox.lower.z = leftFrustumPoints[i].z;
0281:
0282: if (frustumBBox.upper.x < leftFrustumPoints[i].x)
0283: frustumBBox.upper.x = leftFrustumPoints[i].x;
0284: if (frustumBBox.upper.y < leftFrustumPoints[i].y)
0285: frustumBBox.upper.y = leftFrustumPoints[i].y;
0286: if (frustumBBox.upper.z < leftFrustumPoints[i].z)
0287: frustumBBox.upper.z = leftFrustumPoints[i].z;
0288: }
0289:
0290: if (useStereo) {
0291:
0292: for (i = 0; i < rightFrustumPoints.length; i++) {
0293: if (frustumBBox.lower.x > rightFrustumPoints[i].x)
0294: frustumBBox.lower.x = rightFrustumPoints[i].x;
0295: if (frustumBBox.lower.y > rightFrustumPoints[i].y)
0296: frustumBBox.lower.y = rightFrustumPoints[i].y;
0297: if (frustumBBox.lower.z > rightFrustumPoints[i].z)
0298: frustumBBox.lower.z = rightFrustumPoints[i].z;
0299:
0300: if (frustumBBox.upper.x < rightFrustumPoints[i].x)
0301: frustumBBox.upper.x = rightFrustumPoints[i].x;
0302: if (frustumBBox.upper.y < rightFrustumPoints[i].y)
0303: frustumBBox.upper.y = rightFrustumPoints[i].y;
0304: if (frustumBBox.upper.z < rightFrustumPoints[i].z)
0305: frustumBBox.upper.z = rightFrustumPoints[i].z;
0306: }
0307:
0308: }
0309: }
0310:
0311: void copyComputedCanvasViewCache(CanvasViewCache cvc,
0312: boolean doInfinite) {
0313: // For performance reason, only data needed by renderer are copied.
0314: // useStereo,
0315: // canvasWidth,
0316: // canvasHeight,
0317: // leftProjection,
0318: // rightProjection,
0319: // leftVpcToEc,
0320: // rightVpcToEc,
0321: // leftFrustumPlanes,
0322: // rightFrustumPlanes,
0323: // vpcToVworld,
0324: // vworldToVpc.
0325:
0326: cvc.useStereo = useStereo;
0327: cvc.canvasWidth = canvasWidth;
0328: cvc.canvasHeight = canvasHeight;
0329: cvc.leftProjection.set(leftProjection);
0330: cvc.rightProjection.set(rightProjection);
0331: cvc.leftVpcToEc.set(leftVpcToEc);
0332: cvc.rightVpcToEc.set(rightVpcToEc);
0333:
0334: cvc.vpcToVworld = vpcToVworld;
0335: cvc.vworldToVpc.set(vworldToVpc);
0336:
0337: if (doInfinite) {
0338: cvc.infLeftProjection.set(infLeftProjection);
0339: cvc.infRightProjection.set(infRightProjection);
0340: cvc.infLeftVpcToEc.set(infLeftVpcToEc);
0341: cvc.infRightVpcToEc.set(infRightVpcToEc);
0342: cvc.infVworldToVpc.set(infVworldToVpc);
0343: }
0344:
0345: for (int i = 0; i < leftFrustumPlanes.length; i++) {
0346: cvc.leftFrustumPlanes[i].x = leftFrustumPlanes[i].x;
0347: cvc.leftFrustumPlanes[i].y = leftFrustumPlanes[i].y;
0348: cvc.leftFrustumPlanes[i].z = leftFrustumPlanes[i].z;
0349: cvc.leftFrustumPlanes[i].w = leftFrustumPlanes[i].w;
0350:
0351: cvc.rightFrustumPlanes[i].x = rightFrustumPlanes[i].x;
0352: cvc.rightFrustumPlanes[i].y = rightFrustumPlanes[i].y;
0353: cvc.rightFrustumPlanes[i].z = rightFrustumPlanes[i].z;
0354: cvc.rightFrustumPlanes[i].w = rightFrustumPlanes[i].w;
0355: }
0356: }
0357:
0358: /**
0359: * Take snapshot of all per-canvas API parameters and input values.
0360: * NOTE: This is probably not needed, but we'll do it for symmetry
0361: * with the ScreenViewCache and ViewCache objects.
0362: */
0363: synchronized void snapshot(boolean computeFrustum) {
0364: // Issue 109 : determine the the correct index to use -- either the
0365: // Renderer or RenderBin
0366: int dirtyIndex = computeFrustum ? Canvas3D.RENDER_BIN_DIRTY_IDX
0367: : Canvas3D.RENDERER_DIRTY_IDX;
0368:
0369: synchronized (canvas.dirtyMaskLock) {
0370: // Issue 109 : read/clear the dirty bits for the correct index
0371: cvcDirtyMask = canvas.cvDirtyMask[dirtyIndex];
0372: canvas.cvDirtyMask[dirtyIndex] = 0;
0373: }
0374:
0375: useStereo = canvas.useStereo;
0376: monoscopicViewPolicy = canvas.monoscopicViewPolicy;
0377: leftManualEyeInImagePlate.set(canvas.leftManualEyeInImagePlate);
0378: rightManualEyeInImagePlate
0379: .set(canvas.rightManualEyeInImagePlate);
0380:
0381: if ((cvcDirtyMask & Canvas3D.MOVED_OR_RESIZED_DIRTY) != 0) {
0382: getCanvasPositionAndSize();
0383: }
0384:
0385: renderBin = canvas.view.renderBin;
0386:
0387: }
0388:
0389: /**
0390: * Compute derived data using the snapshot of the per-canvas,
0391: * per-screen and per-view data.
0392: */
0393: synchronized void computeDerivedData(boolean currentFlag,
0394: CanvasViewCache cvc, BoundingBox frustumBBox,
0395: boolean doInfinite) {
0396:
0397: if ((J3dDebug.devPhase)
0398: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
0399: synchronized (debugLock) {
0400: System.err.println("------------------------------");
0401: doComputeDerivedData(currentFlag, cvc, frustumBBox,
0402: doInfinite);
0403: }
0404: } else {
0405: doComputeDerivedData(currentFlag, cvc, frustumBBox,
0406: doInfinite);
0407: }
0408: }
0409:
0410: /**
0411: * Compute derived data using the snapshot of the per-canvas,
0412: * per-screen and per-view data. Caller must synchronize before
0413: * calling this method.
0414: */
0415: private void doComputeDerivedData(boolean currentFlag,
0416: CanvasViewCache cvc, BoundingBox frustumBBox,
0417: boolean doInfinite) {
0418:
0419: // Issue 109 : determine the the correct index to use -- either the
0420: // Renderer or RenderBin
0421: int dirtyIndex = (frustumBBox != null) ? Canvas3D.RENDER_BIN_DIRTY_IDX
0422: : Canvas3D.RENDERER_DIRTY_IDX;
0423: int scrvcDirtyMask;
0424:
0425: // Issue 109 : read/clear the dirty bits for the correct index
0426: synchronized (screenViewCache) {
0427: scrvcDirtyMask = screenViewCache.scrvcDirtyMask[dirtyIndex];
0428: // reset screen view dirty mask if canvas is offScreen. Note:
0429: // there is only one canvas per offscreen, so it is ok to
0430: // do the reset here.
0431: if (canvas.offScreen) {
0432: screenViewCache.scrvcDirtyMask[dirtyIndex] = 0;
0433: }
0434: }
0435:
0436: if ((J3dDebug.devPhase)
0437: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0438: if (cvcDirtyMask != 0)
0439: System.err.println("cvcDirtyMask : " + cvcDirtyMask);
0440:
0441: if (scrvcDirtyMask != 0)
0442: System.err
0443: .println("scrvcDirtyMask : " + scrvcDirtyMask);
0444:
0445: if (viewCache.vcDirtyMask != 0)
0446: System.err.println("vcDirtyMask : "
0447: + viewCache.vcDirtyMask);
0448: }
0449:
0450: // NOTE: This fix is only fixing the symptoms, but not the
0451: // root of the bug. We shouldn't have to check for null here.
0452: if (viewCache.vpRetained == null) {
0453: System.err
0454: .println("CanvasViewCache : Error! viewCache.vpRetained is null");
0455: return;
0456: }
0457:
0458: // This flag is use to force a computation when a ViewPlatformTransform
0459: // is detected. No sync. needed. We're doing a read of t/f.
0460: // XXXX: Peeking at the dirty flag is a hack. Need to revisit this.
0461: boolean vprNotDirty = (viewCache.vpRetained.vprDirtyMask == 0);
0462:
0463: // Issue 131: If not manual, it has to be considered as an onscreen canvas.
0464: if (!canvas.manualRendering && (vprNotDirty)
0465: && (cvcDirtyMask == 0) && (scrvcDirtyMask == 0)
0466: && (viewCache.vcDirtyMask == 0)
0467: && !(updateLastTime && (doInfinite != lastDoInfinite))) {
0468: if (frustumBBox != null)
0469: computefrustumBBox(frustumBBox);
0470:
0471: // Copy the computed data into cvc.
0472: if (cvc != null) {
0473: copyComputedCanvasViewCache(cvc, doInfinite);
0474: }
0475: lastDoInfinite = doInfinite;
0476: updateLastTime = false;
0477: return;
0478: }
0479:
0480: lastDoInfinite = doInfinite;
0481: updateLastTime = true;
0482:
0483: if (currentFlag) {
0484: vpcToVworld.set(viewCache.vpRetained
0485: .getCurrentLocalToVworld(null));
0486: } else {
0487: vpcToVworld.set(viewCache.vpRetained
0488: .getLastLocalToVworld(null));
0489: }
0490:
0491: // System.err.println("vpcToVworld is \n" + vpcToVworld);
0492:
0493: try {
0494: vworldToVpc.invert(vpcToVworld);
0495: } catch (SingularMatrixException e) {
0496: vworldToVpc.setIdentity();
0497: //System.err.println("SingularMatrixException encountered when doing vworldToVpc invert");
0498: }
0499: if (doInfinite) {
0500: vworldToVpc.getRotation(infVworldToVpc);
0501: }
0502:
0503: // Compute global flags
0504: if (monoscopicViewPolicy == View.CYCLOPEAN_EYE_VIEW)
0505: effectiveMonoscopicViewPolicy = viewCache.monoscopicViewPolicy;
0506: else
0507: effectiveMonoscopicViewPolicy = monoscopicViewPolicy;
0508:
0509: // Recompute info about current canvas window
0510: computeCanvasInfo();
0511:
0512: // Compute coexistence center (in plate coordinates)
0513: computeCoexistenceCenter();
0514:
0515: // Get Eye position in image-plate coordinates
0516: cacheEyePosition();
0517:
0518: // Compute VPC to COE and COE to PLATE transforms
0519: computeVpcToCoexistence();
0520: computeCoexistenceToPlate();
0521:
0522: // Compute view and projection matrices
0523: computeView(doInfinite);
0524:
0525: computePlateToVworld();
0526:
0527: if (!currentFlag) {
0528: // save the result for use in RasterRetained computeWinCoord
0529: lastVworldToLeftPlate.set(vworldToLeftPlate);
0530: }
0531: computeHeadToVworld();
0532:
0533: if (frustumBBox != null)
0534: computefrustumBBox(frustumBBox);
0535:
0536: // Issue 109: cvc should *always* be null
0537: assert cvc == null;
0538: if (cvc != null)
0539: copyComputedCanvasViewCache(cvc, doInfinite);
0540:
0541: canvas.canvasDirty |= Canvas3D.VIEW_MATRIX_DIRTY;
0542:
0543: if ((J3dDebug.devPhase)
0544: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
0545: // Print some data :
0546: System.err.println("useStereo = " + useStereo);
0547: System.err.println("leftProjection:\n" + leftProjection);
0548: System.err.println("rightProjection:\n " + rightProjection);
0549: System.err.println("leftVpcToEc:\n" + leftVpcToEc);
0550: System.err.println("rightVpcToEc:\n" + rightVpcToEc);
0551: System.err.println("vpcToVworld:\n" + vpcToVworld);
0552: System.err.println("vworldToVpc:\n" + vworldToVpc);
0553:
0554: if ((J3dDebug.devPhase)
0555: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0556: int i;
0557: for (i = 0; i < leftFrustumPlanes.length; i++) {
0558: System.err.println("leftFrustumPlanes " + i
0559: + " is " + leftFrustumPlanes[i]);
0560: }
0561:
0562: for (i = 0; i < rightFrustumPlanes.length; i++) {
0563: System.err.println("rightFrustumPlanes " + i
0564: + " is " + rightFrustumPlanes[i]);
0565: }
0566: }
0567: }
0568:
0569: }
0570:
0571: private void computeCanvasInfo() {
0572: // Copy the screen width and height info into derived parameters
0573: physicalScreenWidth = screenViewCache.physicalScreenWidth;
0574: physicalScreenHeight = screenViewCache.physicalScreenHeight;
0575:
0576: screenWidth = screenViewCache.screenWidth;
0577: screenHeight = screenViewCache.screenHeight;
0578:
0579: metersPerPixelX = screenViewCache.metersPerPixelX;
0580: metersPerPixelY = screenViewCache.metersPerPixelY;
0581:
0582: // If a multi-screen virtual device (e.g. Xinerama) is being used,
0583: // then awtCanvasX and awtCanvasY are relative to the origin of that
0584: // virtual screen. Subtract the origin of the physical screen to
0585: // compute the origin in physical (image plate) coordinates.
0586: Rectangle screenBounds = canvas.graphicsConfiguration
0587: .getBounds();
0588: canvasX = awtCanvasX - screenBounds.x;
0589: canvasY = awtCanvasY - screenBounds.y;
0590:
0591: // Use awtCanvasWidth and awtCanvasHeight as reported.
0592: canvasWidth = awtCanvasWidth;
0593: canvasHeight = awtCanvasHeight;
0594:
0595: // Convert the window system ``pixel'' coordinate location and size
0596: // of the window into physical units (meters) and coordinate system.
0597:
0598: // Window width and Height in meters
0599: physicalWindowWidth = canvasWidth * metersPerPixelX;
0600: physicalWindowHeight = canvasHeight * metersPerPixelY;
0601:
0602: // Compute the 4 corners of the window in physical units
0603: physicalWindowXLeft = metersPerPixelX * (double) canvasX;
0604: physicalWindowYBottom = metersPerPixelY
0605: * (double) (screenHeight - canvasHeight - canvasY);
0606:
0607: physicalWindowXRight = physicalWindowXLeft
0608: + physicalWindowWidth;
0609: physicalWindowYTop = physicalWindowYBottom
0610: + physicalWindowHeight;
0611:
0612: // Cache the physical location of the center of the window
0613: physicalWindowCenter.x = physicalWindowXLeft
0614: + physicalWindowWidth / 2.0;
0615: physicalWindowCenter.y = physicalWindowYBottom
0616: + physicalWindowHeight / 2.0;
0617: physicalWindowCenter.z = 0.0;
0618:
0619: if ((J3dDebug.devPhase)
0620: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0621: System.err.println("Canvas pos = (" + awtCanvasX + ", "
0622: + awtCanvasY + "), size = " + awtCanvasWidth + "x"
0623: + awtCanvasHeight);
0624:
0625: System.err
0626: .println("Window LL corner (in plate coordinates): "
0627: + "("
0628: + physicalWindowXLeft
0629: + ","
0630: + physicalWindowYBottom + ")");
0631:
0632: System.err.println("Window size (in plate coordinates): "
0633: + "(" + physicalWindowWidth + ","
0634: + physicalWindowHeight + ")");
0635:
0636: System.err.println("Window center (in plate coordinates): "
0637: + physicalWindowCenter);
0638:
0639: System.err.println();
0640: }
0641:
0642: // Compute the view platform scale. This combines
0643: // the screen scale and the window scale.
0644: computeViewPlatformScale();
0645:
0646: if (!viewCache.compatibilityModeEnable
0647: && viewCache.viewPolicy == View.HMD_VIEW) {
0648: if (!useStereo) {
0649: switch (effectiveMonoscopicViewPolicy) {
0650: case View.CYCLOPEAN_EYE_VIEW:
0651: if (J3dDebug.devPhase) {
0652: System.err
0653: .println("CanvasViewCache : Should never reach here.\n"
0654: + "HMD_VIEW with CYCLOPEAN_EYE_VIEW is not allowed");
0655: }
0656: break;
0657:
0658: case View.LEFT_EYE_VIEW:
0659: headTrackerToLeftImagePlate
0660: .set(screenViewCache.headTrackerToLeftImagePlate);
0661: break;
0662:
0663: case View.RIGHT_EYE_VIEW:
0664: headTrackerToLeftImagePlate
0665: .set(screenViewCache.headTrackerToRightImagePlate);
0666: break;
0667: }
0668: } else {
0669: headTrackerToLeftImagePlate
0670: .set(screenViewCache.headTrackerToLeftImagePlate);
0671:
0672: headTrackerToRightImagePlate
0673: .set(screenViewCache.headTrackerToRightImagePlate);
0674: }
0675:
0676: }
0677: }
0678:
0679: // Routine to compute the center of coexistence coordinates in
0680: // imageplate coordinates. Also compute the scale from Vpc
0681: private void computeViewPlatformScale() {
0682: windowScale = screenScale = 1.0;
0683:
0684: if (!viewCache.compatibilityModeEnable) {
0685: switch (viewCache.screenScalePolicy) {
0686: case View.SCALE_SCREEN_SIZE:
0687: screenScale = physicalScreenWidth / 2.0;
0688: break;
0689: case View.SCALE_EXPLICIT:
0690: screenScale = viewCache.screenScale;
0691: break;
0692: }
0693:
0694: if (viewCache.windowResizePolicy == View.PHYSICAL_WORLD) {
0695: windowScale = physicalWindowWidth / physicalScreenWidth;
0696: }
0697: }
0698:
0699: viewPlatformScale = windowScale * screenScale;
0700: if ((J3dDebug.devPhase)
0701: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0702: System.err.println("viewCache.windowResizePolicy = "
0703: + viewCache.windowResizePolicy);
0704: System.err.println("physicalWindowWidth = "
0705: + physicalWindowWidth);
0706: System.err.println("physicalScreenWidth = "
0707: + physicalScreenWidth);
0708: System.err.println("windowScale = " + windowScale);
0709: System.err.println("screenScale = " + screenScale);
0710: System.err.println("viewPlatformScale = "
0711: + viewPlatformScale);
0712: }
0713: }
0714:
0715: private void cacheEyePosFixedField() {
0716: if ((J3dDebug.devPhase)
0717: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
0718: System.err.println("cacheEyePosFixedField:");
0719:
0720: // y is always the window center
0721: rightEyeInImagePlate.y = leftEyeInImagePlate.y = physicalWindowCenter.y;
0722:
0723: if (!useStereo) {
0724: switch (effectiveMonoscopicViewPolicy) {
0725: case View.CYCLOPEAN_EYE_VIEW:
0726: leftEyeInImagePlate.x = physicalWindowCenter.x;
0727: break;
0728:
0729: case View.LEFT_EYE_VIEW:
0730: leftEyeInImagePlate.x = physicalWindowCenter.x
0731: + viewCache.leftEyePosInHead.x;
0732: break;
0733:
0734: case View.RIGHT_EYE_VIEW:
0735: leftEyeInImagePlate.x = physicalWindowCenter.x
0736: + viewCache.rightEyePosInHead.x;
0737: break;
0738: }
0739:
0740: // Set right as well just in case
0741: rightEyeInImagePlate.x = leftEyeInImagePlate.x;
0742: } else {
0743: leftEyeInImagePlate.x = physicalWindowCenter.x
0744: + viewCache.leftEyePosInHead.x;
0745:
0746: rightEyeInImagePlate.x = physicalWindowCenter.x
0747: + viewCache.rightEyePosInHead.x;
0748: }
0749:
0750: //
0751: // Derive the z distance by constraining the field of view of the
0752: // window width to be constant.
0753: //
0754: rightEyeInImagePlate.z = leftEyeInImagePlate.z = physicalWindowWidth
0755: / (2.0 * Math.tan(viewCache.fieldOfView / 2.0));
0756:
0757: // Denote that eyes-in-ImagePlate fields have changed so that
0758: // these new values can be sent to the AudioDevice
0759: if (this .viewCache.view.soundScheduler != null)
0760: this .viewCache.view.soundScheduler
0761: .setListenerFlag(SoundScheduler.EYE_POSITIONS_CHANGED);
0762: }
0763:
0764: /**
0765: * Case of view eye position contrainted to center of window, but
0766: * with z distance from plate eye pos.
0767: */
0768: private void cacheEyePosWindowRelative() {
0769:
0770: if ((J3dDebug.devPhase)
0771: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
0772: System.err.println("cacheEyePosWindowRelative:");
0773:
0774: // y is always the window center
0775: rightEyeInImagePlate.y = leftEyeInImagePlate.y = physicalWindowCenter.y;
0776:
0777: // z is always from the existing eye pos
0778: rightEyeInImagePlate.z = leftEyeInImagePlate.z = leftManualEyeInImagePlate.z;
0779:
0780: if (!useStereo) {
0781:
0782: switch (effectiveMonoscopicViewPolicy) {
0783:
0784: case View.CYCLOPEAN_EYE_VIEW:
0785: leftEyeInImagePlate.x = physicalWindowCenter.x;
0786: break;
0787:
0788: case View.LEFT_EYE_VIEW:
0789: leftEyeInImagePlate.x = physicalWindowCenter.x
0790: + viewCache.leftEyePosInHead.x;
0791: break;
0792:
0793: case View.RIGHT_EYE_VIEW:
0794: leftEyeInImagePlate.x = physicalWindowCenter.x
0795: + viewCache.rightEyePosInHead.x;
0796: break;
0797:
0798: }
0799:
0800: // Set right as well just in case
0801: rightEyeInImagePlate.x = leftEyeInImagePlate.x;
0802:
0803: } else {
0804:
0805: leftEyeInImagePlate.x = physicalWindowCenter.x
0806: + viewCache.leftEyePosInHead.x;
0807:
0808: rightEyeInImagePlate.x = physicalWindowCenter.x
0809: + viewCache.rightEyePosInHead.x;
0810:
0811: // Right z gets its own value
0812: rightEyeInImagePlate.z = rightManualEyeInImagePlate.z;
0813: }
0814:
0815: // Denote that eyes-in-ImagePlate fields have changed so that
0816: // these new values can be sent to the AudioDevice
0817: if (this .viewCache.view.soundScheduler != null)
0818: this .viewCache.view.soundScheduler
0819: .setListenerFlag(SoundScheduler.EYE_POSITIONS_CHANGED);
0820: }
0821:
0822: /**
0823: * Common routine used when head tracking and when using manual
0824: * relative_to_screen eyepoint policy.
0825: */
0826: private void cacheEyePosScreenRelative(Point3d leftEye,
0827: Point3d rightEye) {
0828: if ((J3dDebug.devPhase)
0829: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
0830: System.err.println("cacheEyePosScreenRelative:");
0831:
0832: if (!useStereo) {
0833: switch (effectiveMonoscopicViewPolicy) {
0834:
0835: case View.CYCLOPEAN_EYE_VIEW:
0836: leftEyeInImagePlate.x = (leftEye.x + rightEye.x) / 2.0;
0837: leftEyeInImagePlate.y = (leftEye.y + rightEye.y) / 2.0;
0838: leftEyeInImagePlate.z = (leftEye.z + rightEye.z) / 2.0;
0839: break;
0840:
0841: case View.LEFT_EYE_VIEW:
0842: leftEyeInImagePlate.set(leftEye);
0843: break;
0844:
0845: case View.RIGHT_EYE_VIEW:
0846: leftEyeInImagePlate.set(rightEye);
0847: break;
0848:
0849: }
0850:
0851: // Set right as well just in case
0852: rightEyeInImagePlate.set(leftEyeInImagePlate);
0853: } else {
0854: leftEyeInImagePlate.set(leftEye);
0855: rightEyeInImagePlate.set(rightEye);
0856: }
0857:
0858: // Denote that eyes-in-ImagePlate fields have changed so that
0859: // these new values can be sent to the AudioDevice
0860: if (this .viewCache.view.soundScheduler != null)
0861: this .viewCache.view.soundScheduler
0862: .setListenerFlag(SoundScheduler.EYE_POSITIONS_CHANGED);
0863: }
0864:
0865: private void cacheEyePosCoexistenceRelative(
0866: Point3d leftManualEyeInCoexistence,
0867: Point3d rightManualEyeInCoexistence) {
0868:
0869: tPnt1.set(leftManualEyeInCoexistence);
0870: viewCache.coexistenceToTrackerBase.transform(tPnt1);
0871: screenViewCache.trackerBaseToImagePlate.transform(tPnt1);
0872: tPnt1.add(coexistenceCenter);
0873:
0874: tPnt2.set(rightManualEyeInCoexistence);
0875: viewCache.coexistenceToTrackerBase.transform(tPnt2);
0876: screenViewCache.trackerBaseToImagePlate.transform(tPnt2);
0877: tPnt2.add(coexistenceCenter);
0878:
0879: cacheEyePosScreenRelative(tPnt1, tPnt2);
0880:
0881: }
0882:
0883: /**
0884: * Compute the head-tracked eye position for the right and
0885: * left eyes.
0886: */
0887: private void computeTrackedEyePosition() {
0888: if ((J3dDebug.devPhase)
0889: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0890: System.err.println("computeTrackedEyePosition:");
0891: System.err.println("viewCache.headTrackerToTrackerBase:");
0892: System.err.println(viewCache.headTrackerToTrackerBase);
0893:
0894: System.err.println("viewCache.headToHeadTracker:");
0895: System.err.println(viewCache.headToHeadTracker);
0896: }
0897:
0898: if (viewCache.viewPolicy != View.HMD_VIEW) {
0899: if ((J3dDebug.devPhase)
0900: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0901: System.err
0902: .println("screenViewCache.trackerBaseToImagePlate:");
0903: System.err
0904: .println(screenViewCache.trackerBaseToImagePlate);
0905: }
0906:
0907: headToLeftImagePlate.set(coexistenceCenter);
0908: headToLeftImagePlate
0909: .mul(screenViewCache.trackerBaseToImagePlate);
0910: headToLeftImagePlate
0911: .mul(viewCache.headTrackerToTrackerBase);
0912: headToLeftImagePlate.mul(viewCache.headToHeadTracker);
0913:
0914: headToLeftImagePlate.transform(viewCache.leftEyePosInHead,
0915: leftTrackedEyeInImagePlate);
0916:
0917: headToLeftImagePlate.transform(viewCache.rightEyePosInHead,
0918: rightTrackedEyeInImagePlate);
0919: } else {
0920: if ((J3dDebug.devPhase)
0921: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0922: System.err.println("headTrackerToLeftImagePlate:");
0923: System.err.println(headTrackerToLeftImagePlate);
0924: }
0925:
0926: headToLeftImagePlate.mul(headTrackerToLeftImagePlate,
0927: viewCache.headToHeadTracker);
0928:
0929: headToLeftImagePlate.transform(viewCache.leftEyePosInHead,
0930: leftTrackedEyeInImagePlate);
0931:
0932: if (useStereo) {
0933: headToRightImagePlate.mul(headTrackerToRightImagePlate,
0934: viewCache.headToHeadTracker);
0935:
0936: headToRightImagePlate.transform(
0937: viewCache.rightEyePosInHead,
0938: rightTrackedEyeInImagePlate);
0939: } else { // HMD_VIEW with no stereo.
0940: headToLeftImagePlate.transform(
0941: viewCache.rightEyePosInHead,
0942: rightTrackedEyeInImagePlate);
0943: }
0944:
0945: }
0946:
0947: if ((J3dDebug.devPhase)
0948: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
0949: System.err.println("headToLeftImagePlate:");
0950: System.err.println(headToLeftImagePlate);
0951: System.err.println("headToRightImagePlate:");
0952: System.err.println(headToRightImagePlate);
0953:
0954: }
0955: }
0956:
0957: /**
0958: * Routine to cache the current eye position in image plate
0959: * coordinates.
0960: */
0961: private void cacheEyePosition() {
0962: if (viewCache.compatibilityModeEnable) {
0963: // XXXX: Compute compatibility mode eye position in ImagePlate???
0964: cacheEyePosScreenRelative(leftManualEyeInImagePlate,
0965: rightManualEyeInImagePlate);
0966: } else if (viewCache.getDoHeadTracking()) {
0967: computeTrackedEyePosition();
0968: cacheEyePosScreenRelative(leftTrackedEyeInImagePlate,
0969: rightTrackedEyeInImagePlate);
0970: } else {
0971: switch (viewCache.windowEyepointPolicy) {
0972:
0973: case View.RELATIVE_TO_FIELD_OF_VIEW:
0974: cacheEyePosFixedField();
0975: break;
0976:
0977: case View.RELATIVE_TO_WINDOW:
0978: cacheEyePosWindowRelative();
0979: break;
0980:
0981: case View.RELATIVE_TO_SCREEN:
0982: cacheEyePosScreenRelative(leftManualEyeInImagePlate,
0983: rightManualEyeInImagePlate);
0984: break;
0985:
0986: case View.RELATIVE_TO_COEXISTENCE:
0987: cacheEyePosCoexistenceRelative(
0988: viewCache.leftManualEyeInCoexistence,
0989: viewCache.rightManualEyeInCoexistence);
0990: break;
0991: }
0992: }
0993:
0994: // Compute center eye
0995: centerEyeInImagePlate.add(leftEyeInImagePlate,
0996: rightEyeInImagePlate);
0997: centerEyeInImagePlate.scale(0.5);
0998:
0999: // Compute derived value of nominalEyeOffsetFromNominalScreen
1000: if (viewCache.windowEyepointPolicy == View.RELATIVE_TO_FIELD_OF_VIEW)
1001: nominalEyeOffset = centerEyeInImagePlate.z;
1002: else
1003: nominalEyeOffset = viewCache.nominalEyeOffsetFromNominalScreen;
1004:
1005: if ((J3dDebug.devPhase)
1006: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
1007: System.err.println("leftEyeInImagePlate = "
1008: + leftEyeInImagePlate);
1009: System.err.println("rightEyeInImagePlate = "
1010: + rightEyeInImagePlate);
1011: System.err.println("centerEyeInImagePlate = "
1012: + centerEyeInImagePlate);
1013: System.err
1014: .println("nominalEyeOffset = " + nominalEyeOffset);
1015: System.err.println();
1016: }
1017: }
1018:
1019: private void computePlateToVworld() {
1020: if (viewCache.compatibilityModeEnable) {
1021: // XXXX: implement this correctly for compat mode
1022: leftPlateToVworld.setIdentity();
1023: vworldToLeftPlate.setIdentity();
1024: } else {
1025: try {
1026: leftPlateToVpc.invert(vpcToLeftPlate);
1027: } catch (SingularMatrixException e) {
1028: leftPlateToVpc.setIdentity();
1029: /*
1030: System.err.println("SingularMatrixException encountered when doing" +
1031: " leftPlateToVpc invert");
1032: */
1033: }
1034:
1035: leftPlateToVworld.mul(vpcToVworld, leftPlateToVpc);
1036: vworldToLeftPlate.mul(vpcToLeftPlate, vworldToVpc);
1037:
1038: if (useStereo) {
1039: try {
1040: rightPlateToVpc.invert(vpcToRightPlate);
1041: } catch (SingularMatrixException e) {
1042: rightPlateToVpc.setIdentity();
1043: /*
1044: System.err.println("SingularMatrixException encountered when doing" +
1045: " rightPlateToVpc invert");
1046: */
1047: }
1048:
1049: rightPlateToVworld.mul(vpcToVworld, rightPlateToVpc);
1050: vworldToRightPlate.mul(vpcToRightPlate, vworldToVpc);
1051:
1052: }
1053:
1054: if ((J3dDebug.devPhase)
1055: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1056: System.err.println("vpcToVworld:");
1057: System.err.println(vpcToVworld);
1058: System.err.println("vpcToLeftPlate:");
1059: System.err.println(vpcToLeftPlate);
1060: if (useStereo) {
1061: System.err.println("vpcToRightPlate:");
1062: System.err.println(vpcToRightPlate);
1063:
1064: }
1065:
1066: }
1067: }
1068:
1069: // Denote that eyes-in-ImagePlate fields have changed so that
1070: // these new values can be sent to the AudioDevice
1071: if (this .viewCache.view.soundScheduler != null)
1072: this .viewCache.view.soundScheduler
1073: .setListenerFlag(SoundScheduler.IMAGE_PLATE_TO_VWORLD_CHANGED);
1074: }
1075:
1076: private void computeHeadToVworld() {
1077: // Concatenate headToLeftImagePlate with leftPlateToVworld
1078:
1079: if (viewCache.compatibilityModeEnable) {
1080: // XXXX: implement this correctly for compat mode
1081: headToVworld.setIdentity();
1082: } else {
1083: headToVworld.mul(leftPlateToVworld, headToLeftImagePlate);
1084:
1085: if ((J3dDebug.devPhase)
1086: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1087: System.err.println("leftPlateToVworld:");
1088: System.err.println(leftPlateToVworld);
1089: System.err.println("headToLeftImagePlate:");
1090: System.err.println(headToLeftImagePlate);
1091: System.err.println("...gives -> headToVworld:");
1092: System.err.println(headToVworld);
1093: }
1094: }
1095:
1096: // Denote that eyes-in-ImagePlate fields have changed so that
1097: // these new values can be sent to the AudioDevice
1098: if (this .viewCache.view.soundScheduler != null)
1099: this .viewCache.view.soundScheduler
1100: .setListenerFlag(SoundScheduler.HEAD_TO_VWORLD_CHANGED);
1101: }
1102:
1103: private void computeVpcToCoexistence() {
1104: // Create a transform with the view platform to coexistence scale
1105: tMat1.set(viewPlatformScale);
1106:
1107: // XXXX: Is this really correct to ignore HMD?
1108:
1109: if (viewCache.viewPolicy != View.HMD_VIEW) {
1110: switch (viewCache.coexistenceCenterInPworldPolicy) {
1111: case View.NOMINAL_SCREEN:
1112: switch (viewCache.viewAttachPolicy) {
1113: case View.NOMINAL_SCREEN:
1114: tMat2.setIdentity();
1115: break;
1116: case View.NOMINAL_HEAD:
1117: tVec1.set(0.0, 0.0, nominalEyeOffset);
1118: tMat2.set(tVec1);
1119: break;
1120: case View.NOMINAL_FEET:
1121: tVec1.set(0.0,
1122: -viewCache.nominalEyeHeightFromGround,
1123: nominalEyeOffset);
1124: tMat2.set(tVec1);
1125: break;
1126: }
1127:
1128: break;
1129: case View.NOMINAL_HEAD:
1130: switch (viewCache.viewAttachPolicy) {
1131: case View.NOMINAL_SCREEN:
1132: tVec1.set(0.0, 0.0, -nominalEyeOffset);
1133: tMat2.set(tVec1);
1134: break;
1135: case View.NOMINAL_HEAD:
1136: tMat2.setIdentity();
1137: break;
1138: case View.NOMINAL_FEET:
1139: tVec1.set(0.0,
1140: -viewCache.nominalEyeHeightFromGround, 0.0);
1141: tMat2.set(tVec1);
1142: break;
1143: }
1144: break;
1145: case View.NOMINAL_FEET:
1146: switch (viewCache.viewAttachPolicy) {
1147: case View.NOMINAL_SCREEN:
1148: tVec1.set(0.0,
1149: viewCache.nominalEyeHeightFromGround,
1150: -nominalEyeOffset);
1151: tMat2.set(tVec1);
1152: break;
1153: case View.NOMINAL_HEAD:
1154: tVec1.set(0.0,
1155: viewCache.nominalEyeHeightFromGround, 0.0);
1156: tMat2.set(tVec1);
1157:
1158: break;
1159: case View.NOMINAL_FEET:
1160: tMat2.setIdentity();
1161: break;
1162: }
1163: break;
1164: }
1165:
1166: vpcToCoexistence.mul(tMat2, tMat1);
1167: } else {
1168: vpcToCoexistence.set(tMat1);
1169: }
1170:
1171: if ((J3dDebug.devPhase)
1172: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1173: System.err.println("vpcToCoexistence:");
1174: System.err.println(vpcToCoexistence);
1175: }
1176: }
1177:
1178: private void computeCoexistenceCenter() {
1179:
1180: if ((!viewCache.compatibilityModeEnable)
1181: && (viewCache.viewPolicy != View.HMD_VIEW)
1182: && (viewCache.coexistenceCenteringEnable)
1183: && (viewCache.coexistenceCenterInPworldPolicy == View.NOMINAL_SCREEN)) {
1184:
1185: // Compute the coexistence center in image plate coordinates
1186:
1187: // Image plate cordinates have their orgin in the lower
1188: // left hand corner of the CRT visiable raster.
1189: // The nominal coexistence center is at the *center* of
1190: // targeted area: either the window or screen, depending
1191: // on policy.
1192: if (viewCache.windowMovementPolicy == View.VIRTUAL_WORLD) {
1193: coexistenceCenter.x = physicalScreenWidth / 2.0;
1194: coexistenceCenter.y = physicalScreenHeight / 2.0;
1195: coexistenceCenter.z = 0.0;
1196: } else { // windowMovementPolicy == PHYSICAL_WORLD
1197: coexistenceCenter.x = physicalWindowCenter.x;
1198: coexistenceCenter.y = physicalWindowCenter.y;
1199: coexistenceCenter.z = 0.0;
1200: }
1201: } else {
1202: coexistenceCenter.set(0.0, 0.0, 0.0);
1203: }
1204:
1205: if (J3dDebug.devPhase) {
1206: if (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1) {
1207: System.err.println("coexistenceCenter = "
1208: + coexistenceCenter);
1209: }
1210: }
1211: }
1212:
1213: private void computeCoexistenceToPlate() {
1214: if (viewCache.compatibilityModeEnable) {
1215: // XXXX: implement this correctly
1216: coexistenceToLeftPlate.setIdentity();
1217: return;
1218: }
1219:
1220: if (viewCache.viewPolicy != View.HMD_VIEW) {
1221: coexistenceToLeftPlate.set(coexistenceCenter);
1222: coexistenceToLeftPlate
1223: .mul(screenViewCache.trackerBaseToImagePlate);
1224: coexistenceToLeftPlate
1225: .mul(viewCache.coexistenceToTrackerBase);
1226:
1227: if (useStereo) {
1228: coexistenceToRightPlate.set(coexistenceToLeftPlate);
1229: }
1230: } else {
1231: coexistenceToLeftPlate.mul(headTrackerToLeftImagePlate,
1232: viewCache.trackerBaseToHeadTracker);
1233: coexistenceToLeftPlate
1234: .mul(viewCache.coexistenceToTrackerBase);
1235:
1236: if (useStereo) {
1237: coexistenceToRightPlate.mul(
1238: headTrackerToRightImagePlate,
1239: viewCache.trackerBaseToHeadTracker);
1240: coexistenceToRightPlate
1241: .mul(viewCache.coexistenceToTrackerBase);
1242: }
1243: }
1244:
1245: if ((J3dDebug.devPhase)
1246: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1247: System.err.println("coexistenceToLeftPlate:");
1248: System.err.println(coexistenceToLeftPlate);
1249: if (useStereo) {
1250: System.err.println("coexistenceToRightPlate:");
1251: System.err.println(coexistenceToRightPlate);
1252:
1253: }
1254: }
1255: }
1256:
1257: /**
1258: * Computes the viewing matrices.
1259: *
1260: * computeView computes the following:
1261: *
1262: * <ul>
1263: * left (& right) eye viewing matrices (only left is valid for mono view)
1264: * </ul>
1265: *
1266: * This call works for both fixed screen and HMD displays.
1267: */
1268: private void computeView(boolean doInfinite) {
1269: int i, j;
1270: int backClipPolicy;
1271: double Fl, Fr, B, scale, backClipDistance;
1272:
1273: // compute scale used for transforming clip and fog distances
1274: vworldToCoexistenceScale = vworldToVpc.getDistanceScale()
1275: * vpcToCoexistence.getDistanceScale();
1276: if (doInfinite) {
1277: infVworldToCoexistenceScale = infVworldToVpc
1278: .getDistanceScale()
1279: * vpcToCoexistence.getDistanceScale();
1280: }
1281:
1282: if ((J3dDebug.devPhase)
1283: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1284: System.err.println("vworldToCoexistenceScale = "
1285: + vworldToCoexistenceScale);
1286: }
1287:
1288: // compute coexistenceToVworld transform -- dirty bit candidate!!
1289: tempTrans.mul(viewCache.coexistenceToTrackerBase,
1290: vpcToCoexistence);
1291: vworldToTrackerBase.mul(tempTrans, vworldToVpc);
1292:
1293: // If we are in compatibility mode, compute the view and
1294: // projection matrices accordingly
1295: if (viewCache.compatibilityModeEnable) {
1296: leftProjection.set(viewCache.compatLeftProjection);
1297: leftVpcToEc.set(viewCache.compatVpcToEc);
1298:
1299: if ((J3dDebug.devPhase)
1300: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
1301: System.err.println("Left projection and view matrices");
1302: System.err.println("ecToCc (leftProjection) :");
1303: System.err.println(leftProjection);
1304: System.err.println("vpcToEc:");
1305: System.err.println(leftVpcToEc);
1306: }
1307:
1308: computeFrustumPlanes(leftProjection, leftVpcToEc,
1309: leftFrustumPlanes, leftFrustumPoints,
1310: leftCcToVworld);
1311:
1312: if (useStereo) {
1313: rightProjection.set(viewCache.compatRightProjection);
1314: rightVpcToEc.set(viewCache.compatVpcToEc);
1315:
1316: if ((J3dDebug.devPhase)
1317: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1)) {
1318: System.err
1319: .println("Right projection and view matrices");
1320: System.err.println("ecToCc:");
1321: System.err.println("vpcToEc:");
1322: System.err.println(rightVpcToEc);
1323: }
1324:
1325: computeFrustumPlanes(rightProjection, rightVpcToEc,
1326: rightFrustumPlanes, rightFrustumPoints,
1327: rightCcToVworld);
1328: }
1329:
1330: return;
1331: }
1332:
1333: //
1334: // The clipping plane distances are set from the internal policy.
1335: //
1336: // Note that the plane distance follows the standard Z axis
1337: // convention, e.g. negative numbers further away.
1338: // Note that for policy from eye, the distance is negative in
1339: // the direction of z in front of the eye.
1340: // Note that for policy from screen, the distance is negative for
1341: // locations behind the screen, and positive in front.
1342: //
1343: // The distance attributes are measured either in physical (plate)
1344: // units, or vworld units.
1345: //
1346:
1347: // Compute scale factor for front clip plane computation
1348: if (viewCache.frontClipPolicy == View.VIRTUAL_EYE
1349: || viewCache.frontClipPolicy == View.VIRTUAL_SCREEN) {
1350: scale = vworldToCoexistenceScale;
1351: } else {
1352: scale = windowScale;
1353: }
1354:
1355: // Set left and right front clipping plane distances.
1356: if (viewCache.frontClipPolicy == View.PHYSICAL_EYE
1357: || viewCache.frontClipPolicy == View.VIRTUAL_EYE) {
1358: Fl = leftEyeInImagePlate.z + scale
1359: * -viewCache.frontClipDistance;
1360: Fr = rightEyeInImagePlate.z + scale
1361: * -viewCache.frontClipDistance;
1362: } else {
1363: Fl = scale * -viewCache.frontClipDistance;
1364: Fr = scale * -viewCache.frontClipDistance;
1365: }
1366:
1367: // if there is an active clip node, use it and ignore the view's
1368: // backclip
1369: if ((renderBin != null) && (renderBin.backClipActive)) {
1370: backClipPolicy = View.VIRTUAL_EYE;
1371: backClipDistance = renderBin.backClipDistanceInVworld;
1372: } else {
1373: backClipPolicy = viewCache.backClipPolicy;
1374: backClipDistance = viewCache.backClipDistance;
1375: }
1376:
1377: // Compute scale factor for rear clip plane computation
1378: if (backClipPolicy == View.VIRTUAL_EYE
1379: || backClipPolicy == View.VIRTUAL_SCREEN) {
1380: scale = vworldToCoexistenceScale;
1381: } else {
1382: scale = windowScale;
1383: }
1384:
1385: // Set left and right rear clipping plane distnaces.
1386: if (backClipPolicy == View.PHYSICAL_EYE
1387: || backClipPolicy == View.VIRTUAL_EYE) {
1388: // Yes, left for both left and right rear.
1389: B = leftEyeInImagePlate.z + scale * -backClipDistance;
1390: } else {
1391: B = scale * -backClipDistance;
1392: }
1393:
1394: // XXXX: Can optimize for HMD case.
1395: if (true /*viewCache.viewPolicy != View.HMD_VIEW*/) {
1396:
1397: // Call buildProjView to build the projection and view matrices.
1398:
1399: if ((J3dDebug.devPhase)
1400: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1401: System.err.println("Left projection and view matrices");
1402: System.err.println("Fl " + Fl + " B " + B);
1403: System.err.println("leftEyeInImagePlate\n"
1404: + leftEyeInImagePlate);
1405: System.err.println("Before : leftProjection\n"
1406: + leftProjection);
1407: System.err
1408: .println("Before leftVpcToEc\n" + leftVpcToEc);
1409: }
1410:
1411: buildProjView(leftEyeInImagePlate, coexistenceToLeftPlate,
1412: vpcToLeftPlate, Fl, B, leftProjection, leftVpcToEc,
1413: false);
1414:
1415: if ((J3dDebug.devPhase)
1416: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1417: System.err.println("After : leftProjection\n"
1418: + leftProjection);
1419: System.err.println("After leftVpcToEc\n" + leftVpcToEc);
1420: }
1421:
1422: computeFrustumPlanes(leftProjection, leftVpcToEc,
1423: leftFrustumPlanes, leftFrustumPoints,
1424: leftCcToVworld);
1425:
1426: if (useStereo) {
1427: if ((J3dDebug.devPhase)
1428: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2))
1429: System.err
1430: .println("Right projection and view matrices");
1431:
1432: buildProjView(rightEyeInImagePlate,
1433: coexistenceToRightPlate, vpcToRightPlate, Fr,
1434: B, rightProjection, rightVpcToEc, false);
1435:
1436: computeFrustumPlanes(rightProjection, rightVpcToEc,
1437: rightFrustumPlanes, rightFrustumPoints,
1438: rightCcToVworld);
1439: }
1440:
1441: //
1442: // Now to compute the left (& right) eye (and infinite)
1443: // viewing matrices.
1444: if (doInfinite) {
1445: // Call buildProjView separately for infinite view
1446: buildProjView(leftEyeInImagePlate,
1447: coexistenceToLeftPlate, vpcToLeftPlate,
1448: leftEyeInImagePlate.z - 0.05,
1449: leftEyeInImagePlate.z - 1.5, infLeftProjection,
1450: infLeftVpcToEc, true);
1451:
1452: if (useStereo) {
1453: buildProjView(rightEyeInImagePlate,
1454: coexistenceToRightPlate, vpcToRightPlate,
1455: rightEyeInImagePlate.z - 0.05,
1456: rightEyeInImagePlate.z - 1.5,
1457: infRightProjection, infRightVpcToEc, true);
1458:
1459: }
1460: }
1461: }
1462: // XXXX: The following code has never been ported
1463: // else {
1464: // Point3d cen_eye;
1465: //
1466: // // HMD case. Just concatenate the approprate matrices together.
1467: // // Additional work just for now
1468: //
1469: // compute_lr_plate_to_cc( &cen_eye, Fl, B, 0, &vb, 0);
1470: //
1471: // if(useStereo) {
1472: // mat_mul_dpt(&right_eye_pos_in_head,
1473: // head_to_right_plate, &cen_eye);
1474: // compute_lr_plate_to_cc( &cen_eye, Fr, B,
1475: // 1, &vb, 0);
1476: // }
1477: //
1478: // // Make sure that coexistence_to_plate is current.
1479: // // (It is usually constant for fixed plates, always varies for HMDs.)
1480: // // For HMD case, computes finial matrices that will be used.
1481: // //
1482: // computeCoexistenceToPlate();
1483: // }
1484:
1485: }
1486:
1487: /**
1488: * Debugging routine to analyze the projection matrix.
1489: */
1490: private void analyzeProjection(Transform3D p, double xMax) {
1491: if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION)
1492: System.err.println("PARALLEL_PROJECTION =");
1493: else
1494: System.err.println("PERSPECTIVE_PROJECTION =");
1495:
1496: System.err.println(p);
1497:
1498: double projectionPlaneZ = ((p.mat[0] * xMax + p.mat[3] - p.mat[15]) / (p.mat[14] - p.mat[2]));
1499:
1500: System.err.println("projection plane at z = "
1501: + projectionPlaneZ);
1502: }
1503:
1504: /**
1505: * buildProjView creates a projection and viewing matrix.
1506: *
1507: * Inputs:
1508: * ep : eye point, in plate coordinates
1509: * coe2Plate : matrix from coexistence to image plate.
1510: * F, B : front, back clipping planes, in plate coordinates
1511: * doInfinite : flag to indicate ``at infinity'' view desired
1512: *
1513: * Output:
1514: * vpc2Plate : matric from vpc to image plate.
1515: * ecToCc : projection matrix from Eye Coordinates (EC)
1516: * to Clipping Coordinates (CC)
1517: * vpcToEc : view matrix from ViewPlatform Coordinates (VPC)
1518: * to Eye Coordinates (EC)
1519: */
1520: private void buildProjView(Point3d ep, Transform3D coe2Plate,
1521: Transform3D vpc2Plate, double F, double B,
1522: Transform3D ecToCc, Transform3D vpcToEc, boolean doInfinite) {
1523:
1524: // Lx,Ly Hx,Hy will be adjusted window boundaries
1525: double Lx, Hx, Ly, Hy;
1526: Lx = physicalWindowXLeft;
1527: Hx = physicalWindowXRight;
1528: Ly = physicalWindowYBottom;
1529: Hy = physicalWindowYTop;
1530:
1531: ecToCc.setIdentity();
1532:
1533: // XXXX: we have no concept of glass correction in the Java 3D API
1534: //
1535: // Correction in apparent 3D position of window due to glass/CRT
1536: // and spherical/cylinderical curvarure of CRT.
1537: // This boils down to producing modified values of Lx Ly Hx Hy
1538: // and is different for hot spot vs. window center corrections.
1539: //
1540: /* XXXX:
1541: double cx, cy;
1542: if(viewPolicy != HMD_VIEW && enable_crt_glass_correction) {
1543: if (correction_point == CORRECTION_POINT_WINDOW_CENTER) {
1544: correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy;
1545: correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy;
1546: }
1547: else { // must be hot spot correction
1548: // Not real code yet, for now just do same as above.
1549: correct_crt( ep, Lx, Ly, &cx, &cy); Lx = cx; Ly = cy;
1550: correct_crt( ep, Hx, Hy, &cx, &cy); Hx = cx; Hy = cy;
1551: }
1552: }
1553: */
1554:
1555: if ((J3dDebug.devPhase)
1556: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1557: System.err.println("ep = " + ep);
1558: System.err.println("Lx = " + Lx + ", Hx = " + Hx);
1559: System.err.println("Ly = " + Ly + ", Hy = " + Hy);
1560: System.err.println("F = " + F + ", B = " + B);
1561: }
1562:
1563: // Compute the proper projection equation. Note that we
1564: // do this in two steps: first we generate ImagePlateToCc,
1565: // then we translate this by EcToPlate, resulting in a
1566: // projection from EctoCc.
1567: //
1568: // A more efficient (and more accurate) approach would be to
1569: // modify the equations below to directly project from EcToCc.
1570:
1571: if (viewCache.projectionPolicy == View.PARALLEL_PROJECTION) {
1572: double inv_dx, inv_dy, inv_dz;
1573: inv_dx = 1.0 / (Hx - Lx);
1574: inv_dy = 1.0 / (Hy - Ly);
1575: inv_dz = 1.0 / (F - B);
1576:
1577: ecToCc.mat[0] = 2.0 * inv_dx;
1578: ecToCc.mat[3] = -(Hx + Lx) * inv_dx;
1579: ecToCc.mat[5] = 2.0 * inv_dy;
1580: ecToCc.mat[7] = -(Hy + Ly) * inv_dy;
1581: ecToCc.mat[10] = 2.0 * inv_dz;
1582: ecToCc.mat[11] = -(F + B) * inv_dz;
1583: } else {
1584: double sxy, rzb, inv_dx, inv_dy;
1585:
1586: inv_dx = 1.0 / (Hx - Lx);
1587: inv_dy = 1.0 / (Hy - Ly);
1588: rzb = 1.0 / (ep.z - B);
1589: sxy = ep.z * rzb;
1590:
1591: ecToCc.mat[0] = sxy * 2.0 * inv_dx;
1592: ecToCc.mat[5] = sxy * 2.0 * inv_dy;
1593:
1594: ecToCc.mat[2] = rzb * (Hx + Lx - 2.0 * ep.x) * inv_dx;
1595: ecToCc.mat[6] = rzb * (Hy + Ly - 2.0 * ep.y) * inv_dy;
1596: ecToCc.mat[10] = rzb * (B + F - 2 * ep.z) / (B - F);
1597: ecToCc.mat[14] = -rzb;
1598:
1599: ecToCc.mat[3] = sxy * (-Hx - Lx) * inv_dx;
1600: ecToCc.mat[7] = sxy * (-Hy - Ly) * inv_dy;
1601: ecToCc.mat[11] = rzb
1602: * (B - ep.z - B * (B + F - 2 * ep.z) / (B - F));
1603: ecToCc.mat[15] = sxy;
1604: }
1605:
1606: // Since we set the matrix elements ourselves, we need to set the
1607: // type field. A value of 0 means a non-affine matrix.
1608: ecToCc.setOrthoDirtyBit();
1609:
1610: // EC to ImagePlate matrix is a simple translation.
1611: tVec1.set(ep.x, ep.y, ep.z);
1612: tMat1.set(tVec1);
1613: ecToCc.mul(tMat1);
1614:
1615: if ((J3dDebug.devPhase)
1616: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1617: System.err.println("ecToCc:");
1618: analyzeProjection(ecToCc, Hx);
1619: }
1620:
1621: if (!doInfinite) {
1622: // View matrix is:
1623: // [plateToEc] [coexistence_to_plate] [vpc_to_coexistence]
1624: // where vpc_to_coexistence includes the viewPlatformScale
1625:
1626: // First compute ViewPlatform to Plate
1627: vpc2Plate.mul(coe2Plate, vpcToCoexistence);
1628:
1629: // ImagePlate to EC matrix is a simple translation.
1630: tVec1.set(-ep.x, -ep.y, -ep.z);
1631: tMat1.set(tVec1);
1632: vpcToEc.mul(tMat1, vpc2Plate);
1633:
1634: if ((J3dDebug.devPhase)
1635: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1636: System.err.println("vpcToEc:");
1637: System.err.println(vpcToEc);
1638: }
1639: } else {
1640: // Final infinite composite is:
1641: // [coexistence_to_eye] [vpc_to_coexistence (vom)]
1642: // (does vworld_to_coe_scale_factor get used here??? )
1643: //
1644: // The method is to relocate the coexistence org centered on
1645: // the eye rather than the window center (via coexistence_to_eye).
1646: // Computationaly simpler simplifed equation form may exist.
1647:
1648: // coexistence to eye is a simple translation.
1649: /*
1650: tVec1.set(ep.x, ep.y, ep.z);
1651: tMat1.set(tVec1);
1652: vpcToEc.mul(tMat1, vpcToCoexistence);
1653: // First compute ViewPlatform to Plate
1654: vpcToPlate.mul(coexistenceToPlatevpcToPlate, vpcToCoexistence);
1655: */
1656:
1657: // ImagePlate to EC matrix is a simple translation.
1658: tVec1.set(-ep.x, -ep.y, -ep.z);
1659: tMat1.set(tVec1);
1660: tMat1.mul(tMat1, vpc2Plate);
1661: tMat1.getRotation(vpcToEc); // use only rotation component of transform
1662:
1663: }
1664:
1665: }
1666:
1667: /**
1668: * Compute the plane equations for the frustum in ViewPlatform
1669: * coordinates, plus its viewing frustum points. ccToVworld will
1670: * be cached - used by Canavs3D.getInverseVworldProjection().
1671: */
1672: private void computeFrustumPlanes(Transform3D ecToCc,
1673: Transform3D vpcToEc, Vector4d[] frustumPlanes,
1674: Point4d[] frustumPoints, Transform3D ccToVworld) {
1675:
1676: // Compute the inverse of the Vworld to Cc transform. This
1677: // gives us the Cc to Vworld transform.
1678: tMat2.mul(ecToCc, vpcToEc);
1679: ccToVworld.mul(tMat2, vworldToVpc);
1680: // System.err.println("ccToVworld = " + ccToVworld);
1681: try {
1682: ccToVworld.invert();
1683: } catch (SingularMatrixException e) {
1684: ccToVworld.setIdentity();
1685: // System.err.println("SingularMatrixException encountered when doing invert in computeFrustumPlanes");
1686: }
1687:
1688: if ((J3dDebug.devPhase)
1689: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_2)) {
1690: Transform3D t = new Transform3D();
1691: t.mul(ecToCc, vpcToEc);
1692: t.mul(vworldToVpc);
1693: System.err.println("\nvworldToCc = " + t);
1694: System.err.println("ccToVworld = " + ccToVworld);
1695: t.mul(ccToVworld);
1696: System.err.println("vworldToCc * ccToVworld = " + t);
1697: }
1698:
1699: // Transform the 8 corners of the viewing frustum into Vpc
1700: frustumPoints[0].set(-1.0, -1.0, 1.0, 1.0); // lower-left-front
1701: frustumPoints[1].set(-1.0, 1.0, 1.0, 1.0); // upper-left-front
1702: frustumPoints[2].set(1.0, 1.0, 1.0, 1.0); // upper-right-front
1703: frustumPoints[3].set(1.0, -1.0, 1.0, 1.0); // lower-right-front
1704: frustumPoints[4].set(-1.0, -1.0, -1.0, 1.0); // lower-left-back
1705: frustumPoints[5].set(-1.0, 1.0, -1.0, 1.0); // upper-left-back
1706: frustumPoints[6].set(1.0, 1.0, -1.0, 1.0); // upper-right-back
1707: frustumPoints[7].set(1.0, -1.0, -1.0, 1.0); // lower-right-back
1708:
1709: ccToVworld.get(tMatrix);
1710: int i;
1711: for (i = 0; i < frustumPoints.length; i++) {
1712: tMatrix.transform(frustumPoints[i]);
1713: double w_inv = 1.0 / frustumPoints[i].w;
1714: frustumPoints[i].x *= w_inv;
1715: frustumPoints[i].y *= w_inv;
1716: frustumPoints[i].z *= w_inv;
1717: }
1718:
1719: // Now compute the 6 plane equations
1720: // left
1721: computePlaneEq(frustumPoints[0], frustumPoints[4],
1722: frustumPoints[5], frustumPoints[1], frustumPlanes[0]);
1723:
1724: // right
1725: computePlaneEq(frustumPoints[3], frustumPoints[2],
1726: frustumPoints[6], frustumPoints[7], frustumPlanes[1]);
1727:
1728: // top
1729: computePlaneEq(frustumPoints[1], frustumPoints[5],
1730: frustumPoints[6], frustumPoints[2], frustumPlanes[2]);
1731:
1732: // bottom
1733: computePlaneEq(frustumPoints[0], frustumPoints[3],
1734: frustumPoints[7], frustumPoints[4], frustumPlanes[3]);
1735:
1736: // front
1737: computePlaneEq(frustumPoints[0], frustumPoints[1],
1738: frustumPoints[2], frustumPoints[3], frustumPlanes[4]);
1739:
1740: // back
1741: computePlaneEq(frustumPoints[4], frustumPoints[7],
1742: frustumPoints[6], frustumPoints[5], frustumPlanes[5]);
1743:
1744: //System.err.println("left plane = " + frustumPlanes[0]);
1745: //System.err.println("right plane = " + frustumPlanes[1]);
1746: //System.err.println("top plane = " + frustumPlanes[2]);
1747: //System.err.println("bottom plane = " + frustumPlanes[3]);
1748: //System.err.println("front plane = " + frustumPlanes[4]);
1749: //System.err.println("back plane = " + frustumPlanes[5]);
1750: }
1751:
1752: private void computePlaneEq(Point4d p1, Point4d p2, Point4d p3,
1753: Point4d p4, Vector4d planeEq) {
1754: tVec1.x = p3.x - p1.x;
1755: tVec1.y = p3.y - p1.y;
1756: tVec1.z = p3.z - p1.z;
1757:
1758: tVec2.x = p2.x - p1.x;
1759: tVec2.y = p2.y - p1.y;
1760: tVec2.z = p2.z - p1.z;
1761:
1762: tVec3.cross(tVec2, tVec1);
1763: tVec3.normalize();
1764: planeEq.x = tVec3.x;
1765: planeEq.y = tVec3.y;
1766: planeEq.z = tVec3.z;
1767: planeEq.w = -(planeEq.x * p1.x + planeEq.y * p1.y + planeEq.z
1768: * p1.z);
1769: }
1770:
1771: // Get methods for returning derived data values.
1772: // Eventually, these get functions will cause some of the parameters
1773: // to be lazily evaluated.
1774: //
1775: // NOTE: in the case of Transform3D, and Tuple objects, a reference
1776: // to the actual derived data is returned. In these cases, the caller
1777: // must ensure that the returned data is not modified.
1778: //
1779: // NOTE: the snapshot and computeDerivedData methods are synchronized.
1780: // Callers of the following methods that can run asynchronously with
1781: // the renderer must call these methods and copy the data from within
1782: // a synchronized block on the canvas view cache object.
1783:
1784: int getCanvasX() {
1785: return canvasX;
1786: }
1787:
1788: int getCanvasY() {
1789: return canvasY;
1790: }
1791:
1792: int getCanvasWidth() {
1793: return canvasWidth;
1794: }
1795:
1796: int getCanvasHeight() {
1797: return canvasHeight;
1798: }
1799:
1800: double getPhysicalWindowWidth() {
1801: return physicalWindowWidth;
1802: }
1803:
1804: double getPhysicalWindowHeight() {
1805: return physicalWindowHeight;
1806: }
1807:
1808: boolean getUseStereo() {
1809: return useStereo;
1810: }
1811:
1812: Transform3D getLeftProjection() {
1813: return leftProjection;
1814: }
1815:
1816: Transform3D getRightProjection() {
1817: return rightProjection;
1818: }
1819:
1820: Transform3D getLeftVpcToEc() {
1821: return leftVpcToEc;
1822: }
1823:
1824: Transform3D getRightVpcToEc() {
1825: return rightVpcToEc;
1826: }
1827:
1828: Transform3D getLeftEcToVpc() {
1829: return leftEcToVpc;
1830: }
1831:
1832: Transform3D getRightEcToVpc() {
1833: return rightEcToVpc;
1834: }
1835:
1836: Transform3D getInfLeftProjection() {
1837: return infLeftProjection;
1838: }
1839:
1840: Transform3D getInfRightProjection() {
1841: return infLeftProjection;
1842: }
1843:
1844: Transform3D getInfLeftVpcToEc() {
1845: return infLeftVpcToEc;
1846: }
1847:
1848: Transform3D getInfRightVpcToEc() {
1849: return infRightVpcToEc;
1850: }
1851:
1852: Transform3D getInfLeftEcToVpc() {
1853: return infLeftEcToVpc;
1854: }
1855:
1856: Transform3D getInfgRightEcToVpc() {
1857: return infRightEcToVpc;
1858: }
1859:
1860: Transform3D getInfVworldToVpc() {
1861: return infVworldToVpc;
1862: }
1863:
1864: Transform3D getLeftCcToVworld() {
1865: return leftCcToVworld;
1866: }
1867:
1868: Transform3D getRightCcToVworld() {
1869: return rightCcToVworld;
1870: }
1871:
1872: Transform3D getImagePlateToVworld() {
1873: // XXXX: Document -- This will return the transform of left plate.
1874: return leftPlateToVworld;
1875: }
1876:
1877: Transform3D getLastVworldToImagePlate() {
1878: // XXXX: Document -- This will return the transform of left plate.
1879: return lastVworldToLeftPlate;
1880:
1881: }
1882:
1883: Transform3D getVworldToImagePlate() {
1884: // XXXX: Document -- This will return the transform of left plate.
1885: return vworldToLeftPlate;
1886: }
1887:
1888: Transform3D getVworldToTrackerBase() {
1889: return vworldToTrackerBase;
1890: }
1891:
1892: double getVworldToCoexistenceScale() {
1893: return vworldToCoexistenceScale;
1894: }
1895:
1896: double getInfVworldToCoexistenceScale() {
1897: return infVworldToCoexistenceScale;
1898: }
1899:
1900: Point3d getLeftEyeInImagePlate() {
1901: return leftEyeInImagePlate;
1902: }
1903:
1904: Point3d getRightEyeInImagePlate() {
1905: return rightEyeInImagePlate;
1906: }
1907:
1908: Point3d getCenterEyeInImagePlate() {
1909: return centerEyeInImagePlate;
1910: }
1911:
1912: Transform3D getHeadToVworld() {
1913: return headToVworld;
1914: }
1915:
1916: Transform3D getVpcToVworld() {
1917: return vpcToVworld;
1918: }
1919:
1920: Transform3D getVworldToVpc() {
1921: return vworldToVpc;
1922: }
1923:
1924: // Transform the specified X point in AWT window-relative coordinates
1925: // to image plate coordinates
1926: double getWindowXInImagePlate(double x) {
1927: double xScreen = x + (double) canvasX;
1928: return metersPerPixelX * xScreen;
1929: }
1930:
1931: // Transform the specified Y point in AWT window-relative coordinates
1932: // to image plate coordinates
1933: double getWindowYInImagePlate(double y) {
1934: double yScreen = y + (double) canvasY;
1935: return metersPerPixelY
1936: * ((double) (screenHeight - 1) - yScreen);
1937: }
1938:
1939: Vector4d[] getLeftFrustumPlanesInVworld() {
1940: return leftFrustumPlanes;
1941: }
1942:
1943: Vector4d[] getRightFrustumPlanesInVworld() {
1944: return rightFrustumPlanes;
1945: }
1946:
1947: void getPixelLocationInImagePlate(double x, double y, double z,
1948: Point3d imagePlatePoint) {
1949:
1950: double screenx = (x + canvasX) * metersPerPixelX;
1951: double screeny = (screenHeight - 1 - canvasY - y)
1952: * metersPerPixelY;
1953:
1954: if ((viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION)
1955: && (centerEyeInImagePlate.z != 0)) {
1956: double zScale = 1.0 - z / centerEyeInImagePlate.z;
1957: imagePlatePoint.x = (screenx - centerEyeInImagePlate.x)
1958: * zScale + centerEyeInImagePlate.x;
1959: imagePlatePoint.y = (screeny - centerEyeInImagePlate.y)
1960: * zScale + centerEyeInImagePlate.y;
1961: } else {
1962: imagePlatePoint.x = screenx;
1963: imagePlatePoint.y = screeny;
1964: }
1965: imagePlatePoint.z = z;
1966: }
1967:
1968: /**
1969: * Projects the specified point from image plate coordinates
1970: * into AWT pixel coordinates.
1971: */
1972: void getPixelLocationFromImagePlate(Point3d imagePlatePoint,
1973: Point2d pixelLocation) {
1974:
1975: double screenX, screenY;
1976:
1977: if (viewCache.projectionPolicy == View.PERSPECTIVE_PROJECTION) {
1978: // get the vector from centerEyeInImagePlate to imagePlatePoint
1979: tVec1.sub(imagePlatePoint, centerEyeInImagePlate);
1980:
1981: // Scale this vector to make it end at the projection plane.
1982: // Scale is ratio :
1983: // eye->imagePlate Plane dist / eye->imagePlatePt dist
1984: // eye dist to plane is eyePos.z (eye is in +z space)
1985: // image->eye dist is -tVec1.z (image->eye is in -z dir)
1986: //System.err.println("eye dist = " + (centerEyeInImagePlate.z));
1987: //System.err.println("image dist = " + (-tVec1.z));
1988: if (tVec1.z != 0) {
1989: double zScale = centerEyeInImagePlate.z / (-tVec1.z);
1990: screenX = centerEyeInImagePlate.x + tVec1.x * zScale;
1991: screenY = centerEyeInImagePlate.y + tVec1.y * zScale;
1992:
1993: } else {
1994: screenX = imagePlatePoint.x;
1995: screenY = imagePlatePoint.y;
1996: }
1997:
1998: } else {
1999: screenX = imagePlatePoint.x;
2000: screenY = imagePlatePoint.y;
2001: }
2002:
2003: //System.err.println("screenX = " + screenX + " screenY = " + screenY);
2004: // Note: screenPt is in image plate coords, at z=0
2005:
2006: // Transform from image plate coords to screen coords
2007: pixelLocation.x = (screenX / screenViewCache.metersPerPixelX)
2008: - canvasX;
2009: pixelLocation.y = screenViewCache.screenHeight - 1
2010: - (screenY / screenViewCache.metersPerPixelY) - canvasY;
2011: //System.err.println("pixelLocation = " + pixelLocation);
2012: }
2013:
2014: /**
2015: * Constructs and initializes a CanvasViewCache object.
2016: * Note that the canvas, screen, screenCache, view, and
2017: * viewCache parameters are all fixed at construction time
2018: * and must be non-null.
2019: */
2020: CanvasViewCache(Canvas3D canvas, ScreenViewCache screenViewCache,
2021: ViewCache viewCache) {
2022:
2023: this .canvas = canvas;
2024: this .screenViewCache = screenViewCache;
2025: this .viewCache = viewCache;
2026:
2027: // Set up the initial plane equations
2028: int i;
2029: for (i = 0; i < leftFrustumPlanes.length; i++) {
2030: leftFrustumPlanes[i] = new Vector4d();
2031: rightFrustumPlanes[i] = new Vector4d();
2032: }
2033:
2034: for (i = 0; i < leftFrustumPoints.length; i++) {
2035: leftFrustumPoints[i] = new Point4d();
2036: rightFrustumPoints[i] = new Point4d();
2037: }
2038:
2039: // canvas is null in Renderer copyOfCvCache
2040: if (canvas != null) {
2041: leftEyeInImagePlate.set(canvas.leftManualEyeInImagePlate);
2042: rightEyeInImagePlate.set(canvas.rightManualEyeInImagePlate);
2043: centerEyeInImagePlate.add(leftEyeInImagePlate,
2044: rightEyeInImagePlate);
2045: centerEyeInImagePlate.scale(0.5);
2046: }
2047:
2048: if ((J3dDebug.devPhase)
2049: && (J3dDebug.canvasViewCache >= J3dDebug.LEVEL_1))
2050: System.err.println("Constructed a CanvasViewCache");
2051: }
2052:
2053: synchronized void setCanvas(Canvas3D c) {
2054: canvas = c;
2055: }
2056:
2057: synchronized void setScreenViewCache(ScreenViewCache svc) {
2058: screenViewCache = svc;
2059: }
2060:
2061: synchronized void setViewCache(ViewCache vc) {
2062: viewCache = vc;
2063: }
2064: }
|