/* * Copyright 1997-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; /** * The BoundingLeaf node defines a bounding region object that can be * referenced by other nodes to define a region of influence, an * application region, or a scheduling region. */ class BoundingLeafRetained extends LeafRetained { // Statics used when something in the boundingleaf changes static final int REGION_CHANGED = 0x0001; static final Integer REGION_CHANGED_MESSAGE = new Integer(REGION_CHANGED); // The bounding region object defined by this node Bounds region = null; // For the mirror object, this region is the transformed region // (the region of the original bounding leaf object transformed // by the cache transform) Bounds transformedRegion = null; BoundingLeafRetained mirrorBoundingLeaf; // A list of Objects that refer, directly or indirectly, to this // bounding leaf object ArrayList users = new ArrayList(); // Target threads to be notified when light changes int targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | J3dThread.UPDATE_RENDER; // Target threads for tranform change int transformTargetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | J3dThread.UPDATE_GEOMETRY; BoundingLeafRetained() { this.nodeType = NodeRetained.BOUNDINGLEAF; } void createBoundingLeaf() { this.nodeType = NodeRetained.BOUNDINGLEAF; mirrorBoundingLeaf = new BoundingLeafRetained(); } /** * Initialize the bounding region */ void initRegion(Bounds region) { if (region != null) { this.region = (Bounds) region.clone(); } else { this.region = null; } if (staticTransform != null) { this.region.transform(staticTransform.transform); } } /** * Set the bounding region */ void setRegion(Bounds region) { initRegion(region); J3dMessage createMessage = new J3dMessage(); createMessage.threads = mirrorBoundingLeaf.targetThreads; createMessage.type = J3dMessage.BOUNDINGLEAF_CHANGED; createMessage.universe = universe; createMessage.args[0] = this; createMessage.args[1]= REGION_CHANGED_MESSAGE; if (region != null) { createMessage.args[2] = (Bounds)(region.clone()); } else { createMessage.args[2] = null; } createMessage.args[3] = mirrorBoundingLeaf.users.toArray(); VirtualUniverse.mc.processMessage(createMessage); } /** * Get the bounding region */ Bounds getRegion() { Bounds b = null; if (this.region != null) { b = (Bounds) this.region.clone(); if (staticTransform != null) { Transform3D invTransform = staticTransform.getInvTransform(); b.transform(invTransform); } } return b; } @Override void setLive(SetLiveState s) { super.doSetLive(s); if (inBackgroundGroup) { throw new IllegalSceneGraphException(J3dI18N.getString("BoundingLeafRetained0")); } if (inSharedGroup) { throw new IllegalSharingException(J3dI18N.getString("BoundingLeafRetained1")); } if (s.transformTargets != null && s.transformTargets[0] != null) { s.transformTargets[0].addNode(mirrorBoundingLeaf, Targets.BLN_TARGETS); s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; } mirrorBoundingLeaf.localToVworld = new Transform3D[1][]; mirrorBoundingLeaf.localToVworldIndex = new int[1][]; mirrorBoundingLeaf.localToVworld[0] = this.localToVworld[0]; mirrorBoundingLeaf.localToVworldIndex[0] = this.localToVworldIndex[0]; mirrorBoundingLeaf.parent = parent; if (region != null) { mirrorBoundingLeaf.region = (Bounds)region.clone(); mirrorBoundingLeaf.transformedRegion = (Bounds)region.clone(); mirrorBoundingLeaf.transformedRegion.transform( mirrorBoundingLeaf.getCurrentLocalToVworld()); } else { mirrorBoundingLeaf.region = null; mirrorBoundingLeaf.transformedRegion = null; } // process switch leaf if (s.switchTargets != null && s.switchTargets[0] != null) { s.switchTargets[0].addNode(mirrorBoundingLeaf, Targets.BLN_TARGETS); } mirrorBoundingLeaf.switchState = s.switchStates.get(0); super.markAsLive(); } /** Update the "component" field of the mirror object with the * given "value" */ synchronized void updateImmediateMirrorObject(Object[] objs) { int component = ((Integer)objs[1]).intValue(); Bounds b = ((Bounds)objs[2]); Transform3D t; if ((component & REGION_CHANGED) != 0) { mirrorBoundingLeaf.region = b; if (b != null) { mirrorBoundingLeaf.transformedRegion = (Bounds)b.clone(); t = mirrorBoundingLeaf.getCurrentLocalToVworld(); mirrorBoundingLeaf.transformedRegion.transform(b, t); } else { mirrorBoundingLeaf.transformedRegion = null; } } } /** * Add a user to the list of users. * There is no if (node.source.isLive()) check since * mirror objects are the users of the mirror bounding leaf * and they do not have a source. */ synchronized void addUser(LeafRetained node) { users.add(node); if (node.nodeType == NodeRetained.BACKGROUND || node.nodeType == NodeRetained.CLIP || node.nodeType == NodeRetained.ALTERNATEAPPEARANCE || node instanceof FogRetained || node instanceof LightRetained) { transformTargetThreads |= J3dThread.UPDATE_RENDER; } else if (node instanceof BehaviorRetained) { transformTargetThreads |= J3dThread.UPDATE_BEHAVIOR; targetThreads |= J3dThread.UPDATE_BEHAVIOR; } else if (node instanceof SoundRetained || node.nodeType == NodeRetained.SOUNDSCAPE) { transformTargetThreads |= J3dThread.UPDATE_SOUND; } } /** * Remove user from the list of users. * There is no if (node.source.isLive()) check since * mirror objects are the users of the mirror bounding leaf * and they do not have a source. */ synchronized void removeUser(LeafRetained u) { int i; users.remove(users.indexOf(u)); // For now reconstruct the transform target threads from scratch transformTargetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT; targetThreads = J3dThread.UPDATE_RENDERING_ENVIRONMENT | J3dThread.UPDATE_RENDER; for (i =0; i < users.size(); i++) { LeafRetained node = (LeafRetained)users.get(i); if (node.nodeType == NodeRetained.BACKGROUND || node.nodeType == NodeRetained.CLIP || node.nodeType == NodeRetained.ALTERNATEAPPEARANCE || node instanceof FogRetained || node instanceof LightRetained) { transformTargetThreads |= J3dThread.UPDATE_RENDER; } else if (node.nodeType == NodeRetained.BEHAVIOR) { transformTargetThreads |= J3dThread.UPDATE_BEHAVIOR; targetThreads |= J3dThread.UPDATE_BEHAVIOR; } else if (node instanceof SoundRetained || node.nodeType == NodeRetained.SOUNDSCAPE) { transformTargetThreads |= J3dThread.UPDATE_SOUND; } } } // This function is called on the mirror bounding leaf void updateImmediateTransformChange() { Transform3D t; t = getCurrentLocalToVworld(); if (region != null) { transformedRegion.transform(region, t); } } @Override void clearLive(SetLiveState s) { super.clearLive(); if (s.switchTargets != null && s.switchTargets[0] != null) { s.switchTargets[0].addNode(mirrorBoundingLeaf, Targets.BLN_TARGETS); } if (s.transformTargets != null && s.transformTargets[0] != null) { s.transformTargets[0].addNode(mirrorBoundingLeaf, Targets.BLN_TARGETS); s.notifyThreads |= J3dThread.UPDATE_TRANSFORM; } } @Override void mergeTransform(TransformGroupRetained xform) { super.mergeTransform(xform); region.transform(xform.transform); } }