001: /*
002: * $RCSfile: Behavior.java,v $
003: *
004: * Copyright 1996-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:19 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.Enumeration;
035:
036: /**
037: * The Behavior leaf node provides a framework for adding user-defined
038: * actions into the scene graph. Behavior is an abstract class that
039: * defines two methods that must be overridden by a subclass: An
040: * <code>initialization</code> method, called once when the behavior
041: * becomes "live," and a <code>processStimulus</code> method called
042: * whenever appropriate by the Java 3D behavior scheduler. The
043: * Behavior node also contains an enable flag, a scheduling region,
044: * a scheduling interval, and a wakeup condition.
045: *
046: * <P>
047: * The <i>scheduling region</i> defines a spatial volume that serves
048: * to enable the scheduling of Behavior nodes. A Behavior node is
049: * <i>active</i> (can receive stimuli) whenever an active ViewPlatform's
050: * activation volume intersects a Behavior object's scheduling
051: * region. Only active behaviors can receive stimuli.
052: *
053: * <P>
054: * The <i>scheduling interval</i> defines a partial order of execution
055: * for behaviors that wake up in response to the same wakeup condition
056: * (that is, those behaviors that are processed at the same "time").
057: * Given a set of behaviors whose wakeup conditions are satisfied at
058: * the same time, the behavior scheduler will execute all behaviors in
059: * a lower scheduling interval before executing any behavior in a
060: * higher scheduling interval. Within a scheduling interval,
061: * behaviors can be executed in any order, or in parallel. Note that
062: * this partial ordering is only guaranteed for those behaviors that
063: * wake up at the same time in response to the same wakeup condition,
064: * for example, the set of behaviors that wake up every frame in
065: * response to a WakeupOnElapsedFrames(0) wakeup condition.
066: *
067: * <P>
068: * The <code>initialize</code> method allows a Behavior object to
069: * initialize its internal state and specify its initial wakeup
070: * condition(s). Java 3D invokes a behavior's initialize code when the
071: * behavior's containing BranchGroup node is added to the virtual
072: * universe. Java 3D does not invoke the initialize method in a new
073: * thread. Thus, for Java 3D to regain control, the initialize method
074: * must not execute an infinite loop; it must return. Furthermore, a
075: * wakeup condition must be set or else the behavior's processStimulus
076: * method is never executed.
077: *
078: * <P>
079: * The <code>processStimulus</code> method receives and processes a
080: * behavior's ongoing messages. The Java 3D behavior scheduler invokes
081: * a Behavior node's processStimulus method when an active ViewPlatform's
082: * activation volume intersects a Behavior object's scheduling region
083: * and all of that behavior's wakeup criteria are satisfied. The
084: * processStimulus method performs its computations and actions
085: * (possibly including the registration of state change information
086: * that could cause Java 3D to wake other Behavior objects),
087: * establishes its next wakeup condition, and finally exits.
088: * A typical behavior will modify one or more nodes or node components
089: * in the scene graph. These modifications can happen in parallel
090: * with rendering. In general, applications cannot count on behavior
091: * execution being synchronized with rendering. There are two
092: * exceptions to this general rule:
093: * <ol>
094: * <li>All modifications to scene graph objects (not including geometry
095: * by-reference or texture by-reference) made from the
096: * <code>processStimulus</code> method of a single behavior instance
097: * are guaranteed to take effect in the same rendering frame.</li>
098: * <li>All modifications to scene graph objects (not including geometry
099: * by-reference or texture by-reference) made from the
100: * <code>processStimulus</code> methods of the set of behaviors that
101: * wake up in response to a WakeupOnElapsedFrames(0) wakeup condition
102: * are guaranteed to take effect in the same rendering frame.</li>
103: * </ol>
104: *
105: * Note that modifications to geometry by-reference or texture
106: * by-reference are not guaranteed to show up in the same frame as
107: * other scene graph changes.
108: *
109: * <P>
110: * <b>Code Structure</b>
111: * <P>
112: * When the Java 3D behavior scheduler invokes a Behavior object's
113: * processStimulus method, that method may perform any computation it
114: * wishes. Usually, it will change its internal state and specify its
115: * new wakeup conditions. Most probably, it will manipulate scene
116: * graph elements. However, the behavior code can only change those
117: * aspects of a scene graph element permitted by the capabilities
118: * associated with that scene graph element. A scene graph's
119: * capabilities restrict behavioral manipulation to those
120: * manipulations explicitly allowed.
121: *
122: * <P>
123: * The application must provide the Behavior object with references to
124: * those scene graph elements that the Behavior object will
125: * manipulate. The application provides those references as arguments
126: * to the behavior's constructor when it creates the Behavior
127: * object. Alternatively, the Behavior object itself can obtain access
128: * to the relevant scene graph elements either when Java 3D invokes
129: * its initialize method or each time Java 3D invokes its
130: * processStimulus method.
131: *
132: * <P>
133: * Behavior methods have a very rigid structure. Java 3D assumes that
134: * they always run to completion (if needed, they can spawn
135: * threads). Each method's basic structure consists of the following:
136: *
137: * <P>
138: * <UL>
139: * <LI>Code to decode and extract references from the WakeupCondition
140: * enumeration that caused the object's awakening.</LI>
141: * <LI>Code to perform the manipulations associated with the
142: * WakeupCondition</LI>
143: * <LI>Code to establish this behavior's new WakeupCondition</LI>
144: * <LI>A path to Exit (so that execution returns to the Java 3D
145: * behavior scheduler)</LI>
146: * </UL>
147: *
148: * <P>
149: * <b>WakeupCondition Object</b>
150: * <P>
151: * A WakeupCondition object is an abstract class specialized to
152: * fourteen different WakeupCriterion objects and to four combining
153: * objects containing multiple WakeupCriterion objects. A Behavior
154: * node provides the Java 3D behavior scheduler with a WakeupCondition
155: * object. When that object's WakeupCondition has been satisfied, the
156: * behavior scheduler hands that same WakeupCondition back to the
157: * Behavior via an enumeration.
158: *
159: * <P>
160: * <b>WakeupCriterion Object</b>
161: * <P>
162: * Java 3D provides a rich set of wakeup criteria that Behavior
163: * objects can use in specifying a complex WakeupCondition. These
164: * wakeup criteria can cause Java 3D's behavior scheduler to invoke a
165: * behavior's processStimulus method whenever
166: *
167: * <UL>
168: * <LI>The center of a ViewPlatform enters a specified region</LI>
169: * <LI>The center of a ViewPlatform exits a specified region</LI>
170: * <LI>A behavior is activated</LI>
171: * <LI>A behavior is deactivated</LI>
172: * <LI>A specified TransformGroup node's transform changes</LI>
173: * <LI>Collision is detected between a specified Shape3D node's
174: * Geometry object and any other object</LI>
175: * <LI>Movement occurs between a specified Shape3D node's Geometry
176: * object and any other object with which it collides</LI>
177: * <LI>A specified Shape3D node's Geometry object no longer collides
178: * with any other object</LI>
179: * <LI>A specified Behavior object posts a specific event</LI>
180: * <LI>A specified AWT event occurs</LI>
181: * <LI>A specified time interval elapses</LI>
182: * <LI>A specified number of frames have been drawn</LI>
183: * <LI>The center of a specified Sensor enters a specified region</LI>
184: * <LI>The center of a specified Sensor exits a specified region</LI>
185: * </UL>
186: *
187: * <p>
188: * A Behavior object constructs a WakeupCriterion by constructing the
189: * appropriate criterion object. The Behavior object must provide the
190: * appropriate arguments (usually a reference to some scene graph
191: * object and possibly a region of interest). Thus, to specify a
192: * WakeupOnViewPlatformEntry, a behavior would specify the region that
193: * will cause the behavior to execute if an active ViewPlatform enters it.
194: *
195: * <p>
196: * Note that a unique WakeupCriterion object must be used with each
197: * instance of a Behavior. Sharing wakeup criteria among different
198: * instances of a Behavior is illegal.
199: *
200: * <p>
201: * <b>Additional Information</b>
202: * <p>
203: * For more information, see the
204: * <a href="doc-files/intro.html">Introduction to the Java 3D API</a> and
205: * <a href="doc-files/Behaviors.html">Behaviors and Interpolators</a>
206: * documents.
207: *
208: * @see WakeupCondition
209: */
210:
211: public abstract class Behavior extends Leaf {
212:
213: /**
214: * Constructs a Behavior node with default parameters. The default
215: * values are as follows:
216: * <ul>
217: * enable flag : true<br>
218: * scheduling bounds : null<br>
219: * scheduling bounding leaf : null<br>
220: * scheduling interval : numSchedulingIntervals / 2<br>
221: * </ul>
222: */
223: public Behavior() {
224: }
225:
226: /**
227: * Initialize this behavior. Classes that extend Behavior must
228: * provide their own initialize method.
229: * <br>
230: * NOTE: Applications should <i>not</i> call this method. It is called
231: * by the Java 3D behavior scheduler.
232: */
233: public abstract void initialize();
234:
235: /**
236: * Process a stimulus meant for this behavior. This method is invoked
237: * if the Behavior's wakeup criteria are satisfied and an active
238: * ViewPlatform's
239: * activation volume intersects with the Behavior's scheduling region.
240: * Classes that extend Behavior must provide their own processStimulus
241: * method.
242: * <br>
243: * NOTE: Applications should <i>not</i> call this method. It is called
244: * by the Java 3D behavior scheduler.
245: * @param criteria an enumeration of triggered wakeup criteria for this
246: * behavior
247: */
248: public abstract void processStimulus(Enumeration criteria);
249:
250: /**
251: * Set the Behavior's scheduling region to the specified bounds.
252: * This is used when the scheduling bounding leaf is set to null.
253: * @param region the bounds that contains the Behavior's new scheduling
254: * region
255: */
256: public void setSchedulingBounds(Bounds region) {
257: ((BehaviorRetained) this .retained).setSchedulingBounds(region);
258: }
259:
260: /**
261: * Retrieves the Behavior node's scheduling bounds.
262: * @return this Behavior's scheduling bounds information
263: */
264: public Bounds getSchedulingBounds() {
265: return ((BehaviorRetained) this .retained).getSchedulingBounds();
266: }
267:
268: /**
269: * Set the Behavior's scheduling region to the specified bounding leaf.
270: * When set to a value other than null, this overrides the scheduling
271: * bounds object.
272: * @param region the bounding leaf node used to specify the Behavior
273: * node's new scheduling region
274: */
275: public void setSchedulingBoundingLeaf(BoundingLeaf region) {
276: ((BehaviorRetained) this .retained)
277: .setSchedulingBoundingLeaf(region);
278: }
279:
280: /**
281: * Retrieves the Behavior node's scheduling bounding leaf.
282: * @return this Behavior's scheduling bounding leaf information
283: */
284: public BoundingLeaf getSchedulingBoundingLeaf() {
285: return ((BehaviorRetained) this .retained)
286: .getSchedulingBoundingLeaf();
287: }
288:
289: /**
290: * Creates the retained mode BehaviorRetained object that this
291: * Behavior object will point to.
292: */
293: void createRetained() {
294: this .retained = new BehaviorRetained();
295: this .retained.setSource(this );
296: }
297:
298: /**
299: * Defines this behavior's wakeup criteria. This method
300: * may only be called from a Behavior object's initialize
301: * or processStimulus methods to (re)arm the next wakeup.
302: * It should be the last thing done by those methods.
303: * @param criteria the wakeup criteria for this behavior
304: * @exception IllegalStateException if this method is called by
305: * a method <i>other than</i> initialize or processStimulus
306: */
307: protected void wakeupOn(WakeupCondition criteria) {
308: BehaviorRetained behavret = (BehaviorRetained) this .retained;
309: synchronized (behavret) {
310: if (!behavret.inCallback) {
311: throw new IllegalStateException(J3dI18N
312: .getString("Behavior0"));
313: }
314: }
315: behavret.wakeupOn(criteria);
316: }
317:
318: /**
319: * Retrieves this behavior's current wakeup condition as set by
320: * the wakeupOn method. If no wakeup condition is currently
321: * active, null will be returned. In particular, this means that
322: * null will be returned if Java 3D is executing this behavior's
323: * processStimulus routine and wakeupOn has not yet been called to
324: * re-arm the wakeup condition for next time.
325: *
326: * @return the current wakeup condition for this behavior
327: *
328: * @since Java 3D 1.3
329: */
330: protected WakeupCondition getWakeupCondition() {
331: return ((BehaviorRetained) this .retained).getWakeupCondition();
332: }
333:
334: /**
335: * Posts the specified postId to the Behavior Scheduler. All behaviors
336: * that have registered WakeupOnBehaviorPost with this postId, or a postId
337: * of 0, and with this behavior, or a null behavior, will have that wakeup
338: * condition met.
339: * <p>
340: * This feature allows applications to send arbitrary events into the
341: * behavior scheduler stream. It can be used as a notification scheme
342: * for communicating events to behaviors in the system.
343: * </p>
344: * @param postId the Id being posted
345: *
346: * @see WakeupOnBehaviorPost
347: */
348: public void postId(int postId) {
349: ((BehaviorRetained) this .retained).postId(postId);
350: }
351:
352: /**
353: * Enables or disables this Behavior. The default state is enabled.
354: * @param state true or false to enable or disable this Behavior
355: */
356: public void setEnable(boolean state) {
357: ((BehaviorRetained) this .retained).setEnable(state);
358: }
359:
360: /**
361: * Retrieves the state of the Behavior enable flag.
362: * @return the Behavior enable state
363: */
364: public boolean getEnable() {
365: return ((BehaviorRetained) this .retained).getEnable();
366: }
367:
368: /**
369: * Returns the number of scheduling intervals supported by this
370: * implementation of Java 3D. The minimum number of supported
371: * intervals must be at least 10. The default scheduling interval
372: * for each behavior instance is set to
373: * <code>numSchedulingIntervals / 2</code>.
374: *
375: * @return the number of supported scheduling intervals
376: *
377: * @since Java 3D 1.3
378: */
379: public static int getNumSchedulingIntervals() {
380: return BehaviorRetained.NUM_SCHEDULING_INTERVALS;
381: }
382:
383: /**
384: * Sets the scheduling interval of this Behavior node to the
385: * specified value.
386: *
387: * The scheduling interval defines a partial order of execution
388: * for behaviors that wake up in response to the same wakeup
389: * condition (that is, those behaviors that are processed at the
390: * same "time"). Given a set of behaviors whose wakeup conditions
391: * are satisfied at the same time, the behavior scheduler will
392: * execute all behaviors in a lower scheduling interval before
393: * executing any behavior in a higher scheduling interval. Within
394: * a scheduling interval, behaviors can be executed in any order,
395: * or in parallel. Note that this partial ordering is only
396: * guaranteed for those behaviors that wake up at the same time in
397: * response to the same wakeup condition, for example, the set of
398: * behaviors that wake up every frame in response to a
399: * WakeupOnElapsedFrames(0) wakeup condition.
400: *
401: * The default value is <code>numSchedulingIntervals / 2</code>.
402: *
403: * @param schedulingInterval the new scheduling interval
404: *
405: * @exception IllegalArgumentException if
406: * <code>schedulingInterval</code> < 0 or
407: * <code>schedulingInterval</code> >=
408: * <code>numSchedulingIntervals</code>
409: *
410: * @since Java 3D 1.3
411: */
412: public void setSchedulingInterval(int schedulingInterval) {
413: if (schedulingInterval < 0
414: || schedulingInterval >= getNumSchedulingIntervals()) {
415:
416: throw new IllegalStateException(J3dI18N
417: .getString("Behavior1"));
418: }
419:
420: ((BehaviorRetained) this .retained)
421: .setSchedulingInterval(schedulingInterval);
422: }
423:
424: /**
425: * Retrieves the current scheduling interval of this Behavior
426: * node.
427: *
428: * @return the current scheduling interval
429: *
430: * @since Java 3D 1.3
431: */
432: public int getSchedulingInterval() {
433: return ((BehaviorRetained) this .retained)
434: .getSchedulingInterval();
435: }
436:
437: /**
438: * Returns the primary view associated with this behavior. This method
439: * is useful with certain types of behaviors (e.g., Billboard, LOD) that
440: * rely on per-View information and with behaviors in general in regards
441: * to scheduling (the distance from the view platform determines the
442: * active behaviors). The "primary" view is defined to be the first
443: * View attached to a live ViewPlatform, if there is more than one active
444: * View. So, for instance, Billboard behaviors would be oriented toward
445: * this primary view, in the case of multiple active views into the same
446: * scene graph.
447: */
448: protected View getView() {
449: return ((BehaviorRetained) this .retained).getView();
450: }
451:
452: /**
453: * Copies all Behavior information from
454: * <code>originalNode</code> into
455: * the current node. This method is called from the
456: * <code>cloneNode</code> method which is, in turn, called by the
457: * <code>cloneTree</code> method.<P>
458: *
459: * @param originalNode the original node to duplicate
460: * @param forceDuplicate when set to <code>true</code>, causes the
461: * <code>duplicateOnCloneTree</code> flag to be ignored. When
462: * <code>false</code>, the value of each node's
463: * <code>duplicateOnCloneTree</code> variable determines whether
464: * NodeComponent data is duplicated or copied.
465: *
466: * @exception RestrictedAccessException if this object is part of a live
467: * or compiled scenegraph.
468: *
469: * @see Node#duplicateNode
470: * @see Node#cloneTree
471: * @see NodeComponent#setDuplicateOnCloneTree
472: */
473: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
474: super .duplicateAttributes(originalNode, forceDuplicate);
475:
476: BehaviorRetained attr = (BehaviorRetained) originalNode.retained;
477: BehaviorRetained rt = (BehaviorRetained) retained;
478:
479: rt.setEnable(attr.getEnable());
480: rt.setSchedulingBounds(attr.getSchedulingBounds());
481: rt.setSchedulingInterval(attr.getSchedulingInterval());
482: // will set to the correct one in updateNodeReferences
483: rt.setSchedulingBoundingLeaf(attr.getSchedulingBoundingLeaf());
484:
485: }
486:
487: /**
488: * Callback used to allow a node to check if any scene graph objects
489: * referenced
490: * by that node have been duplicated via a call to <code>cloneTree</code>.
491: * This method is called by <code>cloneTree</code> after all nodes in
492: * the sub-graph have been duplicated. The cloned Leaf node's method
493: * will be called and the Leaf node can then look up any object references
494: * by using the <code>getNewObjectReference</code> method found in the
495: * <code>NodeReferenceTable</code> object. If a match is found, a
496: * reference to the corresponding object in the newly cloned sub-graph
497: * is returned. If no corresponding reference is found, either a
498: * DanglingReferenceException is thrown or a reference to the original
499: * object is returned depending on the value of the
500: * <code>allowDanglingReferences</code> parameter passed in the
501: * <code>cloneTree</code> call.
502: * <p>
503: * NOTE: Applications should <i>not</i> call this method directly.
504: * It should only be called by the cloneTree method.
505: *
506: * @param referenceTable a NodeReferenceTableObject that contains the
507: * <code>getNewObjectReference</code> method needed to search for
508: * new object instances.
509: *
510: * @see NodeReferenceTable
511: * @see Node#cloneTree
512: * @see DanglingReferenceException
513: */
514: public void updateNodeReferences(NodeReferenceTable referenceTable) {
515: super .updateNodeReferences(referenceTable);
516:
517: BehaviorRetained rt = (BehaviorRetained) retained;
518: BoundingLeaf bl = rt.getSchedulingBoundingLeaf();
519:
520: // check for schedulingBoundingLeaf
521: if (bl != null) {
522: Object o = referenceTable.getNewObjectReference(bl);
523: rt.setSchedulingBoundingLeaf((BoundingLeaf) o);
524:
525: }
526: }
527:
528: }
|