diff options
author | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
---|---|---|
committer | Harvey Harrison <[email protected]> | 2015-04-19 21:02:06 -0700 |
commit | 7a2e20caac9db6f789a7b3fab344b9758af45335 (patch) | |
tree | b5236ff2570178de356eab569225108948eb4d30 /src/javax/media/j3d/NodeRetained.java | |
parent | f76ce302c4bb2a9f03bbee571ec5d05c29633023 (diff) |
j3dcore: flatten the directory structure a bit
Signed-off-by: Harvey Harrison <[email protected]>
Diffstat (limited to 'src/javax/media/j3d/NodeRetained.java')
-rw-r--r-- | src/javax/media/j3d/NodeRetained.java | 983 |
1 files changed, 983 insertions, 0 deletions
diff --git a/src/javax/media/j3d/NodeRetained.java b/src/javax/media/j3d/NodeRetained.java new file mode 100644 index 0000000..83739da --- /dev/null +++ b/src/javax/media/j3d/NodeRetained.java @@ -0,0 +1,983 @@ +/* + * Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +package javax.media.j3d; + + +import java.util.ArrayList; +import java.util.Vector; + +/** + * The Node class provides an abstract class for all Group and Leaf + * Nodes. It provides a common framework for constructing a Java 3D + * scene graph, including bounding volumes and parent pointers. + */ +abstract class NodeRetained extends SceneGraphObjectRetained implements NnuId { + + // All the node types in the scene graph + static final int BACKGROUND = 1; + static final int CLIP = 2; + static final int LINEARFOG = 3; + static final int EXPONENTIALFOG = 4; + static final int AMBIENTLIGHT = 5; + static final int DIRECTIONALLIGHT = 6; + static final int POINTLIGHT = 7; + static final int SPOTLIGHT = 8; + static final int LINK = 9; + static final int MORPH = 10; + static final int SHAPE = 11; + static final int BACKGROUNDSOUND = 12; + static final int POINTSOUND = 13; + static final int CONESOUND = 14; + static final int SOUNDSCAPE = 15; + static final int VIEWPLATFORM = 16; + static final int BEHAVIOR = 17; + + static final int SWITCH = 18; + static final int BRANCHGROUP = 19; + static final int ORDEREDGROUP = 20; + static final int DECALGROUP = 21; + static final int SHAREDGROUP = 22; + static final int GROUP = 23; + static final int TRANSFORMGROUP = 24; + static final int BOUNDINGLEAF = 25; + static final int MODELCLIP = 26; + static final int ALTERNATEAPPEARANCE= 27; + static final int ORIENTEDSHAPE3D = 28; + static final int VIEWSPECIFICGROUP = 29; + static final int NUMNODES = 29; + + // traverse flags + static final int CONTAINS_VIEWPLATFORM = 0x1; + + + /** + * The universe that we are in + */ + VirtualUniverse universe = null; + + /** + * The locale that this node is attatched to. This is only non-null + * if this instance is directly linked into a locale. + */ + Locale locale = null; + + /** + * The node's parent. + */ + NodeRetained parent = null; + + /** + * The node's internal identifier. + */ + String nodeId = null; + + /** + * An int that represents the nodes type. Used for quick if tests + * in the traverser. + */ + int nodeType; + + // This keeps track of how many times this Node is refernced, refCount > 1 + // if node is in a shared group + int refCount = 0; + + /** + * This is the index for the child, as seen by its parent. + */ + int childIndex = -1; + + /** + * This boolean is true when the node is in a sharedGroup + */ + boolean inSharedGroup = false; + + /** + * This indicates if the node is pickable. If this node is not + * pickable then neither are any children + */ + boolean pickable = true; + + /** + * The collidable setting; see getCollidable and setCollidable. + */ + boolean collidable = true; + + // A list of localToVworld transforms. If inSharedGroup is false, + // then only localToVworld[0][] is valid. + // Note: this contains reference to the actual transforms in the + // TransformGroupRetained + Transform3D localToVworld[][] = null; + int localToVworldIndex[][] = null; + + static final int LAST_LOCAL_TO_VWORLD = 0; + static final int CURRENT_LOCAL_TO_VWORLD = 1; + + // A parallel array to localToVworld. This is the keys for + // localToVworld transforms in shared groups. + HashKey localToVworldKeys[] = null; + + /** + * This boolean is true when the geometric bounds for the node is + * automatically updated + */ + boolean boundsAutoCompute = true; + + // "effective" bounds in local coordinate if boundsAutoCompute == F, + // used for internal operations, not used if boundsAutoCompute == T + Bounds localBounds; + + // Bounds set by the API + Bounds apiBounds; + + protected Bounds cachedBounds=null; // Cached auto compute bounds, could we use localBounds ? + protected boolean validCachedBounds = false; // Fix to Issue 514 + /** + * Each element, p, of branchGroupPaths is a list of BranchGroup from + * root of the tree to this. + * For BranchGroup under a non-shared group this size of + * branchGroupPaths is always 1. Otherwise, the size is equal to + * the number of possible paths to reach this node. + * This variable is used to cached BranchGroup for fast picking. + * For non BranchGroupRetained class this is a reference to + * the previous BranchGroupRetained branchGroupPaths. + */ +ArrayList<BranchGroupRetained[]> branchGroupPaths = new ArrayList<BranchGroupRetained[]>(1); + + // background node whose geometry branch contains this node + BackgroundRetained geometryBackground = null; + + // closest parent which is a TransformGroupRetained or sharedGroupRetained + GroupRetained parentTransformLink = null; + + // closest parent which is a SwitchRetained or sharedGroupRetained + GroupRetained parentSwitchLink = null; + + // static transform if a parent transform group is merged during compile. + TransformGroupRetained staticTransform = null; + + // orderedId assigned by OrderedGroup parent + Integer orderedId = null; + + // Id use for quick search. + int nnuId; + + NodeRetained() { + // Get a not necessary unique Id. + nnuId = NnuIdManager.getId(); + + localBounds = new BoundingBox((Bounds)null); + } + + + @Override + public int getId() { + return nnuId; + } + + @Override + public int equal(NnuId obj) { + int keyId = obj.getId(); + if(nnuId < keyId) { + return -1; + } + else if(nnuId > keyId) { + return 1; + } + else { // Found it! + return 0; + } + } + + Bounds getLocalBounds(Bounds bounds) { + return (Bounds)bounds.clone(); + } + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for the node + */ + void setBounds(Bounds bounds) { + apiBounds = bounds; + if (source.isLive()) { + if (!boundsAutoCompute) { + if (bounds != null) { + localBounds = getLocalBounds(bounds); + if (staticTransform != null) { + localBounds.transform(staticTransform.transform); + } + } else { + if(localBounds != null) { + localBounds.set((Bounds)null); + } + else { + localBounds = new BoundingBox((Bounds)null); + } + } + } + } else { + if (bounds != null) { + localBounds = getLocalBounds(bounds); + if (staticTransform != null) { + localBounds.transform(staticTransform.transform); + } + } else { + if(localBounds != null) { + localBounds.set((Bounds)null); + } + else { + localBounds = new BoundingBox((Bounds)null); + } + } + } + } + + /** + * Gets the bounding object of a node. + * @return the node's bounding object + */ + Bounds getEffectiveBounds() { + Bounds b = null; + if (localBounds != null && !localBounds.isEmpty()) { + b = (Bounds) localBounds.clone(); + if (staticTransform != null) { + Transform3D invTransform = staticTransform.getInvTransform(); + b.transform(invTransform); + } + } + return b; + } + + Bounds getBounds() { + return apiBounds; + } + + /** + * ONLY needed for SHAPE, MORPH, and LINK node type. + * Compute the combine bounds of bounds and its localBounds. + */ + void computeCombineBounds(Bounds bounds) { + // Do nothing except for Group, Shape3D, Morph, and Link node. + } + + + /** + * Sets the automatic calcuation of geometric bounds of a node. + * @param autoCompute is a boolean value indicating if automatic calcuation + * of bounds + */ + void setBoundsAutoCompute(boolean autoCompute) { + if (this.boundsAutoCompute==autoCompute) { + return; + } + + this.boundsAutoCompute = autoCompute; + dirtyBoundsCache(); + } + + /** + * Gets the auto Compute flag for the geometric bounds. + * @return the node's auto Compute flag for the geometric bounding object + */ + boolean getBoundsAutoCompute() { + return boundsAutoCompute; + } + + /** + * Replaces the specified parent by a new parent. + * @param parent the new parent + */ + void setParent(NodeRetained parent) { + this.parent = parent; + } + +/** + * Returns the parent of the node. + * @return the parent. + */ +NodeRetained getParent() { + return parent; +} + + // Transform the input bound by the current LocalToVWorld + void transformBounds(SceneGraphPath path, Bounds bound) { + if (!((NodeRetained) path.item.retained).inSharedGroup) { + bound.transform(getCurrentLocalToVworld()); + } else { + HashKey key = new HashKey(""); + path.getHashKey(key); + bound.transform(getCurrentLocalToVworld(key)); + } + } + + + // Note : key will get modified in this method. + private void computeLocalToVworld( NodeRetained caller, NodeRetained nodeR, + HashKey key, Transform3D l2Vw) { + int i; + + // To handle localToVworld under a SG. + if(nodeR instanceof SharedGroupRetained) { + // Get the immediate parent's id and remove last id from key. + String nodeId = key.getLastNodeId(); + + SharedGroupRetained sgRetained = (SharedGroupRetained) nodeR; + + // Search for the right parent. + for(i=0; i<sgRetained.parents.size(); i++) { + + if (nodeId.equals(sgRetained.parents.get(i).nodeId)) { + // Found the right link. Now traverse upward. + + computeLocalToVworld(caller, sgRetained.parents.get(i), key, l2Vw); + return; + } + } + // Problem ! + throw new RuntimeException(J3dI18N.getString("NodeRetained4")); + } + else { + + NodeRetained nodeParentR = nodeR.getParent(); + + if(nodeParentR == null) { + // Base case. It has to be a BG attached to a locale. + if(((BranchGroupRetained)(nodeR)).locale != null) { + l2Vw.setIdentity(); + } + else { + throw new RuntimeException(J3dI18N.getString("NodeRetained5")); + } + } + else { + computeLocalToVworld(caller, nodeParentR, key, l2Vw); + + } + + } + + if((nodeR instanceof TransformGroupRetained) && (nodeR != caller)) { + Transform3D t1 = new Transform3D(); + ((TransformGroupRetained)(nodeR)).transform.getWithLock(t1); + l2Vw.mul(t1); + } else if ((nodeR == caller) && (staticTransform != null)) { + l2Vw.mul(staticTransform.transform); + } + + return; + } + + /** + * Compute the LocalToVworld of this node even though it is not live. We + * assume the graph is attached at the origin of a locale + */ + void computeNonLiveLocalToVworld(Transform3D t, Node caller) { + NodeRetained n = getParent(); + + if (n==null) + t.setIdentity(); + else + n.computeNonLiveLocalToVworld(t, caller); + + if (this instanceof TransformGroupRetained && this.source!=caller) { + Transform3D trans = new Transform3D(); + ((TransformGroupRetained)this).getTransform(trans); + t.mul(trans); + } + + } + + /** + * Get the localToVworld transform for a node. + */ + void getLocalToVworld(Transform3D t) { + if (inSharedGroup) { + throw new IllegalSharingException(J3dI18N.getString("NodeRetained0")); + } + + // Lock the object while writing into t. + if (localToVworld == null) { + t.setIdentity(); + } else { + computeLocalToVworld(this, this, null, t); + } + } + + + /** + * Get the localToVworld transform for a node. + */ + void getLocalToVworld(SceneGraphPath path, Transform3D t) { + HashKey key = new HashKey(""); + + if (inSharedGroup == false) { + throw new IllegalSharingException(J3dI18N.getString("NodeRetained1")); + } + path.validate(key); + computeLocalToVworld(this, this, key, t); + + } + + /** + * Get the localToVworld transform for a node + */ + void getLocalToVworld(Transform3D t, HashKey key) { + HashKey newKey = new HashKey(key); + computeLocalToVworld(this, this, newKey, t); + } + + + /** + * Get the Locale to which the node is attached + */ + Locale getLocale() { + if (inSharedGroup) { + throw new IllegalSharingException(J3dI18N.getString("NodeRetained0")); + } + + return locale; + } + + + /** + * Get the current localToVworld transform for a node + */ + Transform3D getCurrentLocalToVworld() { + + if (localToVworld != null) { + return localToVworld[0][localToVworldIndex[0][CURRENT_LOCAL_TO_VWORLD]]; + } else { + return new Transform3D(); + } + } + + // this method expects that localToVworld is not null + + Transform3D getCurrentLocalToVworld(int index) { + return localToVworld[index][localToVworldIndex[index][CURRENT_LOCAL_TO_VWORLD]]; + } + + Transform3D getCurrentLocalToVworld(HashKey key) { + + if (localToVworld != null) { + if (!inSharedGroup) { + return localToVworld[0][localToVworldIndex[0][CURRENT_LOCAL_TO_VWORLD]]; + } else { + int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + if(i>= 0) { + return localToVworld[i][localToVworldIndex[i][CURRENT_LOCAL_TO_VWORLD]]; + } + } + } + return new Transform3D(); + } + + /** + * Get the last localToVworld transform for a node + */ + Transform3D getLastLocalToVworld() { + + if (localToVworld != null) { + return localToVworld[0][localToVworldIndex[0][LAST_LOCAL_TO_VWORLD]]; + } else { + return new Transform3D(); + } + } + + Transform3D getLastLocalToVworld(int index) { + return localToVworld[index][localToVworldIndex[index][LAST_LOCAL_TO_VWORLD]]; + } + + Transform3D getLastLocalToVworld(HashKey key) { + + if (localToVworld != null) { + if (!inSharedGroup) { + return localToVworld[0][localToVworldIndex[0][LAST_LOCAL_TO_VWORLD]]; + } else { + int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length); + if(i>= 0) { + return localToVworld[i][localToVworldIndex[i][LAST_LOCAL_TO_VWORLD]]; + } + } + } + return new Transform3D(); + } + + // Do nothing for NodeRetained. + void setAuxData(SetLiveState s, int index, int hkIndex) { + + } + + void setNodeData(SetLiveState s) { + localToVworld = s.localToVworld; + localToVworldIndex = s.localToVworldIndex; + localToVworldKeys = s.localToVworldKeys; + + // reference to the last branchGroupPaths + branchGroupPaths = s.parentBranchGroupPaths; + + parentTransformLink = s.parentTransformLink; + parentSwitchLink = s.parentSwitchLink; + } + + + // set pickable, recursively update cache result + void setPickable(boolean pickable) { + if (this.pickable == pickable) + return; + + this.pickable = pickable; + + if (source.isLive()) { + synchronized(universe.sceneGraphLock) { + boolean pick[]; + if (!inSharedGroup) { + pick = new boolean[1]; + } else { + pick = new boolean[localToVworldKeys.length]; + } + + findPickableFlags(pick); + updatePickable(localToVworldKeys, pick); + } + } + } + + void updatePickable(HashKey pickKeys[], boolean pick[]) { + for (int i=0; i < pick.length; i++) { + if (!pickable) { + pick[i] = false; + } + } + } + + // get pickable + boolean getPickable() { + return pickable; + } + + + // set collidable, recursively update cache result + void setCollidable(boolean collidable) { + if (this.collidable == collidable) + return; + + this.collidable = collidable; + + if (source.isLive()) { + synchronized(universe.sceneGraphLock) { + boolean collide[]; + if (!inSharedGroup) { + collide = new boolean[1]; + } else { + collide = new boolean[localToVworldKeys.length]; + } + + findCollidableFlags(collide); + updateCollidable(localToVworldKeys, collide); + } + } + } + + + // get collidable + boolean getCollidable() { + return collidable; + } + + + void updateCollidable(HashKey keys[], boolean collide[]) { + for (int i=0; i < collide.length; i++) { + if (!collidable) { + collide[i] = false; + } + } + } + + /** + * For the default, just pass up to parent + */ + void notifySceneGraphChanged(boolean globalTraverse){} + + void recombineAbove() {} + + synchronized void updateLocalToVworld() {} + + + @Override + void setLive(SetLiveState s) { + int oldrefCount = refCount; + + doSetLive(s); + if (oldrefCount <= 0) + super.markAsLive(); + } + + // The default set of setLive actions. + @Override + void doSetLive(SetLiveState s) { + int i; + int oldrefCount = refCount; + + refCount += s.refCount; + if(!(locale == null || universe == s.universe)) + throw new IllegalSharingException(J3dI18N.getString("NodeRetained3")); + if(s.locale == null) + System.err.println("NodeRetained.setLive() locale is null"); + + + locale = s.locale; + inSharedGroup = s.inSharedGroup; + + if (oldrefCount <= 0) { + if (listIdx == null) { + universe = s.universe; + } else { + // sync with getIdxUsed() + if (s.universe != universe) { + synchronized (this) { + universe = s.universe; + incIdxUsed(); + } + } + } + } + s.universe.numNodes++; + + // pickable & collidable array have the same length + for (i=0; i < s.pickable.length; i++) { + if (!pickable) { + s.pickable[i] = false; + } + if (!collidable) { + s.collidable[i] = false; + } + } + + + if (oldrefCount <= 0) + super.doSetLive(s); + + if (inBackgroundGroup) { + geometryBackground = s.geometryBackground; + } + + setNodeData(s); + } + + + /** + * remove the localToVworld transform for this node. + */ + void removeNodeData(SetLiveState s) { + + if (refCount <= 0) { + localToVworld = null; + localToVworldIndex = null; + localToVworldKeys = null; + // restore to default and avoid calling clear() + // that may clear parent reference branchGroupPaths + branchGroupPaths = new ArrayList<BranchGroupRetained[]>(1); + parentTransformLink = null; + parentSwitchLink = null; + } + else { + // Set it back to its parent localToVworld data. This is b/c the parent has + // changed it localToVworld data arrays. + localToVworld = s.localToVworld; + localToVworldIndex = s.localToVworldIndex; + localToVworldKeys = s.localToVworldKeys; + + // Reference of parent branchGroupPaths will not change + + // no need to reset parentSwitchLink or parentTransformLink + // because there are not per path data + } + + } + + // The default set of clearLive actions + void clearLive(SetLiveState s) { + + refCount-=s.refCount; + + if (refCount <= 0) { + super.clearLive(); + + // don't remove the nodeId unless there are no more references + if (nodeId != null) { + universe.nodeIdFreeList.addElement(nodeId); + nodeId = null; + } + } + + universe.numNodes--; + + + removeNodeData(s); + + if(refCount <= 0) { + locale = null; + geometryBackground = null; + } + } + + // search up the parent to determine if this node is pickable + void findPickableFlags(boolean pick[]) { + NodeRetained nodeR = this; + + + if (!inSharedGroup) { + pick[0] = true; + nodeR = nodeR.parent; + while (nodeR != null) { + if (!nodeR.pickable) { + pick[0] = false; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + for (int i=0; i < pick.length; i++) { + nodeR = this; + pick[i] = true; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR instanceof SharedGroupRetained) { + String nodeId = key.getLastNodeId(); + Vector<NodeRetained> parents = ((SharedGroupRetained)nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for(int j=0; j< sz; j++) { + NodeRetained linkR = parents.get(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (prevNodeR == nodeR) { + // branch is already detach + return; + } + } else { + nodeR = nodeR.parent; + } + if (nodeR == null) + break; + if (!nodeR.pickable) { + pick[i] = false; + break; + } + } while (true); + } + } + } + + + // search up the parent to determine if this node is collidable + void findCollidableFlags(boolean collide[]) { + NodeRetained nodeR = this; + + if (!inSharedGroup) { + collide[0] = true; + nodeR = nodeR.parent; + while (nodeR != null) { + if (!nodeR.collidable) { + collide[0] = false; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + for (int i=0; i < collide.length; i++) { + nodeR = this; + collide[i] = true; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR instanceof SharedGroupRetained) { + String nodeId = key.getLastNodeId(); + Vector<NodeRetained> parents = ((SharedGroupRetained)nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for(int j=0; j< sz; j++) { + NodeRetained linkR = parents.get(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (nodeR == prevNodeR) { + return; + } + } else { + nodeR = nodeR.parent; + } + if (nodeR == null) + break; + if (!nodeR.collidable) { + collide[i] = false; + break; + } + } while (true); + } + } + } + + void findTransformLevels(int transformLevels[]) { + NodeRetained nodeR = this; + TransformGroupRetained tg; + + if (!inSharedGroup) { + transformLevels[0] = -1; + while (nodeR != null) { + if (nodeR.nodeType == NodeRetained.TRANSFORMGROUP) { + tg = (TransformGroupRetained)nodeR; + transformLevels[0] = tg.transformLevels[0]; + break; + } + nodeR = nodeR.parent; + } + } else { + HashKey key; + int i,j; + for (i=0; i < transformLevels.length; i++) { + nodeR = this; + transformLevels[i] = -1; + key = new HashKey(localToVworldKeys[i]); + + do { + if (nodeR == null) + break; + else if (nodeR instanceof SharedGroupRetained) { + // note that key is truncated after getLastNodeId + String nodeId = key.getLastNodeId(); + Vector<NodeRetained> parents = ((SharedGroupRetained)nodeR).parents; + int sz = parents.size(); + NodeRetained prevNodeR = nodeR; + for (j=0; j< sz; j++) { + NodeRetained linkR = parents.get(j); + if (linkR.nodeId.equals(nodeId)) { + nodeR = linkR; + break; + } + } + if (prevNodeR == nodeR) { + // branch is already detach + return; + } + } + else if (nodeR.nodeType == NodeRetained.TRANSFORMGROUP) { + tg = (TransformGroupRetained)nodeR; + if (tg.inSharedGroup) { + + j = key.equals(tg.localToVworldKeys, 0, + tg.localToVworldKeys.length); + + transformLevels[i] = tg.transformLevels[j]; + } else { + transformLevels[i] = tg.transformLevels[0]; + } + break; + } + + nodeR = nodeR.parent; + } while (true); + } + } + } + + + @Override + boolean isStatic() { + if (source.getCapability(Node.ALLOW_LOCAL_TO_VWORLD_READ) || + source.getCapability(Node.ALLOW_PARENT_READ) || + source.getCapability(Node.ENABLE_PICK_REPORTING) || + source.getCapability(Node.ENABLE_COLLISION_REPORTING) || + source.getCapability(Node.ALLOW_BOUNDS_READ) || + source.getCapability(Node.ALLOW_BOUNDS_WRITE) || + source.getCapability(Node.ALLOW_PICKABLE_READ) || + source.getCapability(Node.ALLOW_PICKABLE_WRITE) || + source.getCapability(Node.ALLOW_COLLIDABLE_READ) || + source.getCapability(Node.ALLOW_COLLIDABLE_WRITE) || + source.getCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_READ) || + source.getCapability(Node.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE)) { + return false; + } + return true; + } + + @Override + void merge(CompileState compState) { + staticTransform = compState.staticTransform; + if (compState.parentGroup != null) { + compState.parentGroup.compiledChildrenList.add(this); + } + parent = compState.parentGroup; + if (staticTransform != null) { + mergeTransform(staticTransform); + } + } + + @Override + void mergeTransform(TransformGroupRetained xform) { + if (localBounds != null) { + localBounds.transform(xform.transform); + } + } + int[] processViewSpecificInfo(int mode, HashKey k, View v, ArrayList vsgList, int[] keyList, + ArrayList leafList) { + return keyList; + + } + + @Override + VirtualUniverse getVirtualUniverse() { + return universe; + } + + void searchGeometryAtoms(UnorderList list) {} + + /** + * Make the boundsCache of this node and all its parents dirty + */ + void dirtyBoundsCache() { + // Possible optimisation is to not traverse up the tree + // if the cachedBounds==null. However this is not the case + // if the node is the child of a SharedGroup + if (VirtualUniverse.mc.cacheAutoComputedBounds) { + // Issue 514 : NPE in Wonderland : triggered in cached bounds computation + validCachedBounds = false; + if (parent!=null) { + parent.dirtyBoundsCache(); + } + } + } +} + |