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