1 /*
2  * $RCSfile: MorphRetained.java,v $
3  *
4  * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6  *
7  * This code is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 only, as
9  * published by the Free Software Foundation.  Sun designates this
10  * particular file as subject to the "Classpath" exception as provided
11  * by Sun in the LICENSE file that accompanied this code.
12  *
13  * This code is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  * version 2 for more details (a copy is included in the LICENSE file that
17  * accompanied this code).
18  *
19  * You should have received a copy of the GNU General Public License version
20  * 2 along with this work; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
24  * CA 95054 USA or visit www.sun.com if you need additional information or
25  * have any questions.
26  *
27  * $Revision: 1.10 $
28  * $Date: 2008/02/28 20:17:26 $
29  * $State: Exp $
30  */
31 
32 package javax.media.j3d;
33 
34 import javax.vecmath.*;
35 import java.util.ArrayList;
36 import java.util.Vector;
37 
38 /**
39  * A morph leaf node consisting of geometery and appearance properties.
40  */
41 
42 class MorphRetained extends LeafRetained implements GeometryUpdater {
43 
44     // These bits should match the Shape3D bits ...(Since the mirrors for
45     // both are Shape3DRetained
46     static final int GEOMETRY_CHANGED		= 0x00001;
47     static final int APPEARANCE_CHANGED		= 0x00002;
48     static final int COLLISION_CHANGED		= 0x00004;
49     static final int BOUNDS_CHANGED		= 0x00008;
50     static final int APPEARANCEOVERRIDE_CHANGED	= 0x00010;
51     static final int UPDATE_MORPH		= 0x00020;
52 
53     private static final double TOLERANCE = 1.0e-4;
54 
55 
56     /**
57      * The mirror Shape3DRetained nodes for this object.  There is one
58      * mirror for each instance of this Shape3D node.  If it is not in
59      * a SharedGroup, only index 0 is valid.
60      */
61     ArrayList mirrorShape3D = new ArrayList();
62 
63 
64     // Target threads to be notified when morph changes
65     final static int targetThreads = (J3dThread.UPDATE_RENDER |
66 				      J3dThread.UPDATE_GEOMETRY);
67 
68     /**
69      * The appearance component of the morph node.
70      */
71     AppearanceRetained appearance = null;
72 
73     /**
74      * The Geosets associated with the morph node.
75      */
76     GeometryArrayRetained geometryArrays[];
77 
78     private int numGeometryArrays = 0;
79 
80     /**
81      * The weight vector the morph node.
82      */
83     double weights[];
84 
85     /**
86      * Reference to the  BranchGroup path of this mirror shape
87      * This is used for picking only.
88      */
89     BranchGroupRetained branchGroupPath[];
90 
91 
92     // cache value for picking in mirror shape.
93     // True if all the node of the path from this to root are all pickable
94     boolean isPickable = true;
95 
96 
97     // cache value for collidable in mirror shape.
98     // True if all the node of the path from this to root are all collidable
99     boolean isCollidable = true;
100 
101 
102     // closest switch parent
103     SwitchRetained  closestSwitchParent = null;
104 
105     // the child index from the closest switch parent
106     int closestSwitchIndex = -1;
107 
108     // Is this Morph visible ? The default is true.
109     boolean visible = true;
110 
111     // geometry Bounds in local coordinate
112     Bounds bounds = null;
113 
114     // geometry Bounds in virtual world coordinate
115     BoundingBox vwcBounds = new BoundingBox();
116 
117     // collision Bound in local coordinate
118     Bounds collisionBound = null;
119 
120     // collision Bounds in virtual world coordinate
121     Bounds collisionVwcBound = null;
122 
123 
124     GeometryArray morphedGeometryArray = null;
125 
126     // Morph data
127     float[] Mcoord = null;
128     float[] Mcolor = null;
129     float[] Mnormal = null;
130     // First dimension is the coordSet, second dimenension is the vertex index
131     // each vertex has 2 or 3floats
132     float[][]MtexCoord = null;
133 
134     // Whether the normal appearance is overrided by the alternate app
135     boolean appearanceOverrideEnable = false;
136 
137     int changedFrequent = 0;
138 
139 
MorphRetained()140     MorphRetained() {
141         this.nodeType = NodeRetained.MORPH;
142 	localBounds = new BoundingBox();
143 	((BoundingBox)localBounds).setLower( 1.0, 1.0, 1.0);
144 	((BoundingBox)localBounds).setUpper(-1.0,-1.0,-1.0);
145     }
146 
147     /**
148      * Sets the collision bounds of a node.
149      * @param bounds the bounding object for the node
150      */
setCollisionBounds(Bounds bounds)151     void setCollisionBounds(Bounds bounds) {
152         if (bounds != null) {
153 	    collisionBound = (Bounds)bounds.clone();
154 	} else {
155             collisionBound = null;
156 	}
157 	if (source.isLive()) {
158 	    // Notify Geometry Structure to set mirror shape collision
159 	    // bound and check for collision
160 	    J3dMessage message = new J3dMessage();
161 	    message.type = J3dMessage.COLLISION_BOUND_CHANGED;
162             message.threads = J3dThread.UPDATE_TRANSFORM;
163 	    message.universe = universe;
164             message.args[1] = collisionBound;
165 	    VirtualUniverse.mc.processMessage(message);
166 	}
167     }
168 
169     /**
170      * Sets the geometric bounds of a node.
171      * @param bounds the bounding object for the node
172      */
setBounds(Bounds bounds)173     void setBounds(Bounds bounds) {
174 	super.setBounds(bounds);
175 	if (source.isLive() && !boundsAutoCompute) {
176 	    J3dMessage message = new J3dMessage();
177 	    message.type = J3dMessage.REGION_BOUND_CHANGED;
178 	    message.threads = J3dThread.UPDATE_TRANSFORM |
179 		              targetThreads;
180 	    message.universe = universe;
181 	    message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
182 	    message.args[1] = localBounds;
183 	    VirtualUniverse.mc.processMessage(message);
184 	}
185     }
186 
187     /**
188      * Gets the collision bounds of a node.
189      * @return the node's bounding object
190      */
getCollisionBounds()191     Bounds getCollisionBounds() {
192         return (collisionBound == null? null : (Bounds)collisionBound.clone());
193     }
194 
195     /**
196      * Sets the geometryArrays component of the Morph node.
197      * @param geometryArrays the new vector of geometryArrays for the morph node
198      */
setGeometryArrays(GeometryArray geometryArrays[])199     void setGeometryArrays(GeometryArray geometryArrays[]) {
200         int i;
201 
202 	if ((geometryArrays == null || geometryArrays.length == 0) && numGeometryArrays == 0)
203 	    return;
204 
205         GeometryArrayRetained geo, prevGeo;
206 
207         if (numGeometryArrays != 0 && (geometryArrays == null || numGeometryArrays != geometryArrays.length))
208 	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained0"));
209 
210 
211         for (i=1;i < geometryArrays.length;i++) {
212 	    if (geometryArrays[i] == null || geometryArrays[i-1] == null)
213 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
214 	    geo = (GeometryArrayRetained)geometryArrays[i].retained;
215 	    prevGeo = (GeometryArrayRetained)geometryArrays[i-1].retained;
216 	    if (prevGeo == null || geo == null) {
217 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
218 
219 	    }
220 	    doErrorCheck(prevGeo, geo);
221 	}
222 
223 	// Check the first one for vertex attributes
224 	geo = (GeometryArrayRetained)geometryArrays[0].retained;
225 	if ((geo.vertexFormat & GeometryArray.VERTEX_ATTRIBUTES) != 0) {
226 	    throw new UnsupportedOperationException(J3dI18N.getString("MorphRetained9"));
227 	}
228 
229 	// Check if the first one is in Immediate context
230 	if (geometryArrays[0] != null) {
231 	    geo = (GeometryArrayRetained)geometryArrays[0].retained;
232 	}
233 
234 	if (numGeometryArrays == 0) {
235             this.geometryArrays = new GeometryArrayRetained[geometryArrays.length];
236 	    numGeometryArrays = geometryArrays.length;
237 	}
238 
239         for (i=0;i < numGeometryArrays;i++) {
240 	    geo = (GeometryArrayRetained)geometryArrays[i].retained;
241 	    if (((Morph)this.source).isLive()) {
242 		if (this.geometryArrays[i] != null) {
243 		    this.geometryArrays[i].clearLive(refCount);
244 		    this.geometryArrays[i].removeMorphUser(this);
245 		}
246 		if (geo != null) {
247 		    geo.setLive(inBackgroundGroup, refCount);
248 		    geo.addMorphUser(this);
249 		}
250 	    }
251 
252 	    this.geometryArrays[i] = geo;
253 	}
254 	if (this.geometryArrays[0] == null)
255 	    return;
256 
257 
258         if (weights == null) {
259 	    weights = new double[numGeometryArrays];
260 	    weights[0] = 1.0;
261 	    int vFormat = this.geometryArrays[0].vertexFormat;
262 	    // default is zero when new array
263 	    //for (i=1; i < numGeometryArrays;i++)  weights[i] = 0.0;
264 
265 	    int texCoordSetCount = this.geometryArrays[0].getTexCoordSetCount();
266 	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
267 		Mcoord = new float[this.geometryArrays[0].getNumCoordCount()* 3];
268 
269 		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3)
270 		    Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 3];
271 		else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
272 		    Mcolor = new float[this.geometryArrays[0].getNumColorCount()* 4];
273 
274 		MtexCoord = new float[texCoordSetCount][];
275 		if ((vFormat & GeometryArray.NORMALS) != 0)
276 		    Mnormal = new float[this.geometryArrays[0].getNumNormalCount() *3];
277 		for (int k = 0; k < texCoordSetCount; k++) {
278 		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
279 			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 2];
280 		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0))
281 			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 3];
282 		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0))
283 			MtexCoord[k] = new float[this.geometryArrays[0].getNumTexCoordCount(k) * 4];
284 		}
285 	    }
286 	    else {
287 		Mcoord = new float[this.geometryArrays[0].validVertexCount* 3];
288 
289 		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3) {
290 		    Mcolor = new float[this.geometryArrays[0].validVertexCount* 3];
291 		} else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4) {
292 		    Mcolor = new float[this.geometryArrays[0].validVertexCount* 4];
293 		}
294 		MtexCoord = new float[texCoordSetCount][];
295 		if ((vFormat & GeometryArray.NORMALS) != 0) {
296 		    Mnormal = new float[this.geometryArrays[0].validVertexCount *3];
297 		}
298 		for (int k = 0; k < texCoordSetCount; k++) {
299 		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0)
300 			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 2];
301 		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0))
302 			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 3];
303 		    else if (((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0))
304 			MtexCoord[k] = new float[this.geometryArrays[0].validVertexCount * 4];
305 		}
306 	    }
307 	}
308 
309 	//  create a new morphedGeometryArray
310 	initMorphedGeometry();
311 
312 	if (source.isLive()) {
313 
314 	    Shape3DRetained shape = (Shape3DRetained)mirrorShape3D.get(0);
315 
316 	    shape.setMorphGeometry(morphedGeometryArray, mirrorShape3D);
317 
318 	    J3dMessage mChangeMessage = null;
319 	    mChangeMessage = new J3dMessage();
320 	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
321 	    mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY |
322 				      J3dThread.UPDATE_TRANSFORM);
323 	    // If its a indexed geometry array, unindexify in renderBin
324 	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained)
325 		mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES;
326 	    mChangeMessage.args[0] = this;
327 	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
328 	  // a shadow copy of this ArrayList instance. (The elements themselves are not copied.)
329 	    mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
330 	    mChangeMessage.universe = universe;
331 	    VirtualUniverse.mc.processMessage(mChangeMessage);
332 
333 	    if (boundsAutoCompute) {
334 		GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
335 		// Compute the bounds once
336 		mga.incrComputeGeoBounds();// This compute the bbox if dirty
337 		mga.decrComputeGeoBounds();
338 	    }
339 	}
340 
341 
342 
343     }
344 
345     /**
346      * Retrieves the geometryArrays component of this Morph node.
347      * @param index the index of GeometryArray to be returned
348      * @return the geometryArray component of this morph node
349      */
getGeometryArray(int index)350     GeometryArray getGeometryArray(int index) {
351         return (GeometryArray)this.geometryArrays[index].source;
352     }
353 
354     /**
355      * Sets the appearance component of this Morph node.
356      * @param appearance the new apearance component for this morph node
357      */
setAppearance(Appearance newAppearance)358     void setAppearance(Appearance newAppearance) {
359 	boolean visibleIsDirty = false;
360 
361         if (((Morph)this.source).isLive()) {
362 
363 	    if (appearance != null) {
364 		this.appearance.clearLive(refCount);
365 		for (int i=mirrorShape3D.size()-1; i>=0; i--) {
366 		    this.appearance.removeAMirrorUser(
367 					(Shape3DRetained)mirrorShape3D.get(i));
368 		}
369 	    }
370 
371 	    if (newAppearance != null) {
372 		((AppearanceRetained)newAppearance.retained).setLive(inBackgroundGroup, refCount);
373 		appearance = ((AppearanceRetained)newAppearance.retained);
374 		int size= mirrorShape3D.size();
375 		for (int i=0; i<size; i++) {
376 		    appearance.addAMirrorUser((Shape3DRetained)mirrorShape3D.get(i));
377 		}
378 		if((appearance.renderingAttributes != null) &&
379 		   (visible !=  appearance.renderingAttributes.visible)) {
380 		    visible = appearance.renderingAttributes.visible;
381 		    visibleIsDirty = true;
382 		}
383 	    }
384 	    else {
385 		if(visible == false) {
386 		    visible = true;
387 		    visibleIsDirty = true;
388 		}
389 	    }
390 
391 	    // Send a message
392 	    int size = 0;
393 
394 	    if (visibleIsDirty)
395 		size = 2;
396 	    else
397 		size = 1;
398 	    J3dMessage[] createMessage = new J3dMessage[size];
399 	    createMessage[0] = new J3dMessage();
400 	    createMessage[0].threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT |
401 		J3dThread.UPDATE_RENDER;
402 	    createMessage[0].type = J3dMessage.MORPH_CHANGED;
403 	    createMessage[0].universe = universe;
404 	    createMessage[0].args[0] = this;
405 	    createMessage[0].args[1]= new Integer(APPEARANCE_CHANGED);
406 	    Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D.size()];
407 	    mirrorShape3D.toArray(s3dArr);
408 	    createMessage[0].args[2] = s3dArr;
409 	    Object[] obj = new Object[2];
410 	    if (newAppearance == null) {
411 		obj[0] = null;
412 	    }
413 	    else {
414 		obj[0]  = appearance.mirror;
415 	    }
416 	    obj[1] = new Integer(changedFrequent);
417 	    createMessage[0].args[3] = obj;
418 	    createMessage[0].args[4] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
419 	    if(visibleIsDirty) {
420 		createMessage[1] = new J3dMessage();
421 		createMessage[1].threads = J3dThread.UPDATE_GEOMETRY;
422 		createMessage[1].type = J3dMessage.SHAPE3D_CHANGED;
423 		createMessage[1].universe = universe;
424 		createMessage[1].args[0] = this;
425 		createMessage[1].args[1]= new Integer(APPEARANCE_CHANGED);
426 		createMessage[1].args[2]= visible?Boolean.TRUE:Boolean.FALSE;
427 		createMessage[1].args[3]= createMessage[0].args[4];
428 	    }
429 	    VirtualUniverse.mc.processMessage(createMessage);
430         }
431 	else {
432 	    if (newAppearance == null) {
433 		appearance = null;
434 	    } else {
435 		appearance = (AppearanceRetained) newAppearance.retained;
436 	    }
437 	}
438     }
439 
440     /**
441      * Retrieves the morph node's appearance component.
442      * @return the morph node's appearance
443      */
getAppearance()444     Appearance getAppearance() {
445         return (appearance == null ? null :
446 		(Appearance) this.appearance.source);
447     }
448 
setAppearanceOverrideEnable(boolean flag)449     void setAppearanceOverrideEnable(boolean flag) {
450         if (((Morph)this.source).isLive()) {
451 
452 	    // Send a message
453 	    J3dMessage createMessage = new J3dMessage();
454 	    createMessage.threads = J3dThread.UPDATE_RENDERING_ENVIRONMENT |
455 		J3dThread.UPDATE_RENDER;;
456 	    createMessage.type = J3dMessage.MORPH_CHANGED;
457 	    createMessage.universe = universe;
458 	    createMessage.args[0] = this;
459 	    createMessage.args[1]= new Integer(APPEARANCEOVERRIDE_CHANGED);
460 	    Shape3DRetained[] s3dArr = new Shape3DRetained[mirrorShape3D.size()];
461 	    mirrorShape3D.toArray(s3dArr);
462 	    createMessage.args[2] = s3dArr;
463 	    Object[] obj = new Object[2];
464 	    if (flag) {
465 		obj[0] = Boolean.TRUE;
466 	    }
467 	    else {
468 		obj[0]  = Boolean.FALSE;
469 	    }
470 	    obj[1] = new Integer(changedFrequent);
471 	    createMessage.args[3] = obj;
472 	    createMessage.args[4] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
473 	    VirtualUniverse.mc.processMessage(createMessage);
474 	}
475 	appearanceOverrideEnable = flag;
476     }
477 
getAppearanceOverrideEnable()478     boolean getAppearanceOverrideEnable() {
479 	return appearanceOverrideEnable;
480     }
481 
intersect(PickInfo pickInfo, PickShape pickShape, int flags )482     boolean intersect(PickInfo pickInfo, PickShape pickShape, int flags ) {
483 
484         Transform3D localToVworld = pickInfo.getLocalToVWorldRef();
485 
486 	Transform3D vworldToLocal = new Transform3D();
487 	vworldToLocal.invert(localToVworld);
488 	PickShape newPS = pickShape.transform(vworldToLocal);
489 
490 	GeometryRetained geo = (GeometryRetained) (morphedGeometryArray.retained);
491 
492         if (geo.mirrorGeometry != null) {
493             geo = geo.mirrorGeometry;
494         }
495 
496         if (((flags & PickInfo.CLOSEST_INTERSECTION_POINT) == 0) &&
497                 ((flags & PickInfo.CLOSEST_DISTANCE) == 0) &&
498                 ((flags & PickInfo.CLOSEST_GEOM_INFO) == 0) &&
499                 ((flags & PickInfo.ALL_GEOM_INFO) == 0)) {
500             return geo.intersect(newPS, null, 0, null, null, 0);
501         } else {
502             Point3d closestIPnt = new Point3d();
503             Point3d iPnt = new Point3d();
504             Point3d iPntVW = new Point3d();
505 
506             if (geo.intersect(newPS, pickInfo, flags, iPnt, geo, 0)) {
507 
508                 iPntVW.set(iPnt);
509                 localToVworld.transform(iPntVW);
510                 double distance = pickShape.distance(iPntVW);
511 
512                 if ((flags & PickInfo.CLOSEST_DISTANCE) != 0) {
513                     pickInfo.setClosestDistance(distance);
514                 }
515                 if((flags & PickInfo.CLOSEST_INTERSECTION_POINT) != 0) {
516                     pickInfo.setClosestIntersectionPoint(iPnt);
517                 }
518                 return true;
519             }
520         }
521         return false;
522     }
523 
524 
525     /**
526      * Check if the geometry component of this shape node under path
527      *  intersects with the pickShape.
528      * @return true if intersected else false. If return is true, dist
529      *  contains the closest distance of intersection if it is not
530      *  equal to null.
531      */
intersect(SceneGraphPath path, PickShape pickShape, double[] dist)532     boolean intersect(SceneGraphPath path,
533             PickShape pickShape, double[] dist) {
534 
535 	// This method will not do bound intersect check, as it assume caller
536 	// has already done that. ( For performance and code simplification
537 	// reasons. )
538 
539         int flags;
540         PickInfo pickInfo = new PickInfo();
541 
542         Transform3D localToVworld = path.getTransform();
543 	if (localToVworld == null) {
544 	    throw new RuntimeException(J3dI18N.getString("MorphRetained5"));
545 	}
546 
547         pickInfo.setLocalToVWorldRef( localToVworld);
548         //System.err.println("MorphRetained.intersect() : ");
549         if (dist == null) {
550             //System.err.println("      no dist request ....");
551             return intersect(pickInfo, pickShape, 0);
552         }
553 
554         flags = PickInfo.CLOSEST_DISTANCE;
555         if (intersect(pickInfo, pickShape, flags)) {
556             dist[0] = pickInfo.getClosestDistance();
557             return true;
558         }
559 
560         return false;
561 
562       }
563 
564     /**
565      * Sets the Morph node's weight vector
566      * @param wieghts the new vector of weights for the morph node
567      */
setWeights(double weights[])568      void setWeights(double weights[]) {
569 	int i;
570 	double sum= 0.0;
571 
572 	if (weights.length != numGeometryArrays)
573 	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained7"));
574 
575 	for (i=weights.length-1; i>=0; i--)  {
576 	    sum += weights[i];
577 	}
578 
579 	if (Math.abs(sum - 1.0) > TOLERANCE)
580 	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained8"));
581 
582 	// Weights array is ALWAYS malloced in setGeometryArrays method
583 	for (i=numGeometryArrays-1; i>=0; i--)
584 	    this.weights[i] = weights[i];
585 
586 
587 	if (source.isLive()) {
588 	    ((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this);
589 	    J3dMessage mChangeMessage = null;
590 	    mChangeMessage = new J3dMessage();
591 	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
592 	    mChangeMessage.threads = (J3dThread.UPDATE_GEOMETRY |
593 				      J3dThread.UPDATE_TRANSFORM);
594 	    // If its a indexed geometry array, unindexify in renderBin
595 	    if (this.geometryArrays[0] instanceof IndexedGeometryArrayRetained)
596 		mChangeMessage.threads |= J3dThread.UPDATE_RENDERING_ATTRIBUTES;
597 	    mChangeMessage.args[0] = this;
598 	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
599 	    mChangeMessage.args[3] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
600 	    mChangeMessage.universe = universe;
601 	    VirtualUniverse.mc.processMessage(mChangeMessage);
602 	}
603 
604     }
605 
606     /**
607      * Retrieves the Morph node's weight vector
608      * @return the morph node's weight vector.
609      */
getWeights()610     double[] getWeights() {
611 	return (double[]) weights.clone();
612     }
613 
614     /**
615      * Gets the bounding object of a node.
616      * @return the node's bounding object
617      */
getBounds()618     Bounds getBounds() {
619         if(boundsAutoCompute) {
620             GeometryArrayRetained mga =
621 		(GeometryArrayRetained)morphedGeometryArray.retained;
622             if (mga != null) {
623                 synchronized(mga.geoBounds) {
624                     return (Bounds) mga.geoBounds.clone();
625                 }
626             } else {
627                 return null;
628             }
629         } else {
630             return super.getBounds();
631         }
632     }
633 
getEffectiveBounds()634     Bounds getEffectiveBounds() {
635         if(boundsAutoCompute) {
636 	    return getBounds();
637 	}
638 	else {
639 	    return super.getEffectiveBounds();
640 	}
641     }
642 
643     /**
644      * ONLY needed for SHAPE, MORPH, and LINK node type.
645      * Compute the combine bounds of bounds and its localBounds.
646      */
computeCombineBounds(Bounds bounds)647     void computeCombineBounds(Bounds bounds) {
648 
649 	if(boundsAutoCompute) {
650 	    GeometryArrayRetained mga =
651 		(GeometryArrayRetained)morphedGeometryArray.retained;
652 	    if (mga != null) {
653 		synchronized(mga.geoBounds) {
654 		    bounds.combine((Bounds) mga.geoBounds);
655 		}
656 	    }
657 	} else {
658 	    // Should this be lock too ? ( MT safe  ? )
659 	    synchronized(localBounds) {
660 		bounds.combine((Bounds) localBounds);
661 	    }
662 	}
663     }
664 
665     // Return the number of geometry arrays in this MorphRetained object.
getNumGeometryArrays()666     int getNumGeometryArrays() {
667 	return numGeometryArrays;
668     }
669 
670     // If the geometry of a morph changes, make sure that the
671     // validVertexCount has not changed
updateMorphedGeometryArray(GeometryArrayRetained geo, boolean coordinatesChanged)672     void updateMorphedGeometryArray(GeometryArrayRetained geo, boolean coordinatesChanged) {
673 	if (numGeometryArrays > 0) {
674 	    // check if not the first geo, then compare with the first geometry
675 	    if (geometryArrays[0] != geo) {
676 		doErrorCheck(geo, geometryArrays[0]);
677 	    }
678 	    else {
679 		// if first geo, compare with the second geo
680 		if (numGeometryArrays > 1) {
681 		    doErrorCheck(geo, geometryArrays[1]);
682 		}
683 
684 	    }
685 	}
686 
687 
688 	((GeometryArrayRetained)morphedGeometryArray.retained).updateData(this);
689 	// Compute the bounds once
690 	if (boundsAutoCompute && coordinatesChanged) {
691 	    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
692 	    mga.incrComputeGeoBounds();  // This compute the bbox if dirty
693 	    mga.decrComputeGeoBounds();
694 	}
695     }
696 
697     /**
698      * Update GeometryArray computed by morphing input GeometryArrays
699      * with weights
700      */
updateData(Geometry mga)701     public void updateData(Geometry mga) {
702 
703 	int i,j,k, vFormat, geoType, stripVCount[];
704 	int iCount = 0;
705 	int numStrips = 0;
706 	int texCoordSetCount = 0;
707 	float coord[] = new float[3], color[] = new float[4],
708 	    normal[] = new float[3], texCoord[] = new float[3];
709 
710 	vFormat = geometryArrays[0].vertexFormat;
711 	geoType = ((GeometryArrayRetained)geometryArrays[0]).geoType;
712 	texCoordSetCount = geometryArrays[0].getTexCoordSetCount();
713 
714 
715 
716 	int vc = 0, nc = 0, cc = 0, n = 0;
717 	int count = 0;
718 	if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
719 	     count = geometryArrays[0].getNumCoordCount();
720 	} else {
721 	     count = geometryArrays[0].validVertexCount;
722 	}
723 
724 	for (i=0; i < count; i++) {
725 	    Mcoord[vc++] = Mcoord[vc++] = Mcoord[vc++] = 0.0f;
726 	}
727 
728 
729 	if ((vFormat & GeometryArray.COLOR) != 0) {
730 	    if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
731 		count = geometryArrays[0].getNumColorCount();
732 	    } else {
733 		count = geometryArrays[0].validVertexCount;
734 	    }
735 	    for (i=0; i < count; i++) {
736 		if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_3)
737 		    Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f;
738 
739 		else if ((vFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4)
740 		    Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = Mcolor[cc++] = 0.0f;
741 	    }
742 	}
743 
744 
745 	if ((vFormat & GeometryArray.NORMALS) != 0) {
746 	    if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
747 		count = geometryArrays[0].getNumNormalCount();
748 	    } else {
749 		count = geometryArrays[0].validVertexCount;
750 	    }
751 	    for (i=0; i < count; i++) {
752 		Mnormal[nc++] = Mnormal[nc++] = Mnormal[nc++] = 0.0f;
753 	    }
754 	}
755 
756 	if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
757 	    for (k = 0; k < texCoordSetCount; k++) {
758 		if (geometryArrays[0] instanceof IndexedGeometryArrayRetained){
759 		    count = geometryArrays[0].getNumTexCoordCount(k);
760 		} else {
761 		    count = geometryArrays[0].validVertexCount;
762 		}
763 		int tcount = 0;
764 		for (i=0; i < count; i++) {
765 		    MtexCoord[k][tcount++] = MtexCoord[k][tcount++] = 0.0f;
766 		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
767 			MtexCoord[k][tcount++] = 0.0f;
768 		    } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
769 			MtexCoord[k][tcount++] = 0.0f;
770 			MtexCoord[k][tcount++] = 0.0f;
771 		    }
772 		}
773 	    }
774 	}
775 	// If by copy, then ...
776 	if ((vFormat & GeometryArray.BY_REFERENCE) == 0) {
777 	    count = 0;
778 	    for (j=0;j < numGeometryArrays;j++) {
779 		double w = weights[j];
780 		if (w != 0) {
781 		    vc = 0; nc = 0; cc = 0;
782 		    int initialVertex = 0;
783 		    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
784 			initialVertex = 0;
785 			count =  geometryArrays[j].getNumCoordCount();
786 		    }
787 		    else {
788 			initialVertex = geometryArrays[j].getInitialVertexIndex();
789 			count = geometryArrays[j].validVertexCount;
790 		    }
791 		    int endVertex = initialVertex + count;
792 		    for (i=initialVertex; i< endVertex; i++) {
793 			geometryArrays[j].getCoordinate(i, coord);
794 			Mcoord[vc++] += coord[0]*w;
795 			Mcoord[vc++] += coord[1]*w;
796 			Mcoord[vc++] += coord[2]*w;
797 		    }
798 
799 		    if ((vFormat & GeometryArray.COLOR) != 0) {
800 			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
801 			    count =  geometryArrays[j].getNumColorCount();
802 			}
803 			endVertex = initialVertex + count;
804 			for (i=initialVertex; i<  endVertex; i++) {
805 			    geometryArrays[j].getColor(i, color);
806 			    Mcolor[cc++] += color[0]*w;
807 			    Mcolor[cc++] += color[1]*w;
808 			    Mcolor[cc++] += color[2]*w;
809 			    if ((vFormat & GeometryArray.WITH_ALPHA) != 0)
810 				Mcolor[cc++] += color[3]*w;
811 			}
812 		    }
813 		    if ((vFormat & GeometryArray.NORMALS) != 0) {
814 			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
815 			    count =  geometryArrays[j].getNumNormalCount();
816 			}
817 			endVertex = initialVertex + count;
818 			for (i=initialVertex; i<  endVertex; i++) {
819 			    geometryArrays[j].getNormal(i, normal);
820 			    Mnormal[nc++] += normal[0]*w;
821 			    Mnormal[nc++] += normal[1]*w;
822 			    Mnormal[nc++] += normal[2]*w;
823 			}
824 		    }
825 
826 		    if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
827 			for (k = 0; k < texCoordSetCount; k++) {
828 			    int tcount = 0;
829 			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
830 				count =  geometryArrays[j].getNumTexCoordCount(i);
831 			    }
832 			    endVertex = initialVertex + count;
833 			    for (i=initialVertex; i<  endVertex; i++) {
834 				geometryArrays[j].getTextureCoordinate(k, i, texCoord);
835 				MtexCoord[k][tcount++] += texCoord[0]*w;
836 				MtexCoord[k][tcount++] += texCoord[1]*w;
837 				if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
838 				    MtexCoord[k][tcount++] += texCoord[2]*w;
839 				} else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
840 				    MtexCoord[k][tcount++] += texCoord[2]*w;
841 				    MtexCoord[k][tcount++] += texCoord[3]*w;
842 				}
843 			    }
844 			}
845 		    }
846 		}
847 	    }
848 	}
849 	else {
850 	    int vIndex, tIndex, cIndex, nIndex, tstride = 0, cstride = 0;
851 	    if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
852 		if ((vFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
853 		    tstride = 2;
854 		} else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
855 		    tstride = 3;
856 		} else {
857 		    tstride = 4;
858 		}
859 	    }
860 
861 	    if ((vFormat & GeometryArray.COLOR) != 0) {
862 		cstride = 3;
863 		if ((vFormat & GeometryArray.WITH_ALPHA) != 0)
864 		    cstride = 4;
865 	    }
866 
867 	    if ((vFormat & GeometryArray.INTERLEAVED) != 0) {
868 		float[] vdata;
869 		int stride;
870 
871 		stride = geometryArrays[0].stride();
872 		int coffset = geometryArrays[0].colorOffset();
873 		int noffset = geometryArrays[0].normalOffset();
874 		int voffset = geometryArrays[0].coordinateOffset();
875 		int offset = 0;
876 
877 		int initialVertex = 0;
878 		for (j=0;j < numGeometryArrays;j++) {
879 		    double w = weights[j];
880 		    if (w != 0) {
881 			vc = 0; nc = 0; cc = 0; n = 0;
882 			vdata = geometryArrays[j].getInterleavedVertices();
883 			if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
884 			    for (k = 0; k < texCoordSetCount; k++) {
885 				if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
886 				    tIndex = 0;
887 				    count =  geometryArrays[j].getNumCoordCount();
888 				}
889 				else {
890 				    tIndex = geometryArrays[j].getInitialVertexIndex();
891 				    count = geometryArrays[j].validVertexCount;
892 				}
893 				offset = (tIndex * stride)+k*tstride;
894 				int tcount = 0;
895 				for (i = 0; i < count; i++, offset += stride) {
896 				    MtexCoord[k][tcount++] += vdata[offset] * w;
897 				    MtexCoord[k][tcount++] += vdata[offset+1] * w;
898 				    if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
899 					MtexCoord[k][tcount++] += vdata[offset+2]*w;
900 				    } else if ((vFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
901 					MtexCoord[k][tcount++] += vdata[offset+2]*w;
902 					MtexCoord[k][tcount++] += vdata[offset+3]*w;
903 				    }
904 				}
905 			    }
906 
907 			}
908 			if ((vFormat & GeometryArray.COLOR) != 0) {
909 			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
910 				cIndex = 0;
911 				count =  geometryArrays[j].getNumCoordCount();
912 			    }
913 			    else {
914 				cIndex = geometryArrays[j].getInitialVertexIndex();
915 				count = geometryArrays[j].validVertexCount;
916 			    }
917 			    offset = (cIndex * stride)+coffset;
918 			    for (i = 0; i < count; i++, offset += stride) {
919 				Mcolor[cc++] += vdata[offset]*w;
920 				Mcolor[cc++] += vdata[offset+1]*w;
921 				Mcolor[cc++] += vdata[offset+2]*w;
922 				if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
923 				    Mcolor[cc++] += vdata[offset+3]*w;
924 
925 			    }
926 			}
927 
928 			if ((vFormat & GeometryArray.NORMALS) != 0) {
929 			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
930 				nIndex = 0;
931 				count =  geometryArrays[j].getNumCoordCount();
932 			    }
933 			    else {
934 				nIndex = geometryArrays[j].getInitialVertexIndex();
935 				count = geometryArrays[j].validVertexCount;
936 			    }
937 			    offset = (nIndex * stride)+noffset;
938 			    for (i = 0; i < count; i++, offset += stride) {
939 				Mnormal[nc++] += vdata[offset]*w;
940 				Mnormal[nc++] += vdata[offset+1]*w;
941 				Mnormal[nc++] += vdata[offset+2]*w;
942 			    }
943 			}
944 			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
945 			    vIndex = 0;
946 			    count =  geometryArrays[j].getNumCoordCount();
947 			}
948 			else {
949 			    vIndex = geometryArrays[j].getInitialVertexIndex();
950 			    count = geometryArrays[j].validVertexCount;
951 			}
952 			offset = (vIndex * stride)+voffset;
953 			for (i = 0; i < count; i++, offset += stride) {
954 			    Mcoord[vc++] += vdata[offset]*w;
955 			    Mcoord[vc++] += vdata[offset+1]*w;
956 			    Mcoord[vc++] += vdata[offset+2]*w;
957 
958 			}
959 		    }
960 		}
961 	    }
962 	    else {
963 		float byteToFloatScale = 1.0f/255.0f;
964 		for (j=0;j < numGeometryArrays;j++) {
965 		    double w = weights[j];
966 		    if (w != 0) {
967 			if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
968 			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.TEXCOORD_DEFINED)) {
969 			    case GeometryArrayRetained.TF:
970 				for (k = 0; k < texCoordSetCount; k++) {
971 				    float[] tf = geometryArrays[j].getTexCoordRefFloat(k);
972 				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
973 					tIndex = 0;
974 					count =  geometryArrays[j].getNumTexCoordCount(k);
975 				    }
976 				    else {
977 					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
978 					count =  geometryArrays[j].validVertexCount;
979 				    }
980 				    tIndex *= tstride;
981 				    int tcount = 0;
982 				    for (i=0; i< count; i++) {
983 					MtexCoord[k][tcount++] += tf[tIndex++]*w;
984 					MtexCoord[k][tcount++] += tf[tIndex++]*w;
985 					if ((vFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0)
986 					    MtexCoord[k][tcount++] += tf[tIndex++]*w;
987 				    }
988 				}
989 				break;
990 			    case GeometryArrayRetained.T2F:
991 				for (k = 0; k < texCoordSetCount; k++) {
992 				    int tcount = 0;
993 				    float[] tf = geometryArrays[j].getTexCoordRefFloat(k);
994 				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
995 					tIndex = 0;
996 					count =  geometryArrays[j].getNumTexCoordCount(k);
997 				    }
998 				    else {
999 					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
1000 					count =  geometryArrays[j].validVertexCount;
1001 				    }
1002 				    TexCoord2f[] t2f = geometryArrays[j].getTexCoordRef2f(k);
1003 				    for (i=0; i< count; i++, tIndex++) {
1004 					MtexCoord[k][tcount++] += t2f[tIndex].x*w;
1005 					MtexCoord[k][tcount++] += t2f[tIndex].y*w;
1006 				    }
1007 				}
1008 				break;
1009 			    case GeometryArrayRetained.T3F:
1010 				for (k = 0; k < texCoordSetCount; k++) {
1011 				    int tcount = 0;
1012 				    TexCoord3f[] t3f = geometryArrays[j].getTexCoordRef3f(k);
1013 				    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
1014 					tIndex = 0;
1015 					count =  geometryArrays[j].getNumTexCoordCount(k);
1016 				    }
1017 				    else {
1018 					tIndex = geometryArrays[j].getInitialTexCoordIndex(k);
1019 					count =  geometryArrays[j].validVertexCount;
1020 				    }
1021 				    for (i=0; i< count; i++, tIndex++) {
1022 					MtexCoord[k][tcount++] += t3f[tIndex].x*w;
1023 					MtexCoord[k][tcount++] += t3f[tIndex].y*w;
1024 					MtexCoord[k][tcount++] += t3f[tIndex].z*w;
1025 				    }
1026 				}
1027 				break;
1028 
1029 			    }
1030 			}
1031 			if ((vFormat & GeometryArray.COLOR) != 0) {
1032 			    double val = byteToFloatScale * w;
1033 			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
1034 				cIndex = 0;
1035 				count =  geometryArrays[j].getNumColorCount();
1036 			    }
1037 			    else {
1038 				cIndex = geometryArrays[j].getInitialColorIndex();
1039 				count =  geometryArrays[j].validVertexCount;
1040 			    }
1041 
1042 			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.COLOR_DEFINED)) {
1043 			    case GeometryArrayRetained.CF:
1044 				float[] cf = geometryArrays[j].getColorRefFloat();
1045 				cc = 0;
1046 				cIndex *= cstride;
1047 				for (i=0; i< count; i++) {
1048 				    Mcolor[cc++] += cf[cIndex++]*w;
1049 				    Mcolor[cc++] += cf[cIndex++]*w;
1050 				    Mcolor[cc++] += cf[cIndex++]*w;
1051 				    if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
1052 					Mcolor[cc++] += cf[cIndex++]*w;
1053 				}
1054 				break;
1055 			    case GeometryArrayRetained.CUB:
1056 				byte[] cub = geometryArrays[j].getColorRefByte();
1057 				cc = 0;
1058 				cIndex *= cstride;
1059 				for (i=0; i< count; i++) {
1060 				    Mcolor[cc++] += (cub[cIndex++] & 0xff) * val;
1061 				    Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
1062 				    Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
1063 				    if ((vFormat & GeometryArray.WITH_ALPHA)!= 0)
1064 					Mcolor[cc++] += (cub[cIndex++] & 0xff) *val;
1065 				}
1066 
1067 				break;
1068 			    case GeometryArrayRetained.C3F:
1069 				Color3f[] c3f = geometryArrays[j].getColorRef3f();
1070 				cc = 0;
1071 				for (i=0; i< count; i++, cIndex++) {
1072 				    Mcolor[cc++] += c3f[cIndex].x * w;
1073 				    Mcolor[cc++] += c3f[cIndex].y * w;
1074 				    Mcolor[cc++] += c3f[cIndex].z * w;
1075 				}
1076 				break;
1077 			    case GeometryArrayRetained.C4F:
1078 				Color4f[] c4f = geometryArrays[j].getColorRef4f();
1079 				cc = 0;
1080 				for (i=0; i< count; i++, cIndex++) {
1081 				    Mcolor[cc++] += c4f[cIndex].x * w;
1082 				    Mcolor[cc++] += c4f[cIndex].y * w;
1083 				    Mcolor[cc++] += c4f[cIndex].z * w;
1084 				    Mcolor[cc++] += c4f[cIndex].w * w;
1085 				}
1086 				break;
1087 			    case GeometryArrayRetained.C3UB:
1088 				Color3b[] c3b = geometryArrays[j].getColorRef3b();
1089 				cc = 0;
1090 				for (i=0; i< count; i++, cIndex++) {
1091 				    Mcolor[cc++] += (c3b[cIndex].x  & 0xff)* val;
1092 				    Mcolor[cc++] += (c3b[cIndex].y  & 0xff) * val;
1093 				    Mcolor[cc++] += (c3b[cIndex].z & 0xff) * val;
1094 				}
1095 				break;
1096 			    case GeometryArrayRetained.C4UB:
1097 				Color4b[] c4b = geometryArrays[j].getColorRef4b();
1098 				cc = 0;
1099 				for (i=0; i< count; i++, cIndex++) {
1100 				    Mcolor[cc++] += (c4b[cIndex].x  & 0xff)* val;
1101 				    Mcolor[cc++] += (c4b[cIndex].y  & 0xff) * val;
1102 				    Mcolor[cc++] += (c4b[cIndex].z & 0xff) * val;
1103 				    Mcolor[cc++] += (c4b[cIndex].w & 0xff) * val;
1104 				}
1105 				break;
1106 
1107 			    }
1108 			}
1109 			if ((vFormat & GeometryArray.NORMALS) != 0) {
1110 			    nc = 0;
1111 			    if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
1112 				nIndex = 0;
1113 				count =  geometryArrays[j].getNumNormalCount();
1114 			    }
1115 			    else {
1116 				nIndex = geometryArrays[j].getInitialNormalIndex();
1117 				count =  geometryArrays[j].validVertexCount;
1118 			    }
1119 			    switch ((geometryArrays[j].vertexType & GeometryArrayRetained.NORMAL_DEFINED)) {
1120 			    case GeometryArrayRetained.NF:
1121 				float[] nf = geometryArrays[j].getNormalRefFloat();
1122 				nIndex *= 3;
1123 				for (i=0; i< count; i++) {
1124 				    Mnormal[nc++] += nf[nIndex++]*w;
1125 				    Mnormal[nc++] += nf[nIndex++]*w;
1126 				    Mnormal[nc++] += nf[nIndex++]*w;
1127 				}
1128 				break;
1129 			    case GeometryArrayRetained.N3F:
1130 				Vector3f[] n3f = geometryArrays[j].getNormalRef3f();
1131 				for (i=0; i< count; i++, nIndex++) {
1132 				    Mnormal[nc++] += n3f[nIndex].x*w;
1133 				    Mnormal[nc++] += n3f[nIndex].y*w;
1134 				    Mnormal[nc++] += n3f[nIndex].z*w;
1135 				}
1136 				break;
1137 			    }
1138 			}
1139 			// Handle vertices ..
1140 			vc = 0;
1141 			if (geometryArrays[j] instanceof IndexedGeometryArrayRetained) {
1142 			    vIndex = 0;
1143 			    count =  geometryArrays[j].getNumCoordCount();
1144 			}
1145 			else {
1146 			    vIndex = geometryArrays[j].getInitialCoordIndex();
1147 			    count =  geometryArrays[j].validVertexCount;
1148 			}
1149 			switch ((geometryArrays[j].vertexType & GeometryArrayRetained.VERTEX_DEFINED)) {
1150 			case GeometryArrayRetained.PF:
1151 			    float[] pf = geometryArrays[j].getCoordRefFloat();
1152 			    vIndex *= 3;
1153 			    for (i=0; i< count; i++) {
1154 				Mcoord[vc++] += pf[vIndex++]*w;
1155 				Mcoord[vc++] += pf[vIndex++]*w;
1156 				Mcoord[vc++] += pf[vIndex++]*w;
1157 			    }
1158 			    break;
1159 			case GeometryArrayRetained.PD:
1160 			    double[] pd = geometryArrays[j].getCoordRefDouble();
1161 			    vIndex *= 3;
1162 			    for (i=0; i< count; i++) {
1163 				Mcoord[vc++] += (float)pd[vIndex++]*w;
1164 				Mcoord[vc++] += (float)pd[vIndex++]*w;
1165 				Mcoord[vc++] += (float)pd[vIndex++]*w;
1166 			    }
1167 			    break;
1168 			case GeometryArrayRetained.P3F:
1169 			    Point3f[] p3f = geometryArrays[j].getCoordRef3f();
1170 			    for (i=0; i< count; i++, vIndex++) {
1171 				Mcoord[vc++] += p3f[vIndex].x*w;
1172 				Mcoord[vc++] += p3f[vIndex].y*w;
1173 				Mcoord[vc++] += p3f[vIndex].z*w;
1174 			    }
1175 			    break;
1176 			case GeometryArrayRetained.P3D:
1177 			    Point3d[] p3d = geometryArrays[j].getCoordRef3d();
1178 			    for (i=0; i< count; i++, vIndex++) {
1179 				Mcoord[vc++] += (float)p3d[vIndex].x*w;
1180 				Mcoord[vc++] += (float)p3d[vIndex].y*w;
1181 				Mcoord[vc++] += (float)p3d[vIndex].z*w;
1182 			    }
1183 			    break;
1184 
1185 			}
1186 
1187 		    }
1188 		}
1189 	    }
1190 	}
1191 
1192 	GeometryArrayRetained mgaR =
1193 	    (GeometryArrayRetained)mga.retained;
1194 
1195 	mgaR.setCoordRefFloat(Mcoord);
1196 
1197 	if ((vFormat & GeometryArray.COLOR) != 0)
1198 	    mgaR.setColorRefFloat(Mcolor);
1199 
1200 	// *******Need to normalize normals
1201 	if ((vFormat & GeometryArray.NORMALS) != 0)
1202 	    mgaR.setNormalRefFloat(Mnormal);
1203 
1204 	if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
1205     	    for (k = 0; k < texCoordSetCount; k++) {
1206 		mgaR.setTexCoordRefFloat(k, MtexCoord[k]);
1207 	    }
1208 	}
1209     }
1210 
updateImmediateMirrorObject(Object[] objs)1211     void updateImmediateMirrorObject(Object[] objs) {
1212 	int i;
1213 
1214 	int component = ((Integer)objs[1]).intValue();
1215 	Shape3DRetained[] msArr = (Shape3DRetained[]) objs[2];
1216 	if ((component & APPEARANCE_CHANGED) != 0) {
1217 	    Object[] arg = (Object[])objs[3];
1218 	    int val = ((Integer)arg[1]).intValue();
1219 	    for ( i = msArr.length-1; i >=0; i--) {
1220 		msArr[i].appearance = (AppearanceRetained)arg[0];
1221 		msArr[i].changedFrequent = val;
1222 	    }
1223 	}
1224 	if ((component & APPEARANCEOVERRIDE_CHANGED) != 0) {
1225 	    Object[] arg = (Object[])objs[3];
1226 	    int val = ((Integer)arg[1]).intValue();
1227 	    System.err.println("ChangedFrequent = "+changedFrequent);
1228 	    for ( i = msArr.length-1; i >=0; i--) {
1229 		msArr[i].appearanceOverrideEnable = ((Boolean)arg[0]).booleanValue();
1230 		msArr[i].changedFrequent = val;
1231 	    }
1232 	}
1233     }
1234 
1235     /**
1236      * assign a name to this node when it is made live.
1237      */
setLive(SetLiveState s)1238     void setLive(SetLiveState s) {
1239 	int i, j;
1240 	Shape3DRetained shape;
1241 	ArrayList msList = new ArrayList();
1242         GeometryAtom ga;
1243 	int oldrefCount = refCount;
1244 
1245 	super.doSetLive(s);
1246 	nodeId = universe.getNodeId();
1247 
1248 
1249 	for (i = 0; i < numGeometryArrays; i++) {
1250 	    synchronized(geometryArrays[i].liveStateLock) {
1251 		geometryArrays[i].setLive(inBackgroundGroup, s.refCount);
1252 		// Add this morph object as user the first time
1253 		if (oldrefCount <= 0) {
1254 		    geometryArrays[i].addMorphUser(this);
1255 		}
1256 	    }
1257 	}
1258 
1259 	if (this.morphedGeometryArray == null){
1260 	    initMorphedGeometry();
1261 
1262 	}
1263 	((GeometryArrayRetained)(morphedGeometryArray.retained)).setLive(inBackgroundGroup, s.refCount);
1264 
1265 	if (boundsAutoCompute) {
1266 	    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
1267 	    // Compute the bounds once
1268 	    mga.incrComputeGeoBounds(); // This compute the bbox if dirty
1269 	    mga.decrComputeGeoBounds();
1270 	    localBounds.setWithLock(mga.geoBounds);
1271 	}
1272 
1273 
1274 	if (inSharedGroup) {
1275 	    for (i=0; i<s.keys.length; i++) {
1276 		shape = new Shape3DRetained();
1277 		shape.key = s.keys[i];
1278 		shape.localToVworld = new Transform3D[1][];
1279 		shape.localToVworldIndex = new int[1][];
1280 
1281 
1282 		j = s.keys[i].equals(localToVworldKeys, 0,
1283 				     localToVworldKeys.length);
1284 		if(j < 0) {
1285 		    System.err.println("MorphRetained : Can't find hashKey");
1286 		}
1287 
1288 		shape.localToVworld[0] = localToVworld[j];
1289 		shape.localToVworldIndex[0] = localToVworldIndex[j];
1290 		shape.branchGroupPath = (BranchGroupRetained []) branchGroupPaths.get(j);
1291 		shape.isPickable = s.pickable[i];
1292 		shape.isCollidable = s.collidable[i];
1293 
1294 		shape.initMirrorShape3D(s, this, j);
1295 		mirrorShape3D.add(j, shape);
1296 
1297 		msList.add(shape);
1298 		// Add any scoped lights to the mirror shape
1299 		if (s.lights != null) {
1300 		    ArrayList l = (ArrayList)s.lights.get(j);
1301 		    if (l != null) {
1302 			for (int m = 0; m < l.size(); m++) {
1303 			    shape.addLight((LightRetained)l.get(m));
1304 			}
1305 		    }
1306 		}
1307 
1308 		// Add any scoped fog
1309 		if (s.fogs != null) {
1310 		    ArrayList l = (ArrayList)s.fogs.get(j);
1311 		    if (l != null) {
1312 			for (int m = 0; m < l.size(); m++) {
1313 			    shape.addFog((FogRetained)l.get(m));
1314 			}
1315 		    }
1316 		}
1317 
1318 		// Add any scoped modelClip
1319 		if (s.modelClips != null) {
1320 		    ArrayList l = (ArrayList)s.modelClips.get(j);
1321 		    if (l != null) {
1322 			for (int m = 0; m < l.size(); m++) {
1323 			    shape.addModelClip((ModelClipRetained)l.get(m));
1324 			}
1325 		    }
1326 		}
1327 
1328 		// Add any scoped alt app
1329 		if (s.altAppearances != null) {
1330 		    ArrayList l = (ArrayList)s.altAppearances.get(j);
1331 		    if (l != null) {
1332 			for (int m = 0; m < l.size(); m++) {
1333 			    shape.addAltApp((AlternateAppearanceRetained)l.get(m));
1334 			}
1335 		    }
1336 		}
1337 
1338 		if (s.viewLists != null)
1339 		    shape.viewList = (ArrayList)s.viewLists.get(i);
1340 		else
1341 		    shape.viewList = null;
1342 
1343 		//		((GeometryArrayRetained)(morphedGeometryArray.retained)).addUser(shape);
1344 
1345 
1346                 ga = Shape3DRetained.getGeomAtom(shape);
1347 
1348 		// Add the geometry atom for this shape to the Targets
1349 		s.nodeList.add(ga);
1350 
1351                 if (s.transformTargets != null &&
1352                                 s.transformTargets[i] != null) {
1353 		    s.transformTargets[i].addNode(ga, Targets.GEO_TARGETS);
1354 		}
1355                 if (s.switchTargets != null &&
1356                         s.switchTargets[i] != null) {
1357 		    s.switchTargets[i].addNode(shape, Targets.GEO_TARGETS);
1358                     shape.closestSwitchParent = s.closestSwitchParents[i];
1359                     shape.closestSwitchIndex = s.closestSwitchIndices[i];
1360                 }
1361         	shape.switchState = (SwitchState)s.switchStates.get(j);
1362 
1363 	    }
1364 	} else {
1365 	    shape = new Shape3DRetained();
1366 	    shape.localToVworld = new Transform3D[1][];
1367 	    shape.localToVworldIndex = new int[1][];
1368 	    shape.localToVworld[0] = this.localToVworld[0];
1369 	    shape.localToVworldIndex[0] = this.localToVworldIndex[0];
1370 	    shape.branchGroupPath = (BranchGroupRetained []) branchGroupPaths.get(0);
1371 	    shape.isPickable = s.pickable[0];
1372 	    shape.isCollidable = s.collidable[0];
1373 	    shape.initMirrorShape3D(s, this, 0);
1374 	    mirrorShape3D.add(shape);
1375 
1376 	    msList.add(shape);
1377 	    // Add any scoped lights to the mirror shape
1378 	    if (s.lights != null) {
1379 		ArrayList l = (ArrayList)s.lights.get(0);
1380 		if (l != null) {
1381 		    for (int m = 0; m < l.size(); m++) {
1382 			shape.addLight((LightRetained)l.get(m));
1383 		    }
1384 		}
1385 	    }
1386 
1387 	    // Add any scoped fog
1388 	    if (s.fogs != null) {
1389 		ArrayList l = (ArrayList)s.fogs.get(0);
1390 		if (l != null) {
1391 		    for (int m = 0; m < l.size(); m++) {
1392 			shape.addFog((FogRetained)l.get(m));
1393 		    }
1394 		}
1395 	    }
1396 
1397 	    // Add any scoped modelClip
1398 	    if (s.modelClips != null) {
1399 		ArrayList l = (ArrayList)s.modelClips.get(0);
1400 		if (l != null) {
1401 		    for (int m = 0; m < l.size(); m++) {
1402 			shape.addModelClip((ModelClipRetained)l.get(m));
1403 		    }
1404 		}
1405 	    }
1406 
1407 	    // Add any scoped alt app
1408 	    if (s.altAppearances != null) {
1409 		ArrayList l = (ArrayList)s.altAppearances.get(0);
1410 		if (l != null) {
1411 		    for (int m = 0; m < l.size(); m++) {
1412 			shape.addAltApp((AlternateAppearanceRetained)l.get(m));
1413 		    }
1414 		}
1415 	    }
1416 
1417 	    if (s.viewLists != null)
1418 		shape.viewList = (ArrayList)s.viewLists.get(0);
1419 	    else
1420 		shape.viewList = null;
1421 
1422 	    //	    ((GeometryArrayRetained)(morphedGeometryArray.retained)).addUser(shape);
1423 
1424             ga = Shape3DRetained.getGeomAtom(shape);
1425 
1426     	    // Add the geometry atom for this shape to the Targets
1427 	    s.nodeList.add(ga);
1428 
1429             if (s.transformTargets != null &&
1430                                 s.transformTargets[0] != null) {
1431 		s.transformTargets[0].addNode(ga, Targets.GEO_TARGETS);
1432 	    }
1433             if (s.switchTargets != null &&
1434                         s.switchTargets[0] != null) {
1435 		s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS);
1436                 shape.closestSwitchParent = s.closestSwitchParents[0];
1437                 shape.closestSwitchIndex = s.closestSwitchIndices[0];
1438             }
1439             shape.switchState = (SwitchState)s.switchStates.get(0);
1440 	}
1441 	if (appearance != null) {
1442 	    synchronized(appearance.liveStateLock) {
1443 		appearance.setLive(inBackgroundGroup, s.refCount);
1444 		appearance.initMirrorObject();
1445 		if (appearance.renderingAttributes != null)
1446 		    visible = appearance.renderingAttributes.visible;
1447 		for (int k = 0; k < msList.size(); k++) {
1448 		    Shape3DRetained sh = (Shape3DRetained)msList.get(k);
1449 		    sh.appearance = (AppearanceRetained)appearance.mirror;
1450 		    appearance.addAMirrorUser(sh);
1451 		}
1452 	    }
1453 
1454 	}
1455 	else {
1456 	    for (int k = 0; k < msList.size(); k++) {
1457 		Shape3DRetained sh = (Shape3DRetained)msList.get(k);
1458 		sh.appearance = null;
1459 	    }
1460 	}
1461 
1462 	s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY |
1463 			    J3dThread.UPDATE_TRANSFORM |
1464 			    J3dThread.UPDATE_RENDER |
1465 			    J3dThread.UPDATE_RENDERING_ATTRIBUTES);
1466 
1467 	// Need to clone the geometry , if its indexed ...
1468 	if (refCount == 1 && this.geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
1469 	    J3dMessage mChangeMessage = new J3dMessage();
1470 	    mChangeMessage.type = J3dMessage.MORPH_CHANGED;
1471 	    mChangeMessage.threads = J3dThread.UPDATE_RENDERING_ATTRIBUTES;
1472 	    mChangeMessage.args[0] = this;
1473 	    mChangeMessage.args[1]= new Integer(GEOMETRY_CHANGED);
1474 	    mChangeMessage.universe = universe;
1475 	    VirtualUniverse.mc.processMessage(mChangeMessage);
1476 	}
1477 	super.markAsLive();
1478 
1479     }
1480 
1481 
1482     /**
1483      * assign a name to this node when it is made live.
1484      */
clearLive(SetLiveState s)1485     void clearLive(SetLiveState s) {
1486 	int i, j;
1487 	Shape3DRetained shape;
1488 	Object[] shapes;
1489 	ArrayList appList = new ArrayList();
1490 	GeometryAtom ga;
1491 
1492 	super.clearLive(s);
1493 
1494 	for (i = 0; i < numGeometryArrays; i++) {
1495 	    synchronized(geometryArrays[i].liveStateLock) {
1496 		geometryArrays[i].clearLive(s.refCount);
1497 		// Remove this morph object as user, when the last branch
1498 		// is clearlived
1499 		if (refCount <= 0) {
1500 		    geometryArrays[i].removeMorphUser(this);
1501 		}
1502 	    }
1503 	}
1504 	GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
1505 
1506 	mga.clearLive( s.refCount);
1507 
1508 	if (inSharedGroup) {
1509 	    shapes = mirrorShape3D.toArray();
1510 	    for (i=0; i<s.keys.length; i++) {
1511 		for (j=0; j<shapes.length; j++) {
1512 		    shape = (Shape3DRetained)shapes[j];
1513 		    if (shape.key.equals(s.keys[i])) {
1514 			// clearMirrorShape(shape);
1515 			mirrorShape3D.remove(j);
1516                 	if (s.switchTargets != null &&
1517                         	s.switchTargets[i] != null) {
1518                             s.switchTargets[i].addNode(shape,
1519                                                         Targets.GEO_TARGETS);
1520                         }
1521 			if (appearance != null)
1522 			    appList.add(shape);
1523 
1524 			//			((GeometryArrayRetained)(morphedGeometryArray.retained)).removeUser(shape);
1525                         ga = Shape3DRetained.getGeomAtom(shape);
1526 
1527 			// Add the geometry atoms for this shape to the Targets
1528 			s.nodeList.add(ga);
1529                         if (s.transformTargets != null &&
1530                                 s.transformTargets[i] != null) {
1531                             s.transformTargets[i].addNode(ga,
1532 							  Targets.GEO_TARGETS);
1533                         }
1534 		    }
1535 		}
1536 	    }
1537 	} else {
1538 	    // Only entry 0 is valid
1539 	    shape = (Shape3DRetained)mirrorShape3D.get(0);
1540 	    // clearMirrorShape(shape);
1541 	    mirrorShape3D.remove(0);
1542             if (s.switchTargets != null &&
1543                         s.switchTargets[0] != null) {
1544                 s.switchTargets[0].addNode(shape, Targets.GEO_TARGETS);
1545             }
1546 	    if (appearance != null)
1547 		appList.add(shape);
1548 
1549 	    //	    ((GeometryArrayRetained)(morphedGeometryArray.retained)).removeUser(shape);
1550             ga = Shape3DRetained.getGeomAtom(shape);
1551 
1552 	    // Add the geometry atom for this shape to the Targets
1553 	    s.nodeList.add(ga);
1554             if (s.transformTargets != null &&
1555                                 s.transformTargets[0] != null) {
1556                 s.transformTargets[0].addNode(ga, Targets.GEO_TARGETS);
1557             }
1558 	}
1559 	if (appearance != null) {
1560 	    synchronized(appearance.liveStateLock) {
1561 		appearance.clearLive(s.refCount);
1562 		for (int k = 0; k < appList.size(); k++) {
1563 		    appearance.removeAMirrorUser((Shape3DRetained)appList.get(k));
1564 		}
1565 	    }
1566 	}
1567 
1568 	s.notifyThreads |= (J3dThread.UPDATE_GEOMETRY |
1569 			    J3dThread.UPDATE_TRANSFORM |
1570 			    // This is used to clear the scope info
1571 			    // of all the mirror shapes
1572 			    J3dThread.UPDATE_RENDERING_ENVIRONMENT |
1573 			    J3dThread.UPDATE_RENDER);
1574 
1575     }
1576 
1577 
updatePickable(HashKey keys[], boolean pick[])1578     void updatePickable(HashKey keys[], boolean pick[]) {
1579 	super.updatePickable(keys, pick);
1580 
1581 	Shape3DRetained shape;
1582 
1583 	if (!inSharedGroup) {
1584 	    shape = (Shape3DRetained) mirrorShape3D.get(0);
1585 	    shape.isPickable = pick[0];
1586 	} else {
1587 	    int size = mirrorShape3D.size();
1588 	    for (int j=0; j< keys.length; j++) {
1589 		for (int i=0; i < size; i++) {
1590 		    shape = (Shape3DRetained) mirrorShape3D.get(i);
1591 		    if (keys[j].equals(shape.key)) {
1592 			shape.isPickable = pick[j];
1593 			break;
1594 		    }
1595 
1596 		}
1597 	    }
1598 	}
1599     }
1600 
1601 
updateCollidable(HashKey keys[], boolean collide[])1602     void updateCollidable(HashKey keys[], boolean collide[]) {
1603 	super.updateCollidable(keys, collide);
1604 	Shape3DRetained shape;
1605 
1606 	if (!inSharedGroup) {
1607 	    shape = (Shape3DRetained) mirrorShape3D.get(0);
1608 	    shape.isCollidable = collide[0];
1609 	} else {
1610 	    int size = mirrorShape3D.size();
1611 	    for (int j=0; j< keys.length; j++) {
1612 		for (int i=0; i < size; i++) {
1613 		    shape = (Shape3DRetained) mirrorShape3D.get(i);
1614 		    if (keys[j].equals(shape.key)) {
1615 			shape.isCollidable = collide[j];
1616 			break;
1617 		    }
1618 
1619 		}
1620 	    }
1621 	}
1622     }
1623 
getMirrorShape(SceneGraphPath path)1624     Shape3DRetained getMirrorShape(SceneGraphPath path) {
1625 	if (!inSharedGroup) {
1626 	    return (Shape3DRetained) mirrorShape3D.get(0);
1627 	}
1628 	HashKey key = new HashKey("");
1629 	path.getHashKey(key);
1630 	return getMirrorShape(key);
1631     }
1632 
getMirrorShape(HashKey key)1633     Shape3DRetained getMirrorShape(HashKey key) {
1634 	int i = key.equals(localToVworldKeys, 0, localToVworldKeys.length);
1635 	if (i>=0) {
1636 	    return (Shape3DRetained) mirrorShape3D.get(i);
1637 	}
1638 
1639 	// Not possible
1640 	throw new RuntimeException("Shape3DRetained: MirrorShape Not found!");
1641     }
1642 
getMirrorObjects(ArrayList leafList, HashKey key)1643     void getMirrorObjects(ArrayList leafList, HashKey key) {
1644 	Shape3DRetained ms;
1645 	if (inSharedGroup) {
1646 	    ms = getMirrorShape(key);
1647 	}
1648 	else {
1649 	    ms = (Shape3DRetained)mirrorShape3D.get(0);
1650 	}
1651 	GeometryAtom ga = Shape3DRetained.getGeomAtom(ms);
1652 	leafList.add(ga);
1653 
1654     }
1655 
setBoundsAutoCompute(boolean autoCompute)1656     void setBoundsAutoCompute(boolean autoCompute) {
1657         if (autoCompute != boundsAutoCompute) {
1658             if (autoCompute) {
1659                 // localBounds may not have been set to bbox
1660                 localBounds = new BoundingBox();
1661 		if (source.isLive() && morphedGeometryArray != null) {
1662 		    GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
1663 		    mga.incrComputeGeoBounds(); // This compute the bbox if dirty
1664 		    mga.decrComputeGeoBounds();
1665 		}
1666             }
1667 
1668 
1669 	    localBounds = getBounds();
1670             super.setBoundsAutoCompute(autoCompute);
1671             if (source.isLive()) {
1672                 J3dMessage message = new J3dMessage();
1673                 message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
1674                 message.threads = J3dThread.UPDATE_TRANSFORM |
1675 		                  J3dThread.UPDATE_GEOMETRY |
1676 		                  J3dThread.UPDATE_RENDER;
1677                 message.universe = universe;
1678                 message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
1679 		message.args[1] = localBounds;
1680                 VirtualUniverse.mc.processMessage(message);
1681             }
1682         }
1683     }
1684 
updateBounds()1685     void updateBounds() {
1686 	localBounds = getEffectiveBounds();
1687 	if (source.isLive()) {
1688 	    J3dMessage message = new J3dMessage();
1689 	    message.type = J3dMessage.BOUNDS_AUTO_COMPUTE_CHANGED;
1690 	    message.threads = J3dThread.UPDATE_TRANSFORM |
1691 		J3dThread.UPDATE_GEOMETRY |
1692 		J3dThread.UPDATE_RENDER;
1693                 message.universe = universe;
1694                 message.args[0] = Shape3DRetained.getGeomAtomsArray(mirrorShape3D);
1695 		message.args[1] = localBounds;
1696                 VirtualUniverse.mc.processMessage(message);
1697 	}
1698     }
1699 
1700     /**
1701      * Initialization of morphed geometry
1702      */
initMorphedGeometry()1703     void initMorphedGeometry() {
1704       int  vFormat, geoType, stripVCount[];
1705       int iCount = 0;
1706       int numStrips = 0;
1707       int texCoordSetCount = 0;
1708       int texCoordSetMapLen = 0;
1709       int [] texCoordSetMap = null;
1710       int k;
1711       GeometryArrayRetained geo = geometryArrays[0];
1712       vFormat = ((geo.getVertexFormat() | (GeometryArray.BY_REFERENCE)) & ~(GeometryArray.INTERLEAVED)) ;
1713       texCoordSetCount = geo.getTexCoordSetCount();
1714       texCoordSetMapLen = geo.getTexCoordSetMapLength();
1715       if (texCoordSetMapLen > 0) {
1716           texCoordSetMap = new int[texCoordSetMapLen];
1717 	   geo.getTexCoordSetMap(texCoordSetMap);
1718       }
1719       geoType = geo.geoType;
1720 
1721       switch (geoType){
1722 	case GeometryRetained.GEO_TYPE_QUAD_SET:
1723 	    this.morphedGeometryArray =
1724 	     	new QuadArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1725 				texCoordSetMap);
1726 	    break;
1727 	case GeometryRetained.GEO_TYPE_TRI_SET:
1728 	    this.morphedGeometryArray =
1729 		new TriangleArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1730 				texCoordSetMap);
1731 	    break;
1732 	case GeometryRetained.GEO_TYPE_POINT_SET:
1733 	    this.morphedGeometryArray =
1734 		new PointArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1735 				texCoordSetMap);
1736 	    break;
1737 	case GeometryRetained.GEO_TYPE_LINE_SET:
1738 	    this.morphedGeometryArray =
1739 		new LineArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1740 				texCoordSetMap);
1741 	    break;
1742 	case GeometryRetained.GEO_TYPE_TRI_STRIP_SET:
1743 	    numStrips = ((TriangleStripArrayRetained)geo).getNumStrips();
1744 	    stripVCount = new int[numStrips];
1745 	    ((TriangleStripArrayRetained)geo).getStripVertexCounts(stripVCount);
1746 	    this.morphedGeometryArray =
1747 		new TriangleStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1748 			texCoordSetMap, stripVCount);
1749 	    break;
1750 	case GeometryRetained.GEO_TYPE_TRI_FAN_SET:
1751 	    numStrips = ((TriangleFanArrayRetained)geo).getNumStrips();
1752 	    stripVCount = new int[numStrips];
1753 	    ((TriangleFanArrayRetained)geo).getStripVertexCounts(stripVCount);
1754 	    this.morphedGeometryArray =
1755 		new TriangleFanArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1756 			texCoordSetMap, stripVCount);
1757 		break;
1758 	case GeometryRetained.GEO_TYPE_LINE_STRIP_SET:
1759 	    numStrips = ((LineStripArrayRetained)geo).getNumStrips();
1760 	    stripVCount = new int[numStrips];
1761 	    ((LineStripArrayRetained)geo).getStripVertexCounts(stripVCount);
1762 	    this.morphedGeometryArray =
1763 		new LineStripArray(geometryArrays[0].validVertexCount, vFormat, texCoordSetCount,
1764 			texCoordSetMap, stripVCount);
1765 		break;
1766 
1767 	case GeometryRetained.GEO_TYPE_INDEXED_QUAD_SET:
1768 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1769 	    this.morphedGeometryArray =
1770 		new IndexedQuadArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1771 			texCoordSetMap, iCount);
1772 		break;
1773 	case GeometryRetained.GEO_TYPE_INDEXED_TRI_SET:
1774 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1775 	    this.morphedGeometryArray =
1776 		new IndexedTriangleArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1777 			texCoordSetMap, iCount);
1778 		break;
1779 	case GeometryRetained.GEO_TYPE_INDEXED_POINT_SET:
1780 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1781 	    this.morphedGeometryArray =
1782 		new IndexedPointArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1783 			texCoordSetMap, iCount);
1784 		break;
1785 	case GeometryRetained.GEO_TYPE_INDEXED_LINE_SET:
1786 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1787 	    this.morphedGeometryArray =
1788 		new IndexedLineArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1789 			texCoordSetMap, iCount);
1790 	    break;
1791 	case GeometryRetained.GEO_TYPE_INDEXED_TRI_STRIP_SET:
1792 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1793 	    numStrips = ((IndexedTriangleStripArrayRetained)geo).getNumStrips();
1794 	    stripVCount = new int[numStrips];
1795 	    ((IndexedTriangleStripArrayRetained)geo).getStripIndexCounts(stripVCount);
1796 	    this.morphedGeometryArray =
1797 		new IndexedTriangleStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1798 			texCoordSetMap, iCount, stripVCount);break;
1799 	case GeometryRetained.GEO_TYPE_INDEXED_TRI_FAN_SET:
1800 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1801 	    numStrips = ((IndexedTriangleFanArrayRetained)geo).getNumStrips();
1802 	    stripVCount = new int[numStrips];
1803 	    ((IndexedTriangleFanArrayRetained)geo).getStripIndexCounts(stripVCount);
1804 	    this.morphedGeometryArray =
1805 		new IndexedTriangleFanArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1806 			texCoordSetMap, iCount, stripVCount);break;
1807 	case GeometryRetained.GEO_TYPE_INDEXED_LINE_STRIP_SET:
1808 	    iCount = ((IndexedGeometryArrayRetained)geo).getIndexCount();
1809 	    numStrips = ((IndexedLineStripArrayRetained)geo).getNumStrips();
1810 	    stripVCount = new int[numStrips];
1811 	    ((IndexedLineStripArrayRetained)geo).getStripIndexCounts(stripVCount);
1812 	    this.morphedGeometryArray =
1813 		new IndexedLineStripArray(geometryArrays[0].getNumCoordCount(), vFormat, texCoordSetCount,
1814 			texCoordSetMap, iCount, stripVCount);break;
1815 	}
1816 	if (geometryArrays[0] instanceof IndexedGeometryArrayRetained) {
1817 	    IndexedGeometryArrayRetained igeo = (IndexedGeometryArrayRetained)
1818 		geometryArrays[0];
1819 	    IndexedGeometryArray morphedGeo = (IndexedGeometryArray)
1820 		morphedGeometryArray;
1821 	    if ((vFormat & GeometryArray.COORDINATES) != 0) {
1822 		morphedGeo.setCoordinateIndices(0, igeo.indexCoord);
1823 	    }
1824 	    if ((vFormat & GeometryArray.USE_COORD_INDEX_ONLY) == 0) {
1825 	        if ((vFormat & GeometryArray.NORMALS) != 0) {
1826 	            morphedGeo.setNormalIndices(0, igeo.indexNormal);
1827 	        }
1828 	        if ((vFormat & GeometryArray.COLOR) != 0) {
1829 	            morphedGeo.setColorIndices(0, igeo.indexColor);
1830 	        }
1831 	        if ((vFormat & GeometryArray.TEXTURE_COORDINATE) != 0) {
1832 	            for (k = 0; k < texCoordSetCount; k++) {
1833 	                 morphedGeo.setTextureCoordinateIndices(k, 0,
1834                                  igeo.indexTexCoord[k]);
1835 	            }
1836 	        }
1837             }
1838 	}
1839 	this.morphedGeometryArray.setCapability(GeometryArray.ALLOW_REF_DATA_WRITE);
1840 
1841 	GeometryArrayRetained mga = (GeometryArrayRetained)morphedGeometryArray.retained;
1842 	mga.updateData(this);
1843 
1844 
1845     }
1846 
getMirrorShape3D(ArrayList list, HashKey k)1847     void getMirrorShape3D(ArrayList list, HashKey k) {
1848 	Shape3DRetained ms;
1849 	if (inSharedGroup) {
1850 	    ms = getMirrorShape(k);
1851 	}
1852 	else {
1853 	    ms = (Shape3DRetained)mirrorShape3D.get(0);
1854 	}
1855 	list.add(ms);
1856 
1857     }
1858 
compile(CompileState compState)1859     void compile(CompileState compState) {
1860 
1861         super.compile(compState);
1862 
1863         // XXXX: for now keep the static transform in the parent tg
1864         compState.keepTG = true;
1865 
1866         if (J3dDebug.devPhase && J3dDebug.debug) {
1867             compState.numMorphs++;
1868         }
1869     }
1870 
doErrorCheck(GeometryArrayRetained prevGeo, GeometryArrayRetained geo)1871     void doErrorCheck(GeometryArrayRetained prevGeo, GeometryArrayRetained geo) {
1872 
1873 	// If indexed Geometry array check the entire list instead of just the vcount
1874 	if ((prevGeo.vertexFormat != geo.vertexFormat) ||
1875 	    (prevGeo.validVertexCount != geo.validVertexCount) ||
1876 	    (prevGeo.geoType != geo.geoType) ||
1877 	    (prevGeo.texCoordSetCount != geo.texCoordSetCount)) {
1878 	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1879 	}
1880 	if (geo.getTexCoordSetMapLength() != prevGeo.getTexCoordSetMapLength()){
1881 	    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1882 	}
1883 	int texCoordSetMapLen = geo.getTexCoordSetMapLength();
1884 	int[] prevSvc= prevGeo.texCoordSetMap;
1885 	int[] svc= geo.texCoordSetMap;
1886 	for (int k = 0; k < texCoordSetMapLen; k++) {
1887 	    if (prevSvc[k] != svc[k])
1888 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1889 	}
1890 
1891 	if (geo instanceof GeometryStripArrayRetained) {
1892 	    prevSvc= ((GeometryStripArrayRetained)prevGeo).stripVertexCounts;
1893 	    svc= ((GeometryStripArrayRetained)geo).stripVertexCounts;
1894 	    if (prevSvc.length != svc.length)
1895 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1896 	    for (int k = 0; k < prevSvc.length; k++) {
1897 		if (prevSvc[k] != svc[k])
1898 		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1899 	    }
1900 	} else if (geo instanceof IndexedGeometryArrayRetained) {
1901 	    if (((IndexedGeometryArrayRetained)prevGeo).validIndexCount != ((IndexedGeometryArrayRetained)geo).validIndexCount)
1902 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1903 
1904 	    // If by reference, then all array lengths should be same
1905 	    if (geo.getNumCoordCount() != prevGeo.getNumCoordCount() ||
1906 		geo.getNumColorCount() != prevGeo.getNumColorCount() ||
1907 		geo.getNumNormalCount() != prevGeo.getNumNormalCount()) {
1908 		throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1909 	    }
1910 	    int texCoordSetCount = geo.getTexCoordSetCount();
1911 	    for (int k = 0; k < texCoordSetCount; k++) {
1912 		if (geo.getNumTexCoordCount(k) != prevGeo.getNumTexCoordCount(k)) {
1913 		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1914 		}
1915 	    }
1916 
1917 	    if (geo instanceof IndexedGeometryStripArrayRetained) {
1918 		prevSvc= ((IndexedGeometryStripArrayRetained)prevGeo).stripIndexCounts;
1919 		svc= ((IndexedGeometryStripArrayRetained)geo).stripIndexCounts;
1920 		if (prevSvc.length != svc.length)
1921 		    throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1922 		for (int k = 0; k < prevSvc.length; k++) {
1923 		    if (prevSvc[k] != svc[k])
1924 			throw new IllegalArgumentException(J3dI18N.getString("MorphRetained1"));
1925 		}
1926 	    }
1927 	}
1928     }
1929 
handleFrequencyChange(int bit)1930     void handleFrequencyChange(int bit) {
1931 	int mask = 0;
1932 	if (bit == Morph.ALLOW_GEOMETRY_ARRAY_WRITE) {
1933 	    mask = GEOMETRY_CHANGED;
1934 	}
1935 	else if (bit == Morph.ALLOW_APPEARANCE_WRITE) {
1936 	    mask = APPEARANCE_CHANGED;
1937 	}
1938 	else if (bit == Morph.ALLOW_APPEARANCE_OVERRIDE_WRITE) {
1939 	    mask = APPEARANCEOVERRIDE_CHANGED;
1940 	}
1941 	if (mask != 0) {
1942 	    if (source.getCapabilityIsFrequent(bit))
1943 		changedFrequent |= mask;
1944 	    else if (!source.isLive()) {
1945 		changedFrequent &= ~mask;
1946 	    }
1947 	}
1948     }
1949 
searchGeometryAtoms(UnorderList list)1950     void searchGeometryAtoms(UnorderList list) {
1951 	list.add(Shape3DRetained.getGeomAtom(
1952 	     (Shape3DRetained) mirrorShape3D.get(0)));
1953     }
1954 }
1955 
1956 
1957 
1958 
1959 
1960