001: /*
002: * $RCSfile: CompressedGeometryData.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:21 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.geometry.compression;
046:
047: import com.sun.j3d.internal.J3dUtilsI18N;
048: import javax.media.j3d.J3DBuffer;
049: import javax.media.j3d.Shape3D;
050: import javax.vecmath.Point3d;
051:
052: /**
053: * The compressed geometry object is used to store geometry in a
054: * compressed format. Using compressed geometry may increase the speed
055: * objects can be sent over the network. Note that the geometry will
056: * be decompressed in memory, so the application will not see any
057: * memory savings.
058: * <p>
059: * Compressed geometry may be passed to this CompressedGeometryData object
060: * in one of two ways: by copying the data into this object using the
061: * existing constructor, or by passing a reference to the data.
062: * <p>
063: * <ul>
064: * <li>
065: * <b>By Copying:</b>
066: * In by-copy mode, the CompressedGeometryData constructor copies the buffer of
067: * compressed geometry data into this CompressedGeometryData object. This
068: * is appropriate for many applications, and allows Java 3D to verify
069: * the data once and then not worry about it again.
070: * </li>
071: * <li><b>By Reference:</b>
072: * In by-reference mode, the
073: * compressed geometry data is accessed by reference, directly from
074: * the user's array. To use this feature, you need to construct a
075: * CompressedGeometryData object with the <code>byReference</code> flag
076: * set to <code>true</code>. In this mode, a reference to the input
077: * data is saved, but the data itself is not necessarily copied. Note
078: * that the compressed geometry header is still copied into this
079: * compressed geometry object. Data referenced by a
080: * CompressedGeometryData object must not be modified after the
081: * CompressedGeometryData object is constructed.
082: * Applications
083: * must exercise care not to violate this rule. If any referenced
084: * compressed geometry data is modified after construction,
085: * the results are undefined.
086: * </li>
087: * </ul>
088: *
089: * @since Java 3D 1.5
090: */
091: public class CompressedGeometryData extends Object {
092:
093: private Header cgHeader;
094: private CompressedGeometryRetained retained;
095:
096: /**
097: * Creates a new CompressedGeometryData object by copying
098: * the specified compressed geometry data into this object.
099: * If the version number of compressed geometry, as specified by
100: * the Header, is incompatible with the
101: * supported version of compressed geometry, then an exception
102: * will be thrown.
103: *
104: * @param hdr the compressed geometry header. This is copied
105: * into this CompressedGeometryData object.
106: *
107: * @param compressedGeometry the compressed geometry data. The
108: * geometry must conform to the format described in Appendix B of
109: * the <i>Java 3D API Specification</i>.
110: *
111: * @exception IllegalArgumentException if a problem is detected with the
112: * header.
113: */
114: public CompressedGeometryData(Header hdr, byte[] compressedGeometry) {
115:
116: this (hdr, compressedGeometry, false);
117: }
118:
119: /**
120: * Creates a new CompressedGeometryData object. The
121: * specified compressed geometry data is either copied into this
122: * object or is accessed by reference.
123: * If the version number of compressed geometry, as specified by
124: * the Header, is incompatible with the
125: * supported version of compressed geometry, then an exception
126: * will be thrown.
127: *
128: * @param hdr the compressed geometry header. This is copied
129: * into the CompressedGeometryData object.
130: *
131: * @param compressedGeometry the compressed geometry data. The
132: * geometry must conform to the format described in Appendix B of
133: * the <i>Java 3D API Specification</i>.
134: *
135: * @param byReference a flag that indicates whether the data is copied
136: * into this compressed geometry object or is accessed by reference.
137: *
138: * @exception IllegalArgumentException if a problem is detected with the
139: * header.
140: */
141: public CompressedGeometryData(Header hdr,
142: byte[] compressedGeometry, boolean byReference) {
143:
144: if ((hdr.size + hdr.start) > compressedGeometry.length) {
145: throw new IllegalArgumentException(J3dUtilsI18N
146: .getString("CompressedGeometry0"));
147: }
148:
149: // Create a separate copy of the given header.
150: cgHeader = new Header();
151: hdr.copy(cgHeader);
152:
153: // Create the retained object.
154: retained = new CompressedGeometryRetained();
155: this .retained.createCompressedGeometry(cgHeader,
156: compressedGeometry, byReference);
157:
158: // This constructor is designed to accept byte arrays that may contain
159: // possibly many large compressed geometry blocks interspersed with
160: // non-J3D-specific metadata. Only one of these blocks is used per
161: // CompressedGeometry object, so set the geometry offset to zero in
162: // the header if the data itself is copied.
163: if (!byReference)
164: cgHeader.start = 0;
165: }
166:
167: /**
168: * Creates a new CompressedGeometryData object. The
169: * specified compressed geometry data is accessed by reference
170: * from the specified buffer.
171: * If the version number of compressed geometry, as specified by
172: * the Header, is incompatible with the
173: * supported version of compressed geometry, then an exception
174: * will be thrown.
175: *
176: * @param hdr the compressed geometry header. This is copied
177: * into the CompressedGeometryData object.
178: *
179: * @param compressedGeometry a buffer containing an NIO byte buffer
180: * of compressed geometry data. The
181: * geometry must conform to the format described in Appendix B of
182: * the <i>Java 3D API Specification</i>.
183: *
184: * @exception UnsupportedOperationException this method is not
185: * yet implemented
186: *
187: * @exception IllegalArgumentException if a problem is detected with the
188: * header,
189: * or if the java.nio.Buffer contained in the specified J3DBuffer
190: * is not a java.nio.ByteBuffer object.
191: *
192: * @see Header
193: */
194: public CompressedGeometryData(Header hdr,
195: J3DBuffer compressedGeometry) {
196:
197: throw new UnsupportedOperationException("not implemented");
198: }
199:
200: /**
201: * Returns the size, in bytes, of the compressed geometry buffer.
202: * The size of the compressed geometry header is not included.
203: *
204: * @return the size, in bytes, of the compressed geometry buffer.
205: */
206: public int getByteCount() {
207: return cgHeader.size;
208: }
209:
210: /**
211: * Copies the compressed geometry header from the CompressedGeometryData
212: * object into the passed in parameter.
213: *
214: * @param hdr the Header object into which to copy the
215: * CompressedGeometryData object's header; the offset field may differ
216: * from that which was originally specified if a copy of the original
217: * compressed geometry byte array was created.
218: */
219: public void getCompressedGeometryHeader(Header hdr) {
220: cgHeader.copy(hdr);
221: }
222:
223: /**
224: * Retrieves the compressed geometry associated with the
225: * CompressedGeometryData object. Copies the compressed
226: * geometry from the CompressedGeometryData node into the given array.
227: * The array must be large enough to hold all of the bytes.
228: * The individual array elements must be allocated by the caller.
229: *
230: * @param compressedGeometry the array into which to copy the compressed
231: * geometry.
232: *
233: * @exception IllegalStateException if the data access mode for this
234: * object is by-reference.
235: *
236: * @exception ArrayIndexOutOfBoundsException if compressedGeometry byte
237: * array is not large enough to receive the compressed geometry
238: */
239: public void getCompressedGeometry(byte[] compressedGeometry) {
240: if (isByReference()) {
241: throw new IllegalStateException(J3dUtilsI18N
242: .getString("CompressedGeometry7"));
243: }
244:
245: if (cgHeader.size > compressedGeometry.length) {
246: throw new ArrayIndexOutOfBoundsException(J3dUtilsI18N
247: .getString("CompressedGeometry4"));
248: }
249:
250: this .retained.copy(compressedGeometry);
251: }
252:
253: /**
254: * Decompresses the compressed geometry. Returns an array of Shape nodes
255: * containing the decompressed geometry objects, or null if the version
256: * number of the compressed geometry is incompatible with the decompressor
257: * in the current version of Java 3D.
258: *
259: * @return an array of Shape nodes containing the
260: * geometry decompressed from this CompressedGeometryData
261: * object, or null if its version is incompatible
262: */
263: public Shape3D[] decompress() {
264: CompressedGeometryRetained cgr = this .retained;
265:
266: GeometryDecompressorShape3D decompressor = new GeometryDecompressorShape3D();
267:
268: // Decompress the geometry as TriangleStripArrays. A combination of
269: // TriangleStripArrays and TrianglesFanArrays is more compact but
270: // requires twice as many Shape3D objects, resulting in slower
271: // rendering performance.
272: //
273: // Using TriangleArray output is currently the fastest, given the
274: // strip sizes observed from various compressed geometry objects, but
275: // produces about twice as many vertices. TriangleStripArray produces
276: // the same number of Shape3D objects as TriangleArray using 1/2
277: // to 2/3 of the vertices, with only a marginal performance penalty.
278: //
279: return decompressor.toTriangleStripArrays(cgr);
280: }
281:
282: /**
283: * Retrieves the data access mode for this CompressedGeometryData object.
284: *
285: * @return <code>true</code> if the data access mode for this
286: * CompressedGeometryData object is by-reference;
287: * <code>false</code> if the data access mode is by-copying.
288: */
289: public boolean isByReference() {
290: return this .retained.isByReference();
291: }
292:
293: /**
294: * Gets the compressed geometry data reference.
295: *
296: * @return the current compressed geometry data reference.
297: *
298: * @exception IllegalStateException if the data access mode for this
299: * object is not by-reference.
300: */
301: public byte[] getCompressedGeometryRef() {
302: if (!isByReference()) {
303: throw new IllegalStateException(J3dUtilsI18N
304: .getString("CompressedGeometry8"));
305: }
306:
307: return this .retained.getReference();
308: }
309:
310: /**
311: * Gets the compressed geometry data buffer reference, which is
312: * always null since NIO buffers are not supported for
313: * CompressedGeometryData objects.
314: *
315: * @return null
316: */
317: public J3DBuffer getCompressedGeometryBuffer() {
318: return null;
319: }
320:
321: /**
322: * The Header class is a data container for the header information,
323: * used in conjunction with a CompressedGeometryData object.
324: * This information is used to aid the decompression of the compressed geometry.
325: *
326: * <p>
327: * All instance data is declared public and no get or set methods are
328: * provided.
329: *
330: * @since Java 3D 1.5
331: */
332: public static class Header extends Object {
333:
334: /**
335: * bufferType: compressed geometry is made up of individual points.
336: */
337: public static final int POINT_BUFFER = 0;
338:
339: /**
340: * bufferType: compressed geometry is made up of line segments.
341: */
342: public static final int LINE_BUFFER = 1;
343:
344: /**
345: * bufferType: compressed geometry is made up of triangles.
346: */
347: public static final int TRIANGLE_BUFFER = 2;
348:
349: // Valid values for the bufferDataPresent field.
350:
351: /**
352: * bufferDataPresent: bit indicating that normal information is
353: * bundled with the vertices in the compressed geometry buffer.
354: */
355: public static final int NORMAL_IN_BUFFER = 1;
356:
357: /**
358: * bufferDataPresent: bit indicating that RGB color information is
359: * bundled with the vertices in the compressed geometry buffer.
360: */
361: public static final int COLOR_IN_BUFFER = 2;
362:
363: /**
364: * bufferDataPresent: bit indicating that alpha information is
365: * bundled with the vertices in the compressed geometry buffer.
366: */
367: public static final int ALPHA_IN_BUFFER = 4;
368:
369: /**
370: * The major version number for the compressed geometry format that
371: * was used to compress the geometry.
372: * If the version number of compressed geometry is incompatible
373: * with the supported version of compressed geometry in the
374: * current version of Java 3D, the compressed geometry obejct will
375: * not be rendered.
376: *
377: * @see Canvas3D#queryProperties
378: */
379: public int majorVersionNumber;
380:
381: /**
382: * The minor version number for the compressed geometry format that
383: * was used to compress the geometry.
384: * If the version number of compressed geometry is incompatible
385: * with the supported version of compressed geometry in the
386: * current version of Java 3D, the compressed geometry obejct will
387: * not be rendered.
388: *
389: * @see Canvas3D#queryProperties
390: */
391: public int minorVersionNumber;
392:
393: /**
394: * The minor-minor version number for the compressed geometry format
395: * that was used to compress the geometry.
396: * If the version number of compressed geometry is incompatible
397: * with the supported version of compressed geometry in the
398: * current version of Java 3D, the compressed geometry obejct will
399: * not be rendered.
400: *
401: * @see Canvas3D#queryProperties
402: */
403: public int minorMinorVersionNumber;
404:
405: /**
406: * Describes the type of data in the compressed geometry buffer.
407: * Only one type may be present in any given compressed geometry
408: * buffer.
409: */
410: public int bufferType;
411:
412: /**
413: * Contains bits indicating what data is bundled with the vertices in the
414: * compressed geometry buffer. If this data is not present (e.g. color)
415: * then this info will be inherited from the Appearance node.
416: */
417: public int bufferDataPresent;
418:
419: /**
420: * Size of the compressed geometry in bytes.
421: */
422: public int size;
423:
424: /**
425: * Offset in bytes of the start of the compressed geometry from the
426: * beginning of the compressed geometry byte array passed to the
427: * CompressedGeometryData constructor. <p>
428: *
429: * If the CompressedGeometryData is created with reference access semantics,
430: * then this allow external compressors or file readers to embed several
431: * blocks of compressed geometry in a single large byte array, possibly
432: * interspersed with metadata that is not specific to Java 3D, without
433: * having to copy each block to a separate byte array. <p>
434: *
435: * If the CompressedGeometryData is created with copy access semantics, then
436: * <code>size</code> bytes of compressed geometry data are copied from the
437: * offset indicated by <code>start</code> instead of copying the entire
438: * byte array. The getCompressedGeometry() method will return only the
439: * bytes used to construct the object, and the getCompressedGeometryHeader()
440: * method will return a header with the <code>start</code> field set to 0.
441: */
442: public int start;
443:
444: /**
445: * A point that defines the lower bound of the <i>x</i>,
446: * <i>y</i>, and <i>z</i> components for all positions in the
447: * compressed geometry buffer. If null, a lower bound of
448: * (-1,-1,-1) is assumed. Java 3D will use this information to
449: * construct a bounding box around compressed geometry objects
450: * that are used in nodes for which the auto compute bounds flag
451: * is true. The default value for this point is null.
452: */
453: public Point3d lowerBound = null;
454:
455: /**
456: * A point that defines the upper bound of the <i>x</i>,
457: * <i>y</i>, and <i>z</i> components for all positions in the
458: * compressed geometry buffer. If null, an upper bound of (1,1,1)
459: * is assumed. Java 3D will use this information to construct a
460: * bounding box around compressed geometry objects that are used
461: * in nodes for which the auto compute bounds flag is true. The
462: * default value for this point is null.
463: */
464: public Point3d upperBound = null;
465:
466: /**
467: * Creates a new Header object used for the
468: * creation of a CompressedGeometryData object.
469: * All instance data is declared public and no get or set methods are
470: * provided. All values are set to 0 by default and must be filled
471: * in by the application.
472: *
473: * @see CompressedGeometryData
474: */
475: public Header() {
476: }
477:
478: /**
479: * Package-scoped method to copy current Header object
480: * to the passed-in Header object.
481: *
482: * @param hdr the Header object into which to copy the
483: * current Header.
484: */
485: void copy(Header hdr) {
486: hdr.majorVersionNumber = this .majorVersionNumber;
487: hdr.minorVersionNumber = this .minorVersionNumber;
488: hdr.minorMinorVersionNumber = this .minorMinorVersionNumber;
489: hdr.bufferType = this .bufferType;
490: hdr.bufferDataPresent = this .bufferDataPresent;
491: hdr.size = this .size;
492: hdr.start = this .start;
493: hdr.lowerBound = this .lowerBound;
494: hdr.upperBound = this .upperBound;
495: }
496:
497: /**
498: * Returns a String describing the contents of the
499: * Header object.
500: *
501: * @return a String describing contents of the compressed geometry header
502: */
503: public String toString() {
504: String type = "UNKNOWN";
505: switch (bufferType) {
506: case POINT_BUFFER:
507: type = "POINT_BUFFER";
508: break;
509: case LINE_BUFFER:
510: type = "LINE_BUFFER";
511: break;
512: case TRIANGLE_BUFFER:
513: type = "TRIANGLE_BUFFER";
514: break;
515: }
516:
517: String data = "";
518: if ((bufferDataPresent & NORMAL_IN_BUFFER) != 0)
519: data = data + "NORMALS ";
520: if ((bufferDataPresent & COLOR_IN_BUFFER) != 0)
521: data = data + "COLORS ";
522: if ((bufferDataPresent & ALPHA_IN_BUFFER) != 0)
523: data = data + "ALPHA ";
524:
525: String lbound = "null";
526: if (lowerBound != null)
527: lbound = lowerBound.toString();
528:
529: String ubound = "null";
530: if (upperBound != null)
531: ubound = upperBound.toString();
532:
533: return "majorVersionNumber: " + majorVersionNumber + " "
534: + "minorVersionNumber: " + minorVersionNumber
535: + " " + "minorMinorVersionNumber: "
536: + minorMinorVersionNumber + "\n" + "bufferType: "
537: + type + " " + "bufferDataPresent: " + data + "\n"
538: + "size: " + size + " " + "start: " + start + "\n"
539: + "lower bound: " + lbound + "\n" + "upper bound: "
540: + ubound + " ";
541: }
542: }
543: }
|