1 /*
2  * $RCSfile: GeometryInfo.java,v $
3  *
4  * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistribution of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  *
13  * - Redistribution in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  *
18  * Neither the name of Sun Microsystems, Inc. or the names of
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * This software is provided "AS IS," without a warranty of any
23  * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
24  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
26  * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
27  * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
28  * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
29  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
30  * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
31  * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
32  * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
33  * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGES.
35  *
36  * You acknowledge that this software is not designed, licensed or
37  * intended for use in the design, construction, operation or
38  * maintenance of any nuclear facility.
39  *
40  * $Revision: 1.4 $
41  * $Date: 2007/02/09 17:20:19 $
42  * $State: Exp $
43  */
44 
45 package com.sun.j3d.utils.geometry;
46 
47 import com.sun.j3d.utils.geometry.Triangulator;
48 import java.io.*;
49 import javax.media.j3d.*;
50 import javax.vecmath.*;
51 import com.sun.j3d.internal.J3dUtilsI18N;
52 import java.util.HashMap;
53 import com.sun.j3d.utils.geometry.GeometryInfoGenerator;
54 import com.sun.j3d.internal.BufferWrapper;
55 import com.sun.j3d.internal.ByteBufferWrapper;
56 import com.sun.j3d.internal.FloatBufferWrapper;
57 import com.sun.j3d.internal.DoubleBufferWrapper;
58 import com.sun.j3d.internal.ByteOrderWrapper;
59 import javax.media.j3d.J3DBuffer;
60 
61 /**
62  * The GeometryInfo object holds data for processing by the Java3D geometry
63  * utility tools.<p><blockquote>
64  *
65  *         The NormalGenerator adds normals to geometry without normals.<p>
66  *
67  *         The Stripifier combines adjacent triangles into triangle strips for
68  *         more efficent rendering.<p></blockquote>
69  *
70  * Also, the GeometryCompressor can take a set of GeometryInfo objects in a
71  * CompressionSteam and generate a CompressedGeometry object from the
72  * geometry.<p>
73  *         Geometry is loaded into a GeometryInfo in a manner similar to the
74  * <a href="../../../../../javax/media/j3d/GeometryArray.html">
75  * GeometryArray</a> methods.  The constructor for the GeometryInfo takes a flag
76  * that specifies the kind of data being loaded.  The vertex data is
77  * specified using methods that are similar to the GeometryArray methods, but
78  * with fewer variations.<p>
79  *         The major difference between GeometryInfo and GeometryArray is
80  * that the number of vertices, vertex format, and other data are specified
81  * implictly, rather than as part of the constructor.  The number of verticies
82  * comes from the number of coordinates passed to the setCoordinates()
83  * method.  The format comes from the set of data components that are
84  * specified.  For example, calling the setCoordinates(), setColors3() and
85  * setTextureCoordinatesParames(1, 2) methods implies a
86  * format of COORDINATES | COLOR_3
87  * | TEXTURE_COORDINATE_2.  Indexed representation is specified by calling
88  * the methods that specify the indices, for example
89  * setCoordinateIndices().<p>
90  *         Stripped primitives are loaded using the TRIANGLE_FAN_ARRAY or
91  * TRIANGLE_STRIP_ARRAY flags to the constructor.  The setStripCounts()
92  * method specifies the length of each strip.<p>
93  *         A set of complex polygons is loaded using the POLYGON_ARRAY
94  * flag to the constructor.  The setStripCounts() method specifies the length
95  * of each contour of the polygons.  The setContourCounts() method specifies
96  * the number of countours in each polygon. For example, a triangle with a
97  * triangular hole would have strip counts [3, 3] (indicating two contours of
98  * three points) and contour counts [2] (indicating a single polygon with two
99  * contours).<p>
100  *         GeometryInfo itelf contains some simple utilities, such as
101  * calculating indices for non-indexed data ("indexifying") and getting rid
102  * of unused data in your indexed geometry ("compacting").<p>
103  *         The geometry utility tools modify the contents of the
104  * GeometryInfo.  After processing, the resulting geometry can be extracted
105  * from the GeometryInfo by calling getGeometryArray().  If multiple tools
106  * are used, the order of processing should be: generate normals, then
107  * stripify.  For example, to convert a general mesh of polygons without
108  * normals into an optimized mesh call:
109  * <pre><blockquote>
110  *         GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
111  *         // initialize the geometry info here
112  *         // generate normals
113  *         NormalGenerator ng = new NormalGenerator();
114  *         ng.generateNormals(gi);
115  *         // stripify
116  *         Stripifier st = new Stripifier();
117  *         st.stripify(gi);
118  *         GeometryArray result = gi.getGeometryArray();
119  * </blockquote></pre>
120  *
121  * @see NormalGenerator
122  * @see Stripifier
123  * @see com.sun.j3d.utils.compression.CompressionStream
124  * @see com.sun.j3d.utils.compression.GeometryCompressor
125  * @see javax.media.j3d.GeometryArray
126  */
127 
128 public class GeometryInfo {
129 
130   /**
131    * Send to the constructor to inform that the data will be arranged so
132    * that each set of three vertices form an independent triangle
133    */
134   public static final int TRIANGLE_ARRAY = 1;
135 
136   /**
137    * Send to the constructor to inform that the data will be arranged so
138    * that each set of four vertices form an independent quad
139    */
140   public static final int QUAD_ARRAY = 2;
141 
142   /**
143    * Send to the constructor to inform that the data will be arranged so
144    * that the stripCounts array indicates how many vertices to use
145    * for each triangle fan.
146    */
147   public static final int TRIANGLE_FAN_ARRAY = 3;
148 
149   /**
150    * Send to the constructor to inform that the data will be arranged so
151    * that the stripCounts array indicates how many vertices to use
152    * for each triangle strip.
153    */
154   public static final int TRIANGLE_STRIP_ARRAY = 4;
155 
156   /**
157    * Send to the constructor to inform that the data is arranged as
158    * possibly multi-contour, possible non-planar polygons.
159    * The stripCounts array indicates how many vertices to use
160    * for each contour, and the contourCounts array indicates how many
161    * stripCounts entries to use for each polygon.  The first
162    * contour is the bounding polygon, and subsequent contours are
163    * "holes."  If contourCounts is left null, the default is
164    * one contour per polygon.
165    */
166   public static final int POLYGON_ARRAY = 5;
167 
168   private int prim;
169 
170   // 1 Show indexification details
171   private static final int DEBUG = 0;
172 
173   private Point3f coordinates[] = null;
174   private Color3f colors3[] = null;
175   private Color4f colors4[] = null;
176   private Vector3f normals[] = null;
177   private Object texCoordSets[][] = null;
178 
179   private int coordinateIndices[] = null;
180   private int colorIndices[] = null;
181   private int normalIndices[] = null;
182   private int texCoordIndexSets[][] = null;
183 
184   private int[] texCoordSetMap = null;
185   private int texCoordSetCount = 0;
186   private int texCoordDim = 0;
187 
188   private int stripCounts[] = null;
189   private int contourCounts[] = null;
190 
191   private Triangulator tr = null;
192   private NormalGenerator ng = null;
193 
194   private int oldPrim = 0;
195   private int oldStripCounts[] = null;
196 
197   private boolean coordOnly = false;
198 
199 
200 
201   /**
202    * Constructor.
203    * Creates an empty GeometryInfo object.
204    * @param primitive Tells the GeometryInfo object the type of
205    * primitive data to be stored
206    * in it, so it will know the format of the data. It can be one of
207    * TRIANGLE_ARRAY,
208    * QUAD_ARRAY, TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
209    */
GeometryInfo(int primitive)210   public GeometryInfo(int primitive)
211   {
212       if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
213 	  prim = primitive;
214       } else {
215 	  throw new IllegalArgumentException(
216 	      J3dUtilsI18N.getString("GeometryInfo0"));
217       }
218   } // End of GeometryInfo(int)
219 
220 
221 
222   /**
223    * Contructor.  Populates the GeometryInfo with the geometry from
224    * the GeometryArray.<p>
225    * If the GeometryArray uses the <code>Initial</code> and
226    * <code>Valid</code> GeometryArray methods (<code>
227    * setInitialVertexIndex()</code> and <code>setValidVertexCount()
228    * </code> and their cousins) then only the needed geometry
229    * is copied into the GeometryInfo.
230    */
GeometryInfo(GeometryArray ga)231   public GeometryInfo(GeometryArray ga)
232   {
233     GeometryInfoGenerator.create(this, ga);
234   } // End of GeometryInfo(GeometryArray)
235 
236 
237 
238   /**
239    * Removes all data from the GeometryInfo and resets the primitive.
240    * After a call to reset(), the GeometryInfo object will be just like
241    * it was when it was newly constructed.
242    * @param primitive Either TRIANGLE_ARRAY, QUAD_ARRAY,
243    * TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
244    * Tells the GeometryInfo object the type of primitive data to be stored
245    * in it, so it will know the format of the data.
246    */
reset(int primitive)247   public void reset(int primitive)
248   {
249       if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
250 	  prim = primitive;
251       } else {
252 	  throw new IllegalArgumentException(
253 	      J3dUtilsI18N.getString("GeometryInfo0"));
254       }
255 
256       coordinates = null;
257       colors3 = null;
258       colors4 = null;
259       normals = null;
260 
261       coordinateIndices = null;
262       colorIndices = null;
263       normalIndices = null;
264 
265       stripCounts = null;
266       contourCounts = null;
267 
268       oldPrim = 0;
269       oldStripCounts = null;
270 
271       texCoordDim = 0;
272       texCoordSetCount = 0;
273       texCoordSets = null;
274       texCoordIndexSets = null;
275       texCoordSetMap = null;
276 
277       coordOnly = false;
278 
279   } // End of reset(int)
280 
281 
282 
283   /**
284    * Removes all data from this GeometryInfo and populates it with
285    * the geometry from the GeometryArray.
286    */
reset(GeometryArray ga)287   public void reset(GeometryArray ga)
288   {
289     GeometryInfoGenerator.create(this, ga);
290   } // End of reset(GeometryArray)
291 
292 
293 
294   // This method takes an indexed quad array and expands it to
295   // a list of indexed triangles.  It is used for the Coordinate
296   // indices as well as the color and texture indices.
expandQuad(int indices[])297   private int[] expandQuad(int indices[])
298   {
299       int triangles[] = new int[indices.length / 4 * 6];
300 
301       for (int i = 0 ; i < indices.length / 4 ; i++ ) {
302 	  triangles[i * 6 + 0] = indices[i * 4];
303 	  triangles[i * 6 + 1] = indices[i * 4 + 1];
304 	  triangles[i * 6 + 2] = indices[i * 4 + 2];
305 	  triangles[i * 6 + 3] = indices[i * 4];
306 	  triangles[i * 6 + 4] = indices[i * 4 + 2];
307 	  triangles[i * 6 + 5] = indices[i * 4 + 3];
308       }
309 
310       return triangles;
311   } // End of expandQuad
312 
313 
314 
315   // This method takes an indexed triangle fan and expands it to
316   // a list of indexed triangles.  It is used for the Coordinate
317   // indices as well as the color and texture indices.
expandTriFan(int numTris, int indices[])318   private int[] expandTriFan(int numTris, int indices[])
319   {
320       int triangles[] = new int[numTris * 3];
321       int p = 0;
322       int base = 0;
323       for (int f = 0 ; f < stripCounts.length ; f++) {
324 	  for (int t = 0 ; t < stripCounts[f] - 2 ; t++) {
325 	      triangles[p++] = indices[base];
326 	      triangles[p++] = indices[base + t + 1];
327 	      triangles[p++] = indices[base + t + 2];
328 	  }
329 	  base += stripCounts[f];
330       }
331       return triangles;
332   } // End of expandTriFan
333 
334 
335 
336   // This method takes an indexed triangle strip and expands it to
337   // a list of indexed triangles.  It is used for the Coordinate
338   // indices as well as the color and texture indices.
expandTriStrip(int numTris, int indices[])339   private int[] expandTriStrip(int numTris, int indices[])
340   {
341       int triangles[] = new int[numTris * 3];
342 
343       int p = 0;
344       int base = 0;
345       for (int s = 0 ; s < stripCounts.length ; s++) {
346 	  for (int t = 0 ; t < stripCounts[s] - 2 ; t++) {
347 
348 	      // Use a ping-ponging algorithm to reverse order on every other
349 	      // triangle to preserve winding
350 	      if (t % 2 == 0) {
351 		  triangles[p++] = indices[base + t + 0];
352 		  triangles[p++] = indices[base + t + 1];
353 		  triangles[p++] = indices[base + t + 2];
354 	      } else {
355 		  triangles[p++] = indices[base + t + 0];
356 		  triangles[p++] = indices[base + t + 2];
357 		  triangles[p++] = indices[base + t + 1];
358 	      }
359 	  }
360 	  base += stripCounts[s];
361       }
362 
363       return triangles;
364   } // End of expandTriStrip
365 
366 
367 
368   // Used by the NormalGenerator utility.  Informs the GeometryInfo object
369   // to remember its current primitive and stripCounts arrays so that
370   // they can be used to convert the object back to its original
371   // primitive
rememberOldPrim()372   void rememberOldPrim()
373   {
374       oldPrim = prim;
375       oldStripCounts = stripCounts;
376   } // End of rememberOldPrim
377 
378 
379 
380   // The NormalGenerator needs to know the original primitive for
381   // facet normal generation for quads
getOldPrim()382   int getOldPrim()
383   {
384       return oldPrim;
385   } // End of getOldPrim
386 
387 
388 
389   // Used by the Utility libraries other than the NormalGenerator.
390   // Informs the GeometryInfo object that the geometry need not
391   // be converted back to the original primitive before returning.
392   // For example, if a list of Fans is sent, converted to Triangles
393   // for normal generation, and then stripified by the Stripifyer,
394   // we want to make sure that GeometryInfo doesn't convert the
395   // geometry *back* to fans before creating the output GeometryArray.
forgetOldPrim()396   void forgetOldPrim()
397   {
398       oldPrim = 0;
399       oldStripCounts = null;
400   } // End of forgetOldPrim
401 
402 
403 
404   // We have changed the user's data from their original primitive
405   // type to TRIANGLE_ARRAY.  If this method is being called, it
406   // means we need to change it back (to try and hide from the user
407   // the fact that we've converted).  This usually happens when
408   // the user has used GeometryInfo for generating normals, but
409   // they are not Stripifying or Triangulating.  The function is
410   // called from getGeometryArray before creating the output data.
changeBackToOldPrim()411   private void changeBackToOldPrim()
412   {
413       if (oldPrim != 0) {
414 	  convertToIndexedTriangles();
415 	  if (ng == null) ng = new NormalGenerator();
416 	  ng.convertBackToOldPrim(this, oldPrim, oldStripCounts);
417 	  oldPrim = 0;
418 	  oldStripCounts = null;
419       }
420   } // End of changeBackToOldPrim
421 
422 
423 
424   /**
425    * Convert the GeometryInfo object to have primitive type TRIANGLE_ARRAY
426    * and be indexed.
427    * @throws IllegalArgumentException if coordinate data is missing,
428    * if the index lists aren't all the
429    * same length, if an index list is set and the corresponding data
430    * list isn't set, if a data list is set and the corresponding
431    * index list is unset (unless all index lists are unset or in
432    * USE_COORD_INDEX_ONLY format),
433    * if StripCounts or ContourCounts is inconsistent with the current
434    * primitive, if the sum of the contourCounts array doesn't equal
435    * the length of the StripCounts array, or if the number of vertices
436    * isn't a multiple of three (for triangles) or four (for quads).
437    */
convertToIndexedTriangles()438   public void convertToIndexedTriangles()
439   {
440       int triangles = 0;
441 
442       // This calls checkForBadData
443       indexify();
444 
445       if (prim == TRIANGLE_ARRAY) return;
446 
447       switch(prim) {
448 
449 	  case QUAD_ARRAY:
450 
451 	      coordinateIndices = expandQuad(coordinateIndices);
452 	      if (colorIndices != null) colorIndices = expandQuad(colorIndices);
453 	      if (normalIndices != null)
454 		  normalIndices = expandQuad(normalIndices);
455 	      for (int i = 0 ; i < texCoordSetCount ; i++)
456 		  texCoordIndexSets[i] = expandQuad(texCoordIndexSets[i]);
457 	      break;
458 
459 	  case TRIANGLE_FAN_ARRAY:
460 	      // Count how many triangles are in the object
461 	      for (int i = 0 ; i < stripCounts.length ; i++) {
462 		  triangles += stripCounts[i] - 2;
463 	      }
464 
465 	      coordinateIndices = expandTriFan(triangles, coordinateIndices);
466 	      if (colorIndices != null)
467 		  colorIndices = expandTriFan(triangles, colorIndices);
468 	      if (normalIndices != null)
469 		  normalIndices = expandTriFan(triangles, normalIndices);
470 	      for (int i = 0 ; i < texCoordSetCount ; i++)
471 		  texCoordIndexSets[i] = expandTriFan(triangles,
472 			      texCoordIndexSets[i]);
473 	      break;
474 
475 	  case TRIANGLE_STRIP_ARRAY:
476 	      // Count how many triangles are in the object
477 	      for (int i = 0 ; i < stripCounts.length ; i++) {
478 		  triangles += stripCounts[i] - 2;
479 	      }
480 
481 	      coordinateIndices = expandTriStrip(triangles, coordinateIndices);
482 	      if (colorIndices != null)
483 		  colorIndices = expandTriStrip(triangles, colorIndices);
484 	      if (normalIndices != null)
485 		  normalIndices = expandTriStrip(triangles, normalIndices);
486 	      for (int i = 0 ; i < texCoordSetCount ; i++)
487 		  texCoordIndexSets[i] = expandTriStrip(triangles,
488 			      texCoordIndexSets[i]);
489 	      break;
490 
491 	  case POLYGON_ARRAY:
492 	      if (tr == null) tr = new Triangulator();
493 	      tr.triangulate(this);
494 	      break;
495       }
496 
497       prim = TRIANGLE_ARRAY;
498       stripCounts = null;
499   } // End of convertToIndexedTriangles
500 
501 
502 
503   /**
504    * Get the current primitive.  Some of the utilities may change the
505    * primitive type of the data stored in the GeometryInfo object
506    * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
507    */
getPrimitive()508   public int getPrimitive()
509   {
510       return prim;
511   } // End of getPrimitive()
512 
513 
514 
515   /**
516    * Set the current primitive.  Some of the utilities may change the
517    * primitive type of the data stored in the GeometryInfo object
518    * (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
519    * But the user can't change the primitive type - it is set in the
520    * constructor.  Therefore, this method has package scope.
521    */
setPrimitive(int primitive)522   void setPrimitive(int primitive)
523   {
524       if ((prim >= TRIANGLE_ARRAY) && (prim <= POLYGON_ARRAY)) {
525 	  prim = primitive;
526       } else {
527 	  throw new IllegalArgumentException(
528 		  J3dUtilsI18N.getString("GeometryInfo0"));
529       }
530   } // End of setPrimitive()
531 
532 
533 
534   /**
535    * Sets the coordinates array.
536    * No data copying is done because a reference to user data is used.
537    */
setCoordinates(Point3f coordinates[])538   public void setCoordinates(Point3f coordinates[])
539   {
540       this.coordinates = coordinates;
541   } // End of setCoordinates
542 
543 
544 
545   /**
546    * Sets the coordinates array.
547    * The points are copied into the GeometryInfo object.
548    */
setCoordinates(Point3d coordinates[])549   public void setCoordinates(Point3d coordinates[])
550   {
551       if (coordinates == null) this.coordinates = null;
552       else {
553 	  this.coordinates = new Point3f[coordinates.length];
554 	  for (int i = 0 ; i < coordinates.length ; i++) {
555 	      this.coordinates[i] = new Point3f(
556 		      (float)(coordinates[i].x),
557 		      (float)(coordinates[i].y),
558 		      (float)(coordinates[i].z));
559 	  }
560       }
561   } // End of setCoordinates
562 
563 
564 
565   /**
566    * Sets the coordinates array.
567    * The points are copied into the GeometryInfo object.
568    */
setCoordinates(float coordinates[])569   public void setCoordinates(float coordinates[])
570   {
571       if (coordinates == null) this.coordinates = null;
572       else {
573 	  this.coordinates = new Point3f[coordinates.length / 3];
574 	  for (int i = 0 ; i < this.coordinates.length ; i++) {
575 	      this.coordinates[i] = new Point3f(coordinates[i * 3],
576 		      				coordinates[i * 3 + 1],
577 		      				coordinates[i * 3 + 2]);
578 	  }
579       }
580   } // End of setCoordinates
581 
582 
583 
584   /**
585    * Sets the coordinates array.
586    * The points are copied into the GeometryInfo object.
587    */
setCoordinates(double coordinates[])588   public void setCoordinates(double coordinates[])
589   {
590       if (coordinates == null) this.coordinates = null;
591       else {
592 	  this.coordinates = new Point3f[coordinates.length / 3];
593 	  for (int i = 0 ; i < coordinates.length / 3 ; i++) {
594 	      this.coordinates[i] = new Point3f((float)coordinates[i * 3],
595 					        (float)coordinates[i * 3 + 1],
596 					        (float)coordinates[i * 3 + 2]);
597 	  }
598       }
599   } // End of setCoordinates
600 
601 
602 
603   /**
604    * Retrieves a reference to the coordinate array.
605    */
getCoordinates()606   public Point3f[] getCoordinates()
607   {
608       return coordinates;
609   } // End of getCoordinates
610 
611 
612 
613   /**
614    * Sets the colors array.
615    * No data copying is done because a reference to
616    * user data is used.
617    */
setColors(Color3f colors[])618   public void setColors(Color3f colors[])
619   {
620       colors3 = colors;
621       colors4 = null;
622   } // End of setColors
623 
624 
625 
626   /**
627    * Sets the colors array.
628    * No data copying is done because a reference to
629    * user data is used.
630    */
setColors(Color4f colors[])631   public void setColors(Color4f colors[])
632   {
633       colors3 = null;
634       colors4 = colors;
635   } // End of setColors
636 
637 
638 
639   /**
640    * Sets the colors array.
641    * The points are copied into the GeometryInfo object.
642    */
setColors(Color3b colors[])643   public void setColors(Color3b colors[])
644   {
645       if (colors == null) {
646 	  colors3 = null;
647 	  colors4 = null;
648       } else {
649 	  colors3 = new Color3f[colors.length];
650 	  colors4 = null;
651 	  for (int i = 0 ; i < colors.length ; i++) {
652 	      colors3[i] = new Color3f((float) (colors[i].x & 0xff) / 255.0f,
653 		      		       (float) (colors[i].y & 0xff) / 255.0f,
654 		      		       (float) (colors[i].z & 0xff) / 255.0f);
655 	  }
656       }
657   } // End of setColors
658 
659 
660 
661   /**
662    * Sets the colors array.
663    * The points are copied into the GeometryInfo object.
664    */
setColors(Color4b colors[])665   public void setColors(Color4b colors[])
666   {
667       if (colors == null) {
668 	  colors3 = null;
669 	  colors4 = null;
670       } else {
671 	  colors3 = null;
672 	  colors4 = new Color4f[colors.length];
673 	  for (int i = 0 ; i < colors.length ; i++) {
674 	      colors4[i] = new Color4f((float) (colors[i].x & 0xff) / 255.0f,
675 		      		       (float) (colors[i].y & 0xff) / 255.0f,
676 		      		       (float) (colors[i].z & 0xff) / 255.0f,
677 		      		       (float) (colors[i].w & 0xff) / 255.0f);
678 	  }
679       }
680   } // End of setColors
681 
682 
683 
684   /**
685    * Sets the colors array.
686    * The points are copied into the GeometryInfo object, assuming
687    * 3 components (R, G, and B) per vertex.
688    */
setColors3(float colors[])689   public void setColors3(float colors[])
690   {
691       if (colors == null) {
692 	  colors3 = null;
693 	  colors4 = null;
694       } else {
695 	  colors3 = new Color3f[colors.length / 3];
696 	  colors4 = null;
697 	  for (int i = 0 ; i < colors.length / 3 ; i++) {
698 	      colors3[i] = new Color3f(colors[i * 3],
699 				       colors[i * 3 + 1],
700 				       colors[i * 3 + 2]);
701 	  }
702       }
703   } // End of setColors3
704 
705 
706 
707   /**
708    * Sets the colors array.
709    * The points are copied into the GeometryInfo object, assuming
710    * 4 components (R, G, B, and A) per vertex.
711    */
setColors4(float colors[])712   public void setColors4(float colors[])
713   {
714       if (colors == null) {
715 	  colors3 = null;
716 	  colors4 = null;
717       } else {
718 	  colors3 = null;
719 	  colors4 = new Color4f[colors.length / 4];
720 	  for (int i = 0 ; i < colors.length / 4 ; i++) {
721 	      colors4[i] = new Color4f(colors[i * 4],
722 		      		       colors[i * 4 + 1],
723 		      		       colors[i * 4 + 2],
724 		      		       colors[i * 4 + 3]);
725 	  }
726       }
727   } // End of setColors4
728 
729 
730 
731   /**
732    * Sets the colors array.
733    * The points are copied into the GeometryInfo object, assuming
734    * 3 components (R, G, and B) per vertex.
735    */
setColors3(byte colors[])736   public void setColors3(byte colors[])
737   {
738       if (colors == null) {
739 	  colors3 = null;
740 	  colors4 = null;
741       } else {
742 	  colors3 = new Color3f[colors.length / 3];
743 	  colors4 = null;
744 	  for (int i = 0 ; i < colors.length / 3 ; i++) {
745 	      colors3[i] =
746 		  new Color3f((float)(colors[i * 3] & 0xff) / 255.0f,
747 		      	      (float)(colors[i * 3 + 1] & 0xff) / 255.0f,
748 			      (float)(colors[i * 3 + 2] & 0xff) / 255.0f);
749 	  }
750       }
751   } // End of setColors3
752 
753 
754 
755   /**
756    * Sets the colors array.
757    * The points are copied into the GeometryInfo object, assuming
758    * 4 components (R, G, B, and A) per vertex.
759    */
setColors4(byte colors[])760   public void setColors4(byte colors[])
761   {
762       if (colors == null) {
763 	  colors3 = null;
764 	  colors4 = null;
765       } else {
766 	  colors3 = null;
767 	  colors4 = new Color4f[colors.length / 4];
768 	  for (int i = 0 ; i < colors.length / 4 ; i++) {
769 	      colors4[i] =
770 		  new Color4f((float)(colors[i * 4] & 0xff) / 255.0f,
771 			      (float)(colors[i * 4 + 1] & 0xff) / 255.0f,
772 			      (float)(colors[i * 4 + 2] & 0xff) / 255.0f,
773 			      (float)(colors[i * 4 + 3] & 0xff) / 255.0f);
774 	  }
775       }
776   } // End of setColors4
777 
778 
779 
780   /**
781    * Retrieves a reference to the colors array.  Will be either
782    * <code>Color3f[]</code> or <code>Color4f[]</code> depending on
783    * the type of the input data.  Call
784    * getNumColorComponents() to find out which version is returned.
785    */
getColors()786   public Object[] getColors()
787   {
788       if (colors3 != null) return colors3;
789       else return colors4;
790   } // End of getColors
791 
792 
793 
794   /**
795    * Returns the number of color data components stored per vertex
796    * in the current GeometryInfo object (3 for RGB or 4 for RGBA).
797    * If no colors are currently defined, 0 is returned.
798    */
getNumColorComponents()799   public int getNumColorComponents()
800   {
801       if (colors3 != null) return 3;
802       else if (colors4 != null) return 4;
803       else return 0;
804   } // End of getNumColorComponents
805 
806 
807 
808   /**
809    * Sets the normals array.
810    * No data copying is done because a reference to
811    * user data is used.
812    */
setNormals(Vector3f normals[])813   public void setNormals(Vector3f normals[])
814   {
815       this.normals = normals;
816   } // End of setNormals
817 
818 
819 
820   /**
821    * Sets the normals array.
822    * The points are copied into the GeometryInfo object.
823    */
setNormals(float normals[])824   public void setNormals(float normals[])
825   {
826       if (normals == null) this.normals = null;
827       else {
828 	  this.normals = new Vector3f[normals.length / 3];
829 	  for (int i = 0 ; i < this.normals.length ; i++) {
830 	      this.normals[i] = new Vector3f(normals[i * 3],
831 		      			     normals[i * 3 + 1],
832 		      			     normals[i * 3 + 2]);
833 	  }
834       }
835   } // End of setNormals(float[])
836 
837 
838 
839   /**
840    * Retrieves a reference to the normal array.
841    */
getNormals()842   public Vector3f[] getNormals()
843   {
844       return normals;
845   } // End of getNormals
846 
847 
848 
849   /**
850    * This method is used to specify the number of texture coordinate sets
851    * and the dimensionality of the texture coordinates.
852    * The number of texture coordinate sets must be specified to the GeometryInfo
853    * class before any of the sets are specified. The dimensionality of the
854    * texture coordinates may be 2, 3, or 4, corresponding to 2D, 3D, or 4D
855    * texture coordinates respectively.(All sets must have the same
856    * dimensionality.) The default is zero, 2D texture coordinate sets.
857    * This method should be called before any texture coordinate sets are
858    * specified because <b>calling this method will delete all previously
859    * specified texture coordinate and texture coordinate index arrays</b>
860    * associated with this GeometryInfo.  For example:
861    * <blockquote><pre>
862    *	geomInfo.setTextureCoordinateParams(2, 3);
863    *	geomInfo.setTextureCoordinates(0, tex0);
864    *	geomInfo.setTextureCoordinates(1, tex1);
865    *	geomInfo.setTextureCoordinateParams(1, 2);
866    *	geomInfo.getTexCoordSetCount();
867    * </blockquote></pre>
868    * The second call to <code>setTextureCoordinateParams</code> will erase all
869    * the texture coordinate arrays, so the subsequent call to <code>
870    * getTexCoordSetCount</code> will return 1.
871    * @param numSets The number of texture coordinate sets that will be
872    * specified for this GeometryInfo object.
873    * @param dim The dimensionality of the texture coordinates. Has to be 2, 3
874    * or 4.
875    * @throws IllegalArgumentException if the dimensionality of the texture
876    * coordinates is not one of 2, 3 or 4.
877    */
setTextureCoordinateParams(int numSets, int dim)878   public void setTextureCoordinateParams(int numSets, int dim)
879   {
880       if (dim == 2) {
881 	  texCoordSets = new TexCoord2f[numSets][];
882       } else if (dim == 3) {
883 	  texCoordSets = new TexCoord3f[numSets][];
884       } else if (dim == 4) {
885 	  texCoordSets = new TexCoord4f[numSets][];
886       } else {
887           throw new IllegalArgumentException(
888 	      J3dUtilsI18N.getString("GeometryInfo9"));
889       }
890       texCoordIndexSets = new int[numSets][];
891       texCoordDim = dim;
892       texCoordSetCount = numSets;
893   } // End of setTextureCoordinateParams
894 
895 
896 
897   /**
898    * Returns the number of texture coordinate sets in this GeometryInfo.
899    * This value is set with setTextureCoordinateParams().
900    * If setTextureCoordinateParams()
901    * has not been called, 0 is returned unless one of the deprecated
902    * texture coordinate methods has been called.  Calling one of the
903    * deprecated texture coordinate methods sets the count to 1.
904    * The deprecated texture coordinate methods are those that don't
905    * take texCoordSet as the first parameter.
906    * @return the number of texture coordinate sets in this
907    * GeometryInfo.
908    */
getTexCoordSetCount()909   public int getTexCoordSetCount() {
910       return texCoordSetCount;
911   }
912 
913 
914 
915   /**
916    * Returns the number of texture coordinate components that are stored
917    * per vertex.  Returns 2 for ST (2D), 3 for STR (3D),
918    * or 4 for STRQ (4D), aslo known as the "dimensionality" of the
919    * coordinates.  This value is set with
920    * setTextureCoordinateParams().  If setTextureCoordinateParams()
921    * has not been called, 0 is returned unless one of the deprecated
922    * texture coordinate methods has been called.  Calling one of the
923    * deprecated texture coordinate methods sets the dimensionality
924    * explicitly (if you called setTextureCoordinates(Point2f[]) then
925    * 2 is returned).
926    * The deprecated texture coordinate methods are those that don't
927    * take texCoordSet as the first parameter.
928    */
getNumTexCoordComponents()929   public int getNumTexCoordComponents()
930   {
931       return texCoordDim;
932   } // End of getNumTexCoordComponents
933 
934 
935 
936   /**
937    * Sets the mapping between texture coordinate sets and texture units.
938    * See the
939    * <a href="../../../../../javax/media/j3d/GeometryArray.html#texCoordSetMap">
940    * GeometryArray constructor </a> for further details.
941    * <p> <b>Note:</b> If the texCoordSetMap is not set, multi-texturing is
942    * turned off. Only the texture coordinate set at index 0 (if set) will be
943    * used. Any other sets specified by the GeometryInfo.setTextureCoordinate*
944    * methods will be ignored.
945    */
setTexCoordSetMap(int map[])946   public void setTexCoordSetMap(int map[]) {
947       texCoordSetMap = map;
948   }
949 
950 
951 
952   /**
953    * Returns a reference to the texture coordinate set map.
954    * See the
955    * <a href="../../../../../javax/media/j3d/GeometryArray.html#texCoordSetMap">
956    * GeometryArray constructor </a> for further details.
957    */
getTexCoordSetMap()958   public int[] getTexCoordSetMap() {
959       return texCoordSetMap;
960   }
961 
962 
963 
964   /**
965    * Sets the 2D texture coordinates for the specified set.
966    * No data copying is done - a reference to user data is used.
967    * @param texCoordSet The texture coordinate set for which these
968    * coordinates are being specified.
969    * @param texCoords Array of 2D texture coordinates.
970    * @throws IllegalArgumentException if <code>texCoordSet </code> < 0 or
971    * <code>texCoordSet >= texCoordSetCount</code>,
972    * or the texture coordinate parameters were not previously set by
973    * calling <code>setTextureCoordinateParams(texCoordSetCount, 2)</code>.
974    */
setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[])975   public void setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[])
976   {
977       if (texCoordDim != 2)
978 	  throw new IllegalArgumentException(
979 		  J3dUtilsI18N.getString("GeometryInfo15"));
980       if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
981 	  throw new IllegalArgumentException(
982 		  J3dUtilsI18N.getString("GeometryInfo18"));
983 
984       texCoordSets[texCoordSet] = texCoords;
985   } // End of setTextureCoordinates(int, TexCoord3f[])
986 
987 
988 
989   /**
990    * Sets the TextureCoordinates array by copying the data
991    * into the GeometryInfo object.
992    * This method sets the number of texture coordinate sets to 1,
993    * sets the dimensionality of the texture coordinates to 2,
994    * and sets the coordinates for texture coordinate set 0.
995    * @deprecated As of Java 3D 1.3 replaced by
996    * <code>setTextureCoordinates(int texCoordSet, TexCoord2f coords[])</code>
997    */
setTextureCoordinates(Point2f texCoords[])998   public void setTextureCoordinates(Point2f texCoords[])
999   {
1000       texCoordSetCount = 1;
1001       texCoordDim = 2;
1002       texCoordSets = new TexCoord2f[1][];
1003       if (texCoords != null) {
1004 	TexCoord2f[] tex = new TexCoord2f[texCoords.length];
1005 	for (int i = 0 ; i < texCoords.length ; i++)
1006 	    tex[i] = new TexCoord2f(texCoords[i]);
1007 	texCoordSets[0] = tex;
1008       }
1009   } // End of setTextureCoordinates(Point2f[])
1010 
1011 
1012 
1013   /**
1014    * Sets the texture coordinates array for the specified set.
1015    * No data copying is done - a reference to user data is used.
1016    * @param texCoordSet The texture coordinate set for which these coordinates
1017    * are being specified.
1018    * @param texCoords Array of 3D texture coordinates.
1019    * @throws IllegalArgumentException if <code> texCoordSet </code> < 0 or
1020    * <code>texCoordSet >= texCoordSetCount</code>,
1021    * or the texture coordinate parameters were not previously set by
1022    * calling <code>setTextureCoordinateParams(texCoordSetCount, 3)</code>.
1023    */
setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[])1024   public void setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[])
1025   {
1026       if (texCoordDim != 3)
1027 	  throw new IllegalArgumentException(
1028 		  J3dUtilsI18N.getString("GeometryInfo16"));
1029       if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
1030 	  throw new IllegalArgumentException(
1031 		  J3dUtilsI18N.getString("GeometryInfo18"));
1032 
1033       texCoordSets[texCoordSet] = texCoords;
1034   } // End of setTextureCoordinates(int, TexCoord3f[])
1035 
1036 
1037 
1038   /**
1039    * Sets the TextureCoordinates array by copying the data
1040    * into the GeometryInfo object.
1041    * This method sets the number of texture coordinate sets to 1,
1042    * sets the dimensionality of the texture coordinates to 3,
1043    * and sets the coordinates for texture coordinate set 0.
1044    * @deprecated As of Java 3D 1.3 replaced by
1045    * <code>setTextureCoordinates(int texCoordSet, TexCoord3f coords[])</code>
1046    */
setTextureCoordinates(Point3f texCoords[])1047   public void setTextureCoordinates(Point3f texCoords[])
1048   {
1049       texCoordSetCount = 1;
1050       texCoordDim = 3;
1051       texCoordSets = new TexCoord3f[1][];
1052       if (texCoords != null) {
1053 	TexCoord3f[] tex = new TexCoord3f[texCoords.length];
1054 	for (int i = 0 ; i < texCoords.length ; i++)
1055 	    tex[i] = new TexCoord3f(texCoords[i]);
1056 	texCoordSets[0] = tex;
1057       }
1058   } // End of setTextureCoordinates(Point3f[])
1059 
1060 
1061 
1062   /**
1063    * Sets the texture coordinates array for the specified set.
1064    * No data copying is done - a reference to user data is used.
1065    * @param texCoordSet The texture coordinate set for which these coordinates
1066    * are being specified.
1067    * @param texCoords Array of 4D texture coordinates.
1068    * @throws IllegalArgumentException if <code> texCoordSet </code> < 0 or
1069    * <code>texCoordSet >= texCoordSetCount</code>,
1070    * or the texture coordinate parameters were not previously set by
1071    * calling <code>setTextureCoordinateParams(texCoordSetCount, 4)</code>.
1072    */
setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[])1073   public void setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[]) {
1074       if (texCoordDim != 4)
1075 	  throw new IllegalArgumentException(
1076 		  J3dUtilsI18N.getString("GeometryInfo17"));
1077       if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
1078 	  throw new IllegalArgumentException(
1079 		  J3dUtilsI18N.getString("GeometryInfo18"));
1080 
1081       texCoordSets[texCoordSet] = texCoords;
1082   } // End of setTextureCoordinates(int, TexCoord4f[])
1083 
1084 
1085 
1086   /**
1087    * Sets the texture coordinates array by copying the data into the
1088    * GeometryInfo object.  The number of sets and dimensionality of
1089    * the sets must have been set previously with
1090    * setTextureCoordinateParams(texCoordSetCount, dim).
1091    * @param texCoordSet The texture coordinate set for which these coordinates
1092    * are being specified.
1093    * @param texCoords The float array of texture coordinates. For n texture
1094    * coordinates with dimensionality d, there must be d*n floats in the array.
1095    * @throws IllegalArgumentException if <code>texCoordSet </code> < 0 or
1096    * <code>texCoordSet >= texCoordSetCount</code>,
1097    * or the texture coordinate parameters were not previously set by
1098    * calling <code>setTextureCoordinateParams</code>.
1099    */
setTextureCoordinates(int texCoordSet, float texCoords[])1100   public void setTextureCoordinates(int texCoordSet, float texCoords[])
1101   {
1102       if ((texCoords.length % texCoordDim) != 0)
1103 	  throw new IllegalArgumentException(
1104 		  J3dUtilsI18N.getString("GeometryInfo2"));
1105 
1106       // Copy the texCoords into this GeometryInfo object
1107       if (texCoordDim == 2) {
1108 	TexCoord2f tcoords[] = new TexCoord2f[texCoords.length / 2];
1109 	for (int i = 0 ; i < tcoords.length ; i++)
1110 	    tcoords[i] = new TexCoord2f(texCoords[i * 2],
1111 					texCoords[i * 2 + 1]);
1112 	setTextureCoordinates(texCoordSet, tcoords);
1113       } else if (texCoordDim == 3) {
1114 	TexCoord3f tcoords[] = new TexCoord3f[texCoords.length / 3];
1115 	for (int i = 0 ; i < tcoords.length ; i++)
1116 	    tcoords[i] = new TexCoord3f(texCoords[i * 3],
1117 					texCoords[i * 3 + 1],
1118 					texCoords[i * 3 + 2]);
1119 	setTextureCoordinates(texCoordSet, tcoords);
1120       } else if (texCoordDim == 4) {
1121 	TexCoord4f tcoords[] = new TexCoord4f[texCoords.length / 4];
1122 	for (int i = 0 ; i < tcoords.length ; i++)
1123 	    tcoords[i] = new TexCoord4f(texCoords[i * 4],
1124 					texCoords[i * 4 + 1],
1125 					texCoords[i * 4 + 2],
1126 					texCoords[i * 4 + 3]);
1127 	setTextureCoordinates(texCoordSet, tcoords);
1128       } else {
1129 	  throw new IllegalArgumentException(
1130 		  J3dUtilsI18N.getString("GeometryInfo21"));
1131       }
1132   } // End of setTextureCoordinates(int, float[])
1133 
1134 
1135 
1136   /**
1137    * Sets the texture coordinates array by copying the data
1138    * into the GeometryInfo object, assuming two numbers
1139    * (S and T) per vertex.
1140    * This method sets the number of texture coordinate sets to 1,
1141    * sets the dimensionality of the texture coordinates to 2,
1142    * and sets the coordinates for texture coordinate set 0.
1143    * @deprecated As of Java 3D 1.3 replaced by
1144    * <code>setTextureCoordinates(int texCoordSet, float texCoords[])</code>
1145    */
setTextureCoordinates2(float texCoords[])1146   public void setTextureCoordinates2(float texCoords[])
1147   {
1148       texCoordSetCount = 1;
1149       texCoordDim = 2;
1150       texCoordSets = new TexCoord2f[1][];
1151       setTextureCoordinates(0, texCoords);
1152   } // End of setTextureCoordinates2(float[])
1153 
1154 
1155 
1156   /**
1157    * Sets the TextureCoordinates array by copying the data
1158    * into the GeometryInfo object, assuming three numbers
1159    * (S, T, &amp; R) per vertex.
1160    * This method sets the number of texture coordinate sets to 1,
1161    * sets the dimensionality of the texture coordinates to 3,
1162    * and sets the coordinates for texture coordinate set 0.
1163    * @deprecated As of Java 3D 1.3 replaced by
1164    * <code>setTextureCoordinates(int texCoordSet, float texCoords[])</code>
1165    */
setTextureCoordinates3(float texCoords[])1166   public void setTextureCoordinates3(float texCoords[])
1167   {
1168       texCoordSetCount = 1;
1169       texCoordDim = 3;
1170       texCoordSets = new TexCoord3f[1][];
1171       setTextureCoordinates(0, texCoords);
1172   } // End of setTextureCoordinates3(float[])
1173 
1174 
1175 
1176   /**
1177    * Returns a reference to the indicated texture coordinate array.
1178    * The return type will be <code>TexCoord2f[]</code>, <code>TexCoord3f[]
1179    * </code>, or <code>TexCoord4f[]</code> depending on the
1180    * current dimensionality of the texture coordinates in the GeometryInfo
1181    * object.  Use <code>getNumTexCoordComponents()</code> to find out which
1182    * version is returned.
1183    * @param texCoordSet The index of the texture coordinate set to
1184    * retrieve.
1185    * @return An array of texture coordinates at the specified index
1186    * @throws IllegalArgumentException If <code> texCoordSet</code> < 0
1187    * or <code>texCoordSet >= texCoordSetCount</code>
1188    */
getTextureCoordinates(int texCoordSet)1189   public Object[] getTextureCoordinates(int texCoordSet)
1190   {
1191       if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
1192 	  throw new IllegalArgumentException(
1193 	      J3dUtilsI18N.getString("GeometryInfo18"));
1194       return texCoordSets[texCoordSet];
1195   } // End of getTextureCoordinates(int)
1196 
1197 
1198 
1199   /**
1200    * Retrieves a reference to texture coordinate set 0.
1201    * The return type will be <code>TexCoord2f[]</code>, <code>TexCoord3f[]
1202    * </code>, or <code>TexCoord4f[]</code> depending on the
1203    * current dimensionality of the texture coordinates in the GeometryInfo
1204    * object.  Use <code>getNumTexCoordComponents()</code> to find out which
1205    * version is returned.  Equivalent to <code>getTextureCoordinates(0)</code>.
1206    * @return An array of texture coordinates for set 0.
1207    * @deprecated As of Java 3D 1.3 replaced by
1208    * <code>getTextureCoordinates(int texCoordSet)</code>
1209    */
getTextureCoordinates()1210   public Object[] getTextureCoordinates()
1211   {
1212       return texCoordSets[0];
1213   } // End of getTextureCoordinates()
1214 
1215 
1216 
1217   /**
1218    * Sets the array of indices into the Coordinate array.
1219    * No data copying is done - a reference to user data is used.
1220    */
setCoordinateIndices(int coordinateIndices[])1221   public void setCoordinateIndices(int coordinateIndices[])
1222   {
1223       this.coordinateIndices = coordinateIndices;
1224   } // End of setCoordinateIndices
1225 
1226 
1227 
1228   /**
1229    * Retrieves a reference to the array of indices into the
1230    * coordinate array.</p>
1231    *
1232    * This method should be considered for advanced users only.
1233    * Novice users should just use getGeometryArray() to retrieve
1234    * their data so that the internal format of GeometryInfo is
1235    * of no concern.</p>
1236    *
1237    * Depending on which of the utility routines you've called
1238    * on your GeometryInfo object, the results may not be what you
1239    * expect.  If you've called the Stripifier, your GeometryInfo
1240    * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
1241    * and your data will be formatted accordingly.  Similarly, if
1242    * you've called the Triangulator, your data is in indexed
1243    * TRIANGLE_ARRAY format.  Generating normals with the NormalGenerator
1244    * utility will convert your data to indexed TRIANGLE_ARRAY also,
1245    * but if you call getGeometryArray without calling the Stripifier or
1246    * Triangulator, your data will be converted back to the original
1247    * primitive type when creating the GeometryArray object to pass
1248    * back.  However, if your creaseAngle was not Math.PI (no creases -
1249    * smooth shading), then the introduction of
1250    * creases into your model may have split primitives, lengthening
1251    * the StripCounts and index arrays from your original data.
1252    */
getCoordinateIndices()1253   public int[] getCoordinateIndices()
1254   {
1255       return coordinateIndices;
1256   } // End of getCoordinateIndices
1257 
1258 
1259 
1260   /**
1261    * Sets the array of indices into the Color array.
1262    * No data copying is done - a reference to user data is used.
1263    */
setColorIndices(int colorIndices[])1264   public void setColorIndices(int colorIndices[])
1265   {
1266       this.colorIndices = colorIndices;
1267   } // End of setColorIndices
1268 
1269 
1270 
1271   /**
1272    * Retrieves a reference to the array of indices into the
1273    * color array.</p>
1274    *
1275    * This method should be considered for advanced users only.
1276    * Novice users should just use getGeometryArray() to retrieve
1277    * their data so that the internal format of GeometryInfo is
1278    * of no concern.</p>
1279    *
1280    * Depending on which of the utility routines you've called
1281    * on your GeometryInfo object, the results may not be what you
1282    * expect.  If you've called the Stripifier, your GeometryInfo
1283    * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
1284    * and your data will be formatted accordingly.  Similarly, if
1285    * you've called the Triangulator, your data is in indexed
1286    * TRIANGLE_ARRAY format.  Generating normals with the NormalGenerator
1287    * utility will convert your data to indexed TRIANGLE_ARRAY also,
1288    * but if you call getGeometryArray without calling the Stripifier or
1289    * Triangulator, your data will be converted back to the original
1290    * primitive type when creating the GeometryArray object to pass
1291    * back.  However, if your creaseAngle was not Math.PI (no creases -
1292    * smooth shading), then the introduction of
1293    * creases into your model may have split primitives, lengthening
1294    * the StripCounts and index arrays from your original data.
1295    */
getColorIndices()1296   public int[] getColorIndices()
1297   {
1298       return colorIndices;
1299   } // End of getColorIndices
1300 
1301 
1302 
1303   /**
1304    * Sets the array of indices into the Normal array.
1305    * No data copying is done - a reference to user data is used.
1306    */
setNormalIndices(int normalIndices[])1307   public void setNormalIndices(int normalIndices[])
1308   {
1309       this.normalIndices = normalIndices;
1310 
1311   } // End of setNormalIndices
1312 
1313 
1314 
1315   /**
1316    * Retrieves a reference to the array of indices into the
1317    * Normal array.</p>
1318    *
1319    * This method should be considered for advanced users only.
1320    * Novice users should just use getGeometryArray() to retrieve
1321    * their data so that the internal format of GeometryInfo is
1322    * of no concern.</p>
1323    *
1324    * Depending on which of the utility routines you've called
1325    * on your GeometryInfo object, the results may not be what you
1326    * expect.  If you've called the Stripifier, your GeometryInfo
1327    * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
1328    * and your data will be formatted accordingly.  Similarly, if
1329    * you've called the Triangulator, your data is in indexed
1330    * TRIANGLE_ARRAY format.  Generating normals with the NormalGenerator
1331    * utility will convert your data to indexed TRIANGLE_ARRAY also,
1332    * but if you call getGeometryArray without calling the Stripifier or
1333    * Triangulator, your data will be converted back to the original
1334    * primitive type when creating the GeometryArray object to pass
1335    * back.  However, if your creaseAngle was not Math.PI (no creases -
1336    * smooth shading), then the introduction of
1337    * creases into your model may have split primitives, lengthening
1338    * the StripCounts and index arrays from your original data.
1339    */
getNormalIndices()1340   public int[] getNormalIndices()
1341   {
1342       return normalIndices;
1343   } // End of getNormalIndices
1344 
1345 
1346 
1347   /**
1348    * Sets one of the texture coordinate index arrays.
1349    * No data copying is done - a reference to user data is used.
1350    * @param texCoordSet The texture coordinate set for which these coordinate
1351    * indices are being specified.
1352    * @param texIndices The integer array of indices into the specified texture
1353    * coordinate set
1354    * @throws IllegalArgumentException If <code> texCoordSet</code> < 0 or
1355    * <code>texCoordSet >= texCoordSetCount</code>.
1356    */
setTextureCoordinateIndices(int texCoordSet, int texIndices[])1357   public void setTextureCoordinateIndices(int texCoordSet, int texIndices[])
1358   {
1359       if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
1360 	  throw new IllegalArgumentException(
1361 		  J3dUtilsI18N.getString("GeometryInfo18"));
1362 
1363       // Texture coordinates are indexed
1364       texCoordIndexSets[texCoordSet] = texIndices;
1365   } // End of setTextureCoordinateIndices(int, int[])
1366 
1367 
1368 
1369   /**
1370    * Sets the array of indices into texture coordinate set 0.  Do not
1371    * call this method if you are using more than one set of texture
1372    * coordinates.
1373    * No data is copied - a reference to the user data is used.
1374    * @deprecated As of Java 3D 1.3 replaced by
1375    * <code>setTextureCoordinateIndices(int texCoordSet, int indices[])</code>
1376    * @throws IllegalArgumentException If <code>texCoordSetCount > 1</code>.
1377    */
setTextureCoordinateIndices(int texIndices[])1378   public void setTextureCoordinateIndices(int texIndices[])
1379   {
1380       if (texCoordSetCount > 1)
1381 	  throw new IllegalArgumentException(
1382 		  J3dUtilsI18N.getString("GeometryInfo1"));
1383       texCoordIndexSets = new int[1][];
1384       texCoordIndexSets[0] = texIndices;
1385   } // End of setTextureCoordinateIndices(int[])
1386 
1387 
1388 
1389   /**
1390    * Retrieves a reference to the specified array of texture
1391    * coordinate indices.<p>
1392    *
1393    * This method should be considered for advanced users only.
1394    * Novice users should just use getGeometryArray() to retrieve
1395    * their data so that the internal format of GeometryInfo is
1396    * of no concern.</p>
1397    *
1398    * Depending on which of the utility routines you've called
1399    * on your GeometryInfo object, the results may not be what you
1400    * expect.  If you've called the Stripifier, your GeometryInfo
1401    * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
1402    * and your data will be formatted accordingly.  Similarly, if
1403    * you've called the Triangulator, your data is in indexed
1404    * TRIANGLE_ARRAY format.  Generating normals with the NormalGenerator
1405    * utility will convert your data to indexed TRIANGLE_ARRAY also,
1406    * but if you call getGeometryArray without calling the Stripifier or
1407    * Triangulator, your data will be converted back to the original
1408    * primitive type when creating the GeometryArray object to pass
1409    * back.  However, if your creaseAngle was not Math.PI (no creases -
1410    * smooth shading), then the introduction of
1411    * creases into your model may have split primitives, lengthening
1412    * the StripCounts and index arrays from your original data.
1413    * @param texCoordSet The texture coordinate index set to be
1414    * retrieved.
1415    * @return Integer array of the texture coordinate indices for the specified
1416    * set.
1417    */
getTextureCoordinateIndices(int texCoordSet)1418   public int[] getTextureCoordinateIndices(int texCoordSet) {
1419       return texCoordIndexSets[texCoordSet];
1420   }
1421 
1422 
1423   /**
1424    * Returns a reference to texture coordinate index set 0.
1425    * Equivalent to
1426    * <code>getTextureCoordinateIndices(0)</code>.
1427    * @deprecated As of Java 3D 1.3 replaced by
1428    * <code>int[] getTextureCoordinateIndices(int texCoordSet) </code>
1429    * @return Integer array of the texture coordinate indices for set 0
1430    */
getTextureCoordinateIndices()1431   public int[] getTextureCoordinateIndices()
1432   {
1433       if (texCoordIndexSets == null) return null;
1434       return texCoordIndexSets[0];
1435   } // End of getTextureCoordinateIndices()
1436 
1437 
1438 
1439   /**
1440    * Sets the array of strip counts.  If index lists have been set for
1441    * this GeomteryInfo object then the data is indexed and the stripCounts
1442    * are like stripIndexCounts.  If no index lists have been set then
1443    * the data is non-indexed and the stripCounts are like
1444    * stripVertexCounts.
1445    * @see GeometryStripArray#GeometryStripArray(int, int,
1446    * int[] stripVertexCounts)
1447    * @see IndexedGeometryStripArray#IndexedGeometryStripArray(int, int, int,
1448    * int[] stripIndexCounts)
1449    */
setStripCounts(int stripCounts[])1450   public void setStripCounts(int stripCounts[])
1451   {
1452       this.stripCounts = stripCounts;
1453   } // End of setStripCounts
1454 
1455 
1456 
1457   /**
1458    * Retrieves a reference to the array of stripCounts.</p>
1459    *
1460    * This method should be considered for advanced users only.
1461    * Novice users should just use getGeometryArray() to retrieve
1462    * their data so that the internal format of GeometryInfo is
1463    * of no concern.</p>
1464    *
1465    * Depending on which of the utility routines you've called
1466    * on your GeometryInfo object, the results may not be what you
1467    * expect.  If you've called the Stripifier, your GeometryInfo
1468    * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
1469    * and your data will be formatted accordingly.  Similarly, if
1470    * you've called the Triangulator, your data is in indexed
1471    * TRIANGLE_ARRAY format.  Generating normals with the NormalGenerator
1472    * utility will convert your data to indexed TRIANGLE_ARRAY also,
1473    * but if you call getGeometryArray without calling the Stripifier or
1474    * Triangulator, your data will be converted back to the original
1475    * primitive type when creating the GeometryArray object to pass
1476    * back.  However, if your creaseAngle was not Math.PI (no creases -
1477    * smooth shading), then the introduction of
1478    * creases into your model may have split primitives, lengthening
1479    * the StripCounts and index arrays from your original data.
1480    */
getStripCounts()1481   public int[] getStripCounts()
1482   {
1483       return stripCounts;
1484   } // End of getStripCounts
1485 
1486 
1487 
1488   /**
1489    * Sets the list of contour counts.  Only used with the POLYGON_ARRAY
1490    * primitive.  Polygons can be made of several vertex lists
1491    * called contours.  The first list is the polygon, and
1492    * subsequent lists are "holes" that are removed from the
1493    * polygon.  All of the holes must be contained entirely
1494    * within the polygon.
1495    */
setContourCounts(int contourCounts[])1496   public void setContourCounts(int contourCounts[])
1497   {
1498       this.contourCounts = contourCounts;
1499   } // End of setContourCounts
1500 
1501 
1502 
1503   /**
1504    * Retrieves a reference to the array of contourCounts.
1505    */
getContourCounts()1506   public int[] getContourCounts()
1507   {
1508       return contourCounts;
1509   } // End of getContourCounts
1510 
1511 
1512 
1513   /*
1514    * This routine will return an index list for any array of objects.
1515    */
getListIndices(Object list[])1516   int[] getListIndices(Object list[])
1517   {
1518       // Create list of indices to return
1519       int indices[] = new int[list.length];
1520 
1521       // Create hash table with initial capacity equal to the number
1522       // of components (assuming about half will be duplicates)
1523       HashMap table = new HashMap(list.length);
1524 
1525       Integer idx;
1526       for (int i = 0 ; i < list.length ; i++) {
1527 
1528 	  // Find index associated with this object
1529 	  idx = (Integer)table.get(list[i]);
1530 
1531 	  if (idx == null) {
1532 	      // We haven't seen this object before
1533 	      indices[i] = i;
1534 
1535 	      // Put into hash table and remember the index
1536 	      table.put(list[i], new Integer(i));
1537 
1538 	  } else {
1539 	      // We've seen this object
1540 	      indices[i] = idx.intValue();
1541 	  }
1542       }
1543 
1544       return indices;
1545   } // End of getListIndices
1546 
1547 
1548 
1549   // Class to hash 'size' integers
1550   private class IndexRow {
1551     int[] val;
1552     int size;
1553     private static final int HASHCONST = 0xBABEFACE;
1554 
hashCode()1555     public int hashCode()
1556     {
1557       int bits = 0;
1558       for (int i = 0 ; i < size ; i++) {
1559 	bits ^= (bits * HASHCONST) << 2;
1560       }
1561       return bits;
1562     } // End of IndexRow.hashCode
1563 
equals(Object obj)1564     public boolean equals(Object obj)
1565     {
1566       for (int i = 0 ; i < size ; i++) {
1567 	if (((IndexRow)obj).get(i) != val[i]) return false;
1568       }
1569       return true;
1570     } // End of IndexRow.equals()
1571 
get(int index)1572     public int get(int index)
1573     {
1574       return val[index];
1575     } // End of IndexRow.get
1576 
set(int index, int value)1577     public void set(int index, int value)
1578     {
1579       val[index] = value;
1580     } // End of IndexRow.set
1581 
IndexRow(int numColumns)1582     IndexRow(int numColumns)
1583     {
1584       size = numColumns;
1585       val = new int[size];
1586     } // End of IndexRow constructor
1587   } // End of class IndexRow
1588 
1589 
1590 
1591   /**
1592    * Create index lists for all data lists.
1593    * Identical data entries are guaranteed to
1594    * use the same index value.  Does not remove unused data values
1595    * from the object - call compact() to do this.
1596    * @param useCoordIndexOnly Reformat the data into the
1597    * GeometryArray.USE_COORD_INDEX_ONLY format where there is only
1598    * one index list.  If the data is already in the USE_COORD_INDEX_ONLY
1599    * format, sending false (or calling indexify()) will change
1600    * it to the normal indexed format.
1601    * @throws IllegalArgumentException if coordinate data is missing,
1602    * if the index lists aren't all the
1603    * same length, if an index list is set and the corresponding data
1604    * list isn't set, if a data list is set and the corresponding
1605    * index list is unset (unless all index lists are unset or in
1606    * USE_COORD_INDEX_ONLY format),
1607    * if StripCounts or ContourCounts is inconsistent with the current
1608    * primitive, if the sum of the contourCounts array doesn't equal
1609    * the length of the StripCounts array, or if the number of vertices
1610    * isn't a multiple of three (for triangles) or four (for quads).
1611    */
indexify(boolean useCoordIndexOnly)1612   public void indexify(boolean useCoordIndexOnly)
1613   {
1614       checkForBadData();
1615 
1616       if (useCoordIndexOnly) {
1617 	// Return if already in this format
1618 	if (coordOnly) return;
1619 
1620 	// Start from normal indexed format
1621 	indexify(false);
1622 
1623 	// Reformat data to USE_COORD_INDEX_ONLY format
1624 	// Need to make an index into the index lists using each
1625 	// row of indexes as one value
1626 
1627 	// First, find out how many index lists there are;
1628 	int numLists = 1;		// Always have coordinates
1629 	if (colorIndices != null) numLists++;
1630         if (normalIndices != null) numLists++;
1631 	numLists += texCoordSetCount;
1632 
1633 	// Make single array containing all indices
1634 	int n = coordinateIndices.length;
1635 	IndexRow[] ir = new IndexRow[n];
1636 	int j;
1637 	for (int i = 0 ; i < n ; i++) {
1638 	  ir[i] = new IndexRow(numLists);
1639 	  j = 0;
1640 	  ir[i].set(j++, coordinateIndices[i]);
1641 	  if (colorIndices != null) ir[i].set(j++, colorIndices[i]);
1642 	  if (normalIndices != null) ir[i].set(j++, normalIndices[i]);
1643 	  for (int k = 0 ; k < texCoordSetCount ; k++) {
1644 	    ir[i].set(j++, texCoordIndexSets[k][i]);
1645 	  }
1646 	}
1647 
1648 	// Get index into that array
1649 	int[] coordOnlyIndices = getListIndices(ir);
1650 
1651 	// Get rid of duplicate rows
1652 	int newInd[] = new int[coordOnlyIndices.length];
1653 	ir = (IndexRow[])compactData(coordOnlyIndices, ir, newInd);
1654 	coordOnlyIndices = newInd;
1655 
1656 	// Reformat data lists to correspond to new index
1657 
1658 	// Allocate arrays to hold reformatted data
1659 	Point3f[] newCoords = new Point3f[ir.length];
1660 	Color3f[] newColors3 = null;
1661 	Color4f[] newColors4 = null;
1662 	Vector3f[] newNormals = null;
1663 	Object newTexCoordSets[][] = null;
1664 	if (colors3 != null) newColors3 = new Color3f[ir.length];
1665 	else if (colors4 != null) newColors4 = new Color4f[ir.length];
1666 	if (normals != null) newNormals = new Vector3f[ir.length];
1667 	for (int i = 0 ; i < texCoordSetCount ; i++) {
1668 	  if (texCoordDim == 2) {
1669 	    if (i == 0) newTexCoordSets = new TexCoord2f[texCoordSetCount][];
1670 	    newTexCoordSets[i] = new TexCoord2f[ir.length];
1671 	  } else if (texCoordDim == 3) {
1672 	    if (i == 0) newTexCoordSets = new TexCoord3f[texCoordSetCount][];
1673 	    newTexCoordSets[i] = new TexCoord3f[ir.length];
1674 	  } else if (texCoordDim == 4) {
1675 	    if (i == 0) newTexCoordSets = new TexCoord4f[texCoordSetCount][];
1676 	    newTexCoordSets[i] = new TexCoord4f[ir.length];
1677 	  }
1678 	}
1679 
1680 	// Copy data into new arrays
1681 	n = ir.length;
1682 	for (int i = 0 ; i < n ; i++) {
1683 	  j = 0;
1684 	  newCoords[i] = coordinates[(ir[i]).get(j++)];
1685 	  if (colors3 != null) {
1686 	    newColors3[i] = colors3[(ir[i]).get(j++)];
1687 	  } else if (colors4 != null) {
1688 	    newColors4[i] = colors4[(ir[i]).get(j++)];
1689 	  }
1690 	  if (normals != null) newNormals[i] = normals[(ir[i]).get(j++)];
1691 	  for (int k = 0 ; k < texCoordSetCount ; k++) {
1692 	    newTexCoordSets[k][i] = texCoordSets[k][(ir[i]).get(j++)];
1693 	  }
1694 	}
1695 
1696 	// Replace old arrays with new arrays
1697         coordinates = newCoords;
1698 	colors3 = newColors3;
1699 	colors4 = newColors4;
1700 	normals = newNormals;
1701 	texCoordSets = newTexCoordSets;
1702 	coordinateIndices = coordOnlyIndices;
1703 	colorIndices = null;
1704 	normalIndices = null;
1705 	texCoordIndexSets = new int[texCoordSetCount][];
1706 
1707 	coordOnly = true;
1708       } else if (coordOnly) {
1709 	// Need to change from useCoordIndexOnly format to normal
1710 	// indexed format.  Should make a more efficient implementation
1711 	// later.
1712 
1713 	int n = coordinateIndices.length;
1714 	if ((colors3 != null) || (colors4 != null)) {
1715 	  colorIndices = new int[n];
1716 	  for (int i = 0 ; i < n ; i++) colorIndices[i] = coordinateIndices[i];
1717 	}
1718 	if (normals != null) {
1719 	  normalIndices = new int[n];
1720 	  for (int i = 0 ; i < n ; i++) normalIndices[i] = coordinateIndices[i];
1721 	}
1722 	texCoordIndexSets = new int[texCoordSetCount][];
1723 	for (int i = 0 ; i < texCoordSetCount ; i++) {
1724 	  texCoordIndexSets[i] = new int[n];
1725 	  for (int j = 0 ; j < n ; j++) {
1726 	    texCoordIndexSets[i][j] = coordinateIndices[j];
1727 	  }
1728 	}
1729 	coordOnly = false;
1730       } else {
1731 
1732 	// No need to indexify if already indexed
1733 	if (coordinateIndices != null) return;
1734 
1735 	coordinateIndices = getListIndices(coordinates);
1736 
1737 	if (colors3 != null) colorIndices = getListIndices(colors3);
1738 	else if (colors4 != null) colorIndices = getListIndices(colors4);
1739 
1740 	if (normals != null) normalIndices = getListIndices(normals);
1741 
1742 	texCoordIndexSets = new int[texCoordSetCount][];
1743 	for(int i = 0 ; i < texCoordSetCount ; i++) {
1744 	    texCoordIndexSets[i] = getListIndices(texCoordSets[i]);
1745 	}
1746 
1747 	coordOnly = false;
1748       }
1749 
1750       if ((DEBUG & 1) == 1) {
1751 	  System.out.println("Coordinate Array:");
1752 	  for (int i = 0 ; i < coordinates.length ; i++) {
1753 	      System.out.println("  " + i + " " + coordinates[i] +
1754 		      " " + coordinates[i].hashCode());
1755 	  }
1756 	  System.out.println("Index array:");
1757 	  for (int i = 0 ; i < coordinateIndices.length ; i++) {
1758 	      System.out.println("  " + i + " " + coordinateIndices[i]);
1759 	  }
1760       }
1761 
1762   } // End of indexify
1763 
1764 
1765 
indexify()1766   public void indexify()
1767   {
1768     indexify(false);
1769   } // End of indexify()
1770 
1771 
1772 
1773   /**
1774    * Allocates an array of the same type as the input type. This allows us to
1775    * use a generic compactData method.
1776    *
1777    * @param data Array of coordinate, color, normal or texture coordinate data
1778    * The data can be in one of the following formats - Point3f, Color3f,
1779    * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
1780    *
1781    * @param num The size of the array to be allocated
1782    *
1783    * @return An array of size num of the same type as the input type
1784    *
1785    * @exception IllegalArgumentException if the input array is not one of the
1786    * types listed above.
1787    */
allocateArray(Object data[], int num)1788   Object[] allocateArray(Object data[], int num) {
1789       Object newData[] = null;
1790       if (data instanceof javax.vecmath.Point3f[]) {
1791 	  newData = new Point3f[num];
1792       } else if (data instanceof javax.vecmath.Vector3f[]) {
1793 	  newData = new Vector3f[num];
1794       } else if (data instanceof javax.vecmath.Color3f[]) {
1795 	  newData = new Color3f[num];
1796       } else if (data instanceof javax.vecmath.Color4f[]) {
1797 	  newData = new Color4f[num];
1798       } else if (data instanceof javax.vecmath.TexCoord2f[]) {
1799 	  newData = new TexCoord2f[num];
1800       } else if (data instanceof javax.vecmath.TexCoord3f[]) {
1801 	  newData = new TexCoord3f[num];
1802       } else if (data instanceof javax.vecmath.TexCoord4f[]) {
1803 	  newData = new TexCoord4f[num];
1804       } else if (data instanceof IndexRow[]) {
1805 	  // Hack so we can use compactData for coordIndexOnly
1806 	  newData = new IndexRow[num];
1807       } else throw new IllegalArgumentException(
1808 	  J3dUtilsI18N.getString("GeometryInfo9"));
1809       return newData;
1810   } // End of allocateArray
1811 
1812 
1813 
1814   /**
1815    * Generic method that compacts (ie removes unreferenced/duplicate data)
1816    * any type of indexed data.
1817    * Used to compact coordinate, color, normal and texture coordinate data.
1818    * @param indices Array of indices
1819    * @param data Array of coordinate, color, normal or texture coordinate data
1820    * The data can be in one of the following formats - Point3f, Color3f,
1821    * Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
1822    * @param newInd The new array of indexes after the data has been compacted.
1823    * This must be allocated by the calling method. On return, this array will
1824    * contain the new index data. The size of this array must be equal to
1825    * indices.length
1826    * @return Array of the data with unreferenced and duplicate entries removed.
1827    * The return type will be the same as the type that was passed in data.
1828    */
1829    // TODO:  Remove duplicate entries in data lists.
compactData(int indices[], Object data[], int newInd[])1830   private Object[] compactData(int indices[], Object data[], int newInd[]) {
1831       Object newData[] = null;
1832       /*
1833        * This is a three step process.
1834        * First, find out how many unique indexes are used.  This
1835        * will be the size of the new data array.
1836        */
1837       int numUnique = 0;
1838       int translationTable[] = new int[data.length];
1839       for (int i = 0 ; i < indices.length ; i++) {
1840 	  if (translationTable[indices[i]] == 0) {
1841 
1842 	      numUnique++;
1843 	      translationTable[indices[i]] = 1;
1844 	  }
1845       }
1846       /*
1847        * Second, build the new data list.  Remember the new indexes so
1848        * we can use the table to translate the old indexes to the new
1849        */
1850       newData = allocateArray(data, numUnique);
1851       int newIdx = 0;
1852       for (int i = 0 ; i < translationTable.length ; i++) {
1853 	  if (translationTable[i] != 0) {
1854 	      newData[newIdx] = data[i];
1855 	      translationTable[i] = newIdx++;
1856 	  }
1857       }
1858       /*
1859        * Third, make the new index list
1860        */
1861       for (int i = 0 ; i < indices.length ; i++) {
1862 	  newInd[i] = translationTable[indices[i]];
1863       }
1864       return newData;
1865   } // End of compactData
1866 
1867 
1868 
1869   /**
1870    * Remove unused data from an indexed dataset.
1871    * Indexed data may contain data entries that are never referenced by
1872    * the dataset.  This routine will remove those entries where
1873    * appropriate and renumber the indices to match the new values.
1874    * @throws IllegalArgumentException if coordinate data is missing,
1875    * if the index lists aren't all the
1876    * same length, if an index list is set and the corresponding data
1877    * list isn't set, if a data list is set and the corresponding
1878    * index list is unset (unless all index lists are unset or in
1879    * USE_COORD_INDEX_ONLY format),
1880    * if StripCounts or ContourCounts is inconsistent with the current
1881    * primitive, if the sum of the contourCounts array doesn't equal
1882    * the length of the StripCounts array, or if the number of vertices
1883    * isn't a multiple of three (for triangles) or four (for quads).
1884    */
compact()1885   public void compact()
1886   {
1887       checkForBadData();
1888 
1889       // Only usable on indexed data
1890       if (coordinateIndices == null) return;
1891 
1892       // USE_COORD_INDEX_ONLY never has unused data
1893       if (coordOnly) return;
1894 
1895       int newInd[] = new int[coordinateIndices.length];
1896       coordinates =
1897 	  (Point3f[])compactData(coordinateIndices, coordinates, newInd);
1898       coordinateIndices = newInd;
1899 
1900       if (colorIndices != null) {
1901 	  newInd = new int[colorIndices.length];
1902 	  if (colors3 != null)
1903 	      colors3 = (Color3f[])compactData(colorIndices, colors3, newInd);
1904 	  else if (colors4 != null)
1905 	      colors4 = (Color4f[])compactData(colorIndices, colors4, newInd);
1906 	  colorIndices = newInd;
1907       }
1908 
1909       if (normalIndices != null) {
1910 	  newInd = new int[normalIndices.length];
1911 	  normals = (Vector3f[])compactData(normalIndices, normals, newInd);
1912 	  normalIndices = newInd;
1913       }
1914 
1915       for (int i = 0 ; i < texCoordSetCount ; i++) {
1916 	  newInd = new int[texCoordIndexSets[i].length];
1917 	  texCoordSets[i] = compactData(texCoordIndexSets[i],
1918 					  texCoordSets[i], newInd);
1919 	  texCoordIndexSets[i] = newInd;
1920       }
1921   } // End of compact
1922 
1923 
1924 
1925   /**
1926    * Check the data to make sure everything's consistent.
1927    */
checkForBadData()1928   private void checkForBadData() {
1929       boolean badData = false;
1930 
1931       //
1932       // Coordinates are required
1933       //
1934       if (coordinates == null) {
1935 	  throw new IllegalArgumentException(
1936 		  J3dUtilsI18N.getString("GeometryInfo3"));
1937       }
1938 
1939       //
1940       // Check for indices with no data
1941       //
1942       if ((colors3 == null) && (colors4 == null) && (colorIndices != null))
1943 	  throw new IllegalArgumentException(
1944 		  J3dUtilsI18N.getString("GeometryInfo4"));
1945       if ((normals == null) && (normalIndices != null))
1946 	  throw new IllegalArgumentException(
1947 		  J3dUtilsI18N.getString("GeometryInfo11"));
1948 
1949       //
1950       // Make sure all TextureCoordinate data is set (indices or not)
1951       //
1952       for (int i = 0 ; i < texCoordSetCount ; i++) {
1953 	if (texCoordSets[i] == null)
1954 	  throw new IllegalArgumentException(
1955 		  J3dUtilsI18N.getString("GeometryInfo10"));
1956       }
1957 
1958       //
1959       // Check for Missing Index lists
1960       //
1961       boolean texInds = false;	// Indicates whether we have texcoord indices
1962       if (texCoordIndexSets != null) {
1963 	for (int i = 0 ; i < texCoordSetCount ; i++) {
1964 	  if (texCoordIndexSets[i] != null) texInds = true;
1965 	}
1966       }
1967       if ((coordinateIndices != null) ||
1968 	  (colorIndices != null) ||
1969 	  (normalIndices != null) ||
1970 	  texInds) {
1971 	// At least one index list is present, so they all must be
1972 	// present (unless coordOnly)
1973 	if (coordinateIndices == null) badData = true;
1974 	else if (coordOnly) {
1975 	  if ((colorIndices != null) ||
1976 	      (normalIndices != null) ||
1977 	      (texInds == true)) {
1978 	    throw new IllegalArgumentException(
1979 	      J3dUtilsI18N.getString("GeometryInfo20"));
1980 	  }
1981 	} else if (((colors3 != null) || (colors4 != null)) &&
1982 	         (colorIndices == null)) badData = true;
1983 	else if ((normals != null) && (normalIndices == null)) badData = true;
1984 	else if ((texCoordSetCount > 0) && !texInds) badData = true;
1985 	if (badData) throw new
1986 	  IllegalArgumentException(J3dUtilsI18N.getString("GeometryInfo19"));
1987       }
1988 
1989       //
1990       // Make sure index lists are all the same length
1991       //
1992       if ((coordinateIndices != null) && (!coordOnly)) {
1993 	  if (((colors3 != null) || (colors4 != null)) &&
1994 	      (colorIndices.length != coordinateIndices.length))
1995 	    badData = true;
1996 	  else if ((normals != null) &&
1997 	           (normalIndices.length != coordinateIndices.length))
1998 	    badData = true;
1999 	  else {
2000 	    //Check all texCoord indices have the same length
2001 	    for (int i = 0 ; i < texCoordSetCount ; i++) {
2002 	      if (texCoordIndexSets[i].length != coordinateIndices.length) {
2003 		badData = true;
2004 		break;
2005 	      }
2006 	    }
2007 	  }
2008 	  if (badData) {
2009 	      throw new IllegalArgumentException(
2010 		      J3dUtilsI18N.getString("GeometryInfo5"));
2011 	  }
2012       }
2013 
2014       //
2015       // For stripped primitives, make sure we have strip counts
2016       //
2017       if ((prim == TRIANGLE_STRIP_ARRAY) ||
2018 	  (prim == TRIANGLE_FAN_ARRAY) ||
2019 	  (prim == POLYGON_ARRAY)) {
2020 	  if (stripCounts == null) badData = true;
2021       } else if (stripCounts != null) badData = true;
2022       if (badData) {
2023 	  throw new IllegalArgumentException(
2024 		  J3dUtilsI18N.getString("GeometryInfo6"));
2025       }
2026 
2027       // Find out how much data we have
2028       int count;
2029       if (coordinateIndices == null) count = coordinates.length;
2030       else count = coordinateIndices.length;
2031 
2032       //
2033       // Make sure sum of strip counts equals indexCount (or vertexCount)
2034       // and check to make sure triangles and quads have the right number
2035       // of vertices
2036       //
2037       if ((prim == TRIANGLE_STRIP_ARRAY) ||
2038 	  (prim == TRIANGLE_FAN_ARRAY) ||
2039 	  (prim == POLYGON_ARRAY)) {
2040 	  int sum = 0;
2041 	  for (int i = 0 ; i < stripCounts.length ; i++) {
2042 	      sum += stripCounts[i];
2043 	  }
2044 	  if (sum != count) {
2045 	      throw new IllegalArgumentException(
2046 		      J3dUtilsI18N.getString("GeometryInfo7"));
2047 	  }
2048       } else if (prim == TRIANGLE_ARRAY) {
2049 	  if (count % 3 != 0) {
2050 	      throw new IllegalArgumentException(
2051 		      J3dUtilsI18N.getString("GeometryInfo12"));
2052 	  }
2053       } else if (prim == QUAD_ARRAY) {
2054 	  if (count % 4 != 0) {
2055 	      throw new IllegalArgumentException(
2056 		      J3dUtilsI18N.getString("GeometryInfo13"));
2057 	  }
2058       }
2059 
2060       //
2061       // For polygons, make sure the contours add up.
2062       //
2063       if (prim == POLYGON_ARRAY) {
2064 	  if (contourCounts != null) {
2065 	      int c = 0;
2066 	      for (int i = 0 ; i < contourCounts.length ; i++)
2067 		  c += contourCounts[i];
2068 	      if (c != stripCounts.length) {
2069 		  throw new IllegalArgumentException(
2070 			  J3dUtilsI18N.getString("GeometryInfo8"));
2071 	      }
2072 	  }
2073       } else {
2074 	  if (contourCounts != null) {
2075 	      throw new IllegalArgumentException(
2076 		      J3dUtilsI18N.getString("GeometryInfo14"));
2077 	  }
2078       }
2079   } // End of checkForBadData
2080 
2081 
2082 
2083   /**
2084    * Get rid of index lists by reorganizing data into an un-indexed
2085    * format.  Does nothing if no index lists are set.
2086    * @throws IllegalArgumentException if coordinate data is missing,
2087    * if the index lists aren't all the
2088    * same length, if an index list is set and the corresponding data
2089    * list isn't set, if a data list is set and the corresponding
2090    * index list is unset (unless all index lists are unset or in
2091    * USE_COORD_INDEX_ONLY format),
2092    * if StripCounts or ContourCounts is inconsistent with the current
2093    * primitive, if the sum of the contourCounts array doesn't equal
2094    * the length of the StripCounts array, or if the number of vertices
2095    * isn't a multiple of three (for triangles) or four (for quads).
2096    */
unindexify()2097   public void unindexify() {
2098       checkForBadData();
2099       if (coordinateIndices != null) {
2100 	  // Switch from USE_COORD_INDEX_ONLY format
2101 	  if (coordOnly) indexify(false);
2102 
2103 	  coordinates =
2104 	    (Point3f[])unindexifyData(coordinates, coordinateIndices);
2105 	  coordinateIndices = null;
2106 
2107 	  if (colors3 != null) {
2108 	      colors3 = (Color3f[])unindexifyData(colors3, colorIndices);
2109 	  } else if (colors4 != null) {
2110 	      colors4 = (Color4f[])unindexifyData(colors4, colorIndices);
2111 	  }
2112 	  colorIndices = null;
2113 
2114           if (normals != null) {
2115 	    normals = (Vector3f[])unindexifyData(normals, normalIndices);
2116 	    normalIndices = null;
2117 	  }
2118 
2119 	  for (int i = 0 ; i < texCoordSetCount ; i++)
2120 	    texCoordSets[i] = unindexifyData(texCoordSets[i],
2121 					     texCoordIndexSets[i]);
2122 	  texCoordIndexSets = new int[texCoordSetCount][];
2123       }
2124   } // End of unindexify
2125 
2126 
2127 
2128   /**
2129    * Generic unindexify method. Can unindex data in any of the following
2130    * formats Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f,
2131    * TexCoord4f.
2132    */
unindexifyData(Object data[], int index[])2133   private Object[] unindexifyData(Object data[], int index[])
2134   {
2135       Object newData[] = allocateArray(data, index.length);
2136       for (int i = 0 ; i < index.length ; i++) {
2137 	  newData[i] = data[index[i]];
2138       }
2139       return newData;
2140   } // End of unindexifyData
2141 
2142 
2143 
2144   /**
2145    * Calculate vertexFormat based on data.
2146    */
getVertexFormat()2147   private int getVertexFormat()
2148   {
2149       int vertexFormat = GeometryArray.COORDINATES;
2150 
2151       if (colors3 != null) vertexFormat |= GeometryArray.COLOR_3;
2152       else if (colors4 != null) vertexFormat |= GeometryArray.COLOR_4;
2153 
2154       if (normals != null) vertexFormat |= GeometryArray.NORMALS;
2155 
2156       if (texCoordDim == 2)
2157 	  vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2;
2158       else if (texCoordDim == 3)
2159 	  vertexFormat |= GeometryArray.TEXTURE_COORDINATE_3;
2160       else if (texCoordDim == 4)
2161 	  vertexFormat |= GeometryArray.TEXTURE_COORDINATE_4;
2162 
2163       return vertexFormat;
2164   } // End of getVertexFormat
2165 
2166 
2167 
2168   /**
2169    * Calculate vertexCount based on data
2170    */
getVertexCount()2171   private int getVertexCount()
2172   {
2173       int vertexCount = coordinates.length;
2174 
2175       if (colors3 != null) {
2176 	  if (colors3.length > vertexCount) vertexCount = colors3.length;
2177       } else if (colors4 != null) {
2178 	  if (colors4.length > vertexCount) vertexCount = colors4.length;
2179       }
2180 
2181       if (normals != null) {
2182 	  if (normals.length > vertexCount) vertexCount = normals.length;
2183       }
2184 
2185       // Find max length tex coord set
2186       for (int i = 0 ; i < texCoordSetCount ; i++) {
2187 	  if (texCoordSets[i].length > vertexCount)
2188 	      vertexCount = texCoordSets[i].length;
2189       }
2190 
2191       return vertexCount;
2192   } // End of getVertexCount
2193 
2194 
2195 
2196   /**
2197    * Converts an array of Tuple2f, Tuple3f, or Tuple4f values into
2198    * an array of floats.  Assumes array is not null.  Returns null
2199    * if array is not Tuple2f, Tuple3f, or Tuple4f.  Used by fillIn()
2200    * for BY_REFERENCE not INTERLEAVED geometry.
2201    */
vecmathToFloat(Object[] ar)2202   private float[] vecmathToFloat(Object[] ar)
2203   {
2204     if (ar[0] instanceof Tuple2f) {
2205       float[] p = new float[ar.length * 2];
2206       Tuple2f[] a = (Tuple2f[])ar;
2207       for (int i = 0 ; i < ar.length ; i++) {
2208 	p[i * 2]     = a[i].x;
2209 	p[i * 2 + 1] = a[i].y;
2210       }
2211       return p;
2212     } else if (ar[0] instanceof Tuple3f) {
2213       float[] p = new float[ar.length * 3];
2214       Tuple3f[] a = (Tuple3f[])ar;
2215       for (int i = 0 ; i < ar.length ; i++) {
2216 	p[i * 3]     = a[i].x;
2217 	p[i * 3 + 1] = a[i].y;
2218 	p[i * 3 + 2] = a[i].z;
2219       }
2220       return p;
2221     } else if (ar[0] instanceof Tuple4f) {
2222       float[] p = new float[ar.length * 4];
2223       Tuple4f[] a = (Tuple4f[])ar;
2224       for (int i = 0 ; i < ar.length ; i++) {
2225 	p[i * 4]     = a[i].x;
2226 	p[i * 4 + 1] = a[i].y;
2227 	p[i * 4 + 2] = a[i].z;
2228 	p[i * 4 + 3] = a[i].w;
2229       }
2230       return p;
2231     }
2232     return null;
2233   } // End of vecmathToFloat
2234 
2235 
2236 
2237   /**
2238    * Fill in the GeometryArray object.  Used by getGeometryArray and
2239    * getIndexedGeometryArray.  checkForBadData has already been called.
2240    */
fillIn(GeometryArray ga, boolean byRef, boolean interleaved, boolean nio)2241   private void fillIn(GeometryArray ga, boolean byRef, boolean interleaved,
2242 		      boolean nio)
2243   {
2244       if (interleaved) {
2245 	// Calculate number of words per vertex
2246 	int wpv = 3;                      // Always have coordinate data
2247 	if (normals != null) wpv += 3;
2248 	if (colors3 != null) wpv += 3;
2249 	else if (colors4 != null) wpv += 4;
2250 	wpv += (texCoordSetCount * texCoordDim);
2251 
2252         // Build array of interleaved data
2253 	float[] d = new float[wpv * coordinates.length];
2254 
2255 	// Fill in the array
2256 	int offset = 0;
2257 	for (int i = 0 ; i < coordinates.length ; i++) {
2258 	  if (texCoordDim == 2) {
2259 	    for (int j = 0 ; j < texCoordSetCount ; j++) {
2260 	      d[offset++] = ((TexCoord2f)texCoordSets[j][i]).x;
2261 	      d[offset++] = ((TexCoord2f)texCoordSets[j][i]).y;
2262 	    }
2263 	  } else if (texCoordDim == 3) {
2264 	    for (int j = 0 ; j < texCoordSetCount ; j++) {
2265 	      d[offset++] = ((TexCoord3f)texCoordSets[j][i]).x;
2266 	      d[offset++] = ((TexCoord3f)texCoordSets[j][i]).y;
2267 	      d[offset++] = ((TexCoord3f)texCoordSets[j][i]).z;
2268 	    }
2269 	  } else if (texCoordDim == 4) {
2270 	    for (int j = 0 ; j < texCoordSetCount ; j++) {
2271 	      d[offset++] = ((TexCoord4f)texCoordSets[j][i]).x;
2272 	      d[offset++] = ((TexCoord4f)texCoordSets[j][i]).y;
2273 	      d[offset++] = ((TexCoord4f)texCoordSets[j][i]).z;
2274 	      d[offset++] = ((TexCoord4f)texCoordSets[j][i]).w;
2275 	    }
2276 	  }
2277 
2278 	  if (colors3 != null) {
2279 	    d[offset++] = colors3[i].x;
2280 	    d[offset++] = colors3[i].y;
2281 	    d[offset++] = colors3[i].z;
2282 	  } else if (colors4 != null) {
2283 	    d[offset++] = colors4[i].x;
2284 	    d[offset++] = colors4[i].y;
2285 	    d[offset++] = colors4[i].z;
2286 	    d[offset++] = colors4[i].w;
2287 	  }
2288 
2289 	  if (normals != null) {
2290 	    d[offset++] = normals[i].x;
2291 	    d[offset++] = normals[i].y;
2292 	    d[offset++] = normals[i].z;
2293 	  }
2294 
2295 	  d[offset++] = coordinates[i].x;
2296 	  d[offset++] = coordinates[i].y;
2297 	  d[offset++] = coordinates[i].z;
2298 	}
2299 	// Register reference to array of interleaved data
2300 	if (nio) {
2301 	  ByteBufferWrapper b = ByteBufferWrapper.allocateDirect(d.length * 4);
2302 	  FloatBufferWrapper f =
2303 	    b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2304 	  f.put(d);
2305 	  ga.setInterleavedVertexBuffer(f.getJ3DBuffer());
2306 	} else ga.setInterleavedVertices(d);
2307       } else if (nio) {
2308 
2309 	ByteBufferWrapper b =
2310 	  ByteBufferWrapper.allocateDirect(coordinates.length * 4 * 3);
2311 	FloatBufferWrapper f =
2312 	  b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2313 	f.put(vecmathToFloat(coordinates));
2314 	ga.setCoordRefBuffer(f.getJ3DBuffer());
2315 
2316 	if (colors3 != null) {
2317 	  b = ByteBufferWrapper.allocateDirect(colors3.length * 4 * 3);
2318 	  f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2319 	  f.put(vecmathToFloat(colors3));
2320 	  ga.setColorRefBuffer(f.getJ3DBuffer());
2321 	} else if (colors4 != null) {
2322 	  b = ByteBufferWrapper.allocateDirect(colors4.length * 4 * 4);
2323 	  f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2324 	  f.put(vecmathToFloat(colors4));
2325 	  ga.setColorRefBuffer(f.getJ3DBuffer());
2326 	}
2327 
2328 	if (normals != null) {
2329 	  b = ByteBufferWrapper.allocateDirect(normals.length * 4 * 3);
2330 	  f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2331 	  f.put(vecmathToFloat(normals));
2332 	  ga.setNormalRefBuffer(f.getJ3DBuffer());
2333 	}
2334 
2335 	for (int i = 0 ; i < texCoordSetCount ; i++) {
2336 	  b = ByteBufferWrapper.allocateDirect(
2337 	    texCoordSets[i].length * 4 * texCoordDim);
2338 	  f = b.order( ByteOrderWrapper.nativeOrder() ).asFloatBuffer();
2339 	  f.put(vecmathToFloat(texCoordSets[i]));
2340 	  ga.setTexCoordRefBuffer(i, f.getJ3DBuffer());
2341 	}
2342       } else if (byRef) {
2343 	// Need to copy the data into float arrays - GeometryArray
2344 	// prefers them over the vecmath types
2345 	ga.setCoordRefFloat(vecmathToFloat(coordinates));
2346 	if (colors3 != null) ga.setColorRefFloat(vecmathToFloat(colors3));
2347 	else if (colors4 != null) ga.setColorRefFloat(vecmathToFloat(colors4));
2348 	if (normals != null) ga.setNormalRefFloat(vecmathToFloat(normals));
2349 	for (int i = 0 ; i < texCoordSetCount ; i++) {
2350 	    ga.setTexCoordRefFloat(i, vecmathToFloat(texCoordSets[i]));
2351 	}
2352       } else {
2353 	ga.setCoordinates(0, coordinates);
2354 	if (colors3 != null) ga.setColors(0, colors3);
2355 	else if (colors4 != null) ga.setColors(0, colors4);
2356 	if (normals != null) ga.setNormals(0, normals);
2357 	for (int i = 0 ; i < texCoordSetCount ; i++) {
2358 	  if (texCoordDim == 2) {
2359 	    ga.setTextureCoordinates(i, 0, (TexCoord2f[])texCoordSets[i]);
2360 	  } else if (texCoordDim == 3) {
2361 	    ga.setTextureCoordinates(i, 0, (TexCoord3f[])texCoordSets[i]);
2362 	  } else if (texCoordDim == 4) {
2363 	    ga.setTextureCoordinates(i, 0, (TexCoord4f[])texCoordSets[i]);
2364 	  }
2365 	}
2366       }
2367 
2368       if (coordinateIndices != null) {
2369 	IndexedGeometryArray iga = null;
2370 	iga = (IndexedGeometryArray)ga;
2371 	iga.setCoordinateIndices(0, coordinateIndices);
2372 	if (!coordOnly) {
2373 	  if (colorIndices != null) iga.setColorIndices(0, colorIndices);
2374 	  if (normalIndices != null) iga.setNormalIndices(0, normalIndices);
2375 	  for (int i = 0 ; i < texCoordSetCount ; i++)
2376 	    iga.setTextureCoordinateIndices(i, 0, texCoordIndexSets[i]);
2377 	}
2378       }
2379   } // End of fillIn
2380 
2381 
2382 
2383   /**
2384    * Redo indexes to guarantee connection information.
2385    * Use this routine if your original data is in indexed format, but
2386    * you don't trust that the indexing is correct.  After this
2387    * routine it is guaranteed that two points with the same
2388    * position will have the same coordinate index (for example).
2389    * Try this if you see
2390    * glitches in your normals or stripification, to rule out
2391    * bad indexing as the source of the problem.  Works with normal
2392    * indexed format or USE_COORD_INDEX_ONLY format.
2393    * @throws IllegalArgumentException if coordinate data is missing,
2394    * if the index lists aren't all the
2395    * same length, if an index list is set and the corresponding data
2396    * list isn't set, if a data list is set and the corresponding
2397    * index list is unset (unless all index lists are unset or in
2398    * USE_COORD_INDEX_ONLY format),
2399    * if StripCounts or ContourCounts is inconsistent with the current
2400    * primitive, if the sum of the contourCounts array doesn't equal
2401    * the length of the StripCounts array, or if the number of vertices
2402    * isn't a multiple of three (for triangles) or four (for quads).
2403    */
recomputeIndices()2404   public void recomputeIndices()
2405   {
2406       boolean remember = coordOnly;
2407 
2408       // Can make more efficient implementation later
2409       unindexify();
2410       indexify(remember);
2411   } // End of recomputeIndices
2412 
2413 
2414 
2415   /**
2416    * Reverse the order of an array of ints (computer class homework
2417    * problem).
2418    */
reverseList(int list[])2419   private void reverseList(int list[])
2420   {
2421       int t;
2422 
2423       if (list == null) return;
2424 
2425       for (int i = 0 ; i < list.length / 2 ; i++) {
2426 	  t = list[i];
2427 	  list[i] = list[list.length - i - 1];
2428 	  list[list.length - i - 1] = t;
2429       }
2430   } // End of reverseList
2431 
2432 
2433 
2434   /**
2435    * Reverse the order of all lists.  If your polygons are formatted with
2436    * clockwise winding, you will always see the back and never the front.
2437    * (Java 3D always wants vertices specified with a counter-clockwise
2438    * winding.)
2439    * This method will (in effect) reverse the winding of your data by
2440    * inverting all of the index lists and the stripCounts
2441    * and contourCounts lists.
2442    * @throws IllegalArgumentException if coordinate data is missing,
2443    * if the index lists aren't all the
2444    * same length, if an index list is set and the corresponding data
2445    * list isn't set, if a data list is set and the corresponding
2446    * index list is unset (unless all index lists are unset or in
2447    * USE_COORD_INDEX_ONLY format),
2448    * if StripCounts or ContourCounts is inconsistent with the current
2449    * primitive, if the sum of the contourCounts array doesn't equal
2450    * the length of the StripCounts array, or if the number of vertices
2451    * isn't a multiple of three (for triangles) or four (for quads).
2452    */
reverse()2453   public void reverse()
2454   {
2455       indexify();
2456       reverseList(stripCounts);
2457       reverseList(oldStripCounts);
2458       reverseList(contourCounts);
2459       reverseList(coordinateIndices);
2460       reverseList(colorIndices);
2461       reverseList(normalIndices);
2462       for (int i = 0 ; i < texCoordSetCount ; i++)
2463 	  reverseList(texCoordIndexSets[i]);
2464   } // End of reverse
2465 
2466 
2467 
2468   /**
2469    * Returns true if the data in this GeometryInfo is currently
2470    * formatted in the USE_COORD_INDEX_ONLY format where a single
2471    * index list is used to index into all data lists.
2472    * @see GeometryInfo#indexify(boolean)
2473    * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
2474    * boolean, boolean)
2475    */
getUseCoordIndexOnly()2476   public boolean getUseCoordIndexOnly()
2477   {
2478     return coordOnly;
2479   } // End of getUseCoordIndexOnly
2480 
2481 
2482 
2483   /**
2484    * Tells the GeometryInfo that its data is formatted in the
2485    * USE_COORD_INDEX_ONLY format with a single index list
2486    * (the coordinate index list) that indexes into all data
2487    * lists (coordinates, normals, colors, and texture
2488    * coordinates).  NOTE: this will not convert the data
2489    * for you.  This method is for when you are sending in
2490    * data useng the setCoordinates, setNormals, setColors,
2491    * and/or setTextureCoordinates methods, and you are only
2492    * setting one index using setCoordinateIndices().  If
2493    * you want GeometryInfo to convert your data to the
2494    * USE_COORD_INDEX_ONLY format, use indexify(true) or
2495    * getIndexedGeometryArray with the useCoordIndexOnly
2496    * parameter set to true.
2497    * @see GeometryInfo#indexify(boolean)
2498    * @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
2499    * boolean, boolean)
2500    */
setUseCoordIndexOnly(boolean useCoordIndexOnly)2501   public void setUseCoordIndexOnly(boolean useCoordIndexOnly)
2502   {
2503     coordOnly = useCoordIndexOnly;
2504   } // End of setUseCoordIndexOnly
2505 
2506 
2507 
2508   /**
2509    * Creates and returns a non-indexed Java 3D GeometryArray object
2510    * based on the data in the GeometryInfo object.  This object is
2511    * suitable to be attached to a Shape3D node for rendering.
2512    * @param byRef Use geometry BY_REFERENCE
2513    * @param interleaved Use INTERLEAVED geometry.  Implies byRef is
2514    * true as well.
2515    * @param nio Create GeometryArray using java.nio.Buffer for
2516    * geometry arrays.  Only usable on JDK 1.4 or higher.  Implies
2517    * byRef is true as well.
2518    * @throws IllegalArgumentException if coordinate data is missing,
2519    * if the index lists aren't all the
2520    * same length, if an index list is set and the corresponding data
2521    * list isn't set, if a data list is set and the corresponding
2522    * index list is unset (unless all index lists are unset or in
2523    * USE_COORD_INDEX_ONLY format),
2524    * if StripCounts or ContourCounts is inconsistent with the current
2525    * primitive, if the sum of the contourCounts array doesn't equal
2526    * the length of the StripCounts array, or if the number of vertices
2527    * isn't a multiple of three (for triangles) or four (for quads).
2528    */
getGeometryArray(boolean byRef, boolean interleaved, boolean nio)2529   public GeometryArray getGeometryArray(boolean byRef, boolean interleaved,
2530 					boolean nio)
2531   {
2532       checkForBadData();
2533 
2534       if (prim == POLYGON_ARRAY) {
2535 	  if (tr == null) tr = new Triangulator();
2536 	  tr.triangulate(this);
2537       } else changeBackToOldPrim();
2538 
2539       unindexify();
2540 
2541       int vertexFormat = getVertexFormat();
2542       if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE |
2543 				GeometryArray.USE_NIO_BUFFER);
2544       if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE |
2545 					GeometryArray.INTERLEAVED);
2546       if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE;
2547 
2548       int vertexCount = coordinates.length;
2549 
2550       // If the texCoordSetMap hasn't been set, assume one set of
2551       // texture coordinates only and one texture state unit
2552       if ((texCoordSetCount > 0) && (texCoordSetMap == null)) {
2553 	  texCoordSetCount = 1;
2554 	  texCoordSetMap = new int[1];
2555 	  texCoordSetMap[0] = 0;
2556       }
2557 
2558       // Create the GeometryArray object
2559       GeometryArray ga = null;
2560       switch (prim) {
2561 	  case TRIANGLE_ARRAY:
2562 	      TriangleArray ta = new TriangleArray(vertexCount, vertexFormat,
2563 		      texCoordSetCount, texCoordSetMap);
2564 	      ga = (GeometryArray)ta;
2565 	      break;
2566 
2567 	  case QUAD_ARRAY:
2568 	      QuadArray qa = new QuadArray(vertexCount, vertexFormat,
2569 		      texCoordSetCount, texCoordSetMap);
2570 	      ga = (GeometryArray)qa;
2571 	      break;
2572 
2573 	  case TRIANGLE_STRIP_ARRAY:
2574 	      TriangleStripArray tsa = new TriangleStripArray(vertexCount,
2575 		      vertexFormat, texCoordSetCount, texCoordSetMap,
2576 		      stripCounts);
2577 	      ga = (GeometryArray)tsa;
2578 	      break;
2579 
2580 	  case TRIANGLE_FAN_ARRAY:
2581 	      TriangleFanArray tfa = new TriangleFanArray(vertexCount,
2582 		      vertexFormat, texCoordSetCount, texCoordSetMap,
2583 		      stripCounts);
2584 	      ga = (GeometryArray)tfa;
2585 	      break;
2586       }
2587 
2588       fillIn(ga, byRef, interleaved, nio);
2589 
2590       return ga;
2591   } // End of getGeometryArray(int, int)
2592 
2593 
2594 
2595   /**
2596    * Creates and returns a non-indexed Java 3D GeometryArray object
2597    * based on the data in the GeometryInfo object.  This object is
2598    * suitable to be attached to a Shape3D node for rendering.
2599    * The geometry is <b>not</b> created using data BY_REFERENCE,
2600    * INTERLEAVED, or USE_NIO_BUFFER.
2601    * @throws IllegalArgumentException if coordinate data is missing,
2602    * if the index lists aren't all the
2603    * same length, if an index list is set and the corresponding data
2604    * list isn't set, if a data list is set and the corresponding
2605    * index list is unset (unless all index lists are unset or in
2606    * USE_COORD_INDEX_ONLY format),
2607    * if StripCounts or ContourCounts is inconsistent with the current
2608    * primitive, if the sum of the contourCounts array doesn't equal
2609    * the length of the StripCounts array, or if the number of vertices
2610    * isn't a multiple of three (for triangles) or four (for quads).
2611    */
getGeometryArray()2612   public GeometryArray getGeometryArray()
2613   {
2614     return getGeometryArray(false, false, false);
2615   } // End of getGeometryArray()
2616 
2617 
2618 
2619   /**
2620    * Creates and returns a IndexedGeometryArray
2621    * based on the data in the GeometryInfo object.  This object is
2622    * suitable to be attached to a Shape3D node for rendering.
2623    * @param compact Remove Coordinates, Colors, Normals, and
2624    * TextureCoordinates that aren't referenced by any indices.
2625    * @param byRef Create the IndexedGeometryArray using geometry
2626    * BY_REFERENCE.
2627    * @param interleaved Use INTERLEAVED geometry.  Implies byRef is
2628    * true as well.
2629    * @param nio Create GeometryArray using java.nio.Buffer for
2630    * geometry arrays.  Only usable on JDK 1.4 or higher.  Implies
2631    * byRef is true as well.
2632    * @param useCoordIndexOnly Create the IndexedGeometryArray using
2633    * USE_COORD_INDEX_ONLY.  Values from the coordinate index array
2634    * are used as a single set of indices into all vertex
2635    * component arrays (coord, color, normal, and texCoord).
2636    * @throws IllegalArgumentException if coordinate data is missing,
2637    * if the index lists aren't all the
2638    * same length, if an index list is set and the corresponding data
2639    * list isn't set, if a data list is set and the corresponding
2640    * index list is unset (unless all index lists are unset or in
2641    * USE_COORD_INDEX_ONLY format),
2642    * if StripCounts or ContourCounts is inconsistent with the current
2643    * primitive, if the sum of the contourCounts array doesn't equal
2644    * the length of the StripCounts array, or if the number of vertices
2645    * isn't a multiple of three (for triangles) or four (for quads).
2646    */
getIndexedGeometryArray(boolean compact, boolean byRef, boolean interleaved, boolean useCoordIndexOnly, boolean nio)2647   public IndexedGeometryArray getIndexedGeometryArray(boolean compact,
2648  						      boolean byRef,
2649 						      boolean interleaved,
2650 						      boolean useCoordIndexOnly,
2651 						      boolean nio)
2652   {
2653       indexify(useCoordIndexOnly);
2654 
2655       if (compact) compact();
2656 
2657       if (prim == POLYGON_ARRAY) {
2658 	  if (tr == null) tr = new Triangulator();
2659 	  tr.triangulate(this);
2660       } else changeBackToOldPrim();
2661 
2662        if (useCoordIndexOnly && coordOnly == false) {
2663            // Check to see if we can optimize for USE_COORD_INDEX_ONLY
2664 	   int i, j;
2665            boolean canUseCoordIndexOnly = true;
2666 
2667            if (coordinateIndices != null) {
2668              // See if all the array lengths are the same
2669              if (colorIndices != null &&
2670                  colorIndices.length != coordinateIndices.length) {
2671                  canUseCoordIndexOnly = false;
2672              }
2673              if (normalIndices != null &&
2674                  normalIndices.length != coordinateIndices.length) {
2675                  canUseCoordIndexOnly = false;
2676              }
2677              for (i = 0 ; i < texCoordSetCount ; i++) {
2678                  if (texCoordIndexSets[i] != null &&
2679                      texCoordIndexSets[i].length != coordinateIndices.length) {
2680                      canUseCoordIndexOnly = false;
2681                      break;
2682                  }
2683              }
2684              if (canUseCoordIndexOnly &&
2685 		 ((colorIndices != null) ||
2686 		  (normalIndices != null) ||
2687 		  (texCoordSetCount > 0))) {
2688                  // All array lengths are the same.  Check their contents
2689 
2690                  for (i=0; i<coordinateIndices.length; i++) {
2691                      int indexValue = coordinateIndices[i];
2692 
2693 
2694                      if (colorIndices != null &&
2695                          colorIndices[i] != indexValue) {
2696                          canUseCoordIndexOnly = false;
2697                          break;
2698                      }
2699                      if (normalIndices != null &&
2700                          normalIndices[i] != indexValue) {
2701                          canUseCoordIndexOnly = false;
2702                          break;
2703                      }
2704                      for (j=0; j<texCoordSetCount; j++) {
2705                          if (texCoordIndexSets[j] != null &&
2706                              texCoordIndexSets[j][i] != indexValue) {
2707                              canUseCoordIndexOnly = false;
2708                              break;
2709                          }
2710                      }
2711                  }
2712              }
2713            }
2714          coordOnly = canUseCoordIndexOnly;
2715        }
2716 
2717       int vertexFormat = getVertexFormat();
2718       if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE |
2719 				GeometryArray.USE_NIO_BUFFER);
2720       if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE |
2721 					GeometryArray.INTERLEAVED);
2722       if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE;
2723       if (coordOnly) vertexFormat |= GeometryArray.USE_COORD_INDEX_ONLY;
2724 
2725       int vertexCount = getVertexCount();
2726 
2727       if ((texCoordSetCount > 0) && (texCoordSetMap == null)) {
2728 	  texCoordSetCount = 1;
2729 	  texCoordSetMap = new int[1];
2730 	  texCoordSetMap[0] = 0;
2731       }
2732 
2733       //
2734       // Create the IndexedGeometryArray object
2735       //
2736 
2737       IndexedGeometryArray ga = null;
2738 
2739       switch (prim) {
2740 	  case TRIANGLE_ARRAY:
2741 	      IndexedTriangleArray ta = new IndexedTriangleArray(vertexCount,
2742 		      vertexFormat, texCoordSetCount, texCoordSetMap,
2743 		      coordinateIndices.length);
2744 	      ga = (IndexedGeometryArray)ta;
2745 	      break;
2746 
2747 	  case QUAD_ARRAY:
2748 	      IndexedQuadArray qa = new IndexedQuadArray(vertexCount,
2749 		      vertexFormat, texCoordSetCount, texCoordSetMap,
2750 		      coordinateIndices.length);
2751 	      ga = (IndexedGeometryArray)qa;
2752 	      break;
2753 	  case TRIANGLE_STRIP_ARRAY:
2754 	      IndexedTriangleStripArray tsa = new IndexedTriangleStripArray(
2755 		      vertexCount, vertexFormat, texCoordSetCount,
2756 		      texCoordSetMap, coordinateIndices.length, stripCounts);
2757 	      ga = (IndexedGeometryArray)tsa;
2758 	      break;
2759 
2760 	  case TRIANGLE_FAN_ARRAY:
2761 	      IndexedTriangleFanArray tfa = new IndexedTriangleFanArray(
2762 		      vertexCount, vertexFormat, texCoordSetCount,
2763 		      texCoordSetMap, coordinateIndices.length, stripCounts);
2764 	      ga = (IndexedGeometryArray)tfa;
2765 	      break;
2766       }
2767 
2768       // Fill in the GeometryArray object
2769       fillIn(ga, byRef, interleaved, nio);
2770 
2771       return ga;
2772   } // End of getIndexedGeometryArray(bool, bool, bool, bool, bool)
2773 
2774 
2775 
2776   /**
2777    * Creates and returns an IndexedGeometryArray
2778    * based on the data in the GeometryInfo object.  This object is
2779    * suitable to be attached to a Shape3D node for rendering.
2780    * Equivalent to <code>getIndexedGeometryArray(compact, false,
2781    * false, false, false)</code>.
2782    * @param compact Remove Coordinates, Colors, Normals, and
2783    * TextureCoordinates that aren't referenced by any indices.
2784    * @throws IllegalArgumentException if coordinate data is missing,
2785    * if the index lists aren't all the
2786    * same length, if an index list is set and the corresponding data
2787    * list isn't set, if a data list is set and the corresponding
2788    * index list is unset (unless all index lists are unset or in
2789    * USE_COORD_INDEX_ONLY format),
2790    * if StripCounts or ContourCounts is inconsistent with the current
2791    * primitive, if the sum of the contourCounts array doesn't equal
2792    * the length of the StripCounts array, or if the number of vertices
2793    * isn't a multiple of three (for triangles) or four (for quads).
2794    */
getIndexedGeometryArray(boolean compact)2795   public IndexedGeometryArray getIndexedGeometryArray(boolean compact)
2796   {
2797     return getIndexedGeometryArray(compact, false, false, false, false);
2798   } // End of getIndexedGeometryArray(boolean)
2799 
2800 
2801 
2802   /**
2803    * Creates and returns an IndexedGeometryArray
2804    * based on the data in the GeometryInfo object.  This object is
2805    * suitable to be attached to a Shape3D node for rendering.
2806    * Equivalent to <code>getIndexedGeometryArray(false, false,
2807    * false, false, false)</code>.
2808    * @throws IllegalArgumentException if coordinate data is missing,
2809    * if the index lists aren't all the
2810    * same length, if an index list is set and the corresponding data
2811    * list isn't set, if a data list is set and the corresponding
2812    * index list is unset (unless all index lists are unset or in
2813    * USE_COORD_INDEX_ONLY format),
2814    * if StripCounts or ContourCounts is inconsistent with the current
2815    * primitive, if the sum of the contourCounts array doesn't equal
2816    * the length of the StripCounts array, or if the number of vertices
2817    * isn't a multiple of three (for triangles) or four (for quads).
2818    */
getIndexedGeometryArray()2819   public IndexedGeometryArray getIndexedGeometryArray()
2820   {
2821       return getIndexedGeometryArray(false, false, false, false, false);
2822   } // End of getIndexedGeometryArray()
2823 
2824 } // End of class GeometryInfo
2825 
2826 // End of file GeometryInfo.java
2827