0001: /*
0002: * $RCSfile: TransformGroupRetained.java,v $
0003: *
0004: * Copyright 1996-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.13 $
0028: * $Date: 2008/02/28 20:17:32 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.util.ArrayList;
0035:
0036: /**
0037: * Group node that contains a transform.
0038: */
0039:
0040: class TransformGroupRetained extends GroupRetained implements
0041: TargetsInterface {
0042:
0043: /**
0044: * The Transform value for the TransformGroup.
0045: */
0046: Transform3D transform = new Transform3D();
0047:
0048: /**
0049: * The inverse of the transform
0050: */
0051: Transform3D invTransform = null;
0052:
0053: /**
0054: * The transpose of the inverse of the transform
0055: */
0056: Transform3D normalTransform = null;
0057:
0058: /**
0059: * The Transform value currently being used internally
0060: */
0061: Transform3D currentTransform = new Transform3D();
0062:
0063: /**
0064: * localVworld values for children of this TG
0065: */
0066: Transform3D[][] childLocalToVworld = null;
0067: int[][] childLocalToVworldIndex = null;
0068:
0069: // working variable for children transforms
0070: Transform3D[][] childTrans = null;
0071: int[][] childTransIndex = null;
0072:
0073: /**
0074: * A bitmask of the types in targets
0075: */
0076: int localTargetThreads = 0;
0077:
0078: // combined localTargetThreads and decendants' localTargetThreads
0079: int targetThreads = 0;
0080:
0081: /**
0082: * A list of WakeupOnTransformChange conditions for this Transform
0083: */
0084: WakeupIndexedList transformChange = null;
0085:
0086: // The current list of child transform group nodes or link nodes
0087: // under a transform group
0088: ArrayList childTransformLinks = new ArrayList(1);
0089:
0090: // working area while compile
0091: boolean needNormalsTransform = false; // true if normals transformation
0092: // is needed to push this
0093: // transform down to geometry
0094:
0095: // key which identifies a unique path from a
0096: // locale to this transform group
0097: HashKey currentKey = new HashKey();
0098:
0099: boolean aboveAViewPlatform = false;
0100:
0101: // maximum transform level of all shared path
0102: int maxTransformLevel = -1;
0103:
0104: // List of transform level, one per shared path
0105: int transformLevels[] = null;
0106:
0107: // J3d copy.
0108: CachedTargets[] j3dCTs = null;
0109:
0110: // User copy.
0111: CachedTargets[] cachedTargets = null;
0112:
0113: // Contains per path data, XXXX: move to NodeRetained
0114: TransformGroupData[] perPathData = null;
0115:
0116: /**
0117: * The constructor
0118: */
0119: TransformGroupRetained() {
0120: this .nodeType = NodeRetained.TRANSFORMGROUP;
0121: }
0122:
0123: /**
0124: * Sets the transform component of this TransformGroup to the value of
0125: * the passed transform.
0126: * @param t1 the transform to be copied
0127: */
0128: void setTransform(Transform3D t1) {
0129: J3dMessage tchangeMessage = null;
0130: int i, j;
0131: Transform3D trans = null;
0132:
0133: if (staticTransform != null) {
0134: // this writeable transformGroup has a static transform
0135: // merged into this node
0136:
0137: trans = new Transform3D(staticTransform.transform);
0138: trans.mul(t1);
0139:
0140: transform.setWithLock(trans);
0141:
0142: } else {
0143: trans = new Transform3D(t1);
0144: transform.setWithLock(t1);
0145: }
0146:
0147: if (transformChange != null) {
0148: notifyConditions();
0149: }
0150:
0151: if (source.isLive()) {
0152:
0153: if (aboveAViewPlatform && !t1.isCongruent()) {
0154: throw new BadTransformException(J3dI18N
0155: .getString("ViewPlatformRetained0"));
0156: }
0157:
0158: tchangeMessage = new J3dMessage();
0159: tchangeMessage.type = J3dMessage.TRANSFORM_CHANGED;
0160: tchangeMessage.threads = targetThreads;
0161: tchangeMessage.args[1] = this ;
0162: tchangeMessage.args[2] = trans;
0163:
0164: tchangeMessage.universe = universe;
0165: //System.err.println("TransformGroupRetained --- TRANSFORM_CHANGED " + this);
0166: VirtualUniverse.mc.processMessage(tchangeMessage);
0167: }
0168: dirtyBoundsCache();
0169: }
0170:
0171: /**
0172: * Copies the transform component of this TransformGroup into
0173: * the passed transform object.
0174: * @param t1 the transform object to be copied into
0175: */
0176: void getTransform(Transform3D t1) {
0177: transform.getWithLock(t1);
0178:
0179: // if staticTransform exists for this node, need to
0180: // redetermine the original user specified transform
0181:
0182: if (staticTransform != null) {
0183: Transform3D invTransform = staticTransform
0184: .getInvTransform();
0185: t1.mul(invTransform, t1);
0186: }
0187: }
0188:
0189: // get the inverse of the transform -- note: this method only
0190: // supports static transform
0191:
0192: Transform3D getInvTransform() {
0193: if (invTransform == null) {
0194: invTransform = new Transform3D(transform);
0195: invTransform.invert();
0196: }
0197: return invTransform;
0198: }
0199:
0200: // get the inverse of the transpose -- note: this method only
0201: // supports static transform, the translation component will
0202: // not transform
0203: Transform3D getNormalTransform() {
0204: if (normalTransform == null) {
0205: normalTransform = new Transform3D(transform);
0206: normalTransform.invert();
0207: normalTransform.transpose();
0208: }
0209: return normalTransform;
0210: }
0211:
0212: // synchronized with TransformStructure
0213: synchronized void setNodeData(SetLiveState s) {
0214: int i;
0215:
0216: super .setNodeData(s);
0217:
0218: childTrans = new Transform3D[s.currentTransforms.length][2];
0219: childTransIndex = new int[s.currentTransforms.length][2];
0220:
0221: for (i = 0; i < s.currentTransforms.length; i++) {
0222: childTrans[i][0] = new Transform3D();
0223:
0224: childTrans[i][0]
0225: .mul(
0226: s.currentTransforms[i][s.currentTransformsIndex[i][CURRENT_LOCAL_TO_VWORLD]],
0227: currentTransform);
0228: childTrans[i][1] = new Transform3D(childTrans[i][0]);
0229: childTransIndex[i][0] = 0;
0230: childTransIndex[i][1] = 0;
0231:
0232: }
0233:
0234: if (!s.inSharedGroup) {
0235: s.transformLevels[0] += 1;
0236: maxTransformLevel = s.transformLevels[0];
0237: } else {
0238: for (i = 0; i < s.keys.length; i++) {
0239: s.transformLevels[i] += 1;
0240: if (s.transformLevels[i] > maxTransformLevel) {
0241: maxTransformLevel = s.transformLevels[i];
0242: }
0243: }
0244: }
0245:
0246: if (!inSharedGroup) {
0247: if (childLocalToVworld == null) {
0248: // If the node is a transformGroup then need to keep
0249: // the child transforms as well
0250: childLocalToVworld = new Transform3D[1][];
0251: childLocalToVworldIndex = new int[1][];
0252: transformLevels = new int[1];
0253: // Use by TransformStructure
0254: cachedTargets = new CachedTargets[1];
0255: perPathData = new TransformGroupData[1];
0256: }
0257: childLocalToVworld[0] = childTrans[0];
0258: childLocalToVworldIndex[0] = childTransIndex[0];
0259: transformLevels[0] = s.transformLevels[0];
0260:
0261: setAuxData(s, 0, 0);
0262: } else {
0263:
0264: // For inSharedGroup case.
0265: int j, len;
0266:
0267: if (childLocalToVworld == null) {
0268: childLocalToVworld = new Transform3D[s.keys.length][];
0269: childLocalToVworldIndex = new int[s.keys.length][];
0270: transformLevels = new int[s.keys.length];
0271: cachedTargets = new CachedTargets[s.keys.length];
0272: perPathData = new TransformGroupData[s.keys.length];
0273: len = 0;
0274: } else {
0275:
0276: len = localToVworld.length - s.keys.length;
0277:
0278: int newLen = localToVworld.length;
0279:
0280: Transform3D newChildTList[][] = new Transform3D[newLen][];
0281: int newChildIndexList[][] = new int[newLen][];
0282: int newTransformLevels[] = new int[newLen];
0283: CachedTargets newTargets[] = new CachedTargets[newLen];
0284: TransformGroupData newPerPathData[] = new TransformGroupData[newLen];
0285:
0286: System.arraycopy(childLocalToVworld, 0, newChildTList,
0287: 0, childLocalToVworld.length);
0288: System.arraycopy(childLocalToVworldIndex, 0,
0289: newChildIndexList, 0,
0290: childLocalToVworldIndex.length);
0291: System.arraycopy(transformLevels, 0,
0292: newTransformLevels, 0, transformLevels.length);
0293:
0294: System.arraycopy(cachedTargets, 0, newTargets, 0,
0295: cachedTargets.length);
0296:
0297: System.arraycopy(perPathData, 0, newPerPathData, 0,
0298: perPathData.length);
0299:
0300: childLocalToVworld = newChildTList;
0301: childLocalToVworldIndex = newChildIndexList;
0302: transformLevels = newTransformLevels;
0303: cachedTargets = newTargets;
0304: perPathData = newPerPathData;
0305: }
0306:
0307: int hkIndex;
0308: int hkIndexPlus1, blkSize;
0309:
0310: for (i = len, j = 0; i < localToVworld.length; i++, j++) {
0311: hkIndex = s.keys[j].equals(localToVworldKeys, 0,
0312: localToVworldKeys.length);
0313:
0314: if (hkIndex < 0) {
0315: MasterControl
0316: .getCoreLogger()
0317: .severe(
0318: "Can't Find matching hashKey in setNodeData.");
0319: break;
0320: } else if (hkIndex >= i) { // Append to last.
0321: childLocalToVworld[i] = childTrans[j];
0322: childLocalToVworldIndex[i] = childTransIndex[j];
0323: transformLevels[i] = s.transformLevels[j];
0324: } else {
0325: hkIndexPlus1 = hkIndex + 1;
0326: blkSize = i - hkIndex;
0327:
0328: System.arraycopy(childLocalToVworld, hkIndex,
0329: childLocalToVworld, hkIndexPlus1, blkSize);
0330:
0331: System.arraycopy(childLocalToVworldIndex, hkIndex,
0332: childLocalToVworldIndex, hkIndexPlus1,
0333: blkSize);
0334:
0335: System.arraycopy(transformLevels, hkIndex,
0336: transformLevels, hkIndexPlus1, blkSize);
0337:
0338: System.arraycopy(cachedTargets, hkIndex,
0339: cachedTargets, hkIndexPlus1, blkSize);
0340:
0341: System.arraycopy(perPathData, hkIndex, perPathData,
0342: hkIndexPlus1, blkSize);
0343:
0344: childLocalToVworld[hkIndex] = childTrans[j];
0345: childLocalToVworldIndex[hkIndex] = childTransIndex[j];
0346: transformLevels[hkIndex] = s.transformLevels[j];
0347: }
0348:
0349: setAuxData(s, j, hkIndex);
0350: }
0351: }
0352: if (s.childTransformLinks != null) {
0353: // do not duplicate shared nodes
0354: synchronized (s.childTransformLinks) {
0355: if (!inSharedGroup
0356: || !s.childTransformLinks.contains(this )) {
0357: s.childTransformLinks.add(this );
0358: }
0359: }
0360: }
0361:
0362: s.localToVworld = childLocalToVworld;
0363: s.localToVworldIndex = childLocalToVworldIndex;
0364: s.currentTransforms = childTrans;
0365: s.currentTransformsIndex = childTransIndex;
0366:
0367: s.childTransformLinks = childTransformLinks;
0368: s.parentTransformLink = this ;
0369: }
0370:
0371: void setAuxData(SetLiveState s, int index, int hkIndex) {
0372: super .setAuxData(s, index, hkIndex);
0373: perPathData[hkIndex] = new TransformGroupData();
0374: perPathData[hkIndex].switchState = (SwitchState) s.switchStates
0375: .get(hkIndex);
0376: }
0377:
0378: // Add a WakeupOnTransformChange to the list
0379: void removeCondition(WakeupOnTransformChange wakeup) {
0380: synchronized (transformChange) {
0381: transformChange.remove(wakeup);
0382: }
0383: }
0384:
0385: // Add a WakeupOnTransformChange to the list
0386: void addCondition(WakeupOnTransformChange wakeup) {
0387: synchronized (transformChange) {
0388: transformChange.add(wakeup);
0389: }
0390: }
0391:
0392: void notifyConditions() {
0393: synchronized (transformChange) {
0394: WakeupOnTransformChange list[] = (WakeupOnTransformChange[]) transformChange
0395: .toArray(false);
0396: for (int i = transformChange.size() - 1; i >= 0; i--) {
0397: list[i].setTriggered();
0398: }
0399: }
0400: }
0401:
0402: boolean isStatic() {
0403: if (!super .isStatic()
0404: || source
0405: .getCapability(TransformGroup.ALLOW_TRANSFORM_READ)
0406: || source
0407: .getCapability(TransformGroup.ALLOW_TRANSFORM_WRITE)) {
0408: return false;
0409: } else {
0410: return true;
0411: }
0412: }
0413:
0414: void mergeTransform(TransformGroupRetained xform) {
0415: super .mergeTransform(xform);
0416: transform.mul(xform.transform, transform);
0417: }
0418:
0419: void traverse(boolean sameLevel, int level) {
0420:
0421: System.err.println();
0422: for (int i = 0; i < level; i++) {
0423: System.err.print(".");
0424: }
0425: System.err.print(this );
0426:
0427: if (isStatic()) {
0428: System.err.print(" (s)");
0429: } else {
0430: System.err.print(" (w)");
0431: }
0432: System.err.println();
0433: System.err.println(transform.toString());
0434: super .traverse(true, level);
0435: }
0436:
0437: void compile(CompileState compState) {
0438:
0439: // save and reset the keepTG and needNormalsTransform flags
0440:
0441: boolean saveKeepTG = compState.keepTG;
0442: compState.keepTG = false;
0443:
0444: boolean saveNeedNormalsTransform = compState.needNormalsTransform;
0445: compState.needNormalsTransform = false;
0446:
0447: super .compile(compState);
0448:
0449: if (compState.keepTG) {
0450: // keep this transform group, don't merge it
0451:
0452: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
0453: }
0454:
0455: if (J3dDebug.devPhase && J3dDebug.debug) {
0456: compState.numTransformGroups++;
0457: if (isStatic())
0458: compState.numStaticTransformGroups++;
0459: if (mergeFlag == SceneGraphObjectRetained.MERGE)
0460: compState.numMergedTransformGroups++;
0461: }
0462:
0463: if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) {
0464: // a non-mergeable TG will trigger a merge of its subtree
0465:
0466: compState.staticTransform = null;
0467: compState.parentGroup = null;
0468: super .merge(compState);
0469:
0470: } else {
0471: // flag this TG as to be merged later on
0472: mergeFlag = SceneGraphObjectRetained.MERGE;
0473: }
0474:
0475: // restore compile state
0476: compState.keepTG = saveKeepTG;
0477: this .needNormalsTransform = compState.needNormalsTransform;
0478: compState.needNormalsTransform = saveNeedNormalsTransform;
0479: }
0480:
0481: void merge(CompileState compState) {
0482:
0483: TransformGroupRetained saveStaticTransform;
0484:
0485: // merge the transforms
0486: if (compState.staticTransform != null) {
0487: staticTransform = compState.staticTransform;
0488: mergeTransform(compState.staticTransform);
0489: }
0490:
0491: if (mergeFlag == SceneGraphObjectRetained.MERGE) {
0492:
0493: // before we push down the static transform, check
0494: // to see if the transform will be pushed down to shapes
0495: // with geometry_with_normals and if so, check if
0496: // the normal transform has uniform scale or not. If
0497: // it doesn't, don't push it down.
0498:
0499: if (this .needNormalsTransform) {
0500: Transform3D normalXform = this .getNormalTransform();
0501: if (!normalXform.isCongruent()) {
0502: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
0503: }
0504: }
0505: }
0506:
0507: if (mergeFlag == SceneGraphObjectRetained.MERGE) {
0508: saveStaticTransform = compState.staticTransform;
0509: compState.staticTransform = this ;
0510:
0511: // go to the merge method of the group node to start
0512: // pushing down the static transform until it hits
0513: // a leaf or a subtree which is already merged.
0514: super .merge(compState);
0515:
0516: // reset the compile state
0517: compState.staticTransform = saveStaticTransform;
0518:
0519: } else {
0520: compState.parentGroup.compiledChildrenList.add(this );
0521: parent = compState.parentGroup;
0522: }
0523:
0524: mergeFlag = SceneGraphObjectRetained.MERGE_DONE;
0525: }
0526:
0527: /**
0528: * This setlive simply concatinates it's transform onto all the ones
0529: * passed in.
0530: */
0531: void setLive(SetLiveState s) {
0532: int i, j;
0533: Transform3D trans = null;
0534: Targets[] newTargets = null;
0535: Targets[] savedTransformTargets = null;
0536: int oldTraverseFlags = 0;
0537: int len;
0538: Object obj;
0539:
0540: // XXXX - optimization for targetThreads computation, require
0541: // cleanup in GroupRetained.doSetLive()
0542: //int savedTargetThreads = 0;
0543: //savedTargetThreads = s.transformTargetThreads;
0544: //s.transformTargetThreads = 0;
0545:
0546: oldTraverseFlags = s.traverseFlags;
0547:
0548: savedTransformTargets = s.transformTargets;
0549:
0550: int numPaths = (s.inSharedGroup) ? s.keys.length : 1;
0551: newTargets = new Targets[numPaths];
0552: for (i = 0; i < numPaths; i++) {
0553: newTargets[i] = new Targets();
0554: }
0555:
0556: s.transformTargets = newTargets;
0557: s.traverseFlags = 0;
0558:
0559: // This is needed b/c super.setlive is called after inSharedGroup check.
0560: inSharedGroup = s.inSharedGroup;
0561:
0562: trans = new Transform3D();
0563: transform.getWithLock(trans);
0564: currentTransform.set(trans);
0565:
0566: ArrayList savedChildTransformLinks = s.childTransformLinks;
0567: GroupRetained savedParentTransformLink = s.parentTransformLink;
0568: Transform3D[][] oldCurrentList = s.currentTransforms;
0569: int[][] oldCurrentIndexList = s.currentTransformsIndex;
0570:
0571: super .doSetLive(s);
0572:
0573: if (!inSharedGroup) {
0574: if (s.transformTargets[0] != null) {
0575: cachedTargets[0] = s.transformTargets[0].snapShotInit();
0576: }
0577: if (s.switchTargets != null && s.switchTargets[0] != null) {
0578: s.switchTargets[0].addNode(this , Targets.GRP_TARGETS);
0579: }
0580: } else {
0581: int hkIndex;
0582: for (i = 0; i < numPaths; i++) {
0583: if (s.transformTargets[i] != null) {
0584: hkIndex = s.keys[i].equals(localToVworldKeys, 0,
0585: localToVworldKeys.length);
0586: cachedTargets[hkIndex] = s.transformTargets[i]
0587: .snapShotInit();
0588: }
0589: if (s.switchTargets != null
0590: && s.switchTargets[i] != null) {
0591: s.switchTargets[i].addNode(this ,
0592: Targets.GRP_TARGETS);
0593: }
0594: }
0595: }
0596:
0597: // Assign data in cachedTargets to j3dCTs.
0598: j3dCTs = new CachedTargets[cachedTargets.length];
0599: copyCachedTargets(TargetsInterface.TRANSFORM_TARGETS, j3dCTs);
0600:
0601: computeTargetThreads(TargetsInterface.TRANSFORM_TARGETS,
0602: cachedTargets);
0603:
0604: // restore setLiveState from it's local variables.
0605: // setNodeData did keep a reference to these variables.
0606: s.localToVworld = localToVworld;
0607: s.localToVworldIndex = localToVworldIndex;
0608: s.currentTransforms = oldCurrentList;
0609: s.currentTransformsIndex = oldCurrentIndexList;
0610:
0611: s.childTransformLinks = savedChildTransformLinks;
0612: s.parentTransformLink = savedParentTransformLink;
0613:
0614: s.transformTargets = savedTransformTargets;
0615:
0616: if (!s.inSharedGroup) {
0617: s.transformLevels[0] -= 1;
0618: } else {
0619: for (i = 0; i < s.keys.length; i++) {
0620: s.transformLevels[i] -= 1;
0621: }
0622: }
0623:
0624: if ((s.traverseFlags & NodeRetained.CONTAINS_VIEWPLATFORM) != 0) {
0625: aboveAViewPlatform = true;
0626: }
0627: s.traverseFlags |= oldTraverseFlags;
0628:
0629: if (aboveAViewPlatform && !trans.isCongruent()) {
0630: throw new BadTransformException(J3dI18N
0631: .getString("ViewPlatformRetained0"));
0632: }
0633:
0634: super .markAsLive();
0635: }
0636:
0637: /**
0638: * remove the localToVworld transform for a transformGroup
0639: */
0640: void removeNodeData(SetLiveState s) {
0641:
0642: synchronized (this ) { // synchronized with TransformStructure
0643:
0644: if (refCount <= 0) {
0645: childLocalToVworld = null;
0646: childLocalToVworldIndex = null;
0647: transformLevels = null;
0648: // only use by TransformStruct.
0649: cachedTargets = null;
0650: perPathData = null;
0651: targetThreads = 0;
0652:
0653: if (parentTransformLink != null) {
0654: ArrayList obj;
0655: if (parentTransformLink instanceof TransformGroupRetained) {
0656: obj = ((TransformGroupRetained) parentTransformLink).childTransformLinks;
0657: } else {
0658: obj = ((SharedGroupRetained) parentTransformLink).childTransformLinks;
0659: }
0660: synchronized (obj) {
0661: obj.remove(this );
0662: }
0663: }
0664: aboveAViewPlatform = false;
0665: } else {
0666: int i, index, len;
0667: // Remove the localToVworld key
0668: int newLen = localToVworld.length - s.keys.length;
0669:
0670: Transform3D[][] newChildTList = new Transform3D[newLen][];
0671: int[][] newChildIndexList = new int[newLen][];
0672: int[] newTransformLevels = new int[newLen];
0673: ArrayList[] newChildPTG = new ArrayList[newLen];
0674: CachedTargets[] newTargets = new CachedTargets[newLen];
0675: TransformGroupData[] newPerPathData = new TransformGroupData[newLen];
0676:
0677: int[] tempIndex = new int[s.keys.length];
0678: int curStart = 0, newStart = 0;
0679: boolean found = false;
0680: for (i = 0; i < s.keys.length; i++) {
0681: index = s.keys[i].equals(localToVworldKeys, 0,
0682: localToVworldKeys.length);
0683:
0684: tempIndex[i] = index;
0685:
0686: if (index >= 0) {
0687: found = true;
0688:
0689: if (index == curStart) {
0690: curStart++;
0691: } else {
0692: len = index - curStart;
0693: System.arraycopy(childLocalToVworld,
0694: curStart, newChildTList, newStart,
0695: len);
0696: System.arraycopy(childLocalToVworldIndex,
0697: curStart, newChildIndexList,
0698: newStart, len);
0699: System.arraycopy(transformLevels, curStart,
0700: newTransformLevels, newStart, len);
0701: System.arraycopy(cachedTargets, curStart,
0702: newTargets, newStart, len);
0703: System.arraycopy(perPathData, curStart,
0704: newPerPathData, newStart, len);
0705:
0706: curStart = index + 1;
0707: newStart = newStart + len;
0708: }
0709: } else {
0710: found = false;
0711: MasterControl
0712: .getCoreLogger()
0713: .severe(
0714: "TG.removeNodeData-Can't find matching hashKey.");
0715: }
0716: }
0717:
0718: if ((found == true)
0719: && (curStart < localToVworld.length)) {
0720: len = localToVworld.length - curStart;
0721: System.arraycopy(childLocalToVworld, curStart,
0722: newChildTList, newStart, len);
0723: System.arraycopy(childLocalToVworldIndex, curStart,
0724: newChildIndexList, newStart, len);
0725: System.arraycopy(transformLevels, curStart,
0726: newTransformLevels, newStart, len);
0727: System.arraycopy(cachedTargets, curStart,
0728: newTargets, newStart, len);
0729: System.arraycopy(perPathData, curStart,
0730: newPerPathData, newStart, len);
0731: }
0732:
0733: childLocalToVworld = newChildTList;
0734: childLocalToVworldIndex = newChildIndexList;
0735: transformLevels = newTransformLevels;
0736: cachedTargets = newTargets;
0737: perPathData = newPerPathData;
0738: }
0739: super .removeNodeData(s);
0740: // Set it back to its parent localToVworld data.
0741: // This is b/c the parent has changed it localToVworld data arrays.
0742: s.localToVworld = childLocalToVworld;
0743: s.localToVworldIndex = childLocalToVworldIndex;
0744: }
0745: }
0746:
0747: void clearLive(SetLiveState s) {
0748:
0749: Targets[] savedTransformTargets = null;
0750:
0751: savedTransformTargets = s.transformTargets;
0752: // no need to gather targets from tg in clear live
0753: s.transformTargets = null;
0754:
0755: super .clearLive(s);
0756:
0757: // restore setLiveState from it's local variables.
0758: // removeNodeData has altered these variables.
0759: s.localToVworld = localToVworld;
0760: s.localToVworldIndex = localToVworldIndex;
0761: s.transformTargets = savedTransformTargets;
0762:
0763: synchronized (this ) { // synchronized with TransformStructure
0764: if (inSharedGroup) {
0765: if (transformLevels != null) {
0766: maxTransformLevel = transformLevels[0];
0767: for (int i = 1; i < transformLevels.length; i++) {
0768: if (transformLevels[i] > maxTransformLevel) {
0769: maxTransformLevel = transformLevels[i];
0770: }
0771: }
0772: } else {
0773: maxTransformLevel = -1;
0774: }
0775:
0776: if (s.switchTargets != null) {
0777: for (int i = 0; i < s.switchTargets.length; i++) {
0778: if (s.switchTargets[i] != null) {
0779: s.switchTargets[i].addNode(this ,
0780: Targets.GRP_TARGETS);
0781: }
0782: }
0783: }
0784:
0785: } else {
0786: maxTransformLevel = -1;
0787: if (s.switchTargets != null
0788: && s.switchTargets[0] != null) {
0789: s.switchTargets[0].addNode(this ,
0790: Targets.GRP_TARGETS);
0791: }
0792: }
0793: }
0794: // XXXX: recontruct targetThreads
0795: }
0796:
0797: void computeCombineBounds(Bounds bounds) {
0798: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
0799: if (validCachedBounds && boundsAutoCompute) {
0800: Bounds b = (Bounds) cachedBounds.clone();
0801: // Should this be lock too ? ( MT safe ? )
0802: // Thoughts :
0803: // Make a temp copy with lock : transform.getWithLock(trans);, but this will cause gc ...
0804: synchronized (transform) {
0805: b.transform(transform);
0806: }
0807: bounds.combine(b);
0808: return;
0809: }
0810:
0811: NodeRetained child;
0812: //issue 544
0813: Bounds boundingObject = null;
0814: if (VirtualUniverse.mc.useBoxForGroupBounds) {
0815: boundingObject = new BoundingBox((Bounds) null);
0816: } else {
0817: boundingObject = new BoundingSphere();
0818: ((BoundingSphere) boundingObject).setRadius(-1.0);
0819: }
0820: if (boundsAutoCompute) {
0821: for (int i = children.size() - 1; i >= 0; i--) {
0822: child = (NodeRetained) children.get(i);
0823: if (child != null)
0824: child.computeCombineBounds(boundingObject);
0825: }
0826:
0827: if (VirtualUniverse.mc.cacheAutoComputedBounds) {
0828: cachedBounds = (Bounds) boundingObject.clone();
0829: }
0830: } else {
0831: // Should this be lock too ? ( MT safe ? )
0832: synchronized (localBounds) {
0833: boundingObject.set(localBounds);
0834: }
0835: }
0836:
0837: // Should this be lock too ? ( MT safe ? )
0838: // Thoughts :
0839: // Make a temp copy with lock : transform.getWithLock(trans);, but this will cause gc ...
0840: synchronized (transform) {
0841: boundingObject.transform(transform);
0842: }
0843: bounds.combine(boundingObject);
0844:
0845: }
0846:
0847: void processChildLocalToVworld(ArrayList dirtyTransformGroups,
0848: ArrayList keySet, UpdateTargets targets, ArrayList blUsers) {
0849:
0850: synchronized (this ) { // sync with setLive/clearLive
0851:
0852: if (inSharedGroup) {
0853: if (localToVworldKeys != null) {
0854: for (int j = 0; j < localToVworldKeys.length; j++) {
0855: if (perPathData[j].markedDirty) {
0856: updateChildLocalToVworld(
0857: localToVworldKeys[j], j,
0858: dirtyTransformGroups, keySet,
0859: targets, blUsers);
0860: } else {
0861: //System.err.println("tg.procChild markedDiry skip");
0862: }
0863: }
0864: }
0865: } else {
0866: if (perPathData != null && perPathData[0].markedDirty) {
0867: updateChildLocalToVworld(dirtyTransformGroups,
0868: keySet, targets, blUsers);
0869: } else {
0870: //System.err.println("tg.procChild markedDiry skip");
0871: }
0872: }
0873: }
0874: }
0875:
0876: // for shared case
0877: void updateChildLocalToVworld(HashKey key, int index,
0878: ArrayList dirtyTransformGroups, ArrayList keySet,
0879: UpdateTargets targets, ArrayList blUsers) {
0880:
0881: int i, j;
0882: Object obj;
0883: Transform3D lToVw, childLToVw;
0884: TransformGroupRetained tg;
0885: LinkRetained ln;
0886: CachedTargets ct;
0887:
0888: synchronized (this ) { // sync with setLive/clearLive
0889:
0890: if (localToVworld != null) {
0891: perPathData[index].markedDirty = false;
0892: // update immediate child's localToVworld
0893:
0894: if (perPathData[index].switchState.currentSwitchOn) {
0895: lToVw = getCurrentLocalToVworld(index);
0896: childLToVw = getUpdateChildLocalToVworld(index);
0897: childLToVw.mul(lToVw, currentTransform);
0898: dirtyTransformGroups.add(this );
0899: keySet.add(key);
0900: ct = j3dCTs[index];
0901: if (ct != null) {
0902: targets.addCachedTargets(ct);
0903: if (ct.targetArr[Targets.BLN_TARGETS] != null) {
0904: gatherBlUsers(blUsers,
0905: ct.targetArr[Targets.BLN_TARGETS]);
0906: }
0907: }
0908: } else {
0909: perPathData[index].switchDirty = true;
0910: //System.err.println("tg.updateChild skip");
0911: }
0912:
0913: // update child's localToVworld of its children
0914: // transformLink may contain link nodes
0915: synchronized (childTransformLinks) {
0916: for (i = 0; i < childTransformLinks.size(); i++) {
0917: obj = childTransformLinks.get(i);
0918:
0919: if (obj instanceof TransformGroupRetained) {
0920: tg = (TransformGroupRetained) obj;
0921: tg.updateChildLocalToVworld(
0922: tg.localToVworldKeys[index], index,
0923: dirtyTransformGroups, keySet,
0924: targets, blUsers);
0925: } else { // LinkRetained
0926: ln = (LinkRetained) obj;
0927: currentKey.set(localToVworldKeys[index]);
0928: currentKey.append(LinkRetained.plus)
0929: .append(ln.nodeId);
0930: if ((ln.sharedGroup != null)
0931: && (ln.sharedGroup.localToVworldKeys != null)) {
0932: j = currentKey
0933: .equals(
0934: ln.sharedGroup.localToVworldKeys,
0935: 0,
0936: ln.sharedGroup.localToVworldKeys.length);
0937: if (j < 0) {
0938: System.err
0939: .println("TransformGroupRetained : Can't find hashKey");
0940: }
0941:
0942: if (j < ln.sharedGroup.localToVworldKeys.length) {
0943: ln.sharedGroup
0944: .updateChildLocalToVworld(
0945: ln.sharedGroup.localToVworldKeys[j],
0946: j,
0947: dirtyTransformGroups,
0948: keySet, targets,
0949: blUsers);
0950: }
0951: }
0952: }
0953: }
0954: }
0955: }
0956: }
0957: }
0958:
0959: // for non-shared case
0960: void updateChildLocalToVworld(ArrayList dirtyTransformGroups,
0961: ArrayList keySet, UpdateTargets targets, ArrayList blUsers) {
0962: int i, j;
0963: Object obj;
0964: Transform3D lToVw, childLToVw;
0965: TransformGroupRetained tg;
0966: LinkRetained ln;
0967: CachedTargets ct;
0968:
0969: synchronized (this ) { // sync with setLive/clearLive
0970:
0971: if (localToVworld != null) {
0972: perPathData[0].markedDirty = false;
0973: // update immediate child's localToVworld
0974:
0975: if (perPathData[0].switchState.currentSwitchOn) {
0976: lToVw = getCurrentLocalToVworld(0);
0977: childLToVw = getUpdateChildLocalToVworld(0);
0978: childLToVw.mul(lToVw, currentTransform);
0979: dirtyTransformGroups.add(this );
0980: ct = j3dCTs[0];
0981: if (ct != null) {
0982: targets.addCachedTargets(ct);
0983: if (ct.targetArr[Targets.BLN_TARGETS] != null) {
0984: gatherBlUsers(blUsers,
0985: ct.targetArr[Targets.BLN_TARGETS]);
0986: }
0987: }
0988: } else {
0989: perPathData[0].switchDirty = true;
0990: //System.err.println("tg.updateChild skip");
0991: }
0992:
0993: // update child's localToVworld of its children
0994: // transformLink contains top level transform group nodes
0995: // and link nodes
0996: synchronized (childTransformLinks) {
0997: for (i = 0; i < childTransformLinks.size(); i++) {
0998: obj = childTransformLinks.get(i);
0999:
1000: if (obj instanceof TransformGroupRetained) {
1001: tg = (TransformGroupRetained) obj;
1002: tg.updateChildLocalToVworld(
1003: dirtyTransformGroups, keySet,
1004: targets, blUsers);
1005:
1006: } else { // LinkRetained
1007: ln = (LinkRetained) obj;
1008: currentKey.reset();
1009: currentKey.append(locale.nodeId);
1010: currentKey.append(LinkRetained.plus)
1011: .append(ln.nodeId);
1012: if ((ln.sharedGroup != null)
1013: && (ln.sharedGroup.localToVworldKeys != null)) {
1014: j = currentKey
1015: .equals(
1016: ln.sharedGroup.localToVworldKeys,
1017: 0,
1018: ln.sharedGroup.localToVworldKeys.length);
1019: if (j < 0) {
1020: System.err
1021: .println("TransformGroupRetained : Can't find hashKey");
1022: }
1023:
1024: if (j < ln.sharedGroup.localToVworldKeys.length) {
1025: ln.sharedGroup
1026: .updateChildLocalToVworld(
1027: ln.sharedGroup.localToVworldKeys[j],
1028: j,
1029: dirtyTransformGroups,
1030: keySet, targets,
1031: blUsers);
1032: }
1033: }
1034: }
1035: }
1036: }
1037: }
1038: }
1039: }
1040:
1041: /**
1042: * Transform the input bound by the current LocalToVWorld, this
1043: * one overwrite the one defined in NodeRetained since for
1044: * TransformGroup, it has to use currentChildLocalToVworld
1045: * instead of currentLocalToVworld
1046: */
1047: void transformBounds(SceneGraphPath path, Bounds bound) {
1048: if (!((NodeRetained) path.item.retained).inSharedGroup) {
1049: bound.transform(getCurrentChildLocalToVworld());
1050: } else {
1051: HashKey key = new HashKey("");
1052: path.getHashKey(key);
1053: bound.transform(getCurrentChildLocalToVworld(key));
1054: }
1055: }
1056:
1057: /**
1058: * get the to be updated child localToVworld
1059: */
1060: Transform3D getUpdateChildLocalToVworld(int index) {
1061: int currentIndex = childLocalToVworldIndex[index][NodeRetained.CURRENT_LOCAL_TO_VWORLD];
1062:
1063: if (currentIndex == childLocalToVworldIndex[index][NodeRetained.LAST_LOCAL_TO_VWORLD]) {
1064: currentIndex = currentIndex ^ 1;
1065: childLocalToVworldIndex[index][NodeRetained.CURRENT_LOCAL_TO_VWORLD] = currentIndex;
1066: }
1067: return childLocalToVworld[index][currentIndex];
1068: }
1069:
1070: /**
1071: * Get the current child localToVworld transform for a node
1072: */
1073: Transform3D getCurrentChildLocalToVworld() {
1074: return getCurrentChildLocalToVworld(0);
1075: }
1076:
1077: Transform3D getCurrentChildLocalToVworld(int index) {
1078: return childLocalToVworld[index][childLocalToVworldIndex[index][NodeRetained.CURRENT_LOCAL_TO_VWORLD]];
1079: }
1080:
1081: Transform3D getCurrentChildLocalToVworld(HashKey key) {
1082: if (!inSharedGroup) {
1083: return childLocalToVworld[0][childLocalToVworldIndex[0][NodeRetained.CURRENT_LOCAL_TO_VWORLD]];
1084: } else {
1085: int i = key.equals(localToVworldKeys, 0,
1086: localToVworldKeys.length);
1087: if (i >= 0) {
1088: return childLocalToVworld[i][childLocalToVworldIndex[i][NodeRetained.CURRENT_LOCAL_TO_VWORLD]];
1089: }
1090: }
1091: return new Transform3D();
1092: }
1093:
1094: /**
1095: * Get the last child localToVworld transform for a node
1096: */
1097: Transform3D getLastChildLocalToVworld(HashKey key) {
1098:
1099: if (!inSharedGroup) {
1100: return childLocalToVworld[0][childLocalToVworldIndex[0][NodeRetained.LAST_LOCAL_TO_VWORLD]];
1101: } else {
1102: int i = key.equals(localToVworldKeys, 0,
1103: localToVworldKeys.length);
1104: if (i >= 0) {
1105: return childLocalToVworld[i][childLocalToVworldIndex[i][NodeRetained.LAST_LOCAL_TO_VWORLD]];
1106: }
1107: }
1108: return new Transform3D();
1109: }
1110:
1111: // ****************************
1112: // TargetsInterface methods
1113: // ****************************
1114:
1115: public int getTargetThreads(int type) {
1116: // type is ignored here, only need for SharedGroup
1117: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1118: return targetThreads;
1119: } else {
1120: System.err.println("getTargetsThreads: wrong arguments");
1121: return -1;
1122: }
1123: }
1124:
1125: public CachedTargets getCachedTargets(int type, int index, int child) {
1126: // type is ignored here, only need for SharedGroup
1127: // child is ignored here
1128: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1129: return cachedTargets[index];
1130: } else {
1131: System.err.println("getCachedTargets: wrong arguments");
1132: return null;
1133: }
1134: }
1135:
1136: TargetsInterface getClosestTargetsInterface(int type) {
1137: return (type == TargetsInterface.TRANSFORM_TARGETS) ? (TargetsInterface) this
1138: : (TargetsInterface) parentSwitchLink;
1139: }
1140:
1141: // re-evalute localTargetThreads using newCachedTargets and
1142: // re-evaluate targetThreads
1143: public void computeTargetThreads(int type,
1144: CachedTargets[] newCachedTargets) {
1145:
1146: // type is ignored here, only need for SharedGroup
1147: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1148: localTargetThreads = J3dThread.UPDATE_TRANSFORM;
1149:
1150: for (int i = 0; i < newCachedTargets.length; i++) {
1151: if (newCachedTargets[i] != null) {
1152: localTargetThreads |= newCachedTargets[i]
1153: .computeTargetThreads();
1154: }
1155: }
1156: targetThreads = localTargetThreads;
1157:
1158: int numLinks = childTransformLinks.size();
1159: TargetsInterface childLink;
1160: NodeRetained node;
1161: for (int i = 0; i < numLinks; i++) {
1162:
1163: node = (NodeRetained) childTransformLinks.get(i);
1164: if (node.nodeType == NodeRetained.LINK) {
1165: childLink = (TargetsInterface) ((LinkRetained) node).sharedGroup;
1166: } else {
1167: childLink = (TargetsInterface) node;
1168: }
1169: if (childLink != null) {
1170: targetThreads |= childLink
1171: .getTargetThreads(TargetsInterface.TRANSFORM_TARGETS);
1172: }
1173: }
1174: } else {
1175: System.err
1176: .println("computeTargetsThreads: wrong arguments");
1177: }
1178:
1179: }
1180:
1181: // re-compute localTargetThread, targetThreads and
1182: // propagate changes to ancestors
1183: public void updateTargetThreads(int type,
1184: CachedTargets[] newCachedTargets) {
1185: // type is ignored here, only need for SharedGroup
1186: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1187: computeTargetThreads(type, newCachedTargets);
1188: if (parentTransformLink != null) {
1189: TargetsInterface pti = (TargetsInterface) parentTransformLink;
1190: pti.propagateTargetThreads(
1191: TargetsInterface.TRANSFORM_TARGETS,
1192: targetThreads);
1193: }
1194: } else {
1195: System.err.println("updateTargetThreads: wrong arguments");
1196: }
1197: }
1198:
1199: // re-evaluate targetThreads using childTargetThreads and
1200: // propagate changes to ancestors
1201: public void propagateTargetThreads(int type, int childTargetThreads) {
1202: // type is ignored here, only need for SharedGroup
1203:
1204: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1205: // XXXX : For now we'll OR more than exact.
1206: //targetThreads = localTargetThreads | childTargetThreads;
1207: targetThreads = targetThreads | childTargetThreads;
1208: if (parentTransformLink != null) {
1209: TargetsInterface pti = (TargetsInterface) parentTransformLink;
1210: pti.propagateTargetThreads(
1211: TargetsInterface.TRANSFORM_TARGETS,
1212: targetThreads);
1213: }
1214: } else {
1215: System.err
1216: .println("propagateTargetThreads: wrong arguments");
1217: }
1218: }
1219:
1220: public void updateCachedTargets(int type, CachedTargets[] newCt) {
1221: // type is ignored here, only need for SharedGroup
1222: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1223: j3dCTs = newCt;
1224: } else {
1225: System.err.println("updateCachedTargets: wrong arguments");
1226: }
1227: }
1228:
1229: public void copyCachedTargets(int type, CachedTargets[] newCt) {
1230: // type is ignored here, only need for SharedGroup
1231: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1232: int size = cachedTargets.length;
1233: for (int i = 0; i < size; i++) {
1234: newCt[i] = cachedTargets[i];
1235: }
1236: } else {
1237: System.err.println("copyCachedTargets: wrong arguments");
1238: }
1239: }
1240:
1241: public void resetCachedTargets(int type, CachedTargets[] newCtArr,
1242: int child) {
1243: // type is ignored here, only need for SharedGroup
1244: // child is ignored here
1245: if (type == TargetsInterface.TRANSFORM_TARGETS) {
1246: cachedTargets = newCtArr;
1247: } else {
1248: System.err.println("resetCachedTargets: wrong arguments");
1249: }
1250: }
1251:
1252: public ArrayList getTargetsData(int type, int index) {
1253: // not used
1254: return null;
1255: }
1256:
1257: void childCheckSetLive(NodeRetained child, int childIndex,
1258: SetLiveState s, NodeRetained linkNode) {
1259: s.currentTransforms = childLocalToVworld;
1260: s.currentTransformsIndex = childLocalToVworldIndex;
1261: s.parentTransformLink = this;
1262: s.childTransformLinks = childTransformLinks;
1263: s.localToVworld = s.currentTransforms;
1264: s.localToVworldIndex = s.currentTransformsIndex;
1265:
1266: child.setLive(s);
1267: }
1268: }
|