aboutsummaryrefslogtreecommitdiffstats
path: root/src/javax/media/j3d/GeneralizedStrip.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/javax/media/j3d/GeneralizedStrip.java')
-rw-r--r--src/javax/media/j3d/GeneralizedStrip.java889
1 files changed, 889 insertions, 0 deletions
diff --git a/src/javax/media/j3d/GeneralizedStrip.java b/src/javax/media/j3d/GeneralizedStrip.java
new file mode 100644
index 0000000..baddedf
--- /dev/null
+++ b/src/javax/media/j3d/GeneralizedStrip.java
@@ -0,0 +1,889 @@
+/*
+ * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package javax.media.j3d;
+
+
+/**
+ * This class provides static methods to support topological
+ * transformations on generalized strips. This is used by the
+ * GeometryDecompressor. These methods only need to look at the
+ * vertex replacement flags to determine how the vertices in the strip
+ * are connected. The connections are rearranged in different ways to
+ * transform generalized strips to GeometryArray representations.
+ *
+ * @see GeneralizedStripFlags
+ * @see GeneralizedVertexList
+ * @see GeometryDecompressor
+ */
+class GeneralizedStrip {
+ private static final boolean debug = false ;
+
+ // Private convenience copies of various constants.
+ private static final int CW =
+ GeneralizedStripFlags.FRONTFACE_CW ;
+ private static final int CCW =
+ GeneralizedStripFlags.FRONTFACE_CCW ;
+ private static final int RESTART_CW =
+ GeneralizedStripFlags.RESTART_CW ;
+ private static final int RESTART_CCW =
+ GeneralizedStripFlags.RESTART_CCW ;
+ private static final int REPLACE_MIDDLE =
+ GeneralizedStripFlags.REPLACE_MIDDLE ;
+ private static final int REPLACE_OLDEST =
+ GeneralizedStripFlags.REPLACE_OLDEST ;
+
+ /**
+ * The IntList is like an ArrayList, but avoids the Integer
+ * object wrapper and accessor overhead for simple lists of ints.
+ */
+ static class IntList {
+ /**
+ * The array of ints.
+ */
+ int ints[] ;
+
+ /**
+ * The number of ints in this instance.
+ */
+ int count ;
+
+ /**
+ * Construct a new empty IntList of the given initial size.
+ * @param initialSize initial size of the backing array
+ */
+ IntList(int initialSize) {
+ ints = new int[initialSize] ;
+ count = 0 ;
+ }
+
+ /**
+ * Constructs an IntList with the given contents.
+ * @param ints the array of ints to use as the contents
+ */
+ IntList(int ints[]) {
+ this.ints = ints ;
+ this.count = ints.length ;
+ }
+
+ /**
+ * Add a new int to the end of this list.
+ * @param i the int to be appended to this list
+ */
+ void add(int i) {
+ if (count == ints.length) {
+ int newints[] = new int[2*count] ;
+ System.arraycopy(ints, 0, newints, 0, count) ;
+ ints = newints ;
+ if (debug)
+ System.err.println
+ ("GeneralizedStrip.IntList: reallocated " +
+ (2*count) + " ints") ;
+ }
+ ints[count++] = i ;
+ }
+
+ /**
+ * Trim the backing array to the current count and return the
+ * resulting backing array.
+ */
+ int[] trim() {
+ if (count != ints.length) {
+ int newints[] = new int[count] ;
+ System.arraycopy(ints, 0, newints, 0, count) ;
+ ints = newints ;
+ }
+ return ints ;
+ }
+
+ /**
+ * Fill the list with consecutive integers starting from 0.
+ */
+ void fillAscending() {
+ for (int i = 0 ; i < ints.length ; i++)
+ ints[i] = i ;
+
+ count = ints.length ;
+ }
+
+ @Override
+ public String toString() {
+ String s = new String("[") ;
+ for (int i = 0 ; i < count-1 ; i++)
+ s = s + Integer.toString(ints[i]) + ", " ;
+ return s + Integer.toString(ints[count-1]) + "]" ;
+ }
+ }
+
+ /**
+ * The StripArray class is used as the output of some conversion methods
+ * in the GeneralizedStrip class.
+ */
+ static class StripArray {
+ /**
+ * A list of indices into the vertices of the original generalized
+ * strip. It specifies the order in which vertices in the original
+ * strip should be followed to build GeometryArray objects.
+ */
+ IntList vertices ;
+
+ /**
+ * A list of strip counts.
+ */
+ IntList stripCounts ;
+
+ /**
+ * Creates a StripArray with the specified vertices and stripCounts.
+ * @param vertices IntList containing vertex indicies.
+ * @param stripCounts IntList containing strip lengths.
+ */
+ StripArray(IntList vertices, IntList stripCounts) {
+ this.vertices = vertices ;
+ this.stripCounts = stripCounts ;
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a 2-element array of
+ * StripArray objects. The first StripArray will contain triangle strips
+ * and the second will contain triangle fans.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return a 2-element array containing strips in 0 and fans in 1
+ */
+ static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices,
+ int frontFace) {
+
+ int size = vertices.getFlagCount() ;
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(size*3) ;
+ IntList fanVerts = new IntList(size*3) ;
+ IntList stripCounts = new IntList(size) ;
+ IntList fanCounts = new IntList(size) ;
+
+ toStripsAndFans(vertices, frontFace,
+ stripVerts, stripCounts, fanVerts, fanCounts) ;
+
+ // Construct the StripArray output.
+ StripArray sa[] = new StripArray[2] ;
+
+ if (stripCounts.count > 0)
+ sa[0] = new StripArray(stripVerts, stripCounts) ;
+
+ if (fanCounts.count > 0)
+ sa[1] = new StripArray(fanVerts, fanCounts) ;
+
+ return sa ;
+ }
+
+ private static void toStripsAndFans(GeneralizedStripFlags vertices,
+ int frontFace,
+ IntList stripVerts,
+ IntList stripCounts,
+ IntList fanVerts,
+ IntList fanCounts) {
+ int newFlag, curFlag, winding ;
+ int v, size, stripStart, stripLength ;
+ boolean transition = false ;
+
+ stripStart = 0 ;
+ stripLength = 3 ;
+ curFlag = vertices.getFlag(0) ;
+ winding = (curFlag == RESTART_CW ? CW : CCW) ;
+ size = vertices.getFlagCount() ;
+
+ // Vertex replace flags for the first 3 vertices are irrelevant since
+ // they can only define a single triangle. The first meaningful
+ // replace flag starts at the 4th vertex.
+ v = 3 ;
+ if (v < size)
+ curFlag = vertices.getFlag(v) ;
+
+ while (v < size) {
+ newFlag = vertices.getFlag(v) ;
+
+ if ((newFlag == curFlag) &&
+ (newFlag != RESTART_CW) && (newFlag != RESTART_CCW)) {
+ // The last flag was the same as this one, and it wasn't a
+ // restart: proceed to the next vertex.
+ stripLength++ ;
+ v++ ;
+
+ } else {
+ // Either this vertex flag changed from the last one, or
+ // the flag explicitly specifies a restart: process the
+ // last strip and start up a new one.
+ if (curFlag == REPLACE_MIDDLE)
+ addFan(fanVerts, fanCounts, stripStart, stripLength,
+ frontFace, winding, transition) ;
+ else
+ addStrip(stripVerts, stripCounts, stripStart, stripLength,
+ frontFace, winding) ;
+
+ // Restart: skip to the 4th vertex of the new strip.
+ if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) {
+ winding = (newFlag == RESTART_CW ? CW : CCW) ;
+ stripStart = v ;
+ stripLength = 3 ;
+ v += 3 ;
+ transition = false ;
+ if (v < size)
+ curFlag = vertices.getFlag(v) ;
+ }
+ // Strip/fan transition: decrement start of strip.
+ else {
+ if (newFlag == REPLACE_OLDEST) {
+ // Flip winding order when transitioning from fans
+ // to strips.
+ winding = (winding == CW ? CCW : CW) ;
+ stripStart = v-2 ;
+ stripLength = 3 ;
+ } else {
+ // Flip winding order when transitioning from
+ // strips to fans only if the preceding strip has
+ // an even number of vertices.
+ if ((stripLength & 0x01) == 0)
+ winding = (winding == CW ? CCW : CW) ;
+ stripStart = v-3 ;
+ stripLength = 4 ;
+ }
+ v++ ;
+ transition = true ;
+ curFlag = newFlag ;
+ }
+ }
+ }
+
+ // Finish off the last strip or fan.
+ // If v > size then the strip is degenerate.
+ if (v == size)
+ if (curFlag == REPLACE_MIDDLE)
+ addFan(fanVerts, fanCounts, stripStart, stripLength,
+ frontFace, winding, transition) ;
+ else
+ addStrip(stripVerts, stripCounts, stripStart, stripLength,
+ frontFace, winding) ;
+ else
+ throw new IllegalArgumentException
+ (J3dI18N.getString("GeneralizedStrip0")) ;
+
+ if (debug) {
+ System.err.println("GeneralizedStrip.toStripsAndFans") ;
+ if (v > size)
+ System.err.println(" ended with a degenerate triangle:" +
+ " number of vertices: " + (v-size)) ;
+
+ System.err.println("\n number of strips: " + stripCounts.count) ;
+ if (stripCounts.count > 0) {
+ System.err.println(" number of vertices: " + stripVerts.count) ;
+ System.err.println(" vertices/strip: " +
+ (float)stripVerts.count/stripCounts.count) ;
+ System.err.println(" strip counts: " + stripCounts.toString()) ;
+ // System.err.println(" indices: " + stripVerts.toString()) ;
+ }
+
+ System.err.println("\n number of fans: " + fanCounts.count) ;
+ if (fanCounts.count > 0) {
+ System.err.println(" number of vertices: " + fanVerts.count) ;
+ System.err.println(" vertices/strip: " +
+ (float)fanVerts.count/fanCounts.count) ;
+ System.err.println(" fan counts: " + fanCounts.toString()) ;
+ // System.err.println(" indices: " + fanVerts.toString()) ;
+ }
+ System.err.println("\n total vertices: " +
+ (stripVerts.count + fanVerts.count) +
+ "\n original number of vertices: " + size +
+ "\n") ;
+ }
+ }
+
+ //
+ // Java 3D specifies that the vertices of front-facing polygons
+ // have counter-clockwise (CCW) winding order when projected to
+ // the view surface. Polygons with clockwise (CW) vertex winding
+ // will be culled as back-facing by default.
+ //
+ // Generalized triangle strips can flip the orientation of their
+ // triangles with the RESTART_CW and RESTART_CCW vertex flags.
+ // Strips flagged with an orientation opposite to what has been
+ // specified as front-facing must have their windings reversed in
+ // order to have the correct face orientation when represented as
+ // GeometryArray objects.
+ //
+ private static void addStrip(IntList stripVerts,
+ IntList stripCounts,
+ int start, int length,
+ int frontFace, int winding) {
+ int vindex = start ;
+
+ if (winding == frontFace) {
+ // Maintain original order.
+ stripCounts.add(length) ;
+ while (vindex < start + length) {
+ stripVerts.add(vindex++) ;
+ }
+ } else if ((length & 0x1) == 1) {
+ // Reverse winding order if number of vertices is odd.
+ stripCounts.add(length) ;
+ vindex += length-1 ;
+ while (vindex >= start) {
+ stripVerts.add(vindex--) ;
+ }
+ } else if (length == 4) {
+ // Swap middle vertices.
+ stripCounts.add(4) ;
+ stripVerts.add(vindex) ;
+ stripVerts.add(vindex+2) ;
+ stripVerts.add(vindex+1) ;
+ stripVerts.add(vindex+3) ;
+ } else {
+ // Make the 1st triangle a singleton with reverse winding.
+ stripCounts.add(3) ;
+ stripVerts.add(vindex) ;
+ stripVerts.add(vindex+2) ;
+ stripVerts.add(vindex+1) ;
+ if (length > 3) {
+ // Copy the rest of the vertices in original order.
+ vindex++ ;
+ stripCounts.add(length-1) ;
+ while (vindex < start + length) {
+ stripVerts.add(vindex++) ;
+ }
+ }
+ }
+ }
+
+ private static void addFan(IntList fanVerts,
+ IntList fanCounts,
+ int start, int length,
+ int frontFace, int winding,
+ boolean transition) {
+ int vindex = start ;
+ fanVerts.add(vindex++) ;
+
+ if (winding == frontFace) {
+ if (transition) {
+ // Skip 1st triangle if this is the result of a transition.
+ fanCounts.add(length-1) ;
+ vindex++ ;
+ } else {
+ fanCounts.add(length) ;
+ fanVerts.add(vindex++) ;
+ }
+ while (vindex < start + length) {
+ fanVerts.add(vindex++) ;
+ }
+ } else {
+ // Reverse winding order.
+ vindex += length-2 ;
+ while (vindex > start+1) {
+ fanVerts.add(vindex--) ;
+ }
+ if (transition) {
+ // Skip 1st triangle if this is the result of a transition.
+ fanCounts.add(length-1) ;
+ } else {
+ fanCounts.add(length) ;
+ fanVerts.add(vindex) ;
+ }
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a StripArray containing
+ * exclusively strips.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return a StripArray containing the converted strips
+ */
+ static StripArray toTriangleStrips(GeneralizedStripFlags vertices,
+ int frontFace) {
+
+ int size = vertices.getFlagCount() ;
+
+ // initialize lists to worst-case sizes.
+ IntList stripVerts = new IntList(size*3) ;
+ IntList fanVerts = new IntList(size*3) ;
+ IntList stripCounts = new IntList(size) ;
+ IntList fanCounts = new IntList(size) ;
+
+ toStripsAndFans(vertices, frontFace,
+ stripVerts, stripCounts, fanVerts, fanCounts) ;
+
+ if (fanCounts.count == 0)
+ if (stripCounts.count > 0)
+ return new StripArray(stripVerts, stripCounts) ;
+ else
+ return null ;
+
+ // convert each fan to one or more strips
+ int i, v = 0 ;
+ for (i = 0 ; i < fanCounts.count ; i++) {
+ fanToStrips(v, fanCounts.ints[i], fanVerts.ints,
+ stripVerts, stripCounts, false) ;
+ v += fanCounts.ints[i] ;
+ }
+
+ // create the StripArray output
+ StripArray sa = new StripArray(stripVerts, stripCounts) ;
+
+ if (debug) {
+ System.err.println("GeneralizedStrip.toTriangleStrips" +
+ "\n number of strips: " +
+ sa.stripCounts.count) ;
+ if (sa.stripCounts.count > 0) {
+ System.err.println(" number of vertices: " +
+ sa.vertices.count +
+ "\n vertices/strip: " +
+ ((float)sa.vertices.count /
+ (float)sa.stripCounts.count)) ;
+ System.err.print(" strip counts: [") ;
+ for (i = 0 ; i < sa.stripCounts.count-1 ; i++)
+ System.err.print(sa.stripCounts.ints[i] + ", ") ;
+ System.err.println(sa.stripCounts.ints[i] + "]") ;
+ }
+ System.err.println() ;
+ }
+ return sa ;
+ }
+
+ private static void fanToStrips(int v, int length, int fans[],
+ IntList stripVerts,
+ IntList stripCounts,
+ boolean convexPlanar) {
+ if (convexPlanar) {
+ // Construct a strip by criss-crossing across the interior.
+ stripCounts.add(length) ;
+ stripVerts.add(fans[v]) ;
+
+ int j = v + 1 ;
+ int k = v + (length - 1) ;
+ while (j <= k) {
+ stripVerts.add(fans[j++]) ;
+ if (j > k) break ;
+ stripVerts.add(fans[k--]) ;
+ }
+ } else {
+ // Traverse non-convex or non-planar fan, biting off 3-triangle
+ // strips or less. First 5 vertices produce 1 strip of 3
+ // triangles, and every 4 vertices after that produce another
+ // strip of 3 triangles. Each remaining strip adds 2 vertices.
+ int fanStart = v ;
+ v++ ;
+ while (v+4 <= fanStart + length) {
+ stripVerts.add(fans[v]) ;
+ stripVerts.add(fans[v+1]) ;
+ stripVerts.add(fans[fanStart]) ;
+ stripVerts.add(fans[v+2]) ;
+ stripVerts.add(fans[v+3]) ;
+ stripCounts.add(5) ;
+ v += 3 ;
+ }
+
+ // Finish off the fan.
+ if (v+1 < fanStart + length) {
+ stripVerts.add(fans[v]) ;
+ stripVerts.add(fans[v+1]) ;
+ stripVerts.add(fans[fanStart]) ;
+ v++ ;
+
+ if (v+1 < fanStart + length) {
+ stripVerts.add(fans[v+1]) ;
+ stripCounts.add(4) ;
+ }
+ else
+ stripCounts.add(3) ;
+ }
+ }
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning an array of vertex
+ * references representing the original generalized strip as individual
+ * triangles. Each sequence of three consecutive vertex references in the
+ * output defines a single triangle.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @return an array of indices into the original vertex array
+ */
+ static int[] toTriangles(GeneralizedStripFlags vertices, int frontFace) {
+
+ int vertexCount = 0 ;
+ StripArray sa[] = toStripsAndFans(vertices, frontFace) ;
+
+ if (sa[0] != null)
+ vertexCount = 3 * getTriangleCount(sa[0].stripCounts) ;
+ if (sa[1] != null)
+ vertexCount += 3 * getTriangleCount(sa[1].stripCounts) ;
+
+ if (debug)
+ System.err.println("GeneralizedStrip.toTriangles\n" +
+ " number of triangles: " + vertexCount/3 + "\n" +
+ " number of vertices: " + vertexCount + "\n") ;
+ int t = 0 ;
+ int triangles[] = new int[vertexCount] ;
+
+ if (sa[0] != null)
+ t = stripsToTriangles(t, triangles,
+ 0, sa[0].vertices.ints,
+ 0, sa[0].stripCounts.ints,
+ sa[0].stripCounts.count) ;
+ if (sa[1] != null)
+ t = fansToTriangles(t, triangles,
+ 0, sa[1].vertices.ints,
+ 0, sa[1].stripCounts.ints,
+ sa[1].stripCounts.count) ;
+ return triangles ;
+ }
+
+ private static int stripsToTriangles(int tstart, int tbuff[],
+ int vstart, int vertices[],
+ int stripStart, int stripCounts[],
+ int stripCount) {
+ int t = tstart ;
+ int v = vstart ;
+ for (int i = 0 ; i < stripCount ; i++) {
+ for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
+ if ((j & 0x01) == 0) {
+ // even-numbered triangles
+ tbuff[t*3 +0] = vertices[v+0] ;
+ tbuff[t*3 +1] = vertices[v+1] ;
+ tbuff[t*3 +2] = vertices[v+2] ;
+ } else {
+ // odd-numbered triangles
+ tbuff[t*3 +0] = vertices[v+1] ;
+ tbuff[t*3 +1] = vertices[v+0] ;
+ tbuff[t*3 +2] = vertices[v+2] ;
+ }
+ t++ ; v++ ;
+ }
+ v += 2 ;
+ }
+ return t ;
+ }
+
+ private static int fansToTriangles(int tstart, int tbuff[],
+ int vstart, int vertices[],
+ int stripStart, int stripCounts[],
+ int stripCount) {
+ int t = tstart ;
+ int v = vstart ;
+ for (int i = 0 ; i < stripCount ; i++) {
+ for (int j = 0 ; j < stripCounts[i+stripStart] - 2 ; j++) {
+ tbuff[t*3 +0] = vertices[v] ;
+ tbuff[t*3 +1] = vertices[v+j+1] ;
+ tbuff[t*3 +2] = vertices[v+j+2] ;
+ t++ ;
+ }
+ v += stripCounts[i+stripStart] ;
+ }
+ return t ;
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a 2-element array of
+ * StripArray objects. The first StripArray will contain triangle strips
+ * and the second will contain individual triangles in the vertices
+ * field. Short strips will be converted to individual triangles.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
+ * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
+ * @param shortStripSize strips this size or less will be converted to
+ * individual triangles if there are more than maxShortStrips of them
+ * @param maxShortStrips maximum number of short strips allowed before
+ * creating individual triangles
+ * @return a 2-element array containing strips in 0 and triangles in 1
+ */
+ static StripArray[] toStripsAndTriangles(GeneralizedStripFlags vertices,
+ int frontFace, int shortStripSize,
+ int maxShortStrips) {
+ int longStripCount = 0 ;
+ int longStripVertexCount = 0 ;
+ int shortStripCount = 0 ;
+ int triangleCount = 0 ;
+
+ StripArray sa[] = new StripArray[2] ;
+ StripArray ts = toTriangleStrips(vertices, frontFace) ;
+
+ for (int i = 0 ; i < ts.stripCounts.count ; i++)
+ if (ts.stripCounts.ints[i] <= shortStripSize) {
+ shortStripCount++ ;
+ triangleCount += ts.stripCounts.ints[i] - 2 ;
+ } else {
+ longStripCount++ ;
+ longStripVertexCount += ts.stripCounts.ints[i] ;
+ }
+
+ if (debug)
+ System.err.print("GeneralizedStrip.toStripsAndTriangles\n" +
+ " short strip size: " + shortStripSize +
+ " short strips tolerated: " + maxShortStrips +
+ " number of short strips: " + shortStripCount +
+ "\n\n") ;
+
+ if (shortStripCount <= maxShortStrips) {
+ sa[0] = ts ;
+ sa[1] = null ;
+ } else {
+ int si = 0 ; int newStripVerts[] = new int[longStripVertexCount] ;
+ int ci = 0 ; int newStripCounts[] = new int[longStripCount] ;
+ int ti = 0 ; int triangles[] = new int[3*triangleCount] ;
+ int vi = 0 ;
+
+ for (int i = 0 ; i < ts.stripCounts.count ; i++) {
+ if (ts.stripCounts.ints[i] <= shortStripSize) {
+ ti = stripsToTriangles(ti, triangles,
+ vi, ts.vertices.ints,
+ i, ts.stripCounts.ints, 1) ;
+ vi += ts.stripCounts.ints[i] ;
+ } else {
+ newStripCounts[ci++] = ts.stripCounts.ints[i] ;
+ for (int j = 0 ; j < ts.stripCounts.ints[i] ; j++)
+ newStripVerts[si++] = ts.vertices.ints[vi++] ;
+ }
+ }
+
+ if (longStripCount > 0)
+ sa[0] = new StripArray(new IntList(newStripVerts),
+ new IntList(newStripCounts)) ;
+ else
+ sa[0] = null ;
+
+ sa[1] = new StripArray(new IntList(triangles), null) ;
+
+ if (debug) {
+ System.err.println(" triangles separated: " + triangleCount) ;
+ if (longStripCount > 0) {
+ System.err.println
+ (" new vertices/strip: " +
+ ((float)longStripVertexCount/(float)longStripCount)) ;
+
+ System.err.print(" long strip counts: [") ;
+ for (int i = 0 ; i < longStripCount-1 ; i++)
+ System.err.print(newStripCounts[i++] + ", ") ;
+
+ System.err.println
+ (newStripCounts[longStripCount-1] + "]\n") ;
+ }
+ }
+ }
+ return sa ;
+ }
+
+ /**
+ * Interprets the vertex flags associated with a class implementing
+ * GeneralizedStripFlags, constructing and returning a StripArray.
+ *
+ * RESTART_CW and RESTART_CCW are treated as equivalent, as are
+ * REPLACE_MIDDLE and REPLACE_OLDEST.
+ *
+ * @param vertices an object implementing GeneralizedStripFlags
+ * @return a StripArray representing an array of line strips
+ */
+ static StripArray toLineStrips(GeneralizedStripFlags vertices) {
+ int v, size, stripStart, stripLength, flag ;
+
+ stripStart = 0 ;
+ stripLength = 2 ;
+ size = vertices.getFlagCount() ;
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(size*2) ;
+ IntList stripCounts = new IntList(size) ;
+
+ // Vertex replace flags for the first two vertices are irrelevant.
+ v = 2 ;
+ while (v < size) {
+ flag = vertices.getFlag(v) ;
+
+ if ((flag != RESTART_CW) && (flag != RESTART_CCW)) {
+ // proceed to the next vertex.
+ stripLength++ ;
+ v++ ;
+
+ } else {
+ // Record the last strip.
+ stripCounts.add(stripLength) ;
+ for (int i = stripStart ; i < stripStart+stripLength ; i++)
+ stripVerts.add(i) ;
+
+ // Start a new strip and skip to its 3rd vertex.
+ stripStart = v ;
+ stripLength = 2 ;
+ v += 2 ;
+ }
+ }
+
+ // Finish off the last strip.
+ // If v > size then the strip is degenerate.
+ if (v == size) {
+ stripCounts.add(stripLength) ;
+ for (int i = stripStart ; i < stripStart+stripLength ; i++)
+ stripVerts.add(i) ;
+ } else
+ throw new IllegalArgumentException
+ (J3dI18N.getString("GeneralizedStrip0")) ;
+
+ if (debug) {
+ System.err.println("GeneralizedStrip.toLineStrips\n") ;
+ if (v > size)
+ System.err.println(" ended with a degenerate line") ;
+
+ System.err.println(" number of strips: " + stripCounts.count) ;
+ if (stripCounts.count > 0) {
+ System.err.println(" number of vertices: " + stripVerts.count) ;
+ System.err.println(" vertices/strip: " +
+ (float)stripVerts.count/stripCounts.count) ;
+ System.err.println(" strip counts: " + stripCounts.toString()) ;
+ // System.err.println(" indices: " + stripVerts.toString()) ;
+ }
+ System.err.println() ;
+ }
+
+ if (stripCounts.count > 0)
+ return new StripArray(stripVerts, stripCounts) ;
+ else
+ return null ;
+ }
+
+ /**
+ * Counts the number of lines defined by arrays of line strips.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return number of lines in the strips
+ */
+ static int getLineCount(int stripCounts[]) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.length ; i++)
+ count += (stripCounts[i] - 1) ;
+ return count ;
+ }
+
+ /**
+ * Counts the number of triangles defined by arrays of
+ * triangle strips or fans.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return number of triangles in the strips or fans
+ */
+ static int getTriangleCount(int stripCounts[]) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.length ; i++)
+ count += (stripCounts[i] - 2) ;
+ return count ;
+ }
+
+ /**
+ * Counts the number of triangles defined by arrays of
+ * triangle strips or fans.
+ *
+ * @param stripCounts IntList of strip counts
+ * @return number of triangles in the strips or fans
+ */
+ static int getTriangleCount(IntList stripCounts) {
+ int count = 0 ;
+ for (int i = 0 ; i < stripCounts.count ; i++)
+ count += (stripCounts.ints[i] - 2) ;
+ return count ;
+ }
+
+ /**
+ * Breaks up triangle strips into separate triangles.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return array of ints which index into the original vertex array; each
+ * set of three consecutive vertex indices defines a single triangle
+ */
+ static int[] stripsToTriangles(int stripCounts[]) {
+ int triangleCount = getTriangleCount(stripCounts) ;
+ int tbuff[] = new int[3*triangleCount] ;
+ IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
+
+ vertices.fillAscending() ;
+ stripsToTriangles(0, tbuff,
+ 0, vertices.ints,
+ 0, stripCounts,
+ stripCounts.length) ;
+ return tbuff ;
+ }
+
+ /**
+ * Breaks up triangle fans into separate triangles.
+ *
+ * @param stripCounts array of strip counts, as used by the
+ * GeometryStripArray object
+ * @return array of ints which index into the original vertex array; each
+ * set of three consecutive vertex indices defines a single triangle
+ */
+ static int[] fansToTriangles(int stripCounts[]) {
+ int triangleCount = getTriangleCount(stripCounts) ;
+ int tbuff[] = new int[3*triangleCount] ;
+ IntList vertices = new IntList(triangleCount + 2*stripCounts.length) ;
+
+ vertices.fillAscending() ;
+ fansToTriangles(0, tbuff,
+ 0, vertices.ints,
+ 0, stripCounts,
+ stripCounts.length) ;
+ return tbuff ;
+ }
+
+ /**
+ * Takes a fan and converts it to one or more strips.
+ *
+ * @param v index into the fans array of the first vertex in the fan
+ * @param length number of vertices in the fan
+ * @param fans array of vertex indices representing one or more fans
+ * @param convexPlanar if true indicates that the fan is convex and
+ * planar; such fans will always be converted into a single strip
+ * @return a StripArray containing the converted strips
+ */
+ static StripArray fanToStrips(int v, int length, int fans[],
+ boolean convexPlanar) {
+
+ // Initialize IntLists to worst-case sizes.
+ IntList stripVerts = new IntList(length*3) ;
+ IntList stripCounts = new IntList(length) ;
+
+ fanToStrips(v, length, fans, stripVerts, stripCounts, convexPlanar) ;
+ return new StripArray(stripVerts, stripCounts) ;
+ }
+}