001: /*
002: * $RCSfile: SwitchRetained.java,v $
003: *
004: * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.11 $
028: * $Date: 2008/02/28 20:17:31 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.BitSet;
035: import java.util.ArrayList;
036:
037: /**
038: * The switch node controls which one of its children will be rendered.
039: */
040:
041: class SwitchRetained extends GroupRetained implements TargetsInterface {
042: static final int GEO_NODES = 0x0001;
043: static final int ENV_NODES = 0x0002;
044: static final int BEHAVIOR_NODES = 0x0004;
045: static final int SOUND_NODES = 0x0008;
046: static final int BOUNDINGLEAF_NODES = 0x0010;
047:
048: /**
049: * The value specifing which child to render.
050: */
051: int whichChild = Switch.CHILD_NONE;
052:
053: /**
054: * The BitSet specifying which children are to be selected for
055: * rendering. This is used ONLY if whichChild is set to CHILD_MASK.
056: */
057: BitSet childMask = new BitSet();
058:
059: /**
060: * The childmask bitset used for rendering
061: */
062: BitSet renderChildMask = new BitSet();
063:
064: // A boolean indication that something changed
065: boolean isDirty = true;
066:
067: // switchLevel per key, used in traversing switch children
068: ArrayList switchLevels = new ArrayList(1);
069:
070: // key which identifies a unique path from a locale to this switch link
071: HashKey switchKey = new HashKey();
072:
073: // switch index counter to identify specific children
074: int switchIndexCount = 0;
075:
076: // for message processing
077: UpdateTargets updateTargets = null;
078:
079: ArrayList childrenSwitchStates = null;
080:
081: SwitchRetained() {
082: this .nodeType = NodeRetained.SWITCH;
083: }
084:
085: /**
086: * Sets which child should be drawn.
087: * @param whichChild the child to choose during a render operation
088: */
089: // synchronized with clearLive
090: synchronized void setWhichChild(int whichChild, boolean updateAlways) {
091:
092: int i, nchildren;
093:
094: this .whichChild = whichChild;
095: isDirty = true;
096:
097: if (source != null && source.isLive()) {
098: updateTargets = new UpdateTargets();
099: ArrayList updateList = new ArrayList(1);
100: nchildren = children.size();
101: switch (whichChild) {
102: case Switch.CHILD_ALL:
103: for (i = 0; i < nchildren; i++) {
104: if (renderChildMask.get(i) == false || updateAlways) {
105: renderChildMask.set(i);
106: updateSwitchChild(i, true, updateList);
107: }
108: }
109: break;
110: case Switch.CHILD_NONE:
111: for (i = 0; i < nchildren; i++) {
112: if (renderChildMask.get(i) == true || updateAlways) {
113: renderChildMask.clear(i);
114: updateSwitchChild(i, false, updateList);
115: }
116: }
117: break;
118: case Switch.CHILD_MASK:
119: for (i = 0; i < nchildren; i++) {
120: if (childMask.get(i) == true) {
121: if (renderChildMask.get(i) == false
122: || updateAlways) {
123: renderChildMask.set(i);
124: updateSwitchChild(i, true, updateList);
125: }
126: } else {
127: if (renderChildMask.get(i) == true
128: || updateAlways) {
129: renderChildMask.clear(i);
130: updateSwitchChild(i, false, updateList);
131: }
132: }
133: }
134: break;
135: default:
136: for (i = 0; i < nchildren; i++) {
137: if (i == whichChild) {
138: if (renderChildMask.get(i) == false
139: || updateAlways) {
140: renderChildMask.set(i);
141: updateSwitchChild(i, true, updateList);
142: }
143: } else {
144: if (renderChildMask.get(i) == true
145: || updateAlways) {
146: renderChildMask.clear(i);
147: updateSwitchChild(i, false, updateList);
148: }
149: }
150: }
151: break;
152: }
153: sendMessage(updateList);
154: }
155: dirtyBoundsCache();
156: }
157:
158: /**
159: * Returns the index of the current child.
160: * @return the default child's index
161: */
162: int getWhichChild() {
163: return this .whichChild;
164: }
165:
166: /**
167: * Sets current childMask.
168: * @param childMask a BitSet to select the children for rendering
169: */
170: // synchronized with clearLive
171: synchronized final void setChildMask(BitSet childMask) {
172: int i, nbits, nchildren;
173:
174: if (childMask.size() > this .childMask.size()) {
175: nbits = childMask.size();
176: } else {
177: nbits = this .childMask.size();
178: }
179:
180: for (i = 0; i < nbits; i++) {
181: if (childMask.get(i)) {
182: this .childMask.set(i);
183: } else {
184: this .childMask.clear(i);
185: }
186: }
187: this .isDirty = true;
188: if (source != null && source.isLive()
189: && whichChild == Switch.CHILD_MASK) {
190: updateTargets = new UpdateTargets();
191: ArrayList updateList = new ArrayList(1);
192: nchildren = children.size();
193: for (i = 0; i < nchildren; i++) {
194: if (childMask.get(i) == true) {
195: if (renderChildMask.get(i) == false) {
196: renderChildMask.set(i);
197: updateSwitchChild(i, true, updateList);
198: }
199: } else {
200: if (renderChildMask.get(i) == true) {
201: renderChildMask.clear(i);
202: updateSwitchChild(i, false, updateList);
203: }
204: }
205: }
206: sendMessage(updateList);
207: }
208: dirtyBoundsCache();
209: }
210:
211: void sendMessage(ArrayList updateList) {
212:
213: J3dMessage m;
214: int i, j, size, threads;
215: Object[] nodesArr, nodes;
216:
217: threads = updateTargets.computeSwitchThreads();
218:
219: if (threads > 0) {
220:
221: m = new J3dMessage();
222: m.type = J3dMessage.SWITCH_CHANGED;
223: m.universe = universe;
224: m.threads = threads;
225: m.args[0] = updateTargets;
226: m.args[2] = updateList;
227: UnorderList blnList = updateTargets.targetList[Targets.BLN_TARGETS];
228:
229: if (blnList != null) {
230: BoundingLeafRetained mbleaf;
231: size = blnList.size();
232:
233: Object[] boundingLeafUsersArr = new Object[size];
234: nodesArr = blnList.toArray(false);
235: for (j = 0; j < size; j++) {
236: nodes = (Object[]) nodesArr[j];
237: Object[] boundingLeafUsers = new Object[nodes.length];
238: boundingLeafUsersArr[j] = boundingLeafUsers;
239: for (i = 0; i < nodes.length; i++) {
240: mbleaf = (BoundingLeafRetained) nodes[i];
241: boundingLeafUsers[i] = mbleaf.users.toArray();
242: }
243: }
244: m.args[1] = boundingLeafUsersArr;
245: }
246: VirtualUniverse.mc.processMessage(m);
247: }
248:
249: UnorderList vpList = updateTargets.targetList[Targets.VPF_TARGETS];
250: if (vpList != null) {
251: ViewPlatformRetained vp;
252: size = vpList.size();
253:
254: nodesArr = vpList.toArray(false);
255: for (j = 0; j < size; j++) {
256: nodes = (Object[]) nodesArr[j];
257: for (i = 0; i < nodes.length; i++) {
258: vp = (ViewPlatformRetained) nodes[i];
259: vp.processSwitchChanged();
260: }
261: }
262: }
263: }
264:
265: /**
266: * Returns the current childMask.
267: * @return the current childMask
268: */
269: final BitSet getChildMask() {
270: return (BitSet) this .childMask.clone();
271: }
272:
273: /**
274: * Returns the current child.
275: * @return the current child
276: */
277: Node currentChild() {
278: if ((whichChild < 0) || (whichChild >= children.size()))
279: return null;
280: else
281: return getChild(whichChild);
282: }
283:
284: void updateSwitchChild(int child, boolean switchOn,
285: ArrayList updateList) {
286: int i;
287: int switchLevel;
288:
289: if (inSharedGroup) {
290: for (i = 0; i < localToVworldKeys.length; i++) {
291: switchLevel = ((Integer) switchLevels.get(i))
292: .intValue();
293: traverseSwitchChild(child, localToVworldKeys[i], i,
294: this , false, false, switchOn, switchLevel,
295: updateList);
296: }
297: } else {
298: switchLevel = ((Integer) switchLevels.get(0)).intValue();
299: traverseSwitchChild(child, null, 0, this , false, false,
300: switchOn, switchLevel, updateList);
301: }
302: }
303:
304: // Switch specific data at SetLive.
305: void setAuxData(SetLiveState s, int index, int hkIndex) {
306: int size;
307: ArrayList switchStates;
308:
309: // Group's setAuxData()
310: super .setAuxData(s, index, hkIndex);
311: switchLevels.add(new Integer(s.switchLevels[index]));
312: int nchildren = children.size();
313: for (int i = 0; i < nchildren; i++) {
314: switchStates = (ArrayList) childrenSwitchStates.get(i);
315: switchStates.add(hkIndex, new SwitchState(true));
316: }
317: }
318:
319: void setNodeData(SetLiveState s) {
320: super .setNodeData(s);
321: // add this node to parent's childSwitchLink
322: if (s.childSwitchLinks != null) {
323: if (!inSharedGroup ||
324: // only add if not already added in sharedGroup
325: !s.childSwitchLinks.contains(this )) {
326: s.childSwitchLinks.add(this );
327: }
328: }
329: // Note that s.childSwitchLinks is updated in super.setLive
330: s.parentSwitchLink = this ;
331:
332: if (!inSharedGroup) {
333: setAuxData(s, 0, 0);
334: } else {
335: // For inSharedGroup case.
336: int j, hkIndex;
337:
338: s.hashkeyIndex = new int[s.keys.length];
339: for (j = 0; j < s.keys.length; j++) {
340: hkIndex = s.keys[j].equals(localToVworldKeys, 0,
341: localToVworldKeys.length);
342: if (hkIndex >= 0) {
343: setAuxData(s, j, hkIndex);
344: } else {
345: MasterControl
346: .getCoreLogger()
347: .severe(
348: "Can't Find matching hashKey in setNodeData.");
349: }
350: s.hashkeyIndex[j] = hkIndex;
351: }
352: }
353: }
354:
355: void setLive(SetLiveState s) {
356: int i, j, k;
357: boolean switchOn;
358: SwitchRetained switchRoot;
359: int size;
360:
361: // save setLiveState
362: Targets[] savedSwitchTargets = s.switchTargets;
363: ArrayList savedSwitchStates = s.switchStates;
364: SwitchRetained[] savedClosestSwitchParents = s.closestSwitchParents;
365: int[] savedClosestSwitchIndices = s.closestSwitchIndices;
366: ArrayList savedChildSwitchLinks = s.childSwitchLinks;
367: GroupRetained savedParentSwitchLink = s.parentSwitchLink;
368: int[] savedHashkeyIndex = s.hashkeyIndex;
369:
370: // update setLiveState for this node
371: s.closestSwitchParents = (SwitchRetained[]) savedClosestSwitchParents
372: .clone();
373: s.closestSwitchIndices = (int[]) savedClosestSwitchIndices
374: .clone();
375:
376: // Note that s.containsNodesList is updated in super.setLive
377: // Note that s.closestSwitchIndices is updated in super.setLive
378: for (i = 0; i < s.switchLevels.length; i++) {
379: s.switchLevels[i]++;
380: s.closestSwitchParents[i] = this ;
381: }
382:
383: super .doSetLive(s);
384:
385: initRenderChildMask();
386:
387: // update switch leaves' compositeSwitchMask
388: // and update switch leaves' switchOn flag if this is top level switch
389: if (inSharedGroup) {
390: for (i = 0; i < s.keys.length; i++) {
391: j = s.hashkeyIndex[i];
392: // j is index in ContainNodes
393: if (j < localToVworldKeys.length) {
394: switchRoot = (s.switchLevels[i] == 0) ? this : null;
395: size = children.size();
396: for (k = 0; k < size; k++) {
397: switchOn = renderChildMask.get(k);
398: traverseSwitchChild(k, s.keys[i], j,
399: switchRoot, true, false, switchOn,
400: s.switchLevels[i], null);
401: }
402: }
403: }
404: } else {
405: switchRoot = (s.switchLevels[0] == 0) ? this : null;
406: size = children.size();
407: for (i = 0; i < size; i++) {
408: switchOn = renderChildMask.get(i);
409: traverseSwitchChild(i, null, 0, switchRoot, true,
410: false, switchOn, s.switchLevels[0], null);
411: }
412: }
413:
414: // restore setLiveState
415: s.switchTargets = savedSwitchTargets;
416: s.switchStates = savedSwitchStates;
417: s.closestSwitchParents = savedClosestSwitchParents;
418: s.closestSwitchIndices = savedClosestSwitchIndices;
419: for (i = 0; i < s.switchLevels.length; i++) {
420: s.switchLevels[i]--;
421: }
422: s.childSwitchLinks = savedChildSwitchLinks;
423: s.parentSwitchLink = savedParentSwitchLink;
424: s.hashkeyIndex = savedHashkeyIndex;
425: super .markAsLive();
426: }
427:
428: void removeNodeData(SetLiveState s) {
429:
430: int numChildren = children.size();
431: int i, j;
432: ArrayList switchStates;
433:
434: if (refCount <= 0) {
435: // remove this node from parentSwitchLink's childSwitchLinks
436: // clear childSwitchLinks
437: ArrayList switchLinks;
438: if (parentSwitchLink != null) {
439: for (i = 0; i < parentSwitchLink.childrenSwitchLinks
440: .size(); i++) {
441: switchLinks = (ArrayList) parentSwitchLink.childrenSwitchLinks
442: .get(i);
443: if (switchLinks.contains(this )) {
444: switchLinks.remove(this );
445: break;
446: }
447: }
448: }
449: for (j = 0; j < numChildren; j++) {
450: switchStates = (ArrayList) childrenSwitchStates.get(j);
451: switchStates.clear();
452: }
453: switchLevels.remove(0);
454: } else {
455: // remove children dependent data
456: int hkIndex;
457:
458: // Must be in reverse, to preserve right indexing.
459: for (i = s.keys.length - 1; i >= 0; i--) {
460: hkIndex = s.keys[i].equals(localToVworldKeys, 0,
461: localToVworldKeys.length);
462: if (hkIndex >= 0) {
463: for (j = 0; j < numChildren; j++) {
464: switchStates = (ArrayList) childrenSwitchStates
465: .get(j);
466: switchStates.remove(hkIndex);
467: }
468: switchLevels.remove(hkIndex);
469: }
470: }
471: }
472:
473: super .removeNodeData(s);
474: }
475:
476: // synchronized with setWhichChild and setChildMask
477: synchronized void clearLive(SetLiveState s) {
478: Targets[] savedSwitchTargets = s.switchTargets;
479: s.switchTargets = null;
480: super .clearLive(s);
481: s.switchTargets = savedSwitchTargets;
482: }
483:
484: void initRenderChildMask() {
485: int i, nchildren;
486: nchildren = children.size();
487: switch (whichChild) {
488: case Switch.CHILD_ALL:
489: for (i = 0; i < nchildren; i++) {
490: renderChildMask.set(i);
491: }
492: break;
493: case Switch.CHILD_NONE:
494: for (i = 0; i < nchildren; i++) {
495: renderChildMask.clear(i);
496: }
497: break;
498: case Switch.CHILD_MASK:
499: for (i = 0; i < nchildren; i++) {
500: if (childMask.get(i) == true) {
501: renderChildMask.set(i);
502: } else {
503: renderChildMask.clear(i);
504: }
505: }
506: break;
507: default:
508: for (i = 0; i < nchildren; i++) {
509:
510: if (i == whichChild) {
511: renderChildMask.set(i);
512: } else {
513: renderChildMask.clear(i);
514: }
515: }
516: }
517: }
518:
519: void traverseSwitchChild(int child, HashKey key, int index,
520: SwitchRetained switchRoot, boolean init, boolean swChanged,
521: boolean switchOn, int switchLevel, ArrayList updateList) {
522: int i, j, k;
523: SwitchRetained sw;
524: LinkRetained ln;
525: Object obj;
526: ArrayList childSwitchLinks;
527:
528: boolean newSwChanged = false;
529: ArrayList childSwitchStates = (ArrayList) childrenSwitchStates
530: .get(child);
531: SwitchState switchState = (SwitchState) childSwitchStates
532: .get(index);
533: switchState.updateCompositeSwitchMask(switchLevel, switchOn);
534:
535: if (switchRoot != null) {
536: if (init) {
537: if (!switchState.initialized) {
538: switchState.initSwitchOn();
539: }
540: } else {
541: boolean compositeSwitchOn = switchState
542: .evalCompositeSwitchOn();
543: if (switchState.cachedSwitchOn != compositeSwitchOn) {
544: switchState.updateCachedSwitchOn();
545:
546: switchRoot.updateTargets
547: .addCachedTargets(switchState.cachedTargets);
548: newSwChanged = true;
549: updateList.add(switchState);
550: }
551: }
552: }
553:
554: childSwitchLinks = (ArrayList) childrenSwitchLinks.get(child);
555: int cslSize = childSwitchLinks.size();
556: for (i = 0; i < cslSize; i++) {
557:
558: obj = childSwitchLinks.get(i);
559: if (obj instanceof SwitchRetained) {
560: sw = (SwitchRetained) obj;
561: int swSize = sw.children.size();
562: for (j = 0; j < swSize; j++) {
563: sw.traverseSwitchChild(j, key, index, switchRoot,
564: init, newSwChanged, switchOn, switchLevel,
565: updateList);
566: }
567: } else { // LinkRetained
568: ln = (LinkRetained) obj;
569: if (key == null) {
570: switchKey.reset();
571: switchKey.append(locale.nodeId);
572: } else {
573: switchKey.set(key);
574: }
575: switchKey.append(LinkRetained.plus).append(ln.nodeId);
576:
577: if ((ln.sharedGroup != null)
578: && (ln.sharedGroup.localToVworldKeys != null)) {
579:
580: j = switchKey.equals(
581: ln.sharedGroup.localToVworldKeys, 0,
582: ln.sharedGroup.localToVworldKeys.length);
583: if (j < 0) {
584: System.err
585: .println("SwitchRetained : Can't find hashKey");
586: }
587:
588: if (j < ln.sharedGroup.localToVworldKeys.length) {
589: int lscSize = ln.sharedGroup.children.size();
590: for (k = 0; k < lscSize; k++) {
591: ln.sharedGroup
592: .traverseSwitchChild(
593: k,
594: ln.sharedGroup.localToVworldKeys[j],
595: j, switchRoot, init,
596: newSwChanged, switchOn,
597: switchLevel, updateList);
598: }
599: }
600: }
601: }
602: }
603: }
604:
605: void traverseSwitchParent() {
606: boolean switchOn;
607: int switchLevel;
608: SwitchRetained switchRoot;
609: int i, j;
610: int size;
611:
612: // first traverse this node's child
613: if (inSharedGroup) {
614: for (j = 0; j < localToVworldKeys.length; j++) {
615: switchLevel = ((Integer) switchLevels.get(j))
616: .intValue();
617: switchRoot = (switchLevel == 0) ? this : null;
618: size = children.size();
619: for (i = 0; i < size; i++) {
620: switchOn = renderChildMask.get(i);
621: traverseSwitchChild(i, localToVworldKeys[j], j,
622: switchRoot, true, false, switchOn,
623: switchLevel, null);
624: }
625: }
626: } else {
627: switchLevel = ((Integer) switchLevels.get(0)).intValue();
628: switchRoot = (switchLevel == 0) ? this : null;
629: size = children.size();
630: for (i = 0; i < size; i++) {
631: switchOn = renderChildMask.get(i);
632: traverseSwitchChild(i, null, 0, switchRoot, true,
633: false, switchOn, switchLevel, null);
634: }
635: }
636:
637: // now traverse this node's parent
638: if (parentSwitchLink != null) {
639: if (parentSwitchLink instanceof SwitchRetained) {
640: ((SwitchRetained) parentSwitchLink)
641: .traverseSwitchParent();
642: } else if (parentSwitchLink instanceof SharedGroupRetained) {
643: ((SharedGroupRetained) parentSwitchLink)
644: .traverseSwitchParent();
645: }
646: }
647: }
648:
649: void computeCombineBounds(Bounds bounds) {
650: int i;
651: NodeRetained child;
652:
653: if (boundsAutoCompute) {
654: if (!VirtualUniverse.mc.cacheAutoComputedBounds) {
655: if (whichChild == Switch.CHILD_ALL) {
656: for (i = 0; i < children.size(); i++) {
657: child = (NodeRetained) children.get(i);
658: if (child != null) {
659: child.computeCombineBounds(bounds);
660: }
661: }
662: } else if (whichChild == Switch.CHILD_MASK) {
663: for (i = 0; i < children.size(); i++) {
664: if (childMask.get(i)) {
665: child = (NodeRetained) children.get(i);
666: if (child != null) {
667: child.computeCombineBounds(bounds);
668: }
669: }
670: }
671: } else if (whichChild != Switch.CHILD_NONE) {
672: if (whichChild < children.size()) {
673: child = (NodeRetained) children.get(whichChild);
674: if (child != null) {
675: child.computeCombineBounds(bounds);
676: }
677: }
678: }
679: } else {
680: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
681: if (!validCachedBounds) {
682: validCachedBounds = true;
683:
684: // Issue 544
685: if (VirtualUniverse.mc.useBoxForGroupBounds) {
686: cachedBounds = new BoundingBox((Bounds) null);
687: } else {
688: cachedBounds = new BoundingSphere();
689: ((BoundingSphere) cachedBounds).setRadius(-1);
690: }
691: if (whichChild == Switch.CHILD_ALL) {
692: for (i = 0; i < children.size(); i++) {
693: child = (NodeRetained) children.get(i);
694: if (child != null) {
695: child
696: .computeCombineBounds(cachedBounds);
697: }
698: }
699: } else if (whichChild == Switch.CHILD_MASK) {
700: for (i = 0; i < children.size(); i++) {
701: if (childMask.get(i)) {
702: child = (NodeRetained) children.get(i);
703: if (child != null) {
704: child
705: .computeCombineBounds(cachedBounds);
706: }
707: }
708: }
709: } else if (whichChild != Switch.CHILD_NONE) {
710: if (whichChild < children.size()) {
711: child = (NodeRetained) children
712: .get(whichChild);
713: if (child != null) {
714: child
715: .computeCombineBounds(cachedBounds);
716: }
717: }
718: }
719: }
720: bounds.combine(cachedBounds);
721: }
722: } else {
723: // Should this be lock too ? ( MT safe ? )
724: synchronized (localBounds) {
725: bounds.combine(localBounds);
726: }
727: }
728: }
729:
730: /**
731: * Gets the bounding object of a node.
732: * @return the node's bounding object
733: */
734: Bounds getBounds() {
735:
736: int i;
737: NodeRetained child;
738:
739: if (boundsAutoCompute) {
740: // Issue 514 : NPE in Wonderland : triggered in cached bounds computation
741: if (validCachedBounds) {
742: return (Bounds) cachedBounds.clone();
743: }
744:
745: // issue 544
746: Bounds boundingObject = null;
747: if (VirtualUniverse.mc.useBoxForGroupBounds) {
748: boundingObject = new BoundingBox((Bounds) null);
749: } else {
750: boundingObject = new BoundingSphere();
751: ((BoundingSphere) boundingObject).setRadius(-1.0);
752: }
753:
754: if (whichChild == Switch.CHILD_ALL) {
755: for (i = 0; i < children.size(); i++) {
756: child = (NodeRetained) children.get(i);
757: if (child != null) {
758: child
759: .computeCombineBounds((Bounds) boundingObject);
760: }
761: }
762: } else if (whichChild == Switch.CHILD_MASK) {
763: for (i = 0; i < children.size(); i++) {
764: if (childMask.get(i)) {
765: child = (NodeRetained) children.get(i);
766: if (child != null) {
767: child
768: .computeCombineBounds((Bounds) boundingObject);
769: }
770: }
771: }
772: } else if (whichChild != Switch.CHILD_NONE
773: && whichChild >= 0 && whichChild < children.size()) {
774:
775: child = (NodeRetained) children.get(whichChild);
776: if (child != null) {
777: child.computeCombineBounds((Bounds) boundingObject);
778: }
779: }
780:
781: return (Bounds) boundingObject;
782: } else {
783: return super .getBounds();
784: }
785: }
786:
787: /*
788: void compile(CompileState compState) {
789: setCompiled();
790: compState.startGroup(null); // don't merge at this level
791: compileChildren(compState);
792: compState.endGroup();
793: }
794: */
795:
796: /**
797: * Compiles the children of the switch, preventing shape merging at
798: * this level or above
799: */
800: void compile(CompileState compState) {
801:
802: super .compile(compState);
803:
804: // don't remove this group node
805: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
806:
807: if (J3dDebug.devPhase && J3dDebug.debug) {
808: compState.numSwitches++;
809: }
810: }
811:
812: void insertChildrenData(int index) {
813: if (childrenSwitchStates == null) {
814: childrenSwitchStates = new ArrayList(1);
815: childrenSwitchLinks = new ArrayList(1);
816: }
817:
818: childrenSwitchLinks.add(index, new ArrayList(1));
819:
820: ArrayList switchStates = new ArrayList(1);
821: childrenSwitchStates.add(index, switchStates);
822: if (source != null && source.isLive()) {
823: for (int i = 0; i < localToVworld.length; i++) {
824: switchStates.add(new SwitchState(true));
825: }
826: }
827: }
828:
829: void appendChildrenData() {
830: if (childrenSwitchStates == null) {
831: childrenSwitchStates = new ArrayList(1);
832: childrenSwitchLinks = new ArrayList(1);
833: }
834: childrenSwitchLinks.add(new ArrayList(1));
835:
836: ArrayList switchStates = new ArrayList(1);
837: childrenSwitchStates.add(switchStates);
838: if (source != null && source.isLive()) {
839: for (int i = 0; i < localToVworld.length; i++) {
840: switchStates.add(new SwitchState(true));
841: }
842: }
843: }
844:
845: void removeChildrenData(int index) {
846: ArrayList oldSwitchStates = (ArrayList) childrenSwitchStates
847: .get(index);
848: oldSwitchStates.clear();
849: childrenSwitchStates.remove(index);
850:
851: ArrayList oldSwitchLinks = (ArrayList) childrenSwitchLinks
852: .get(index);
853: oldSwitchLinks.clear();
854: childrenSwitchLinks.remove(index);
855: }
856:
857: void childDoSetLive(NodeRetained child, int childIndex,
858: SetLiveState s) {
859:
860: int numPaths = (inSharedGroup) ? s.keys.length : 1;
861: s.childSwitchLinks = (ArrayList) childrenSwitchLinks
862: .get(childIndex);
863: for (int j = 0; j < numPaths; j++) {
864: s.closestSwitchIndices[j] = switchIndexCount;
865: s.closestSwitchParents[j] = this ;
866: }
867: // use switchIndexCount instead of child index to avoid
868: // reordering due to add/remove child later
869: switchIndexCount++;
870:
871: Targets[] newTargets = new Targets[numPaths];
872: for (int i = 0; i < numPaths; i++) {
873: newTargets[i] = new Targets();
874: }
875: s.switchTargets = newTargets;
876: s.switchStates = (ArrayList) childrenSwitchStates
877: .get(childIndex);
878:
879: if (child != null)
880: child.setLive(s);
881:
882: CachedTargets cachedTargets;
883: SwitchState switchState;
884: if (!inSharedGroup) {
885: cachedTargets = s.switchTargets[0].snapShotInit();
886: switchState = (SwitchState) s.switchStates.get(0);
887: switchState.cachedTargets = cachedTargets;
888: } else {
889: for (int i = 0; i < numPaths; i++) {
890: cachedTargets = s.switchTargets[i].snapShotInit();
891: switchState = (SwitchState) s.switchStates
892: .get(s.hashkeyIndex[i]);
893: switchState.cachedTargets = cachedTargets;
894: }
895: }
896: }
897:
898: // ***************************
899: // TargetsInterface methods
900: // ***************************
901:
902: TargetsInterface getClosestTargetsInterface(int type) {
903: return (type == TargetsInterface.SWITCH_TARGETS) ? (TargetsInterface) this
904: : (TargetsInterface) parentTransformLink;
905: }
906:
907: public CachedTargets getCachedTargets(int type, int index, int child) {
908: if (type == TargetsInterface.SWITCH_TARGETS) {
909: ArrayList switchStates = (ArrayList) childrenSwitchStates
910: .get(child);
911: if (index < switchStates.size()) {
912: SwitchState switchState = (SwitchState) switchStates
913: .get(index);
914: return switchState.cachedTargets;
915: } else {
916: return null;
917: }
918: } else {
919: System.err.println("getCachedTargets: wrong arguments");
920: return null;
921: }
922: }
923:
924: public void resetCachedTargets(int type, CachedTargets[] newCtArr,
925: int child) {
926: if (type == TargetsInterface.SWITCH_TARGETS) {
927: ArrayList switchStates = (ArrayList) childrenSwitchStates
928: .get(child);
929: if (newCtArr.length != switchStates.size()) {
930: System.err
931: .println("resetCachedTargets: unmatched length!"
932: + newCtArr.length
933: + " "
934: + switchStates.size());
935: System.err.println(" resetCachedTargets: " + this );
936: }
937: SwitchState switchState;
938: for (int i = 0; i < newCtArr.length; i++) {
939: switchState = (SwitchState) switchStates.get(i);
940: switchState.cachedTargets = newCtArr[i];
941: }
942: } else {
943: System.err.println("resetCachedTargets: wrong arguments");
944: }
945: }
946:
947: public ArrayList getTargetsData(int type, int child) {
948: if (type == TargetsInterface.SWITCH_TARGETS) {
949: return (ArrayList) childrenSwitchStates.get(child);
950: } else {
951: System.err.println("getTargetsData: wrong arguments");
952: return null;
953: }
954: }
955:
956: public int getTargetThreads(int type) {
957: System.err.println("getTargetsThreads: wrong arguments");
958: return -1;
959: }
960:
961: public void updateCachedTargets(int type, CachedTargets[] newCt) {
962: System.err.println("updateCachedTarget: wrong arguments");
963: }
964:
965: public void computeTargetThreads(int type, CachedTargets[] newCt) {
966: System.err.println("computeTargetThreads: wrong arguments");
967: }
968:
969: public void updateTargetThreads(int type, CachedTargets[] newCt) {
970: System.err.println("updateTargetThreads: wrong arguments");
971: }
972:
973: public void propagateTargetThreads(int type, int newTargetThreads) {
974: System.err.println("propagateTargetThreads: wrong arguments");
975: }
976:
977: public void copyCachedTargets(int type, CachedTargets[] newCt) {
978: System.err.println("copyCachedTarget: wrong arguments");
979: }
980: }
|