0001: /*
0002: * $RCSfile: GroupRetained.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.16 $
0028: * $Date: 2008/02/28 20:17:23 $
0029: * $State: Exp $
0030: */
0031:
0032: package javax.media.j3d;
0033:
0034: import java.util.Vector;
0035: import java.util.Enumeration;
0036: import java.util.ArrayList;
0037:
0038: /**
0039: * Group node.
0040: */
0041:
0042: class GroupRetained extends NodeRetained implements BHLeafInterface {
0043: /**
0044: * The Group Node's children vector.
0045: */
0046: ArrayList children = new ArrayList(1);
0047:
0048: /**
0049: * The Group node's collision bounds in local coordinates.
0050: */
0051: Bounds collisionBound = null;
0052:
0053: // The locale that this node is decended from
0054: Locale locale = null;
0055:
0056: // The list of lights that are scoped to this node
0057: // One such arraylist per path. If not in sharedGroup
0058: // then only index 0 is valid
0059: ArrayList lights = null;
0060:
0061: // The list of fogs that are scoped to this node
0062: // One such arraylist per path. If not in sharedGroup
0063: // then only index 0 is valid
0064: ArrayList fogs = null;
0065:
0066: // The list of model clips that are scoped to this node
0067: // One such arraylist per path. If not in sharedGroup
0068: // then only index 0 is valid
0069: ArrayList modelClips = null;
0070:
0071: // The list of alternateappearance that are scoped to this node
0072: // One such arraylist per path. If not in sharedGroup
0073: // then only index 0 is valid
0074: ArrayList altAppearances = null;
0075:
0076: // indicates whether this Group node can be the target of a collision
0077: boolean collisionTarget = false;
0078:
0079: // per child switchLinks
0080: ArrayList childrenSwitchLinks = null;
0081:
0082: // the immediate childIndex of a parentSwitchLink
0083: int parentSwitchLinkChildIndex = -1;
0084:
0085: // per shared path ordered path data
0086: ArrayList orderedPaths = null;
0087:
0088: /**
0089: * If collisionBound is set, this is equal to the
0090: * transformed collisionBounds, otherwise it is equal
0091: * to the transformed localBounds.
0092: * This variable is set to null unless collisionTarget = true.
0093: * This bound is only used by mirror Group.
0094: */
0095: BoundingBox collisionVwcBounds;
0096:
0097: /**
0098: * Mirror group of this node, it is only used when
0099: * collisionTarget = true. Otherwise it is set to null.
0100: * If not in shared group,
0101: * only entry 0 is used.
0102: *
0103: */
0104: ArrayList mirrorGroup;
0105:
0106: /**
0107: * key of mirror GroupRetained.
0108: */
0109: HashKey key;
0110:
0111: /**
0112: * sourceNode of this mirror Group
0113: */
0114: GroupRetained sourceNode;
0115:
0116: /**
0117: * The BHLeafNode for this GeometryAtom.
0118: */
0119: BHLeafNode bhLeafNode = null;
0120:
0121: //
0122: // The following variables are used during compile
0123: //
0124:
0125: // true if this is the root of the scenegraph tree
0126: boolean isRoot = false;
0127:
0128: boolean allocatedLights = false;
0129:
0130: boolean allocatedFogs = false;
0131:
0132: boolean allocatedMclips = false;
0133:
0134: boolean allocatedAltApps = false;
0135:
0136: // > 0 if this group is being used in scoping
0137: int scopingRefCount = 0;
0138:
0139: ArrayList compiledChildrenList = null;
0140:
0141: boolean isInClearLive = false;
0142:
0143: // List of viewes scoped to this Group, for all subclasses
0144: // of group, except ViewSpecificGroup its a pointer to closest
0145: // ViewSpecificGroup parent
0146: // viewList for this node, if inSharedGroup is
0147: // false then only viewList(0) is valid
0148: // For VSGs, this list is an intersection of
0149: // higher level VSGs
0150: ArrayList viewLists = null;
0151:
0152: // True if this Node is descendent of ViewSpecificGroup;
0153: boolean inViewSpecificGroup = false;
0154:
0155: GroupRetained() {
0156: this .nodeType = NodeRetained.GROUP;
0157: // issue 544
0158: if (VirtualUniverse.mc.useBoxForGroupBounds) {
0159: localBounds = new BoundingBox((Bounds) null);
0160: } else {
0161: localBounds = new BoundingSphere();
0162: ((BoundingSphere) localBounds).setRadius(-1.0);
0163: }
0164: }
0165:
0166: /**
0167: * Sets the collision bounds of a node.
0168: * @param bounds the bounding object for the node
0169: */
0170: void setCollisionBounds(Bounds bounds) {
0171: if (bounds == null) {
0172: this .collisionBound = null;
0173: } else {
0174: this .collisionBound = (Bounds) bounds.clone();
0175: }
0176:
0177: if (source.isLive()) {
0178: J3dMessage message = new J3dMessage();
0179: message.type = J3dMessage.COLLISION_BOUND_CHANGED;
0180: message.threads = J3dThread.UPDATE_TRANSFORM
0181: | J3dThread.UPDATE_GEOMETRY;
0182: message.universe = universe;
0183: message.args[0] = this ;
0184: VirtualUniverse.mc.processMessage(message);
0185: }
0186:
0187: }
0188:
0189: /**
0190: * Gets the collision bounds of a node.
0191: * @return the node's bounding object
0192: */
0193: Bounds getCollisionBounds() {
0194: return (collisionBound == null ? null : (Bounds) collisionBound
0195: .clone());
0196: }
0197:
0198: /**
0199: * Replaces the specified child with the child provided.
0200: * @param child the new child
0201: * @param index which child to replace
0202: */
0203: void setChild(Node child, int index) {
0204:
0205: checkValidChild(child, "GroupRetained0");
0206: if (this .source.isLive()) {
0207: universe.resetWaitMCFlag();
0208: synchronized (universe.sceneGraphLock) {
0209: doSetChild(child, index);
0210: universe.setLiveState.clear();
0211: }
0212: universe.waitForMC();
0213:
0214: } else {
0215: doSetChild(child, index);
0216: if (universe != null) {
0217: synchronized (universe.sceneGraphLock) {
0218: universe.setLiveState.clear();
0219: }
0220: }
0221: }
0222: dirtyBoundsCache();
0223: }
0224:
0225: // The method that does the work once the lock is acquired.
0226: void doSetChild(Node child, int index) {
0227: NodeRetained oldchildr;
0228: J3dMessage[] messages = null;
0229: int numMessages = 0;
0230: int attachStartIndex = 0;
0231:
0232: // since we want to make sure the replacement of the child
0233: // including removal of the oldChild and insertion of the newChild
0234: // all happen in the same frame, we'll send all the necessary
0235: // messages to masterControl for processing in one call.
0236: // So let's first find out how many messages will be sent
0237:
0238: oldchildr = (NodeRetained) children.get(index);
0239:
0240: if (this .source.isLive()) {
0241: if (oldchildr != null) {
0242: numMessages += 3; // REMOVE_NODES, ORDERED_GROUP_REMOVED
0243: // VIEWSPECIFICGROUP_CLEAR
0244: attachStartIndex = 3;
0245: }
0246:
0247: if (child != null) {
0248: numMessages += 4; // INSERT_NODES,BEHAVIOR_ACTIVATE,ORDERED_GROUP_INSERTED,
0249: // VIEWSPECIFICGROUP_INIT
0250: }
0251:
0252: messages = new J3dMessage[numMessages];
0253: for (int i = 0; i < numMessages; i++) {
0254: messages[i] = new J3dMessage();
0255: }
0256: }
0257:
0258: if (oldchildr != null) {
0259: oldchildr.setParent(null);
0260: checkClearLive(oldchildr, messages, 0, index, null);
0261: if (this .source.isLive()) {
0262: universe.notifyStructureChangeListeners(false,
0263: this .source, (BranchGroup) oldchildr.source);
0264: }
0265: }
0266: removeChildrenData(index);
0267:
0268: if (child == null) {
0269: children.set(index, null);
0270: if (messages != null) {
0271: VirtualUniverse.mc.processMessage(messages);
0272: }
0273: return;
0274: }
0275:
0276: if (this .source.isLive()) {
0277: universe.notifyStructureChangeListeners(true, this .source,
0278: (BranchGroup) child);
0279: }
0280: NodeRetained childr = (NodeRetained) child.retained;
0281: childr.setParent(this );
0282: children.set(index, childr);
0283:
0284: insertChildrenData(index);
0285: checkSetLive(childr, index, messages, attachStartIndex, null);
0286: if (this .source.isLive()) {
0287: ((BranchGroupRetained) childr).isNew = true;
0288: }
0289:
0290: if (messages != null) {
0291: VirtualUniverse.mc.processMessage(messages);
0292: }
0293: }
0294:
0295: /**
0296: * Inserts the specified child at specified index.
0297: * @param child the new child
0298: * @param index position to insert new child at
0299: */
0300: void insertChild(Node child, int index) {
0301:
0302: checkValidChild(child, "GroupRetained1");
0303: if (this .source.isLive()) {
0304: universe.resetWaitMCFlag();
0305: synchronized (universe.sceneGraphLock) {
0306: universe.notifyStructureChangeListeners(true,
0307: this .source, (BranchGroup) child);
0308: doInsertChild(child, index);
0309: universe.setLiveState.clear();
0310: }
0311: universe.waitForMC();
0312: } else {
0313: doInsertChild(child, index);
0314: if (universe != null) {
0315: synchronized (universe.sceneGraphLock) {
0316: universe.setLiveState.clear();
0317: }
0318: }
0319: }
0320: dirtyBoundsCache();
0321: }
0322:
0323: // The method that does the work once the lock is acquired.
0324: void doInsertChild(Node child, int index) {
0325: int i;
0326: NodeRetained childi;
0327:
0328: insertChildrenData(index);
0329: for (i = index; i < children.size(); i++) {
0330: childi = (NodeRetained) children.get(i);
0331: if (childi != null)
0332: childi.childIndex++;
0333: }
0334: if (child == null) {
0335: children.add(index, null);
0336: return;
0337: }
0338:
0339: NodeRetained childr = (NodeRetained) child.retained;
0340: childr.setParent(this );
0341: children.add(index, childr);
0342: checkSetLive(childr, index, null, 0, null);
0343: if (this .source.isLive()) {
0344: ((BranchGroupRetained) childr).isNew = true;
0345: }
0346: }
0347:
0348: /**
0349: * Removes the child at specified index.
0350: * @param index which child to remove
0351: */
0352: void removeChild(int index) {
0353:
0354: if (this .source.isLive()) {
0355: universe.resetWaitMCFlag();
0356: synchronized (universe.sceneGraphLock) {
0357: NodeRetained childr = (NodeRetained) children
0358: .get(index);
0359: doRemoveChild(index, null, 0);
0360: universe.setLiveState.clear();
0361: universe.notifyStructureChangeListeners(false,
0362: this .source, (BranchGroup) childr.source);
0363: }
0364: universe.waitForMC();
0365: } else {
0366: doRemoveChild(index, null, 0);
0367: if (universe != null) {
0368: synchronized (universe.sceneGraphLock) {
0369: universe.setLiveState.clear();
0370: }
0371: }
0372: }
0373: dirtyBoundsCache();
0374: }
0375:
0376: /**
0377: * Returns the index of the specified Node in this Group's list of Nodes
0378: * @param Node whose index is desired
0379: * @return index of the Node
0380: */
0381: int indexOfChild(Node child) {
0382: if (child != null)
0383: return children.indexOf((NodeRetained) child.retained);
0384: else
0385: return children.indexOf(null);
0386: }
0387:
0388: /**
0389: * Removes the specified child from this Group's list of
0390: * children. If the specified child is not found, the method returns
0391: * quietly
0392: *
0393: * @param child to be removed
0394: */
0395: void removeChild(Node child) {
0396: int i = indexOfChild(child);
0397: if (i >= 0)
0398: removeChild(i);
0399: }
0400:
0401: void removeAllChildren() {
0402: int n = children.size();
0403: for (int i = n - 1; i >= 0; i--) {
0404: removeChild(i);
0405: }
0406: }
0407:
0408: // The method that does the work once the lock is acquired.
0409: void doRemoveChild(int index, J3dMessage messages[],
0410: int messageIndex) {
0411: NodeRetained oldchildr, child;
0412: int i;
0413:
0414: oldchildr = (NodeRetained) children.get(index);
0415:
0416: int size = children.size();
0417: for (i = index; i < size; i++) {
0418: child = (NodeRetained) children.get(i);
0419: if (child != null)
0420: child.childIndex--;
0421: }
0422:
0423: if (oldchildr != null) {
0424: oldchildr.setParent(null);
0425: checkClearLive(oldchildr, messages, messageIndex, index,
0426: null);
0427: }
0428:
0429: children.remove(index);
0430: removeChildrenData(index);
0431:
0432: if (nodeType == NodeRetained.SWITCH) {
0433: // force reEvaluation of switch children
0434: SwitchRetained sg = (SwitchRetained) this ;
0435: sg.setWhichChild(sg.whichChild, true);
0436: }
0437:
0438: }
0439:
0440: /**
0441: * Returns the child specified by the index.
0442: * @param index which child to return
0443: * @return the children at location index
0444: */
0445: Node getChild(int index) {
0446:
0447: SceneGraphObjectRetained sgo = (SceneGraphObjectRetained) children
0448: .get(index);
0449: if (sgo == null)
0450: return null;
0451: else
0452: return (Node) sgo.source;
0453: }
0454:
0455: /**
0456: * Returns an enumeration object of the children.
0457: * @return an enumeration object of the children
0458: */
0459: Enumeration getAllChildren() {
0460: Vector userChildren = new Vector(children.size());
0461: SceneGraphObjectRetained sgo;
0462:
0463: for (int i = 0; i < children.size(); i++) {
0464: sgo = (SceneGraphObjectRetained) children.get(i);
0465: if (sgo != null)
0466: userChildren.add(sgo.source);
0467: else
0468: userChildren.add(null);
0469: }
0470:
0471: return userChildren.elements();
0472: }
0473:
0474: void checkValidChild(Node child, String s) {
0475:
0476: if ((child != null)
0477: && (((child instanceof BranchGroup) && (((BranchGroupRetained) child.retained).attachedToLocale)) || (((NodeRetained) child.retained).parent != null))) {
0478: throw new MultipleParentException(J3dI18N.getString(s));
0479: }
0480: }
0481:
0482: /**
0483: * Appends the specified child to this node's list of children.
0484: * @param child the child to add to this node's list of children
0485: */
0486: void addChild(Node child) {
0487: checkValidChild(child, "GroupRetained2");
0488:
0489: if (this .source.isLive()) {
0490: universe.resetWaitMCFlag();
0491: synchronized (universe.sceneGraphLock) {
0492: universe.notifyStructureChangeListeners(true,
0493: this .source, (BranchGroup) child);
0494: doAddChild(child, null, 0);
0495: universe.setLiveState.clear();
0496: }
0497: universe.waitForMC();
0498: } else {
0499: doAddChild(child, null, 0);
0500: if (universe != null) {
0501: synchronized (universe.sceneGraphLock) {
0502: universe.setLiveState.clear();
0503: }
0504: }
0505: }
0506: dirtyBoundsCache();
0507: }
0508:
0509: // The method that does the work once the lock is acquired.
0510: void doAddChild(Node child, J3dMessage messages[], int messageIndex) {
0511:
0512: appendChildrenData();
0513:
0514: if (child == null) {
0515: children.add(null);
0516: return;
0517: }
0518:
0519: NodeRetained childr = (NodeRetained) child.retained;
0520: childr.setParent(this );
0521: children.add(childr);
0522: checkSetLive(childr, children.size() - 1, messages,
0523: messageIndex, null);
0524: if (this .source.isLive()) {
0525: ((BranchGroupRetained) childr).isNew = true;
0526: }
0527:
0528: }
0529:
0530: void moveTo(BranchGroup bg) {
0531: if (bg != null) {
0532: ((GroupRetained) bg.retained).dirtyBoundsCache();
0533: }
0534: if (this .source.isLive()) {
0535: universe.resetWaitMCFlag();
0536: synchronized (universe.sceneGraphLock) {
0537: GroupRetained oldParent = (GroupRetained) ((BranchGroupRetained) bg.retained).parent;
0538: doMoveTo(bg);
0539: universe.setLiveState.clear();
0540: if (oldParent == null)
0541: universe.notifyStructureChangeListeners(
0542: ((BranchGroupRetained) bg.retained).locale,
0543: this .source, bg);
0544: else
0545: universe.notifyStructureChangeListeners(
0546: oldParent.source, this .source, bg);
0547: }
0548: universe.waitForMC();
0549: } else {
0550: doMoveTo(bg);
0551: if (universe != null) {
0552: synchronized (universe.sceneGraphLock) {
0553: universe.setLiveState.clear();
0554: }
0555: }
0556: }
0557: dirtyBoundsCache();
0558: }
0559:
0560: // The method that does the work once the lock is acquired.
0561: void doMoveTo(BranchGroup branchGroup) {
0562: J3dMessage messages[] = null;
0563: int numMessages = 0;
0564: int detachStartIndex = 0;
0565: int attachStartIndex = 0;
0566: if (branchGroup != null) {
0567: BranchGroupRetained bg = (BranchGroupRetained) branchGroup.retained;
0568: GroupRetained g = (GroupRetained) bg.parent;
0569:
0570: // Find out how many messages to be created
0571: // Note that g can be NULL if branchGroup parent is
0572: // a Locale, in this case the following condition
0573: // will fail.
0574: // Figure out the number of messages based on whether the group
0575: // from which its moving from is live and group to which its
0576: // moving to is live
0577: if (g != null) {
0578: if (g.source.isLive()) {
0579: numMessages = 3; // REMOVE_NODES, ORDERED_GROUP_REMOVED,VIEWSPECIFICGROUP_CLEAR
0580: attachStartIndex = 3;
0581: } else {
0582: numMessages = 0;
0583: attachStartIndex = 0;
0584: }
0585:
0586: } else { // Attached to locale
0587: numMessages = 3; // REMOVE_NODES, ORDERED_GROUP_REMOVED, VIEWSPECIFICGROUP_CLEAR
0588: attachStartIndex = 3;
0589: }
0590: // Now, do the evaluation for the group that its going to be
0591: // attached to ..
0592: if (this .source.isLive()) {
0593: numMessages += 4; // INSERT_NODES, BEHAVIOR_ACTIVATE
0594: // ORDERED_GROUP_INSERTED, VIEWSPECIFICGROUP_INIT
0595:
0596: }
0597: messages = new J3dMessage[numMessages];
0598: for (int i = 0; i < numMessages; i++) {
0599: messages[i] = new J3dMessage();
0600: messages[i].type = J3dMessage.INVALID_TYPE;
0601: }
0602:
0603: // Remove it from it's parents state
0604: if (g == null) {
0605: if (bg.locale != null) {
0606: bg.locale.doRemoveBranchGraph(branchGroup,
0607: messages, detachStartIndex);
0608: }
0609: } else {
0610: g.doRemoveChild(g.children.indexOf(bg), messages,
0611: detachStartIndex);
0612: }
0613: }
0614:
0615: // Add it to it's new parent
0616: doAddChild(branchGroup, messages, attachStartIndex);
0617:
0618: if (numMessages > 0) {
0619: int count = 0;
0620: for (int i = 0; i < numMessages; i++) {
0621: if (messages[i].type != J3dMessage.INVALID_TYPE) {
0622: count++;
0623: }
0624: }
0625: if (count == numMessages) {
0626: // in most cases
0627: VirtualUniverse.mc.processMessage(messages);
0628: } else {
0629: J3dMessage ms[] = null;
0630:
0631: if (count > 0) {
0632: ms = new J3dMessage[count];
0633: }
0634:
0635: int k = 0;
0636: for (int i = 0; i < numMessages; i++) {
0637: if (messages[i].type != J3dMessage.INVALID_TYPE) {
0638: ms[k++] = messages[i];
0639: }
0640: }
0641: if (ms != null) {
0642: VirtualUniverse.mc.processMessage(ms);
0643: }
0644: }
0645: }
0646: }
0647:
0648: /**
0649: * Returns a count of this nodes' children.
0650: * @return the number of children descendant from this node
0651: */
0652: int numChildren() {
0653: return children.size();
0654: }
0655:
0656: // Remove a light from the list of lights
0657: void removeLight(int numLgt, LightRetained[] removelight,
0658: HashKey key) {
0659: ArrayList l;
0660: int index;
0661: if (inSharedGroup) {
0662: int hkIndex = key.equals(localToVworldKeys, 0,
0663: localToVworldKeys.length);
0664: l = (ArrayList) lights.get(hkIndex);
0665: if (l != null) {
0666: for (int i = 0; i < numLgt; i++) {
0667: index = l.indexOf(removelight[i]);
0668: l.remove(index);
0669: }
0670: }
0671: } else {
0672: l = (ArrayList) lights.get(0);
0673: for (int i = 0; i < numLgt; i++) {
0674: index = l.indexOf(removelight[i]);
0675: l.remove(index);
0676: }
0677: }
0678:
0679: /*
0680: // XXXX: lights may remove twice or more during clearLive(),
0681: // one from itself and one call from every LightRetained
0682: // reference this. So there is case that this procedure get
0683: // called when light already removed.
0684: if (i >= 0)
0685: lights.remove(i);
0686: */
0687: }
0688:
0689: void addAllNodesForScopedLight(int numLgts, LightRetained[] ml,
0690: ArrayList list, HashKey k) {
0691: if (inSharedGroup) {
0692: for (int i = 0; i < localToVworldKeys.length; i++) {
0693: k.set(localToVworldKeys[i]);
0694: processAllNodesForScopedLight(numLgts, ml, list, k);
0695: }
0696: } else {
0697: processAllNodesForScopedLight(numLgts, ml, list, k);
0698: }
0699: }
0700:
0701: void processAllNodesForScopedLight(int numLgts, LightRetained[] ml,
0702: ArrayList list, HashKey k) {
0703: if (allocatedLights) {
0704: addLight(ml, numLgts, k);
0705: }
0706: if (this .source.isLive() || this .isInSetLive()) {
0707: for (int i = children.size() - 1; i >= 0; i--) {
0708: NodeRetained child = (NodeRetained) children.get(i);
0709: if (child != null) {
0710: if (child instanceof GroupRetained
0711: && (child.source.isLive() || child
0712: .isInSetLive()))
0713: ((GroupRetained) child)
0714: .processAllNodesForScopedLight(numLgts,
0715: ml, list, k);
0716: else if (child instanceof LinkRetained
0717: && (child.source.isLive() || child
0718: .isInSetLive())) {
0719: int lastCount = k.count;
0720: LinkRetained ln = (LinkRetained) child;
0721: if (k.count == 0) {
0722: k.append(locale.nodeId);
0723: }
0724: ((GroupRetained) (ln.sharedGroup))
0725: .processAllNodesForScopedLight(numLgts,
0726: ml, list, k.append("+").append(
0727: ln.nodeId));
0728: k.count = lastCount;
0729: } else if (child instanceof Shape3DRetained
0730: && child.source.isLive()) {
0731: ((Shape3DRetained) child).getMirrorObjects(
0732: list, k);
0733: } else if (child instanceof MorphRetained
0734: && child.source.isLive()) {
0735: ((MorphRetained) child).getMirrorObjects(list,
0736: k);
0737: }
0738: }
0739: }
0740: }
0741: }
0742:
0743: // If its a group, then add the scope to the group, if
0744: // its a shape, then keep a list to be added during
0745: // updateMirrorObject
0746: void removeAllNodesForScopedLight(int numLgts, LightRetained[] ml,
0747: ArrayList list, HashKey k) {
0748: if (inSharedGroup) {
0749: for (int i = 0; i < localToVworldKeys.length; i++) {
0750: k.set(localToVworldKeys[i]);
0751: processRemoveAllNodesForScopedLight(numLgts, ml, list,
0752: k);
0753: }
0754: } else {
0755: processRemoveAllNodesForScopedLight(numLgts, ml, list, k);
0756: }
0757: }
0758:
0759: void processRemoveAllNodesForScopedLight(int numLgts,
0760: LightRetained[] ml, ArrayList list, HashKey k) {
0761: if (allocatedLights) {
0762: removeLight(numLgts, ml, k);
0763: }
0764: // If the source is live, then notify the children
0765: if (this .source.isLive() && !isInClearLive) {
0766: for (int i = children.size() - 1; i >= 0; i--) {
0767: NodeRetained child = (NodeRetained) children.get(i);
0768: if (child != null) {
0769: if (child instanceof GroupRetained
0770: && (child.source.isLive() && !((GroupRetained) child).isInClearLive))
0771: ((GroupRetained) child)
0772: .processRemoveAllNodesForScopedLight(
0773: numLgts, ml, list, k);
0774: else if (child instanceof LinkRetained
0775: && child.source.isLive()) {
0776: int lastCount = k.count;
0777: LinkRetained ln = (LinkRetained) child;
0778: if (k.count == 0) {
0779: k.append(locale.nodeId);
0780: }
0781: ((GroupRetained) (ln.sharedGroup))
0782: .processRemoveAllNodesForScopedLight(
0783: numLgts, ml, list, k
0784: .append("+").append(
0785: ln.nodeId));
0786: k.count = lastCount;
0787: } else if (child instanceof Shape3DRetained
0788: && child.source.isLive()) {
0789: ((Shape3DRetained) child).getMirrorObjects(
0790: list, k);
0791: } else if (child instanceof MorphRetained
0792: && child.source.isLive()) {
0793: ((MorphRetained) child).getMirrorObjects(list,
0794: k);
0795: }
0796: }
0797: }
0798: }
0799: }
0800:
0801: void addAllNodesForScopedFog(FogRetained mfog, ArrayList list,
0802: HashKey k) {
0803: if (inSharedGroup) {
0804: for (int i = 0; i < localToVworldKeys.length; i++) {
0805: k.set(localToVworldKeys[i]);
0806: processAddNodesForScopedFog(mfog, list, k);
0807: }
0808: } else {
0809: processAddNodesForScopedFog(mfog, list, k);
0810: }
0811: }
0812:
0813: void processAddNodesForScopedFog(FogRetained mfog, ArrayList list,
0814: HashKey k) {
0815: // If this group has it own scoping list then add ..
0816: if (allocatedFogs)
0817: addFog(mfog, k);
0818: // If the source is live, then notify the children
0819: if (this .source.isLive() || this .isInSetLive()) {
0820: for (int i = children.size() - 1; i >= 0; i--) {
0821: NodeRetained child = (NodeRetained) children.get(i);
0822: if (child != null) {
0823: if (child instanceof GroupRetained
0824: && (child.source.isLive() || child
0825: .isInSetLive()))
0826: ((GroupRetained) child)
0827: .processAddNodesForScopedFog(mfog,
0828: list, k);
0829: else if (child instanceof LinkRetained
0830: && (child.source.isLive() || child
0831: .isInSetLive())) {
0832: int lastCount = k.count;
0833: LinkRetained ln = (LinkRetained) child;
0834: if (k.count == 0) {
0835: k.append(locale.nodeId);
0836: }
0837: ((GroupRetained) (ln.sharedGroup))
0838: .processAddNodesForScopedFog(mfog,
0839: list, k.append("+").append(
0840: ln.nodeId));
0841: k.count = lastCount;
0842: } else if (child instanceof Shape3DRetained
0843: && child.source.isLive()) {
0844: ((Shape3DRetained) child).getMirrorObjects(
0845: list, k);
0846: } else if (child instanceof MorphRetained
0847: && child.source.isLive()) {
0848: ((MorphRetained) child).getMirrorObjects(list,
0849: k);
0850: }
0851: }
0852: }
0853: }
0854: }
0855:
0856: // If its a group, then add the scope to the group, if
0857: // its a shape, then keep a list to be added during
0858: // updateMirrorObject
0859: void removeAllNodesForScopedFog(FogRetained mfog, ArrayList list,
0860: HashKey k) {
0861: if (inSharedGroup) {
0862: for (int i = 0; i < localToVworldKeys.length; i++) {
0863: k.set(localToVworldKeys[i]);
0864: processRemoveAllNodesForScopedFog(mfog, list, k);
0865: }
0866: } else {
0867: processRemoveAllNodesForScopedFog(mfog, list, k);
0868: }
0869: }
0870:
0871: void processRemoveAllNodesForScopedFog(FogRetained mfog,
0872: ArrayList list, HashKey k) {
0873: // If the source is live, then notify the children
0874: if (allocatedFogs)
0875: removeFog(mfog, k);
0876: if (this .source.isLive() && !isInClearLive) {
0877: for (int i = children.size() - 1; i >= 0; i--) {
0878: NodeRetained child = (NodeRetained) children.get(i);
0879: if (child != null) {
0880: if (child instanceof GroupRetained
0881: && (child.source.isLive() && !((GroupRetained) child).isInClearLive))
0882: ((GroupRetained) child)
0883: .processRemoveAllNodesForScopedFog(
0884: mfog, list, k);
0885: else if (child instanceof LinkRetained
0886: && child.source.isLive()) {
0887: int lastCount = k.count;
0888: LinkRetained ln = (LinkRetained) child;
0889: if (k.count == 0) {
0890: k.append(locale.nodeId);
0891: }
0892: ((GroupRetained) (ln.sharedGroup))
0893: .processRemoveAllNodesForScopedFog(
0894: mfog, list, k.append("+")
0895: .append(ln.nodeId));
0896: k.count = lastCount;
0897: } else if (child instanceof Shape3DRetained
0898: && child.source.isLive()) {
0899: ((Shape3DRetained) child).getMirrorObjects(
0900: list, k);
0901: } else if (child instanceof MorphRetained
0902: && child.source.isLive()) {
0903: ((MorphRetained) child).getMirrorObjects(list,
0904: k);
0905: }
0906: }
0907: }
0908: }
0909: }
0910:
0911: void addAllNodesForScopedModelClip(ModelClipRetained mModelClip,
0912: ArrayList list, HashKey k) {
0913: if (inSharedGroup) {
0914: for (int i = 0; i < localToVworldKeys.length; i++) {
0915: k.set(localToVworldKeys[i]);
0916: processAddNodesForScopedModelClip(mModelClip, list, k);
0917: }
0918: } else {
0919: processAddNodesForScopedModelClip(mModelClip, list, k);
0920: }
0921: }
0922:
0923: void processAddNodesForScopedModelClip(
0924: ModelClipRetained mModelClip, ArrayList list, HashKey k) {
0925: if (allocatedMclips)
0926: addModelClip(mModelClip, k);
0927: // If the source is live, then notify the children
0928: if (this .source.isLive() || this .isInSetLive()) {
0929: for (int i = children.size() - 1; i >= 0; i--) {
0930: NodeRetained child = (NodeRetained) children.get(i);
0931: if (child != null) {
0932: if (child instanceof GroupRetained
0933: && (child.source.isLive() || child
0934: .isInSetLive()))
0935: ((GroupRetained) child)
0936: .processAddNodesForScopedModelClip(
0937: mModelClip, list, k);
0938: else if (child instanceof LinkRetained
0939: && (child.source.isLive() || child
0940: .isInSetLive())) {
0941: int lastCount = k.count;
0942: LinkRetained ln = (LinkRetained) child;
0943: if (k.count == 0) {
0944: k.append(locale.nodeId);
0945: }
0946: ((GroupRetained) (ln.sharedGroup))
0947: .processAddNodesForScopedModelClip(
0948: mModelClip, list, k.append("+")
0949: .append(ln.nodeId));
0950: k.count = lastCount;
0951: } else if (child instanceof Shape3DRetained
0952: && child.source.isLive()) {
0953: ((Shape3DRetained) child).getMirrorObjects(
0954: list, k);
0955: } else if (child instanceof MorphRetained
0956: && child.source.isLive()) {
0957: ((MorphRetained) child).getMirrorObjects(list,
0958: k);
0959: }
0960: }
0961: }
0962: }
0963: }
0964:
0965: void removeAllNodesForScopedModelClip(ModelClipRetained mModelClip,
0966: ArrayList list, HashKey k) {
0967: if (inSharedGroup) {
0968: for (int i = 0; i < localToVworldKeys.length; i++) {
0969: k.set(localToVworldKeys[i]);
0970: processRemoveAllNodesForScopedModelClip(mModelClip,
0971: list, k);
0972: }
0973: } else {
0974: processRemoveAllNodesForScopedModelClip(mModelClip, list, k);
0975: }
0976:
0977: }
0978:
0979: // If its a group, then add the scope to the group, if
0980: // its a shape, then keep a list to be added during
0981: // updateMirrorObject
0982: void processRemoveAllNodesForScopedModelClip(
0983: ModelClipRetained mModelClip, ArrayList list, HashKey k) {
0984: // If the source is live, then notify the children
0985: if (allocatedMclips)
0986: removeModelClip(mModelClip, k);
0987: if (this .source.isLive() && !isInClearLive) {
0988: for (int i = children.size() - 1; i >= 0; i--) {
0989: NodeRetained child = (NodeRetained) children.get(i);
0990: if (child != null) {
0991: if (child instanceof GroupRetained
0992: && (child.source.isLive() && !((GroupRetained) child).isInClearLive))
0993: ((GroupRetained) child)
0994: .processRemoveAllNodesForScopedModelClip(
0995: mModelClip, list, k);
0996: else if (child instanceof LinkRetained
0997: && child.source.isLive()) {
0998: int lastCount = k.count;
0999: LinkRetained ln = (LinkRetained) child;
1000: if (k.count == 0) {
1001: k.append(locale.nodeId);
1002: }
1003: ((GroupRetained) (ln.sharedGroup))
1004: .processRemoveAllNodesForScopedModelClip(
1005: mModelClip, list, k.append("+")
1006: .append(ln.nodeId));
1007: k.count = lastCount;
1008: } else if (child instanceof Shape3DRetained
1009: && child.source.isLive()) {
1010: ((Shape3DRetained) child).getMirrorObjects(
1011: list, k);
1012: } else if (child instanceof MorphRetained
1013: && child.source.isLive()) {
1014: ((MorphRetained) child).getMirrorObjects(list,
1015: k);
1016: }
1017: }
1018: }
1019: }
1020: }
1021:
1022: void addAllNodesForScopedAltApp(
1023: AlternateAppearanceRetained mAltApp, ArrayList list,
1024: HashKey k) {
1025: if (inSharedGroup) {
1026: for (int i = 0; i < localToVworldKeys.length; i++) {
1027: k.set(localToVworldKeys[i]);
1028: processAddNodesForScopedAltApp(mAltApp, list, k);
1029: }
1030: } else {
1031: processAddNodesForScopedAltApp(mAltApp, list, k);
1032: }
1033: }
1034:
1035: // If its a group, then add the scope to the group, if
1036: // its a shape, then keep a list to be added during
1037: // updateMirrorObject
1038: void processAddNodesForScopedAltApp(
1039: AlternateAppearanceRetained mAltApp, ArrayList list,
1040: HashKey k) {
1041: // If the source is live, then notify the children
1042: if (allocatedAltApps)
1043: addAltApp(mAltApp, k);
1044: if (this .source.isLive() || this .isInSetLive()) {
1045: for (int i = children.size() - 1; i >= 0; i--) {
1046: NodeRetained child = (NodeRetained) children.get(i);
1047: if (child != null) {
1048: if (child instanceof GroupRetained
1049: && (child.source.isLive() || child
1050: .isInSetLive()))
1051: ((GroupRetained) child)
1052: .processAddNodesForScopedAltApp(
1053: mAltApp, list, k);
1054: else if (child instanceof LinkRetained
1055: && child.source.isLive()) {
1056: int lastCount = k.count;
1057: LinkRetained ln = (LinkRetained) child;
1058: if (k.count == 0) {
1059: k.append(locale.nodeId);
1060: }
1061: ((GroupRetained) (ln.sharedGroup))
1062: .processAddNodesForScopedAltApp(
1063: mAltApp, list, k.append("+")
1064: .append(ln.nodeId));
1065: k.count = lastCount;
1066: } else if (child instanceof Shape3DRetained
1067: && child.source.isLive()) {
1068: ((Shape3DRetained) child).getMirrorObjects(
1069: list, k);
1070: } else if (child instanceof MorphRetained
1071: && child.source.isLive()) {
1072: ((MorphRetained) child).getMirrorObjects(list,
1073: k);
1074: }
1075: }
1076: }
1077: }
1078: }
1079:
1080: void removeAllNodesForScopedAltApp(
1081: AlternateAppearanceRetained mAltApp, ArrayList list,
1082: HashKey k) {
1083: if (inSharedGroup) {
1084: for (int i = 0; i < localToVworldKeys.length; i++) {
1085: k.set(localToVworldKeys[i]);
1086: processRemoveNodesForScopedAltApp(mAltApp, list, k);
1087: }
1088: } else {
1089: processAddNodesForScopedAltApp(mAltApp, list, k);
1090: }
1091: }
1092:
1093: // If its a group, then add the scope to the group, if
1094: // its a shape, then keep a list to be added during
1095: // updateMirrorObject
1096: void processRemoveNodesForScopedAltApp(
1097: AlternateAppearanceRetained mAltApp, ArrayList list,
1098: HashKey k) {
1099: // If the source is live, then notify the children
1100: if (allocatedAltApps)
1101: removeAltApp(mAltApp, k);
1102: if (this .source.isLive() && !isInClearLive) {
1103: for (int i = children.size() - 1; i >= 0; i--) {
1104: NodeRetained child = (NodeRetained) children.get(i);
1105: if (child != null) {
1106: if (child instanceof GroupRetained
1107: && (child.source.isLive() && !((GroupRetained) child).isInClearLive))
1108: ((GroupRetained) child)
1109: .processRemoveNodesForScopedAltApp(
1110: mAltApp, list, k);
1111: else if (child instanceof LinkRetained
1112: && child.source.isLive()) {
1113: int lastCount = k.count;
1114: LinkRetained ln = (LinkRetained) child;
1115: if (k.count == 0) {
1116: k.append(locale.nodeId);
1117: }
1118: ((GroupRetained) (ln.sharedGroup))
1119: .processRemoveNodesForScopedAltApp(
1120: mAltApp, list, k.append("+")
1121: .append(ln.nodeId));
1122: k.count = lastCount;
1123: } else if (child instanceof Shape3DRetained
1124: && child.source.isLive()) {
1125: ((Shape3DRetained) child).getMirrorObjects(
1126: list, k);
1127: } else if (child instanceof MorphRetained
1128: && child.source.isLive()) {
1129: ((MorphRetained) child).getMirrorObjects(list,
1130: k);
1131: }
1132: }
1133: }
1134: }
1135: }
1136:
1137: synchronized void setLightScope() {
1138: // Make group's own copy
1139: ArrayList newLights;
1140: if (!allocatedLights) {
1141: allocatedLights = true;
1142: if (lights != null) {
1143: newLights = new ArrayList(lights.size());
1144: int size = lights.size();
1145: for (int i = 0; i < size; i++) {
1146: ArrayList l = (ArrayList) lights.get(i);
1147: if (l != null) {
1148: newLights.add(l.clone());
1149: } else {
1150: newLights.add(null);
1151: }
1152: }
1153: } else {
1154: if (inSharedGroup) {
1155: newLights = new ArrayList();
1156: for (int i = 0; i < localToVworldKeys.length; i++) {
1157: newLights.add(new ArrayList());
1158: }
1159: } else {
1160: newLights = new ArrayList();
1161: newLights.add(new ArrayList());
1162: }
1163: }
1164: lights = newLights;
1165:
1166: }
1167: scopingRefCount++;
1168: }
1169:
1170: synchronized void removeLightScope() {
1171: scopingRefCount--;
1172: }
1173:
1174: synchronized void setFogScope() {
1175: // Make group's own copy
1176: ArrayList newFogs;
1177: if (!allocatedFogs) {
1178: allocatedFogs = true;
1179: if (fogs != null) {
1180: newFogs = new ArrayList(fogs.size());
1181: int size = fogs.size();
1182: for (int i = 0; i < size; i++) {
1183: ArrayList l = (ArrayList) fogs.get(i);
1184: if (l != null) {
1185: newFogs.add(l.clone());
1186: } else {
1187: newFogs.add(null);
1188: }
1189: }
1190: } else {
1191: if (inSharedGroup) {
1192: newFogs = new ArrayList();
1193: for (int i = 0; i < localToVworldKeys.length; i++) {
1194: newFogs.add(new ArrayList());
1195: }
1196: } else {
1197: newFogs = new ArrayList();
1198: newFogs.add(new ArrayList());
1199: }
1200: }
1201: fogs = newFogs;
1202:
1203: }
1204: scopingRefCount++;
1205: }
1206:
1207: synchronized void removeFogScope() {
1208: scopingRefCount--;
1209: }
1210:
1211: synchronized void setMclipScope() {
1212: // Make group's own copy
1213: ArrayList newMclips;
1214: if (!allocatedMclips) {
1215: allocatedMclips = true;
1216: if (modelClips != null) {
1217: newMclips = new ArrayList(modelClips.size());
1218: int size = modelClips.size();
1219: for (int i = 0; i < size; i++) {
1220: ArrayList l = (ArrayList) modelClips.get(i);
1221: if (l != null) {
1222: newMclips.add(l.clone());
1223: } else {
1224: newMclips.add(null);
1225: }
1226: }
1227: } else {
1228: if (inSharedGroup) {
1229: newMclips = new ArrayList();
1230: for (int i = 0; i < localToVworldKeys.length; i++) {
1231: newMclips.add(new ArrayList());
1232: }
1233: } else {
1234: newMclips = new ArrayList();
1235: newMclips.add(new ArrayList());
1236: }
1237: }
1238: modelClips = newMclips;
1239:
1240: }
1241: scopingRefCount++;
1242: }
1243:
1244: synchronized void removeMclipScope() {
1245: scopingRefCount--;
1246: }
1247:
1248: synchronized void setAltAppScope() {
1249: // Make group's own copy
1250: ArrayList newAltApps;
1251: if (!allocatedAltApps) {
1252: allocatedAltApps = true;
1253: if (altAppearances != null) {
1254: newAltApps = new ArrayList(altAppearances.size());
1255: int size = altAppearances.size();
1256: for (int i = 0; i < size; i++) {
1257: ArrayList l = (ArrayList) altAppearances.get(i);
1258: if (l != null) {
1259: newAltApps.add(l.clone());
1260: } else {
1261: newAltApps.add(null);
1262: }
1263: }
1264: } else {
1265: if (inSharedGroup) {
1266: newAltApps = new ArrayList();
1267: for (int i = 0; i < localToVworldKeys.length; i++) {
1268: newAltApps.add(new ArrayList());
1269: }
1270: } else {
1271: newAltApps = new ArrayList();
1272: newAltApps.add(new ArrayList());
1273: }
1274: }
1275: altAppearances = newAltApps;
1276:
1277: }
1278: scopingRefCount++;
1279: }
1280:
1281: synchronized void removeAltAppScope() {
1282: scopingRefCount--;
1283: }
1284:
1285: synchronized boolean usedInScoping() {
1286: return (scopingRefCount > 0);
1287: }
1288:
1289: // Add a light to the list of lights
1290: void addLight(LightRetained[] addlight, int numLgts, HashKey key) {
1291: ArrayList l;
1292: if (inSharedGroup) {
1293: int hkIndex = key.equals(localToVworldKeys, 0,
1294: localToVworldKeys.length);
1295: l = (ArrayList) lights.get(hkIndex);
1296: if (l != null) {
1297: for (int i = 0; i < numLgts; i++) {
1298: l.add(addlight[i]);
1299: }
1300: }
1301: } else {
1302: l = (ArrayList) lights.get(0);
1303: for (int i = 0; i < numLgts; i++) {
1304: l.add(addlight[i]);
1305: }
1306: }
1307:
1308: }
1309:
1310: // Add a fog to the list of fogs
1311: void addFog(FogRetained fog, HashKey key) {
1312: ArrayList l;
1313: if (inSharedGroup) {
1314: int hkIndex = key.equals(localToVworldKeys, 0,
1315: localToVworldKeys.length);
1316: l = (ArrayList) fogs.get(hkIndex);
1317: if (l != null) {
1318: l.add(fog);
1319: }
1320: } else {
1321: l = (ArrayList) fogs.get(0);
1322: l.add(fog);
1323: }
1324:
1325: }
1326:
1327: // Add a ModelClip to the list of ModelClip
1328: void addModelClip(ModelClipRetained modelClip, HashKey key) {
1329: ArrayList l;
1330: if (inSharedGroup) {
1331: int hkIndex = key.equals(localToVworldKeys, 0,
1332: localToVworldKeys.length);
1333: l = (ArrayList) modelClips.get(hkIndex);
1334: if (l != null) {
1335: l.add(modelClip);
1336: }
1337: } else {
1338: l = (ArrayList) modelClips.get(0);
1339: l.add(modelClip);
1340: }
1341:
1342: }
1343:
1344: // Add a alt appearance to the list of alt appearance
1345: void addAltApp(AlternateAppearanceRetained altApp, HashKey key) {
1346: ArrayList l;
1347: if (inSharedGroup) {
1348: int hkIndex = key.equals(localToVworldKeys, 0,
1349: localToVworldKeys.length);
1350: l = (ArrayList) altAppearances.get(hkIndex);
1351: if (l != null) {
1352: l.add(altApp);
1353: }
1354: } else {
1355: l = (ArrayList) altAppearances.get(0);
1356: l.add(altApp);
1357: }
1358:
1359: }
1360:
1361: // Remove a fog from the list of fogs
1362: void removeFog(FogRetained fog, HashKey key) {
1363: ArrayList l;
1364: int index;
1365: if (inSharedGroup) {
1366: int hkIndex = key.equals(localToVworldKeys, 0,
1367: localToVworldKeys.length);
1368: l = (ArrayList) fogs.get(hkIndex);
1369: if (l != null) {
1370: index = l.indexOf(fog);
1371: l.remove(index);
1372: }
1373: } else {
1374: l = (ArrayList) fogs.get(0);
1375: index = l.indexOf(fog);
1376: l.remove(index);
1377: }
1378:
1379: }
1380:
1381: // Remove a ModelClip from the list of ModelClip
1382: void removeModelClip(ModelClipRetained modelClip, HashKey key) {
1383: ArrayList l;
1384: int index;
1385: if (inSharedGroup) {
1386: int hkIndex = key.equals(localToVworldKeys, 0,
1387: localToVworldKeys.length);
1388: l = (ArrayList) modelClips.get(hkIndex);
1389: if (l != null) {
1390: index = l.indexOf(modelClip);
1391: l.remove(index);
1392: }
1393: } else {
1394: l = (ArrayList) modelClips.get(0);
1395: index = l.indexOf(modelClip);
1396: l.remove(index);
1397: }
1398: }
1399:
1400: // Remove a fog from the list of alt appearance
1401: void removeAltApp(AlternateAppearanceRetained altApp, HashKey key) {
1402: ArrayList l;
1403: int index;
1404: if (inSharedGroup) {
1405: int hkIndex = key.equals(localToVworldKeys, 0,
1406: localToVworldKeys.length);
1407: l = (ArrayList) altAppearances.get(hkIndex);
1408: if (l != null) {
1409: index = l.indexOf(altApp);
1410: l.remove(index);
1411: }
1412: } else {
1413: l = (ArrayList) altAppearances.get(0);
1414: index = l.indexOf(altApp);
1415: l.remove(index);
1416: }
1417:
1418: }
1419:
1420: void updatePickable(HashKey keys[], boolean pick[]) {
1421: int numChildLessOne = children.size() - 1;
1422: super .updatePickable(keys, pick);
1423: int i = 0;
1424: NodeRetained child;
1425:
1426: // Fix for issue 540
1427: if (numChildLessOne < 0) {
1428: return;
1429: }
1430: // End fix for issue 540
1431:
1432: for (i = 0; i < numChildLessOne; i++) {
1433: child = (NodeRetained) children.get(i);
1434: if (child != null)
1435: child.updatePickable(keys, (boolean[]) pick.clone());
1436: }
1437: // No need to clone for the last value
1438:
1439: child = (NodeRetained) children.get(i);
1440: if (child != null)
1441: child.updatePickable(keys, pick);
1442:
1443: }
1444:
1445: void updateCollidable(HashKey keys[], boolean collide[]) {
1446: int numChildLessOne = children.size() - 1;
1447: super .updateCollidable(keys, collide);
1448: int i = 0;
1449: NodeRetained child;
1450:
1451: // Fix for issue 540
1452: if (numChildLessOne < 0) {
1453: return;
1454: }
1455: // End fix for issue 540
1456:
1457: for (i = 0; i < numChildLessOne; i++) {
1458: child = (NodeRetained) children.get(i);
1459: if (child != null)
1460: child.updateCollidable(keys, (boolean[]) collide
1461: .clone());
1462: }
1463: // No need to clone for the last value
1464: child = (NodeRetained) children.get(i);
1465: if (child != null)
1466: child.updateCollidable(keys, collide);
1467: }
1468:
1469: void setAlternateCollisionTarget(boolean target) {
1470: if (collisionTarget == target)
1471: return;
1472:
1473: collisionTarget = target;
1474:
1475: if (source.isLive()) {
1476: // Notify parent TransformGroup to add itself
1477: // Since we want to update collisionVwcBounds when
1478: // transform change in TransformStructure.
1479: TransformGroupRetained tg;
1480: J3dMessage message = new J3dMessage();
1481: message.threads = J3dThread.UPDATE_GEOMETRY;
1482: message.universe = universe;
1483: // send message to GeometryStructure to add/remove this
1484: // group node in BHTree as AlternateCollisionTarget
1485:
1486: int numPath;
1487: CachedTargets newCtArr[] = null;
1488:
1489: if (target) {
1490: createMirrorGroup();
1491:
1492: TargetsInterface ti = getClosestTargetsInterface(TargetsInterface.TRANSFORM_TARGETS);
1493: if (ti != null) {
1494:
1495: // update targets
1496: CachedTargets ct;
1497: Targets targets = new Targets();
1498: numPath = mirrorGroup.size();
1499: newCtArr = new CachedTargets[numPath];
1500: for (int i = 0; i < numPath; i++) {
1501: ct = ti.getCachedTargets(
1502: TargetsInterface.TRANSFORM_TARGETS, i,
1503: -1);
1504: if (ct != null) {
1505: targets.addNode((NnuId) mirrorGroup.get(i),
1506: Targets.GRP_TARGETS);
1507: newCtArr[i] = targets.snapShotAdd(ct);
1508: } else {
1509: newCtArr[i] = null;
1510: }
1511: }
1512:
1513: // update target threads and propagate change to above
1514: // nodes in scene graph
1515: ti.updateTargetThreads(
1516: TargetsInterface.TRANSFORM_TARGETS,
1517: newCtArr);
1518: ti.resetCachedTargets(
1519: TargetsInterface.TRANSFORM_TARGETS,
1520: newCtArr, -1);
1521: }
1522:
1523: message.type = J3dMessage.INSERT_NODES;
1524: message.args[0] = mirrorGroup.toArray();
1525: message.args[1] = ti;
1526: message.args[2] = newCtArr;
1527:
1528: } else {
1529: TargetsInterface ti = getClosestTargetsInterface(TargetsInterface.TRANSFORM_TARGETS);
1530: if (ti != null) {
1531:
1532: // update targets
1533: Targets targets = new Targets();
1534: CachedTargets ct;
1535: numPath = mirrorGroup.size();
1536: newCtArr = new CachedTargets[numPath];
1537: for (int i = 0; i < numPath; i++) {
1538: ct = ti.getCachedTargets(
1539: TargetsInterface.TRANSFORM_TARGETS, i,
1540: -1);
1541: if (ct != null) {
1542: targets.addNode((NnuId) mirrorGroup.get(i),
1543: Targets.GRP_TARGETS);
1544: //Note snapShotRemove calls targets.clearNode()
1545: newCtArr[i] = targets.snapShotRemove(ct);
1546: } else {
1547: newCtArr[i] = null;
1548: }
1549: }
1550: // update target threads and propagate change to above
1551: // nodes in scene graph
1552: ti.updateTargetThreads(
1553: TargetsInterface.TRANSFORM_TARGETS,
1554: newCtArr);
1555: ti.resetCachedTargets(
1556: TargetsInterface.TRANSFORM_TARGETS,
1557: newCtArr, -1);
1558: }
1559:
1560: message.type = J3dMessage.REMOVE_NODES;
1561: message.args[0] = mirrorGroup.toArray();
1562: message.args[1] = ti;
1563: message.args[2] = newCtArr;
1564: mirrorGroup = null; // for gc
1565: }
1566: VirtualUniverse.mc.processMessage(message);
1567: }
1568: }
1569:
1570: boolean getAlternateCollisionTarget() {
1571: return collisionTarget;
1572: }
1573:
1574: /**
1575: * This checks is setLive needs to be called. If it does, it gets the
1576: * needed info and calls it.
1577: */
1578: void checkSetLive(NodeRetained child, int childIndex,
1579: J3dMessage messages[], int messageIndex,
1580: NodeRetained linkNode) {
1581: checkSetLive(child, childIndex, localToVworldKeys,
1582: inSharedGroup, messages, messageIndex, linkNode);
1583: }
1584:
1585: /**
1586: * This checks is setLive needs to be called. If it does, it gets the
1587: * needed info and calls it.
1588: */
1589: void checkSetLive(NodeRetained child, int childIndex,
1590: HashKey keys[], boolean isShared, J3dMessage messages[],
1591: int messageIndex, NodeRetained linkNode) {
1592:
1593: SceneGraphObject me = this .source;
1594: SetLiveState s;
1595: J3dMessage createMessage;
1596: boolean sendMessages = false;
1597: boolean sendOGMessage = true;
1598: boolean sendVSGMessage = true;
1599:
1600: if (me.isLive()) {
1601:
1602: s = universe.setLiveState;
1603: s.reset(locale);
1604: s.refCount = refCount;
1605: s.inSharedGroup = isShared;
1606: s.inBackgroundGroup = inBackgroundGroup;
1607: s.inViewSpecificGroup = inViewSpecificGroup;
1608: s.geometryBackground = geometryBackground;
1609: s.keys = keys;
1610: s.viewLists = viewLists;
1611: s.parentBranchGroupPaths = branchGroupPaths;
1612: // Note that there is no need to clone individual
1613: // branchGroupArray since they will get replace (not append)
1614: // by creating a new reference in child's group.
1615: s.branchGroupPaths = (ArrayList) branchGroupPaths.clone();
1616: s.orderedPaths = orderedPaths;
1617:
1618: // Make the scoped fogs and lights of the child to include, the
1619: // the scoped fog of this group
1620: s.lights = lights;
1621: s.altAppearances = altAppearances;
1622: s.fogs = fogs;
1623: s.modelClips = modelClips;
1624:
1625: boolean pick[];
1626: boolean collide[];
1627:
1628: if (!inSharedGroup) {
1629: pick = new boolean[1];
1630: collide = new boolean[1];
1631: } else {
1632: pick = new boolean[localToVworldKeys.length];
1633: collide = new boolean[localToVworldKeys.length];
1634: }
1635: findPickableFlags(pick);
1636: super .updatePickable(null, pick);
1637: s.pickable = pick;
1638:
1639: findCollidableFlags(collide);
1640: super .updateCollidable(null, collide);
1641: s.collidable = collide;
1642:
1643: TargetsInterface transformInterface, switchInterface;
1644: transformInterface = initTransformStates(s, true);
1645: switchInterface = initSwitchStates(s, this , child,
1646: linkNode, true);
1647:
1648: if (s.inViewSpecificGroup && (s.changedViewGroup == null)) {
1649: s.changedViewGroup = new ArrayList();
1650: s.changedViewList = new ArrayList();
1651: s.keyList = new int[10];
1652: s.viewScopedNodeList = new ArrayList();
1653: s.scopedNodesViewList = new ArrayList();
1654: }
1655:
1656: childCheckSetLive(child, childIndex, s, linkNode);
1657:
1658: CachedTargets[] newCtArr = null;
1659: newCtArr = updateTransformStates(s, transformInterface,
1660: true);
1661: updateSwitchStates(s, switchInterface, true);
1662:
1663: // We're sending multiple messages in the call, inorder to
1664: // have all these messages to be process as an atomic operation.
1665: // We need to create an array of messages to MasterControl, this
1666: // will ensure that all these messages will get the same time stamp.
1667:
1668: // If it is called from "moveTo", messages is not null.
1669: if (messages == null) {
1670: int numMessages = 2;
1671: if (s.ogList.size() > 0) {
1672: numMessages++;
1673: } else {
1674: sendOGMessage = false;
1675: }
1676: if (s.changedViewGroup != null) {
1677: numMessages++;
1678: } else {
1679: sendVSGMessage = false;
1680: }
1681:
1682: messages = new J3dMessage[numMessages];
1683: messageIndex = 0;
1684: for (int mIndex = 0; mIndex < numMessages; mIndex++) {
1685: messages[mIndex] = new J3dMessage();
1686: }
1687: sendMessages = true;
1688: }
1689:
1690: if (sendOGMessage) {
1691: createMessage = messages[messageIndex++];
1692: createMessage.threads = J3dThread.UPDATE_RENDER
1693: | J3dThread.UPDATE_RENDERING_ENVIRONMENT;
1694: createMessage.type = J3dMessage.ORDERED_GROUP_INSERTED;
1695: createMessage.universe = universe;
1696: createMessage.args[0] = s.ogList.toArray();
1697: createMessage.args[1] = s.ogChildIdList.toArray();
1698: createMessage.args[2] = s.ogOrderedIdList.toArray();
1699: createMessage.args[3] = s.ogCIOList.toArray();
1700: createMessage.args[4] = s.ogCIOTableList.toArray();
1701: }
1702:
1703: if (sendVSGMessage) {
1704: createMessage = messages[messageIndex++];
1705: createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT;
1706: createMessage.type = J3dMessage.VIEWSPECIFICGROUP_INIT;
1707: createMessage.universe = universe;
1708: createMessage.args[0] = s.changedViewGroup;
1709: createMessage.args[1] = s.changedViewList;
1710: createMessage.args[2] = s.keyList;
1711: }
1712:
1713: createMessage = messages[messageIndex++];
1714: createMessage.threads = s.notifyThreads;
1715: createMessage.type = J3dMessage.INSERT_NODES;
1716: createMessage.universe = universe;
1717: createMessage.args[0] = s.nodeList.toArray();
1718: if (newCtArr != null) {
1719: createMessage.args[1] = transformInterface;
1720: createMessage.args[2] = newCtArr;
1721: } else {
1722: createMessage.args[1] = null;
1723: createMessage.args[2] = null;
1724: }
1725:
1726: if (s.viewScopedNodeList != null) {
1727: createMessage.args[3] = s.viewScopedNodeList;
1728: createMessage.args[4] = s.scopedNodesViewList;
1729: }
1730:
1731: // execute user behavior's initialize methods
1732: int sz = s.behaviorNodes.size();
1733:
1734: for (int i = 0; i < sz; i++) {
1735: BehaviorRetained b;
1736: b = (BehaviorRetained) s.behaviorNodes.get(i);
1737: b.executeInitialize();
1738: }
1739:
1740: s.behaviorNodes.clear();
1741:
1742: createMessage = messages[messageIndex++];
1743:
1744: createMessage.threads = J3dThread.UPDATE_BEHAVIOR;
1745: createMessage.type = J3dMessage.BEHAVIOR_ACTIVATE;
1746: createMessage.universe = universe;
1747:
1748: if (sendMessages == true) {
1749: VirtualUniverse.mc.processMessage(messages);
1750: }
1751:
1752: if (nodeType == NodeRetained.SWITCH) {
1753: // force reEvaluation of switch children
1754: SwitchRetained sw = (SwitchRetained) this ;
1755: sw.setWhichChild(sw.whichChild, true);
1756: }
1757:
1758: //Reset SetLiveState to free up memory.
1759: s.reset(null);
1760: }
1761: }
1762:
1763: void checkClearLive(NodeRetained child, J3dMessage messages[],
1764: int messageIndex, int childIndex, NodeRetained linkNode) {
1765: checkClearLive(child, localToVworldKeys, inSharedGroup,
1766: messages, messageIndex, childIndex, linkNode);
1767: }
1768:
1769: /**
1770: * This checks if clearLive needs to be called. If it does, it gets the
1771: * needed info and calls it.
1772: */
1773: void checkClearLive(NodeRetained child, HashKey keys[],
1774: boolean isShared, J3dMessage messages[], int messageIndex,
1775: int childIndex, NodeRetained linkNode) {
1776:
1777: SceneGraphObject me = this .source;
1778: J3dMessage destroyMessage;
1779: boolean sendMessages = false;
1780: boolean sendOGMessage = true;
1781: boolean sendVSGMessage = true;
1782:
1783: int i, j;
1784: TransformGroupRetained tg;
1785:
1786: if (me.isLive()) {
1787: SetLiveState s = universe.setLiveState;
1788:
1789: s.reset(locale);
1790: s.refCount = refCount;
1791: s.inSharedGroup = isShared;
1792: s.inBackgroundGroup = inBackgroundGroup;
1793: s.inViewSpecificGroup = inViewSpecificGroup;
1794: s.keys = keys;
1795: s.fogs = fogs;
1796: s.lights = lights;
1797: s.altAppearances = altAppearances;
1798: s.modelClips = modelClips;
1799:
1800: // Issue 312: Allocate data structures if we are in a ViewSpecificGroup
1801: if (s.inViewSpecificGroup && (s.changedViewGroup == null)) {
1802: s.changedViewGroup = new ArrayList();
1803: s.changedViewList = new ArrayList();
1804: s.keyList = new int[10];
1805: s.viewScopedNodeList = new ArrayList();
1806: s.scopedNodesViewList = new ArrayList();
1807: }
1808:
1809: if (this instanceof OrderedGroupRetained
1810: && linkNode == null) {
1811: // set this regardless of refCount
1812: s.ogList.add(this );
1813: s.ogChildIdList.add(new Integer(childIndex));
1814: s.ogCIOList.add(this );
1815: int[] newArr = null;
1816: OrderedGroupRetained og = (OrderedGroupRetained) this ;
1817: if (og.userChildIndexOrder != null) {
1818: newArr = new int[og.userChildIndexOrder.length];
1819: System.arraycopy(og.userChildIndexOrder, 0, newArr,
1820: 0, og.userChildIndexOrder.length);
1821: }
1822: s.ogCIOTableList.add(newArr);
1823:
1824: }
1825:
1826: // Issue 312: always initialize s.viewLists
1827: s.viewLists = viewLists;
1828:
1829: TargetsInterface transformInterface, switchInterface;
1830: transformInterface = initTransformStates(s, false);
1831: switchInterface = initSwitchStates(s, this , child,
1832: linkNode, false);
1833:
1834: child.clearLive(s);
1835:
1836: CachedTargets[] newCtArr = null;
1837: newCtArr = updateTransformStates(s, transformInterface,
1838: false);
1839: updateSwitchStates(s, switchInterface, false);
1840:
1841: // We're sending multiple messages in the call, inorder to
1842: // have all these messages to be process as an atomic operation.
1843: // We need to create an array of messages to MasterControl, this
1844: // will ensure that all these messages will get the same time stamp.
1845:
1846: // If it is called from "moveTo", messages is not null.
1847: if (messages == null) {
1848: int numMessages = 1;
1849: if (s.ogList.size() > 0) {
1850: numMessages++;
1851: } else {
1852: sendOGMessage = false;
1853: }
1854:
1855: if (s.changedViewGroup != null) {
1856: numMessages++;
1857: } else {
1858: sendVSGMessage = false;
1859: }
1860:
1861: messages = new J3dMessage[numMessages];
1862: messageIndex = 0;
1863: for (int mIndex = 0; mIndex < numMessages; mIndex++) {
1864: messages[mIndex] = new J3dMessage();
1865: }
1866: sendMessages = true;
1867: }
1868:
1869: if (sendOGMessage) {
1870: destroyMessage = messages[messageIndex++];
1871: destroyMessage.threads = J3dThread.UPDATE_RENDER
1872: | J3dThread.UPDATE_RENDERING_ENVIRONMENT;
1873: destroyMessage.type = J3dMessage.ORDERED_GROUP_REMOVED;
1874: destroyMessage.universe = universe;
1875: destroyMessage.args[0] = s.ogList.toArray();
1876: destroyMessage.args[1] = s.ogChildIdList.toArray();
1877: destroyMessage.args[3] = s.ogCIOList.toArray();
1878: destroyMessage.args[4] = s.ogCIOTableList.toArray();
1879: }
1880:
1881: // Issue 312: We need to send the REMOVE_NODES message to the
1882: // RenderingEnvironmentStructure before we send VIEWSPECIFICGROUP_CLEAR,
1883: // since the latter clears the list of views that is referred to by
1884: // scopedNodesViewList and used by removeNodes.
1885: destroyMessage = messages[messageIndex++];
1886: destroyMessage.threads = s.notifyThreads;
1887: destroyMessage.type = J3dMessage.REMOVE_NODES;
1888: destroyMessage.universe = universe;
1889: destroyMessage.args[0] = s.nodeList.toArray();
1890:
1891: if (newCtArr != null) {
1892: destroyMessage.args[1] = transformInterface;
1893: destroyMessage.args[2] = newCtArr;
1894: } else {
1895: destroyMessage.args[1] = null;
1896: destroyMessage.args[2] = null;
1897: }
1898: if (s.viewScopedNodeList != null) {
1899: destroyMessage.args[3] = s.viewScopedNodeList;
1900: destroyMessage.args[4] = s.scopedNodesViewList;
1901: }
1902:
1903: if (sendVSGMessage) {
1904: destroyMessage = messages[messageIndex++];
1905: destroyMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT;
1906: destroyMessage.type = J3dMessage.VIEWSPECIFICGROUP_CLEAR;
1907: destroyMessage.universe = universe;
1908: destroyMessage.args[0] = s.changedViewGroup;
1909: destroyMessage.args[1] = s.keyList;
1910: }
1911:
1912: if (sendMessages == true) {
1913: VirtualUniverse.mc.processMessage(messages);
1914: }
1915:
1916: s.reset(null); // for GC
1917: }
1918: }
1919:
1920: TargetsInterface initTransformStates(SetLiveState s,
1921: boolean isSetLive) {
1922:
1923: int numPaths = (inSharedGroup) ? s.keys.length : 1;
1924: TargetsInterface ti = getClosestTargetsInterface(TargetsInterface.TRANSFORM_TARGETS);
1925:
1926: if (isSetLive) {
1927: s.currentTransforms = localToVworld;
1928: s.currentTransformsIndex = localToVworldIndex;
1929: s.localToVworldKeys = localToVworldKeys;
1930: s.localToVworld = s.currentTransforms;
1931: s.localToVworldIndex = s.currentTransformsIndex;
1932:
1933: s.parentTransformLink = parentTransformLink;
1934: if (parentTransformLink != null) {
1935: if (parentTransformLink instanceof TransformGroupRetained) {
1936: TransformGroupRetained tg;
1937: tg = (TransformGroupRetained) parentTransformLink;
1938: s.childTransformLinks = tg.childTransformLinks;
1939: } else {
1940: SharedGroupRetained sg;
1941: sg = (SharedGroupRetained) parentTransformLink;
1942: s.childTransformLinks = sg.childTransformLinks;
1943: }
1944: }
1945: }
1946:
1947: int transformLevels[] = new int[numPaths];
1948: findTransformLevels(transformLevels);
1949: s.transformLevels = transformLevels;
1950:
1951: if (ti != null) {
1952: Targets[] newTargets = new Targets[numPaths];
1953: for (int i = 0; i < numPaths; i++) {
1954: if (s.transformLevels[i] >= 0) {
1955: newTargets[i] = new Targets();
1956: } else {
1957: newTargets[i] = null;
1958: }
1959: }
1960: s.transformTargets = newTargets;
1961:
1962: // XXXX: optimization for targetThreads computation, require
1963: // cleanup in GroupRetained.doSetLive()
1964: //s.transformTargetThreads = 0;
1965: }
1966:
1967: return ti;
1968: }
1969:
1970: CachedTargets[] updateTransformStates(SetLiveState s,
1971: TargetsInterface ti, boolean isSetLive) {
1972: CachedTargets[] newCtArr = null;
1973:
1974: if (ti != null) {
1975: if (isSetLive) {
1976: CachedTargets ct;
1977: int newTargetThreads = 0;
1978: int hkIndex;
1979:
1980: newCtArr = new CachedTargets[localToVworld.length];
1981:
1982: // update targets
1983: if (!inSharedGroup) {
1984: if (s.transformTargets[0] != null) {
1985: ct = ti.getCachedTargets(
1986: TargetsInterface.TRANSFORM_TARGETS, 0,
1987: -1);
1988: if (ct != null) {
1989: newCtArr[0] = s.transformTargets[0]
1990: .snapShotAdd(ct);
1991: }
1992: } else {
1993: newCtArr[0] = null;
1994: }
1995: } else {
1996: for (int i = 0; i < s.keys.length; i++) {
1997:
1998: if (s.transformTargets[i] != null) {
1999: ct = ti.getCachedTargets(
2000: TargetsInterface.TRANSFORM_TARGETS,
2001: i, -1);
2002: if (ct != null) {
2003: newCtArr[i] = s.transformTargets[i]
2004: .snapShotAdd(ct);
2005: }
2006: } else {
2007: newCtArr[i] = null;
2008: }
2009: }
2010: }
2011: } else {
2012:
2013: CachedTargets ct;
2014: int hkIndex;
2015:
2016: newCtArr = new CachedTargets[localToVworld.length];
2017:
2018: if (!inSharedGroup) {
2019: if (s.transformTargets[0] != null) {
2020: ct = ti.getCachedTargets(
2021: TargetsInterface.TRANSFORM_TARGETS, 0,
2022: -1);
2023: if (ct != null) {
2024: newCtArr[0] = s.transformTargets[0]
2025: .snapShotRemove(ct);
2026: }
2027: } else {
2028: newCtArr[0] = null;
2029: }
2030: } else {
2031: for (int i = 0; i < s.keys.length; i++) {
2032: if (s.transformTargets[i] != null) {
2033: ct = ti.getCachedTargets(
2034: TargetsInterface.TRANSFORM_TARGETS,
2035: i, -1);
2036: if (ct != null) {
2037: newCtArr[i] = s.transformTargets[i]
2038: .snapShotRemove(ct);
2039: }
2040: } else {
2041: newCtArr[i] = null;
2042: }
2043: }
2044: }
2045: }
2046: // update target threads and propagate change to above
2047: // nodes in scene graph
2048:
2049: ti.updateTargetThreads(TargetsInterface.TRANSFORM_TARGETS,
2050: newCtArr);
2051: ti.resetCachedTargets(TargetsInterface.TRANSFORM_TARGETS,
2052: newCtArr, -1);
2053:
2054: }
2055: return newCtArr;
2056: }
2057:
2058: TargetsInterface initSwitchStates(SetLiveState s,
2059: NodeRetained parentNode, NodeRetained childNode,
2060: NodeRetained linkNode, boolean isSetLive) {
2061: NodeRetained child;
2062: NodeRetained parent;
2063: int i, j;
2064:
2065: findSwitchInfo(s, parentNode, childNode, linkNode);
2066: TargetsInterface ti = getClosestTargetsInterface(TargetsInterface.SWITCH_TARGETS);
2067: if (ti != null) {
2068: Targets[] newTargets = null;
2069: int numPaths = (inSharedGroup) ? s.keys.length : 1;
2070: newTargets = new Targets[numPaths];
2071: for (i = 0; i < numPaths; i++) {
2072: if (s.switchLevels[i] >= 0) {
2073: newTargets[i] = new Targets();
2074: } else {
2075: newTargets[i] = null;
2076: }
2077: }
2078: s.switchTargets = newTargets;
2079: }
2080:
2081: if (isSetLive) {
2082: // set switch states
2083: if (nodeType == NodeRetained.SWITCH) {
2084: i = parentSwitchLinkChildIndex;
2085: s.childSwitchLinks = (ArrayList) childrenSwitchLinks
2086: .get(i);
2087: s.parentSwitchLink = this ;
2088:
2089: } else {
2090: if (nodeType == NodeRetained.SHAREDGROUP) {
2091: i = parentSwitchLinkChildIndex;
2092: s.childSwitchLinks = (ArrayList) childrenSwitchLinks
2093: .get(i);
2094: s.parentSwitchLink = this ;
2095:
2096: } else {
2097: s.parentSwitchLink = parentSwitchLink;
2098: if (parentSwitchLink != null) {
2099: i = parentSwitchLinkChildIndex;
2100: s.childSwitchLinks = (ArrayList) parentSwitchLink.childrenSwitchLinks
2101: .get(i);
2102: }
2103: }
2104: }
2105: if (ti != null) {
2106: s.switchStates = ti.getTargetsData(
2107: TargetsInterface.SWITCH_TARGETS,
2108: parentSwitchLinkChildIndex);
2109: } else {
2110: s.switchStates = new ArrayList(1);
2111: s.switchStates.add(new SwitchState(false));
2112: }
2113: }
2114: return ti;
2115: }
2116:
2117: void updateSwitchStates(SetLiveState s, TargetsInterface ti,
2118: boolean isSetLive) {
2119:
2120: // update switch leaves's compositeSwitchMask for ancestors
2121: // and update switch leaves' switchOn flag if at top level switch
2122:
2123: if (ti != null) {
2124: if (isSetLive) {
2125: CachedTargets[] newCtArr = null;
2126: CachedTargets ct;
2127:
2128: newCtArr = new CachedTargets[localToVworld.length];
2129:
2130: // update targets
2131: if (!inSharedGroup) {
2132:
2133: if (s.switchTargets[0] != null) {
2134: ct = ti.getCachedTargets(
2135: TargetsInterface.SWITCH_TARGETS, 0,
2136: parentSwitchLinkChildIndex);
2137: if (ct != null) {
2138: newCtArr[0] = s.switchTargets[0]
2139: .snapShotAdd(ct);
2140: } else {
2141: newCtArr[0] = s.switchTargets[0]
2142: .snapShotInit();
2143: }
2144: } else {
2145: newCtArr[0] = null;
2146: }
2147: } else {
2148: for (int i = 0; i < s.keys.length; i++) {
2149: if (s.switchTargets[i] != null) {
2150: ct = ti.getCachedTargets(
2151: TargetsInterface.SWITCH_TARGETS, i,
2152: parentSwitchLinkChildIndex);
2153: if (ct != null) {
2154: newCtArr[i] = s.switchTargets[i]
2155: .snapShotAdd(ct);
2156: } else {
2157: newCtArr[i] = s.switchTargets[i]
2158: .snapShotInit();
2159: }
2160: } else {
2161: newCtArr[i] = null;
2162: }
2163: }
2164: }
2165: ti.resetCachedTargets(TargetsInterface.SWITCH_TARGETS,
2166: newCtArr, parentSwitchLinkChildIndex);
2167: if (ti instanceof SwitchRetained) {
2168: ((SwitchRetained) ti).traverseSwitchParent();
2169: } else if (ti instanceof SharedGroupRetained) {
2170: ((SharedGroupRetained) ti).traverseSwitchParent();
2171: }
2172: } else {
2173: CachedTargets ct;
2174:
2175: CachedTargets[] newCtArr = new CachedTargets[localToVworld.length];
2176:
2177: if (!inSharedGroup) {
2178: if (s.switchTargets[0] != null) {
2179: ct = ti.getCachedTargets(
2180: TargetsInterface.SWITCH_TARGETS, 0,
2181: parentSwitchLinkChildIndex);
2182: if (ct != null) {
2183: newCtArr[0] = s.switchTargets[0]
2184: .snapShotRemove(ct);
2185: }
2186: } else {
2187: newCtArr[0] = null;
2188: }
2189: } else {
2190: for (int i = 0; i < s.keys.length; i++) {
2191: if (s.switchTargets[i] != null) {
2192: ct = ti.getCachedTargets(
2193: TargetsInterface.SWITCH_TARGETS, i,
2194: parentSwitchLinkChildIndex);
2195:
2196: if (ct != null) {
2197: newCtArr[i] = s.switchTargets[i]
2198: .snapShotRemove(ct);
2199: }
2200: } else {
2201: newCtArr[i] = null;
2202: }
2203: }
2204: }
2205: ti.resetCachedTargets(TargetsInterface.SWITCH_TARGETS,
2206: newCtArr, parentSwitchLinkChildIndex);
2207: }
2208: }
2209: }
2210:
2211: void appendChildrenData() {
2212: }
2213:
2214: void insertChildrenData(int index) {
2215: }
2216:
2217: void removeChildrenData(int index) {
2218: }
2219:
2220: TargetsInterface getClosestTargetsInterface(int type) {
2221: return (type == TargetsInterface.TRANSFORM_TARGETS) ? (TargetsInterface) parentTransformLink
2222: : (TargetsInterface) parentSwitchLink;
2223: }
2224:
2225: synchronized void updateLocalToVworld() {
2226: NodeRetained child;
2227:
2228: // For each children call .....
2229: for (int i = children.size() - 1; i >= 0; i--) {
2230: child = (NodeRetained) children.get(i);
2231: if (child != null)
2232: child.updateLocalToVworld();
2233: }
2234: }
2235:
2236: void setNodeData(SetLiveState s) {
2237: super .setNodeData(s);
2238: orderedPaths = s.orderedPaths;
2239: }
2240:
2241: void removeNodeData(SetLiveState s) {
2242:
2243: if ((!inSharedGroup) || (s.keys.length == localToVworld.length)) {
2244: orderedPaths = null;
2245: } else {
2246: // Set it back to its parent localToVworld data. This is b/c the
2247: // parent has changed it localToVworld data arrays.
2248: orderedPaths = s.orderedPaths;
2249: }
2250: super .removeNodeData(s);
2251: }
2252:
2253: void setLive(SetLiveState s) {
2254: doSetLive(s);
2255: super .markAsLive();
2256: }
2257:
2258: // Note that SwitchRetained, OrderedGroupRetained and SharedGroupRetained
2259: // override this method
2260: void childDoSetLive(NodeRetained child, int childIndex,
2261: SetLiveState s) {
2262: if (child != null)
2263: child.setLive(s);
2264: }
2265:
2266: // Note that BranchRetained, OrderedGroupRetained and SharedGroupRetained
2267: // TransformGroupRetained override this method
2268: void childCheckSetLive(NodeRetained child, int childIndex,
2269: SetLiveState s, NodeRetained linkNode) {
2270: child.setLive(s);
2271: }
2272:
2273: /**
2274: * This version of setLive calls setLive on all of its chidren.
2275: */
2276: void doSetLive(SetLiveState s) {
2277: int i, nchildren;
2278: NodeRetained child;
2279: super .doSetLive(s);
2280: locale = s.locale;
2281:
2282: inViewSpecificGroup = s.inViewSpecificGroup;
2283: nchildren = children.size();
2284: ArrayList savedScopedLights = s.lights;
2285: ArrayList savedScopedFogs = s.fogs;
2286: ArrayList savedScopedAltApps = s.altAppearances;
2287: ArrayList savedScopedMclips = s.modelClips;
2288:
2289: boolean oldpickableArray[] = (boolean[]) s.pickable.clone();
2290: boolean oldcollidableArray[] = (boolean[]) s.collidable.clone();
2291: boolean workingpickableArray[] = new boolean[oldpickableArray.length];
2292: boolean workingcollidableArray[] = new boolean[oldcollidableArray.length];
2293: ArrayList oldBranchGroupPaths = s.branchGroupPaths;
2294: setScopingInfo(s);
2295:
2296: if (!(this instanceof ViewSpecificGroupRetained)) {
2297: viewLists = s.viewLists;
2298: }
2299:
2300: for (i = 0; i < nchildren; i++) {
2301: child = (NodeRetained) children.get(i);
2302:
2303: // Restore old values before child.setLive(s)
2304: System.arraycopy(oldpickableArray, 0, workingpickableArray,
2305: 0, oldpickableArray.length);
2306: System.arraycopy(oldcollidableArray, 0,
2307: workingcollidableArray, 0,
2308: oldcollidableArray.length);
2309: s.pickable = workingpickableArray;
2310: s.collidable = workingcollidableArray;
2311: // s.branchGroupPaths will be modified by child setLive()
2312: // so we have to restore it every time.
2313: s.parentBranchGroupPaths = branchGroupPaths;
2314: s.branchGroupPaths = (ArrayList) oldBranchGroupPaths
2315: .clone();
2316: s.inViewSpecificGroup = inViewSpecificGroup;
2317: childDoSetLive(child, i, s);
2318: }
2319:
2320: if (collisionTarget) {
2321: processCollisionTarget(s);
2322: }
2323:
2324: s.lights = savedScopedLights;
2325: s.fogs = savedScopedFogs;
2326: s.altAppearances = savedScopedAltApps;
2327: s.modelClips = savedScopedMclips;
2328: }
2329:
2330: void setScopingInfo(SetLiveState s) {
2331:
2332: int i, k, hkIndex;
2333: // If this is a scoped group , then copy the parent's
2334: // scoping info
2335: if (allocatedLights) {
2336: if (s.lights != null) {
2337: // Add the parent's scoping info to this group
2338: if (inSharedGroup) {
2339: for (i = 0; i < s.keys.length; i++) {
2340: hkIndex = s.keys[i].equals(localToVworldKeys,
2341: 0, localToVworldKeys.length);
2342: ArrayList l = (ArrayList) lights.get(hkIndex);
2343: ArrayList src = (ArrayList) s.lights.get(i);
2344: if (src != null) {
2345: int size = src.size();
2346: for (k = 0; k < size; k++) {
2347: l.add(src.get(k));
2348: }
2349: }
2350:
2351: }
2352: } else {
2353: ArrayList l = (ArrayList) lights.get(0);
2354: ArrayList src = (ArrayList) s.lights.get(0);
2355: int size = src.size();
2356: for (i = 0; i < size; i++) {
2357: l.add(src.get(i));
2358: }
2359: }
2360: }
2361: s.lights = lights;
2362: } else {
2363: lights = s.lights;
2364: }
2365:
2366: if (allocatedFogs) {
2367: if (s.fogs != null) {
2368: // Add the parent's scoping info to this group
2369: if (inSharedGroup) {
2370: for (i = 0; i < s.keys.length; i++) {
2371: hkIndex = s.keys[i].equals(localToVworldKeys,
2372: 0, localToVworldKeys.length);
2373: ArrayList l = (ArrayList) fogs.get(hkIndex);
2374: ArrayList src = (ArrayList) s.fogs.get(i);
2375: if (src != null) {
2376: int size = src.size();
2377: for (k = 0; k < size; k++) {
2378: l.add(src.get(k));
2379: }
2380: }
2381:
2382: }
2383: } else {
2384: ArrayList l = (ArrayList) fogs.get(0);
2385: ArrayList src = (ArrayList) s.fogs.get(0);
2386: int size = src.size();
2387: for (i = 0; i < size; i++) {
2388: l.add(src.get(i));
2389: }
2390: }
2391: }
2392: s.fogs = fogs;
2393: } else {
2394: fogs = s.fogs;
2395: }
2396:
2397: if (allocatedMclips) {
2398: if (s.modelClips != null) {
2399: // Add the parent's scoping info to this group
2400: if (inSharedGroup) {
2401: for (i = 0; i < s.keys.length; i++) {
2402: hkIndex = s.keys[i].equals(localToVworldKeys,
2403: 0, localToVworldKeys.length);
2404: ArrayList l = (ArrayList) modelClips
2405: .get(hkIndex);
2406: ArrayList src = (ArrayList) s.modelClips.get(i);
2407: if (src != null) {
2408: int size = src.size();
2409: for (k = 0; k < size; k++) {
2410: l.add(src.get(k));
2411: }
2412: }
2413:
2414: }
2415: } else {
2416: ArrayList l = (ArrayList) modelClips.get(0);
2417: ArrayList src = (ArrayList) s.modelClips.get(0);
2418: int size = src.size();
2419: for (i = 0; i < size; i++) {
2420: l.add(src.get(i));
2421: }
2422: }
2423: }
2424: s.modelClips = modelClips;
2425: } else {
2426: modelClips = s.modelClips;
2427: }
2428:
2429: if (allocatedAltApps) {
2430: if (s.altAppearances != null) {
2431: // Add the parent's scoping info to this group
2432: if (inSharedGroup) {
2433: for (i = 0; i < s.keys.length; i++) {
2434: hkIndex = s.keys[i].equals(localToVworldKeys,
2435: 0, localToVworldKeys.length);
2436: ArrayList l = (ArrayList) altAppearances
2437: .get(hkIndex);
2438: ArrayList src = (ArrayList) s.altAppearances
2439: .get(i);
2440: if (src != null) {
2441: int size = src.size();
2442: for (k = 0; k < size; k++) {
2443: l.add(src.get(k));
2444: }
2445: }
2446:
2447: }
2448: } else {
2449: ArrayList l = (ArrayList) altAppearances.get(0);
2450: ArrayList src = (ArrayList) s.altAppearances.get(0);
2451: int size = src.size();
2452: for (i = 0; i < size; i++) {
2453: l.add(src.get(i));
2454: }
2455: }
2456: }
2457: s.altAppearances = altAppearances;
2458: } else {
2459: altAppearances = s.altAppearances;
2460: }
2461: }
2462:
2463: void processCollisionTarget(SetLiveState s) {
2464:
2465: GroupRetained g;
2466: if (mirrorGroup == null) {
2467: mirrorGroup = new ArrayList();
2468: }
2469: Bounds bound = (collisionBound != null ? collisionBound
2470: : getEffectiveBounds());
2471: if (inSharedGroup) {
2472: for (int i = 0; i < s.keys.length; i++) {
2473: int j;
2474: g = new GroupRetained();
2475: g.key = s.keys[i];
2476: g.localToVworld = new Transform3D[1][];
2477: g.localToVworldIndex = new int[1][];
2478:
2479: j = s.keys[i].equals(localToVworldKeys, 0,
2480: localToVworldKeys.length);
2481: if (j < 0) {
2482: System.err
2483: .println("GroupRetained : Can't find hashKey");
2484: }
2485:
2486: g.localToVworld[0] = localToVworld[j];
2487: g.localToVworldIndex[0] = localToVworldIndex[j];
2488: g.collisionVwcBounds = new BoundingBox();
2489: g.collisionVwcBounds.transform(bound, g
2490: .getCurrentLocalToVworld(0));
2491: g.sourceNode = this ;
2492: g.locale = locale; // need by getVisibleGeometryAtom()
2493: mirrorGroup.add(g);
2494: /*
2495: System.err.println("processCollisionTarget mirrorGroup.add() : " +
2496: g.getId() + " mirrorGroup.size() "
2497: + mirrorGroup.size());
2498: */
2499: if (s.transformTargets != null
2500: && s.transformTargets[i] != null) {
2501: s.transformTargets[i].addNode(g,
2502: Targets.GRP_TARGETS);
2503: }
2504: s.nodeList.add(g);
2505: }
2506: } else {
2507: g = new GroupRetained();
2508: g.localToVworld = new Transform3D[1][];
2509: g.localToVworldIndex = new int[1][];
2510: g.localToVworld[0] = localToVworld[0];
2511: g.localToVworldIndex[0] = localToVworldIndex[0];
2512: g.collisionVwcBounds = new BoundingBox();
2513: g.collisionVwcBounds.transform(bound, g
2514: .getCurrentLocalToVworld(0));
2515: g.sourceNode = this ;
2516: g.locale = locale; // need by getVisibleGeometryAtom()
2517: mirrorGroup.add(g);
2518: if (s.transformTargets != null
2519: && s.transformTargets[0] != null) {
2520: s.transformTargets[0].addNode(g, Targets.GRP_TARGETS);
2521: }
2522: s.nodeList.add(g);
2523: }
2524: }
2525:
2526: void computeCombineBounds(Bounds bounds) {
2527: if (!VirtualUniverse.mc.cacheAutoComputedBounds) {
2528: if (boundsAutoCompute) {
2529: for (int i = children.size() - 1; i >= 0; i--) {
2530: NodeRetained child = (NodeRetained) children.get(i);
2531: if (child != null)
2532: child.computeCombineBounds(bounds);
2533: }
2534: } else {
2535: // Should this be lock too ? ( MT safe ? )
2536: synchronized (localBounds) {
2537: bounds.combine(localBounds);
2538: }
2539: }
2540: } else {
2541: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
2542: if (validCachedBounds && boundsAutoCompute) {
2543: bounds.combine(cachedBounds);
2544: return;
2545: }
2546:
2547: if (boundsAutoCompute) {
2548: // issue 544
2549: if (VirtualUniverse.mc.useBoxForGroupBounds) {
2550: cachedBounds = new BoundingBox((Bounds) null);
2551: } else {
2552: cachedBounds = new BoundingSphere();
2553: ((BoundingSphere) cachedBounds).setRadius(-1);
2554: }
2555: for (int i = children.size() - 1; i >= 0; i--) {
2556: NodeRetained child = (NodeRetained) children.get(i);
2557: if (child != null) {
2558: child.computeCombineBounds(cachedBounds);
2559: }
2560: }
2561: bounds.combine(cachedBounds);
2562: } else {
2563: // Should this be lock too ? ( MT safe ? )
2564: synchronized (localBounds) {
2565: bounds.combine(localBounds);
2566: }
2567: }
2568: }
2569:
2570: }
2571:
2572: /**
2573: * Gets the bounding object of a node.
2574: * @return the node's bounding object
2575: */
2576: Bounds getBounds() {
2577:
2578: if (boundsAutoCompute) {
2579: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
2580: if (validCachedBounds) {
2581: return (Bounds) cachedBounds.clone();
2582: }
2583: // issue 544
2584: Bounds boundingObject = null;
2585: if (VirtualUniverse.mc.useBoxForGroupBounds) {
2586: boundingObject = new BoundingBox((Bounds) null);
2587: } else {
2588: boundingObject = new BoundingSphere();
2589: ((BoundingSphere) boundingObject).setRadius(-1.0);
2590: }
2591: for (int i = children.size() - 1; i >= 0; i--) {
2592: NodeRetained child = (NodeRetained) children.get(i);
2593: if (child != null) {
2594: child.computeCombineBounds((Bounds) boundingObject);
2595: }
2596: }
2597:
2598: return (Bounds) boundingObject;
2599: }
2600: return super .getBounds();
2601: }
2602:
2603: /**
2604: * Gets the bounding object of a node.
2605: * @return the node's bounding object
2606: */
2607: Bounds getEffectiveBounds() {
2608: if (boundsAutoCompute) {
2609: return getBounds();
2610: }
2611: return super .getEffectiveBounds();
2612: }
2613:
2614: // returns true if children cannot be read/written and none of the
2615: // children can read their parent (i.e., "this") group node
2616: boolean isStaticChildren() {
2617: if (source.getCapability(Group.ALLOW_CHILDREN_READ)
2618: || source.getCapability(Group.ALLOW_CHILDREN_WRITE)) {
2619: return false;
2620: }
2621:
2622: for (int i = children.size() - 1; i >= 0; i--) {
2623: SceneGraphObjectRetained nodeR = (SceneGraphObjectRetained) children
2624: .get(i);
2625: if (nodeR != null
2626: && nodeR.source
2627: .getCapability(Node.ALLOW_PARENT_READ)) {
2628: return false;
2629: }
2630: }
2631:
2632: return true;
2633: }
2634:
2635: boolean isStatic() {
2636: return (super .isStatic() && isStaticChildren());
2637: }
2638:
2639: /**
2640: * This compiles() a group
2641: */
2642: void setCompiled() {
2643: super .setCompiled();
2644: for (int i = children.size() - 1; i >= 0; i--) {
2645: SceneGraphObjectRetained node = (SceneGraphObjectRetained) children
2646: .get(i);
2647: if (node != null)
2648: node.setCompiled();
2649: }
2650: }
2651:
2652: void traverse(boolean sameLevel, int level) {
2653: SceneGraphObjectRetained node;
2654:
2655: if (!sameLevel) {
2656: super .traverse(true, level);
2657:
2658: if (source.getCapability(Group.ALLOW_CHILDREN_READ)) {
2659: System.err.print(" (r)");
2660: } else if (isStatic()) {
2661: System.err.print(" (s)");
2662: } else if (source.getCapability(Group.ALLOW_CHILDREN_WRITE)) {
2663: System.err.print(" (w)");
2664: }
2665: }
2666:
2667: level++;
2668: for (int i = 0; i < children.size(); i++) {
2669: node = (SceneGraphObjectRetained) children.get(i);
2670: if (node != null) {
2671: node.traverse(false, level);
2672: }
2673: }
2674: }
2675:
2676: void compile(CompileState compState) {
2677:
2678: SceneGraphObjectRetained node;
2679:
2680: super .compile(compState);
2681:
2682: mergeFlag = SceneGraphObjectRetained.MERGE;
2683:
2684: if (!isStatic()) {
2685: compState.keepTG = true;
2686: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
2687: }
2688:
2689: if (isRoot || this .usedInScoping()
2690: || (parent instanceof SwitchRetained)) {
2691: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
2692: }
2693:
2694: compiledChildrenList = new ArrayList(5);
2695:
2696: for (int i = 0; i < children.size(); i++) {
2697: node = (SceneGraphObjectRetained) children.get(i);
2698: if (node != null) {
2699: node.compile(compState);
2700: }
2701: }
2702:
2703: if (J3dDebug.devPhase && J3dDebug.debug) {
2704: compState.numGroups++;
2705: }
2706: }
2707:
2708: void merge(CompileState compState) {
2709:
2710: GroupRetained saveParentGroup = null;
2711: SceneGraphObjectRetained node;
2712:
2713: if (mergeFlag != SceneGraphObjectRetained.MERGE_DONE) {
2714: if (mergeFlag == SceneGraphObjectRetained.DONT_MERGE) {
2715:
2716: // don't merge/eliminate this node
2717: super .merge(compState);
2718:
2719: saveParentGroup = compState.parentGroup;
2720: compState.parentGroup = this ;
2721: }
2722:
2723: for (int i = 0; i < children.size(); i++) {
2724: node = (SceneGraphObjectRetained) children.get(i);
2725: if (node != null) {
2726: node.merge(compState);
2727: }
2728: }
2729:
2730: if (compState.parentGroup == this ) {
2731: this .children = compiledChildrenList;
2732: compState.doShapeMerge();
2733: compiledChildrenList = null;
2734: compState.parentGroup = saveParentGroup;
2735: } else {
2736: // this group node can be eliminated
2737: this .children.clear();
2738:
2739: if (J3dDebug.devPhase && J3dDebug.debug) {
2740: compState.numMergedGroups++;
2741: }
2742: }
2743:
2744: mergeFlag = SceneGraphObjectRetained.MERGE_DONE;
2745:
2746: } else {
2747: if (compState.parentGroup != null) {
2748: compState.parentGroup.compiledChildrenList.add(this );
2749: parent = compState.parentGroup;
2750: }
2751: }
2752: }
2753:
2754: /**
2755: * This version of clearLive calls clearLive on all of its chidren.
2756: */
2757: void clearLive(SetLiveState s) {
2758: int i, k, hkIndex, nchildren;
2759: NodeRetained child;
2760: int parentScopedLtSize = 0;
2761: int parentScopedFogSize = 0;
2762: int parentScopedMcSize = 0;
2763: int parentScopedAltAppSize = 0;
2764: int groupScopedLtSize = 0;
2765: int groupScopedFogSize = 0;
2766: int groupScopedMcSize = 0;
2767: int groupScopedAltAppSize = 0;
2768: int size;
2769:
2770: isInClearLive = true;
2771:
2772: // Save this for later use in this method. Temporary. to be removed when OG cleanup.
2773: HashKey[] savedLocalToVworldKeys = localToVworldKeys;
2774:
2775: super .clearLive(s);
2776:
2777: nchildren = this .children.size();
2778:
2779: if (!(this instanceof ViewSpecificGroupRetained)) {
2780: viewLists = s.viewLists;
2781: }
2782:
2783: ArrayList savedParentLights = s.lights;
2784: if (allocatedLights) {
2785: s.lights = lights;
2786: }
2787:
2788: ArrayList savedParentFogs = s.fogs;
2789: if (allocatedFogs) {
2790: s.fogs = fogs;
2791: }
2792:
2793: ArrayList savedParentMclips = s.modelClips;
2794: if (allocatedMclips) {
2795: s.modelClips = modelClips;
2796: }
2797:
2798: ArrayList savedParentAltApps = s.altAppearances;
2799: if (allocatedAltApps) {
2800: s.altAppearances = altAppearances;
2801: }
2802:
2803: for (i = nchildren - 1; i >= 0; i--) {
2804: child = (NodeRetained) children.get(i);
2805: if (this instanceof OrderedGroupRetained) {
2806: OrderedGroupRetained og = (OrderedGroupRetained) this ;
2807:
2808: // adjust refCount, which has been decremented
2809: //in super.clearLive
2810: if ((refCount + 1) == s.refCount) {
2811: //only need to do it once if in shared group. Add
2812: //all the children to the list of OG_REMOVED message
2813: s.ogList.add(this );
2814: s.ogChildIdList.add(new Integer(i));
2815: }
2816: s.orderedPaths = (ArrayList) og.childrenOrderedPaths
2817: .get(i);
2818: }
2819:
2820: if (child != null) {
2821: child.clearLive(s);
2822: }
2823: }
2824: // Has its own copy
2825: // XXXX: Handle the case of
2826: // was non-zero, gone to zero?
2827: if (savedParentLights != null) {
2828: if (allocatedLights) {
2829: if (inSharedGroup) {
2830:
2831: for (i = 0; i < s.keys.length; i++) {
2832: hkIndex = s.keys[i].equals(localToVworldKeys,
2833: 0, localToVworldKeys.length);
2834: ArrayList l = (ArrayList) savedParentLights
2835: .get(hkIndex);
2836: ArrayList gl = (ArrayList) lights.get(hkIndex);
2837: if (l != null) {
2838: size = l.size();
2839: for (k = 0; k < size; k++) {
2840: gl.remove(l.get(k));
2841: }
2842: }
2843:
2844: }
2845: } else {
2846: ArrayList l = (ArrayList) savedParentLights.get(0);
2847: ArrayList gl = (ArrayList) lights.get(0);
2848: size = l.size();
2849: for (int m = 0; m < size; m++) {
2850: gl.remove(l.get(m));
2851: }
2852: }
2853: }
2854: }
2855:
2856: if (savedParentFogs != null) {
2857: if (allocatedFogs) {
2858: if (inSharedGroup) {
2859: for (i = 0; i < s.keys.length; i++) {
2860: hkIndex = s.keys[i].equals(localToVworldKeys,
2861: 0, localToVworldKeys.length);
2862: ArrayList l = (ArrayList) savedParentFogs
2863: .get(hkIndex);
2864: ArrayList gl = (ArrayList) fogs.get(hkIndex);
2865: if (l != null) {
2866: size = l.size();
2867: for (k = 0; k < size; k++) {
2868: gl.remove(l.get(k));
2869: }
2870: }
2871:
2872: }
2873: } else {
2874: ArrayList l = (ArrayList) savedParentFogs.get(0);
2875: size = l.size();
2876: for (int m = 0; m < size; m++) {
2877: fogs.remove(l.get(m));
2878: }
2879: }
2880: }
2881: }
2882:
2883: if (savedParentMclips != null) {
2884: if (allocatedMclips) {
2885: if (inSharedGroup) {
2886: for (i = 0; i < s.keys.length; i++) {
2887: hkIndex = s.keys[i].equals(localToVworldKeys,
2888: 0, localToVworldKeys.length);
2889: ArrayList l = (ArrayList) savedParentMclips
2890: .get(hkIndex);
2891: ArrayList gl = (ArrayList) modelClips
2892: .get(hkIndex);
2893: if (l != null) {
2894: size = l.size();
2895: for (k = 0; k < size; k++) {
2896: gl.remove(l.get(k));
2897: }
2898: }
2899:
2900: }
2901: } else {
2902: ArrayList l = (ArrayList) savedParentMclips.get(0);
2903: size = l.size();
2904: for (int m = 0; m < size; m++) {
2905: modelClips.remove(l.get(m));
2906: }
2907: }
2908: }
2909: }
2910:
2911: if (savedParentAltApps != null) {
2912: if (allocatedAltApps) {
2913: if (inSharedGroup) {
2914: for (i = 0; i < s.keys.length; i++) {
2915: hkIndex = s.keys[i].equals(localToVworldKeys,
2916: 0, localToVworldKeys.length);
2917: ArrayList l = (ArrayList) savedParentAltApps
2918: .get(hkIndex);
2919: ArrayList gl = (ArrayList) altAppearances
2920: .get(hkIndex);
2921: if (l != null) {
2922: size = l.size();
2923: for (k = 0; k < size; k++) {
2924: gl.remove(l.get(k));
2925: }
2926: }
2927:
2928: }
2929: } else {
2930: ArrayList l = (ArrayList) savedParentAltApps.get(0);
2931: size = l.size();
2932: for (int m = 0; m < size; m++) {
2933: altAppearances.remove(l.get(m));
2934: }
2935: }
2936: }
2937: }
2938:
2939: if (collisionTarget) {
2940: GroupRetained g;
2941: if (inSharedGroup) {
2942: for (i = s.keys.length - 1; i >= 0; i--) {
2943: HashKey hkey = s.keys[i];
2944: for (int j = mirrorGroup.size() - 1; j >= 0; j--) {
2945: g = (GroupRetained) mirrorGroup.get(j);
2946: if (g.key.equals(hkey)) {
2947: s.nodeList.add(mirrorGroup.remove(j));
2948: if (s.transformTargets != null
2949: && s.transformTargets[j] != null) {
2950: s.transformTargets[j].addNode(g,
2951: Targets.GRP_TARGETS);
2952: }
2953: break;
2954: }
2955:
2956: }
2957: }
2958: } else {
2959: g = (GroupRetained) mirrorGroup.get(0);
2960: if (s.transformTargets != null
2961: && s.transformTargets[0] != null) {
2962: s.transformTargets[0].addNode(g,
2963: Targets.GRP_TARGETS);
2964: }
2965: s.nodeList.add(mirrorGroup.remove(0));
2966: }
2967: }
2968: s.lights = savedParentLights;
2969: s.modelClips = savedParentMclips;
2970: s.fogs = savedParentFogs;
2971: s.altAppearances = savedParentAltApps;
2972: isInClearLive = false;
2973: }
2974:
2975: // This is only used by alternateCollisionTarget
2976: public BoundingBox computeBoundingHull() {
2977: return collisionVwcBounds;
2978: }
2979:
2980: // If isSwitchOn cached here, we don't need to traverse up the tree
2981: public boolean isEnable() {
2982: return isNodeSwitchOn(this .sourceNode, key);
2983: }
2984:
2985: // If isSwitchOn cached here, we don't need to traverse up the tree
2986: // This method does nothing with vis.
2987: public boolean isEnable(int vis) {
2988: return isNodeSwitchOn(this .sourceNode, key);
2989: }
2990:
2991: // Can't use getLocale, it is used by BranchGroupRetained
2992: public Locale getLocale2() {
2993: return locale;
2994: }
2995:
2996: /**
2997: * Return true of nodeR is not under a switch group or
2998: * nodeR is enable under a switch group.
2999: */
3000: static boolean isNodeSwitchOn(NodeRetained node, HashKey key) {
3001: NodeRetained prevNode = null;
3002: if (key != null) {
3003: key = new HashKey(key);
3004: }
3005:
3006: synchronized (node.universe.sceneGraphLock) {
3007: do {
3008: if ((node instanceof SwitchRetained)
3009: && (prevNode != null)
3010: && !validSwitchChild((SwitchRetained) node,
3011: prevNode)) {
3012: return false;
3013: }
3014: prevNode = node;
3015: if (node instanceof SharedGroupRetained) {
3016: // retrieve the last node ID
3017: String nodeId = key.getLastNodeId();
3018: Vector parents = ((SharedGroupRetained) node).parents;
3019: // find the matching link
3020: for (int i = parents.size() - 1; i >= 0; i--) {
3021: NodeRetained link = (NodeRetained) parents
3022: .get(i);
3023: if (link.nodeId.equals(nodeId)) {
3024: node = link;
3025: break;
3026: }
3027: }
3028: if (node == prevNode) {
3029: // Fail to found a matching link, this is
3030: // probably cause by BHTree not yet updated
3031: // because message not yet arrive
3032: // when collision so it return current node as target.
3033: return false;
3034: }
3035: } else {
3036: node = node.parent;
3037: }
3038: } while (node != null);
3039: // reach locale
3040: }
3041: return true;
3042: }
3043:
3044: /**
3045: * Determinte if nodeR is a valid child to render for
3046: * Switch Node swR.
3047: */
3048: static boolean validSwitchChild(SwitchRetained sw, NodeRetained node) {
3049:
3050: int whichChild = sw.whichChild;
3051:
3052: if (whichChild == Switch.CHILD_NONE) {
3053: return false;
3054: }
3055:
3056: if (whichChild == Switch.CHILD_ALL) {
3057: return true;
3058: }
3059:
3060: ArrayList children = sw.children;
3061:
3062: if (whichChild >= 0) { // most common case
3063: return (children.get(whichChild) == node);
3064: }
3065:
3066: // Switch.CHILD_MASK
3067: for (int i = children.size() - 1; i >= 0; i--) {
3068: if (sw.childMask.get(i) && (children.get(i) == node)) {
3069: return true;
3070: }
3071: }
3072: return false;
3073: }
3074:
3075: /**
3076: * Create mirror group when this Group AlternateCollisionTarget
3077: * is set to true while live.
3078: */
3079: void createMirrorGroup() {
3080: GroupRetained g;
3081:
3082: mirrorGroup = new ArrayList();
3083:
3084: Bounds bound = (collisionBound != null ? collisionBound
3085: : getEffectiveBounds());
3086:
3087: if (inSharedGroup) {
3088: for (int i = 0; i < localToVworldKeys.length; i++) {
3089: g = new GroupRetained();
3090: g.key = localToVworldKeys[i];
3091: g.localToVworld = new Transform3D[1][];
3092: g.localToVworldIndex = new int[1][];
3093: g.localToVworld[0] = localToVworld[i];
3094: g.localToVworldIndex[0] = localToVworldIndex[i];
3095: g.collisionVwcBounds = new BoundingBox();
3096: g.collisionVwcBounds.transform(bound, g
3097: .getCurrentLocalToVworld());
3098: g.sourceNode = this ;
3099: g.locale = locale; // need by getVisibleGeometryAtom()
3100: mirrorGroup.add(g);
3101: }
3102: } else {
3103: g = new GroupRetained();
3104: g.localToVworld = new Transform3D[1][];
3105: g.localToVworldIndex = new int[1][];
3106: g.localToVworld[0] = localToVworld[0];
3107: g.localToVworldIndex[0] = localToVworldIndex[0];
3108: g.collisionVwcBounds = new BoundingBox();
3109: g.collisionVwcBounds.transform(bound, g
3110: .getCurrentLocalToVworld());
3111: g.sourceNode = this ;
3112: g.locale = locale; // need by getVisibleGeometryAtom()
3113: mirrorGroup.add(g);
3114: }
3115: }
3116:
3117: void setBoundsAutoCompute(boolean autoCompute) {
3118: if (autoCompute != boundsAutoCompute) {
3119: super .setBoundsAutoCompute(autoCompute);
3120: if (!autoCompute) {
3121: localBounds = getEffectiveBounds();
3122: }
3123: if (source.isLive() && collisionBound == null
3124: && autoCompute && mirrorGroup != null) {
3125:
3126: J3dMessage message = new J3dMessage();
3127: message.type = J3dMessage.COLLISION_BOUND_CHANGED;
3128: message.threads = J3dThread.UPDATE_TRANSFORM
3129: | J3dThread.UPDATE_GEOMETRY;
3130: message.universe = universe;
3131: message.args[0] = this ;
3132: VirtualUniverse.mc.processMessage(message);
3133: }
3134: }
3135: }
3136:
3137: void setBounds(Bounds bounds) {
3138: super .setBounds(bounds);
3139: if (source.isLive() && !boundsAutoCompute
3140: && collisionBound == null && mirrorGroup != null) {
3141:
3142: J3dMessage message = new J3dMessage();
3143: message.type = J3dMessage.COLLISION_BOUND_CHANGED;
3144: message.threads = J3dThread.UPDATE_TRANSFORM
3145: | J3dThread.UPDATE_GEOMETRY;
3146: message.universe = universe;
3147: message.args[0] = this ;
3148: VirtualUniverse.mc.processMessage(message);
3149: }
3150: }
3151:
3152: int[] processViewSpecificInfo(int mode, HashKey k, View v,
3153: ArrayList vsgList, int[] keyList, ArrayList leafList) {
3154: int nchildren = children.size();
3155: if (source.isLive()) {
3156: for (int i = 0; i < nchildren; i++) {
3157: NodeRetained child = (NodeRetained) children.get(i);
3158: if (child instanceof LeafRetained) {
3159: if (child instanceof LinkRetained) {
3160: int lastCount = k.count;
3161: LinkRetained ln = (LinkRetained) child;
3162: if (k.count == 0) {
3163: k.append(locale.nodeId);
3164: }
3165: keyList = ((GroupRetained) (ln.sharedGroup))
3166: .processViewSpecificInfo(mode, k
3167: .append("+").append(ln.nodeId),
3168: v, vsgList, keyList, leafList);
3169: k.count = lastCount;
3170: } else {
3171: ((LeafRetained) child).getMirrorObjects(
3172: leafList, k);
3173: }
3174: } else {
3175: keyList = child.processViewSpecificInfo(mode, k, v,
3176: vsgList, keyList, leafList);
3177: }
3178: }
3179: }
3180: return keyList;
3181: }
3182:
3183: void findSwitchInfo(SetLiveState s, NodeRetained parentNode,
3184: NodeRetained childNode, NodeRetained linkNode) {
3185:
3186: NodeRetained child;
3187: NodeRetained parent;
3188:
3189: parentSwitchLinkChildIndex = -1;
3190:
3191: // traverse up scene graph to find switch parent information
3192: if (!inSharedGroup) {
3193: child = (linkNode == null) ? childNode : linkNode;
3194: parent = parentNode;
3195: while (parent != null) {
3196: if (parent instanceof SwitchRetained) {
3197: s.switchLevels[0]++;
3198: if (s.closestSwitchParents[0] == null) {
3199: s.closestSwitchParents[0] = (SwitchRetained) parent;
3200: s.closestSwitchIndices[0] = ((SwitchRetained) parent).switchIndexCount++;
3201: }
3202: if (parentSwitchLinkChildIndex == -1) {
3203: parentSwitchLinkChildIndex = ((GroupRetained) parent).children
3204: .indexOf(child);
3205: }
3206: } else if (parent instanceof SharedGroupRetained) {
3207: if (parentSwitchLinkChildIndex == -1) {
3208: parentSwitchLinkChildIndex = ((GroupRetained) parent).children
3209: .indexOf(child);
3210: }
3211: }
3212: child = parent;
3213: parent = child.parent;
3214: }
3215: } else {
3216: HashKey key;
3217: int i, j;
3218:
3219: s.switchLevels = new int[localToVworldKeys.length];
3220: s.closestSwitchParents = new SwitchRetained[localToVworldKeys.length];
3221: s.closestSwitchIndices = new int[localToVworldKeys.length];
3222: for (i = 0; i < localToVworldKeys.length; i++) {
3223: s.switchLevels[i] = -1;
3224: s.closestSwitchParents[i] = null;
3225: s.closestSwitchIndices[i] = -1;
3226: }
3227:
3228: for (i = 0; i < localToVworldKeys.length; i++) {
3229: child = (linkNode == null) ? childNode : linkNode;
3230: parent = parentNode;
3231: key = new HashKey(localToVworldKeys[i]);
3232:
3233: while (parent != null) {
3234:
3235: if (parent instanceof SwitchRetained) {
3236: s.switchLevels[i]++;
3237: if (s.closestSwitchParents[i] == null) {
3238: s.closestSwitchParents[i] = (SwitchRetained) parent;
3239: s.closestSwitchIndices[i] = ((SwitchRetained) parent).switchIndexCount++;
3240:
3241: }
3242: if (parentSwitchLinkChildIndex == -1) {
3243: parentSwitchLinkChildIndex = ((GroupRetained) parent).children
3244: .indexOf(child);
3245: }
3246: } else if (parent instanceof SharedGroupRetained) {
3247: String nodeId = key.getLastNodeId();
3248: Vector parents = ((SharedGroupRetained) parent).parents;
3249: NodeRetained ln;
3250:
3251: if (parentSwitchLinkChildIndex == -1) {
3252: parentSwitchLinkChildIndex = ((GroupRetained) parent).children
3253: .indexOf(child);
3254: }
3255:
3256: for (j = 0; j < parents.size(); j++) {
3257: ln = (NodeRetained) parents.get(j);
3258: if (ln.nodeId.equals(nodeId)) {
3259: parent = ln;
3260: break;
3261: }
3262: }
3263: }
3264: child = parent;
3265: parent = child.parent;
3266: }
3267: }
3268: }
3269: }
3270:
3271: static void gatherBlUsers(ArrayList blUsers, Object[] blArr) {
3272: ArrayList users;
3273:
3274: for (int i = 0; i < blArr.length; i++) {
3275: users = ((BoundingLeafRetained) blArr[i]).users;
3276: synchronized (users) {
3277: blUsers.addAll(users);
3278: }
3279: }
3280: }
3281:
3282: // recursively found all geometryAtoms under this Group
3283: void searchGeometryAtoms(UnorderList list) {
3284: for (int i = children.size() - 1; i >= 0; i--) {
3285: NodeRetained child = (NodeRetained) children.get(i);
3286: child.searchGeometryAtoms(list);
3287: }
3288: }
3289: }
|