001: /*
002: * $RCSfile: GeometryDecompressorShape3D.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: import java.util.ArrayList;
049: import javax.media.j3d.Appearance;
050: import javax.media.j3d.GeometryArray;
051: import javax.media.j3d.GeometryStripArray;
052: import javax.media.j3d.LineStripArray;
053: import javax.media.j3d.Material;
054: import javax.media.j3d.PointArray;
055: import javax.media.j3d.Shape3D;
056: import javax.media.j3d.TriangleArray;
057: import javax.media.j3d.TriangleStripArray;
058: import javax.vecmath.Color4f;
059: import javax.vecmath.Point3f;
060: import javax.vecmath.Vector3f;
061:
062: /**
063: * This class implements a Shape3D backend for the abstract
064: * GeometryDecompressor.
065: */
066: class GeometryDecompressorShape3D extends GeometryDecompressor {
067: private static final boolean debug = false;
068: private static final boolean benchmark = false;
069: private static final boolean statistics = false;
070: private static final boolean printInfo = debug || benchmark
071: || statistics;
072:
073: // Type of connections in the compressed data:
074: // TYPE_POINT (1), TYPE_LINE (2), or TYPE_TRIANGLE (4).
075: private int bufferDataType;
076:
077: // Data bundled with each vertex: bitwise combination of
078: // NORMAL_IN_BUFFER (1), COLOR_IN_BUFFER (2), ALPHA_IN_BUFFER (4).
079: private int dataPresent;
080:
081: // List for accumulating the output of the decompressor and converting to
082: // GeometryArray representations.
083: private GeneralizedVertexList vlist;
084:
085: // Accumulates Shape3D objects constructed from decompressor output.
086: private ArrayList shapes;
087:
088: // Decompressor output state variables.
089: private Color4f curColor;
090: private Vector3f curNormal;
091:
092: // Variables for gathering statistics.
093: private int origVertexCount;
094: private int stripCount;
095: private int vertexCount;
096: private int triangleCount;
097: private long startTime;
098: private long endTime;
099:
100: // Triangle array type to construct.
101: private int triOutputType;
102:
103: // Types of triangle output available.
104: private static final int TRI_SET = 0;
105: private static final int TRI_STRIP_SET = 1;
106: private static final int TRI_STRIP_AND_FAN_SET = 2;
107: private static final int TRI_STRIP_AND_TRI_SET = 3;
108:
109: // Private convenience copies of various constants.
110: private static final int TYPE_POINT = CompressedGeometryRetained.TYPE_POINT;
111: private static final int TYPE_LINE = CompressedGeometryRetained.TYPE_LINE;
112: private static final int TYPE_TRIANGLE = CompressedGeometryRetained.TYPE_TRIANGLE;
113: private static final int FRONTFACE_CCW = GeneralizedStripFlags.FRONTFACE_CCW;
114:
115: /**
116: * Decompress the given compressed geometry.
117: * @param cgr CompressedGeometryRetained object with compressed geometry
118: * @return an array of Shape3D with TriangleArray geometry if compressed
119: * data contains triangles; otherwise, Shape3D array containing PointArray
120: * or LineStripArray geometry
121: * @see CompressedGeometry
122: * @see GeometryDecompressor
123: */
124: Shape3D[] toTriangleArrays(CompressedGeometryRetained cgr) {
125: return decompress(cgr, TRI_SET);
126: }
127:
128: /**
129: * Decompress the given compressed geometry.
130: * @param cgr CompressedGeometryRetained object with compressed geometry
131: * @return an array of Shape3D with TriangleStripArray geometry if
132: * compressed data contains triangles; otherwise, Shape3D array containing
133: * PointArray or LineStripArray geometry
134: * @see CompressedGeometry
135: * @see GeometryDecompressor
136: */
137: Shape3D[] toTriangleStripArrays(CompressedGeometryRetained cgr) {
138: return decompress(cgr, TRI_STRIP_SET);
139: }
140:
141: /**
142: * Decompress the given compressed geometry.
143: * @param cgr CompressedGeometryRetained object with compressed geometry
144: * @return an array of Shape3D with TriangleStripArray and
145: * TriangleFanArray geometry if compressed data contains triangles;
146: * otherwise, Shape3D array containing PointArray or LineStripArray
147: * geometry
148: * @see CompressedGeometry
149: * @see GeometryDecompressor
150: */
151: Shape3D[] toStripAndFanArrays(CompressedGeometryRetained cgr) {
152: return decompress(cgr, TRI_STRIP_AND_FAN_SET);
153: }
154:
155: /**
156: * Decompress the given compressed geometry.
157: * @param cgr CompressedGeometryRetained object with compressed geometry
158: * @return an array of Shape3D with TriangleStripArray and
159: * TriangleArray geometry if compressed data contains triangles;
160: * otherwise, Shape3D array containing PointArray or LineStripArray
161: * geometry
162: * @see CompressedGeometry
163: * @see GeometryDecompressor
164: */
165: Shape3D[] toStripAndTriangleArrays(CompressedGeometryRetained cgr) {
166: return decompress(cgr, TRI_STRIP_AND_TRI_SET);
167: }
168:
169: /**
170: * Decompress the data contained in a CompressedGeometryRetained and
171: * return an array of Shape3D objects using the specified triangle output
172: * type. The triangle output type is ignored if the compressed data
173: * contains points or lines.
174: */
175: private Shape3D[] decompress(CompressedGeometryRetained cgr,
176: int triOutputType) {
177:
178: if (!checkVersion(cgr.majorVersionNumber,
179: cgr.minorVersionNumber)) {
180: return null;
181: }
182:
183: vlist = null;
184: curColor = null;
185: curNormal = null;
186:
187: // Get descriptors for compressed data.
188: bufferDataType = cgr.bufferType;
189: dataPresent = cgr.bufferContents;
190: if (printInfo)
191: beginPrint();
192:
193: // Initialize the decompressor backend.
194: this .triOutputType = triOutputType;
195: shapes = new ArrayList();
196:
197: // Call the superclass decompress() method which calls the output
198: // methods of this subclass. The results are stored in vlist.
199: super .decompress(cgr.offset, cgr.size, cgr.compressedGeometry);
200:
201: // Convert the decompressor output to Shape3D objects.
202: addShape3D();
203: if (printInfo)
204: endPrint();
205:
206: // Return the fixed-length output array.
207: Shape3D shapeArray[] = new Shape3D[shapes.size()];
208: return (Shape3D[]) shapes.toArray(shapeArray);
209: }
210:
211: /**
212: * Initialize the vertex output list based on the vertex format provided
213: * by the SetState decompression command.
214: */
215: void outputVertexFormat(boolean bundlingNorm,
216: boolean bundlingColor, boolean doingAlpha) {
217:
218: if (vlist != null)
219: // Construct shapes using the current vertex format.
220: addShape3D();
221:
222: int vertexFormat = GeometryArray.COORDINATES;
223:
224: if (bundlingNorm) {
225: vertexFormat |= GeometryArray.NORMALS;
226: }
227:
228: if (bundlingColor) {
229: if (doingAlpha) {
230: vertexFormat |= GeometryArray.COLOR_4;
231: } else {
232: vertexFormat |= GeometryArray.COLOR_3;
233: }
234: }
235:
236: vlist = new GeneralizedVertexList(vertexFormat, FRONTFACE_CCW);
237: }
238:
239: /**
240: * Add a new decompressed vertex to the current list.
241: */
242: void outputVertex(Point3f position, Vector3f normal, Color4f color,
243: int vertexReplaceCode) {
244:
245: if (curNormal != null)
246: normal = curNormal;
247: vlist.addVertex(position, normal, color, vertexReplaceCode);
248:
249: if (debug) {
250: System.out.println(" outputVertex: flag "
251: + vertexReplaceCode);
252: System.out.println(" position " + position.toString());
253: if (normal != null)
254: System.out.println(" normal " + normal.toString());
255: if (color != null)
256: System.out.println(" color " + color.toString());
257: }
258: }
259:
260: /**
261: * Create a Shape3D using the current color for both the ambient and
262: * diffuse material colors, then start a new vertex list for the new
263: * color. The outputColor() method is never called if colors are bundled
264: * with each vertex in the compressed buffer.
265: */
266: void outputColor(Color4f color) {
267: if (debug)
268: System.out.println(" outputColor: " + color.toString());
269:
270: if (vlist.size() > 0) {
271: // Construct Shape3D using the current color.
272: addShape3D();
273:
274: // Start a new vertex list for the new color.
275: vlist = new GeneralizedVertexList(vlist.vertexFormat,
276: FRONTFACE_CCW);
277: }
278: if (curColor == null)
279: curColor = new Color4f();
280: curColor.set(color);
281: }
282:
283: /**
284: * Set the current normal that will be copied to each succeeding vertex
285: * output by the decompressor. The per-vertex copy is needed since in
286: * Java 3D a normal is always associated with a vertex. This method is
287: * never called if normals are bundled with each vertex in the compressed
288: * buffer.
289: */
290: void outputNormal(Vector3f normal) {
291: if (debug)
292: System.out.println(" outputNormal: " + normal.toString());
293:
294: if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0) {
295: if (vlist.size() > 0)
296: // Construct Shape3D using the current vertex format.
297: addShape3D();
298:
299: // Start a new vertex list with the new format.
300: vlist = new GeneralizedVertexList(vlist.vertexFormat
301: | GeometryArray.NORMALS, FRONTFACE_CCW);
302: }
303: if (curNormal == null)
304: curNormal = new Vector3f();
305: curNormal.set(normal);
306: }
307:
308: /**
309: * Create a Shape3D object of the desired type from the current vertex
310: * list. Apply the current color, if non-null, as a Material attribute.
311: */
312: private void addShape3D() {
313: Material m = new Material();
314:
315: if (curColor != null) {
316: if ((vlist.vertexFormat & GeometryArray.COLOR_4) != GeometryArray.COLOR_4) {
317: m.setAmbientColor(curColor.x, curColor.y, curColor.z);
318: m.setDiffuseColor(curColor.x, curColor.y, curColor.z);
319: } else {
320: m.setAmbientColor(curColor.x, curColor.y, curColor.z);
321: m.setDiffuseColor(curColor.x, curColor.y, curColor.z,
322: curColor.w);
323: }
324: }
325:
326: if ((vlist.vertexFormat & GeometryArray.NORMALS) == 0)
327: m.setLightingEnable(false);
328: else
329: m.setLightingEnable(true);
330:
331: Appearance a = new Appearance();
332: a.setMaterial(m);
333:
334: switch (bufferDataType) {
335: case TYPE_TRIANGLE:
336: switch (triOutputType) {
337: case TRI_SET:
338: TriangleArray ta = vlist.toTriangleArray();
339: if (ta != null)
340: shapes.add(new Shape3D(ta, a));
341: break;
342: case TRI_STRIP_SET:
343: TriangleStripArray tsa = vlist.toTriangleStripArray();
344: if (tsa != null)
345: shapes.add(new Shape3D(tsa, a));
346: break;
347: case TRI_STRIP_AND_FAN_SET:
348: GeometryStripArray gsa[] = vlist.toStripAndFanArrays();
349: if (gsa[0] != null)
350: shapes.add(new Shape3D(gsa[0], a));
351: if (gsa[1] != null)
352: shapes.add(new Shape3D(gsa[1], a));
353: break;
354: case TRI_STRIP_AND_TRI_SET:
355: GeometryArray ga[] = vlist.toStripAndTriangleArrays();
356: if (ga[0] != null)
357: shapes.add(new Shape3D(ga[0], a));
358: if (ga[1] != null)
359: shapes.add(new Shape3D(ga[1], a));
360: break;
361: default:
362: throw new IllegalArgumentException(J3dUtilsI18N
363: .getString("GeometryDecompressorShape3D0"));
364: }
365: break;
366:
367: case TYPE_LINE:
368: LineStripArray lsa = vlist.toLineStripArray();
369: if (lsa != null)
370: shapes.add(new Shape3D(lsa, a));
371: break;
372:
373: case TYPE_POINT:
374: PointArray pa = vlist.toPointArray();
375: if (pa != null)
376: shapes.add(new Shape3D(pa, a));
377: break;
378:
379: default:
380: throw new IllegalArgumentException(J3dUtilsI18N
381: .getString("GeometryDecompressorShape3D1"));
382: }
383:
384: if (benchmark || statistics) {
385: origVertexCount += vlist.size();
386: vertexCount += vlist.vertexCount;
387: stripCount += vlist.stripCount;
388: triangleCount += vlist.triangleCount;
389: }
390: }
391:
392: private void beginPrint() {
393: System.out.println("\nGeometryDecompressorShape3D");
394:
395: switch (bufferDataType) {
396: case TYPE_TRIANGLE:
397: System.out.println(" buffer TYPE_TRIANGLE");
398: break;
399: case TYPE_LINE:
400: System.out.println(" buffer TYPE_LINE");
401: break;
402: case TYPE_POINT:
403: System.out.println(" buffer TYPE_POINT");
404: break;
405: default:
406: throw new IllegalArgumentException(J3dUtilsI18N
407: .getString("GeometryDecompressorShape3D1"));
408: }
409:
410: System.out.print(" buffer data present: coords");
411:
412: if ((dataPresent & CompressedGeometryData.Header.NORMAL_IN_BUFFER) != 0)
413: System.out.print(" normals");
414: if ((dataPresent & CompressedGeometryData.Header.COLOR_IN_BUFFER) != 0)
415: System.out.print(" colors");
416: if ((dataPresent & CompressedGeometryData.Header.ALPHA_IN_BUFFER) != 0)
417: System.out.print(" alpha");
418:
419: System.out.println();
420:
421: stripCount = 0;
422: vertexCount = 0;
423: triangleCount = 0;
424: origVertexCount = 0;
425:
426: startTime = System.currentTimeMillis();
427: }
428:
429: private void endPrint() {
430: endTime = System.currentTimeMillis();
431:
432: if (benchmark || statistics)
433: printBench();
434:
435: if (statistics)
436: printStats();
437: }
438:
439: private void printBench() {
440: float t = (endTime - startTime) / 1000.0f;
441: System.out.println(" decompression + strip conversion took "
442: + t + " sec.");
443:
444: switch (bufferDataType) {
445: case TYPE_POINT:
446: System.out.println(" points decompressed: " + vertexCount
447: + "\n" + " net decompression rate: "
448: + (vertexCount / t) + " points/sec.\n");
449: break;
450: case TYPE_LINE:
451: System.out.println(" lines decompressed: "
452: + (vertexCount - stripCount) + "\n"
453: + " net decompression rate: "
454: + ((vertexCount - stripCount) / t)
455: + " lines/sec.\n");
456: break;
457: case TYPE_TRIANGLE:
458: System.out.println(" triangles decompressed: "
459: + (vertexCount - 2 * stripCount) + "\n"
460: + " net decompression rate: "
461: + ((vertexCount - 2 * stripCount) / t)
462: + " triangles/sec.\n");
463: break;
464: }
465: }
466:
467: private void printStats() {
468: switch (triOutputType) {
469: case TRI_SET:
470: System.out.println(" using individual triangle output");
471: break;
472: case TRI_STRIP_SET:
473: System.out.println(" using strip output");
474: break;
475: case TRI_STRIP_AND_FAN_SET:
476: System.out.println(" using strips and fans for output");
477: break;
478: case TRI_STRIP_AND_TRI_SET:
479: System.out
480: .println(" using strips and triangles for output");
481: break;
482: }
483:
484: System.out.print(" number of Shape3D objects: " + shapes.size()
485: + "\n number of Shape3D decompressed vertices: ");
486:
487: if (triOutputType == TRI_SET || bufferDataType == TYPE_POINT) {
488: System.out.println(vertexCount);
489: } else if (triOutputType == TRI_STRIP_AND_TRI_SET) {
490: System.out.println((vertexCount + triangleCount * 3)
491: + "\n number of strips: " + stripCount
492: + "\n number of individual triangles: "
493: + triangleCount);
494: if (stripCount > 0)
495: System.out.println(" vertices/strip: "
496: + (float) vertexCount / stripCount
497: + "\n triangles represented in strips: "
498: + (vertexCount - 2 * stripCount));
499: } else {
500: System.out.println(vertexCount + "\n number of strips: "
501: + stripCount);
502: if (stripCount > 0)
503: System.out.println(" vertices/strip: "
504: + (float) vertexCount / stripCount);
505: }
506:
507: System.out
508: .print(" vertex data present in last Shape3D: coords");
509: if ((vlist.vertexFormat & GeometryArray.NORMALS) != 0)
510: System.out.print(" normals");
511:
512: boolean color4 = (vlist.vertexFormat & GeometryArray.COLOR_4) == GeometryArray.COLOR_4;
513: boolean color3 = !color4
514: && (vlist.vertexFormat & GeometryArray.COLOR_3) == GeometryArray.COLOR_3;
515: if (color3 || color4) {
516: System.out.print(" colors");
517: if (color4)
518: System.out.print(" alpha");
519: }
520: System.out.println();
521: }
522: }
|