javax.media.j3d.GeometryStructure Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java3d-core Show documentation
Show all versions of java3d-core Show documentation
Java3D Core And Java3D Util Libraries
The newest version!
/*
* Copyright 1998-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.ArrayList;
import java.util.Arrays;
import javax.vecmath.Vector3d;
/**
* A geometry structure is a object that organizes geometries
* and bounds.
*/
class GeometryStructure extends J3dStructure {
/**
* used during Transform Processing
*/
UpdateTargets targets = null;
/**
* A multiple read single write Lock to sychronize access into this
* GeometryStructure.
* To prevent deadlock a call to read/write lock must end with a read/write
* unlock respectively.
*/
private MRSWLock lock = null;
/**
* A lock object to prevent concurrent getVisibleBHTree query.
*/
private Object visLock = new Object();
/**
* A lock object to prevent concurrent collideEntryList,
* collideExitList using toArray() in BehaviorStructure buildTree()
* while clearMirror() is invoked in GeometryStructure removeNode()
*/
private Object collideListLock = new Object();
/**
* Binary Hull Tree structure for handling geometry atoms.
* Do not change the following private variables to public, their access
* need to synchronize via lock.
*/
private BHTree[] bhTreeArr = null;
private int bhTreeCount;
private int bhTreeMax;
private int bhTreeBlockSize = 5;
/**
* The array of BHNode, a data pool, for passing data between GS and BHTrees.
* Do not change the following private variables to public, their access
* need to synchronize via lock.
*/
private BHNode[] bhNodeArr = null;
private int bhNodeCount, bhNodeMax;
private int bhNodeBlockSize = 50;
// Support for multi-locale.
private Vector3d localeTrans = new Vector3d();
//The lists of wakeupCriterion object currently in collision.
WakeupIndexedList collideEntryList;
WakeupIndexedList collideExitList;
WakeupIndexedList collideMovementList;
// The lists of wakeupCriterion objects that GeometryStructure keeps
WakeupIndexedList wakeupOnCollisionEntry;
WakeupIndexedList wakeupOnCollisionExit;
WakeupIndexedList wakeupOnCollisionMovement;
// When Shape insert/remove for WakeupOnCollisionxxx() using
// Group node and USE_GEOMETRY, we need to reevaluate the
// cache geometryAtoms list.
boolean reEvaluateWakeupCollisionGAs;
private boolean transformMsg = false;
/**
* Constructor.
*/
GeometryStructure(VirtualUniverse u) {
super(u, J3dThread.UPDATE_GEOMETRY);
bhNodeCount = 0;
bhNodeMax = bhNodeBlockSize;
bhNodeArr = new BHNode[bhNodeMax];
bhTreeMax = 1;
bhTreeArr = new BHTree[bhTreeMax];
bhTreeCount=0;
lock = new MRSWLock();
collideEntryList = new WakeupIndexedList(WakeupOnCollisionEntry.class,
WakeupOnCollisionEntry.COLLIDEENTRY_IN_BS_LIST, u);
collideExitList = new WakeupIndexedList(WakeupOnCollisionExit.class,
WakeupOnCollisionExit.COLLIDEEXIT_IN_BS_LIST, u);
collideMovementList = new WakeupIndexedList(WakeupOnCollisionMovement.class,
WakeupOnCollisionMovement.COLLIDEMOVE_IN_BS_LIST, u);
wakeupOnCollisionEntry = new WakeupIndexedList(WakeupOnCollisionEntry.class,
WakeupOnCollisionEntry.COND_IN_GS_LIST, u);
wakeupOnCollisionExit = new WakeupIndexedList(WakeupOnCollisionExit.class,
WakeupOnCollisionExit.COND_IN_GS_LIST, u);
wakeupOnCollisionMovement = new WakeupIndexedList(WakeupOnCollisionMovement.class,
WakeupOnCollisionMovement.COND_IN_GS_LIST, u);
}
@Override
void processMessages(long referenceTime) {
J3dMessage m;
J3dMessage[] messages = getMessages(referenceTime);
int nMsg = getNumMessage();
if (nMsg > 0) {
reEvaluateWakeupCollisionGAs = false;
for (int i=0; i < nMsg; i++) {
lock.writeLock();
m = messages[i];
switch (m.type) {
case J3dMessage.TRANSFORM_CHANGED:
transformMsg = true;
break;
case J3dMessage.SWITCH_CHANGED:
processSwitchChanged(m);
// may need to process dirty switched-on transform
if (universe.transformStructure.getLazyUpdate()) {
transformMsg = true;
}
break;
case J3dMessage.INSERT_NODES:
insertNodes((Object[])m.args[0]);
reEvaluateWakeupCollisionGAs = true;
break;
case J3dMessage.REMOVE_NODES:
removeNodes(m);
reEvaluateWakeupCollisionGAs = true;
break;
case J3dMessage.SHAPE3D_CHANGED: {
int comp = ((Integer)m.args[1]).intValue();
if (comp == Shape3DRetained.GEOMETRY_CHANGED) {
m.args[0] = m.args[2];
removeNodes(m);
insertNodes((Object[])m.args[3]);
reEvaluateWakeupCollisionGAs = true;
}
else if (comp == Shape3DRetained.APPEARANCE_CHANGED) {
processVisibleChanged(m.args[2],
((GeometryAtom[]) m.args[3]));
}
break;
}
case J3dMessage.TEXT3D_DATA_CHANGED:
removeNodes(m);
insertNodes((Object[])m.args[1]);
break;
case J3dMessage.TEXT3D_TRANSFORM_CHANGED:
processBoundsChanged((Object []) m.args[0], false);
break;
case J3dMessage.MORPH_CHANGED: {
int comp = ((Integer)m.args[1]).intValue();
if (comp == MorphRetained.GEOMETRY_CHANGED) {
processBoundsChanged((Object []) m.args[3], false);
}
else if (comp == MorphRetained.APPEARANCE_CHANGED) {
processVisibleChanged(m.args[2],
((GeometryAtom[]) m.args[3]));
}
break;
}
case J3dMessage.REGION_BOUND_CHANGED:
case J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED:
// Only set this flag, when bounds might be empty.
processBoundsChanged((Object [])m.args[0], false);
break;
case J3dMessage.GEOMETRY_CHANGED:
// System.err.println("J3dMessage.GEOMETRY_CHANGED");
processBoundsChanged((Object []) m.args[0], false);
break;
case J3dMessage.RENDERINGATTRIBUTES_CHANGED:
processVisibleChanged(m.args[2],
((GeometryAtom[]) m.args[3]));
break;
}
lock.writeUnlock();
m.decRefcount();
}
if (transformMsg) {
targets = universe.transformStructure.getTargetList();
lock.writeLock();
processTransformChanged(targets);
lock.writeUnlock();
transformMsg = false;
targets = null;
}
Arrays.fill(messages, 0, nMsg, null);
}
processCollisionDetection();
}
private int getBHTreeIndex(Locale locale) {
int i;
for (i=0; i< bhTreeCount; i++) {
if (bhTreeArr[i].locale == locale)
return i;
}
// Can't find will return -1 so that other
// program know this
return -1;
}
private int getOrAddBHTreeIndex(Locale locale) {
int i;
for (i=0; i< bhTreeCount; i++) {
if (bhTreeArr[i].locale == locale)
return i;
}
if (bhTreeCount >= bhTreeMax) {
// allocate a bigger array here....
if (J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2,
"Expanding bhTreeArr array ...\n");
bhTreeMax += bhTreeBlockSize;
BHTree[] oldBhTreeArr = bhTreeArr;
bhTreeArr = new BHTree[bhTreeMax];
System.arraycopy(oldBhTreeArr, 0, bhTreeArr, 0, oldBhTreeArr.length);
}
bhTreeArr[bhTreeCount] = new BHTree(locale);
bhTreeCount++;
return i;
}
private void clearBhNodeArr() {
// Issue 353: set all elements to null so we don't leak
// NOTE: we really should change this to be an ArrayList, but that
// would be a less localized change. Consider for 1.6.0.
for (int i = 0; i < bhNodeCount; i++) {
bhNodeArr[i] = null;
}
bhNodeCount = 0;
}
private void addToBhNodeArr(BHNode bhNode) {
// Add to bhNodeArr.
if (bhNodeCount >= bhNodeMax) {
bhNodeMax += bhNodeBlockSize;
BHNode[] oldbhNodeArr = bhNodeArr;
bhNodeArr = new BHNode[bhNodeMax];
System.arraycopy(oldbhNodeArr, 0, bhNodeArr, 0, oldbhNodeArr.length);
}
bhNodeArr[bhNodeCount] = bhNode;
bhNodeCount++;
}
private void processVisibleChanged(Object valueObj, GeometryAtom[] gaArr) {
boolean visible = true; // Default is true.
int i, treeIndex;
if ((gaArr == null) || (gaArr.length < 1))
return;
treeIndex = getBHTreeIndex(gaArr[0].locale);
visible = ((Boolean)valueObj).booleanValue();
for ( i=gaArr.length-1; i>=0; i--) {
gaArr[i].visible = visible;
}
}
private void insertNodes(Object[] nodes) {
Object node;
GeometryAtom geomAtom;
clearBhNodeArr();
// System.err.println("GS : nodes.length is " + nodes.length);
for (int i=0; i=0; j--) {
wentry = wentryArr[j];
if (wentry.behav == behav) {
collideEntryList.remove(wentry);
}
}
WakeupOnCollisionExit wexit;
WakeupOnCollisionExit wexitArr[] =
(WakeupOnCollisionExit []) collideExitList.toArray();
for (int j=collideExitList.arraySize()-1; j>=0; j--) {
wexit = wexitArr[j];
if (wexit.behav == behav) {
collideExitList.remove(wexit);
}
}
}
}
}
if (bhNodeCount < 1) {
return;
}
int index = getBHTreeIndex(((BHLeafNode) bhNodeArr[0]).getLocale());
if (index < 0) {
// Issue 353: must clear array after we are done with it
clearBhNodeArr();
return;
}
BHTree currTree = bhTreeArr[index];
currTree.delete(bhNodeArr, bhNodeCount);
// Issue 353: must clear array after we are done with it
clearBhNodeArr();
// It is safe to do it here since only GeometryStructure
// thread invoke wakeupOnCollisionEntry/Exit .toArray()
wakeupOnCollisionEntry.clearMirror();
wakeupOnCollisionMovement.clearMirror();
wakeupOnCollisionExit.clearMirror();
synchronized (collideListLock) {
collideEntryList.clearMirror();
collideExitList.clearMirror();
}
}
private void processBoundsChanged(Object[] nodes, boolean transformChanged) {
int index;
Object node;
clearBhNodeArr();
for (int i = 0; i < nodes.length; i++) {
node = nodes[i];
if (node instanceof GeometryAtom) {
synchronized (node) {
GeometryAtom geomAtom = (GeometryAtom) node;
if (geomAtom.bhLeafNode != null) {
addToBhNodeArr(geomAtom.bhLeafNode);
}
}
} else if (node instanceof GroupRetained) {
GroupRetained group = (GroupRetained) node;
if (group.nodeType != NodeRetained.SWITCH) {
synchronized (node) {
if (group.bhLeafNode != null) {
addToBhNodeArr(group.bhLeafNode);
}
}
}
}
}
if (bhNodeCount < 1) {
return;
}
index = getBHTreeIndex(((BHLeafNode)bhNodeArr[0]).getLocale());
if (index >= 0) {
bhTreeArr[index].boundsChanged(bhNodeArr, bhNodeCount);
}
// Issue 353: must clear array after we are done with it
clearBhNodeArr();
}
private void processTransformChanged(UpdateTargets targets) {
int i, j, index;
Object[] nodes, nodesArr;
UnorderList arrList;
int size;
clearBhNodeArr();
arrList = targets.targetList[Targets.GEO_TARGETS];
if (arrList != null) {
size = arrList.size();
nodesArr = arrList.toArray(false);
for (j = 0; j < size; j++) {
nodes = (Object[])nodesArr[j];
for (i = 0; i < nodes.length; i++) {
GeometryAtom geomAtom = (GeometryAtom) nodes[i];
synchronized (geomAtom) {
if (geomAtom.bhLeafNode != null) {
addToBhNodeArr(geomAtom.bhLeafNode);
}
}
}
}
}
arrList = targets.targetList[Targets.GRP_TARGETS];
if (arrList != null) {
size = arrList.size();
nodesArr = arrList.toArray(false);
for ( j = 0; j < size; j++) {
nodes = (Object[])nodesArr[j];
for ( i = 0; i < nodes.length; i++) {
GroupRetained group = (GroupRetained) nodes[i];
if (group.nodeType != NodeRetained.SWITCH) {
synchronized (group) {
if (group.bhLeafNode != null) {
addToBhNodeArr(group.bhLeafNode);
}
}
}
}
}
}
if (bhNodeCount < 1) {
return;
}
index = getBHTreeIndex(((BHLeafNode)bhNodeArr[0]).getLocale());
if (index >= 0) {
bhTreeArr[index].boundsChanged(bhNodeArr, bhNodeCount);
}
// Issue 353: must clear array after we are done with it
clearBhNodeArr();
}
// This method is called by RenderBin to get a array of possibly visible
// sub-trees.
// bhTrees mustn't be null.
// Return true if bhTree's root in encompass by frustumBBox.
boolean getVisibleBHTrees(RenderBin rBin,
BoundingBox frustumBBox,
Locale locale, long referenceTime,
boolean stateChanged,
int visibilityPolicy) {
int i, j;
boolean unviInFB = true;
// System.err.println("GeometryStructure : view's locale is " + locale);
lock.readLock();
// Issue 353: create a new array list each time rather than passing it
// in. This will not generate too much garbage, since we only call
// this once per frame and it is very short-lived.
ArrayList bhTrees = new ArrayList();
if (bhTreeCount == 1) {
// For debugging only.
if (J3dDebug.devPhase) {
if (J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2)) {
System.err.println("GeometryStructure : In simple case");
System.err.println("GeometryStructure : view's locale is " +
locale);
System.err.println("GeometryStructure : bhTreeArr[0].locale is " +
bhTreeArr[0].locale);
}
}
// One locale case - Lets make the simple case fast.
synchronized(visLock) {
unviInFB = bhTreeArr[0].getVisibleBHTrees(rBin, bhTrees, frustumBBox,
referenceTime,
stateChanged,
visibilityPolicy, true);
}
}
else {
// Multiple locale case.
// For debugging only.
if (J3dDebug.devPhase)
J3dDebug.doDebug(J3dDebug.geometryStructure, J3dDebug.LEVEL_2,
"GeometryStructure : bhTreeCount is " +
universe.geometryStructure.bhTreeCount +
" view's locale is " + locale + "\n");
BoundingBox localeFrustumBBox = new BoundingBox();
synchronized(visLock) {
for (j=0; j=0; i--) {
wentry = collideEntryArr[i];
if ((wentry.behav == w.behav) &&
(wentry.geometryAtoms == w.geometryAtoms)) {
collideEntryList.remove(i);
needTrigger = false;
break;
}
}
}
// add to wakeup list
wakeupOnCollisionEntry.add(w);
w.updateCollisionBounds(false);
// check for collision and triggered event
BHLeafInterface target = collide(w.behav.locale,
w.accuracyMode,
w.geometryAtoms,
w.vwcBounds,
w.boundingLeaf,
w.armingNode,
null);
if (target != null) {
collideEntryList.add(w);
w.setTarget(target);
}
if ((target != null) && (needTrigger)) {
w.setTriggered();
}
}
void addWakeupOnCollision(WakeupOnCollisionExit w) {
// Cleanup, since collideExitList did not remove
// its condition in removeWakeupOnCollision
boolean needTrigger = true;
synchronized (collideListLock) {
WakeupOnCollisionExit collideExitArr[] =
(WakeupOnCollisionExit []) collideExitList.toArray();
WakeupOnCollisionExit wexit;
for (int i=collideExitList.arraySize()-1; i>=0; i--) {
wexit = collideExitArr[i];
if ((wexit.behav == w.behav) &&
(wexit.geometryAtoms == w.geometryAtoms)) {
collideExitList.remove(i);
needTrigger = false;
break;
}
}
}
// add condition
wakeupOnCollisionExit.add(w);
w.updateCollisionBounds(false);
BHLeafInterface target = collide(w.behav.locale,
w.accuracyMode,
w.geometryAtoms,
w.vwcBounds,
w.boundingLeaf,
w.armingNode,
null);
if (target != null) {
// store the target that cause this condition to collide
// this is used when this condition is triggered.
w.setTarget(target);
collideExitList.add(w);
}
if (!needTrigger) {
return;
}
// see if the matching wakeupOnCollisionEntry
// condition exists
synchronized (collideListLock) {
WakeupOnCollisionEntry collideEntryArr[] =
(WakeupOnCollisionEntry []) collideEntryList.toArray();
WakeupOnCollisionEntry wentry;
for (int i=collideEntryList.arraySize()-1; i>=0; i--) {
wentry = collideEntryArr[i];
if ((wentry.behav == w.behav) &&
(wentry.geometryAtoms == w.geometryAtoms)) {
// Should not call collideEntryList.remove(i);
// Otherwise wakeupOn for Entry case may call several
// time at when initialize if collide
if (target == null) {
w.setTriggered();
}
break;
}
}
}
}
void addWakeupOnCollision(WakeupOnCollisionMovement w) {
wakeupOnCollisionMovement.add(w);
w.updateCollisionBounds(false);
BHLeafInterface target = collide(w.behav.locale,
w.accuracyMode,
w.geometryAtoms,
w.vwcBounds,
w.boundingLeaf,
w.armingNode,
w);
if (target != null) {
w.setTarget(target);
collideMovementList.add(w);
}
}
void removeWakeupOnCollision(WakeupOnCollisionEntry wentry) {
wakeupOnCollisionEntry.remove(wentry);
// No need to remove collideEntry, it is used next time
// when WakeupOnExitCollision is added to determine
// whether to trigger it.
}
void removeWakeupOnCollision(WakeupOnCollisionExit wexit) {
wakeupOnCollisionExit.remove(wexit);
// No need to remove collideExit, it is used next time
// when WakeupOnExitCollision is added to determine
// whether to trigger it.
}
void removeWakeupOnCollision(WakeupOnCollisionMovement wmovement) {
wakeupOnCollisionMovement.remove(wmovement);
collideMovementList.remove(wmovement); // remove if exists
}
/**
* This method test all wakeupOnCollision list and trigger the
* condition if collision occurs.
*/
void processCollisionDetection() {
int i, idx;
BHLeafInterface target;
// handle WakeupOnCollisionEntry
WakeupOnCollisionEntry wentry;
WakeupOnCollisionEntry wentryArr[] = (WakeupOnCollisionEntry [])
wakeupOnCollisionEntry.toArray();
for (i = wakeupOnCollisionEntry.arraySize()-1; i >=0; i--) {
wentry = wentryArr[i];
wentry.updateCollisionBounds(reEvaluateWakeupCollisionGAs);
target = collide(wentry.behav.locale,
wentry.accuracyMode,
wentry.geometryAtoms,
wentry.vwcBounds,
wentry.boundingLeaf,
wentry.armingNode,
null);
idx = collideEntryList.indexOf(wentry);
if (target != null) {
if (idx < 0) {
collideEntryList.add(wentry);
wentry.setTarget(target);
wentry.setTriggered();
}
} else {
if (idx >= 0) {
collideEntryList.remove(idx);
}
}
}
// handle WakeupOnCollisionMovement
WakeupOnCollisionMovement wmove;
WakeupOnCollisionMovement wmoveArr[] = (WakeupOnCollisionMovement [])
wakeupOnCollisionMovement.toArray();
for (i = wakeupOnCollisionMovement.arraySize()-1; i >=0; i--) {
wmove = wmoveArr[i];
wmove.updateCollisionBounds(reEvaluateWakeupCollisionGAs);
target = collide(wmove.behav.locale,
wmove.accuracyMode,
wmove.geometryAtoms,
wmove.vwcBounds,
wmove.boundingLeaf,
wmove.armingNode,
wmove);
idx = collideMovementList.indexOf(wmove);
if (target != null) {
if (idx < 0) {
collideMovementList.add(wmove);
wmove.setTarget(target);
} else {
if (!wmove.duplicateEvent) {
wmove.setTriggered();
}
}
} else {
if (idx >= 0) {
collideMovementList.remove(idx);
wmove.lastSrcBounds = null;
wmove.lastDstBounds = null;
}
}
}
// Finally, handle WakeupOnCollisionExit
WakeupOnCollisionExit wexit;
WakeupOnCollisionExit wexitArr[] = (WakeupOnCollisionExit [])
wakeupOnCollisionExit.toArray();
for (i = wakeupOnCollisionExit.arraySize()-1; i >=0; i--) {
wexit = wexitArr[i];
wexit.updateCollisionBounds(reEvaluateWakeupCollisionGAs);
target = collide(wexit.behav.locale,
wexit.accuracyMode,
wexit.geometryAtoms,
wexit.vwcBounds,
wexit.boundingLeaf,
wexit.armingNode,
null);
idx = collideExitList.indexOf(wexit);
if (target != null) {
if (idx < 0) {
collideExitList.add(wexit);
wexit.setTarget(target);
}
} else {
if (idx >= 0) {
collideExitList.remove(idx);
wexit.setTriggered();
}
}
}
}
/**
* Check for duplicate WakeupOnCollisionMovement event.
* We don't want to continue deliver event even though the
* two colliding object did not move but this Geometry update
* thread continue to run due to transform change in others
* shape not in collision.
*/
void checkDuplicateEvent(WakeupOnCollisionMovement wmove,
Bounds bound,
BHLeafInterface hitNode) {
Bounds hitBound;
if ((wmove.lastSrcBounds != null) &&
wmove.lastSrcBounds.equals(bound)) {
if (hitNode instanceof GeometryAtom) {
hitBound = ((GeometryAtom) hitNode).source.vwcBounds;
} else {
hitBound = ((GroupRetained) hitNode).collisionVwcBounds;
}
if ((wmove.lastDstBounds != null) &&
wmove.lastDstBounds.equals(hitBound)) {
wmove.duplicateEvent = true;
} else {
wmove.duplicateEvent = false;
wmove.lastDstBounds = (Bounds) hitBound.clone();
}
} else {
wmove.duplicateEvent = false;
wmove.lastSrcBounds = (Bounds) bound.clone();
}
}
/**
* check if either the geomAtoms[] or
* bound or boundingLeaf collide with BHTree.
* Only one of geomAtoms, bound, boundingLeaf is non-null.
* If accurancyMode is USE_GEOMETRY, object geometry is used,
* otherwise object bounding box is used for collision
* detection.
* In case of GROUP & BOUND, the armingNode is used
* to tell whether the colliding Group is itself or not.
* Also in case GROUP, geomAtoms is non-null if USE_GEOMETRY.
* If cond != null, it must be instanceof WakeupOnCollisionMovement
*/
BHLeafInterface collide(Locale locale,
int accurancyMode,
UnorderList geomAtoms,
Bounds bound,
BoundingLeafRetained boundingLeaf,
NodeRetained armingNode,
WakeupCriterion cond) {
lock.readLock();
int idx = getBHTreeIndex(locale);
if (idx < 0) {
lock.readUnlock();
return null;
}
BHLeafInterface hitNode;
if (geomAtoms != null) {
synchronized (bhTreeArr[idx]) {
if ((bound != null) &&
(armingNode instanceof GroupRetained)) {
// Check Bound intersect first before process
// to individual Shape3D geometryAtoms
hitNode = bhTreeArr[idx].selectAny(bound,
accurancyMode,
(GroupRetained)
armingNode);
if (hitNode == null) {
lock.readUnlock();
return null;
}
GeometryAtom galist[] = (GeometryAtom [])
geomAtoms.toArray(false);
hitNode = bhTreeArr[idx].selectAny(galist,
geomAtoms.arraySize(),
accurancyMode);
if (hitNode != null) {
lock.readUnlock();
if (cond != null) {
checkDuplicateEvent((WakeupOnCollisionMovement) cond,
bound, hitNode);
}
return hitNode;
}
} else {
GeometryAtom ga = (GeometryAtom) geomAtoms.get(0);
hitNode = bhTreeArr[idx].selectAny(ga, accurancyMode);
if (hitNode != null) {
lock.readUnlock();
if (cond != null) {
checkDuplicateEvent((WakeupOnCollisionMovement) cond,
ga.source.vwcBounds,
hitNode);
}
return hitNode;
}
}
}
} else {
if (bound == null) {
if (boundingLeaf == null) {
lock.readUnlock();
return null;
}
bound = boundingLeaf.transformedRegion;
}
if (bound == null) {
lock.readUnlock();
return null;
}
if (armingNode instanceof GroupRetained) {
synchronized (bhTreeArr[idx]) {
hitNode = bhTreeArr[idx].selectAny(bound,
accurancyMode,
(GroupRetained)
armingNode);
lock.readUnlock();
if ((hitNode != null) && (cond != null)) {
checkDuplicateEvent((WakeupOnCollisionMovement) cond,
bound, hitNode);
}
return hitNode;
}
} else {
synchronized (bhTreeArr[idx]) {
hitNode = bhTreeArr[idx].selectAny(bound, accurancyMode,
armingNode);
lock.readUnlock();
if ((hitNode != null) && (cond != null)) {
checkDuplicateEvent((WakeupOnCollisionMovement) cond,
bound, hitNode);
}
return hitNode;
}
}
}
lock.readUnlock();
return null;
}
/**
* This prevents wakeupCondition sent out message and set
* conditionMet to true but the
* BehaviorStructure/BehaviorScheduler is not fast enough to
* process the message and reset conditionMet to false
* when view deactivate/unregister.
*/
void resetConditionMet() {
BehaviorStructure.resetConditionMet(wakeupOnCollisionEntry);
BehaviorStructure.resetConditionMet(wakeupOnCollisionExit);
BehaviorStructure.resetConditionMet(wakeupOnCollisionMovement);
}
/**
* This processes a switch change.
*/
private void processSwitchChanged(J3dMessage m) {
// int i;
// UnorderList arrList;
// int size, treeIndex;
// Object[] nodes;
// LeafRetained leaf;
/* is now a NOOP
UpdateTargets targets = (UpdateTargets)m.args[0];
arrList = targets.targetList[Targets.GEO_TARGETS];
if (arrList != null) {
size = arrList.size();
nodes = arrList.toArray(false);
treeIndex = getBHTreeIndex(((LeafRetained)nodes[0]).locale);
for (i=0; i