org.scijava.java3d.utils.geometry.GeometryInfo Maven / Gradle / Ivy
Show all versions of j3dutils Show documentation
/*
* Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistribution of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any
* kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
* EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
* NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
* USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
* ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
* CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
* REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
* INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or
* intended for use in the design, construction, operation or
* maintenance of any nuclear facility.
*
*/
package org.scijava.java3d.utils.geometry;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.HashMap;
import org.scijava.java3d.GeometryArray;
import org.scijava.java3d.IndexedGeometryArray;
import org.scijava.java3d.IndexedQuadArray;
import org.scijava.java3d.IndexedTriangleArray;
import org.scijava.java3d.IndexedTriangleFanArray;
import org.scijava.java3d.IndexedTriangleStripArray;
import org.scijava.java3d.J3DBuffer;
import org.scijava.java3d.QuadArray;
import org.scijava.java3d.TriangleArray;
import org.scijava.java3d.TriangleFanArray;
import org.scijava.java3d.TriangleStripArray;
import org.scijava.vecmath.Color3b;
import org.scijava.vecmath.Color3f;
import org.scijava.vecmath.Color4b;
import org.scijava.vecmath.Color4f;
import org.scijava.vecmath.Point2f;
import org.scijava.vecmath.Point3d;
import org.scijava.vecmath.Point3f;
import org.scijava.vecmath.TexCoord2f;
import org.scijava.vecmath.TexCoord3f;
import org.scijava.vecmath.TexCoord4f;
import org.scijava.vecmath.Tuple2f;
import org.scijava.vecmath.Tuple3f;
import org.scijava.vecmath.Tuple4f;
import org.scijava.vecmath.Vector3f;
import org.scijava.java3d.internal.J3dUtilsI18N;
/**
* The GeometryInfo object holds data for processing by the Java3D geometry
* utility tools.
*
* The NormalGenerator adds normals to geometry without normals.
*
* The Stripifier combines adjacent triangles into triangle strips for
* more efficent rendering.
*
* Also, the GeometryCompressor can take a set of GeometryInfo objects in a
* CompressionSteam and generate a CompressedGeometry object from the
* geometry.
* Geometry is loaded into a GeometryInfo in a manner similar to the
*
* GeometryArray methods. The constructor for the GeometryInfo takes a flag
* that specifies the kind of data being loaded. The vertex data is
* specified using methods that are similar to the GeometryArray methods, but
* with fewer variations.
* The major difference between GeometryInfo and GeometryArray is
* that the number of vertices, vertex format, and other data are specified
* implictly, rather than as part of the constructor. The number of verticies
* comes from the number of coordinates passed to the setCoordinates()
* method. The format comes from the set of data components that are
* specified. For example, calling the setCoordinates(), setColors3() and
* setTextureCoordinatesParames(1, 2) methods implies a
* format of COORDINATES | COLOR_3
* | TEXTURE_COORDINATE_2. Indexed representation is specified by calling
* the methods that specify the indices, for example
* setCoordinateIndices().
* Stripped primitives are loaded using the TRIANGLE_FAN_ARRAY or
* TRIANGLE_STRIP_ARRAY flags to the constructor. The setStripCounts()
* method specifies the length of each strip.
* A set of complex polygons is loaded using the POLYGON_ARRAY
* flag to the constructor. The setStripCounts() method specifies the length
* of each contour of the polygons. The setContourCounts() method specifies
* the number of countours in each polygon. For example, a triangle with a
* triangular hole would have strip counts [3, 3] (indicating two contours of
* three points) and contour counts [2] (indicating a single polygon with two
* contours).
* GeometryInfo itelf contains some simple utilities, such as
* calculating indices for non-indexed data ("indexifying") and getting rid
* of unused data in your indexed geometry ("compacting").
* The geometry utility tools modify the contents of the
* GeometryInfo. After processing, the resulting geometry can be extracted
* from the GeometryInfo by calling getGeometryArray(). If multiple tools
* are used, the order of processing should be: generate normals, then
* stripify. For example, to convert a general mesh of polygons without
* normals into an optimized mesh call:
*
* GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
* // initialize the geometry info here
* // generate normals
* NormalGenerator ng = new NormalGenerator();
* ng.generateNormals(gi);
* // stripify
* Stripifier st = new Stripifier();
* st.stripify(gi);
* GeometryArray result = gi.getGeometryArray();
*
*
* @see NormalGenerator
* @see Stripifier
* @see org.scijava.java3d.utils.compression.CompressionStream
* @see org.scijava.java3d.utils.compression.GeometryCompressor
* @see org.scijava.java3d.GeometryArray
*/
public class GeometryInfo {
/**
* Send to the constructor to inform that the data will be arranged so
* that each set of three vertices form an independent triangle
*/
public static final int TRIANGLE_ARRAY = 1;
/**
* Send to the constructor to inform that the data will be arranged so
* that each set of four vertices form an independent quad
*/
public static final int QUAD_ARRAY = 2;
/**
* Send to the constructor to inform that the data will be arranged so
* that the stripCounts array indicates how many vertices to use
* for each triangle fan.
*/
public static final int TRIANGLE_FAN_ARRAY = 3;
/**
* Send to the constructor to inform that the data will be arranged so
* that the stripCounts array indicates how many vertices to use
* for each triangle strip.
*/
public static final int TRIANGLE_STRIP_ARRAY = 4;
/**
* Send to the constructor to inform that the data is arranged as
* possibly multi-contour, possible non-planar polygons.
* The stripCounts array indicates how many vertices to use
* for each contour, and the contourCounts array indicates how many
* stripCounts entries to use for each polygon. The first
* contour is the bounding polygon, and subsequent contours are
* "holes." If contourCounts is left null, the default is
* one contour per polygon.
*/
public static final int POLYGON_ARRAY = 5;
private int prim;
// 1 Show indexification details
private static final int DEBUG = 0;
private Point3f coordinates[] = null;
private Color3f colors3[] = null;
private Color4f colors4[] = null;
private Vector3f normals[] = null;
private Object texCoordSets[][] = null;
private int coordinateIndices[] = null;
private int colorIndices[] = null;
private int normalIndices[] = null;
private int texCoordIndexSets[][] = null;
private int[] texCoordSetMap = null;
private int texCoordSetCount = 0;
private int texCoordDim = 0;
private int stripCounts[] = null;
private int contourCounts[] = null;
private Triangulator tr = null;
private NormalGenerator ng = null;
private int oldPrim = 0;
private int oldStripCounts[] = null;
private boolean coordOnly = false;
/**
* Constructor.
* Creates an empty GeometryInfo object.
* @param primitive Tells the GeometryInfo object the type of
* primitive data to be stored
* in it, so it will know the format of the data. It can be one of
* TRIANGLE_ARRAY,
* QUAD_ARRAY, TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
*/
public GeometryInfo(int primitive)
{
if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
prim = primitive;
} else {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo0"));
}
} // End of GeometryInfo(int)
/**
* Contructor. Populates the GeometryInfo with the geometry from
* the GeometryArray.
* If the GeometryArray uses the Initial
and
* Valid
GeometryArray methods (
* setInitialVertexIndex()
and setValidVertexCount()
*
and their cousins) then only the needed geometry
* is copied into the GeometryInfo.
*/
public GeometryInfo(GeometryArray ga)
{
GeometryInfoGenerator.create(this, ga);
} // End of GeometryInfo(GeometryArray)
/**
* Removes all data from the GeometryInfo and resets the primitive.
* After a call to reset(), the GeometryInfo object will be just like
* it was when it was newly constructed.
* @param primitive Either TRIANGLE_ARRAY, QUAD_ARRAY,
* TRIANGLE_FAN_ARRAY, TRIANGLE_STRIP_ARRAY, or POLYGON_ARRAY.
* Tells the GeometryInfo object the type of primitive data to be stored
* in it, so it will know the format of the data.
*/
public void reset(int primitive)
{
if ((primitive >= TRIANGLE_ARRAY) && (primitive <= POLYGON_ARRAY)) {
prim = primitive;
} else {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo0"));
}
coordinates = null;
colors3 = null;
colors4 = null;
normals = null;
coordinateIndices = null;
colorIndices = null;
normalIndices = null;
stripCounts = null;
contourCounts = null;
oldPrim = 0;
oldStripCounts = null;
texCoordDim = 0;
texCoordSetCount = 0;
texCoordSets = null;
texCoordIndexSets = null;
texCoordSetMap = null;
coordOnly = false;
} // End of reset(int)
/**
* Removes all data from this GeometryInfo and populates it with
* the geometry from the GeometryArray.
*/
public void reset(GeometryArray ga)
{
GeometryInfoGenerator.create(this, ga);
} // End of reset(GeometryArray)
// This method takes an indexed quad array and expands it to
// a list of indexed triangles. It is used for the Coordinate
// indices as well as the color and texture indices.
private int[] expandQuad(int indices[])
{
int triangles[] = new int[indices.length / 4 * 6];
for (int i = 0 ; i < indices.length / 4 ; i++ ) {
triangles[i * 6 + 0] = indices[i * 4];
triangles[i * 6 + 1] = indices[i * 4 + 1];
triangles[i * 6 + 2] = indices[i * 4 + 2];
triangles[i * 6 + 3] = indices[i * 4];
triangles[i * 6 + 4] = indices[i * 4 + 2];
triangles[i * 6 + 5] = indices[i * 4 + 3];
}
return triangles;
} // End of expandQuad
// This method takes an indexed triangle fan and expands it to
// a list of indexed triangles. It is used for the Coordinate
// indices as well as the color and texture indices.
private int[] expandTriFan(int numTris, int indices[])
{
int triangles[] = new int[numTris * 3];
int p = 0;
int base = 0;
for (int f = 0 ; f < stripCounts.length ; f++) {
for (int t = 0 ; t < stripCounts[f] - 2 ; t++) {
triangles[p++] = indices[base];
triangles[p++] = indices[base + t + 1];
triangles[p++] = indices[base + t + 2];
}
base += stripCounts[f];
}
return triangles;
} // End of expandTriFan
// This method takes an indexed triangle strip and expands it to
// a list of indexed triangles. It is used for the Coordinate
// indices as well as the color and texture indices.
private int[] expandTriStrip(int numTris, int indices[])
{
int triangles[] = new int[numTris * 3];
int p = 0;
int base = 0;
for (int s = 0 ; s < stripCounts.length ; s++) {
for (int t = 0 ; t < stripCounts[s] - 2 ; t++) {
// Use a ping-ponging algorithm to reverse order on every other
// triangle to preserve winding
if (t % 2 == 0) {
triangles[p++] = indices[base + t + 0];
triangles[p++] = indices[base + t + 1];
triangles[p++] = indices[base + t + 2];
} else {
triangles[p++] = indices[base + t + 0];
triangles[p++] = indices[base + t + 2];
triangles[p++] = indices[base + t + 1];
}
}
base += stripCounts[s];
}
return triangles;
} // End of expandTriStrip
// Used by the NormalGenerator utility. Informs the GeometryInfo object
// to remember its current primitive and stripCounts arrays so that
// they can be used to convert the object back to its original
// primitive
void rememberOldPrim()
{
oldPrim = prim;
oldStripCounts = stripCounts;
} // End of rememberOldPrim
// The NormalGenerator needs to know the original primitive for
// facet normal generation for quads
int getOldPrim()
{
return oldPrim;
} // End of getOldPrim
// Used by the Utility libraries other than the NormalGenerator.
// Informs the GeometryInfo object that the geometry need not
// be converted back to the original primitive before returning.
// For example, if a list of Fans is sent, converted to Triangles
// for normal generation, and then stripified by the Stripifyer,
// we want to make sure that GeometryInfo doesn't convert the
// geometry *back* to fans before creating the output GeometryArray.
void forgetOldPrim()
{
oldPrim = 0;
oldStripCounts = null;
} // End of forgetOldPrim
// We have changed the user's data from their original primitive
// type to TRIANGLE_ARRAY. If this method is being called, it
// means we need to change it back (to try and hide from the user
// the fact that we've converted). This usually happens when
// the user has used GeometryInfo for generating normals, but
// they are not Stripifying or Triangulating. The function is
// called from getGeometryArray before creating the output data.
private void changeBackToOldPrim()
{
if (oldPrim != 0) {
convertToIndexedTriangles();
if (ng == null) ng = new NormalGenerator();
ng.convertBackToOldPrim(this, oldPrim, oldStripCounts);
oldPrim = 0;
oldStripCounts = null;
}
} // End of changeBackToOldPrim
/**
* Convert the GeometryInfo object to have primitive type TRIANGLE_ARRAY
* and be indexed.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void convertToIndexedTriangles()
{
int triangles = 0;
// This calls checkForBadData
indexify();
if (prim == TRIANGLE_ARRAY) return;
switch(prim) {
case QUAD_ARRAY:
coordinateIndices = expandQuad(coordinateIndices);
if (colorIndices != null) colorIndices = expandQuad(colorIndices);
if (normalIndices != null)
normalIndices = expandQuad(normalIndices);
for (int i = 0 ; i < texCoordSetCount ; i++)
texCoordIndexSets[i] = expandQuad(texCoordIndexSets[i]);
break;
case TRIANGLE_FAN_ARRAY:
// Count how many triangles are in the object
for (int i = 0 ; i < stripCounts.length ; i++) {
triangles += stripCounts[i] - 2;
}
coordinateIndices = expandTriFan(triangles, coordinateIndices);
if (colorIndices != null)
colorIndices = expandTriFan(triangles, colorIndices);
if (normalIndices != null)
normalIndices = expandTriFan(triangles, normalIndices);
for (int i = 0 ; i < texCoordSetCount ; i++)
texCoordIndexSets[i] = expandTriFan(triangles,
texCoordIndexSets[i]);
break;
case TRIANGLE_STRIP_ARRAY:
// Count how many triangles are in the object
for (int i = 0 ; i < stripCounts.length ; i++) {
triangles += stripCounts[i] - 2;
}
coordinateIndices = expandTriStrip(triangles, coordinateIndices);
if (colorIndices != null)
colorIndices = expandTriStrip(triangles, colorIndices);
if (normalIndices != null)
normalIndices = expandTriStrip(triangles, normalIndices);
for (int i = 0 ; i < texCoordSetCount ; i++)
texCoordIndexSets[i] = expandTriStrip(triangles,
texCoordIndexSets[i]);
break;
case POLYGON_ARRAY:
if (tr == null) tr = new Triangulator();
tr.triangulate(this);
break;
}
prim = TRIANGLE_ARRAY;
stripCounts = null;
} // End of convertToIndexedTriangles
/**
* Get the current primitive. Some of the utilities may change the
* primitive type of the data stored in the GeometryInfo object
* (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
*/
public int getPrimitive()
{
return prim;
} // End of getPrimitive()
/**
* Set the current primitive. Some of the utilities may change the
* primitive type of the data stored in the GeometryInfo object
* (for example, the stripifyer will change it to TRIANGLE_STRIP_ARRAY).
* But the user can't change the primitive type - it is set in the
* constructor. Therefore, this method has package scope.
*/
void setPrimitive(int primitive)
{
if ((prim >= TRIANGLE_ARRAY) && (prim <= POLYGON_ARRAY)) {
prim = primitive;
} else {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo0"));
}
} // End of setPrimitive()
/**
* Sets the coordinates array.
* No data copying is done because a reference to user data is used.
*/
public void setCoordinates(Point3f coordinates[])
{
this.coordinates = coordinates;
} // End of setCoordinates
/**
* Sets the coordinates array.
* The points are copied into the GeometryInfo object.
*/
public void setCoordinates(Point3d coordinates[])
{
if (coordinates == null) this.coordinates = null;
else {
this.coordinates = new Point3f[coordinates.length];
for (int i = 0 ; i < coordinates.length ; i++) {
this.coordinates[i] = new Point3f(
(float)(coordinates[i].x),
(float)(coordinates[i].y),
(float)(coordinates[i].z));
}
}
} // End of setCoordinates
/**
* Sets the coordinates array.
* The points are copied into the GeometryInfo object.
*/
public void setCoordinates(float coordinates[])
{
if (coordinates == null) this.coordinates = null;
else {
this.coordinates = new Point3f[coordinates.length / 3];
for (int i = 0 ; i < this.coordinates.length ; i++) {
this.coordinates[i] = new Point3f(coordinates[i * 3],
coordinates[i * 3 + 1],
coordinates[i * 3 + 2]);
}
}
} // End of setCoordinates
/**
* Sets the coordinates array.
* The points are copied into the GeometryInfo object.
*/
public void setCoordinates(double coordinates[])
{
if (coordinates == null) this.coordinates = null;
else {
this.coordinates = new Point3f[coordinates.length / 3];
for (int i = 0 ; i < coordinates.length / 3 ; i++) {
this.coordinates[i] = new Point3f((float)coordinates[i * 3],
(float)coordinates[i * 3 + 1],
(float)coordinates[i * 3 + 2]);
}
}
} // End of setCoordinates
/**
* Retrieves a reference to the coordinate array.
*/
public Point3f[] getCoordinates()
{
return coordinates;
} // End of getCoordinates
/**
* Sets the colors array.
* No data copying is done because a reference to
* user data is used.
*/
public void setColors(Color3f colors[])
{
colors3 = colors;
colors4 = null;
} // End of setColors
/**
* Sets the colors array.
* No data copying is done because a reference to
* user data is used.
*/
public void setColors(Color4f colors[])
{
colors3 = null;
colors4 = colors;
} // End of setColors
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object.
*/
public void setColors(Color3b colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = new Color3f[colors.length];
colors4 = null;
for (int i = 0 ; i < colors.length ; i++) {
colors3[i] = new Color3f((float) (colors[i].x & 0xff) / 255.0f,
(float) (colors[i].y & 0xff) / 255.0f,
(float) (colors[i].z & 0xff) / 255.0f);
}
}
} // End of setColors
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object.
*/
public void setColors(Color4b colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = null;
colors4 = new Color4f[colors.length];
for (int i = 0 ; i < colors.length ; i++) {
colors4[i] = new Color4f((float) (colors[i].x & 0xff) / 255.0f,
(float) (colors[i].y & 0xff) / 255.0f,
(float) (colors[i].z & 0xff) / 255.0f,
(float) (colors[i].w & 0xff) / 255.0f);
}
}
} // End of setColors
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object, assuming
* 3 components (R, G, and B) per vertex.
*/
public void setColors3(float colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = new Color3f[colors.length / 3];
colors4 = null;
for (int i = 0 ; i < colors.length / 3 ; i++) {
colors3[i] = new Color3f(colors[i * 3],
colors[i * 3 + 1],
colors[i * 3 + 2]);
}
}
} // End of setColors3
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object, assuming
* 4 components (R, G, B, and A) per vertex.
*/
public void setColors4(float colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = null;
colors4 = new Color4f[colors.length / 4];
for (int i = 0 ; i < colors.length / 4 ; i++) {
colors4[i] = new Color4f(colors[i * 4],
colors[i * 4 + 1],
colors[i * 4 + 2],
colors[i * 4 + 3]);
}
}
} // End of setColors4
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object, assuming
* 3 components (R, G, and B) per vertex.
*/
public void setColors3(byte colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = new Color3f[colors.length / 3];
colors4 = null;
for (int i = 0 ; i < colors.length / 3 ; i++) {
colors3[i] =
new Color3f((float)(colors[i * 3] & 0xff) / 255.0f,
(float)(colors[i * 3 + 1] & 0xff) / 255.0f,
(float)(colors[i * 3 + 2] & 0xff) / 255.0f);
}
}
} // End of setColors3
/**
* Sets the colors array.
* The points are copied into the GeometryInfo object, assuming
* 4 components (R, G, B, and A) per vertex.
*/
public void setColors4(byte colors[])
{
if (colors == null) {
colors3 = null;
colors4 = null;
} else {
colors3 = null;
colors4 = new Color4f[colors.length / 4];
for (int i = 0 ; i < colors.length / 4 ; i++) {
colors4[i] =
new Color4f((float)(colors[i * 4] & 0xff) / 255.0f,
(float)(colors[i * 4 + 1] & 0xff) / 255.0f,
(float)(colors[i * 4 + 2] & 0xff) / 255.0f,
(float)(colors[i * 4 + 3] & 0xff) / 255.0f);
}
}
} // End of setColors4
/**
* Retrieves a reference to the colors array. Will be either
* Color3f[]
or Color4f[]
depending on
* the type of the input data. Call
* getNumColorComponents() to find out which version is returned.
*/
public Object[] getColors()
{
if (colors3 != null) return colors3;
else return colors4;
} // End of getColors
/**
* Returns the number of color data components stored per vertex
* in the current GeometryInfo object (3 for RGB or 4 for RGBA).
* If no colors are currently defined, 0 is returned.
*/
public int getNumColorComponents()
{
if (colors3 != null) return 3;
else if (colors4 != null) return 4;
else return 0;
} // End of getNumColorComponents
/**
* Sets the normals array.
* No data copying is done because a reference to
* user data is used.
*/
public void setNormals(Vector3f normals[])
{
this.normals = normals;
} // End of setNormals
/**
* Sets the normals array.
* The points are copied into the GeometryInfo object.
*/
public void setNormals(float normals[])
{
if (normals == null) this.normals = null;
else {
this.normals = new Vector3f[normals.length / 3];
for (int i = 0 ; i < this.normals.length ; i++) {
this.normals[i] = new Vector3f(normals[i * 3],
normals[i * 3 + 1],
normals[i * 3 + 2]);
}
}
} // End of setNormals(float[])
/**
* Retrieves a reference to the normal array.
*/
public Vector3f[] getNormals()
{
return normals;
} // End of getNormals
/**
* This method is used to specify the number of texture coordinate sets
* and the dimensionality of the texture coordinates.
* The number of texture coordinate sets must be specified to the GeometryInfo
* class before any of the sets are specified. The dimensionality of the
* texture coordinates may be 2, 3, or 4, corresponding to 2D, 3D, or 4D
* texture coordinates respectively.(All sets must have the same
* dimensionality.) The default is zero, 2D texture coordinate sets.
* This method should be called before any texture coordinate sets are
* specified because calling this method will delete all previously
* specified texture coordinate and texture coordinate index arrays
* associated with this GeometryInfo. For example:
*
* geomInfo.setTextureCoordinateParams(2, 3);
* geomInfo.setTextureCoordinates(0, tex0);
* geomInfo.setTextureCoordinates(1, tex1);
* geomInfo.setTextureCoordinateParams(1, 2);
* geomInfo.getTexCoordSetCount();
*
* The second call to setTextureCoordinateParams
will erase all
* the texture coordinate arrays, so the subsequent call to
* getTexCoordSetCount
will return 1.
* @param numSets The number of texture coordinate sets that will be
* specified for this GeometryInfo object.
* @param dim The dimensionality of the texture coordinates. Has to be 2, 3
* or 4.
* @throws IllegalArgumentException if the dimensionality of the texture
* coordinates is not one of 2, 3 or 4.
*/
public void setTextureCoordinateParams(int numSets, int dim)
{
if (dim == 2) {
texCoordSets = new TexCoord2f[numSets][];
} else if (dim == 3) {
texCoordSets = new TexCoord3f[numSets][];
} else if (dim == 4) {
texCoordSets = new TexCoord4f[numSets][];
} else {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo9"));
}
texCoordIndexSets = new int[numSets][];
texCoordDim = dim;
texCoordSetCount = numSets;
} // End of setTextureCoordinateParams
/**
* Returns the number of texture coordinate sets in this GeometryInfo.
* This value is set with setTextureCoordinateParams().
* If setTextureCoordinateParams()
* has not been called, 0 is returned unless one of the deprecated
* texture coordinate methods has been called. Calling one of the
* deprecated texture coordinate methods sets the count to 1.
* The deprecated texture coordinate methods are those that don't
* take texCoordSet as the first parameter.
* @return the number of texture coordinate sets in this
* GeometryInfo.
*/
public int getTexCoordSetCount() {
return texCoordSetCount;
}
/**
* Returns the number of texture coordinate components that are stored
* per vertex. Returns 2 for ST (2D), 3 for STR (3D),
* or 4 for STRQ (4D), aslo known as the "dimensionality" of the
* coordinates. This value is set with
* setTextureCoordinateParams(). If setTextureCoordinateParams()
* has not been called, 0 is returned unless one of the deprecated
* texture coordinate methods has been called. Calling one of the
* deprecated texture coordinate methods sets the dimensionality
* explicitly (if you called setTextureCoordinates(Point2f[]) then
* 2 is returned).
* The deprecated texture coordinate methods are those that don't
* take texCoordSet as the first parameter.
*/
public int getNumTexCoordComponents()
{
return texCoordDim;
} // End of getNumTexCoordComponents
/**
* Sets the mapping between texture coordinate sets and texture units.
* See the
*
* GeometryArray constructor for further details.
* Note: If the texCoordSetMap is not set, multi-texturing is
* turned off. Only the texture coordinate set at index 0 (if set) will be
* used. Any other sets specified by the GeometryInfo.setTextureCoordinate*
* methods will be ignored.
*/
public void setTexCoordSetMap(int map[]) {
texCoordSetMap = map;
}
/**
* Returns a reference to the texture coordinate set map.
* See the
*
* GeometryArray constructor for further details.
*/
public int[] getTexCoordSetMap() {
return texCoordSetMap;
}
/**
* Sets the 2D texture coordinates for the specified set.
* No data copying is done - a reference to user data is used.
* @param texCoordSet The texture coordinate set for which these
* coordinates are being specified.
* @param texCoords Array of 2D texture coordinates.
* @throws IllegalArgumentException if texCoordSet
< 0 or
* texCoordSet >= texCoordSetCount
,
* or the texture coordinate parameters were not previously set by
* calling setTextureCoordinateParams(texCoordSetCount, 2)
.
*/
public void setTextureCoordinates(int texCoordSet, TexCoord2f texCoords[])
{
if (texCoordDim != 2)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo15"));
if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo18"));
texCoordSets[texCoordSet] = texCoords;
} // End of setTextureCoordinates(int, TexCoord3f[])
/**
* Sets the TextureCoordinates array by copying the data
* into the GeometryInfo object.
* This method sets the number of texture coordinate sets to 1,
* sets the dimensionality of the texture coordinates to 2,
* and sets the coordinates for texture coordinate set 0.
* @deprecated As of Java 3D 1.3 replaced by
* setTextureCoordinates(int texCoordSet, TexCoord2f coords[])
*/
public void setTextureCoordinates(Point2f texCoords[])
{
texCoordSetCount = 1;
texCoordDim = 2;
texCoordSets = new TexCoord2f[1][];
if (texCoords != null) {
TexCoord2f[] tex = new TexCoord2f[texCoords.length];
for (int i = 0 ; i < texCoords.length ; i++)
tex[i] = new TexCoord2f(texCoords[i]);
texCoordSets[0] = tex;
}
} // End of setTextureCoordinates(Point2f[])
/**
* Sets the texture coordinates array for the specified set.
* No data copying is done - a reference to user data is used.
* @param texCoordSet The texture coordinate set for which these coordinates
* are being specified.
* @param texCoords Array of 3D texture coordinates.
* @throws IllegalArgumentException if texCoordSet
< 0 or
* texCoordSet >= texCoordSetCount
,
* or the texture coordinate parameters were not previously set by
* calling setTextureCoordinateParams(texCoordSetCount, 3)
.
*/
public void setTextureCoordinates(int texCoordSet, TexCoord3f texCoords[])
{
if (texCoordDim != 3)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo16"));
if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo18"));
texCoordSets[texCoordSet] = texCoords;
} // End of setTextureCoordinates(int, TexCoord3f[])
/**
* Sets the TextureCoordinates array by copying the data
* into the GeometryInfo object.
* This method sets the number of texture coordinate sets to 1,
* sets the dimensionality of the texture coordinates to 3,
* and sets the coordinates for texture coordinate set 0.
* @deprecated As of Java 3D 1.3 replaced by
* setTextureCoordinates(int texCoordSet, TexCoord3f coords[])
*/
public void setTextureCoordinates(Point3f texCoords[])
{
texCoordSetCount = 1;
texCoordDim = 3;
texCoordSets = new TexCoord3f[1][];
if (texCoords != null) {
TexCoord3f[] tex = new TexCoord3f[texCoords.length];
for (int i = 0 ; i < texCoords.length ; i++)
tex[i] = new TexCoord3f(texCoords[i]);
texCoordSets[0] = tex;
}
} // End of setTextureCoordinates(Point3f[])
/**
* Sets the texture coordinates array for the specified set.
* No data copying is done - a reference to user data is used.
* @param texCoordSet The texture coordinate set for which these coordinates
* are being specified.
* @param texCoords Array of 4D texture coordinates.
* @throws IllegalArgumentException if texCoordSet
< 0 or
* texCoordSet >= texCoordSetCount
,
* or the texture coordinate parameters were not previously set by
* calling setTextureCoordinateParams(texCoordSetCount, 4)
.
*/
public void setTextureCoordinates(int texCoordSet, TexCoord4f texCoords[]) {
if (texCoordDim != 4)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo17"));
if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo18"));
texCoordSets[texCoordSet] = texCoords;
} // End of setTextureCoordinates(int, TexCoord4f[])
/**
* Sets the texture coordinates array by copying the data into the
* GeometryInfo object. The number of sets and dimensionality of
* the sets must have been set previously with
* setTextureCoordinateParams(texCoordSetCount, dim).
* @param texCoordSet The texture coordinate set for which these coordinates
* are being specified.
* @param texCoords The float array of texture coordinates. For n texture
* coordinates with dimensionality d, there must be d*n floats in the array.
* @throws IllegalArgumentException if texCoordSet
< 0 or
* texCoordSet >= texCoordSetCount
,
* or the texture coordinate parameters were not previously set by
* calling setTextureCoordinateParams
.
*/
public void setTextureCoordinates(int texCoordSet, float texCoords[])
{
if ((texCoords.length % texCoordDim) != 0)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo2"));
// Copy the texCoords into this GeometryInfo object
if (texCoordDim == 2) {
TexCoord2f tcoords[] = new TexCoord2f[texCoords.length / 2];
for (int i = 0 ; i < tcoords.length ; i++)
tcoords[i] = new TexCoord2f(texCoords[i * 2],
texCoords[i * 2 + 1]);
setTextureCoordinates(texCoordSet, tcoords);
} else if (texCoordDim == 3) {
TexCoord3f tcoords[] = new TexCoord3f[texCoords.length / 3];
for (int i = 0 ; i < tcoords.length ; i++)
tcoords[i] = new TexCoord3f(texCoords[i * 3],
texCoords[i * 3 + 1],
texCoords[i * 3 + 2]);
setTextureCoordinates(texCoordSet, tcoords);
} else if (texCoordDim == 4) {
TexCoord4f tcoords[] = new TexCoord4f[texCoords.length / 4];
for (int i = 0 ; i < tcoords.length ; i++)
tcoords[i] = new TexCoord4f(texCoords[i * 4],
texCoords[i * 4 + 1],
texCoords[i * 4 + 2],
texCoords[i * 4 + 3]);
setTextureCoordinates(texCoordSet, tcoords);
} else {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo21"));
}
} // End of setTextureCoordinates(int, float[])
/**
* Sets the texture coordinates array by copying the data
* into the GeometryInfo object, assuming two numbers
* (S and T) per vertex.
* This method sets the number of texture coordinate sets to 1,
* sets the dimensionality of the texture coordinates to 2,
* and sets the coordinates for texture coordinate set 0.
* @deprecated As of Java 3D 1.3 replaced by
* setTextureCoordinates(int texCoordSet, float texCoords[])
*/
public void setTextureCoordinates2(float texCoords[])
{
texCoordSetCount = 1;
texCoordDim = 2;
texCoordSets = new TexCoord2f[1][];
setTextureCoordinates(0, texCoords);
} // End of setTextureCoordinates2(float[])
/**
* Sets the TextureCoordinates array by copying the data
* into the GeometryInfo object, assuming three numbers
* (S, T, & R) per vertex.
* This method sets the number of texture coordinate sets to 1,
* sets the dimensionality of the texture coordinates to 3,
* and sets the coordinates for texture coordinate set 0.
* @deprecated As of Java 3D 1.3 replaced by
* setTextureCoordinates(int texCoordSet, float texCoords[])
*/
public void setTextureCoordinates3(float texCoords[])
{
texCoordSetCount = 1;
texCoordDim = 3;
texCoordSets = new TexCoord3f[1][];
setTextureCoordinates(0, texCoords);
} // End of setTextureCoordinates3(float[])
/**
* Returns a reference to the indicated texture coordinate array.
* The return type will be TexCoord2f[]
, TexCoord3f[]
*
, or TexCoord4f[]
depending on the
* current dimensionality of the texture coordinates in the GeometryInfo
* object. Use getNumTexCoordComponents()
to find out which
* version is returned.
* @param texCoordSet The index of the texture coordinate set to
* retrieve.
* @return An array of texture coordinates at the specified index
* @throws IllegalArgumentException If texCoordSet
< 0
* or texCoordSet >= texCoordSetCount
*/
public Object[] getTextureCoordinates(int texCoordSet)
{
if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo18"));
return texCoordSets[texCoordSet];
} // End of getTextureCoordinates(int)
/**
* Retrieves a reference to texture coordinate set 0.
* The return type will be TexCoord2f[]
, TexCoord3f[]
*
, or TexCoord4f[]
depending on the
* current dimensionality of the texture coordinates in the GeometryInfo
* object. Use getNumTexCoordComponents()
to find out which
* version is returned. Equivalent to getTextureCoordinates(0)
.
* @return An array of texture coordinates for set 0.
* @deprecated As of Java 3D 1.3 replaced by
* getTextureCoordinates(int texCoordSet)
*/
public Object[] getTextureCoordinates()
{
return texCoordSets[0];
} // End of getTextureCoordinates()
/**
* Sets the array of indices into the Coordinate array.
* No data copying is done - a reference to user data is used.
*/
public void setCoordinateIndices(int coordinateIndices[])
{
this.coordinateIndices = coordinateIndices;
} // End of setCoordinateIndices
/**
* Retrieves a reference to the array of indices into the
* coordinate array.
texCoordSet
< 0 or
* texCoordSet >= texCoordSetCount
.
*/
public void setTextureCoordinateIndices(int texCoordSet, int texIndices[])
{
if ((texCoordSet >= texCoordSetCount) || (texCoordSet < 0))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo18"));
// Texture coordinates are indexed
texCoordIndexSets[texCoordSet] = texIndices;
} // End of setTextureCoordinateIndices(int, int[])
/**
* Sets the array of indices into texture coordinate set 0. Do not
* call this method if you are using more than one set of texture
* coordinates.
* No data is copied - a reference to the user data is used.
* @deprecated As of Java 3D 1.3 replaced by
* setTextureCoordinateIndices(int texCoordSet, int indices[])
* @throws IllegalArgumentException If texCoordSetCount > 1
.
*/
public void setTextureCoordinateIndices(int texIndices[])
{
if (texCoordSetCount > 1)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo1"));
texCoordIndexSets = new int[1][];
texCoordIndexSets[0] = texIndices;
} // End of setTextureCoordinateIndices(int[])
/**
* Retrieves a reference to the specified array of texture
* coordinate indices.* * This method should be considered for advanced users only. * Novice users should just use getGeometryArray() to retrieve * their data so that the internal format of GeometryInfo is * of no concern.
* * Depending on which of the utility routines you've called * on your GeometryInfo object, the results may not be what you * expect. If you've called the Stripifier, your GeometryInfo * object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY * and your data will be formatted accordingly. Similarly, if * you've called the Triangulator, your data is in indexed * TRIANGLE_ARRAY format. Generating normals with the NormalGenerator * utility will convert your data to indexed TRIANGLE_ARRAY also, * but if you call getGeometryArray without calling the Stripifier or * Triangulator, your data will be converted back to the original * primitive type when creating the GeometryArray object to pass * back. However, if your creaseAngle was not Math.PI (no creases - * smooth shading), then the introduction of * creases into your model may have split primitives, lengthening * the StripCounts and index arrays from your original data. * @param texCoordSet The texture coordinate index set to be * retrieved. * @return Integer array of the texture coordinate indices for the specified * set. */ public int[] getTextureCoordinateIndices(int texCoordSet) { return texCoordIndexSets[texCoordSet]; } /** * Returns a reference to texture coordinate index set 0. * Equivalent to *getTextureCoordinateIndices(0)
.
* @deprecated As of Java 3D 1.3 replaced by
* int[] getTextureCoordinateIndices(int texCoordSet)
* @return Integer array of the texture coordinate indices for set 0
*/
public int[] getTextureCoordinateIndices()
{
if (texCoordIndexSets == null) return null;
return texCoordIndexSets[0];
} // End of getTextureCoordinateIndices()
/**
* Sets the array of strip counts. If index lists have been set for
* this GeomteryInfo object then the data is indexed and the stripCounts
* are like stripIndexCounts. If no index lists have been set then
* the data is non-indexed and the stripCounts are like
* stripVertexCounts.
* @see GeometryStripArray#GeometryStripArray(int, int,
* int[] stripVertexCounts)
* @see IndexedGeometryStripArray#IndexedGeometryStripArray(int, int, int,
* int[] stripIndexCounts)
*/
public void setStripCounts(int stripCounts[])
{
this.stripCounts = stripCounts;
} // End of setStripCounts
/**
* Retrieves a reference to the array of stripCounts.
*
* This method should be considered for advanced users only.
* Novice users should just use getGeometryArray() to retrieve
* their data so that the internal format of GeometryInfo is
* of no concern.
*
* Depending on which of the utility routines you've called
* on your GeometryInfo object, the results may not be what you
* expect. If you've called the Stripifier, your GeometryInfo
* object's Primitive has been changed to indexed TRIANGLE_STRIP_ARRAY
* and your data will be formatted accordingly. Similarly, if
* you've called the Triangulator, your data is in indexed
* TRIANGLE_ARRAY format. Generating normals with the NormalGenerator
* utility will convert your data to indexed TRIANGLE_ARRAY also,
* but if you call getGeometryArray without calling the Stripifier or
* Triangulator, your data will be converted back to the original
* primitive type when creating the GeometryArray object to pass
* back. However, if your creaseAngle was not Math.PI (no creases -
* smooth shading), then the introduction of
* creases into your model may have split primitives, lengthening
* the StripCounts and index arrays from your original data.
*/
public int[] getStripCounts()
{
return stripCounts;
} // End of getStripCounts
/**
* Sets the list of contour counts. Only used with the POLYGON_ARRAY
* primitive. Polygons can be made of several vertex lists
* called contours. The first list is the polygon, and
* subsequent lists are "holes" that are removed from the
* polygon. All of the holes must be contained entirely
* within the polygon.
*/
public void setContourCounts(int contourCounts[])
{
this.contourCounts = contourCounts;
} // End of setContourCounts
/**
* Retrieves a reference to the array of contourCounts.
*/
public int[] getContourCounts()
{
return contourCounts;
} // End of getContourCounts
/*
* This routine will return an index list for any array of objects.
*/
int[] getListIndices(Object list[])
{
// Create list of indices to return
int indices[] = new int[list.length];
// Create hash table with initial capacity equal to the number
// of components (assuming about half will be duplicates)
HashMap table = new HashMap(list.length);
Integer idx;
for (int i = 0 ; i < list.length ; i++) {
// Find index associated with this object
idx = (Integer)table.get(list[i]);
if (idx == null) {
// We haven't seen this object before
indices[i] = i;
// Put into hash table and remember the index
table.put(list[i], new Integer(i));
} else {
// We've seen this object
indices[i] = idx.intValue();
}
}
return indices;
} // End of getListIndices
// Class to hash 'size' integers
private class IndexRow {
int[] val;
int size;
private static final int HASHCONST = 0xBABEFACE;
@Override
public int hashCode()
{
int bits = 0;
for (int i = 0 ; i < size ; i++) {
bits ^= (bits * HASHCONST) << 2;
}
return bits;
} // End of IndexRow.hashCode
@Override
public boolean equals(Object obj)
{
for (int i = 0 ; i < size ; i++) {
if (((IndexRow)obj).get(i) != val[i]) return false;
}
return true;
} // End of IndexRow.equals()
public int get(int index)
{
return val[index];
} // End of IndexRow.get
public void set(int index, int value)
{
val[index] = value;
} // End of IndexRow.set
IndexRow(int numColumns)
{
size = numColumns;
val = new int[size];
} // End of IndexRow constructor
} // End of class IndexRow
/**
* Create index lists for all data lists.
* Identical data entries are guaranteed to
* use the same index value. Does not remove unused data values
* from the object - call compact() to do this.
* @param useCoordIndexOnly Reformat the data into the
* GeometryArray.USE_COORD_INDEX_ONLY format where there is only
* one index list. If the data is already in the USE_COORD_INDEX_ONLY
* format, sending false (or calling indexify()) will change
* it to the normal indexed format.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void indexify(boolean useCoordIndexOnly)
{
checkForBadData();
if (useCoordIndexOnly) {
// Return if already in this format
if (coordOnly) return;
// Start from normal indexed format
indexify(false);
// Reformat data to USE_COORD_INDEX_ONLY format
// Need to make an index into the index lists using each
// row of indexes as one value
// First, find out how many index lists there are;
int numLists = 1; // Always have coordinates
if (colorIndices != null) numLists++;
if (normalIndices != null) numLists++;
numLists += texCoordSetCount;
// Make single array containing all indices
int n = coordinateIndices.length;
IndexRow[] ir = new IndexRow[n];
int j;
for (int i = 0 ; i < n ; i++) {
ir[i] = new IndexRow(numLists);
j = 0;
ir[i].set(j++, coordinateIndices[i]);
if (colorIndices != null) ir[i].set(j++, colorIndices[i]);
if (normalIndices != null) ir[i].set(j++, normalIndices[i]);
for (int k = 0 ; k < texCoordSetCount ; k++) {
ir[i].set(j++, texCoordIndexSets[k][i]);
}
}
// Get index into that array
int[] coordOnlyIndices = getListIndices(ir);
// Get rid of duplicate rows
int newInd[] = new int[coordOnlyIndices.length];
ir = (IndexRow[])compactData(coordOnlyIndices, ir, newInd);
coordOnlyIndices = newInd;
// Reformat data lists to correspond to new index
// Allocate arrays to hold reformatted data
Point3f[] newCoords = new Point3f[ir.length];
Color3f[] newColors3 = null;
Color4f[] newColors4 = null;
Vector3f[] newNormals = null;
Object newTexCoordSets[][] = null;
if (colors3 != null) newColors3 = new Color3f[ir.length];
else if (colors4 != null) newColors4 = new Color4f[ir.length];
if (normals != null) newNormals = new Vector3f[ir.length];
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordDim == 2) {
if (i == 0) newTexCoordSets = new TexCoord2f[texCoordSetCount][];
newTexCoordSets[i] = new TexCoord2f[ir.length];
} else if (texCoordDim == 3) {
if (i == 0) newTexCoordSets = new TexCoord3f[texCoordSetCount][];
newTexCoordSets[i] = new TexCoord3f[ir.length];
} else if (texCoordDim == 4) {
if (i == 0) newTexCoordSets = new TexCoord4f[texCoordSetCount][];
newTexCoordSets[i] = new TexCoord4f[ir.length];
}
}
// Copy data into new arrays
n = ir.length;
for (int i = 0 ; i < n ; i++) {
j = 0;
newCoords[i] = coordinates[(ir[i]).get(j++)];
if (colors3 != null) {
newColors3[i] = colors3[(ir[i]).get(j++)];
} else if (colors4 != null) {
newColors4[i] = colors4[(ir[i]).get(j++)];
}
if (normals != null) newNormals[i] = normals[(ir[i]).get(j++)];
for (int k = 0 ; k < texCoordSetCount ; k++) {
newTexCoordSets[k][i] = texCoordSets[k][(ir[i]).get(j++)];
}
}
// Replace old arrays with new arrays
coordinates = newCoords;
colors3 = newColors3;
colors4 = newColors4;
normals = newNormals;
texCoordSets = newTexCoordSets;
coordinateIndices = coordOnlyIndices;
colorIndices = null;
normalIndices = null;
texCoordIndexSets = new int[texCoordSetCount][];
coordOnly = true;
} else if (coordOnly) {
// Need to change from useCoordIndexOnly format to normal
// indexed format. Should make a more efficient implementation
// later.
int n = coordinateIndices.length;
if ((colors3 != null) || (colors4 != null)) {
colorIndices = new int[n];
for (int i = 0 ; i < n ; i++) colorIndices[i] = coordinateIndices[i];
}
if (normals != null) {
normalIndices = new int[n];
for (int i = 0 ; i < n ; i++) normalIndices[i] = coordinateIndices[i];
}
texCoordIndexSets = new int[texCoordSetCount][];
for (int i = 0 ; i < texCoordSetCount ; i++) {
texCoordIndexSets[i] = new int[n];
for (int j = 0 ; j < n ; j++) {
texCoordIndexSets[i][j] = coordinateIndices[j];
}
}
coordOnly = false;
} else {
// No need to indexify if already indexed
if (coordinateIndices != null) return;
coordinateIndices = getListIndices(coordinates);
if (colors3 != null) colorIndices = getListIndices(colors3);
else if (colors4 != null) colorIndices = getListIndices(colors4);
if (normals != null) normalIndices = getListIndices(normals);
texCoordIndexSets = new int[texCoordSetCount][];
for(int i = 0 ; i < texCoordSetCount ; i++) {
texCoordIndexSets[i] = getListIndices(texCoordSets[i]);
}
coordOnly = false;
}
if ((DEBUG & 1) == 1) {
System.out.println("Coordinate Array:");
for (int i = 0 ; i < coordinates.length ; i++) {
System.out.println(" " + i + " " + coordinates[i] +
" " + coordinates[i].hashCode());
}
System.out.println("Index array:");
for (int i = 0 ; i < coordinateIndices.length ; i++) {
System.out.println(" " + i + " " + coordinateIndices[i]);
}
}
} // End of indexify
public void indexify()
{
indexify(false);
} // End of indexify()
/**
* Allocates an array of the same type as the input type. This allows us to
* use a generic compactData method.
*
* @param data Array of coordinate, color, normal or texture coordinate data
* The data can be in one of the following formats - Point3f, Color3f,
* Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
*
* @param num The size of the array to be allocated
*
* @return An array of size num of the same type as the input type
*
* @exception IllegalArgumentException if the input array is not one of the
* types listed above.
*/
Object[] allocateArray(Object data[], int num) {
Object newData[] = null;
if (data instanceof org.scijava.vecmath.Point3f[]) {
newData = new Point3f[num];
} else if (data instanceof org.scijava.vecmath.Vector3f[]) {
newData = new Vector3f[num];
} else if (data instanceof org.scijava.vecmath.Color3f[]) {
newData = new Color3f[num];
} else if (data instanceof org.scijava.vecmath.Color4f[]) {
newData = new Color4f[num];
} else if (data instanceof org.scijava.vecmath.TexCoord2f[]) {
newData = new TexCoord2f[num];
} else if (data instanceof org.scijava.vecmath.TexCoord3f[]) {
newData = new TexCoord3f[num];
} else if (data instanceof org.scijava.vecmath.TexCoord4f[]) {
newData = new TexCoord4f[num];
} else if (data instanceof IndexRow[]) {
// Hack so we can use compactData for coordIndexOnly
newData = new IndexRow[num];
} else throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo9"));
return newData;
} // End of allocateArray
/**
* Generic method that compacts (ie removes unreferenced/duplicate data)
* any type of indexed data.
* Used to compact coordinate, color, normal and texture coordinate data.
* @param indices Array of indices
* @param data Array of coordinate, color, normal or texture coordinate data
* The data can be in one of the following formats - Point3f, Color3f,
* Color4f, TexCoord2f, TexCoord3f, TexCoord4f.
* @param newInd The new array of indexes after the data has been compacted.
* This must be allocated by the calling method. On return, this array will
* contain the new index data. The size of this array must be equal to
* indices.length
* @return Array of the data with unreferenced and duplicate entries removed.
* The return type will be the same as the type that was passed in data.
*/
// TODO: Remove duplicate entries in data lists.
private Object[] compactData(int indices[], Object data[], int newInd[]) {
Object newData[] = null;
/*
* This is a three step process.
* First, find out how many unique indexes are used. This
* will be the size of the new data array.
*/
int numUnique = 0;
int translationTable[] = new int[data.length];
for (int i = 0 ; i < indices.length ; i++) {
if (translationTable[indices[i]] == 0) {
numUnique++;
translationTable[indices[i]] = 1;
}
}
/*
* Second, build the new data list. Remember the new indexes so
* we can use the table to translate the old indexes to the new
*/
newData = allocateArray(data, numUnique);
int newIdx = 0;
for (int i = 0 ; i < translationTable.length ; i++) {
if (translationTable[i] != 0) {
newData[newIdx] = data[i];
translationTable[i] = newIdx++;
}
}
/*
* Third, make the new index list
*/
for (int i = 0 ; i < indices.length ; i++) {
newInd[i] = translationTable[indices[i]];
}
return newData;
} // End of compactData
/**
* Remove unused data from an indexed dataset.
* Indexed data may contain data entries that are never referenced by
* the dataset. This routine will remove those entries where
* appropriate and renumber the indices to match the new values.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void compact()
{
checkForBadData();
// Only usable on indexed data
if (coordinateIndices == null) return;
// USE_COORD_INDEX_ONLY never has unused data
if (coordOnly) return;
int newInd[] = new int[coordinateIndices.length];
coordinates =
(Point3f[])compactData(coordinateIndices, coordinates, newInd);
coordinateIndices = newInd;
if (colorIndices != null) {
newInd = new int[colorIndices.length];
if (colors3 != null)
colors3 = (Color3f[])compactData(colorIndices, colors3, newInd);
else if (colors4 != null)
colors4 = (Color4f[])compactData(colorIndices, colors4, newInd);
colorIndices = newInd;
}
if (normalIndices != null) {
newInd = new int[normalIndices.length];
normals = (Vector3f[])compactData(normalIndices, normals, newInd);
normalIndices = newInd;
}
for (int i = 0 ; i < texCoordSetCount ; i++) {
newInd = new int[texCoordIndexSets[i].length];
texCoordSets[i] = compactData(texCoordIndexSets[i],
texCoordSets[i], newInd);
texCoordIndexSets[i] = newInd;
}
} // End of compact
/**
* Check the data to make sure everything's consistent.
*/
private void checkForBadData() {
boolean badData = false;
//
// Coordinates are required
//
if (coordinates == null) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo3"));
}
//
// Check for indices with no data
//
if ((colors3 == null) && (colors4 == null) && (colorIndices != null))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo4"));
if ((normals == null) && (normalIndices != null))
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo11"));
//
// Make sure all TextureCoordinate data is set (indices or not)
//
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordSets[i] == null)
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo10"));
}
//
// Check for Missing Index lists
//
boolean texInds = false; // Indicates whether we have texcoord indices
if (texCoordIndexSets != null) {
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordIndexSets[i] != null) texInds = true;
}
}
if ((coordinateIndices != null) ||
(colorIndices != null) ||
(normalIndices != null) ||
texInds) {
// At least one index list is present, so they all must be
// present (unless coordOnly)
if (coordinateIndices == null) badData = true;
else if (coordOnly) {
if ((colorIndices != null) ||
(normalIndices != null) ||
(texInds == true)) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo20"));
}
} else if (((colors3 != null) || (colors4 != null)) &&
(colorIndices == null)) badData = true;
else if ((normals != null) && (normalIndices == null)) badData = true;
else if ((texCoordSetCount > 0) && !texInds) badData = true;
if (badData) throw new
IllegalArgumentException(J3dUtilsI18N.getString("GeometryInfo19"));
}
//
// Make sure index lists are all the same length
//
if ((coordinateIndices != null) && (!coordOnly)) {
if (((colors3 != null) || (colors4 != null)) &&
(colorIndices.length != coordinateIndices.length))
badData = true;
else if ((normals != null) &&
(normalIndices.length != coordinateIndices.length))
badData = true;
else {
//Check all texCoord indices have the same length
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordIndexSets[i].length != coordinateIndices.length) {
badData = true;
break;
}
}
}
if (badData) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo5"));
}
}
//
// For stripped primitives, make sure we have strip counts
//
if ((prim == TRIANGLE_STRIP_ARRAY) ||
(prim == TRIANGLE_FAN_ARRAY) ||
(prim == POLYGON_ARRAY)) {
if (stripCounts == null) badData = true;
} else if (stripCounts != null) badData = true;
if (badData) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo6"));
}
// Find out how much data we have
int count;
if (coordinateIndices == null) count = coordinates.length;
else count = coordinateIndices.length;
//
// Make sure sum of strip counts equals indexCount (or vertexCount)
// and check to make sure triangles and quads have the right number
// of vertices
//
if ((prim == TRIANGLE_STRIP_ARRAY) ||
(prim == TRIANGLE_FAN_ARRAY) ||
(prim == POLYGON_ARRAY)) {
int sum = 0;
for (int i = 0 ; i < stripCounts.length ; i++) {
sum += stripCounts[i];
}
if (sum != count) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo7"));
}
} else if (prim == TRIANGLE_ARRAY) {
if (count % 3 != 0) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo12"));
}
} else if (prim == QUAD_ARRAY) {
if (count % 4 != 0) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo13"));
}
}
//
// For polygons, make sure the contours add up.
//
if (prim == POLYGON_ARRAY) {
if (contourCounts != null) {
int c = 0;
for (int i = 0 ; i < contourCounts.length ; i++)
c += contourCounts[i];
if (c != stripCounts.length) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo8"));
}
}
} else {
if (contourCounts != null) {
throw new IllegalArgumentException(
J3dUtilsI18N.getString("GeometryInfo14"));
}
}
} // End of checkForBadData
/**
* Get rid of index lists by reorganizing data into an un-indexed
* format. Does nothing if no index lists are set.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void unindexify() {
checkForBadData();
if (coordinateIndices != null) {
// Switch from USE_COORD_INDEX_ONLY format
if (coordOnly) indexify(false);
coordinates =
(Point3f[])unindexifyData(coordinates, coordinateIndices);
coordinateIndices = null;
if (colors3 != null) {
colors3 = (Color3f[])unindexifyData(colors3, colorIndices);
} else if (colors4 != null) {
colors4 = (Color4f[])unindexifyData(colors4, colorIndices);
}
colorIndices = null;
if (normals != null) {
normals = (Vector3f[])unindexifyData(normals, normalIndices);
normalIndices = null;
}
for (int i = 0 ; i < texCoordSetCount ; i++)
texCoordSets[i] = unindexifyData(texCoordSets[i],
texCoordIndexSets[i]);
texCoordIndexSets = new int[texCoordSetCount][];
}
} // End of unindexify
/**
* Generic unindexify method. Can unindex data in any of the following
* formats Point3f, Color3f, Color4f, Vector3f, TexCoord2f, TexCoord3f,
* TexCoord4f.
*/
private Object[] unindexifyData(Object data[], int index[])
{
Object newData[] = allocateArray(data, index.length);
for (int i = 0 ; i < index.length ; i++) {
newData[i] = data[index[i]];
}
return newData;
} // End of unindexifyData
/**
* Calculate vertexFormat based on data.
*/
private int getVertexFormat()
{
int vertexFormat = GeometryArray.COORDINATES;
if (colors3 != null) vertexFormat |= GeometryArray.COLOR_3;
else if (colors4 != null) vertexFormat |= GeometryArray.COLOR_4;
if (normals != null) vertexFormat |= GeometryArray.NORMALS;
if (texCoordDim == 2)
vertexFormat |= GeometryArray.TEXTURE_COORDINATE_2;
else if (texCoordDim == 3)
vertexFormat |= GeometryArray.TEXTURE_COORDINATE_3;
else if (texCoordDim == 4)
vertexFormat |= GeometryArray.TEXTURE_COORDINATE_4;
return vertexFormat;
} // End of getVertexFormat
/**
* Calculate vertexCount based on data
*/
private int getVertexCount()
{
int vertexCount = coordinates.length;
if (colors3 != null) {
if (colors3.length > vertexCount) vertexCount = colors3.length;
} else if (colors4 != null) {
if (colors4.length > vertexCount) vertexCount = colors4.length;
}
if (normals != null) {
if (normals.length > vertexCount) vertexCount = normals.length;
}
// Find max length tex coord set
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordSets[i].length > vertexCount)
vertexCount = texCoordSets[i].length;
}
return vertexCount;
} // End of getVertexCount
/**
* Converts an array of Tuple2f, Tuple3f, or Tuple4f values into
* an array of floats. Assumes array is not null. Returns null
* if array is not Tuple2f, Tuple3f, or Tuple4f. Used by fillIn()
* for BY_REFERENCE not INTERLEAVED geometry.
*/
private float[] vecmathToFloat(Object[] ar)
{
if (ar[0] instanceof Tuple2f) {
float[] p = new float[ar.length * 2];
Tuple2f[] a = (Tuple2f[])ar;
for (int i = 0 ; i < ar.length ; i++) {
p[i * 2] = a[i].x;
p[i * 2 + 1] = a[i].y;
}
return p;
} else if (ar[0] instanceof Tuple3f) {
float[] p = new float[ar.length * 3];
Tuple3f[] a = (Tuple3f[])ar;
for (int i = 0 ; i < ar.length ; i++) {
p[i * 3] = a[i].x;
p[i * 3 + 1] = a[i].y;
p[i * 3 + 2] = a[i].z;
}
return p;
} else if (ar[0] instanceof Tuple4f) {
float[] p = new float[ar.length * 4];
Tuple4f[] a = (Tuple4f[])ar;
for (int i = 0 ; i < ar.length ; i++) {
p[i * 4] = a[i].x;
p[i * 4 + 1] = a[i].y;
p[i * 4 + 2] = a[i].z;
p[i * 4 + 3] = a[i].w;
}
return p;
}
return null;
} // End of vecmathToFloat
/**
* Fill in the GeometryArray object. Used by getGeometryArray and
* getIndexedGeometryArray. checkForBadData has already been called.
*/
private void fillIn(GeometryArray ga, boolean byRef, boolean interleaved,
boolean nio)
{
if (interleaved) {
// Calculate number of words per vertex
int wpv = 3; // Always have coordinate data
if (normals != null) wpv += 3;
if (colors3 != null) wpv += 3;
else if (colors4 != null) wpv += 4;
wpv += (texCoordSetCount * texCoordDim);
// Build array of interleaved data
float[] d = new float[wpv * coordinates.length];
// Fill in the array
int offset = 0;
for (int i = 0 ; i < coordinates.length ; i++) {
if (texCoordDim == 2) {
for (int j = 0 ; j < texCoordSetCount ; j++) {
d[offset++] = ((TexCoord2f)texCoordSets[j][i]).x;
d[offset++] = ((TexCoord2f)texCoordSets[j][i]).y;
}
} else if (texCoordDim == 3) {
for (int j = 0 ; j < texCoordSetCount ; j++) {
d[offset++] = ((TexCoord3f)texCoordSets[j][i]).x;
d[offset++] = ((TexCoord3f)texCoordSets[j][i]).y;
d[offset++] = ((TexCoord3f)texCoordSets[j][i]).z;
}
} else if (texCoordDim == 4) {
for (int j = 0 ; j < texCoordSetCount ; j++) {
d[offset++] = ((TexCoord4f)texCoordSets[j][i]).x;
d[offset++] = ((TexCoord4f)texCoordSets[j][i]).y;
d[offset++] = ((TexCoord4f)texCoordSets[j][i]).z;
d[offset++] = ((TexCoord4f)texCoordSets[j][i]).w;
}
}
if (colors3 != null) {
d[offset++] = colors3[i].x;
d[offset++] = colors3[i].y;
d[offset++] = colors3[i].z;
} else if (colors4 != null) {
d[offset++] = colors4[i].x;
d[offset++] = colors4[i].y;
d[offset++] = colors4[i].z;
d[offset++] = colors4[i].w;
}
if (normals != null) {
d[offset++] = normals[i].x;
d[offset++] = normals[i].y;
d[offset++] = normals[i].z;
}
d[offset++] = coordinates[i].x;
d[offset++] = coordinates[i].y;
d[offset++] = coordinates[i].z;
}
// Register reference to array of interleaved data
if (nio) {
ByteBuffer b = ByteBuffer.allocateDirect(d.length * 4);
FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(d);
ga.setInterleavedVertexBuffer(new J3DBuffer(f));
} else ga.setInterleavedVertices(d);
} else if (nio) {
ByteBuffer b = ByteBuffer.allocateDirect(coordinates.length * 4 * 3);
FloatBuffer f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(vecmathToFloat(coordinates));
ga.setCoordRefBuffer(new J3DBuffer(f));
if (colors3 != null) {
b = ByteBuffer.allocateDirect(colors3.length * 4 * 3);
f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(vecmathToFloat(colors3));
ga.setColorRefBuffer(new J3DBuffer(f));
} else if (colors4 != null) {
b = ByteBuffer.allocateDirect(colors4.length * 4 * 4);
f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(vecmathToFloat(colors4));
ga.setColorRefBuffer(new J3DBuffer(f));
}
if (normals != null) {
b = ByteBuffer.allocateDirect(normals.length * 4 * 3);
f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(vecmathToFloat(normals));
ga.setNormalRefBuffer(new J3DBuffer(f));
}
for (int i = 0 ; i < texCoordSetCount ; i++) {
b = ByteBuffer.allocateDirect(texCoordSets[i].length * 4 * texCoordDim);
f = b.order(ByteOrder.nativeOrder()).asFloatBuffer();
f.put(vecmathToFloat(texCoordSets[i]));
ga.setTexCoordRefBuffer(i, new J3DBuffer(f));
}
} else if (byRef) {
// Need to copy the data into float arrays - GeometryArray
// prefers them over the vecmath types
ga.setCoordRefFloat(vecmathToFloat(coordinates));
if (colors3 != null) ga.setColorRefFloat(vecmathToFloat(colors3));
else if (colors4 != null) ga.setColorRefFloat(vecmathToFloat(colors4));
if (normals != null) ga.setNormalRefFloat(vecmathToFloat(normals));
for (int i = 0 ; i < texCoordSetCount ; i++) {
ga.setTexCoordRefFloat(i, vecmathToFloat(texCoordSets[i]));
}
} else {
ga.setCoordinates(0, coordinates);
if (colors3 != null) ga.setColors(0, colors3);
else if (colors4 != null) ga.setColors(0, colors4);
if (normals != null) ga.setNormals(0, normals);
for (int i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordDim == 2) {
ga.setTextureCoordinates(i, 0, (TexCoord2f[])texCoordSets[i]);
} else if (texCoordDim == 3) {
ga.setTextureCoordinates(i, 0, (TexCoord3f[])texCoordSets[i]);
} else if (texCoordDim == 4) {
ga.setTextureCoordinates(i, 0, (TexCoord4f[])texCoordSets[i]);
}
}
}
if (coordinateIndices != null) {
IndexedGeometryArray iga = null;
iga = (IndexedGeometryArray)ga;
iga.setCoordinateIndices(0, coordinateIndices);
if (!coordOnly) {
if (colorIndices != null) iga.setColorIndices(0, colorIndices);
if (normalIndices != null) iga.setNormalIndices(0, normalIndices);
for (int i = 0 ; i < texCoordSetCount ; i++)
iga.setTextureCoordinateIndices(i, 0, texCoordIndexSets[i]);
}
}
} // End of fillIn
/**
* Redo indexes to guarantee connection information.
* Use this routine if your original data is in indexed format, but
* you don't trust that the indexing is correct. After this
* routine it is guaranteed that two points with the same
* position will have the same coordinate index (for example).
* Try this if you see
* glitches in your normals or stripification, to rule out
* bad indexing as the source of the problem. Works with normal
* indexed format or USE_COORD_INDEX_ONLY format.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void recomputeIndices()
{
boolean remember = coordOnly;
// Can make more efficient implementation later
unindexify();
indexify(remember);
} // End of recomputeIndices
/**
* Reverse the order of an array of ints (computer class homework
* problem).
*/
private void reverseList(int list[])
{
int t;
if (list == null) return;
for (int i = 0 ; i < list.length / 2 ; i++) {
t = list[i];
list[i] = list[list.length - i - 1];
list[list.length - i - 1] = t;
}
} // End of reverseList
/**
* Reverse the order of all lists. If your polygons are formatted with
* clockwise winding, you will always see the back and never the front.
* (Java 3D always wants vertices specified with a counter-clockwise
* winding.)
* This method will (in effect) reverse the winding of your data by
* inverting all of the index lists and the stripCounts
* and contourCounts lists.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public void reverse()
{
indexify();
reverseList(stripCounts);
reverseList(oldStripCounts);
reverseList(contourCounts);
reverseList(coordinateIndices);
reverseList(colorIndices);
reverseList(normalIndices);
for (int i = 0 ; i < texCoordSetCount ; i++)
reverseList(texCoordIndexSets[i]);
} // End of reverse
/**
* Returns true if the data in this GeometryInfo is currently
* formatted in the USE_COORD_INDEX_ONLY format where a single
* index list is used to index into all data lists.
* @see GeometryInfo#indexify(boolean)
* @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
* boolean, boolean)
*/
public boolean getUseCoordIndexOnly()
{
return coordOnly;
} // End of getUseCoordIndexOnly
/**
* Tells the GeometryInfo that its data is formatted in the
* USE_COORD_INDEX_ONLY format with a single index list
* (the coordinate index list) that indexes into all data
* lists (coordinates, normals, colors, and texture
* coordinates). NOTE: this will not convert the data
* for you. This method is for when you are sending in
* data useng the setCoordinates, setNormals, setColors,
* and/or setTextureCoordinates methods, and you are only
* setting one index using setCoordinateIndices(). If
* you want GeometryInfo to convert your data to the
* USE_COORD_INDEX_ONLY format, use indexify(true) or
* getIndexedGeometryArray with the useCoordIndexOnly
* parameter set to true.
* @see GeometryInfo#indexify(boolean)
* @see GeometryInfo#getIndexedGeometryArray(boolean, boolean, boolean,
* boolean, boolean)
*/
public void setUseCoordIndexOnly(boolean useCoordIndexOnly)
{
coordOnly = useCoordIndexOnly;
} // End of setUseCoordIndexOnly
/**
* Creates and returns a non-indexed Java 3D GeometryArray object
* based on the data in the GeometryInfo object. This object is
* suitable to be attached to a Shape3D node for rendering.
* @param byRef Use geometry BY_REFERENCE
* @param interleaved Use INTERLEAVED geometry. Implies byRef is
* true as well.
* @param nio Create GeometryArray using java.nio.Buffer for
* geometry arrays. Only usable on JDK 1.4 or higher. Implies
* byRef is true as well.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public GeometryArray getGeometryArray(boolean byRef, boolean interleaved,
boolean nio)
{
checkForBadData();
if (prim == POLYGON_ARRAY) {
if (tr == null) tr = new Triangulator();
tr.triangulate(this);
} else changeBackToOldPrim();
unindexify();
int vertexFormat = getVertexFormat();
if (nio) vertexFormat |= (GeometryArray.BY_REFERENCE |
GeometryArray.USE_NIO_BUFFER);
if (interleaved) vertexFormat |= (GeometryArray.BY_REFERENCE |
GeometryArray.INTERLEAVED);
if (byRef) vertexFormat |= GeometryArray.BY_REFERENCE;
int vertexCount = coordinates.length;
// If the texCoordSetMap hasn't been set, assume one set of
// texture coordinates only and one texture state unit
if ((texCoordSetCount > 0) && (texCoordSetMap == null)) {
texCoordSetCount = 1;
texCoordSetMap = new int[1];
texCoordSetMap[0] = 0;
}
// Create the GeometryArray object
GeometryArray ga = null;
switch (prim) {
case TRIANGLE_ARRAY:
TriangleArray ta = new TriangleArray(vertexCount, vertexFormat,
texCoordSetCount, texCoordSetMap);
ga = (GeometryArray)ta;
break;
case QUAD_ARRAY:
QuadArray qa = new QuadArray(vertexCount, vertexFormat,
texCoordSetCount, texCoordSetMap);
ga = (GeometryArray)qa;
break;
case TRIANGLE_STRIP_ARRAY:
TriangleStripArray tsa = new TriangleStripArray(vertexCount,
vertexFormat, texCoordSetCount, texCoordSetMap,
stripCounts);
ga = (GeometryArray)tsa;
break;
case TRIANGLE_FAN_ARRAY:
TriangleFanArray tfa = new TriangleFanArray(vertexCount,
vertexFormat, texCoordSetCount, texCoordSetMap,
stripCounts);
ga = (GeometryArray)tfa;
break;
}
fillIn(ga, byRef, interleaved, nio);
return ga;
} // End of getGeometryArray(int, int)
/**
* Creates and returns a non-indexed Java 3D GeometryArray object
* based on the data in the GeometryInfo object. This object is
* suitable to be attached to a Shape3D node for rendering.
* The geometry is not created using data BY_REFERENCE,
* INTERLEAVED, or USE_NIO_BUFFER.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public GeometryArray getGeometryArray()
{
return getGeometryArray(false, false, false);
} // End of getGeometryArray()
/**
* Creates and returns a IndexedGeometryArray
* based on the data in the GeometryInfo object. This object is
* suitable to be attached to a Shape3D node for rendering.
* @param compact Remove Coordinates, Colors, Normals, and
* TextureCoordinates that aren't referenced by any indices.
* @param byRef Create the IndexedGeometryArray using geometry
* BY_REFERENCE.
* @param interleaved Use INTERLEAVED geometry. Implies byRef is
* true as well.
* @param useCoordIndexOnly Create the IndexedGeometryArray using
* USE_COORD_INDEX_ONLY. Values from the coordinate index array
* are used as a single set of indices into all vertex
* component arrays (coord, color, normal, and texCoord).
* @param nio Create GeometryArray using java.nio.Buffer for
* geometry arrays. Only usable on JDK 1.4 or higher. Implies
* byRef is true as well.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public IndexedGeometryArray getIndexedGeometryArray(boolean compact,
boolean byRef,
boolean interleaved,
boolean useCoordIndexOnly,
boolean nio)
{
indexify(useCoordIndexOnly);
if (compact) compact();
if (prim == POLYGON_ARRAY) {
if (tr == null) tr = new Triangulator();
tr.triangulate(this);
} else changeBackToOldPrim();
if (useCoordIndexOnly && coordOnly == false) {
// Check to see if we can optimize for USE_COORD_INDEX_ONLY
int i, j;
boolean canUseCoordIndexOnly = true;
if (coordinateIndices != null) {
// See if all the array lengths are the same
if (colorIndices != null &&
colorIndices.length != coordinateIndices.length) {
canUseCoordIndexOnly = false;
}
if (normalIndices != null &&
normalIndices.length != coordinateIndices.length) {
canUseCoordIndexOnly = false;
}
for (i = 0 ; i < texCoordSetCount ; i++) {
if (texCoordIndexSets[i] != null &&
texCoordIndexSets[i].length != coordinateIndices.length) {
canUseCoordIndexOnly = false;
break;
}
}
if (canUseCoordIndexOnly &&
((colorIndices != null) ||
(normalIndices != null) ||
(texCoordSetCount > 0))) {
// All array lengths are the same. Check their contents
for (i=0; igetIndexedGeometryArray(compact, false,
* false, false, false)
.
* @param compact Remove Coordinates, Colors, Normals, and
* TextureCoordinates that aren't referenced by any indices.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public IndexedGeometryArray getIndexedGeometryArray(boolean compact)
{
return getIndexedGeometryArray(compact, false, false, false, false);
} // End of getIndexedGeometryArray(boolean)
/**
* Creates and returns an IndexedGeometryArray
* based on the data in the GeometryInfo object. This object is
* suitable to be attached to a Shape3D node for rendering.
* Equivalent to getIndexedGeometryArray(false, false,
* false, false, false)
.
* @throws IllegalArgumentException if coordinate data is missing,
* if the index lists aren't all the
* same length, if an index list is set and the corresponding data
* list isn't set, if a data list is set and the corresponding
* index list is unset (unless all index lists are unset or in
* USE_COORD_INDEX_ONLY format),
* if StripCounts or ContourCounts is inconsistent with the current
* primitive, if the sum of the contourCounts array doesn't equal
* the length of the StripCounts array, or if the number of vertices
* isn't a multiple of three (for triangles) or four (for quads).
*/
public IndexedGeometryArray getIndexedGeometryArray()
{
return getIndexedGeometryArray(false, false, false, false, false);
} // End of getIndexedGeometryArray()
} // End of class GeometryInfo
// End of file GeometryInfo.java