2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 package com.jme.scene;
35 import java.io.IOException;
37 import com.jme.math.Vector3f;
38 import com.jme.system.JmeException;
39 import com.jme.util.export.InputCapsule;
40 import com.jme.util.export.JMEExporter;
41 import com.jme.util.export.JMEImporter;
42 import com.jme.util.export.OutputCapsule;
45 * <code>DistanceSwitchModel</code> defines a <code>SwitchModel</code> for
46 * selecting a child node based on the current distance from the containing node
47 * to the camera. This can be used with the <code>DiscreteLodNode</code>
48 * subclass of <code>SwitchNode</code> to all the detail level to decrease as
49 * the camera travels futher away from the object. The number of children to
50 * switch between is provided and the distances are also set. So, each child
51 * would have a minimum distance and a maximum distance. The child selected is
52 * the one that the camera to model distance is between the a particular child's
53 * min and max. If no values are valid, SN_INVALID_CHILD is returned.
56 * @version $Id: DistanceSwitchModel.java,v 1.2 2004/03/13 18:07:56 mojomonkey
59 public class DistanceSwitchModel implements SwitchModel {
61 private float[] modelMin;
63 private float[] modelMax;
65 private float[] worldMin;
67 private float[] worldMax;
69 private int numChildren;
71 private float worldScaleSquared;
73 private Vector3f diff;
75 public DistanceSwitchModel() {}
78 * Constructor instantiates a new <code>DistanceSwitchModel</code> object
79 * with the number of children to select from.
82 * the number of children this model selects from.
84 public DistanceSwitchModel(int numChildren) {
85 this.numChildren = numChildren;
86 modelMin = new float[numChildren];
87 modelMax = new float[numChildren];
88 worldMin = new float[numChildren];
89 worldMax = new float[numChildren];
93 * Returns the number of children that distances exist for.
96 public int getNumChildren() {
101 * Gets the minimum distance for this spatial index.
105 public float getModelMinDistance(int index) {
106 return modelMin[index];
110 * Gets the maximum distance for this spatial index.
114 public float getModelMaxDistance(int index) {
115 return modelMax[index];
120 * <code>setModelMinDistance</code> sets the minimum distance that a
121 * particular child should be used.
124 * the index of the child.
126 * the minimum of this child.
128 public void setModelMinDistance(int index, float minDist) {
129 if(index >= numChildren) {
130 reallocateArrays(index + 1);
133 modelMin[index] = minDist;
137 * Creates larger arrays for the max and mins while copying existing data.
140 private void reallocateArrays(int newLength) {
141 // create the new arrays
142 float modelMinNew[] = new float[newLength];
143 float modelMaxNew[] = new float[newLength];
144 float worldMinNew[] = new float[newLength];
145 float worldMaxNew[] = new float[newLength];
148 for(int i = 0; i < numChildren; i++) {
149 modelMinNew[i] = modelMin[i];
150 modelMaxNew[i] = modelMax[i];
151 worldMinNew[i] = worldMin[i];
152 worldMaxNew[i] = worldMax[i];
156 modelMin = modelMinNew;
157 modelMax = modelMaxNew;
158 worldMin = worldMinNew;
159 worldMax = worldMaxNew;
160 numChildren = newLength;
164 * <code>setModelMaxDistance</code> sets the maximum distance that a
165 * particular child should be used.
168 * the index of the child.
170 * the maximum of this child.
172 public void setModelMaxDistance(int index, float maxDist) {
173 if(index >= numChildren) {
174 reallocateArrays(index + 1);
177 modelMax[index] = maxDist;
182 * <code>setModelDistance</code> sets the minimum and maximum distance
183 * that a particular child should be used.
186 * the index of the child.
188 * the minimum of this child.
190 * the maximum of this child.
192 public void setModelDistance(int index, float minDist, float maxDist) {
193 if(index >= numChildren) {
194 reallocateArrays(index + 1);
197 modelMin[index] = minDist;
198 modelMax[index] = maxDist;
202 * <code>set</code> accepts Float and Vector3f objects to set the
203 * properties of the distance switch model. If the value passed is a Float
204 * object, this value is used to determine the world scale (squared) value,
205 * which allows the adjustment of the min and max distances for switching.
206 * If the value passed is a Vector3f, that is used to set the difference of
207 * the switch node and a comparison point which is typically the camera
211 * either Float - the world scale squared value, or Vector3f -
212 * the difference between the switch node and a location.
214 public void set(Object value) {
215 if (value instanceof Float) {
217 worldScaleSquared = ((Float) value).floatValue();
219 for (int i = 0; i < numChildren; i++) {
220 worldMin[i] = worldScaleSquared * modelMin[i] * modelMin[i];
221 worldMax[i] = worldScaleSquared * modelMax[i] * modelMax[i];
223 } else if (value instanceof Vector3f) {
224 diff = (Vector3f) value;
226 throw new JmeException("Invalid value for set method.");
231 * <code>getSwitchChild</code> returns the index of the child that should
232 * be switched on. The current distance between the parent switch node and a
233 * supplied point is used to determine the valid child.
235 * @return the index of the valid child.
237 public int getSwitchChild() {
238 // select the switch child
239 if (numChildren > 0) {
240 float sqrDistance = diff.lengthSquared();
242 for (int i = 0; i < numChildren; i++) {
243 if (worldMin[i] <= sqrDistance && sqrDistance < worldMax[i]) {
249 return SwitchNode.SN_INVALID_CHILD;
252 public void write(JMEExporter e) throws IOException {
253 OutputCapsule capsule = e.getCapsule(this);
255 capsule.write(modelMin, "modelMin", new float[0]);
256 capsule.write(modelMax, "modelMax", new float[0]);
257 capsule.write(worldMin, "worldMin", new float[0]);
258 capsule.write(worldMax, "worldMax", new float[0]);
259 capsule.write(numChildren, "numChildren", 0);
260 capsule.write(worldScaleSquared, "worldScaleSquared", 0);
261 capsule.write(diff, "diff", Vector3f.ZERO);
264 public void read(JMEImporter e) throws IOException {
265 InputCapsule capsule = e.getCapsule(this);
267 modelMin = capsule.readFloatArray("modelMin", new float[0]);
268 modelMax = capsule.readFloatArray("modelMax", new float[0]);
269 worldMin = capsule.readFloatArray("worldMin", new float[0]);
270 worldMax = capsule.readFloatArray("worldMax", new float[0]);
271 numChildren = capsule.readInt("numChildren", 0);
272 worldScaleSquared = capsule.readFloat("worldScaleSquared", 0);
273 diff = (Vector3f)capsule.readSavable("diff", Vector3f.ZERO.clone());
276 public Class getClassTag() {
277 return this.getClass();