📄 behaviorretained.java
字号:
/* * $RCSfile: BehaviorRetained.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Use is subject to license terms. * * $Revision: 1.5 $ * $Date: 2007/02/09 17:17:52 $ * $State: Exp $ */package javax.media.j3d;import java.util.ArrayList;/** * Behavior is an abstract class that contains the framework for all * behavioral components in Java 3D. */class BehaviorRetained extends LeafRetained { // These bitmasks are used to quickly tell what conditions this behavior // is waiting for. Currently BehaviorStructure only used 4 of them. static final int WAKEUP_ACTIVATE_INDEX = 0; static final int WAKEUP_DEACTIVATE_INDEX = 1; static final int WAKEUP_VP_ENTRY_INDEX = 2; static final int WAKEUP_VP_EXIT_INDEX = 3; static final int WAKEUP_TIME_INDEX = 4; static final int NUM_WAKEUPS = 5; static final int WAKEUP_ACTIVATE = 0x0001; static final int WAKEUP_DEACTIVATE = 0x0002; static final int WAKEUP_VP_ENTRY = 0x0004; static final int WAKEUP_VP_EXIT = 0x0008; static final int WAKEUP_TIME = 0x0010; /** * The number of scheduling intervals supported by this * implementation. This is fixed for a particular implementation * and must be at least 10. */ static final int NUM_SCHEDULING_INTERVALS = 10; // different types of IndexedUnorderedSet that use in BehaviorStructure static final int BEHAIVORS_IN_BS_LIST = 0; static final int SCHEDULE_IN_BS_LIST = 1; // total number of different IndexedUnorderedSet types static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2; /** * The Boundary object defining the behavior's scheduling region. */ Bounds schedulingRegion = null; /** * The bounding leaf reference */ BoundingLeafRetained boundingLeaf = null; /** * The current wakeup condition. */ WakeupCondition wakeupCondition = null; /** * This is the new WakeupCondition to be set in * initialize wakeupOn() */ WakeupCondition newWakeupCondition = null; /** * The current view platform for this behavior; this value is * false until it comes into range of a view platform. */ ViewPlatformRetained vp = null; /** * The current activation status for this behavior; this value * is false until it comes into range of a view platform. */ boolean active = false; /** * Flag indicating whether the behavior is enabled. */ boolean enable = true; /** * Current scheduling interval. */ int schedulingInterval = NUM_SCHEDULING_INTERVALS / 2; /** * This is a flag that tells the behavior scheduler whether the * user-programmed process stimulus called wakeupOn, if it did * not, then the wakeupCondition will be set to null. */ boolean conditionSet = false; /** * This is a flag that indicates whether we are in an initialize or * processStimulus callback. If wakeupOn is called for this behavior * when this flag is not set, an exception will be thrown. */ boolean inCallback = false; /** * This is a flag that indicates whether we are in initialize * callback. If wakeupOn is called for this behavior when * this flag is true, then its * buildTree() will delay until insert nodes message * is get. This is because some localToVworld[] that wakeup * depends may not initialize when this behavior setLive(). */ boolean inInitCallback = false; /** * The transformed schedulingRegion */ Bounds transformedRegion = null; // A bitmask that indicates that the scheduling region has changed. int isDirty = 0xffff; /** * A bitmask that represents all conditions that this behavior is waiting on. */ int wakeupMask = 0; /** * An array of ints that count how many of each wakup is present */ int[] wakeupArray = new int[NUM_WAKEUPS]; // use to post message when bounds change, always point to this Object targets[] = new Object[1]; BehaviorRetained() { this.nodeType = NodeRetained.BEHAVIOR; localBounds = new BoundingBox(); ((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0); ((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0); targets[0] = this; IndexedUnorderSet.init(this, TOTAL_INDEXED_UNORDER_SET_TYPES); } /** * Get the Behavior's scheduling region. * @return this Behavior's scheduling region information */ Bounds getSchedulingBounds() { Bounds b = null; if (schedulingRegion != null) { b = (Bounds) schedulingRegion.clone(); if (staticTransform != null) { Transform3D invTransform = staticTransform.getInvTransform(); b.transform(invTransform); } } return b; } /** * Set the Behavior's scheduling region. * @param region a region that contains the Behavior's new scheduling * bounds */ synchronized void setSchedulingBounds(Bounds region) { if (region != null) { schedulingRegion = (Bounds) region.clone(); if (staticTransform != null) { schedulingRegion.transform(staticTransform.transform); } } else { schedulingRegion = null; } if (source != null && source.isLive()) { sendMessage(J3dMessage.REGION_BOUND_CHANGED); } } /** * Set the Sound's scheduling region to the specified Leaf node. */ synchronized void setSchedulingBoundingLeaf(BoundingLeaf region) { if (source != null && source.isLive()) { if (boundingLeaf != null) boundingLeaf.mirrorBoundingLeaf.removeUser(this); } if (region != null) { boundingLeaf = (BoundingLeafRetained)region.retained; } else { boundingLeaf = null; } if (source != null && source.isLive()) { if (boundingLeaf != null) boundingLeaf.mirrorBoundingLeaf.addUser(this); sendMessage(J3dMessage.REGION_BOUND_CHANGED); } } /** * Enables or disables this Behavior. The default state is enabled. * @param state true or false to enable or disable this Behavior */ void setEnable(boolean state) { if (enable != state) { enable = state; if (source != null && source.isLive()) { sendMessage(state ? J3dMessage.BEHAVIOR_ENABLE: J3dMessage.BEHAVIOR_DISABLE); } } } /** * Retrieves the state of the Behavior enable flag. * @return the Behavior enable state */ boolean getEnable() { return enable; } /** * Sets the scheduling interval of this Behavior node to the * specified value. * @param schedulingInterval the new scheduling interval */ void setSchedulingInterval(int schedulingInterval) { if ((source != null) && source.isLive() && !inCallback) { // avoid MT safe problem when user thread setting // this while behavior scheduling using this. sendMessage(J3dMessage.SCHEDULING_INTERVAL_CHANGED, new Integer(schedulingInterval)); } else { // garantee this setting reflect in next frame this.schedulingInterval = schedulingInterval; } } /** * Retrieves the current scheduling interval of this Behavior * node. * * @return the current scheduling interval */ int getSchedulingInterval() { return schedulingInterval; } /** * Get the Behavior's scheduling region */ BoundingLeaf getSchedulingBoundingLeaf() { return (boundingLeaf != null ? (BoundingLeaf)boundingLeaf.source : null); } /** * This setLive routine first calls the superclass's method, then * it activates all canvases that are associated with the attached * view. */ synchronized void setLive(SetLiveState s) { super.doSetLive(s); if (inBackgroundGroup) { throw new IllegalSceneGraphException(J3dI18N.getString("BehaviorRetained0")); } if (inSharedGroup) { throw new IllegalSharingException(J3dI18N.getString("BehaviorRetained1")); } s.nodeList.add(this); s.behaviorNodes.add(this); s.notifyThreads |= J3dThread.UPDATE_BEHAVIOR; // process switch leaf if (s.switchTargets != null && s.switchTargets[0] != null) { s.switchTargets[0].addNode(this, Targets.BEH_TARGETS); } switchState = (SwitchState)s.switchStates.get(0); if (boundingLeaf != null) { boundingLeaf.mirrorBoundingLeaf.addUser(this); } if (s.transformTargets != null && s.transformTargets[0] != null) { s.transformTargets[0].addNode(this, Targets.BEH_TARGETS); s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; } super.markAsLive(); } /** * This clearLive routine first calls the superclass's method, then * it deactivates all canvases that are associated with the attached * view. */ synchronized void clearLive(SetLiveState s) { super.clearLive(s); s.nodeList.add(this); if (s.transformTargets != null && s.transformTargets[0] != null) { s.transformTargets[0].addNode(this, Targets.BEH_TARGETS); s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; } s.notifyThreads |= J3dThread.UPDATE_BEHAVIOR; if (s.switchTargets != null && s.switchTargets[0] != null) { s.switchTargets[0].addNode(this, Targets.BEH_TARGETS); } if (boundingLeaf != null) { boundingLeaf.mirrorBoundingLeaf.removeUser(this); } // BehaviorStructure removeBehavior() will do the // wakeupCondition.cleanTree() over there. } /** * This routine execute the user's initialize method */ void executeInitialize() { synchronized (this) { boolean inCallbackSaved = inCallback; boolean inInitCallbackSaved = inInitCallback; inCallback = true; inInitCallback = true; try { ((Behavior)this.source).initialize(); } catch (RuntimeException e) { System.err.println("Exception occurred during Behavior initialization:"); e.printStackTrace(); } catch (Error e) { // Issue 264 - catch Error System.err.println("Error occurred during Behavior initialization:"); e.printStackTrace(); } inCallback = inCallbackSaved; inInitCallback = inInitCallbackSaved; } } /** * Defines this behavior's wakeup criteria. * @param criteria The wakeup criterion for this object */ void wakeupOn(WakeupCondition criteria) { // If not call by initialize(), buildTree will // delay until insertNodes in BehaviorStructure // Otherwise BehaviorScheduler will invoke // handleLastWakeupOn() if (criteria == null) { throw new NullPointerException(J3dI18N.getString("BehaviorRetained2")); } if (!inInitCallback) { conditionSet = true; wakeupCondition = criteria; } else { // delay setting wakeup condition in BehaviorStructure // activateBehaviors(). This is because there may have // previously wakeupCondition attach to it and // scheduling even after clearLive() due to message // delay processing. It is not MT safe to set it // in user thread. newWakeupCondition = criteria; } } // The above wakeupOn() just remember the reference // We only need to handle (and ignore the rest) the // last wakeupOn() condition set in the behavior. // This handle the case when multiple wakeupOn() // are invoked in the same processStimulus() void handleLastWakeupOn(WakeupCondition prevWakeupCond, BehaviorStructure bs) { if (bs == universe.behaviorStructure) { if (wakeupCondition == prevWakeupCond) { // reuse the same wakeupCondition wakeupCondition.resetTree(); } else { if (prevWakeupCond != null) { prevWakeupCond.cleanTree(bs); } wakeupCondition.buildTree(null, 0, this); } } else { // No need to do prevWakeupCond.cleanTree(bs) // since removeBehavior() will do so } } /** * Returns this behavior's wakeup criteria. * @return criteria The wakeup criteria of this object */ WakeupCondition getWakeupCondition() { return wakeupCondition; } /** * Post the specified Id. Behaviors use this method to cause sequential * scheduling of other behavior object. * @param postId The Id being posted */ void postId(int postId){ if (source != null && source.isLive()) { universe.behaviorStructure.handleBehaviorPost((Behavior) source, postId); } } protected View getView() { return (universe != null ? universe.getCurrentView() : null); } synchronized void updateTransformRegion(Bounds bound) { if (boundingLeaf == null) { updateTransformRegion(); } else { if (bound == null) { transformedRegion = null; } else { transformedRegion = (Bounds) bound.clone(); transformedRegion.transform( boundingLeaf.mirrorBoundingLeaf.getCurrentLocalToVworld()); } } } synchronized void updateTransformRegion() { if (boundingLeaf == null || !boundingLeaf.mirrorBoundingLeaf.switchState.currentSwitchOn) { if (schedulingRegion == null) { transformedRegion = null; } else { // use schedulingRegion if (transformedRegion != null) { transformedRegion.set(schedulingRegion); } else { transformedRegion = (Bounds) schedulingRegion.clone(); } transformedRegion.transform(getCurrentLocalToVworld()); } } else { // use boundingLeaf transformedRegion = boundingLeaf.mirrorBoundingLeaf.transformedRegion; } } // Note: This routine will only to update the object's // transformed region void updateBoundingLeaf(long refTime) { transformedRegion = (Bounds)boundingLeaf.mirrorBoundingLeaf.transformedRegion; } void addWakeupCondition() {} final void sendMessage(int mtype, Object arg) { J3dMessage createMessage = new J3dMessage(); createMessage.threads = J3dThread.UPDATE_BEHAVIOR; createMessage.type = mtype; createMessage.universe = universe; createMessage.args[0] = targets; createMessage.args[1]= this; createMessage.args[2]= arg; VirtualUniverse.mc.processMessage(createMessage); } final void sendMessage(int mtype) { sendMessage(mtype, null); } void mergeTransform(TransformGroupRetained xform) { super.mergeTransform(xform); if (schedulingRegion != null) { schedulingRegion.transform(xform.transform); } if (source instanceof DistanceLOD) { ((DistanceLOD)source).mergeTransform(xform); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -