OSDN Git Service

22cc9ab6bcfdaca8e6540fa656333018d74fb233
[mikumikustudio/MikuMikuStudio.git] / src / com / jme / scene / DistanceSwitchModel.java
1 /*
2  * Copyright (c) 2003-2009 jMonkeyEngine
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  *   notice, this list of conditions and the following disclaimer.
11  *
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.
15  *
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.
19  *
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.
31  */
32
33 package com.jme.scene;
34
35 import java.io.IOException;
36
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;
43
44 /**
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.
54  * 
55  * @author Mark Powell
56  * @version $Id: DistanceSwitchModel.java,v 1.2 2004/03/13 18:07:56 mojomonkey
57  *          Exp $
58  */
59 public class DistanceSwitchModel implements SwitchModel {
60
61         private float[] modelMin;
62
63         private float[] modelMax;
64
65         private float[] worldMin;
66
67         private float[] worldMax;
68
69         private int numChildren;
70
71         private float worldScaleSquared;
72
73         private Vector3f diff;
74
75     public DistanceSwitchModel() {}
76     
77         /**
78          * Constructor instantiates a new <code>DistanceSwitchModel</code> object
79          * with the number of children to select from.
80          * 
81          * @param numChildren
82          *            the number of children this model selects from.
83          */
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];
90         }
91
92         /**
93          * Returns the number of children that distances exist for.
94          * @return
95          */
96         public  int             getNumChildren() {
97                 return numChildren;
98         }
99         
100         /**
101          * Gets the minimum distance for this spatial index.
102          * @param index
103          * @return
104          */
105         public  float           getModelMinDistance(int index) {
106                 return modelMin[index];
107         }
108         
109         /**
110          * Gets the maximum distance for this spatial index.
111          * @param index
112          * @return
113          */
114         public  float           getModelMaxDistance(int index) {
115                 return modelMax[index];
116         }
117         
118         /**
119          * 
120          * <code>setModelMinDistance</code> sets the minimum distance that a
121          * particular child should be used.
122          * 
123          * @param index
124          *            the index of the child.
125          * @param minDist
126          *            the minimum of this child.
127          */
128         public void setModelMinDistance(int index, float minDist) {
129                 if(index >= numChildren) {
130                         reallocateArrays(index + 1);
131                 }
132                 
133                 modelMin[index] = minDist;
134         }
135
136         /**
137          * Creates larger arrays for the max and mins while copying existing data.
138          * @param newLength
139          */
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];
146                 
147                 // copy in existing
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];
153                 }
154                 
155                 // reassign
156                 modelMin = modelMinNew;
157                 modelMax = modelMaxNew;
158                 worldMin = worldMinNew;
159                 worldMax = worldMaxNew;
160                 numChildren = newLength;
161         }
162         /**
163          * 
164          * <code>setModelMaxDistance</code> sets the maximum distance that a
165          * particular child should be used.
166          * 
167          * @param index
168          *            the index of the child.
169          * @param maxDist
170          *            the maximum of this child.
171          */
172         public void setModelMaxDistance(int index, float maxDist) {
173                 if(index >= numChildren) {
174                         reallocateArrays(index + 1);
175                 }
176                 
177                 modelMax[index] = maxDist;
178         }
179
180         /**
181          * 
182          * <code>setModelDistance</code> sets the minimum and maximum distance
183          * that a particular child should be used.
184          * 
185          * @param index
186          *            the index of the child.
187          * @param minDist
188          *            the minimum of this child.
189          * @param maxDist
190          *            the maximum of this child.
191          */
192         public void setModelDistance(int index, float minDist, float maxDist) {
193                 if(index >= numChildren) {
194                         reallocateArrays(index + 1);
195                 }
196                 
197                 modelMin[index] = minDist;
198                 modelMax[index] = maxDist;
199         }
200
201         /**
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
208          * location.
209          * 
210          * @param value
211          *            either Float - the world scale squared value, or Vector3f -
212          *            the difference between the switch node and a location.
213          */
214         public void set(Object value) {
215                 if (value instanceof Float) {
216
217                         worldScaleSquared = ((Float) value).floatValue();
218
219                         for (int i = 0; i < numChildren; i++) {
220                                 worldMin[i] = worldScaleSquared * modelMin[i] * modelMin[i];
221                                 worldMax[i] = worldScaleSquared * modelMax[i] * modelMax[i];
222                         }
223                 } else if (value instanceof Vector3f) {
224                         diff = (Vector3f) value;
225                 } else {
226                         throw new JmeException("Invalid value for set method.");
227                 }
228         }
229
230         /**
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.
234          * 
235          * @return the index of the valid child.
236          */
237         public int getSwitchChild() {
238                 // select the switch child
239                 if (numChildren > 0) {
240                         float sqrDistance = diff.lengthSquared();
241
242                         for (int i = 0; i < numChildren; i++) {
243                                 if (worldMin[i] <= sqrDistance && sqrDistance < worldMax[i]) {
244                                         return i;
245                                 }
246                         }
247                 }
248
249                 return SwitchNode.SN_INVALID_CHILD;
250         }
251     
252     public void write(JMEExporter e) throws IOException {
253         OutputCapsule capsule = e.getCapsule(this);
254         
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);
262     }
263     
264     public void read(JMEImporter e) throws IOException {
265         InputCapsule capsule = e.getCapsule(this);
266         
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());
274     }
275     
276     public Class getClassTag() {
277         return this.getClass();
278     }
279 }