diff options
Diffstat (limited to 'src/javax/media/j3d/Node.java')
-rw-r--r-- | src/javax/media/j3d/Node.java | 823 |
1 files changed, 823 insertions, 0 deletions
diff --git a/src/javax/media/j3d/Node.java b/src/javax/media/j3d/Node.java new file mode 100644 index 0000000..70bfe02 --- /dev/null +++ b/src/javax/media/j3d/Node.java @@ -0,0 +1,823 @@ +/* + * 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.Enumeration; +import java.util.Hashtable; + +/** + * 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, + * specifically bounding volumes. + * + * <p> + * For more information, see the + * <a href="doc-files/intro.html">Introduction to the Java 3D API</a>. + * + * <p> + * NOTE: Applications should <i>not</i> extend this class directly. + */ +public abstract class Node extends SceneGraphObject { + + /** + * Specifies that this Node will be reported in the pick + * SceneGraphPath if a pick occurs. This capability is only + * specifiable for Group nodes; it is ignored for leaf nodes. + * The default for Group nodes is false. All interior nodes not + * needed for uniqueness in a SceneGraphPath that don't have + * ENABLE_PICK_REPORTING set to true will not be reported in the + * SceneGraphPath. + * @see SceneGraphPath + */ + public static final int + ENABLE_PICK_REPORTING = CapabilityBits.NODE_ENABLE_PICK_REPORTING; + + /** + * Specifies that this Node will be reported in the collision + * SceneGraphPath if a collision occurs. This capability is only + * specifiable for Group nodes; it is ignored for leaf nodes. + * The default for Group nodes is false. All interior nodes not + * needed for uniqueness in a SceneGraphPath that don't have + * ENABLE_COLLISION_REPORTING set to true will not be reported + * in the SceneGraphPath. + * @see SceneGraphPath + */ + public static final int + ENABLE_COLLISION_REPORTING = CapabilityBits.NODE_ENABLE_COLLISION_REPORTING; + + /** + * Specifies that this Node allows read access to its bounds + * information. + */ + public static final int + ALLOW_BOUNDS_READ = CapabilityBits.NODE_ALLOW_BOUNDS_READ; + + /** + * Specifies that this Node allows write access to its bounds + * information. + */ + public static final int + ALLOW_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_BOUNDS_WRITE; + + /** + * Specifies that this Node allows reading its pickability state. + */ + public static final int + ALLOW_PICKABLE_READ = CapabilityBits.NODE_ALLOW_PICKABLE_READ; + + /** + * Specifies that this Node allows write access its pickability state. + */ + public static final int + ALLOW_PICKABLE_WRITE = CapabilityBits.NODE_ALLOW_PICKABLE_WRITE; + + /** + * Specifies that this Node allows reading its collidability state. + */ + public static final int + ALLOW_COLLIDABLE_READ = CapabilityBits.NODE_ALLOW_COLLIDABLE_READ; + + /** + * Specifies that this Node allows write access its collidability state. + */ + public static final int + ALLOW_COLLIDABLE_WRITE = CapabilityBits.NODE_ALLOW_COLLIDABLE_WRITE; + + /** + * Specifies that this Node allows read access to its bounds + * auto compute information. + */ + public static final int + ALLOW_AUTO_COMPUTE_BOUNDS_READ = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_READ; + + /** + * Specifies that this Node allows write access to its bounds + * auto compute information. + */ + public static final int + ALLOW_AUTO_COMPUTE_BOUNDS_WRITE = CapabilityBits.NODE_ALLOW_AUTO_COMPUTE_BOUNDS_WRITE; + + /** + * Specifies that this Node allows read access to its local + * coordinates to virtual world (Vworld) coordinates transform. + */ + public static final int + ALLOW_LOCAL_TO_VWORLD_READ = CapabilityBits.NODE_ALLOW_LOCAL_TO_VWORLD_READ; + + /** + * Specifies that this Node allows read access to its parent Group node. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_PARENT_READ = CapabilityBits.NODE_ALLOW_PARENT_READ; + + /** + * Specifies that this Node allows read access to its Locale. + * + * @since Java 3D 1.4 + */ + public static final int + ALLOW_LOCALE_READ = CapabilityBits.NODE_ALLOW_LOCALE_READ; + + // Array for setting default read capabilities + private static final int[] readCapabilities = { + ALLOW_BOUNDS_READ, + ALLOW_PICKABLE_READ, + ALLOW_COLLIDABLE_READ, + ALLOW_AUTO_COMPUTE_BOUNDS_READ, + ALLOW_LOCAL_TO_VWORLD_READ, + ALLOW_PARENT_READ, + ALLOW_LOCALE_READ + }; + + // for checking for cycles + private boolean visited = false; + + + /** + * Constructs a Node object with default parameters. The default + * values are as follows: + * <ul> + * pickable : true<br> + * collidable : true<br> + * bounds auto compute : true<br> + * bounds : N/A (automatically computed)<br> + * </ul> + */ + public Node() { + // set default read capabilities + setDefaultReadCapabilities(readCapabilities); + } + + /** + + * @return the parent of this node, or null if this node has no parent + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public Node getParent() { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_PARENT_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node0")); + } + } + + NodeRetained nr = ((NodeRetained)this.retained).getParent(); + return (nr == null ? null : (Node) nr.getSource()); + } + + /** + * Sets the geometric bounds of a node. + * @param bounds the bounding object for a node + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBounds(Bounds bounds) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node1")); + + ((NodeRetained)this.retained).setBounds(bounds); + } + + /** + * Returns the bounding object of a node. + * @return the node's bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + */ + public Bounds getBounds() { + + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_BOUNDS_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node2")); + } + } + else { + // this will throw a SceneGraphCycleException if there is + // a cycle + checkForCycle(); + } + + return ((NodeRetained)this.retained).getBounds(); + } + + /** + * Returns the collidable value; this value determines whether this node + * and it's children, if a group node, can be considered for collision + * purposes; if it is set to false, then neither this node nor any + * children nodes will be traversed for collision purposes; the default + * value is true. The collidable setting is the way that an + * application can perform collision culling. + * @return the present collidable value for this node + */ + public boolean getCollidable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLIDABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node16")); + + return ((NodeRetained)retained).getCollidable(); + } + + /** + * Sets the collidable value; determines whether this node and any of its + * children, if a group node, can be considered for collision purposes. + * @param collidable the new collidable value for this node + */ + public void setCollidable( boolean collidable ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_COLLIDABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node4")); + + ((NodeRetained)retained).setCollidable(collidable); + } + + /** + * Turns the automatic calcuation of geometric bounds of a node on/off. + * @param autoCompute indicates if the node's bounding object is + * automatically computed. + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public void setBoundsAutoCompute(boolean autoCompute) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node5")); + + ((NodeRetained)this.retained).setBoundsAutoCompute(autoCompute); + } + + /** + * Gets the value indicating if the automatic calcuation of geometric bounds of a node is on/off. + * @return the node's auto compute flag for the geometric bounding object + * @exception CapabilityNotSetException if appropriate capability is + * not set and this object is part of live or compiled scene graph + */ + public boolean getBoundsAutoCompute() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_AUTO_COMPUTE_BOUNDS_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node6")); + + return ((NodeRetained)this.retained).getBoundsAutoCompute(); + } + + /** + * Retrieves the local coordinates to virtual world coordinates + * transform for this node in the scene graph. This is the composite + * of all transforms in the scene graph from the root down to + * <code>this</code> node. It is only valid + * for nodes that are part of a live scene graph. + * If the node is not part of a live scene graph then the coordinates are + * calculated as if the graph was attached at the origin of a locale. + * @param t the object that will receive the local coordinates to + * Vworld coordinates transform. + * @exception RestrictedAccessException if the node is compiled but not + * part of a live scene graph + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live or compiled scene graph + * @exception IllegalSharingException if the node is a descendant + * of a SharedGroup node. + */ + public void getLocalToVworld(Transform3D t) { + if (isLiveOrCompiled()) { + if(!this.getCapability(ALLOW_LOCAL_TO_VWORLD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node8")); + } + + if (!isLive()) { + // TODO Support compiled graphs + if (isCompiled()) + throw new RestrictedAccessException(J3dI18N.getString("Node7")); + + // In 1.4 we support getLocalToVworld for non live nodes + ((NodeRetained)this.retained).computeNonLiveLocalToVworld(t, this); + //throw new RestrictedAccessException(J3dI18N.getString("Node7")); + } else { + ((NodeRetained)this.retained).getLocalToVworld(t); + } + } + + + /** + * Retrieves the local coordinates to virtual world coordinates + * transform for the particular path in the scene graph ending with + * this node. This is the composite + * of all transforms in the scene graph from the root down to + * <code>this</code> node via the specified Link nodes. It is + * only valid for nodes that are part of a live scene graph. + * @param path the specific path from the node to the Locale + * @param t the object that will receive the local coordinates to + * Vworld coordinates transform. + * @exception RestrictedAccessException if the node is <em>not</em> + * part of a live scene graph + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live scene graph + * @exception IllegalArgumentException if the specified path does + * not contain a valid Locale, or if the last node in the path is + * different from this node + * @exception IllegalSharingException if the node is not a descendant + * of a SharedGroup node. + */ + public void getLocalToVworld(SceneGraphPath path, Transform3D t) { + if (!isLive()) { + throw new RestrictedAccessException(J3dI18N.getString("Node7")); + } + + if(!this.getCapability(ALLOW_LOCAL_TO_VWORLD_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node8")); + + ((NodeRetained)this.retained).getLocalToVworld(path,t); + + } + + /** + * Retrieves the locale to which this node is attached. If the + * node is not part of a live scene graph, null is returned. + * + * @return the locale to which this node is attached. + * + * @exception CapabilityNotSetException if appropriate capability is + * not set and this node is part of live scene graph + * @exception IllegalSharingException if the node is a descendant + * of a SharedGroup node. + * + * @since Java 3D 1.4 + */ + public Locale getLocale() { + if (!isLive()) { + return null; + } + + if(!this.getCapability(ALLOW_LOCALE_READ)) { + throw new CapabilityNotSetException(J3dI18N.getString("Node17")); + } + + return ((NodeRetained)this.retained).getLocale(); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> + * and then <code>cloneTree</code> + * is called for each child node. For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * @return a reference to the cloned sub-graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree() { + return cloneTree(new NodeReferenceTable(), false, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> + * and then <code>cloneTree</code> is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> determines whether data is + * duplicated or copied. + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree(boolean forceDuplicate) { + return cloneTree(new NodeReferenceTable(), forceDuplicate, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> and + * then <code>cloneTree</code> is called for each child node. For + * Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> + * flag to be ignored. When <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> determines whether data is + * duplicated or copied. + * + * @param allowDanglingReferences when set to <code>true</code> allows + * the <code>cloneTree</code> + * method to complete even whan a dangling reference is discovered. When + * this parameter is <code>false</code> a + * <code>DanglingReferenceException</code> is generated as + * soon as cloneTree detects this situation. + * + * @return a reference to the cloned scene graph. + * + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation and the + * <code>allowDanglingReference</code> parameter is </code>false</code>. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneTree(boolean forceDuplicate, + boolean allowDanglingReferences) { + return cloneTree(new NodeReferenceTable(), + forceDuplicate, allowDanglingReferences); + } + + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> + * and then <code>cloneTree</code> + * is called for each child node. For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @return a reference to the cloned sub-graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable) { + return cloneTree(referenceTable, false, false); + } + + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> + * and then <code>cloneTree</code> is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> determines whether data is + * duplicated or copied. + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable, + boolean forceDuplicate) { + return cloneTree(referenceTable, forceDuplicate, false); + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> + * and then <code>cloneTree</code> is called for each child node. + * For Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * @param referenceTable table that stores the mapping between + * original and cloned nodes. All previous values in the + * referenceTable will be cleared before the clone is made. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> determines whether data is + * duplicated or copied. + * + * @param allowDanglingReferences when set to <code>true</code> allows + * the <code>cloneTree</code> + * method to complete even whan a dangling reference is discovered. When + * this parameter is <code>false</code> a + * <code>DanglingReferenceException</code> is generated as + * soon as cloneTree detects this situation. + * + * @return a reference to the cloned scene graph. + * @exception DanglingReferenceException When a dangling reference is + * discovered during the cloneTree operation. + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * @exception SceneGraphCycleException if there is a cycle in the + * scene graph + * @see NodeComponent#setDuplicateOnCloneTree + * @since Java 3D 1.2 + */ + public Node cloneTree(NodeReferenceTable referenceTable, + boolean forceDuplicate, + boolean allowDanglingReferences) { + + if (!isLiveOrCompiled()) { + // this will throw a SceneGraphCycleException if there is + // a cycle + checkForCycle(); + } + + referenceTable.set(allowDanglingReferences, new Hashtable()); + Node n = cloneTree(forceDuplicate, referenceTable.objectHashtable); + + // go through hash table looking for Leaf nodes. + // call updateNodeReferences for each. + Enumeration e = referenceTable.objectHashtable.elements(); + + while (e.hasMoreElements()) { + SceneGraphObject o = (SceneGraphObject) e.nextElement(); + o.updateNodeReferences(referenceTable); + } + return n; + } + + /** + * Duplicates all the nodes of the specified sub-graph. For Group Nodes + * the group node is duplicated via a call to <code>cloneNode</code> and + * then <code>cloneTree</code> is called for each child node. For + * Leaf Nodes, component + * data can either be duplicated or be made a reference to the original + * data. Leaf Node cloneTree behavior is determined by the + * <code>duplicateOnCloneTree</code> flag found in every Leaf Node's + * component data class and by the <code>forceDuplicate</code> paramter. + * + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> + * flag to be ignored. When <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> determines whether data is + * duplicated or copied. + * + * @param nodeHashtable a hashtable used to map orignal node references to + * their cloned counterpart. + * + * @return a reference to the cloned scene graph. + * + * @see NodeComponent#setDuplicateOnCloneTree + */ + Node cloneTree(boolean forceDuplicate, Hashtable nodeHashtable) { + Node l; + this.nodeHashtable = nodeHashtable; + try { + l = cloneNode(forceDuplicate); + } catch (RuntimeException e) { + this.nodeHashtable = null; + throw e; + } + // must reset to null so that we can tell whether the call is from user + // or cloneTree + this.nodeHashtable = null; + nodeHashtable.put(this, l); + return l; + } + + + /** + * Used to create a new instance of the node. This routine is called + * by <code>cloneTree</code> to duplicate the current node. + * <code>cloneNode</code> should be overridden by any user subclassed + * objects. All subclasses must have their <code>cloneNode</code> + * method consist of the following lines: + * <P><blockquote><pre> + * public Node cloneNode(boolean forceDuplicate) { + * UserSubClass usc = new UserSubClass(); + * usc.duplicateNode(this, forceDuplicate); + * return usc; + * } + * </pre></blockquote> + * NOTE: Applications should <i>not</i> call this method directly. + * It should only be called by the cloneTree method. + * + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if this object is part of live + * or compiled scene graph + * + * @see Node#cloneTree + * @see Node#duplicateNode + * @see NodeComponent#setDuplicateOnCloneTree + */ + public Node cloneNode(boolean forceDuplicate) { + throw new RuntimeException(J3dI18N.getString("Node12")); + } + + + /** + * Copies all node information from <code>originalNode</code> into + * the current node. This method is called from the + * <code>cloneNode</code> method which is, in turn, called by the + * <code>cloneTree</code> method. + * <P> + * For any <code>NodeComponent</code> objects + * contained by the object being duplicated, each <code>NodeComponent</code> + * object's <code>duplicateOnCloneTree</code> value is used to determine + * whether the <code>NodeComponent</code> should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * <code>forceDuplicate</code> parameter in the <code>cloneTree</code> + * method to <code>true</code>. + * + * <br> + * NOTE: Applications should <i>not</i> call this method directly. + * It should only be called by the cloneNode method. + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + public void duplicateNode(Node originalNode, + boolean forceDuplicate) { + duplicateAttributes(originalNode, forceDuplicate); + } + + /** + * Copies all node information from <code>originalNode</code> into + * the current node. This method is called from subclass of + * <code>duplicateNode</code> method which is, in turn, called by the + * <code>cloneNode</code> method. + * <P> + * For any <i>NodeComponent</i> objects + * contained by the object being duplicated, each <i>NodeComponent</i> + * object's <code>duplicateOnCloneTree</code> value is used to determine + * whether the <i>NodeComponent<i> should be duplicated in the new node + * or if just a reference to the current node should be placed in the + * new node. This flag can be overridden by setting the + * <code>forceDuplicate</code> parameter in the <code>cloneTree</code> + * method to <code>true</code>. + * + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> variable determines whether + * NodeComponent data is duplicated or copied. + * + * @see Group#cloneNode + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + final void checkDuplicateNode(Node originalNode, + boolean forceDuplicate) { + if (originalNode.nodeHashtable != null) { + duplicateAttributes(originalNode, forceDuplicate); + } else { + // user call cloneNode() or duplicateNode() directly + // instead of via cloneTree() + originalNode.nodeHashtable = new Hashtable(); + duplicateAttributes(originalNode, forceDuplicate); + originalNode.nodeHashtable = null; + } + } + + + /** + * Copies all Node information from + * <code>originalNode</code> into + * the current node. This method is called from the + * <code>cloneNode</code> method which is, in turn, called by the + * <code>cloneTree</code> method.<P> + * + * @param originalNode the original node to duplicate. + * @param forceDuplicate when set to <code>true</code>, causes the + * <code>duplicateOnCloneTree</code> flag to be ignored. When + * <code>false</code>, the value of each node's + * <code>duplicateOnCloneTree</code> variable determines whether + * NodeComponent data is duplicated or copied. + * + * @exception RestrictedAccessException if originalNode object is part of a live + * or compiled scenegraph. + * + * @see Node#duplicateNode + * @see Node#cloneTree + * @see NodeComponent#setDuplicateOnCloneTree + */ + void duplicateAttributes(Node originalNode, boolean forceDuplicate) { + + if (originalNode.isLiveOrCompiled()) { + throw new RestrictedAccessException(J3dI18N.getString("Node13")); + } + super.duplicateSceneGraphObject(originalNode); + NodeRetained attr = (NodeRetained) originalNode.retained; + NodeRetained rt = (NodeRetained) retained; + + rt.setPickable(attr.getPickable()); + rt.setCollidable(attr.getCollidable()); + } + + + /** + * When set to <code>true</code> this <code>Node</code> can be Picked. + * Setting to false indicates that this node and it's children + * are ALL unpickable. + * + * @param pickable Indicates if this node should be pickable or not + */ + public void setPickable( boolean pickable ) { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PICKABLE_WRITE)) + throw new CapabilityNotSetException(J3dI18N.getString("Node14")); + + ((NodeRetained)retained).setPickable(pickable); + } + + /** + * Returns true if this <code>Node</code> is pickable, + * false if it is not pickable. + */ + public boolean getPickable() { + if (isLiveOrCompiled()) + if(!this.getCapability(ALLOW_PICKABLE_READ)) + throw new CapabilityNotSetException(J3dI18N.getString("Node3")); + + return ((NodeRetained)retained).getPickable(); + } + + /** + * checks for cycles in the scene graph + */ + void checkForCycle() { + if (visited) { + throw new SceneGraphCycleException(J3dI18N.getString("Node15")); + } + visited = true; + Node parent = getParent(); + if (parent != null) { + parent.checkForCycle(); + } + visited = false; + } + +} |