001: /*
002: * $RCSfile: WakeupOnCollisionExit.java,v $
003: *
004: * Copyright 1997-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.5 $
028: * $Date: 2008/02/28 20:17:33 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.*;
035:
036: /**
037: * Class specifying a wakeup when the specified object
038: * no longer collides with any other object in the scene graph.
039: */
040: public final class WakeupOnCollisionExit extends WakeupCriterion {
041:
042: // different types of WakeupIndexedList that use in GeometryStructure
043: static final int COND_IN_GS_LIST = 0;
044: static final int COLLIDEEXIT_IN_BS_LIST = 1;
045:
046: // total number of different IndexedUnorderedSet types
047: static final int TOTAL_INDEXED_UNORDER_SET_TYPES = 2;
048:
049: /**
050: * Use geometry in computing collisions.
051: */
052: public static final int USE_GEOMETRY = WakeupOnCollisionEntry.USE_GEOMETRY;
053:
054: /**
055: * Use geometric bounds as an approximation in computing collisions.
056: */
057: public static final int USE_BOUNDS = WakeupOnCollisionEntry.USE_BOUNDS;
058:
059: /**
060: * Accuracy mode one of USE_GEOMETRY or USE_BOUNDS
061: */
062: int accuracyMode;
063:
064: // Cached the arming Node being used when it is not BOUND
065: NodeRetained armingNode;
066:
067: // A transformed Bounds of Group/Bounds
068: // use by BOUND, GROUP
069: Bounds vwcBounds;
070:
071: // use by GROUP to cache local bounds
072: Bounds localBounds = null;
073:
074: // Use by BoundingLeaf, point to mirror BoundingLeaf
075: // transformedRegion under this leaf is used.
076: BoundingLeafRetained boundingLeaf = null;
077:
078: /**
079: * Geometry atoms that this wakeup condition refer to.
080: * Only use by SHAPE, MORPH, GROUP, ORIENTEDSHAPE
081: */
082: UnorderList geometryAtoms = null;
083:
084: // one of GROUP, BOUNDINGLEAF, SHAPE, MORPH, BOUND
085: int nodeType;
086:
087: SceneGraphPath armingPath = null;
088: Bounds armingBounds = null;
089:
090: // the following two references are set only after a collision
091: // has occurred
092: SceneGraphPath collidingPath = null;
093: Bounds collidingBounds = null;
094:
095: /**
096: * Constructs a new WakeupOnCollisionExit criterion.
097: * @param armingPath the path used to <em>arm</em> collision
098: * detection
099: * @exception IllegalArgumentException if object associated with the
100: * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node.
101: */
102: public WakeupOnCollisionExit(SceneGraphPath armingPath) {
103: this (armingPath, USE_BOUNDS);
104: }
105:
106: /**
107: * Constructs a new WakeupOnCollisionExit criterion.
108: * @param armingPath the path used to <em>arm</em> collision
109: * detection
110: * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how
111: * accurately Java 3D will perform collision detection
112: * @exception IllegalArgumentException if hint is not one of
113: * USE_GEOMETRY or USE_BOUNDS.
114: * @exception IllegalArgumentException if object associated with the
115: * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node.
116: */
117: public WakeupOnCollisionExit(SceneGraphPath armingPath,
118: int speedHint) {
119: this (new SceneGraphPath(armingPath), speedHint, null);
120: }
121:
122: /**
123: * Constructs a new WakeupOnCollisionExit criterion.
124: * @param armingNode the Group, Shape, or Morph node used to
125: * <em>arm</em> collision detection
126: * @exception IllegalArgumentException if object is under a
127: * SharedGroup node or object is other than a Group, Shape3D,
128: * Morph or BoundingLeaf node.
129: */
130: public WakeupOnCollisionExit(Node armingNode) {
131: this (armingNode, USE_BOUNDS);
132: }
133:
134: /**
135: * Constructs a new WakeupOnCollisionExit criterion.
136: * @param armingNode the Group, Shape, or Morph node used to
137: * <em>arm</em> collision detection
138: * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how
139: * accurately Java 3D will perform collision detection
140: * @exception IllegalArgumentException if hint is not one of
141: * USE_GEOMETRY or USE_BOUNDS.
142: * @exception IllegalArgumentException if object is under a
143: * SharedGroup node or object is other than a Group, Shape3D,
144: * Morph or BoundingLeaf node.
145: */
146: public WakeupOnCollisionExit(Node armingNode, int speedHint) {
147: this (new SceneGraphPath(null, armingNode), speedHint, null);
148: }
149:
150: /**
151: * Constructs a new WakeupOnCollisionExit criterion.
152: * @param armingBounds the bounds object used to <em>arm</em> collision
153: * detection
154: */
155: public WakeupOnCollisionExit(Bounds armingBounds) {
156: this (null, USE_BOUNDS, (Bounds) armingBounds.clone());
157: }
158:
159: /**
160: * Constructs a new WakeupOnCollisionExit criterion.
161: * @param armingPath the path used to <em>arm</em> collision
162: * detection
163: * @param speedHint one of USE_GEOMETRY or USE_BOUNDS, specifies how
164: * accurately Java 3D will perform collision detection
165: * @param armingBounds the bounds object used to <em>arm</em> collision
166: * detection
167: * @exception IllegalArgumentException if hint is not one of
168: * USE_GEOMETRY or USE_BOUNDS.
169: * @exception IllegalArgumentException if object associated with the
170: * SceneGraphPath is other than a Group, Shape3D, Morph, or BoundingLeaf node.
171: */
172: WakeupOnCollisionExit(SceneGraphPath armingPath, int speedHint,
173: Bounds armingBounds) {
174: if (armingPath != null) {
175: this .armingNode = (NodeRetained) armingPath.getObject().retained;
176: nodeType = WakeupOnCollisionEntry.getNodeType(armingNode,
177: armingPath, "WakeupOnCollisionExit");
178: this .armingPath = armingPath;
179: WakeupOnCollisionEntry.validateSpeedHint(speedHint,
180: "WakeupOnCollisionExit4");
181: } else {
182: this .armingBounds = armingBounds;
183: nodeType = WakeupOnCollisionEntry.BOUND;
184: }
185: accuracyMode = speedHint;
186: WakeupIndexedList.init(this , TOTAL_INDEXED_UNORDER_SET_TYPES);
187: }
188:
189: /**
190: * Returns the path used in specifying the collision condition.
191: * @return the SceneGraphPath object generated when arming this
192: * criterion---null implies that a bounds object armed this criteria
193: */
194: public SceneGraphPath getArmingPath() {
195: return (armingPath != null ? new SceneGraphPath(armingPath)
196: : null);
197: }
198:
199: /**
200: * Returns the bounds object used in specifying the collision condition.
201: * @return the Bounds object generated when arming this
202: * criterion---null implies that a SceneGraphPath armed this criteria
203: */
204: public Bounds getArmingBounds() {
205: return (armingBounds != null ? (Bounds) armingBounds.clone()
206: : null);
207: }
208:
209: /**
210: * Retrieves the path describing the object causing the collision.
211: * @return the SceneGraphPath that describes the triggering object.
212: * @exception IllegalStateException if not called from within the
213: * a behavior's processStimulus method which was awoken by a collision.
214: */
215: public SceneGraphPath getTriggeringPath() {
216: if (behav == null) {
217: throw new IllegalStateException(J3dI18N
218: .getString("WakeupOnCollisionExit5"));
219: }
220:
221: synchronized (behav) {
222: if (!behav.inCallback) {
223: throw new IllegalStateException(J3dI18N
224: .getString("WakeupOnCollisionExit5"));
225: }
226: }
227: return (collidingPath != null ? new SceneGraphPath(
228: collidingPath) : null);
229: }
230:
231: /**
232: * Retrieves the Bounds object that caused the collision
233: * @return the colliding Bounds object.
234: * @exception IllegalStateException if not called from within the
235: * a behavior's processStimulus method which was awoken by a collision.
236: */
237: public Bounds getTriggeringBounds() {
238: if (behav == null) {
239: throw new IllegalStateException(J3dI18N
240: .getString("WakeupOnCollisionExit6"));
241: }
242:
243: synchronized (behav) {
244: if (!behav.inCallback) {
245: throw new IllegalStateException(J3dI18N
246: .getString("WakeupOnCollisionExit6"));
247: }
248: }
249: return (collidingBounds != null ? (Bounds) (collidingBounds
250: .clone()) : null);
251: }
252:
253: /**
254: * This is a callback from BehaviorStructure. It is
255: * used to add wakeupCondition to behavior structure.
256: */
257: void addBehaviorCondition(BehaviorStructure bs) {
258:
259: switch (nodeType) {
260: case WakeupOnCollisionEntry.SHAPE: // Use geometryAtoms[].collisionBounds
261: case WakeupOnCollisionEntry.ORIENTEDSHAPE3D:
262: if (!armingNode.source.isLive()) {
263: return;
264: }
265: if (geometryAtoms == null) {
266: geometryAtoms = new UnorderList(1, GeometryAtom.class);
267: }
268: Shape3DRetained shape = (Shape3DRetained) armingNode;
269: geometryAtoms.add(Shape3DRetained.getGeomAtom(shape
270: .getMirrorShape(armingPath)));
271: break;
272: case WakeupOnCollisionEntry.MORPH: // Use geometryAtoms[].collisionBounds
273: if (!armingNode.source.isLive()) {
274: return;
275: }
276: if (geometryAtoms == null) {
277: geometryAtoms = new UnorderList(1, GeometryAtom.class);
278: }
279: MorphRetained morph = (MorphRetained) armingNode;
280: geometryAtoms.add(Shape3DRetained.getGeomAtom(morph
281: .getMirrorShape(armingPath)));
282: break;
283: case WakeupOnCollisionEntry.BOUNDINGLEAF: // use BoundingLeaf.transformedRegion
284: if (!armingNode.source.isLive()) {
285: return;
286: }
287: this .boundingLeaf = ((BoundingLeafRetained) armingNode).mirrorBoundingLeaf;
288: break;
289: case WakeupOnCollisionEntry.BOUND: // use this.vwcBounds
290: vwcBounds = (Bounds) armingBounds.clone();
291: this .armingNode = behav;
292: break;
293: case WakeupOnCollisionEntry.GROUP:
294: if (!armingNode.source.isLive()) {
295: return;
296: }
297: if (accuracyMode == USE_GEOMETRY) {
298: if (geometryAtoms == null) {
299: geometryAtoms = new UnorderList(1,
300: GeometryAtom.class);
301: }
302: ((GroupRetained) armingNode)
303: .searchGeometryAtoms(geometryAtoms);
304: }
305: // else use this.vwcBounds
306: default:
307: }
308:
309: behav.universe.geometryStructure.addWakeupOnCollision(this );
310: }
311:
312: /**
313: * This is a callback from BehaviorStructure. It is
314: * used to remove wakeupCondition from behavior structure.
315: */
316: void removeBehaviorCondition(BehaviorStructure bs) {
317: vwcBounds = null;
318: if (geometryAtoms != null) {
319: geometryAtoms.clear();
320: }
321: boundingLeaf = null;
322: behav.universe.geometryStructure.removeWakeupOnCollision(this );
323: }
324:
325: // Set collidingPath & collidingBounds
326: void setTarget(BHLeafInterface leaf) {
327: SceneGraphPath path;
328: Bounds bound;
329:
330: if (leaf instanceof GeometryAtom) {
331: // Find the triggered Path & Bounds for this geometry Atom
332: GeometryAtom geomAtom = (GeometryAtom) leaf;
333: Shape3DRetained shape = geomAtom.source;
334: path = WakeupOnCollisionEntry.getSceneGraphPath(
335: shape.sourceNode, shape.key, shape
336: .getCurrentLocalToVworld(0));
337: bound = WakeupOnCollisionEntry.getTriggeringBounds(shape);
338:
339: } else {
340: // Find the triggered Path & Bounds for this alternative
341: // collision target
342: GroupRetained group = (GroupRetained) leaf;
343: path = WakeupOnCollisionEntry.getSceneGraphPath(group);
344: bound = WakeupOnCollisionEntry.getTriggeringBounds(group);
345: }
346:
347: if (path != null) {
348: // colliding path may be null when branch detach before
349: // user behavior retrieve the previous colliding path
350: collidingPath = path;
351: collidingBounds = bound;
352: }
353:
354: }
355:
356: // Invoke from GeometryStructure to update vwcBounds of GROUP
357: void updateCollisionBounds(boolean reEvaluateGAs) {
358: if (nodeType == WakeupOnCollisionEntry.GROUP) {
359: GroupRetained group = (GroupRetained) armingNode;
360: if (group.collisionBound != null) {
361: vwcBounds = (Bounds) group.collisionBound.clone();
362: } else {
363: // this may involve recursive tree traverse if
364: // BoundsAutoCompute is true, we can't avoid
365: // since the bound under it may change by transform
366: vwcBounds = group.getEffectiveBounds();
367: }
368: group.transformBounds(armingPath, vwcBounds);
369: } else if (nodeType == WakeupOnCollisionEntry.BOUND) {
370: vwcBounds.transform(armingBounds, behav
371: .getCurrentLocalToVworld());
372: }
373:
374: if (reEvaluateGAs && (nodeType == WakeupOnCollisionEntry.GROUP)
375: && (accuracyMode == USE_GEOMETRY)) {
376: geometryAtoms.clear();
377: ((GroupRetained) armingNode)
378: .searchGeometryAtoms(geometryAtoms);
379: }
380: }
381:
382: void setTriggered() {
383: // if path not set, probably the branch is just detach.
384: if (collidingPath != null) {
385: super .setTriggered();
386: }
387: }
388:
389: /**
390: * Perform task in addBehaviorCondition() that has to be
391: * set every time the condition met.
392: */
393: void resetBehaviorCondition(BehaviorStructure bs) {
394: // The reference geometryAtom will not change once
395: // Shape3D create so there is no need to set this.
396: }
397: }
|