001: /*
002: * $RCSfile: SwitchValueInterpolator.java,v $
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.5 $
028: * $Date: 2008/02/28 20:17:31 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.Enumeration;
035:
036: /**
037: * SwitchValueInterpolator behavior. This class defines a
038: * behavior that modifies the selected child of the target
039: * switch node by linearly interpolating between a pair of
040: * specified child index values (using the value generated
041: * by the specified Alpha object).
042: */
043:
044: public class SwitchValueInterpolator extends Interpolator {
045:
046: Switch target;
047: int firstSwitchIndex;
048: int lastSwitchIndex;
049: int childCount;
050:
051: // We can't use a boolean flag since it is possible
052: // that after alpha change, this procedure only run
053: // once at alpha.finish(). So the best way is to
054: // detect alpha value change.
055: private float prevAlphaValue = Float.NaN;
056: private WakeupCriterion passiveWakeupCriterion = (WakeupCriterion) new WakeupOnElapsedFrames(
057: 0, true);
058:
059: // non-public, default constructor used by cloneNode
060: SwitchValueInterpolator() {
061: }
062:
063: /**
064: * Constructs a SwitchValueInterpolator behavior that varies its target
065: * Switch node's child index between 0 and <i>n</i>-1, where <i>n</i>
066: * is the number of children in the target Switch node.
067: * @param alpha the alpha object for this interpolator
068: * @param target the Switch node affected by this interpolator
069: */
070: public SwitchValueInterpolator(Alpha alpha, Switch target) {
071:
072: super (alpha);
073:
074: this .target = target;
075: firstSwitchIndex = 0;
076: childCount = target.numChildren();
077: lastSwitchIndex = childCount - 1;
078:
079: }
080:
081: /**
082: * Constructs a SwitchValueInterpolator behavior that varies its target
083: * Switch node's child index between the two values provided.
084: * @param alpha the alpha object for this interpolator
085: * @param target the Switch node affected by this interpolator
086: * @param firstChildIndex the index of first child in the Switch node to
087: * select
088: * @param lastChildIndex the index of last child in the Switch node to
089: * select
090: */
091: public SwitchValueInterpolator(Alpha alpha, Switch target,
092: int firstChildIndex, int lastChildIndex) {
093:
094: super (alpha);
095:
096: this .target = target;
097: firstSwitchIndex = firstChildIndex;
098: lastSwitchIndex = lastChildIndex;
099: computeChildCount();
100: }
101:
102: /**
103: * This method sets the firstChildIndex for this interpolator.
104: * @param firstIndex the new index for the first child
105: */
106: public void setFirstChildIndex(int firstIndex) {
107: firstSwitchIndex = firstIndex;
108: computeChildCount();
109: }
110:
111: /**
112: * This method retrieves this interpolator's firstChildIndex.
113: * @return the interpolator's firstChildIndex
114: */
115: public int getFirstChildIndex() {
116: return this .firstSwitchIndex;
117: }
118:
119: /**
120: * This method sets the lastChildIndex for this interpolator.
121: * @param lastIndex the new index for the last child
122: */
123: public void setLastChildIndex(int lastIndex) {
124: lastSwitchIndex = lastIndex;
125: computeChildCount();
126: }
127:
128: /**
129: * This method retrieves this interpolator's lastSwitchIndex.
130: * @return the interpolator's maximum scale value
131: */
132: public int getLastChildIndex() {
133: return this .lastSwitchIndex;
134: }
135:
136: /**
137: * This method sets the target for this interpolator.
138: * @param target the target Switch node
139: */
140: public void setTarget(Switch target) {
141: this .target = target;
142: }
143:
144: /**
145: * This method retrieves this interpolator's target Switch node
146: * reference.
147: * @return the interpolator's target Switch node
148: */
149: public Switch getTarget() {
150: return target;
151: }
152:
153: // The SwitchValueInterpolator's initialize routine uses the default
154: // initialization routine.
155:
156: /**
157: * This method is invoked by the behavior scheduler every frame.
158: * It maps the alpha value that corresponds to the current time
159: * into a child index value and updates the specified Switch node
160: * with this new child index value.
161: * @param criteria an enumeration of the criteria that triggered
162: * this stimulus
163: */
164: public void processStimulus(Enumeration criteria) {
165: // Handle stimulus
166: WakeupCriterion criterion = passiveWakeupCriterion;
167:
168: if (alpha != null) {
169: float value = alpha.value();
170:
171: if (value != prevAlphaValue) {
172: int child;
173:
174: if (lastSwitchIndex > firstSwitchIndex) {
175: child = (int) (firstSwitchIndex + (int) (value
176: * (childCount - 1) + 0.49999999999f));
177: } else {
178: child = (int) (firstSwitchIndex - (int) (value
179: * (childCount - 1) + 0.49999999999f));
180: }
181: target.setWhichChild(child);
182: prevAlphaValue = value;
183: }
184: if (!alpha.finished() && !alpha.isPaused()) {
185: criterion = defaultWakeupCriterion;
186: }
187: }
188: wakeupOn(criterion);
189: }
190:
191: /**
192: * calculate the number of the child to manage for this switch node
193: */
194: final private void computeChildCount() {
195: if (lastSwitchIndex >= firstSwitchIndex) {
196: childCount = lastSwitchIndex - firstSwitchIndex + 1;
197: } else {
198: childCount = firstSwitchIndex - lastSwitchIndex + 1;
199: }
200: }
201:
202: /**
203: * Used to create a new instance of the node. This routine is called
204: * by <code>cloneTree</code> to duplicate the current node.
205: * @param forceDuplicate when set to <code>true</code>, causes the
206: * <code>duplicateOnCloneTree</code> flag to be ignored. When
207: * <code>false</code>, the value of each node's
208: * <code>duplicateOnCloneTree</code> variable determines whether
209: * NodeComponent data is duplicated or copied.
210: *
211: * @see Node#cloneTree
212: * @see Node#cloneNode
213: * @see Node#duplicateNode
214: * @see NodeComponent#setDuplicateOnCloneTree
215: */
216: public Node cloneNode(boolean forceDuplicate) {
217: SwitchValueInterpolator svi = new SwitchValueInterpolator();
218: svi.duplicateNode(this , forceDuplicate);
219: return svi;
220: }
221:
222: /**
223: * Copies all SwitchValueInterpolator information from
224: * <code>originalNode</code> into
225: * the current node. This method is called from the
226: * <code>cloneNode</code> method which is, in turn, called by the
227: * <code>cloneTree</code> method.<P>
228: *
229: * @param originalNode the original node to duplicate.
230: * @param forceDuplicate when set to <code>true</code>, causes the
231: * <code>duplicateOnCloneTree</code> flag to be ignored. When
232: * <code>false</code>, the value of each node's
233: * <code>duplicateOnCloneTree</code> variable determines whether
234: * NodeComponent data is duplicated or copied.
235: *
236: * @exception RestrictedAccessException if this object is part of a live
237: * or compiled scenegraph.
238: *
239: * @see Node#duplicateNode
240: * @see Node#cloneTree
241: * @see NodeComponent#setDuplicateOnCloneTree
242: */
243: void duplicateAttributes(Node originalNode, boolean forceDuplicate) {
244: super .duplicateAttributes(originalNode, forceDuplicate);
245:
246: SwitchValueInterpolator si = (SwitchValueInterpolator) originalNode;
247:
248: setFirstChildIndex(si.getFirstChildIndex());
249: setLastChildIndex(si.getLastChildIndex());
250: // this reference will be updated in updateNodeReferences()
251: setTarget(si.getTarget());
252: }
253:
254: /**
255: * Callback used to allow a node to check if any nodes referenced
256: * by that node have been duplicated via a call to <code>cloneTree</code>.
257: * This method is called by <code>cloneTree</code> after all nodes in
258: * the sub-graph have been duplicated. The cloned Leaf node's method
259: * will be called and the Leaf node can then look up any node references
260: * by using the <code>getNewObjectReference</code> method found in the
261: * <code>NodeReferenceTable</code> object. If a match is found, a
262: * reference to the corresponding Node in the newly cloned sub-graph
263: * is returned. If no corresponding reference is found, either a
264: * DanglingReferenceException is thrown or a reference to the original
265: * node is returned depending on the value of the
266: * <code>allowDanglingReferences</code> parameter passed in the
267: * <code>cloneTree</code> call.
268: * <p>
269: * NOTE: Applications should <i>not</i> call this method directly.
270: * It should only be called by the cloneTree method.
271: *
272: * @param referenceTable a NodeReferenceTableObject that contains the
273: * <code>getNewObjectReference</code> method needed to search for
274: * new object instances.
275: * @see NodeReferenceTable
276: * @see Node#cloneTree
277: * @see DanglingReferenceException
278: */
279: public void updateNodeReferences(NodeReferenceTable referenceTable) {
280: super .updateNodeReferences(referenceTable);
281:
282: // check Switch
283: Node n = getTarget();
284:
285: if (n != null) {
286: setTarget((Switch) referenceTable.getNewObjectReference(n));
287: }
288: }
289: }
|