/*
* Copyright 1999-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.Enumeration;
import java.util.Vector;
import javax.vecmath.Vector4d;
/**
* The ModelClip retained object.
*/
class ModelClipRetained extends LeafRetained {
// Statics used when something in the fog changes
static final int PLANE_CHANGED = 0x0001;
static final int PLANES_CHANGED = 0x0002;
static final int ENABLE_CHANGED = 0x0004;
static final int ENABLES_CHANGED = 0x0008;
static final int BOUNDS_CHANGED = 0x0010;
static final int BOUNDINGLEAF_CHANGED = 0x0020;
static final int SCOPE_CHANGED = 0x0040;
static final int INIT_MIRROR = 0x0080;
static final int CLEAR_MIRROR = 0x0100;
static final int LAST_DEFINED_BIT = 0x0100;
/**
* The clip planes and the enable bits
*/
Vector4d[] planes = new Vector4d[6];
boolean[] enables = new boolean[6];
Vector4d[] xformPlanes = new Vector4d[6];
// enableFlag is true if one of the enables is true
// only used by mirror object
boolean enableFlag = false;
/**
* The Boundary object defining the model clip's region of influencing
*/
Bounds regionOfInfluence = null;
/**
* The bounding leaf reference
*/
BoundingLeafRetained boundingLeaf = null;
/**
* The transformed value of the influencingRegion.
*/
Bounds region = null;
/**
* Vector of GroupRetained nodes that scopes this model clip.
*/
Vector<GroupRetained> scopes = new Vector<GroupRetained>();
//Boolean to indicate if this object is scoped (only used for mirror objects
boolean isScoped = false;
// The object that contains the dynamic HashKey - a string type object
// Used in scoping
HashKey tempKey = new HashKey(250);
// This is true when this model clip is referenced in an immediate mode context
boolean inImmCtx = false;
// The mirror copy of this modelClip
ModelClipRetained mirrorModelClip = null;
// A reference to the scene graph model clip
ModelClipRetained sgModelClip = null;
// Target threads to be notified when model clip changes
final static int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT |
J3dThread.UPDATE_RENDER;
/**
* The EnvironmentSets which reference this model clip.
* Note that multiple RenderBin update thread may access
* this shared environmentSets simultaneously.
* So we use UnorderList which sync. all the operations.
*/
UnorderList environmentSets = new UnorderList(1, EnvironmentSet.class);
// Is true, if the mirror clip is viewScoped
boolean isViewScoped = false;
/**
* Constructs and initializes model clip planes
*/
ModelClipRetained() {
// planes contains the negate default values
planes[0] = new Vector4d( 1.0, 0.0, 0.0,-1.0);
planes[1] = new Vector4d(-1.0, 0.0, 0.0,-1.0);
planes[2] = new Vector4d( 0.0, 1.0, 0.0,-1.0);
planes[3] = new Vector4d( 0.0,-1.0, 0.0,-1.0);
planes[4] = new Vector4d( 0.0, 0.0, 1.0,-1.0);
planes[5] = new Vector4d( 0.0, 0.0, -1.0,-1.0);
for (int i = 0; i < 6; i++)
xformPlanes[i] = new Vector4d(planes[i]);
enables[0] = enables[1] = enables[2] = enables[3] =
enables[4] = enables[5] = true;
}
/**
* Initializes planes before the object is live
*/
void initPlanes(Vector4d[] planes) {
if (staticTransform != null) {
Transform3D xform = staticTransform.getNormalTransform();
for (int i = 0; i < 6; i++) {
this.planes[i].set(planes[i]);
xform.transform(this.planes[i], this.xformPlanes[i]);
}
} else {
for (int i = 0; i < 6; i++) {
this.planes[i].set(planes[i]);
this.xformPlanes[i].set(this.planes[i]);
}
}
}
/**
* Sets the clip planes and send a message
*/
void setPlanes(Vector4d[] planes) {
Vector4d[] pl = new Vector4d[6];
initPlanes(planes);
for (int i = 0; i < 6; i++) {
pl[i] = new Vector4d(this.xformPlanes[i]);
}
sendMessage(PLANES_CHANGED, pl, null);
}
/**
* Initializes planes before the object is live
*/
void initPlane(int planeNum, Vector4d plane) {
if (planeNum < 0 || planeNum > 5)
throw new IllegalArgumentException(J3dI18N.getString("ModelClip6"));
if (staticTransform != null) {
Transform3D xform = staticTransform.getNormalTransform();
this.planes[planeNum].set(plane);
xform.transform(this.planes[planeNum], this.xformPlanes[planeNum]);
} else {
this.planes[planeNum].set(plane);
this.xformPlanes[planeNum].set(plane);
}
}
/**
* Sets the clip planes and send a message
*/
void setPlane(int planeNum, Vector4d plane) {
initPlane(planeNum, plane);
sendMessage(PLANE_CHANGED,
new Integer(planeNum),
new Vector4d(this.xformPlanes[planeNum]));
}
/**
* Gets planes
*/
void getPlanes(Vector4d[] planes){
for (int i = 0; i < 6; i++) {
planes[i].set(this.planes[i]);
}
}
/**
* Gets the specified clipping plane
*/
void getPlane(int planeNum, Vector4d plane) {
if (planeNum < 0 || planeNum > 5)
throw new IllegalArgumentException(J3dI18N.getString("ModelClip6"));
plane.set(this.planes[planeNum]);
}
/**
* Initializes planes before the object is live
*/
void initEnables(boolean[] enables) {
this.enables[0] = enables[0];
this.enables[1] = enables[1];
this.enables[2] = enables[2];
this.enables[3] = enables[3];
this.enables[4] = enables[4];
this.enables[5] = enables[5];
}
/**
* Sets the clip planes and send a message
*/
void setEnables(boolean[] enables) {
Boolean[] en = new Boolean[6];
initEnables(enables);
en[0] = (enables[0] ? Boolean.TRUE: Boolean.FALSE);
en[1] = (enables[1] ? Boolean.TRUE: Boolean.FALSE);
en[2] = (enables[2] ? Boolean.TRUE: Boolean.FALSE);
en[3] = (enables[3] ? Boolean.TRUE: Boolean.FALSE);
en[4] = (enables[4] ? Boolean.TRUE: Boolean.FALSE);
en[5] = (enables[5] ? Boolean.TRUE: Boolean.FALSE);
sendMessage(ENABLES_CHANGED, en, null);
}
/**
* Initializes planes before the object is live
*/
void initEnable(int planeNum, boolean enable) {
if (planeNum < 0 || planeNum > 5)
throw new IllegalArgumentException(J3dI18N.getString("ModelClip6"));
this.enables[planeNum] = enable;
}
/**
* Sets the clip planes and send a message
*/
void setEnable(int planeNum, boolean enable) {
initEnable(planeNum, enable);
sendMessage(ENABLE_CHANGED,
new Integer(planeNum),
(enable ? Boolean.TRUE: Boolean.FALSE));
}
/**
* Gets enables
*/
void getEnables(boolean[] enables) {
enables[0] = this.enables[0];
enables[1] = this.enables[1];
enables[2] = this.enables[2];
enables[3] = this.enables[3];
enables[4] = this.enables[4];
enables[5] = this.enables[5];
}
/**
* Gets the specified enable
*/
boolean getEnable(int planeNum) {
if (planeNum < 0 || planeNum > 5)
throw new IllegalArgumentException(J3dI18N.getString("ModelClip6"));
return (this.enables[planeNum]);
}
/**
* Set the Model Clip's region of influencing
*/
void initInfluencingBounds(Bounds region) {
if (region != null) {
this.regionOfInfluence = (Bounds) region.clone();
if (staticTransform != null) {
regionOfInfluence.transform(staticTransform.transform);
}
} else {
this.regionOfInfluence = null;
}
}
/**
* Set the Model Clip's region of influencing and send message
*/
void setInfluencingBounds(Bounds region) {
initInfluencingBounds(region);
sendMessage(BOUNDS_CHANGED,
(region != null ? (Bounds) region.clone(): null),
null);
}
/**
* Get the Model Clip's region of influencing.
*/
Bounds getInfluencingBounds() {
Bounds b = null;
if (regionOfInfluence != null) {
b = (Bounds) regionOfInfluence.clone();
if (staticTransform != null) {
Transform3D invTransform = staticTransform.getInvTransform();
b.transform(invTransform);
}
}
return b;
}
/**
* Set the Model Clip's region of influencing to the specified Leaf node.
*/
void initInfluencingBoundingLeaf(BoundingLeaf region) {
if (region != null) {
boundingLeaf = (BoundingLeafRetained)region.retained;
} else {
boundingLeaf = null;
}
}
/**
* Set the Model Clip's region of influencing to the specified Leaf node.
*/
void setInfluencingBoundingLeaf(BoundingLeaf region) {
if (boundingLeaf != null)
boundingLeaf.mirrorBoundingLeaf.removeUser(mirrorModelClip);
if (region != null) {
boundingLeaf = (BoundingLeafRetained)region.retained;
boundingLeaf.mirrorBoundingLeaf.addUser(mirrorModelClip);
} else {
boundingLeaf = null;
}
sendMessage(BOUNDINGLEAF_CHANGED,
(boundingLeaf != null ?
boundingLeaf.mirrorBoundingLeaf : null),
null);
}
/**
* Get the Model Clip's region of influencing.
*/
BoundingLeaf getInfluencingBoundingLeaf() {
return (boundingLeaf != null ?
(BoundingLeaf)boundingLeaf.source : null);
}
/**
* Replaces the specified scope with the scope provided.
* @param scope the new scope
* @param index which scope to replace
*/
void initScope(Group scope, int index) {
scopes.setElementAt((GroupRetained)(scope.retained), index);
}
/**
* Replaces the specified scope with the scope provided.
* @param scope the new scope
* @param index which scope to replace
*/
void setScope(Group scope, int index) {
ArrayList addScopeList = new ArrayList();
ArrayList removeScopeList = new ArrayList();
GroupRetained group;
Object[] scopeInfo = new Object[3];
group = scopes.get(index);
tempKey.reset();
group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey);
group = (GroupRetained)scope.retained;
initScope(scope, index);
tempKey.reset();
// If its a group, then add the scope to the group, if
// its a shape, then keep a list to be added during
// updateMirrorObject
group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey);
scopeInfo[0] = addScopeList;
scopeInfo[1] = removeScopeList;
scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE:Boolean.FALSE);
sendMessage(SCOPE_CHANGED, scopeInfo, null);
}
/**
* Inserts the specified scope at specified index
* @param scope the new scope
* @param index position to insert new scope at
*/
void initInsertScope(Node scope, int index) {
GroupRetained group = (GroupRetained)scope.retained;
group.setMclipScope();
scopes.insertElementAt((GroupRetained)(scope.retained), index);
}
/**
* Inserts the specified scope at specified index and sends
* a message
* @param scope the new scope
* @param index position to insert new scope at
*/
void insertScope(Node scope, int index) {
Object[] scopeInfo = new Object[3];
ArrayList addScopeList = new ArrayList();
initInsertScope(scope, index);
GroupRetained group = (GroupRetained)scope.retained;
tempKey.reset();
group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey);
scopeInfo[0] = addScopeList;
scopeInfo[1] = null;
scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE);
sendMessage(SCOPE_CHANGED, scopeInfo, null);
}
void initRemoveScope(int index) {
GroupRetained group = scopes.elementAt(index);
group.removeMclipScope();
scopes.removeElementAt(index);
}
void removeScope(int index) {
Object[] scopeInfo = new Object[3];
ArrayList removeScopeList = new ArrayList();
GroupRetained group = scopes.elementAt(index);
initRemoveScope(index);
tempKey.reset();
group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey);
scopeInfo[0] = null;
scopeInfo[1] = removeScopeList;
scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE);
sendMessage(SCOPE_CHANGED, scopeInfo, null);
}
/**
* Removes the specified Group node from this ModelClip's list of
* scopes if the specified node is not found in the list of scoped
* nodes, method returns quietly.
*
* @param Group node to be removed
*/
void removeScope(Group node) {
int ind = indexOfScope(node);
if(ind >= 0)
removeScope(ind);
}
void initRemoveScope(Group node) {
int ind = indexOfScope(node);
if(ind >= 0)
initRemoveScope(ind);
}
/**
* Removes all the Group nodes from the ModelClip's scope
* list. The ModelClip reverts to universal scope.
*/
void removeAllScopes() {
Object[] scopeInfo = new Object[3];
ArrayList removeScopeList = new ArrayList();
int n = scopes.size();
for(int index = n-1; index >= 0; index--) {
GroupRetained group = scopes.elementAt(index);
initRemoveScope(index);
tempKey.reset();
group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey);
}
scopeInfo[0] = null;
scopeInfo[1] = removeScopeList;
scopeInfo[2] = (Boolean.FALSE);
sendMessage(SCOPE_CHANGED, scopeInfo, null);
}
void initRemoveAllScopes() {
int n = scopes.size();
for(int i = n-1; i >= 0; i--) {
initRemoveScope(i);
}
}
/**
* Returns the scope specified by the index.
* @param index which scope to return
* @return the scoperen at location index
*/
Group getScope(int index) {
return (Group)scopes.elementAt(index).source;
}
/**
* Returns an enumeration object of the scoperen.
* @return an enumeration object of the scoperen
*/
Enumeration<Group> getAllScopes() {
Enumeration<GroupRetained> elm = scopes.elements();
Vector<Group> v = new Vector<Group>(scopes.size());
while (elm.hasMoreElements()) {
v.add((Group)elm.nextElement().source);
}
return v.elements();
}
/**
* Appends the specified scope to this node's list of scopes before
* the fog is alive
* @param scope the scope to add to this node's list of scopes
*/
void initAddScope(Group scope) {
GroupRetained group = (GroupRetained)scope.retained;
scopes.addElement((GroupRetained)(scope.retained));
group.setMclipScope();
}
/**
* Appends the specified scope to this node's list of scopes.
* @param scope the scope to add to this node's list of scopes
*/
void addScope(Group scope) {
Object[] scopeInfo = new Object[3];
ArrayList addScopeList = new ArrayList();
GroupRetained group = (GroupRetained)scope.retained;
initAddScope(scope);
tempKey.reset();
group.addAllNodesForScopedModelClip(mirrorModelClip,addScopeList, tempKey);
scopeInfo[0] = addScopeList;
scopeInfo[1] = null;
scopeInfo[2] = (scopes.size() > 0 ? Boolean.TRUE: Boolean.FALSE);
sendMessage(SCOPE_CHANGED, scopeInfo, null);
}
/**
* Returns a count of this nodes' scopes.
* @return the number of scopes descendant from this node
*/
int numScopes() {
return scopes.size();
}
/**
* Returns the index of the specified Group node within the ModelClip's list of scoped
* Group nodes
* @param Group node whose index is desired
* @return index of this node
*/
int indexOfScope(Group node) {
if(node != null)
return scopes.indexOf(node.retained);
else
return scopes.indexOf(null);
}
/**
* This sets the immedate mode context flag
*/
void setInImmCtx(boolean inCtx) {
inImmCtx = inCtx;
}
/**
* This gets the immedate mode context flag
*/
boolean getInImmCtx() {
return (inImmCtx);
}
/**
* This method and its native counterpart update the native context
* model clip planes.
*/
void update(Canvas3D cv, int enableMask) {
cv.setModelViewMatrix(cv.ctx,
cv.vworldToEc.mat,
getLastLocalToVworld());
update(cv.ctx, enableMask, getLastLocalToVworld());
}
void update(Context ctx, int enableMask, Transform3D trans) {
for (int i = 0; i < 6; i++) {
Vector4d v = xformPlanes[i];
boolean enable = ((enableMask & (1 << i)) != 0);
Pipeline.getPipeline().updateModelClip(ctx, i, enable,
v.x, v.y, v.z, v.w);
}
}
void initMirrorObject(Object[] args) {
Shape3DRetained shape;
Object[] scopeInfo = (Object[]) args[2];
Boolean scoped = (Boolean)scopeInfo[0];
ArrayList shapeList = (ArrayList)scopeInfo[1];
BoundingLeafRetained bl=(BoundingLeafRetained)((Object[])args[4])[0];
Bounds bnds = (Bounds)((Object[])args[4])[1];
for (int i = 0; i < shapeList.size(); i++) {
shape = ((GeometryAtom)shapeList.get(i)).source;
shape.addModelClip(mirrorModelClip);
}
mirrorModelClip.isScoped = scoped.booleanValue();
if (bl != null) {
mirrorModelClip.boundingLeaf = bl.mirrorBoundingLeaf;
mirrorModelClip.region = boundingLeaf.transformedRegion;
} else {
mirrorModelClip.boundingLeaf = null;
mirrorModelClip.region = null;
}
if (bnds != null) {
mirrorModelClip.regionOfInfluence = bnds;
if (mirrorModelClip.region == null) {
mirrorModelClip.region = (Bounds)regionOfInfluence.clone();
mirrorModelClip.region.transform(regionOfInfluence, getLastLocalToVworld());
}
}
else {
mirrorModelClip.regionOfInfluence = null;
}
boolean[] ens = (boolean[])((Object[])args[4])[2];
for (int i = 0; i < ens.length; i++) {
mirrorModelClip.enables[i] = ens[i];
}
mirrorModelClip.enableFlag = mirrorModelClip.enables[0] |
mirrorModelClip.enables[1] |
mirrorModelClip.enables[2] |
mirrorModelClip.enables[3] |
mirrorModelClip.enables[4] |
mirrorModelClip.enables[5] ;
}
@Override
void updateMirrorObject(Object[] objs) {
int component = ((Integer)objs[1]).intValue();
if ((component & PLANES_CHANGED) != 0) {
Vector4d[] pl = ((Vector4d[]) objs[2]);
for (int i = 0; i < 6; i++) {
mirrorModelClip.xformPlanes[i].set(pl[i]);
}
}
else if ((component & PLANE_CHANGED) != 0) {
int planeNum = ((Integer)objs[2]).intValue();
mirrorModelClip.xformPlanes[planeNum].set((Vector4d)objs[3]);
}
else if ((component & INIT_MIRROR) != 0) {
Vector4d[] pl = (Vector4d[]) objs[3];
for (int i = 0; i < 6; i++) {
mirrorModelClip.xformPlanes[i].set(pl[i]);
}
}
}
// The update Object function.
void updateImmediateMirrorObject(Object[] objs) {
int component = ((Integer)objs[1]).intValue();
if ((component & BOUNDINGLEAF_CHANGED) != 0) {
mirrorModelClip.boundingLeaf = (BoundingLeafRetained)objs[2];
if (objs[2] != null) {
mirrorModelClip.region = mirrorModelClip.boundingLeaf.transformedRegion;
}
else {
if (mirrorModelClip.regionOfInfluence != null) {
mirrorModelClip.region = mirrorModelClip.regionOfInfluence.copy(mirrorModelClip.region);
mirrorModelClip.region.transform(mirrorModelClip.regionOfInfluence,
getCurrentLocalToVworld());
}
else {
mirrorModelClip.region = null;
}
}
}
if ((component & BOUNDS_CHANGED) != 0) {
mirrorModelClip.regionOfInfluence = (Bounds) objs[2];
if (mirrorModelClip.boundingLeaf == null) {
if (objs[2] != null) {
mirrorModelClip.region = mirrorModelClip.regionOfInfluence.copy(mirrorModelClip.region);
mirrorModelClip.region.transform(mirrorModelClip.regionOfInfluence,
getCurrentLocalToVworld());
}
else {
mirrorModelClip.region = null;
}
}
}
if ((component & SCOPE_CHANGED) != 0) {
Object[] scopeList = (Object[])objs[2];
ArrayList addList = (ArrayList)scopeList[0];
ArrayList removeList = (ArrayList)scopeList[1];
boolean isScoped = ((Boolean)scopeList[2]).booleanValue();
if (addList != null) {
mirrorModelClip.isScoped = isScoped;
for (int i = 0; i < addList.size(); i++) {
Shape3DRetained obj = ((GeometryAtom)addList.get(i)).source;
obj.addModelClip(mirrorModelClip);
}
}
if (removeList != null) {
mirrorModelClip.isScoped = isScoped;
for (int i = 0; i < removeList.size(); i++) {
Shape3DRetained obj = ((GeometryAtom)removeList.get(i)).source;
obj.removeModelClip(mirrorModelClip);
}
}
}
if ((component & ENABLES_CHANGED) != 0) {
Boolean[] en = ((Boolean[]) objs[2]);
mirrorModelClip.enables[0] = en[0].booleanValue();
mirrorModelClip.enables[1] = en[1].booleanValue();
mirrorModelClip.enables[2] = en[2].booleanValue();
mirrorModelClip.enables[3] = en[3].booleanValue();
mirrorModelClip.enables[4] = en[4].booleanValue();
mirrorModelClip.enables[5] = en[5].booleanValue();
mirrorModelClip.enableFlag = mirrorModelClip.enables[0] |
mirrorModelClip.enables[1] |
mirrorModelClip.enables[2] |
mirrorModelClip.enables[3] |
mirrorModelClip.enables[4] |
mirrorModelClip.enables[5] ;
} else if ((component & ENABLE_CHANGED) != 0) {
int planeNum = ((Integer)objs[2]).intValue();
mirrorModelClip.enables[planeNum] = ((Boolean)objs[3]).booleanValue();
mirrorModelClip.enableFlag = mirrorModelClip.enables[0] |
mirrorModelClip.enables[1] |
mirrorModelClip.enables[2] |
mirrorModelClip.enables[3] |
mirrorModelClip.enables[4] |
mirrorModelClip.enables[5] ;
}
}
/** Note: This routine will only be called on
* the mirror object - will update the object's
* cached region and transformed region
*/
@Override
void updateBoundingLeaf() {
if (boundingLeaf != null && boundingLeaf.switchState.currentSwitchOn) {
region = boundingLeaf.transformedRegion;
} else {
if (regionOfInfluence != null) {
region = regionOfInfluence.copy(region);
region.transform(regionOfInfluence, getCurrentLocalToVworld());
} else {
region = null;
}
}
}
@Override
void setLive(SetLiveState s) {
GroupRetained group;
super.doSetLive(s);
if (inSharedGroup) {
throw new
IllegalSharingException(J3dI18N.getString("ModelClipRetained1"));
}
// Create the mirror object
if (mirrorModelClip == null) {
mirrorModelClip = (ModelClipRetained)this.clone();
mirrorModelClip.boundingLeaf = null;
mirrorModelClip.sgModelClip = this;
}
if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
s.viewScopedNodeList.add(mirrorModelClip);
s.scopedNodesViewList.add(s.viewLists.get(0));
} else {
s.nodeList.add(mirrorModelClip);
}
// If bounding leaf is not null, add the mirror object as a user
// so that any changes to the bounding leaf will be received
if (boundingLeaf != null) {
boundingLeaf.mirrorBoundingLeaf.addUser(mirrorModelClip);
}
// process switch leaf
if (s.switchTargets != null &&
s.switchTargets[0] != null) {
s.switchTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS);
}
mirrorModelClip.switchState = s.switchStates.get(0);
// add this model clip to the transform target
if (s.transformTargets != null && s.transformTargets[0] != null) {
s.transformTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS);
s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
}
s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT|
J3dThread.UPDATE_RENDER;
super.markAsLive();
// Initialize the mirror object, this needs to be done, when
// renderBin is not accessing any of the fields
J3dMessage createMessage = new J3dMessage();
createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT;
createMessage.universe = universe;
createMessage.type = J3dMessage.MODELCLIP_CHANGED;
createMessage.args[0] = this;
// a snapshot of all attributes that needs to be initialized
// in the mirror object
createMessage.args[1]= new Integer(INIT_MIRROR);
ArrayList addScopeList = new ArrayList();
for (int i = 0; i < scopes.size(); i++) {
group = scopes.get(i);
tempKey.reset();
group.addAllNodesForScopedModelClip(mirrorModelClip, addScopeList, tempKey);
}
Object[] scopeInfo = new Object[2];
scopeInfo[0] = ((scopes.size() > 0) ? Boolean.TRUE:Boolean.FALSE);
scopeInfo[1] = addScopeList;
createMessage.args[2] = scopeInfo;
createMessage.args[3] = xformPlanes.clone();
Object[] obj = new Object[3];
obj[0] = boundingLeaf;
obj[1] = (regionOfInfluence != null?regionOfInfluence.clone():null);
obj[2] = enables.clone();
createMessage.args[4] = obj;
VirtualUniverse.mc.processMessage(createMessage);
}
/**
* This clearLive routine first calls the superclass's method, then
* it removes itself to the list of model clip
*/
@Override
void clearLive(SetLiveState s) {
super.clearLive(s);
s.notifyThreads |= J3dThread.UPDATE_RENDERING_ENVIRONMENT|
J3dThread.UPDATE_RENDER;
if (s.switchTargets != null &&
s.switchTargets[0] != null) {
s.switchTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS);
}
// Remove this mirror light as users of the bounding leaf
if (mirrorModelClip.boundingLeaf != null)
mirrorModelClip.boundingLeaf.removeUser(mirrorModelClip);
if ((s.viewScopedNodeList != null) && (s.viewLists != null)) {
s.viewScopedNodeList.add(mirrorModelClip);
s.scopedNodesViewList.add(s.viewLists.get(0));
} else {
s.nodeList.add(mirrorModelClip);
}
if (s.transformTargets != null && s.transformTargets[0] != null) {
s.transformTargets[0].addNode(mirrorModelClip, Targets.ENV_TARGETS);
s.notifyThreads |= J3dThread.UPDATE_TRANSFORM;
}
if (scopes.size() > 0) {
J3dMessage createMessage = new J3dMessage();
createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT;
createMessage.universe = universe;
createMessage.type = J3dMessage.MODELCLIP_CHANGED;
createMessage.args[0] = this;
createMessage.args[1]= new Integer(CLEAR_MIRROR);
ArrayList removeScopeList = new ArrayList();
for (int i = 0; i < scopes.size(); i++) {
GroupRetained group = scopes.get(i);
tempKey.reset();
group.removeAllNodesForScopedModelClip(mirrorModelClip, removeScopeList, tempKey);
}
createMessage.args[2] = removeScopeList;
VirtualUniverse.mc.processMessage(createMessage);
}
}
// This is called on the parent object
void clearMirrorObject(Object[] args) {
Shape3DRetained shape;
ArrayList shapeList = (ArrayList)args[2];
for (int i = 0; i < shapeList.size(); i++) {
shape = ((GeometryAtom)shapeList.get(i)).source;
shape.removeModelClip(mirrorModelClip);
}
mirrorModelClip.isScoped = false;
}
// Clone the retained side only, internal use only
@Override
protected Object clone() {
ModelClipRetained mc = (ModelClipRetained)super.clone();
mc.planes = new Vector4d[6];
for (int i = 0; i < 6; i++) {
mc.planes[i] = new Vector4d(this.planes[i]);
mc.xformPlanes[i] = new Vector4d(this.xformPlanes[i]);
}
mc.enables = new boolean[6];
getEnables(mc.enables);
// Derive the enables flag
mc.enableFlag = (mc.enables[0] |
mc.enables[1] |
mc.enables[2] |
mc.enables[3] |
mc.enables[4] |
mc.enables[5] );
mc.inImmCtx = false;
mc.region = null;
mc.sgModelClip = null;
mc.mirrorModelClip = null;
mc.environmentSets = new UnorderList(1, EnvironmentSet.class);
if (regionOfInfluence != null) {
mc.regionOfInfluence = (Bounds) regionOfInfluence.clone();
}
return mc;
}
// Called on mirror object
void updateImmediateTransformChange() {
// If bounding leaf is null, tranform the bounds object
if (boundingLeaf == null) {
if (regionOfInfluence != null) {
region = regionOfInfluence.copy(region);
region.transform(regionOfInfluence,
sgModelClip.getCurrentLocalToVworld());
}
}
}
void printPlane(int index, String string)
{
System.err.println(string + " : < " + planes[index].toString()
+ " > " + enables[index]);
}
void printPlanes(String string, Vector4d[] planes)
{
System.err.println(string);
printPlane(0, "[0]");
printPlane(1, "[1]");
printPlane(2, "[2]");
printPlane(3, "[3]");
printPlane(4, "[4]");
printPlane(5, "[5]");
}
void printEnables(String string, boolean[] enables)
{
System.err.println(string);
System.err.println("[0] : < " + enables[0] + " >");
System.err.println("[1] : < " + enables[1] + " >");
System.err.println("[2] : < " + enables[2] + " >");
System.err.println("[3] : < " + enables[3] + " >");
System.err.println("[4] : < " + enables[4] + " >");
System.err.println("[5] : < " + enables[5] + " >");
}
final void sendMessage(int attrMask, Object attr1, Object attr2) {
J3dMessage createMessage = new J3dMessage();
createMessage.threads = targetThreads;
createMessage.type = J3dMessage.MODELCLIP_CHANGED;
createMessage.universe = universe;
createMessage.args[0] = this;
createMessage.args[1]= new Integer(attrMask);
createMessage.args[2] = attr1;
createMessage.args[3] = attr2;
VirtualUniverse.mc.processMessage(createMessage);
}
@Override
void mergeTransform(TransformGroupRetained staticTransform) {
super.mergeTransform(staticTransform);
if (regionOfInfluence != null) {
regionOfInfluence.transform(staticTransform.transform);
}
Transform3D xform = staticTransform.getNormalTransform();
for (int i = 0; i < 6; i++) {
xform.transform(planes[i], xformPlanes[i]);
}
}
@Override
void getMirrorObjects(ArrayList leafList, HashKey key) {
leafList.add(mirrorModelClip);
}
}