Java tutorial
/* * 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.Enumeration; /** * SwitchValueInterpolator behavior. This class defines a * behavior that modifies the selected child of the target * switch node by linearly interpolating between a pair of * specified child index values (using the value generated * by the specified Alpha object). */ public class SwitchValueInterpolator extends Interpolator { Switch target; int firstSwitchIndex; int lastSwitchIndex; int childCount; // We can't use a boolean flag since it is possible // that after alpha change, this procedure only run // once at alpha.finish(). So the best way is to // detect alpha value change. private float prevAlphaValue = Float.NaN; private WakeupCriterion passiveWakeupCriterion = new WakeupOnElapsedFrames(0, true); // non-public, default constructor used by cloneNode SwitchValueInterpolator() { } /** * Constructs a SwitchValueInterpolator behavior that varies its target * Switch node's child index between 0 and <i>n</i>-1, where <i>n</i> * is the number of children in the target Switch node. * @param alpha the alpha object for this interpolator * @param target the Switch node affected by this interpolator */ public SwitchValueInterpolator(Alpha alpha, Switch target) { super(alpha); this.target = target; firstSwitchIndex = 0; childCount = target.numChildren(); lastSwitchIndex = childCount - 1; } /** * Constructs a SwitchValueInterpolator behavior that varies its target * Switch node's child index between the two values provided. * @param alpha the alpha object for this interpolator * @param target the Switch node affected by this interpolator * @param firstChildIndex the index of first child in the Switch node to * select * @param lastChildIndex the index of last child in the Switch node to * select */ public SwitchValueInterpolator(Alpha alpha, Switch target, int firstChildIndex, int lastChildIndex) { super(alpha); this.target = target; firstSwitchIndex = firstChildIndex; lastSwitchIndex = lastChildIndex; computeChildCount(); } /** * This method sets the firstChildIndex for this interpolator. * @param firstIndex the new index for the first child */ public void setFirstChildIndex(int firstIndex) { firstSwitchIndex = firstIndex; computeChildCount(); } /** * This method retrieves this interpolator's firstChildIndex. * @return the interpolator's firstChildIndex */ public int getFirstChildIndex() { return this.firstSwitchIndex; } /** * This method sets the lastChildIndex for this interpolator. * @param lastIndex the new index for the last child */ public void setLastChildIndex(int lastIndex) { lastSwitchIndex = lastIndex; computeChildCount(); } /** * This method retrieves this interpolator's lastSwitchIndex. * @return the interpolator's maximum scale value */ public int getLastChildIndex() { return this.lastSwitchIndex; } /** * This method sets the target for this interpolator. * @param target the target Switch node */ public void setTarget(Switch target) { this.target = target; } /** * This method retrieves this interpolator's target Switch node * reference. * @return the interpolator's target Switch node */ public Switch getTarget() { return target; } // The SwitchValueInterpolator's initialize routine uses the default // initialization routine. /** * This method is invoked by the behavior scheduler every frame. * It maps the alpha value that corresponds to the current time * into a child index value and updates the specified Switch node * with this new child index value. * @param criteria an enumeration of the criteria that triggered * this stimulus */ @Override public void processStimulus(Enumeration criteria) { // Handle stimulus WakeupCriterion criterion = passiveWakeupCriterion; if (alpha != null) { float value = alpha.value(); if (value != prevAlphaValue) { int child; if (lastSwitchIndex > firstSwitchIndex) { child = (int) (firstSwitchIndex + (int) (value * (childCount - 1) + 0.49999999999f)); } else { child = (int) (firstSwitchIndex - (int) (value * (childCount - 1) + 0.49999999999f)); } target.setWhichChild(child); prevAlphaValue = value; } if (!alpha.finished() && !alpha.isPaused()) { criterion = defaultWakeupCriterion; } } wakeupOn(criterion); } /** * calculate the number of the child to manage for this switch node */ final private void computeChildCount() { if (lastSwitchIndex >= firstSwitchIndex) { childCount = lastSwitchIndex - firstSwitchIndex + 1; } else { childCount = firstSwitchIndex - lastSwitchIndex + 1; } } /** * Used to create a new instance of the node. This routine is called * by <code>cloneTree</code> to duplicate the current node. * @param forceDuplicate when set to <code>true</code>, causes the * <code>duplicateOnCloneTree</code> flag to be ignored. When * <code>false</code>, the value of each node's * <code>duplicateOnCloneTree</code> variable determines whether * NodeComponent data is duplicated or copied. * * @see Node#cloneTree * @see Node#cloneNode * @see Node#duplicateNode * @see NodeComponent#setDuplicateOnCloneTree */ @Override public Node cloneNode(boolean forceDuplicate) { SwitchValueInterpolator svi = new SwitchValueInterpolator(); svi.duplicateNode(this, forceDuplicate); return svi; } /** * Copies all SwitchValueInterpolator information from * <code>originalNode</code> into * the current node. This method is called from the * <code>cloneNode</code> method which is, in turn, called by the * <code>cloneTree</code> method.<P> * * @param originalNode the original node to duplicate. * @param forceDuplicate when set to <code>true</code>, causes the * <code>duplicateOnCloneTree</code> flag to be ignored. When * <code>false</code>, the value of each node's * <code>duplicateOnCloneTree</code> variable determines whether * NodeComponent data is duplicated or copied. * * @exception RestrictedAccessException if this object is part of a live * or compiled scenegraph. * * @see Node#duplicateNode * @see Node#cloneTree * @see NodeComponent#setDuplicateOnCloneTree */ @Override void duplicateAttributes(Node originalNode, boolean forceDuplicate) { super.duplicateAttributes(originalNode, forceDuplicate); SwitchValueInterpolator si = (SwitchValueInterpolator) originalNode; setFirstChildIndex(si.getFirstChildIndex()); setLastChildIndex(si.getLastChildIndex()); // this reference will be updated in updateNodeReferences() setTarget(si.getTarget()); } /** * Callback used to allow a node to check if any nodes referenced * by that node have been duplicated via a call to <code>cloneTree</code>. * This method is called by <code>cloneTree</code> after all nodes in * the sub-graph have been duplicated. The cloned Leaf node's method * will be called and the Leaf node can then look up any node references * by using the <code>getNewObjectReference</code> method found in the * <code>NodeReferenceTable</code> object. If a match is found, a * reference to the corresponding Node in the newly cloned sub-graph * is returned. If no corresponding reference is found, either a * DanglingReferenceException is thrown or a reference to the original * node is returned depending on the value of the * <code>allowDanglingReferences</code> parameter passed in the * <code>cloneTree</code> call. * <p> * NOTE: Applications should <i>not</i> call this method directly. * It should only be called by the cloneTree method. * * @param referenceTable a NodeReferenceTableObject that contains the * <code>getNewObjectReference</code> method needed to search for * new object instances. * @see NodeReferenceTable * @see Node#cloneTree * @see DanglingReferenceException */ @Override public void updateNodeReferences(NodeReferenceTable referenceTable) { super.updateNodeReferences(referenceTable); // check Switch Node n = getTarget(); if (n != null) { setTarget((Switch) referenceTable.getNewObjectReference(n)); } } }