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, & 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