aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/DistanceLOD.java
blob: 244c06a8e53fd8b6c9057ce959060f1f872749d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/*
 * 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;

import javax.vecmath.Point3f;

/**
 * This class defines a distance-based LOD behavior node that operates on
 * a Switch group node to select one of the children of that Switch node
 * based on the distance of this LOD node from the viewer.
 * An array of <i>n</i> monotonically increasing distance values is
 * specified, such that distances[0] is associated with the highest level of
 * detail and distances[<i>n</i>-1] is associated with the lowest level of
 * detail.  Based on the actual distance from the viewer to
 * this DistanceLOD node, these <i>n</i>
 * distance values [0, <i>n</i>-1] select from among <i>n</i>+1
 * levels of detail [0, <i>n</i>].  If <i>d</i> is the distance from
 * the viewer to the LOD node, then the equation for determining
 * which level of detail (child of the Switch node) is selected is:
 * <p>
 * <ul>
 *     0, if <i>d</i> <= distances[0]
 * <br>
 *     <i>i</i>, if distances[<i>i</i>-1] < <i>d</i> <= distances[<i>i</i>]
 * <br>
 *     <i>n</i>, if d > distances[<i>n</i>-1]
 * </ul>
 * <p>
 * Note that both the position and the array of distances are
 * specified in the local coordinate system of this node.
 */
public class DistanceLOD extends LOD {

    private double distances[];
    private Point3f position = new Point3f(0.0f, 0.0f, 0.0f);

    // variables for processStimulus
    private Point3f center = new Point3f();
    private Point3f viewPosition = new Point3f();

    /**
     * Constructs and initializes a DistanceLOD node with default values.
     * Note that the default constructor creates a DistanceLOD object with
     * a single distance value set to 0.0 and is, therefore, not useful.
     */
    public DistanceLOD() {
	distances = new double[1];
	distances[0] = 0.0;
    }

    /**
     * Constructs and initializes a DistanceLOD node with the specified
     * array of distances and a default position of (0,0,0).
     * @param distances an array of values representing LOD cutoff distances
     */
    public DistanceLOD(float[] distances) {
	this.distances = new double[distances.length];

	for(int i=0;i<distances.length;i++) {
 	   this.distances[i] = (double)distances[i];
        }
    }

    /**
     * Constructs and initializes a DistanceLOD node with the specified
     * array of distances and the specified position.
     * @param distances an array of values representing LOD cutoff distances
     * @param position the position of this LOD node
     */
    public DistanceLOD(float[] distances, Point3f position) {
	this.distances = new double[distances.length];

	for(int i=0;i<distances.length;i++) {
 	   this.distances[i] = (double)distances[i];
        }
	this.position.set(position);
    }

    /**
     * Sets the position of this LOD node.  This position is specified in
     * the local coordinates of this node, and is
     * the position from which the distance to the viewer is computed.
     * @param position the new position
     */
    public void setPosition(Point3f position) {
	if (((NodeRetained)retained).staticTransform != null) {
	    ((NodeRetained)retained).staticTransform.transform.transform(
					position, this.position);
	} else {
	    this.position.set(position);
	}
    }

    /**
     * Retrieves the current position of this LOD node.  This position is
     * in the local coordinates of this node.
     * @param position the object that will receive the current position
     */
    public void getPosition(Point3f position) {
        if (((NodeRetained)retained).staticTransform != null) {
            Transform3D invTransform =
                ((NodeRetained)retained).staticTransform.getInvTransform();
            invTransform.transform(this.position, position);
        } else {
            position.set(this.position);
        }
    }

    /**
     * Returns a count of the number of LOD distance cut-off parameters.
     * Note that the number of levels of detail (children of the Switch node)
     * is one greater than the number of distance values.
     * @return a count of the LOD cut-off distances
     */
    public int numDistances() {
	return distances.length;
    }

    /**
     * Returns a particular LOD cut-off distance.
     * @param whichDistance an index specifying which LOD distance to return
     * @return the cut-off distance value associated with the index provided
     */
    public double getDistance(int whichDistance) {
	return distances[whichDistance];
    }

    /**
     * Sets a particular LOD cut-off distance.
     * @param whichDistance an index specifying which LOD distance to modify
     * @param distance the cut-off distance associated with the index provided
     */
    public void setDistance(int whichDistance, double distance) {
	     distances[whichDistance] = distance;
    }

    /**
     * Initialize method that sets up initial wakeup criteria.
     */
    @Override
    public void initialize() {
	// Insert wakeup condition into queue
	wakeupOn(wakeupFrame);
    }

    /**
     * Process stimulus method that computes appropriate level of detail.
     * @param criteria an enumeration of the criteria that caused the
     * stimulus
     */
    @Override
    public void processStimulus(Enumeration criteria) {


	// compute distance in virtual world
	View v = this.getView();
	if( v == null ) {
	    wakeupOn(wakeupFrame);
	    return;
	}

	ViewPlatform vp = v.getViewPlatform();
	if (vp == null) {
	    return;
	}

	// Handle stimulus
	double viewDistance = 0.0;
	int nSwitches,i,index=0;

	Transform3D localToWorldTrans = new Transform3D();

        localToWorldTrans.set(((NodeRetained)this.retained).getCurrentLocalToVworld());


	//  DistanceLOD's location in virutal world
	localToWorldTrans.transform( position, center);


	viewPosition.x = (float)((ViewPlatformRetained)vp.retained).schedSphere.center.x;
	viewPosition.y = (float)((ViewPlatformRetained)vp.retained).schedSphere.center.y;
	viewPosition.z = (float)((ViewPlatformRetained)vp.retained).schedSphere.center.z;
	viewDistance = center.distance( viewPosition);


	// convert distance into local coordinates
	viewDistance = viewDistance/localToWorldTrans.getDistanceScale();

	nSwitches = numSwitches();

	index = distances.length; // viewDistance > distances[n-1]

	if( viewDistance <= distances[0] ) {
	    index = 0;
	} else {
	    for (i=1; i < distances.length; i++) {
		if ((viewDistance > distances[i-1]) &&
		    (viewDistance <= distances[i])) {
		    index = i;
		    break;
		}
	    }
	}

	for(i=nSwitches-1; i>=0; i--) {
	    Switch sw = getSwitch(i);
	    // Optimize, this behavior is passive
	    // Note that we skip the capability check for getWhichChild()
	    if (((SwitchRetained) sw.retained).getWhichChild() !=
		index) {
		sw.setWhichChild(index);
	    }
	}
	// Insert wakeup condition into queue
	wakeupOn(wakeupFrame);

    }

    /**
     * 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) {
        DistanceLOD d = new DistanceLOD();
        d.duplicateNode(this, forceDuplicate);
        return d;
    }


   /**
     * Copies all DistanceLOD 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);

	DistanceLOD lod = (DistanceLOD) originalNode;

        int numD = lod.numDistances();

	// No API available to set the size of this array after initialize
        this.distances = new double[numD];

        for (int i = 0; i < numD; i++)
            setDistance(i, lod.getDistance(i));

        Point3f p = new Point3f();
        lod.getPosition(p);
        setPosition(p);
    }

    void mergeTransform(TransformGroupRetained xform) {
	xform.transform.transform(position, position);
    }
}