001: /*
002: * $RCSfile: LinkRetained.java,v $
003: *
004: * Copyright 1997-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.6 $
028: * $Date: 2008/02/28 20:17:26 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.*;
035:
036: /**
037: * A Link leaf node consisting of a reference to a SharedGroup node.
038: */
039:
040: class LinkRetained extends LeafRetained {
041: /**
042: * The SharedGroup component of the link node.
043: */
044: SharedGroupRetained sharedGroup;
045:
046: static String plus = "+";
047:
048: // This is used when setLive to check for cycle scene graph
049: boolean visited = false;
050:
051: LinkRetained() {
052: this .nodeType = NodeRetained.LINK;
053: localBounds = new BoundingBox();
054: ((BoundingBox) localBounds).setLower(1.0, 1.0, 1.0);
055: ((BoundingBox) localBounds).setUpper(-1.0, -1.0, -1.0);
056: }
057:
058: /**
059: * Sets the SharedGroup reference.
060: * @param sharedGroup the SharedGroup node
061: */
062: void setSharedGroup(SharedGroup sharedGroup) {
063: // Note that it is possible that the sharedGroup pass
064: // in already link to another link and live.
065: HashKey newKeys[] = null;
066: boolean abort = false;
067:
068: if (source.isLive()) {
069: // bug 4370407: if sharedGroup is a parent, then don't do anything
070: if (sharedGroup != null) {
071: synchronized (universe.sceneGraphLock) {
072: NodeRetained pa;
073: for (pa = parent; pa != null; pa = pa.parent) {
074: if (pa == (NodeRetained) sharedGroup.retained) {
075: abort = true;
076: throw new SceneGraphCycleException(J3dI18N
077: .getString("LinkRetained1"));
078: }
079: }
080: }
081: if (abort)
082: return;
083: }
084:
085: newKeys = getNewKeys(locale.nodeId, localToVworldKeys);
086:
087: if (this .sharedGroup != null) {
088: ((GroupRetained) parent).checkClearLive(
089: this .sharedGroup, newKeys, true, null, 0, 0,
090: this );
091: this .sharedGroup.parents.removeElement(this );
092: }
093: }
094:
095: if (sharedGroup != null) {
096: this .sharedGroup = (SharedGroupRetained) sharedGroup.retained;
097: } else {
098: this .sharedGroup = null;
099: }
100:
101: if (source.isLive() && (sharedGroup != null)) {
102:
103: this .sharedGroup.parents.addElement(this );
104: visited = true;
105: try {
106: int ci = ((GroupRetained) parent)
107: .indexOfChild((Node) this .sharedGroup.source);
108: ((GroupRetained) parent).checkSetLive(this .sharedGroup,
109: ci, newKeys, true, null, 0, this );
110: } catch (SceneGraphCycleException e) {
111: throw e;
112: } finally {
113: visited = false;
114: }
115: }
116:
117: }
118:
119: /**
120: * Retrieves the SharedGroup reference.
121: * @return the SharedGroup node
122: */
123: SharedGroup getSharedGroup() {
124: return (sharedGroup != null ? (SharedGroup) this .sharedGroup.source
125: : null);
126: }
127:
128: void computeCombineBounds(Bounds bounds) {
129:
130: if (boundsAutoCompute) {
131: sharedGroup.computeCombineBounds(bounds);
132: } else {
133: // Should this be lock too ? ( MT safe ? )
134: synchronized (localBounds) {
135: bounds.combine(localBounds);
136: }
137: }
138: }
139:
140: /**
141: * Gets the bounding object of a node.
142: * @return the node's bounding object
143: */
144: Bounds getBounds() {
145: return (boundsAutoCompute ? (Bounds) sharedGroup.getBounds()
146: .clone() : super .getBounds());
147: }
148:
149: /**
150: * assign a name to this node when it is made live.
151: */
152: void setLive(SetLiveState s) {
153:
154: super .doSetLive(s);
155:
156: if (inBackgroundGroup) {
157: throw new IllegalSceneGraphException(J3dI18N
158: .getString("LinkRetained0"));
159: }
160:
161: if (nodeId == null) {
162: nodeId = universe.getNodeId();
163: }
164:
165: if (sharedGroup != null) {
166: this .sharedGroup.parents.addElement(this );
167: HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys);
168: HashKey oldKeys[] = s.keys;
169: s.keys = newKeys;
170: s.inSharedGroup = true;
171: if (visited) {
172: throw new SceneGraphCycleException(J3dI18N
173: .getString("LinkRetained1"));
174: }
175: visited = true;
176: try {
177: this .sharedGroup.setLive(s);
178: } catch (SceneGraphCycleException e) {
179: throw e;
180: } finally {
181: visited = false;
182: }
183:
184: s.inSharedGroup = inSharedGroup;
185: s.keys = oldKeys;
186:
187: localBounds.setWithLock(this .sharedGroup.localBounds);
188: }
189:
190: super .markAsLive();
191: }
192:
193: void setNodeData(SetLiveState s) {
194:
195: super .setNodeData(s);
196:
197: // add this node to parentTransformLink's childTransformLink
198: if (s.childTransformLinks != null) {
199: // do not duplicate shared nodes
200: synchronized (s.childTransformLinks) {
201: if (!inSharedGroup
202: || !s.childTransformLinks.contains(this )) {
203: s.childTransformLinks.add(this );
204: }
205: }
206: }
207:
208: // add this node to parentSwitchLink's childSwitchLink
209: if (s.childSwitchLinks != null) {
210: if (!inSharedGroup ||
211: // only add if not already added in sharedGroup
212: !s.childSwitchLinks.contains(this )) {
213: s.childSwitchLinks.add(this );
214: }
215: }
216: }
217:
218: void recombineAbove() {
219: localBounds.setWithLock(sharedGroup.localBounds);
220: parent.recombineAbove();
221: }
222:
223: /**
224: * assign a name to this node when it is made live.
225: */
226: void clearLive(SetLiveState s) {
227:
228: if (sharedGroup != null) {
229: HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys);
230: super .clearLive(s);
231: HashKey oldKeys[] = s.keys;
232: s.keys = newKeys;
233: s.inSharedGroup = true;
234: this .sharedGroup.parents.removeElement(this );
235: this .sharedGroup.clearLive(s);
236: s.inSharedGroup = inSharedGroup;
237: s.keys = oldKeys;
238: } else {
239: super .clearLive(s);
240: }
241: }
242:
243: void removeNodeData(SetLiveState s) {
244: if (refCount <= 0) {
245: // either not in sharedGroup or last instance in sharedGroup
246: // remove this node from parentTransformLink's childTransformLink
247: if (parentTransformLink != null) {
248: ArrayList obj;
249: if (parentTransformLink instanceof TransformGroupRetained) {
250: obj = ((TransformGroupRetained) parentTransformLink).childTransformLinks;
251: } else {
252: obj = ((SharedGroupRetained) parentTransformLink).childTransformLinks;
253: }
254: synchronized (obj) {
255: obj.remove(this );
256: }
257: }
258:
259: // remove this node from parentSwitchLink's childSwitchLink
260: if (parentSwitchLink != null) {
261: ArrayList switchLinks;
262: for (int i = 0; i < parentSwitchLink.childrenSwitchLinks
263: .size(); i++) {
264: switchLinks = (ArrayList) parentSwitchLink.childrenSwitchLinks
265: .get(i);
266: if (switchLinks.contains(this )) {
267: switchLinks.remove(this );
268: break;
269: }
270: }
271: }
272: }
273: super .removeNodeData(s);
274: }
275:
276: void updatePickable(HashKey keys[], boolean pick[]) {
277: super .updatePickable(keys, pick);
278:
279: if (sharedGroup != null) {
280: HashKey newKeys[] = getNewKeys(locale.nodeId, keys);
281: sharedGroup.updatePickable(newKeys, pick);
282: }
283: }
284:
285: void updateCollidable(HashKey keys[], boolean collide[]) {
286: super .updateCollidable(keys, collide);
287:
288: if (sharedGroup != null) {
289: HashKey newKeys[] = getNewKeys(locale.nodeId, keys);
290: sharedGroup.updateCollidable(newKeys, collide);
291: }
292: }
293:
294: void setBoundsAutoCompute(boolean autoCompute) {
295: super .setBoundsAutoCompute(autoCompute);
296: if (!autoCompute) {
297: localBounds = getBounds();
298: }
299: }
300:
301: void setCompiled() {
302: super .setCompiled();
303: if (sharedGroup != null) {
304: sharedGroup.setCompiled();
305: }
306: }
307:
308: void compile(CompileState compState) {
309:
310: super .compile(compState);
311:
312: // XXXX: for now keep the static transform in the parent tg
313: compState.keepTG = true;
314:
315: // don't remove this group node
316: mergeFlag = SceneGraphObjectRetained.DONT_MERGE;
317:
318: if (J3dDebug.devPhase && J3dDebug.debug) {
319: compState.numLinks++;
320: }
321: }
322:
323: HashKey[] getNewKeys(String localeNodeId, HashKey oldKeys[]) {
324: HashKey newKeys[];
325:
326: if (!inSharedGroup) {
327: newKeys = new HashKey[1];
328: newKeys[0] = new HashKey(localeNodeId);
329: newKeys[0].append(plus + nodeId);
330: } else {
331: // Need to append this link node id to all keys passed in.
332: newKeys = new HashKey[oldKeys.length];
333: for (int i = oldKeys.length - 1; i >= 0; i--) {
334: newKeys[i] = new HashKey(oldKeys[i].toString() + plus
335: + nodeId);
336: }
337: }
338: return newKeys;
339: }
340:
341: void searchGeometryAtoms(UnorderList list) {
342: if (sharedGroup != null) {
343: sharedGroup.searchGeometryAtoms(list);
344: }
345: }
346: }
|