/*
* 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 org.scijava.java3d;
import java.util.Enumeration;
/**
* The Behavior leaf node provides a framework for adding user-defined
* actions into the scene graph. Behavior is an abstract class that
* defines two methods that must be overridden by a subclass: An
* initialization method, called once when the behavior
* becomes "live," and a processStimulus method called
* whenever appropriate by the Java 3D behavior scheduler. The
* Behavior node also contains an enable flag, a scheduling region,
* a scheduling interval, and a wakeup condition.
*
*
* The scheduling region defines a spatial volume that serves * to enable the scheduling of Behavior nodes. A Behavior node is * active (can receive stimuli) whenever an active ViewPlatform's * activation volume intersects a Behavior object's scheduling * region. Only active behaviors can receive stimuli. * *
* The scheduling interval defines a partial order of execution * for behaviors that wake up in response to the same wakeup condition * (that is, those behaviors that are processed at the same "time"). * Given a set of behaviors whose wakeup conditions are satisfied at * the same time, the behavior scheduler will execute all behaviors in * a lower scheduling interval before executing any behavior in a * higher scheduling interval. Within a scheduling interval, * behaviors can be executed in any order, or in parallel. Note that * this partial ordering is only guaranteed for those behaviors that * wake up at the same time in response to the same wakeup condition, * for example, the set of behaviors that wake up every frame in * response to a WakeupOnElapsedFrames(0) wakeup condition. * *
* The initialize method allows a Behavior object to
* initialize its internal state and specify its initial wakeup
* condition(s). Java 3D invokes a behavior's initialize code when the
* behavior's containing BranchGroup node is added to the virtual
* universe. Java 3D does not invoke the initialize method in a new
* thread. Thus, for Java 3D to regain control, the initialize method
* must not execute an infinite loop; it must return. Furthermore, a
* wakeup condition must be set or else the behavior's processStimulus
* method is never executed.
*
*
* The processStimulus method receives and processes a
* behavior's ongoing messages. The Java 3D behavior scheduler invokes
* a Behavior node's processStimulus method when an active ViewPlatform's
* activation volume intersects a Behavior object's scheduling region
* and all of that behavior's wakeup criteria are satisfied. The
* processStimulus method performs its computations and actions
* (possibly including the registration of state change information
* that could cause Java 3D to wake other Behavior objects),
* establishes its next wakeup condition, and finally exits.
* A typical behavior will modify one or more nodes or node components
* in the scene graph. These modifications can happen in parallel
* with rendering. In general, applications cannot count on behavior
* execution being synchronized with rendering. There are two
* exceptions to this general rule:
*
processStimulus method of a single behavior instance
* are guaranteed to take effect in the same rendering frame.processStimulus methods of the set of behaviors that
* wake up in response to a WakeupOnElapsedFrames(0) wakeup condition
* are guaranteed to take effect in the same rendering frame.* Code Structure *
* When the Java 3D behavior scheduler invokes a Behavior object's * processStimulus method, that method may perform any computation it * wishes. Usually, it will change its internal state and specify its * new wakeup conditions. Most probably, it will manipulate scene * graph elements. However, the behavior code can only change those * aspects of a scene graph element permitted by the capabilities * associated with that scene graph element. A scene graph's * capabilities restrict behavioral manipulation to those * manipulations explicitly allowed. * *
* The application must provide the Behavior object with references to * those scene graph elements that the Behavior object will * manipulate. The application provides those references as arguments * to the behavior's constructor when it creates the Behavior * object. Alternatively, the Behavior object itself can obtain access * to the relevant scene graph elements either when Java 3D invokes * its initialize method or each time Java 3D invokes its * processStimulus method. * *
* Behavior methods have a very rigid structure. Java 3D assumes that * they always run to completion (if needed, they can spawn * threads). Each method's basic structure consists of the following: * *
*
* WakeupCondition Object *
* A WakeupCondition object is an abstract class specialized to * fourteen different WakeupCriterion objects and to four combining * objects containing multiple WakeupCriterion objects. A Behavior * node provides the Java 3D behavior scheduler with a WakeupCondition * object. When that object's WakeupCondition has been satisfied, the * behavior scheduler hands that same WakeupCondition back to the * Behavior via an enumeration. * *
* WakeupCriterion Object *
* Java 3D provides a rich set of wakeup criteria that Behavior * objects can use in specifying a complex WakeupCondition. These * wakeup criteria can cause Java 3D's behavior scheduler to invoke a * behavior's processStimulus method whenever * *
* A Behavior object constructs a WakeupCriterion by constructing the * appropriate criterion object. The Behavior object must provide the * appropriate arguments (usually a reference to some scene graph * object and possibly a region of interest). Thus, to specify a * WakeupOnViewPlatformEntry, a behavior would specify the region that * will cause the behavior to execute if an active ViewPlatform enters it. * *
* Note that a unique WakeupCriterion object must be used with each * instance of a Behavior. Sharing wakeup criteria among different * instances of a Behavior is illegal. * *
* Additional Information *
* For more information, see the * Introduction to the Java 3D API and * Behaviors and Interpolators * documents. * * @see WakeupCondition */ public abstract class Behavior extends Leaf { /** * Constructs a Behavior node with default parameters. The default * values are as follows: *
* This feature allows applications to send arbitrary events into the * behavior scheduler stream. It can be used as a notification scheme * for communicating events to behaviors in the system. *
* @param postId the Id being posted * * @see WakeupOnBehaviorPost */ public void postId(int postId){ ((BehaviorRetained)this.retained).postId(postId); } /** * Enables or disables this Behavior. The default state is enabled. * @param state true or false to enable or disable this Behavior */ public void setEnable(boolean state) { ((BehaviorRetained)this.retained).setEnable(state); } /** * Retrieves the state of the Behavior enable flag. * @return the Behavior enable state */ public boolean getEnable() { return ((BehaviorRetained)this.retained).getEnable(); } /** * Returns the number of scheduling intervals supported by this * implementation of Java 3D. The minimum number of supported * intervals must be at least 10. The default scheduling interval * for each behavior instance is set to *numSchedulingIntervals / 2.
*
* @return the number of supported scheduling intervals
*
* @since Java 3D 1.3
*/
public static int getNumSchedulingIntervals() {
return BehaviorRetained.NUM_SCHEDULING_INTERVALS;
}
/**
* Sets the scheduling interval of this Behavior node to the
* specified value.
*
* The scheduling interval defines a partial order of execution
* for behaviors that wake up in response to the same wakeup
* condition (that is, those behaviors that are processed at the
* same "time"). Given a set of behaviors whose wakeup conditions
* are satisfied at the same time, the behavior scheduler will
* execute all behaviors in a lower scheduling interval before
* executing any behavior in a higher scheduling interval. Within
* a scheduling interval, behaviors can be executed in any order,
* or in parallel. Note that this partial ordering is only
* guaranteed for those behaviors that wake up at the same time in
* response to the same wakeup condition, for example, the set of
* behaviors that wake up every frame in response to a
* WakeupOnElapsedFrames(0) wakeup condition.
*
* The default value is numSchedulingIntervals / 2.
*
* @param schedulingInterval the new scheduling interval
*
* @exception IllegalArgumentException if
* schedulingInterval < 0 or
* schedulingInterval >=
* numSchedulingIntervals
*
* @since Java 3D 1.3
*/
public void setSchedulingInterval(int schedulingInterval) {
if (schedulingInterval < 0 ||
schedulingInterval >= getNumSchedulingIntervals()) {
throw new IllegalStateException(J3dI18N.getString("Behavior1"));
}
((BehaviorRetained)this.retained).
setSchedulingInterval(schedulingInterval);
}
/**
* Retrieves the current scheduling interval of this Behavior
* node.
*
* @return the current scheduling interval
*
* @since Java 3D 1.3
*/
public int getSchedulingInterval() {
return ((BehaviorRetained)this.retained).getSchedulingInterval();
}
/**
* Returns the primary view associated with this behavior. This method
* is useful with certain types of behaviors (e.g., Billboard, LOD) that
* rely on per-View information and with behaviors in general in regards
* to scheduling (the distance from the view platform determines the
* active behaviors). The "primary" view is defined to be the first
* View attached to a live ViewPlatform, if there is more than one active
* View. So, for instance, Billboard behaviors would be oriented toward
* this primary view, in the case of multiple active views into the same
* scene graph.
*/
protected View getView() {
return ((BehaviorRetained)this.retained).getView();
}
/**
* Copies all Behavior information from
* originalNode into
* the current node. This method is called from the
* cloneNode method which is, in turn, called by the
* cloneTree method.
*
* @param originalNode the original node to duplicate
* @param forceDuplicate when set to true, causes the
* duplicateOnCloneTree flag to be ignored. When
* false, the value of each node's
* duplicateOnCloneTree variable determines whether
* NodeComponent data is duplicated or copied.
*
* @exception RestrictedAccessException if this object is part of a live
* or compiled scenegraph.
*
* @see Node#duplicateNode
* @see Node#cloneTree
* @see NodeComponent#setDuplicateOnCloneTree
*/
@Override
void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
super.duplicateAttributes(originalNode, forceDuplicate);
BehaviorRetained attr = (BehaviorRetained) originalNode.retained;
BehaviorRetained rt = (BehaviorRetained) retained;
rt.setEnable(attr.getEnable());
rt.setSchedulingBounds(attr.getSchedulingBounds());
rt.setSchedulingInterval(attr.getSchedulingInterval());
// will set to the correct one in updateNodeReferences
rt.setSchedulingBoundingLeaf(attr.getSchedulingBoundingLeaf());
}
/**
* Callback used to allow a node to check if any scene graph objects
* referenced
* by that node have been duplicated via a call to cloneTree.
* This method is called by cloneTree after all nodes in
* the sub-graph have been duplicated. The cloned Leaf node's method
* will be called and the Leaf node can then look up any object references
* by using the getNewObjectReference method found in the
* NodeReferenceTable object. If a match is found, a
* reference to the corresponding object in the newly cloned sub-graph
* is returned. If no corresponding reference is found, either a
* DanglingReferenceException is thrown or a reference to the original
* object is returned depending on the value of the
* allowDanglingReferences parameter passed in the
* cloneTree call.
*
* NOTE: Applications should not call this method directly.
* It should only be called by the cloneTree method.
*
* @param referenceTable a NodeReferenceTableObject that contains the
* getNewObjectReference method needed to search for
* new object instances.
*
* @see NodeReferenceTable
* @see Node#cloneTree
* @see DanglingReferenceException
*/
@Override
public void updateNodeReferences(NodeReferenceTable referenceTable) {
super.updateNodeReferences(referenceTable);
BehaviorRetained rt = (BehaviorRetained) retained;
BoundingLeaf bl= rt.getSchedulingBoundingLeaf();
// check for schedulingBoundingLeaf
if (bl != null) {
Object o = referenceTable.getNewObjectReference(bl);
rt.setSchedulingBoundingLeaf((BoundingLeaf) o);
}
}
}