001: /*
002: * $RCSfile: GeneralizedStrip.java,v $
003: *
004: * Copyright 1998-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.6 $
028: * $Date: 2008/02/28 20:17:21 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.*;
035:
036: /**
037: * This class provides static methods to support topological
038: * transformations on generalized strips. This is used by the
039: * GeometryDecompressor. These methods only need to look at the
040: * vertex replacement flags to determine how the vertices in the strip
041: * are connected. The connections are rearranged in different ways to
042: * transform generalized strips to GeometryArray representations.
043: *
044: * @see GeneralizedStripFlags
045: * @see GeneralizedVertexList
046: * @see GeometryDecompressor
047: */
048: class GeneralizedStrip {
049: private static final boolean debug = false;
050:
051: // Private convenience copies of various constants.
052: private static final int CW = GeneralizedStripFlags.FRONTFACE_CW;
053: private static final int CCW = GeneralizedStripFlags.FRONTFACE_CCW;
054: private static final int RESTART_CW = GeneralizedStripFlags.RESTART_CW;
055: private static final int RESTART_CCW = GeneralizedStripFlags.RESTART_CCW;
056: private static final int REPLACE_MIDDLE = GeneralizedStripFlags.REPLACE_MIDDLE;
057: private static final int REPLACE_OLDEST = GeneralizedStripFlags.REPLACE_OLDEST;
058:
059: /**
060: * The IntList is like an ArrayList, but avoids the Integer
061: * object wrapper and accessor overhead for simple lists of ints.
062: */
063: static class IntList {
064: /**
065: * The array of ints.
066: */
067: int ints[];
068:
069: /**
070: * The number of ints in this instance.
071: */
072: int count;
073:
074: /**
075: * Construct a new empty IntList of the given initial size.
076: * @param initialSize initial size of the backing array
077: */
078: IntList(int initialSize) {
079: ints = new int[initialSize];
080: count = 0;
081: }
082:
083: /**
084: * Constructs an IntList with the given contents.
085: * @param ints the array of ints to use as the contents
086: */
087: IntList(int ints[]) {
088: this .ints = ints;
089: this .count = ints.length;
090: }
091:
092: /**
093: * Add a new int to the end of this list.
094: * @param i the int to be appended to this list
095: */
096: void add(int i) {
097: if (count == ints.length) {
098: int newints[] = new int[2 * count];
099: System.arraycopy(ints, 0, newints, 0, count);
100: ints = newints;
101: if (debug)
102: System.err
103: .println("GeneralizedStrip.IntList: reallocated "
104: + (2 * count) + " ints");
105: }
106: ints[count++] = i;
107: }
108:
109: /**
110: * Trim the backing array to the current count and return the
111: * resulting backing array.
112: */
113: int[] trim() {
114: if (count != ints.length) {
115: int newints[] = new int[count];
116: System.arraycopy(ints, 0, newints, 0, count);
117: ints = newints;
118: }
119: return ints;
120: }
121:
122: /**
123: * Fill the list with consecutive integers starting from 0.
124: */
125: void fillAscending() {
126: for (int i = 0; i < ints.length; i++)
127: ints[i] = i;
128:
129: count = ints.length;
130: }
131:
132: public String toString() {
133: String s = new String("[");
134: for (int i = 0; i < count - 1; i++)
135: s = s + Integer.toString(ints[i]) + ", ";
136: return s + Integer.toString(ints[count - 1]) + "]";
137: }
138: }
139:
140: /**
141: * The StripArray class is used as the output of some conversion methods
142: * in the GeneralizedStrip class.
143: */
144: static class StripArray {
145: /**
146: * A list of indices into the vertices of the original generalized
147: * strip. It specifies the order in which vertices in the original
148: * strip should be followed to build GeometryArray objects.
149: */
150: IntList vertices;
151:
152: /**
153: * A list of strip counts.
154: */
155: IntList stripCounts;
156:
157: /**
158: * Creates a StripArray with the specified vertices and stripCounts.
159: * @param vertices IntList containing vertex indicies.
160: * @param stripCounts IntList containing strip lengths.
161: */
162: StripArray(IntList vertices, IntList stripCounts) {
163: this .vertices = vertices;
164: this .stripCounts = stripCounts;
165: }
166: }
167:
168: /**
169: * Interprets the vertex flags associated with a class implementing
170: * GeneralizedStripFlags, constructing and returning a 2-element array of
171: * StripArray objects. The first StripArray will contain triangle strips
172: * and the second will contain triangle fans.
173: *
174: * @param vertices an object implementing GeneralizedStripFlags
175: * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
176: * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
177: * @return a 2-element array containing strips in 0 and fans in 1
178: */
179: static StripArray[] toStripsAndFans(GeneralizedStripFlags vertices,
180: int frontFace) {
181:
182: int size = vertices.getFlagCount();
183:
184: // Initialize IntLists to worst-case sizes.
185: IntList stripVerts = new IntList(size * 3);
186: IntList fanVerts = new IntList(size * 3);
187: IntList stripCounts = new IntList(size);
188: IntList fanCounts = new IntList(size);
189:
190: toStripsAndFans(vertices, frontFace, stripVerts, stripCounts,
191: fanVerts, fanCounts);
192:
193: // Construct the StripArray output.
194: StripArray sa[] = new StripArray[2];
195:
196: if (stripCounts.count > 0)
197: sa[0] = new StripArray(stripVerts, stripCounts);
198:
199: if (fanCounts.count > 0)
200: sa[1] = new StripArray(fanVerts, fanCounts);
201:
202: return sa;
203: }
204:
205: private static void toStripsAndFans(GeneralizedStripFlags vertices,
206: int frontFace, IntList stripVerts, IntList stripCounts,
207: IntList fanVerts, IntList fanCounts) {
208: int newFlag, curFlag, winding;
209: int v, size, stripStart, stripLength;
210: boolean transition = false;
211:
212: stripStart = 0;
213: stripLength = 3;
214: curFlag = vertices.getFlag(0);
215: winding = (curFlag == RESTART_CW ? CW : CCW);
216: size = vertices.getFlagCount();
217:
218: // Vertex replace flags for the first 3 vertices are irrelevant since
219: // they can only define a single triangle. The first meaningful
220: // replace flag starts at the 4th vertex.
221: v = 3;
222: if (v < size)
223: curFlag = vertices.getFlag(v);
224:
225: while (v < size) {
226: newFlag = vertices.getFlag(v);
227:
228: if ((newFlag == curFlag) && (newFlag != RESTART_CW)
229: && (newFlag != RESTART_CCW)) {
230: // The last flag was the same as this one, and it wasn't a
231: // restart: proceed to the next vertex.
232: stripLength++;
233: v++;
234:
235: } else {
236: // Either this vertex flag changed from the last one, or
237: // the flag explicitly specifies a restart: process the
238: // last strip and start up a new one.
239: if (curFlag == REPLACE_MIDDLE)
240: addFan(fanVerts, fanCounts, stripStart,
241: stripLength, frontFace, winding, transition);
242: else
243: addStrip(stripVerts, stripCounts, stripStart,
244: stripLength, frontFace, winding);
245:
246: // Restart: skip to the 4th vertex of the new strip.
247: if ((newFlag == RESTART_CW) || (newFlag == RESTART_CCW)) {
248: winding = (newFlag == RESTART_CW ? CW : CCW);
249: stripStart = v;
250: stripLength = 3;
251: v += 3;
252: transition = false;
253: if (v < size)
254: curFlag = vertices.getFlag(v);
255: }
256: // Strip/fan transition: decrement start of strip.
257: else {
258: if (newFlag == REPLACE_OLDEST) {
259: // Flip winding order when transitioning from fans
260: // to strips.
261: winding = (winding == CW ? CCW : CW);
262: stripStart = v - 2;
263: stripLength = 3;
264: } else {
265: // Flip winding order when transitioning from
266: // strips to fans only if the preceding strip has
267: // an even number of vertices.
268: if ((stripLength & 0x01) == 0)
269: winding = (winding == CW ? CCW : CW);
270: stripStart = v - 3;
271: stripLength = 4;
272: }
273: v++;
274: transition = true;
275: curFlag = newFlag;
276: }
277: }
278: }
279:
280: // Finish off the last strip or fan.
281: // If v > size then the strip is degenerate.
282: if (v == size)
283: if (curFlag == REPLACE_MIDDLE)
284: addFan(fanVerts, fanCounts, stripStart, stripLength,
285: frontFace, winding, transition);
286: else
287: addStrip(stripVerts, stripCounts, stripStart,
288: stripLength, frontFace, winding);
289: else
290: throw new IllegalArgumentException(J3dI18N
291: .getString("GeneralizedStrip0"));
292:
293: if (debug) {
294: System.err.println("GeneralizedStrip.toStripsAndFans");
295: if (v > size)
296: System.err.println(" ended with a degenerate triangle:"
297: + " number of vertices: " + (v - size));
298:
299: System.err.println("\n number of strips: "
300: + stripCounts.count);
301: if (stripCounts.count > 0) {
302: System.err.println(" number of vertices: "
303: + stripVerts.count);
304: System.err.println(" vertices/strip: "
305: + (float) stripVerts.count / stripCounts.count);
306: System.err.println(" strip counts: "
307: + stripCounts.toString());
308: // System.err.println(" indices: " + stripVerts.toString()) ;
309: }
310:
311: System.err.println("\n number of fans: " + fanCounts.count);
312: if (fanCounts.count > 0) {
313: System.err.println(" number of vertices: "
314: + fanVerts.count);
315: System.err.println(" vertices/strip: "
316: + (float) fanVerts.count / fanCounts.count);
317: System.err.println(" fan counts: "
318: + fanCounts.toString());
319: // System.err.println(" indices: " + fanVerts.toString()) ;
320: }
321: System.err.println("\n total vertices: "
322: + (stripVerts.count + fanVerts.count)
323: + "\n original number of vertices: " + size + "\n");
324: }
325: }
326:
327: //
328: // Java 3D specifies that the vertices of front-facing polygons
329: // have counter-clockwise (CCW) winding order when projected to
330: // the view surface. Polygons with clockwise (CW) vertex winding
331: // will be culled as back-facing by default.
332: //
333: // Generalized triangle strips can flip the orientation of their
334: // triangles with the RESTART_CW and RESTART_CCW vertex flags.
335: // Strips flagged with an orientation opposite to what has been
336: // specified as front-facing must have their windings reversed in
337: // order to have the correct face orientation when represented as
338: // GeometryArray objects.
339: //
340: private static void addStrip(IntList stripVerts,
341: IntList stripCounts, int start, int length, int frontFace,
342: int winding) {
343: int vindex = start;
344:
345: if (winding == frontFace) {
346: // Maintain original order.
347: stripCounts.add(length);
348: while (vindex < start + length) {
349: stripVerts.add(vindex++);
350: }
351: } else if ((length & 0x1) == 1) {
352: // Reverse winding order if number of vertices is odd.
353: stripCounts.add(length);
354: vindex += length - 1;
355: while (vindex >= start) {
356: stripVerts.add(vindex--);
357: }
358: } else if (length == 4) {
359: // Swap middle vertices.
360: stripCounts.add(4);
361: stripVerts.add(vindex);
362: stripVerts.add(vindex + 2);
363: stripVerts.add(vindex + 1);
364: stripVerts.add(vindex + 3);
365: } else {
366: // Make the 1st triangle a singleton with reverse winding.
367: stripCounts.add(3);
368: stripVerts.add(vindex);
369: stripVerts.add(vindex + 2);
370: stripVerts.add(vindex + 1);
371: if (length > 3) {
372: // Copy the rest of the vertices in original order.
373: vindex++;
374: stripCounts.add(length - 1);
375: while (vindex < start + length) {
376: stripVerts.add(vindex++);
377: }
378: }
379: }
380: }
381:
382: private static void addFan(IntList fanVerts, IntList fanCounts,
383: int start, int length, int frontFace, int winding,
384: boolean transition) {
385: int vindex = start;
386: fanVerts.add(vindex++);
387:
388: if (winding == frontFace) {
389: if (transition) {
390: // Skip 1st triangle if this is the result of a transition.
391: fanCounts.add(length - 1);
392: vindex++;
393: } else {
394: fanCounts.add(length);
395: fanVerts.add(vindex++);
396: }
397: while (vindex < start + length) {
398: fanVerts.add(vindex++);
399: }
400: } else {
401: // Reverse winding order.
402: vindex += length - 2;
403: while (vindex > start + 1) {
404: fanVerts.add(vindex--);
405: }
406: if (transition) {
407: // Skip 1st triangle if this is the result of a transition.
408: fanCounts.add(length - 1);
409: } else {
410: fanCounts.add(length);
411: fanVerts.add(vindex);
412: }
413: }
414: }
415:
416: /**
417: * Interprets the vertex flags associated with a class implementing
418: * GeneralizedStripFlags, constructing and returning a StripArray containing
419: * exclusively strips.
420: *
421: * @param vertices an object implementing GeneralizedStripFlags
422: * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
423: * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
424: * @return a StripArray containing the converted strips
425: */
426: static StripArray toTriangleStrips(GeneralizedStripFlags vertices,
427: int frontFace) {
428:
429: int size = vertices.getFlagCount();
430:
431: // initialize lists to worst-case sizes.
432: IntList stripVerts = new IntList(size * 3);
433: IntList fanVerts = new IntList(size * 3);
434: IntList stripCounts = new IntList(size);
435: IntList fanCounts = new IntList(size);
436:
437: toStripsAndFans(vertices, frontFace, stripVerts, stripCounts,
438: fanVerts, fanCounts);
439:
440: if (fanCounts.count == 0)
441: if (stripCounts.count > 0)
442: return new StripArray(stripVerts, stripCounts);
443: else
444: return null;
445:
446: // convert each fan to one or more strips
447: int i, v = 0;
448: for (i = 0; i < fanCounts.count; i++) {
449: fanToStrips(v, fanCounts.ints[i], fanVerts.ints,
450: stripVerts, stripCounts, false);
451: v += fanCounts.ints[i];
452: }
453:
454: // create the StripArray output
455: StripArray sa = new StripArray(stripVerts, stripCounts);
456:
457: if (debug) {
458: System.err.println("GeneralizedStrip.toTriangleStrips"
459: + "\n number of strips: " + sa.stripCounts.count);
460: if (sa.stripCounts.count > 0) {
461: System.err
462: .println(" number of vertices: "
463: + sa.vertices.count
464: + "\n vertices/strip: "
465: + ((float) sa.vertices.count / (float) sa.stripCounts.count));
466: System.err.print(" strip counts: [");
467: for (i = 0; i < sa.stripCounts.count - 1; i++)
468: System.err.print(sa.stripCounts.ints[i] + ", ");
469: System.err.println(sa.stripCounts.ints[i] + "]");
470: }
471: System.err.println();
472: }
473: return sa;
474: }
475:
476: private static void fanToStrips(int v, int length, int fans[],
477: IntList stripVerts, IntList stripCounts,
478: boolean convexPlanar) {
479: if (convexPlanar) {
480: // Construct a strip by criss-crossing across the interior.
481: stripCounts.add(length);
482: stripVerts.add(fans[v]);
483:
484: int j = v + 1;
485: int k = v + (length - 1);
486: while (j <= k) {
487: stripVerts.add(fans[j++]);
488: if (j > k)
489: break;
490: stripVerts.add(fans[k--]);
491: }
492: } else {
493: // Traverse non-convex or non-planar fan, biting off 3-triangle
494: // strips or less. First 5 vertices produce 1 strip of 3
495: // triangles, and every 4 vertices after that produce another
496: // strip of 3 triangles. Each remaining strip adds 2 vertices.
497: int fanStart = v;
498: v++;
499: while (v + 4 <= fanStart + length) {
500: stripVerts.add(fans[v]);
501: stripVerts.add(fans[v + 1]);
502: stripVerts.add(fans[fanStart]);
503: stripVerts.add(fans[v + 2]);
504: stripVerts.add(fans[v + 3]);
505: stripCounts.add(5);
506: v += 3;
507: }
508:
509: // Finish off the fan.
510: if (v + 1 < fanStart + length) {
511: stripVerts.add(fans[v]);
512: stripVerts.add(fans[v + 1]);
513: stripVerts.add(fans[fanStart]);
514: v++;
515:
516: if (v + 1 < fanStart + length) {
517: stripVerts.add(fans[v + 1]);
518: stripCounts.add(4);
519: } else
520: stripCounts.add(3);
521: }
522: }
523: }
524:
525: /**
526: * Interprets the vertex flags associated with a class implementing
527: * GeneralizedStripFlags, constructing and returning an array of vertex
528: * references representing the original generalized strip as individual
529: * triangles. Each sequence of three consecutive vertex references in the
530: * output defines a single triangle.
531: *
532: * @param vertices an object implementing GeneralizedStripFlags
533: * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
534: * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
535: * @return an array of indices into the original vertex array
536: */
537: static int[] toTriangles(GeneralizedStripFlags vertices,
538: int frontFace) {
539:
540: int vertexCount = 0;
541: StripArray sa[] = toStripsAndFans(vertices, frontFace);
542:
543: if (sa[0] != null)
544: vertexCount = 3 * getTriangleCount(sa[0].stripCounts);
545: if (sa[1] != null)
546: vertexCount += 3 * getTriangleCount(sa[1].stripCounts);
547:
548: if (debug)
549: System.err.println("GeneralizedStrip.toTriangles\n"
550: + " number of triangles: " + vertexCount / 3 + "\n"
551: + " number of vertices: " + vertexCount + "\n");
552: int t = 0;
553: int triangles[] = new int[vertexCount];
554:
555: if (sa[0] != null)
556: t = stripsToTriangles(t, triangles, 0, sa[0].vertices.ints,
557: 0, sa[0].stripCounts.ints, sa[0].stripCounts.count);
558: if (sa[1] != null)
559: t = fansToTriangles(t, triangles, 0, sa[1].vertices.ints,
560: 0, sa[1].stripCounts.ints, sa[1].stripCounts.count);
561: return triangles;
562: }
563:
564: private static int stripsToTriangles(int tstart, int tbuff[],
565: int vstart, int vertices[], int stripStart,
566: int stripCounts[], int stripCount) {
567: int t = tstart;
568: int v = vstart;
569: for (int i = 0; i < stripCount; i++) {
570: for (int j = 0; j < stripCounts[i + stripStart] - 2; j++) {
571: if ((j & 0x01) == 0) {
572: // even-numbered triangles
573: tbuff[t * 3 + 0] = vertices[v + 0];
574: tbuff[t * 3 + 1] = vertices[v + 1];
575: tbuff[t * 3 + 2] = vertices[v + 2];
576: } else {
577: // odd-numbered triangles
578: tbuff[t * 3 + 0] = vertices[v + 1];
579: tbuff[t * 3 + 1] = vertices[v + 0];
580: tbuff[t * 3 + 2] = vertices[v + 2];
581: }
582: t++;
583: v++;
584: }
585: v += 2;
586: }
587: return t;
588: }
589:
590: private static int fansToTriangles(int tstart, int tbuff[],
591: int vstart, int vertices[], int stripStart,
592: int stripCounts[], int stripCount) {
593: int t = tstart;
594: int v = vstart;
595: for (int i = 0; i < stripCount; i++) {
596: for (int j = 0; j < stripCounts[i + stripStart] - 2; j++) {
597: tbuff[t * 3 + 0] = vertices[v];
598: tbuff[t * 3 + 1] = vertices[v + j + 1];
599: tbuff[t * 3 + 2] = vertices[v + j + 2];
600: t++;
601: }
602: v += stripCounts[i + stripStart];
603: }
604: return t;
605: }
606:
607: /**
608: * Interprets the vertex flags associated with a class implementing
609: * GeneralizedStripFlags, constructing and returning a 2-element array of
610: * StripArray objects. The first StripArray will contain triangle strips
611: * and the second will contain individual triangles in the vertices
612: * field. Short strips will be converted to individual triangles.
613: *
614: * @param vertices an object implementing GeneralizedStripFlags
615: * @param frontFace a flag, either GeneralizedStripFlags.FRONTFACE_CW or
616: * GeneralizedStripFlags.FRONTFACE_CCW, indicating front face winding
617: * @param shortStripSize strips this size or less will be converted to
618: * individual triangles if there are more than maxShortStrips of them
619: * @param maxShortStrips maximum number of short strips allowed before
620: * creating individual triangles
621: * @return a 2-element array containing strips in 0 and triangles in 1
622: */
623: static StripArray[] toStripsAndTriangles(
624: GeneralizedStripFlags vertices, int frontFace,
625: int shortStripSize, int maxShortStrips) {
626: int longStripCount = 0;
627: int longStripVertexCount = 0;
628: int shortStripCount = 0;
629: int triangleCount = 0;
630:
631: StripArray sa[] = new StripArray[2];
632: StripArray ts = toTriangleStrips(vertices, frontFace);
633:
634: for (int i = 0; i < ts.stripCounts.count; i++)
635: if (ts.stripCounts.ints[i] <= shortStripSize) {
636: shortStripCount++;
637: triangleCount += ts.stripCounts.ints[i] - 2;
638: } else {
639: longStripCount++;
640: longStripVertexCount += ts.stripCounts.ints[i];
641: }
642:
643: if (debug)
644: System.err.print("GeneralizedStrip.toStripsAndTriangles\n"
645: + " short strip size: " + shortStripSize
646: + " short strips tolerated: " + maxShortStrips
647: + " number of short strips: " + shortStripCount
648: + "\n\n");
649:
650: if (shortStripCount <= maxShortStrips) {
651: sa[0] = ts;
652: sa[1] = null;
653: } else {
654: int si = 0;
655: int newStripVerts[] = new int[longStripVertexCount];
656: int ci = 0;
657: int newStripCounts[] = new int[longStripCount];
658: int ti = 0;
659: int triangles[] = new int[3 * triangleCount];
660: int vi = 0;
661:
662: for (int i = 0; i < ts.stripCounts.count; i++) {
663: if (ts.stripCounts.ints[i] <= shortStripSize) {
664: ti = stripsToTriangles(ti, triangles, vi,
665: ts.vertices.ints, i, ts.stripCounts.ints, 1);
666: vi += ts.stripCounts.ints[i];
667: } else {
668: newStripCounts[ci++] = ts.stripCounts.ints[i];
669: for (int j = 0; j < ts.stripCounts.ints[i]; j++)
670: newStripVerts[si++] = ts.vertices.ints[vi++];
671: }
672: }
673:
674: if (longStripCount > 0)
675: sa[0] = new StripArray(new IntList(newStripVerts),
676: new IntList(newStripCounts));
677: else
678: sa[0] = null;
679:
680: sa[1] = new StripArray(new IntList(triangles), null);
681:
682: if (debug) {
683: System.err.println(" triangles separated: "
684: + triangleCount);
685: if (longStripCount > 0) {
686: System.err
687: .println(" new vertices/strip: "
688: + ((float) longStripVertexCount / (float) longStripCount));
689:
690: System.err.print(" long strip counts: [");
691: for (int i = 0; i < longStripCount - 1; i++)
692: System.err.print(newStripCounts[i++] + ", ");
693:
694: System.err
695: .println(newStripCounts[longStripCount - 1]
696: + "]\n");
697: }
698: }
699: }
700: return sa;
701: }
702:
703: /**
704: * Interprets the vertex flags associated with a class implementing
705: * GeneralizedStripFlags, constructing and returning a StripArray.
706: *
707: * RESTART_CW and RESTART_CCW are treated as equivalent, as are
708: * REPLACE_MIDDLE and REPLACE_OLDEST.
709: *
710: * @param vertices an object implementing GeneralizedStripFlags
711: * @return a StripArray representing an array of line strips
712: */
713: static StripArray toLineStrips(GeneralizedStripFlags vertices) {
714: int v, size, stripStart, stripLength, flag;
715:
716: stripStart = 0;
717: stripLength = 2;
718: size = vertices.getFlagCount();
719:
720: // Initialize IntLists to worst-case sizes.
721: IntList stripVerts = new IntList(size * 2);
722: IntList stripCounts = new IntList(size);
723:
724: // Vertex replace flags for the first two vertices are irrelevant.
725: v = 2;
726: while (v < size) {
727: flag = vertices.getFlag(v);
728:
729: if ((flag != RESTART_CW) && (flag != RESTART_CCW)) {
730: // proceed to the next vertex.
731: stripLength++;
732: v++;
733:
734: } else {
735: // Record the last strip.
736: stripCounts.add(stripLength);
737: for (int i = stripStart; i < stripStart + stripLength; i++)
738: stripVerts.add(i);
739:
740: // Start a new strip and skip to its 3rd vertex.
741: stripStart = v;
742: stripLength = 2;
743: v += 2;
744: }
745: }
746:
747: // Finish off the last strip.
748: // If v > size then the strip is degenerate.
749: if (v == size) {
750: stripCounts.add(stripLength);
751: for (int i = stripStart; i < stripStart + stripLength; i++)
752: stripVerts.add(i);
753: } else
754: throw new IllegalArgumentException(J3dI18N
755: .getString("GeneralizedStrip0"));
756:
757: if (debug) {
758: System.err.println("GeneralizedStrip.toLineStrips\n");
759: if (v > size)
760: System.err.println(" ended with a degenerate line");
761:
762: System.err.println(" number of strips: "
763: + stripCounts.count);
764: if (stripCounts.count > 0) {
765: System.err.println(" number of vertices: "
766: + stripVerts.count);
767: System.err.println(" vertices/strip: "
768: + (float) stripVerts.count / stripCounts.count);
769: System.err.println(" strip counts: "
770: + stripCounts.toString());
771: // System.err.println(" indices: " + stripVerts.toString()) ;
772: }
773: System.err.println();
774: }
775:
776: if (stripCounts.count > 0)
777: return new StripArray(stripVerts, stripCounts);
778: else
779: return null;
780: }
781:
782: /**
783: * Counts the number of lines defined by arrays of line strips.
784: *
785: * @param stripCounts array of strip counts, as used by the
786: * GeometryStripArray object
787: * @return number of lines in the strips
788: */
789: static int getLineCount(int stripCounts[]) {
790: int count = 0;
791: for (int i = 0; i < stripCounts.length; i++)
792: count += (stripCounts[i] - 1);
793: return count;
794: }
795:
796: /**
797: * Counts the number of triangles defined by arrays of
798: * triangle strips or fans.
799: *
800: * @param stripCounts array of strip counts, as used by the
801: * GeometryStripArray object
802: * @return number of triangles in the strips or fans
803: */
804: static int getTriangleCount(int stripCounts[]) {
805: int count = 0;
806: for (int i = 0; i < stripCounts.length; i++)
807: count += (stripCounts[i] - 2);
808: return count;
809: }
810:
811: /**
812: * Counts the number of triangles defined by arrays of
813: * triangle strips or fans.
814: *
815: * @param stripCounts IntList of strip counts
816: * @return number of triangles in the strips or fans
817: */
818: static int getTriangleCount(IntList stripCounts) {
819: int count = 0;
820: for (int i = 0; i < stripCounts.count; i++)
821: count += (stripCounts.ints[i] - 2);
822: return count;
823: }
824:
825: /**
826: * Breaks up triangle strips into separate triangles.
827: *
828: * @param stripCounts array of strip counts, as used by the
829: * GeometryStripArray object
830: * @return array of ints which index into the original vertex array; each
831: * set of three consecutive vertex indices defines a single triangle
832: */
833: static int[] stripsToTriangles(int stripCounts[]) {
834: int triangleCount = getTriangleCount(stripCounts);
835: int tbuff[] = new int[3 * triangleCount];
836: IntList vertices = new IntList(triangleCount + 2
837: * stripCounts.length);
838:
839: vertices.fillAscending();
840: stripsToTriangles(0, tbuff, 0, vertices.ints, 0, stripCounts,
841: stripCounts.length);
842: return tbuff;
843: }
844:
845: /**
846: * Breaks up triangle fans into separate triangles.
847: *
848: * @param stripCounts array of strip counts, as used by the
849: * GeometryStripArray object
850: * @return array of ints which index into the original vertex array; each
851: * set of three consecutive vertex indices defines a single triangle
852: */
853: static int[] fansToTriangles(int stripCounts[]) {
854: int triangleCount = getTriangleCount(stripCounts);
855: int tbuff[] = new int[3 * triangleCount];
856: IntList vertices = new IntList(triangleCount + 2
857: * stripCounts.length);
858:
859: vertices.fillAscending();
860: fansToTriangles(0, tbuff, 0, vertices.ints, 0, stripCounts,
861: stripCounts.length);
862: return tbuff;
863: }
864:
865: /**
866: * Takes a fan and converts it to one or more strips.
867: *
868: * @param v index into the fans array of the first vertex in the fan
869: * @param length number of vertices in the fan
870: * @param fans array of vertex indices representing one or more fans
871: * @param convexPlanar if true indicates that the fan is convex and
872: * planar; such fans will always be converted into a single strip
873: * @return a StripArray containing the converted strips
874: */
875: static StripArray fanToStrips(int v, int length, int fans[],
876: boolean convexPlanar) {
877:
878: // Initialize IntLists to worst-case sizes.
879: IntList stripVerts = new IntList(length * 3);
880: IntList stripCounts = new IntList(length);
881:
882: fanToStrips(v, length, fans, stripVerts, stripCounts,
883: convexPlanar);
884: return new StripArray(stripVerts, stripCounts);
885: }
886: }
|