/* * Copyright 1996-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 java.util.BitSet; /** * The switch node controls which one of its children will be rendered. */ class SwitchRetained extends GroupRetained implements TargetsInterface { static final int GEO_NODES = 0x0001; static final int ENV_NODES = 0x0002; static final int BEHAVIOR_NODES = 0x0004; static final int SOUND_NODES = 0x0008; static final int BOUNDINGLEAF_NODES = 0x0010; /** * The value specifing which child to render. */ int whichChild = Switch.CHILD_NONE; /** * The BitSet specifying which children are to be selected for * rendering. This is used ONLY if whichChild is set to CHILD_MASK. */ BitSet childMask = new BitSet(); /** * The childmask bitset used for rendering */ BitSet renderChildMask = new BitSet(); // A boolean indication that something changed boolean isDirty = true; // switchLevel per key, used in traversing switch children ArrayList switchLevels = new ArrayList(1); // key which identifies a unique path from a locale to this switch link HashKey switchKey = new HashKey(); // switch index counter to identify specific children int switchIndexCount = 0; // for message processing UpdateTargets updateTargets = null; ArrayList> childrenSwitchStates = null; SwitchRetained() { this.nodeType = NodeRetained.SWITCH; } /** * Sets which child should be drawn. * @param whichChild the child to choose during a render operation */ // synchronized with clearLive synchronized void setWhichChild(int whichChild, boolean updateAlways) { int i, nchildren; this.whichChild = whichChild; isDirty = true; if (source != null && source.isLive()) { updateTargets = new UpdateTargets(); ArrayList updateList = new ArrayList(1); nchildren = children.size(); switch (whichChild) { case Switch.CHILD_ALL: for (i=0; i this.childMask.size()) { nbits = childMask.size(); } else { nbits = this.childMask.size(); } for (i=0; i updateList = new ArrayList(1); nchildren = children.size(); for (i=0; i updateList) { J3dMessage m ; int i,j,size,threads; Object[] nodesArr, nodes; threads = updateTargets.computeSwitchThreads(); if (threads > 0) { m = new J3dMessage(); m.type = J3dMessage.SWITCH_CHANGED; m.universe = universe; m.threads = threads; m.args[0] = updateTargets; m.args[2] = updateList; UnorderList blnList = updateTargets.targetList[Targets.BLN_TARGETS]; if (blnList != null) { BoundingLeafRetained mbleaf; size = blnList.size(); Object[] boundingLeafUsersArr = new Object[size]; nodesArr = blnList.toArray(false); for (j=0; j= children.size())) return null; else return getChild(whichChild); } void updateSwitchChild(int child, boolean switchOn, ArrayList updateList) { int i; int switchLevel; if (inSharedGroup) { for (i=0; i switchStates; // Group's setAuxData() super.setAuxData(s, index, hkIndex); switchLevels.add(new Integer(s.switchLevels[index])); int nchildren = children.size(); for (int i=0; i= 0) { setAuxData(s, j, hkIndex); } else { MasterControl.getCoreLogger().severe("Can't Find matching hashKey in setNodeData."); } s.hashkeyIndex[j] = hkIndex; } } } @Override void setLive(SetLiveState s) { int i,j,k; boolean switchOn; SwitchRetained switchRoot; int size; // save setLiveState Targets[] savedSwitchTargets = s.switchTargets; ArrayList savedSwitchStates = s.switchStates; SwitchRetained[] savedClosestSwitchParents = s.closestSwitchParents; int[] savedClosestSwitchIndices = s.closestSwitchIndices; ArrayList savedChildSwitchLinks = s.childSwitchLinks; GroupRetained savedParentSwitchLink = s.parentSwitchLink; int[] savedHashkeyIndex = s.hashkeyIndex; // update setLiveState for this node s.closestSwitchParents = (SwitchRetained[]) savedClosestSwitchParents.clone(); s.closestSwitchIndices = Arrays.copyOf(savedClosestSwitchIndices, savedClosestSwitchIndices.length); // Note that s.containsNodesList is updated in super.setLive // Note that s.closestSwitchIndices is updated in super.setLive for (i=0; i< s.switchLevels.length; i++) { s.switchLevels[i]++; s.closestSwitchParents[i] = this; } super.doSetLive(s); initRenderChildMask(); // update switch leaves' compositeSwitchMask // and update switch leaves' switchOn flag if this is top level switch if (inSharedGroup) { for (i=0; i switchStates; if (refCount <= 0) { // remove this node from parentSwitchLink's childSwitchLinks // clear childSwitchLinks if (parentSwitchLink != null) { for(i=0; i switchLinks = parentSwitchLink.childrenSwitchLinks.get(i); if (switchLinks.contains(this)) { switchLinks.remove(this); break; } } } for (j=0; j= 0; i--) { hkIndex = s.keys[i].equals(localToVworldKeys, 0, localToVworldKeys.length); if(hkIndex >= 0) { for (j=0; j updateList) { int i,j,k; SwitchRetained sw; LinkRetained ln; Object obj; boolean newSwChanged = false; ArrayList childSwitchStates = childrenSwitchStates.get(child); SwitchState switchState = childSwitchStates.get(index); switchState.updateCompositeSwitchMask(switchLevel, switchOn); if (switchRoot != null) { if (init) { if (!switchState.initialized) { switchState.initSwitchOn(); } } else { boolean compositeSwitchOn = switchState.evalCompositeSwitchOn(); if (switchState.cachedSwitchOn != compositeSwitchOn) { switchState.updateCachedSwitchOn(); switchRoot.updateTargets.addCachedTargets( switchState.cachedTargets); newSwChanged = true; updateList.add(switchState); } } } ArrayList childSwitchLinks = childrenSwitchLinks.get(child); int cslSize =childSwitchLinks.size(); for (i=0; i= 0 && whichChild < children.size()) { NodeRetained child = children.get(whichChild); if (child != null) { child.computeCombineBounds(boundingObject); } } return boundingObject; } else { return super.getBounds(); } } /* void compile(CompileState compState) { setCompiled(); compState.startGroup(null); // don't merge at this level compileChildren(compState); compState.endGroup(); } */ /** * Compiles the children of the switch, preventing shape merging at * this level or above */ @Override void compile(CompileState compState) { super.compile(compState); // don't remove this group node mergeFlag = SceneGraphObjectRetained.DONT_MERGE; if (J3dDebug.devPhase && J3dDebug.debug) { compState.numSwitches++; } } @Override void insertChildrenData(int index) { if (childrenSwitchStates == null) { childrenSwitchStates = new ArrayList>(1); childrenSwitchLinks = new ArrayList>(1); } childrenSwitchLinks.add(index, new ArrayList(1)); ArrayList switchStates = new ArrayList(1); childrenSwitchStates.add(index, switchStates); if (source != null && source.isLive()) { for (int i=0; i>(1); childrenSwitchLinks = new ArrayList>(1); } childrenSwitchLinks.add(new ArrayList(1)); ArrayList switchStates = new ArrayList(1); childrenSwitchStates.add(switchStates); if (source != null && source.isLive()) { for (int i=0; i oldSwitchStates = childrenSwitchStates.get(index); oldSwitchStates.clear(); childrenSwitchStates.remove(index); ArrayList oldSwitchLinks = childrenSwitchLinks.get(index); oldSwitchLinks.clear(); childrenSwitchLinks.remove(index); } @Override void childDoSetLive(NodeRetained child, int childIndex, SetLiveState s) { int numPaths = (inSharedGroup)? s.keys.length : 1; s.childSwitchLinks = childrenSwitchLinks.get(childIndex); for (int j=0; j< numPaths; j++) { s.closestSwitchIndices[j] = switchIndexCount; s.closestSwitchParents[j] = this; } // use switchIndexCount instead of child index to avoid // reordering due to add/remove child later switchIndexCount++; Targets[] newTargets = new Targets[numPaths]; for(int i=0; i switchStates = childrenSwitchStates.get(child); if (index < switchStates.size()) { SwitchState switchState = switchStates.get(index); return switchState.cachedTargets; } else { return null; } } else { System.err.println("getCachedTargets: wrong arguments"); return null; } } @Override public void resetCachedTargets(int type, CachedTargets[] newCtArr, int child) { if (type == TargetsInterface.SWITCH_TARGETS) { ArrayList switchStates = childrenSwitchStates.get(child); if (newCtArr.length != switchStates.size()) { System.err.println("resetCachedTargets: unmatched length!" + newCtArr.length + " " + switchStates.size()); System.err.println(" resetCachedTargets: " + this); } SwitchState switchState; for (int i=0; i getTargetsData(int type, int child) { if (type == TargetsInterface.SWITCH_TARGETS) { return childrenSwitchStates.get(child); } else { System.err.println("getTargetsData: wrong arguments"); return null; } } @Override public int getTargetThreads(int type) { System.err.println("getTargetsThreads: wrong arguments"); return -1; } @Override public void updateCachedTargets(int type, CachedTargets[] newCt) { System.err.println("updateCachedTarget: wrong arguments"); } @Override public void computeTargetThreads(int type, CachedTargets[] newCt) { System.err.println("computeTargetThreads: wrong arguments"); } @Override public void updateTargetThreads(int type, CachedTargets[] newCt) { System.err.println("updateTargetThreads: wrong arguments"); } @Override public void propagateTargetThreads(int type, int newTargetThreads) { System.err.println("propagateTargetThreads: wrong arguments"); } @Override public void copyCachedTargets(int type, CachedTargets[] newCt) { System.err.println("copyCachedTarget: wrong arguments"); } }