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