1 /* 2 * $RCSfile: LinkRetained.java,v $ 3 * 4 * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Sun designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Sun in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 24 * CA 95054 USA or visit www.sun.com if you need additional information or 25 * have any questions. 26 * 27 * $Revision: 1.6 $ 28 * $Date: 2008/02/28 20:17:26 $ 29 * $State: Exp $ 30 */ 31 32 package javax.media.j3d; 33 import java.util.*; 34 35 /** 36 * A Link leaf node consisting of a reference to a SharedGroup node. 37 */ 38 39 class LinkRetained extends LeafRetained { 40 /** 41 * The SharedGroup component of the link node. 42 */ 43 SharedGroupRetained sharedGroup; 44 45 static String plus = "+"; 46 47 // This is used when setLive to check for cycle scene graph 48 boolean visited = false; 49 LinkRetained()50 LinkRetained() { 51 this.nodeType = NodeRetained.LINK; 52 localBounds = new BoundingBox(); 53 ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); 54 ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); 55 } 56 57 /** 58 * Sets the SharedGroup reference. 59 * @param sharedGroup the SharedGroup node 60 */ setSharedGroup(SharedGroup sharedGroup)61 void setSharedGroup(SharedGroup sharedGroup) { 62 // Note that it is possible that the sharedGroup pass 63 // in already link to another link and live. 64 HashKey newKeys[] = null; 65 boolean abort = false; 66 67 if (source.isLive()) { 68 // bug 4370407: if sharedGroup is a parent, then don't do anything 69 if (sharedGroup != null) { 70 synchronized(universe.sceneGraphLock) { 71 NodeRetained pa; 72 for (pa = parent; pa != null; pa = pa.parent) { 73 if (pa == (NodeRetained)sharedGroup.retained) { 74 abort = true; 75 throw new SceneGraphCycleException(J3dI18N.getString("LinkRetained1")); 76 } 77 } 78 } 79 if (abort) 80 return; 81 } 82 83 newKeys = getNewKeys(locale.nodeId, localToVworldKeys); 84 85 if (this.sharedGroup != null) { 86 ((GroupRetained) parent).checkClearLive(this.sharedGroup, 87 newKeys, true, null, 88 0, 0, this); 89 this.sharedGroup.parents.removeElement(this); 90 } 91 } 92 93 if (sharedGroup != null) { 94 this.sharedGroup = 95 (SharedGroupRetained)sharedGroup.retained; 96 } else { 97 this.sharedGroup = null; 98 } 99 100 if (source.isLive() && (sharedGroup != null)) { 101 102 this.sharedGroup.parents.addElement(this); 103 visited = true; 104 try { 105 int ci = ((GroupRetained) parent).indexOfChild((Node)this.sharedGroup.source); 106 ((GroupRetained) parent).checkSetLive(this.sharedGroup, ci, 107 newKeys, true, null, 108 0, this); 109 } catch (SceneGraphCycleException e) { 110 throw e; 111 } finally { 112 visited = false; 113 } 114 } 115 116 } 117 118 /** 119 * Retrieves the SharedGroup reference. 120 * @return the SharedGroup node 121 */ getSharedGroup()122 SharedGroup getSharedGroup() { 123 return (sharedGroup != null ? 124 (SharedGroup)this.sharedGroup.source : null); 125 } 126 computeCombineBounds(Bounds bounds)127 void computeCombineBounds(Bounds bounds) { 128 129 if (boundsAutoCompute) { 130 sharedGroup.computeCombineBounds(bounds); 131 } else { 132 // Should this be lock too ? ( MT safe ? ) 133 synchronized(localBounds) { 134 bounds.combine(localBounds); 135 } 136 } 137 } 138 139 140 /** 141 * Gets the bounding object of a node. 142 * @return the node's bounding object 143 */ getBounds()144 Bounds getBounds() { 145 return (boundsAutoCompute ? 146 (Bounds)sharedGroup.getBounds().clone() : 147 super.getBounds()); 148 } 149 150 151 /** 152 * assign a name to this node when it is made live. 153 */ setLive(SetLiveState s)154 void setLive(SetLiveState s) { 155 156 super.doSetLive(s); 157 158 if (inBackgroundGroup) { 159 throw new 160 IllegalSceneGraphException(J3dI18N.getString("LinkRetained0")); 161 } 162 163 if (nodeId == null) { 164 nodeId = universe.getNodeId(); 165 } 166 167 if (sharedGroup != null) { 168 this.sharedGroup.parents.addElement(this); 169 HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys); 170 HashKey oldKeys[] = s.keys; 171 s.keys = newKeys; 172 s.inSharedGroup = true; 173 if (visited) { 174 throw new SceneGraphCycleException(J3dI18N.getString("LinkRetained1")); 175 } 176 visited = true; 177 try { 178 this.sharedGroup.setLive(s); 179 } catch (SceneGraphCycleException e) { 180 throw e; 181 } finally { 182 visited = false; 183 } 184 185 s.inSharedGroup = inSharedGroup; 186 s.keys = oldKeys; 187 188 localBounds.setWithLock(this.sharedGroup.localBounds); 189 } 190 191 super.markAsLive(); 192 } 193 setNodeData(SetLiveState s)194 void setNodeData(SetLiveState s) { 195 196 super.setNodeData(s); 197 198 // add this node to parentTransformLink's childTransformLink 199 if (s.childTransformLinks != null) { 200 // do not duplicate shared nodes 201 synchronized(s.childTransformLinks) { 202 if(!inSharedGroup || !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 recombineAbove()219 void recombineAbove() { 220 localBounds.setWithLock(sharedGroup.localBounds); 221 parent.recombineAbove(); 222 } 223 224 /** 225 * assign a name to this node when it is made live. 226 */ clearLive(SetLiveState s)227 void clearLive(SetLiveState s) { 228 229 if (sharedGroup != null) { 230 HashKey newKeys[] = getNewKeys(s.locale.nodeId, s.keys); 231 super.clearLive(s); 232 HashKey oldKeys[] = s.keys; 233 s.keys = newKeys; 234 s.inSharedGroup = true; 235 this.sharedGroup.parents.removeElement(this); 236 this.sharedGroup.clearLive(s); 237 s.inSharedGroup = inSharedGroup; 238 s.keys = oldKeys; 239 } else { 240 super.clearLive(s); 241 } 242 } 243 removeNodeData(SetLiveState s)244 void removeNodeData(SetLiveState s) { 245 if(refCount <= 0) { 246 // either not in sharedGroup or last instance in sharedGroup 247 // remove this node from parentTransformLink's childTransformLink 248 if (parentTransformLink != null) { 249 ArrayList obj; 250 if (parentTransformLink instanceof TransformGroupRetained) { 251 obj = ((TransformGroupRetained) 252 parentTransformLink).childTransformLinks; 253 } else { 254 obj = ((SharedGroupRetained) 255 parentTransformLink).childTransformLinks; 256 } 257 synchronized(obj) { 258 obj.remove(this); 259 } 260 } 261 262 // remove this node from parentSwitchLink's childSwitchLink 263 if (parentSwitchLink != null) { 264 ArrayList switchLinks; 265 for(int i=0; i<parentSwitchLink.childrenSwitchLinks.size();i++){ 266 switchLinks = (ArrayList) 267 parentSwitchLink.childrenSwitchLinks.get(i); 268 if (switchLinks.contains(this)) { 269 switchLinks.remove(this); 270 break; 271 } 272 } 273 } 274 } 275 super.removeNodeData(s); 276 } 277 278 updatePickable(HashKey keys[], boolean pick[])279 void updatePickable(HashKey keys[], boolean pick[]) { 280 super.updatePickable(keys, pick); 281 282 if (sharedGroup != null) { 283 HashKey newKeys[] = getNewKeys(locale.nodeId, keys); 284 sharedGroup.updatePickable(newKeys, pick); 285 } 286 } 287 updateCollidable(HashKey keys[], boolean collide[])288 void updateCollidable(HashKey keys[], boolean collide[]) { 289 super.updateCollidable(keys, collide); 290 291 if (sharedGroup != null) { 292 HashKey newKeys[] = getNewKeys(locale.nodeId, keys); 293 sharedGroup.updateCollidable(newKeys, collide); 294 } 295 } 296 setBoundsAutoCompute(boolean autoCompute)297 void setBoundsAutoCompute(boolean autoCompute) { 298 super.setBoundsAutoCompute(autoCompute); 299 if (!autoCompute) { 300 localBounds = getBounds(); 301 } 302 } 303 setCompiled()304 void setCompiled() { 305 super.setCompiled(); 306 if (sharedGroup != null) { 307 sharedGroup.setCompiled(); 308 } 309 } 310 compile(CompileState compState)311 void compile(CompileState compState) { 312 313 super.compile(compState); 314 315 // XXXX: for now keep the static transform in the parent tg 316 compState.keepTG = true; 317 318 // don't remove this group node 319 mergeFlag = SceneGraphObjectRetained.DONT_MERGE; 320 321 if (J3dDebug.devPhase && J3dDebug.debug) { 322 compState.numLinks++; 323 } 324 } 325 getNewKeys(String localeNodeId, HashKey oldKeys[])326 HashKey[] getNewKeys(String localeNodeId, HashKey oldKeys[]) { 327 HashKey newKeys[]; 328 329 if (!inSharedGroup) { 330 newKeys = new HashKey[1]; 331 newKeys[0] = new HashKey(localeNodeId); 332 newKeys[0].append(plus + nodeId); 333 } else { 334 // Need to append this link node id to all keys passed in. 335 newKeys = new HashKey[oldKeys.length]; 336 for (int i=oldKeys.length-1; i>=0; i--) { 337 newKeys[i] = new HashKey(oldKeys[i].toString() 338 + plus + nodeId); 339 } 340 } 341 return newKeys; 342 } 343 searchGeometryAtoms(UnorderList list)344 void searchGeometryAtoms(UnorderList list) { 345 if (sharedGroup != null) { 346 sharedGroup.searchGeometryAtoms(list); 347 } 348 } 349 } 350