0001: /*
0002: * $RCSfile: CompressionStream.java,v $
0003: *
0004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * Redistribution and use in source and binary forms, with or without
0007: * modification, are permitted provided that the following conditions
0008: * are met:
0009: *
0010: * - Redistribution of source code must retain the above copyright
0011: * notice, this list of conditions and the following disclaimer.
0012: *
0013: * - Redistribution in binary form must reproduce the above copyright
0014: * notice, this list of conditions and the following disclaimer in
0015: * the documentation and/or other materials provided with the
0016: * distribution.
0017: *
0018: * Neither the name of Sun Microsystems, Inc. or the names of
0019: * contributors may be used to endorse or promote products derived
0020: * from this software without specific prior written permission.
0021: *
0022: * This software is provided "AS IS," without a warranty of any
0023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
0024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
0025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
0026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
0027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
0028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
0029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
0030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
0031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
0032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
0033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
0034: * POSSIBILITY OF SUCH DAMAGES.
0035: *
0036: * You acknowledge that this software is not designed, licensed or
0037: * intended for use in the design, construction, operation or
0038: * maintenance of any nuclear facility.
0039: *
0040: * $Revision: 1.3 $
0041: * $Date: 2007/02/09 17:20:22 $
0042: * $State: Exp $
0043: */
0044:
0045: package com.sun.j3d.utils.geometry.compression;
0046:
0047: import com.sun.j3d.internal.BufferWrapper;
0048: import com.sun.j3d.internal.ByteBufferWrapper;
0049: import com.sun.j3d.internal.DoubleBufferWrapper;
0050: import com.sun.j3d.internal.FloatBufferWrapper;
0051: import com.sun.j3d.utils.geometry.GeometryInfo;
0052: import java.util.Collection;
0053: import java.util.Iterator;
0054: import java.util.LinkedList;
0055: import javax.media.j3d.Appearance;
0056: import javax.media.j3d.Geometry;
0057: import javax.media.j3d.GeometryArray;
0058: import javax.media.j3d.GeometryStripArray;
0059: import javax.media.j3d.IndexedGeometryArray;
0060: import javax.media.j3d.IndexedGeometryStripArray;
0061: import javax.media.j3d.IndexedLineArray;
0062: import javax.media.j3d.IndexedLineStripArray;
0063: import javax.media.j3d.IndexedQuadArray;
0064: import javax.media.j3d.IndexedTriangleArray;
0065: import javax.media.j3d.IndexedTriangleFanArray;
0066: import javax.media.j3d.IndexedTriangleStripArray;
0067: import javax.media.j3d.J3DBuffer;
0068: import javax.media.j3d.LineArray;
0069: import javax.media.j3d.LineStripArray;
0070: import javax.media.j3d.Material;
0071: import javax.media.j3d.QuadArray;
0072: import javax.media.j3d.Shape3D;
0073: import javax.media.j3d.TriangleArray;
0074: import javax.media.j3d.TriangleFanArray;
0075: import javax.media.j3d.TriangleStripArray;
0076: import javax.vecmath.Color3f;
0077: import javax.vecmath.Color4f;
0078: import javax.vecmath.Point3d;
0079: import javax.vecmath.Point3f;
0080: import javax.vecmath.Point3i;
0081: import javax.vecmath.Vector3f;
0082:
0083: /**
0084: * This class is used as input to a geometry compressor. It collects elements
0085: * such as vertices, normals, colors, mesh references, and quantization
0086: * parameters in an ordered stream. This stream is then traversed during
0087: * the compression process and used to build the compressed output buffer.
0088: *
0089: * @see GeometryCompressor
0090: *
0091: * @since Java 3D 1.5
0092: */
0093: public class CompressionStream {
0094: //
0095: // NOTE: For now, copies are made of all GeometryArray vertex components
0096: // even when by-reference access is available.
0097: //
0098: // TODO: Retrofit all CompressionStreamElements and MeshBuffer to handle
0099: // offsets to vertex data array references so that vertex components don't
0100: // have to be copied. New CompressionStreamElements could be defined to
0101: // set the current array reference during the quantization pass, or the
0102: // reference could be included in every CompressionStreamElement along
0103: // with the data offsets.
0104: //
0105: // TODO: Quantize on-the-fly when adding GeometryArray vertex data so that
0106: // CompressionStreamElements don't need references to the original float,
0107: // double, or byte data. Quantization is currently a separate pass since
0108: // the 1st pass adds vertex data and gets the total object bounds, but
0109: // this can be computed by merging the bounds of each GeometryArray
0110: // compressed into a single object. The 2nd pass quantization is still
0111: // needed for vertex data which isn't retrieved from a GeometryArray; for
0112: // example, apps that might use the addVertex() methods directly instead
0113: // of addGeometryArray().
0114: //
0115: // TODO: To further optimize memory, create new subclasses of
0116: // CompressionStream{Color, Normal} for bundled attributes and add them as
0117: // explicit stream elements. Then CompressionStreamVertex won't need to
0118: // carry references to them. This memory savings might be negated by the
0119: // extra overhead of adding more elements to the stream, however.
0120: //
0121: // TODO: Keep the absolute quantized values in the mesh buffer mirror so
0122: // that unmeshed CompressionStreamElements don't need to carry them.
0123: //
0124: // TODO: Support texture coordinate compression even though Level II is
0125: // not supported by any hardware decompressor on any graphics card.
0126: // Software decompression is still useful for applications interested in
0127: // minimizing file space, transmission time, and object loading time.
0128: //
0129: private static final boolean debug = false;
0130: private static final boolean benchmark = false;
0131:
0132: // Mesh buffer normal substitution is unavailable in Level I.
0133: private static final boolean noMeshNormalSubstitution = true;
0134:
0135: /**
0136: * This flag indicates that a vertex starts a new triangle or line strip.
0137: */
0138: static final int RESTART = 1;
0139:
0140: /**
0141: * This flag indicates that the next triangle in the strip is defined by
0142: * replacing the middle vertex of the previous triangle in the strip.
0143: * Equivalent to REPLACE_OLDEST for line strips.
0144: */
0145: static final int REPLACE_MIDDLE = 2;
0146:
0147: /**
0148: * This flag indicates that the next triangle in the strip is defined by
0149: * replacing the oldest vertex of the previous triangle in the strip.
0150: * Equivalent to REPLACE_MIDDLE for line strips.
0151: */
0152: static final int REPLACE_OLDEST = 3;
0153:
0154: /**
0155: * This flag indicates that a vertex is to be pushed into the mesh buffer.
0156: */
0157: static final int MESH_PUSH = 1;
0158:
0159: /**
0160: * This flag indicates that a vertex does not use the mesh buffer.
0161: */
0162: static final int NO_MESH_PUSH = 0;
0163:
0164: /**
0165: * Byte to float scale factor for scaling byte color components.
0166: */
0167: static final float ByteToFloatScale = 1.0f / 255.0f;
0168:
0169: /**
0170: * Type of this stream, either CompressedGeometryData.Header.POINT_BUFFER,
0171: * CompressedGeometryData.Header.LINE_BUFFER, or
0172: * CompressedGeometryData.Header.TRIANGLE_BUFFER
0173: */
0174: int streamType;
0175:
0176: /**
0177: * A mask indicating which components are present in each vertex, as
0178: * defined by GeometryArray.
0179: */
0180: int vertexComponents;
0181:
0182: /**
0183: * Boolean indicating colors are bundled with the vertices.
0184: */
0185: boolean vertexColors;
0186:
0187: /**
0188: * Boolean indicating RGB colors are bundled with the vertices.
0189: */
0190: boolean vertexColor3;
0191:
0192: /**
0193: * Boolean indicating RGBA colors are bundled with the vertices.
0194: */
0195: boolean vertexColor4;
0196:
0197: /**
0198: * Boolean indicating normals are bundled with the vertices.
0199: */
0200: boolean vertexNormals;
0201:
0202: /**
0203: * Boolean indicating texture coordinates are present.
0204: */
0205: boolean vertexTextures;
0206:
0207: /**
0208: * Boolean indicating that 2D texture coordinates are used.
0209: * Currently only used to skip over textures in interleaved data.
0210: */
0211: boolean vertexTexture2;
0212:
0213: /**
0214: * Boolean indicating that 3D texture coordinates are used.
0215: * Currently only used to skip over textures in interleaved data.
0216: */
0217: boolean vertexTexture3;
0218:
0219: /**
0220: * Boolean indicating that 4D texture coordinates are used.
0221: * Currently only used to skip over textures in interleaved data.
0222: */
0223: boolean vertexTexture4;
0224:
0225: /**
0226: * Axes-aligned box enclosing all vertices in model coordinates.
0227: */
0228: Point3d mcBounds[] = new Point3d[2];
0229:
0230: /**
0231: * Axes-aligned box enclosing all vertices in normalized coordinates.
0232: */
0233: Point3d ncBounds[] = new Point3d[2];
0234:
0235: /**
0236: * Axes-aligned box enclosing all vertices in quantized coordinates.
0237: */
0238: Point3i qcBounds[] = new Point3i[2];
0239:
0240: /**
0241: * Center for normalizing positions to the unit cube.
0242: */
0243: double center[] = new double[3];
0244:
0245: /**
0246: * Maximum position range along the 3 axes.
0247: */
0248: double positionRangeMaximum;
0249:
0250: /**
0251: * Scale for normalizing positions to the unit cube.
0252: */
0253: double scale;
0254:
0255: /**
0256: * Current position component (X, Y, and Z) quantization value. This can
0257: * range from 1 to 16 bits and has a default of 16.<p>
0258: *
0259: * At 1 bit of quantization it is not possible to express positive
0260: * absolute or delta positions.
0261: */
0262: int positionQuant;
0263:
0264: /**
0265: * Current color component (R, G, B, A) quantization value. This can
0266: * range from 2 to 16 bits and has a default of 9.<p>
0267: *
0268: * A color component is represented with a signed fixed-point value in
0269: * order to be able express negative deltas; the default of 9 bits
0270: * corresponds to the 8-bit color component range of the graphics hardware
0271: * commonly available. Colors must be non-negative, so the lower limit of
0272: * quantization is 2 bits.
0273: */
0274: int colorQuant;
0275:
0276: /**
0277: * Current normal component (U and V) quantization value. This can range
0278: * from 0 to 6 bits and has a default of 6.<p>
0279: *
0280: * At 0 bits of quantization normals are represented only as 6 bit
0281: * sextant/octant pairs and 14 specially encoded normals (the 6 axis
0282: * normals and the 8 octant midpoint normals); since U and V can only be 0
0283: * at the minimum quantization, the totally number of unique normals is
0284: * 12 + 14 = 26.
0285: */
0286: int normalQuant;
0287:
0288: /**
0289: * Flag indicating position quantization change.
0290: */
0291: boolean positionQuantChanged;
0292:
0293: /**
0294: * Flag indicating color quantization change.
0295: */
0296: boolean colorQuantChanged;
0297:
0298: /**
0299: * Flag indicating normal quantization change.
0300: */
0301: boolean normalQuantChanged;
0302:
0303: /**
0304: * Last quantized position.
0305: */
0306: int lastPosition[] = new int[3];
0307:
0308: /**
0309: * Last quantized color.
0310: */
0311: int lastColor[] = new int[4];
0312:
0313: /**
0314: * Last quantized normal's sextant.
0315: */
0316: int lastSextant;
0317:
0318: /**
0319: * Last quantized normal's octant.
0320: */
0321: int lastOctant;
0322:
0323: /**
0324: * Last quantized normal's U encoding parameter.
0325: */
0326: int lastU;
0327:
0328: /**
0329: * Last quantized normal's V encoding parameter.
0330: */
0331: int lastV;
0332:
0333: /**
0334: * Flag indicating last normal used a special encoding.
0335: */
0336: boolean lastSpecialNormal;
0337:
0338: /**
0339: * Flag indicating the first position in this stream.
0340: */
0341: boolean firstPosition;
0342:
0343: /**
0344: * Flag indicating the first color in this stream.
0345: */
0346: boolean firstColor;
0347:
0348: /**
0349: * Flag indicating the first normal in this stream.
0350: */
0351: boolean firstNormal;
0352:
0353: /**
0354: * The total number of bytes used to create the uncompressed geometric
0355: * elements in this stream, useful for performance analysis. This
0356: * excludes mesh buffer references.
0357: */
0358: int byteCount;
0359:
0360: /**
0361: * The number of vertices created for this stream, excluding mesh buffer
0362: * references.
0363: */
0364: int vertexCount;
0365:
0366: /**
0367: * The number of mesh buffer references created for this stream.
0368: */
0369: int meshReferenceCount;
0370:
0371: /**
0372: * Mesh buffer mirror used for computing deltas during quantization pass
0373: * and a limited meshing algorithm for unstripped data.
0374: */
0375: MeshBuffer meshBuffer = new MeshBuffer();
0376:
0377: // Collection which holds the elements of this stream.
0378: private Collection stream;
0379:
0380: // True if preceding stream elements were colors or normals. Used to flag
0381: // color and normal mesh buffer substitution when computing deltas during
0382: // quantization pass.
0383: private boolean lastElementColor = false;
0384: private boolean lastLastElementColor = false;
0385: private boolean lastElementNormal = false;
0386: private boolean lastLastElementNormal = false;
0387:
0388: // Some convenient temporary holding variables.
0389: private Point3f p3f = new Point3f();
0390: private Color3f c3f = new Color3f();
0391: private Color4f c4f = new Color4f();
0392: private Vector3f n3f = new Vector3f();
0393:
0394: // Private constructor for common initializations.
0395: private CompressionStream() {
0396: this .stream = new LinkedList();
0397:
0398: byteCount = 0;
0399: vertexCount = 0;
0400: meshReferenceCount = 0;
0401:
0402: mcBounds[0] = new Point3d(Double.POSITIVE_INFINITY,
0403: Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY);
0404: mcBounds[1] = new Point3d(Double.NEGATIVE_INFINITY,
0405: Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY);
0406:
0407: qcBounds[0] = new Point3i(Integer.MAX_VALUE, Integer.MAX_VALUE,
0408: Integer.MAX_VALUE);
0409: qcBounds[1] = new Point3i(Integer.MIN_VALUE, Integer.MIN_VALUE,
0410: Integer.MIN_VALUE);
0411:
0412: /* normalized bounds computed from quantized bounds */
0413: ncBounds[0] = new Point3d();
0414: ncBounds[1] = new Point3d();
0415: }
0416:
0417: /**
0418: * Creates a new CompressionStream for the specified geometry type and
0419: * vertex format.<p>
0420: *
0421: * @param streamType type of data in this stream, either
0422: * CompressedGeometryData.Header.POINT_BUFFER,
0423: * CompressedGeometryData.Header.LINE_BUFFER, or
0424: * CompressedGeometryData.Header.TRIANGLE_BUFFER
0425: * @param vertexComponents a mask indicating which components are present
0426: * in each vertex, as defined by GeometryArray: COORDINATES, NORMALS, and
0427: * COLOR_3 or COLOR_4.
0428: * @see GeometryCompressor
0429: * @see GeometryArray
0430: */
0431: CompressionStream(int streamType, int vertexComponents) {
0432: this ();
0433: this .streamType = streamType;
0434: this .vertexComponents = getVertexComponents(vertexComponents);
0435: }
0436:
0437: // See what vertex geometry components are present. The byReference,
0438: // interleaved, useNIOBuffer, and useCoordIndexOnly flags are not
0439: // examined.
0440: private int getVertexComponents(int vertexFormat) {
0441: int components = 0;
0442:
0443: vertexColors = vertexColor3 = vertexColor4 = vertexNormals = vertexTextures = vertexTexture2 = vertexTexture3 = vertexTexture4 = false;
0444:
0445: if ((vertexFormat & GeometryArray.NORMALS) != 0) {
0446: vertexNormals = true;
0447: components &= GeometryArray.NORMALS;
0448: if (debug)
0449: System.out.println("vertexNormals");
0450: }
0451:
0452: if ((vertexFormat & GeometryArray.COLOR_3) != 0) {
0453: vertexColors = true;
0454:
0455: if ((vertexFormat & GeometryArray.COLOR_4) != 0) {
0456: vertexColor4 = true;
0457: components &= GeometryArray.COLOR_4;
0458: if (debug)
0459: System.out.println("vertexColor4");
0460: } else {
0461: vertexColor3 = true;
0462: components &= GeometryArray.COLOR_3;
0463: if (debug)
0464: System.out.println("vertexColor3");
0465: }
0466: }
0467:
0468: if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_2) != 0) {
0469: vertexTextures = true;
0470: vertexTexture2 = true;
0471: components &= GeometryArray.TEXTURE_COORDINATE_2;
0472: if (debug)
0473: System.out.println("vertexTexture2");
0474: } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_3) != 0) {
0475: vertexTextures = true;
0476: vertexTexture3 = true;
0477: components &= GeometryArray.TEXTURE_COORDINATE_3;
0478: if (debug)
0479: System.out.println("vertexTexture3");
0480: } else if ((vertexFormat & GeometryArray.TEXTURE_COORDINATE_4) != 0) {
0481: vertexTextures = true;
0482: vertexTexture4 = true;
0483: components &= GeometryArray.TEXTURE_COORDINATE_4;
0484: if (debug)
0485: System.out.println("vertexTexture4");
0486: }
0487:
0488: if (vertexTextures)
0489: // Throw exception for now until texture is supported.
0490: throw new UnsupportedOperationException(
0491: "\ncompression of texture coordinates is not supported");
0492:
0493: return components;
0494: }
0495:
0496: // Get the streamType associated with a GeometryArray instance.
0497: private int getStreamType(GeometryArray ga) {
0498: if (ga instanceof TriangleStripArray
0499: || ga instanceof IndexedTriangleStripArray
0500: || ga instanceof TriangleFanArray
0501: || ga instanceof IndexedTriangleFanArray
0502: || ga instanceof TriangleArray
0503: || ga instanceof IndexedTriangleArray
0504: || ga instanceof QuadArray
0505: || ga instanceof IndexedQuadArray)
0506:
0507: return CompressedGeometryData.Header.TRIANGLE_BUFFER;
0508:
0509: else if (ga instanceof LineArray
0510: || ga instanceof IndexedLineArray
0511: || ga instanceof LineStripArray
0512: || ga instanceof IndexedLineStripArray)
0513:
0514: return CompressedGeometryData.Header.LINE_BUFFER;
0515:
0516: else
0517: return CompressedGeometryData.Header.POINT_BUFFER;
0518: }
0519:
0520: /**
0521: * Iterates across all compression stream elements and applies
0522: * quantization parameters, encoding consecutive vertices as delta values
0523: * whenever possible. Each geometric element is mapped to a HuffmanNode
0524: * object containing its resulting bit length, right shift (trailing 0
0525: * count), and absolute or relative status.<p>
0526: *
0527: * Positions are normalized to span a unit cube via an offset and a
0528: * uniform scale factor that maps the midpoint of the object extents along
0529: * each dimension to the origin, and the longest dimension of the object to
0530: * the open interval (-1.0 .. +1.0). The geometric endpoints along that
0531: * dimension are both one quantum away from unity; for example, at a
0532: * position quantization of 6 bits, an object would be normalized so that
0533: * its most negative dimension is at (-1 + 1/64) and the most positive is
0534: * at (1 - 1/64).<p>
0535: *
0536: * Normals are assumed to be of unit length. Color components are clamped
0537: * to the [0..1) range, where the right endpoint is one quantum less
0538: * than 1.0.<p>
0539: *
0540: * @param huffmanTable Table which will map geometric compression stream
0541: * elements to HuffmanNode objects describing each element's data
0542: * representation. This table can then be processed with Huffman's
0543: * algorithm to optimize the bit length of descriptor tags according to
0544: * the number of geometric elements mapped to each tag.
0545: */
0546: void quantize(HuffmanTable huffmanTable) {
0547: // Set up default initial quantization parameters. The position and
0548: // color parameters specify the number of bits for each X, Y, Z, R, G,
0549: // B, or A component. The normal quantization parameter specifies the
0550: // number of bits for each U and V component.
0551: positionQuant = 16;
0552: colorQuant = 9;
0553: normalQuant = 6;
0554:
0555: // Compute position center and scaling for normalization to the unit
0556: // cube. This is a volume bounded by the open intervals (-1..1) on
0557: // each axis.
0558: center[0] = (mcBounds[1].x + mcBounds[0].x) / 2.0;
0559: center[1] = (mcBounds[1].y + mcBounds[0].y) / 2.0;
0560: center[2] = (mcBounds[1].z + mcBounds[0].z) / 2.0;
0561:
0562: double xRange = mcBounds[1].x - mcBounds[0].x;
0563: double yRange = mcBounds[1].y - mcBounds[0].y;
0564: double zRange = mcBounds[1].z - mcBounds[0].z;
0565:
0566: if (xRange > yRange)
0567: positionRangeMaximum = xRange;
0568: else
0569: positionRangeMaximum = yRange;
0570:
0571: if (zRange > positionRangeMaximum)
0572: positionRangeMaximum = zRange;
0573:
0574: // Adjust the range of the unit cube to match the default
0575: // quantization.
0576: //
0577: // This scale factor along with the center values computed above will
0578: // produce 16-bit integer representations of the floating point
0579: // position coordinates ranging symmetrically about 0 from -32767 to
0580: // +32767. -32768 is not used and the normalized floating point
0581: // position coordinates of -1.0 as well as +1.0 will not be
0582: // represented.
0583: //
0584: // Applications which wish to seamlessly stitch together compressed
0585: // objects will need to be aware that the range of normalized
0586: // positions will be one quantum away from the [-1..1] endpoints of
0587: // the unit cube and should adjust scale factors accordingly.
0588: scale = (2.0 / positionRangeMaximum) * (32767.0 / 32768.0);
0589:
0590: // Flag quantization change.
0591: positionQuantChanged = colorQuantChanged = normalQuantChanged = true;
0592:
0593: // Flag first position, color, and normal.
0594: firstPosition = firstColor = firstNormal = true;
0595:
0596: // Apply quantization.
0597: Iterator i = stream.iterator();
0598: while (i.hasNext()) {
0599: Object o = i.next();
0600:
0601: if (o instanceof CompressionStreamElement) {
0602: ((CompressionStreamElement) o).quantize(this ,
0603: huffmanTable);
0604:
0605: // Keep track of whether last two elements were colors or
0606: // normals for mesh buffer component substitution semantics.
0607: lastLastElementColor = lastElementColor;
0608: lastLastElementNormal = lastElementNormal;
0609: lastElementColor = lastElementNormal = false;
0610:
0611: if (o instanceof CompressionStreamColor)
0612: lastElementColor = true;
0613: else if (o instanceof CompressionStreamNormal)
0614: lastElementNormal = true;
0615: }
0616: }
0617:
0618: // Compute the bounds in normalized coordinates.
0619: ncBounds[0].x = (double) qcBounds[0].x / 32768.0;
0620: ncBounds[0].y = (double) qcBounds[0].y / 32768.0;
0621: ncBounds[0].z = (double) qcBounds[0].z / 32768.0;
0622:
0623: ncBounds[1].x = (double) qcBounds[1].x / 32768.0;
0624: ncBounds[1].y = (double) qcBounds[1].y / 32768.0;
0625: ncBounds[1].z = (double) qcBounds[1].z / 32768.0;
0626: }
0627:
0628: /**
0629: * Iterates across all compression stream elements and builds the
0630: * compressed geometry command stream output.<p>
0631: *
0632: * @param huffmanTable Table which maps geometric elements in this stream
0633: * to tags describing the encoding parameters (length, shift, and
0634: * absolute/relative status) to be used for their representations in the
0635: * compressed output. All tags must be 6 bits or less in length, and the
0636: * sum of the number of bits in the tag plus the number of bits in the
0637: * data it describes must be at least 6 bits in length.
0638: *
0639: * @param outputBuffer CommandStream to use for collecting the compressed
0640: * bits.
0641: */
0642: void outputCommands(HuffmanTable huffmanTable,
0643: CommandStream outputBuffer) {
0644: //
0645: // The first command output is setState to indicate what data is
0646: // bundled with each vertex. Although the semantics of geometry
0647: // decompression allow setState to appear anywhere in the stream, this
0648: // cannot be handled by the current Java 3D software decompressor,
0649: // which internally decompresses an entire compressed buffer into a
0650: // single retained object sharing a single consistent vertex format.
0651: // This limitation may be removed in subsequent releases of Java 3D.
0652: //
0653: int bnv = (vertexNormals ? 1 : 0);
0654: int bcv = ((vertexColor3 || vertexColor4) ? 1 : 0);
0655: int cap = (vertexColor4 ? 1 : 0);
0656:
0657: int command = CommandStream.SET_STATE | bnv;
0658: long data = (bcv << 2) | (cap << 1);
0659:
0660: // Output the setState command.
0661: outputBuffer.addCommand(command, 8, data, 3);
0662:
0663: // Output the Huffman table commands.
0664: huffmanTable.outputCommands(outputBuffer);
0665:
0666: // Output each compression stream element's data.
0667: Iterator i = stream.iterator();
0668: while (i.hasNext()) {
0669: Object o = i.next();
0670: if (o instanceof CompressionStreamElement)
0671: ((CompressionStreamElement) o).outputCommand(
0672: huffmanTable, outputBuffer);
0673: }
0674:
0675: // Finish the header-forwarding interleave and long-word align.
0676: outputBuffer.end();
0677: }
0678:
0679: /**
0680: * Retrieve the total size of the uncompressed geometric data in bytes,
0681: * excluding mesh buffer references.
0682: * @return uncompressed byte count
0683: */
0684: int getByteCount() {
0685: return byteCount;
0686: }
0687:
0688: /**
0689: * Retrieve the the number of vertices created for this stream, excluding
0690: * mesh buffer references.
0691: * @return vertex count
0692: */
0693: int getVertexCount() {
0694: return vertexCount;
0695: }
0696:
0697: /**
0698: * Retrieve the number of mesh buffer references created for this stream.
0699: * @return mesh buffer reference count
0700: */
0701: int getMeshReferenceCount() {
0702: return meshReferenceCount;
0703: }
0704:
0705: /**
0706: * Stream element that sets position quantization during quantize pass.
0707: */
0708: private class PositionQuant extends CompressionStreamElement {
0709: int value;
0710:
0711: PositionQuant(int value) {
0712: this .value = value;
0713: }
0714:
0715: void quantize(CompressionStream s, HuffmanTable t) {
0716: positionQuant = value;
0717: positionQuantChanged = true;
0718:
0719: // Adjust range of unit cube scaling to match quantization.
0720: scale = (2.0 / positionRangeMaximum)
0721: * (((double) ((1 << (value - 1)) - 1)) / ((double) (1 << (value - 1))));
0722: }
0723:
0724: public String toString() {
0725: return "positionQuant: " + value;
0726: }
0727: }
0728:
0729: /**
0730: * Stream element that sets normal quantization during quantize pass.
0731: */
0732: private class NormalQuant extends CompressionStreamElement {
0733: int value;
0734:
0735: NormalQuant(int value) {
0736: this .value = value;
0737: }
0738:
0739: void quantize(CompressionStream s, HuffmanTable t) {
0740: normalQuant = value;
0741: normalQuantChanged = true;
0742: }
0743:
0744: public String toString() {
0745: return "normalQuant: " + value;
0746: }
0747: }
0748:
0749: /**
0750: * Stream element that sets color quantization during quantize pass.
0751: */
0752: private class ColorQuant extends CompressionStreamElement {
0753: int value;
0754:
0755: ColorQuant(int value) {
0756: this .value = value;
0757: }
0758:
0759: void quantize(CompressionStream s, HuffmanTable t) {
0760: colorQuant = value;
0761: colorQuantChanged = true;
0762: }
0763:
0764: public String toString() {
0765: return "colorQuant: " + value;
0766: }
0767: }
0768:
0769: /**
0770: * Stream element that references the mesh buffer.
0771: */
0772: private class MeshReference extends CompressionStreamElement {
0773: int stripFlag, meshIndex;
0774:
0775: MeshReference(int stripFlag, int meshIndex) {
0776: this .stripFlag = stripFlag;
0777: this .meshIndex = meshIndex;
0778: meshReferenceCount++;
0779: }
0780:
0781: void quantize(CompressionStream s, HuffmanTable t) {
0782: // Retrieve the vertex from the mesh buffer mirror and set up the
0783: // data needed for the next stream element to compute its deltas.
0784: CompressionStreamVertex v = meshBuffer.getVertex(meshIndex);
0785: lastPosition[0] = v.xAbsolute;
0786: lastPosition[1] = v.yAbsolute;
0787: lastPosition[2] = v.zAbsolute;
0788:
0789: // Set up last color data if it exists and previous elements
0790: // don't override it.
0791: if (v.color != null && !lastElementColor
0792: && !(lastElementNormal && lastLastElementColor)) {
0793: lastColor[0] = v.color.rAbsolute;
0794: lastColor[1] = v.color.gAbsolute;
0795: lastColor[2] = v.color.bAbsolute;
0796: lastColor[3] = v.color.aAbsolute;
0797: }
0798:
0799: // Set up last normal data if it exists and previous element
0800: // doesn't override it.
0801: if (v.normal != null && !lastElementNormal
0802: && !(lastElementColor && lastLastElementNormal)) {
0803: lastSextant = v.normal.sextant;
0804: lastOctant = v.normal.octant;
0805: lastU = v.normal.uAbsolute;
0806: lastV = v.normal.vAbsolute;
0807: lastSpecialNormal = v.normal.specialNormal;
0808: }
0809: }
0810:
0811: void outputCommand(HuffmanTable t, CommandStream outputBuffer) {
0812: int command = CommandStream.MESH_B_R;
0813: long data = stripFlag & 0x1;
0814:
0815: command |= (((meshIndex & 0xf) << 1) | (stripFlag >> 1));
0816: outputBuffer.addCommand(command, 8, data, 1);
0817: }
0818:
0819: public String toString() {
0820: return "meshReference: stripFlag " + stripFlag
0821: + " meshIndex " + meshIndex;
0822: }
0823: }
0824:
0825: /**
0826: * Copy vertex data and add it to the end of this stream.
0827: * @param pos position data
0828: * @param stripFlag vertex replacement flag, either RESTART,
0829: * REPLACE_OLDEST, or REPLACE_MIDDLE
0830: */
0831: void addVertex(Point3f pos, int stripFlag) {
0832: stream.add(new CompressionStreamVertex(this , pos,
0833: (Vector3f) null, (Color3f) null, stripFlag,
0834: NO_MESH_PUSH));
0835: }
0836:
0837: /**
0838: * Copy vertex data and add it to the end of this stream.
0839: * @param pos position data
0840: * @param norm normal data
0841: * @param stripFlag vertex replacement flag, either RESTART,
0842: * REPLACE_OLDEST, or REPLACE_MIDDLE
0843: */
0844: void addVertex(Point3f pos, Vector3f norm, int stripFlag) {
0845: stream.add(new CompressionStreamVertex(this , pos, norm,
0846: (Color3f) null, stripFlag, NO_MESH_PUSH));
0847: }
0848:
0849: /**
0850: * Copy vertex data and add it to the end of this stream.
0851: * @param pos position data
0852: * @param color color data
0853: * @param stripFlag vertex replacement flag, either RESTART,
0854: * REPLACE_OLDEST, or REPLACE_MIDDLE
0855: */
0856: void addVertex(Point3f pos, Color3f color, int stripFlag) {
0857: stream.add(new CompressionStreamVertex(this , pos,
0858: (Vector3f) null, color, stripFlag, NO_MESH_PUSH));
0859: }
0860:
0861: /**
0862: * Copy vertex data and add it to the end of this stream.
0863: * @param pos position data
0864: * @param color color data
0865: * @param stripFlag vertex replacement flag, either RESTART,
0866: * REPLACE_OLDEST, or REPLACE_MIDDLE
0867: */
0868: void addVertex(Point3f pos, Color4f color, int stripFlag) {
0869: stream.add(new CompressionStreamVertex(this , pos,
0870: (Vector3f) null, color, stripFlag, NO_MESH_PUSH));
0871: }
0872:
0873: /**
0874: * Copy vertex data and add it to the end of this stream.
0875: * @param pos position data
0876: * @param norm normal data
0877: * @param color color data
0878: * @param stripFlag vertex replacement flag, either RESTART,
0879: * REPLACE_OLDEST, or REPLACE_MIDDLE
0880: */
0881: void addVertex(Point3f pos, Vector3f norm, Color3f color,
0882: int stripFlag) {
0883: stream.add(new CompressionStreamVertex(this , pos, norm, color,
0884: stripFlag, NO_MESH_PUSH));
0885: }
0886:
0887: /**
0888: * Copy vertex data and add it to the end of this stream.
0889: * @param pos position data
0890: * @param norm normal data
0891: * @param color color data
0892: * @param stripFlag vertex replacement flag, either RESTART,
0893: * REPLACE_OLDEST, or REPLACE_MIDDLE
0894: */
0895: void addVertex(Point3f pos, Vector3f norm, Color4f color,
0896: int stripFlag) {
0897: stream.add(new CompressionStreamVertex(this , pos, norm, color,
0898: stripFlag, NO_MESH_PUSH));
0899: }
0900:
0901: /**
0902: * Copy vertex data and add it to the end of this stream.
0903: * @param pos position data
0904: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0905: * or REPLACE_MIDDLE
0906: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0907: */
0908: void addVertex(Point3f pos, int stripFlag, int meshFlag) {
0909: stream.add(new CompressionStreamVertex(this , pos,
0910: (Vector3f) null, (Color3f) null, stripFlag, meshFlag));
0911: }
0912:
0913: /**
0914: * Copy vertex data and add it to the end of this stream.
0915: * @param pos position data
0916: * @param norm normal data
0917: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0918: * or REPLACE_MIDDLE
0919: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0920: */
0921: void addVertex(Point3f pos, Vector3f norm, int stripFlag,
0922: int meshFlag) {
0923: stream.add(new CompressionStreamVertex(this , pos, norm,
0924: (Color3f) null, stripFlag, meshFlag));
0925: }
0926:
0927: /**
0928: * Copy vertex data and add it to the end of this stream.
0929: * @param pos position data
0930: * @param color color data
0931: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0932: * or REPLACE_MIDDLE
0933: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0934: */
0935: void addVertex(Point3f pos, Color3f color, int stripFlag,
0936: int meshFlag) {
0937: stream.add(new CompressionStreamVertex(this , pos,
0938: (Vector3f) null, color, stripFlag, meshFlag));
0939: }
0940:
0941: /**
0942: * Copy vertex data and add it to the end of this stream.
0943: * @param pos position data
0944: * @param color color data
0945: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0946: * or REPLACE_MIDDLE
0947: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0948: */
0949: void addVertex(Point3f pos, Color4f color, int stripFlag,
0950: int meshFlag) {
0951: stream.add(new CompressionStreamVertex(this , pos,
0952: (Vector3f) null, color, stripFlag, meshFlag));
0953: }
0954:
0955: /**
0956: * Copy vertex data and add it to the end of this stream.
0957: * @param pos position data
0958: * @param norm normal data
0959: * @param color color data
0960: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0961: * or REPLACE_MIDDLE
0962: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0963: */
0964: void addVertex(Point3f pos, Vector3f norm, Color3f color,
0965: int stripFlag, int meshFlag) {
0966: stream.add(new CompressionStreamVertex(this , pos, norm, color,
0967: stripFlag, meshFlag));
0968: }
0969:
0970: /**
0971: * Copy vertex data and add it to the end of this stream.
0972: * @param pos position data
0973: * @param norm normal data
0974: * @param color color data
0975: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0976: * or REPLACE_MIDDLE
0977: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0978: */
0979: void addVertex(Point3f pos, Vector3f norm, Color4f color,
0980: int stripFlag, int meshFlag) {
0981: stream.add(new CompressionStreamVertex(this , pos, norm, color,
0982: stripFlag, meshFlag));
0983: }
0984:
0985: /**
0986: * Copy vertex data and add it to the end of this stream.
0987: * @param pos position data
0988: * @param norm normal data
0989: * @param color color data, either Color3f or Color4f, determined by
0990: * current vertex format
0991: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
0992: * or REPLACE_MIDDLE
0993: * @param meshFlag if MESH_PUSH the vertex is pushed into the mesh buffer
0994: */
0995: void addVertex(Point3f pos, Vector3f norm, Object color,
0996: int stripFlag, int meshFlag) {
0997:
0998: if (vertexColor3)
0999: stream.add(new CompressionStreamVertex(this , pos, norm,
1000: (Color3f) color, stripFlag, meshFlag));
1001: else
1002: stream.add(new CompressionStreamVertex(this , pos, norm,
1003: (Color4f) color, stripFlag, meshFlag));
1004: }
1005:
1006: /**
1007: * Add a mesh buffer reference to this stream.
1008: * @param stripFlag vertex replacement flag, either RESTART, REPLACE_OLDEST,
1009: * or REPLACE_MIDDLE
1010: * @param meshIndex index of vertex to retrieve from the mesh buffer
1011: */
1012: void addMeshReference(int stripFlag, int meshIndex) {
1013: stream.add(new MeshReference(stripFlag, meshIndex));
1014: }
1015:
1016: /**
1017: * Copy the given color to the end of this stream and use it as a global
1018: * state change that applies to all subsequent vertices.
1019: */
1020: void addColor(Color3f c3f) {
1021: stream.add(new CompressionStreamColor(this , c3f));
1022: }
1023:
1024: /**
1025: * Copy the given color to the end of this stream and use it as a global
1026: * state change that applies to all subsequent vertices.
1027: */
1028: void addColor(Color4f c4f) {
1029: stream.add(new CompressionStreamColor(this , c4f));
1030: }
1031:
1032: /**
1033: * Copy the given normal to the end of this stream and use it as a global
1034: * state change that applies to all subsequent vertices.
1035: */
1036: void addNormal(Vector3f n) {
1037: stream.add(new CompressionStreamNormal(this , n));
1038: }
1039:
1040: /**
1041: * Add a new position quantization value to the end of this stream that
1042: * will apply to all subsequent vertex positions.
1043: *
1044: * @param value number of bits to quantize each position's X, Y,
1045: * and Z components, ranging from 1 to 16 with a default of 16
1046: */
1047: void addPositionQuantization(int value) {
1048: stream.add(new PositionQuant(value));
1049: }
1050:
1051: /**
1052: * Add a new color quantization value to the end of this stream that will
1053: * apply to all subsequent colors.
1054: *
1055: * @param value number of bits to quantize each color's R, G, B, and
1056: * alpha components, ranging from 2 to 16 with a default of 9
1057: */
1058: void addColorQuantization(int value) {
1059: stream.add(new ColorQuant(value));
1060: }
1061:
1062: /**
1063: * Add a new normal quantization value to the end of this stream that will
1064: * apply to all subsequent normals. This value specifies the number of
1065: * bits for each normal's U and V components.
1066: *
1067: * @param value number of bits for quantizing U and V, ranging from 0 to
1068: * 6 with a default of 6
1069: */
1070: void addNormalQuantization(int value) {
1071: stream.add(new NormalQuant(value));
1072: }
1073:
1074: /**
1075: * Interface to access GeometryArray vertex components and add them to the
1076: * compression stream.
1077: *
1078: * A processVertex() implementation retrieves vertex components using the
1079: * appropriate access semantics of a particular GeometryArray, and adds
1080: * them to the compression stream.
1081: *
1082: * The implementation always pushes vertices into the mesh buffer unless
1083: * they match ones already there; if they do, it generates mesh buffer
1084: * references instead. This reduces the number of vertices when
1085: * non-stripped abutting facets are added to the stream.
1086: *
1087: * Note: Level II geometry compression semantics allow the mesh buffer
1088: * normals to be substituted with the value of an immediately
1089: * preceding SetNormal command, but this is unavailable in Level I.
1090: *
1091: * @param index vertex offset from the beginning of its data array
1092: * @param stripFlag RESTART, REPLACE_MIDDLE, or REPLACE_OLDEST
1093: */
1094: private interface GeometryAccessor {
1095: void processVertex(int index, int stripFlag);
1096: }
1097:
1098: /**
1099: * This class implements the GeometryAccessor interface for geometry
1100: * arrays accessed with by-copy semantics.
1101: */
1102: private class ByCopyGeometry implements GeometryAccessor {
1103: Point3f[] positions = null;
1104: Vector3f[] normals = null;
1105: Color3f[] colors3 = null;
1106: Color4f[] colors4 = null;
1107:
1108: ByCopyGeometry(GeometryArray ga) {
1109: this (ga, ga.getInitialVertexIndex(), ga
1110: .getValidVertexCount());
1111: }
1112:
1113: ByCopyGeometry(GeometryArray ga, int firstVertex,
1114: int validVertexCount) {
1115: int i;
1116: positions = new Point3f[validVertexCount];
1117: for (i = 0; i < validVertexCount; i++)
1118: positions[i] = new Point3f();
1119:
1120: ga.getCoordinates(firstVertex, positions);
1121:
1122: if (vertexNormals) {
1123: normals = new Vector3f[validVertexCount];
1124: for (i = 0; i < validVertexCount; i++)
1125: normals[i] = new Vector3f();
1126:
1127: ga.getNormals(firstVertex, normals);
1128: }
1129:
1130: if (vertexColor3) {
1131: colors3 = new Color3f[validVertexCount];
1132: for (i = 0; i < validVertexCount; i++)
1133: colors3[i] = new Color3f();
1134:
1135: ga.getColors(firstVertex, colors3);
1136: } else if (vertexColor4) {
1137: colors4 = new Color4f[validVertexCount];
1138: for (i = 0; i < validVertexCount; i++)
1139: colors4[i] = new Color4f();
1140:
1141: ga.getColors(firstVertex, colors4);
1142: }
1143: }
1144:
1145: public void processVertex(int v, int stripFlag) {
1146: Point3f p = positions[v];
1147: int r = meshBuffer.getMeshReference(p);
1148:
1149: if ((r == meshBuffer.NOT_FOUND)
1150: || (vertexNormals && noMeshNormalSubstitution && (!normals[v]
1151: .equals(meshBuffer.getNormal(r))))) {
1152:
1153: Vector3f n = vertexNormals ? normals[v] : null;
1154: Object c = vertexColor3 ? (Object) colors3[v]
1155: : vertexColor4 ? (Object) colors4[v] : null;
1156:
1157: addVertex(p, n, c, stripFlag, MESH_PUSH);
1158: meshBuffer.push(p, c, n);
1159: } else {
1160: if (vertexNormals
1161: && !noMeshNormalSubstitution
1162: && (!normals[v].equals(meshBuffer.getNormal(r))))
1163: addNormal(normals[v]);
1164:
1165: if (vertexColor3
1166: && (!colors3[v].equals(meshBuffer.getColor3(r))))
1167: addColor(colors3[v]);
1168:
1169: else if (vertexColor4
1170: && (!colors4[v].equals(meshBuffer.getColor4(r))))
1171: addColor(colors4[v]);
1172:
1173: addMeshReference(stripFlag, r);
1174: }
1175: }
1176: }
1177:
1178: /**
1179: * Class which holds index array references for a geometry array.
1180: */
1181: private static class IndexArrays {
1182: int colorIndices[] = null;
1183: int normalIndices[] = null;
1184: int positionIndices[] = null;
1185: }
1186:
1187: /**
1188: * Retrieves index array references for the specified IndexedGeometryArray.
1189: * Index arrays are copied starting from initialIndexIndex.
1190: */
1191: private void getIndexArrays(GeometryArray ga, IndexArrays ia) {
1192: IndexedGeometryArray iga = (IndexedGeometryArray) ga;
1193:
1194: int initialIndexIndex = iga.getInitialIndexIndex();
1195: int indexCount = iga.getValidIndexCount();
1196: int vertexFormat = iga.getVertexFormat();
1197:
1198: boolean useCoordIndexOnly = false;
1199: if ((vertexFormat & GeometryArray.USE_COORD_INDEX_ONLY) != 0) {
1200: if (debug)
1201: System.out.println("useCoordIndexOnly");
1202: useCoordIndexOnly = true;
1203: }
1204:
1205: ia.positionIndices = new int[indexCount];
1206: iga.getCoordinateIndices(initialIndexIndex, ia.positionIndices);
1207:
1208: if (vertexNormals) {
1209: if (useCoordIndexOnly) {
1210: ia.normalIndices = ia.positionIndices;
1211: } else {
1212: ia.normalIndices = new int[indexCount];
1213: iga.getNormalIndices(initialIndexIndex,
1214: ia.normalIndices);
1215: }
1216: }
1217: if (vertexColor3 || vertexColor4) {
1218: if (useCoordIndexOnly) {
1219: ia.colorIndices = ia.positionIndices;
1220: } else {
1221: ia.colorIndices = new int[indexCount];
1222: iga.getColorIndices(initialIndexIndex, ia.colorIndices);
1223: }
1224: }
1225: }
1226:
1227: /**
1228: * Class which holds indices for a specific vertex of an
1229: * IndexedGeometryArray.
1230: */
1231: private static class VertexIndices {
1232: int pi, ni, ci;
1233: }
1234:
1235: /**
1236: * Retrieves vertex indices for a specific vertex in an
1237: * IndexedGeometryArray.
1238: */
1239: private void getVertexIndices(int v, IndexArrays ia,
1240: VertexIndices vi) {
1241: vi.pi = ia.positionIndices[v];
1242: if (vertexNormals)
1243: vi.ni = ia.normalIndices[v];
1244: if (vertexColors)
1245: vi.ci = ia.colorIndices[v];
1246: }
1247:
1248: /**
1249: * This class implements the GeometryAccessor interface for indexed
1250: * geometry arrays accessed with by-copy semantics.
1251: */
1252: private class IndexedByCopyGeometry extends ByCopyGeometry {
1253: IndexArrays ia = new IndexArrays();
1254: VertexIndices vi = new VertexIndices();
1255:
1256: IndexedByCopyGeometry(GeometryArray ga) {
1257: super (ga, 0, ga.getVertexCount());
1258: getIndexArrays(ga, ia);
1259: }
1260:
1261: public void processVertex(int v, int stripFlag) {
1262: getVertexIndices(v, ia, vi);
1263: int r = meshBuffer.getMeshReference(vi.pi);
1264:
1265: if ((r == meshBuffer.NOT_FOUND)
1266: || (vertexNormals && noMeshNormalSubstitution && (vi.ni != meshBuffer
1267: .getNormalIndex(r)))) {
1268:
1269: Point3f p = positions[vi.pi];
1270: Vector3f n = vertexNormals ? normals[vi.ni] : null;
1271: Object c = vertexColor3 ? (Object) colors3[vi.ci]
1272: : vertexColor4 ? (Object) colors4[vi.ci] : null;
1273:
1274: addVertex(p, n, c, stripFlag, MESH_PUSH);
1275: meshBuffer.push(vi.pi, vi.ci, vi.ni);
1276: } else {
1277: if (vertexNormals && !noMeshNormalSubstitution
1278: && vi.ni != meshBuffer.getNormalIndex(r))
1279: addNormal(normals[vi.ni]);
1280:
1281: if (vertexColor3
1282: && vi.ci != meshBuffer.getColorIndex(r))
1283: addColor(colors3[vi.ci]);
1284:
1285: else if (vertexColor4
1286: && vi.ci != meshBuffer.getColorIndex(r))
1287: addColor(colors4[vi.ci]);
1288:
1289: addMeshReference(stripFlag, r);
1290: }
1291: }
1292: }
1293:
1294: //
1295: // NOTE: For now, copies are made of all GeometryArray vertex components
1296: // even when by-reference access is available.
1297: //
1298: private static class VertexCopy {
1299: Object c = null;
1300: Point3f p = null;
1301: Vector3f n = null;
1302: Color3f c3 = null;
1303: Color4f c4 = null;
1304: }
1305:
1306: private void processVertexCopy(VertexCopy vc, int stripFlag) {
1307: int r = meshBuffer.getMeshReference(vc.p);
1308:
1309: if ((r == meshBuffer.NOT_FOUND)
1310: || (vertexNormals && noMeshNormalSubstitution && (!vc.n
1311: .equals(meshBuffer.getNormal(r))))) {
1312:
1313: addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH);
1314: meshBuffer.push(vc.p, vc.c, vc.n);
1315: } else {
1316: if (vertexNormals && !noMeshNormalSubstitution
1317: && (!vc.n.equals(meshBuffer.getNormal(r))))
1318: addNormal(vc.n);
1319:
1320: if (vertexColor3
1321: && (!vc.c3.equals(meshBuffer.getColor3(r))))
1322: addColor(vc.c3);
1323:
1324: else if (vertexColor4
1325: && (!vc.c4.equals(meshBuffer.getColor4(r))))
1326: addColor(vc.c4);
1327:
1328: addMeshReference(stripFlag, r);
1329: }
1330: }
1331:
1332: private void processIndexedVertexCopy(VertexCopy vc,
1333: VertexIndices vi, int stripFlag) {
1334:
1335: int r = meshBuffer.getMeshReference(vi.pi);
1336:
1337: if ((r == meshBuffer.NOT_FOUND)
1338: || (vertexNormals && noMeshNormalSubstitution && (vi.ni != meshBuffer
1339: .getNormalIndex(r)))) {
1340:
1341: addVertex(vc.p, vc.n, vc.c, stripFlag, MESH_PUSH);
1342: meshBuffer.push(vi.pi, vi.ci, vi.ni);
1343: } else {
1344: if (vertexNormals && !noMeshNormalSubstitution
1345: && vi.ni != meshBuffer.getNormalIndex(r))
1346: addNormal(vc.n);
1347:
1348: if (vertexColor3 && vi.ci != meshBuffer.getColorIndex(r))
1349: addColor(vc.c3);
1350:
1351: else if (vertexColor4
1352: && vi.ci != meshBuffer.getColorIndex(r))
1353: addColor(vc.c4);
1354:
1355: addMeshReference(stripFlag, r);
1356: }
1357: }
1358:
1359: /**
1360: * This abstract class implements the GeometryAccessor interface for
1361: * concrete subclasses which handle float and NIO interleaved geometry
1362: * arrays.
1363: */
1364: private abstract class InterleavedGeometry implements
1365: GeometryAccessor {
1366: VertexCopy vc = new VertexCopy();
1367:
1368: int vstride = 0;
1369: int coffset = 0;
1370: int noffset = 0;
1371: int poffset = 0;
1372: int tstride = 0;
1373: int tcount = 0;
1374:
1375: InterleavedGeometry(GeometryArray ga) {
1376: if (vertexTextures) {
1377: if (vertexTexture2)
1378: tstride = 2;
1379: else if (vertexTexture3)
1380: tstride = 3;
1381: else if (vertexTexture4)
1382: tstride = 4;
1383:
1384: tcount = ga.getTexCoordSetCount();
1385: vstride += tcount * tstride;
1386: }
1387:
1388: if (vertexColors) {
1389: coffset = vstride;
1390: if (vertexColor3)
1391: vstride += 3;
1392: else
1393: vstride += 4;
1394: }
1395:
1396: if (vertexNormals) {
1397: noffset = vstride;
1398: vstride += 3;
1399: }
1400:
1401: poffset = vstride;
1402: vstride += 3;
1403: }
1404:
1405: abstract void copyVertex(int pi, int ni, int ci, VertexCopy vc);
1406:
1407: public void processVertex(int v, int stripFlag) {
1408: copyVertex(v, v, v, vc);
1409: processVertexCopy(vc, stripFlag);
1410: }
1411: }
1412:
1413: /**
1414: * This class implements the GeometryAccessor interface for float
1415: * interleaved geometry arrays.
1416: */
1417: private class InterleavedGeometryFloat extends InterleavedGeometry {
1418: float[] vdata = null;
1419:
1420: InterleavedGeometryFloat(GeometryArray ga) {
1421: super (ga);
1422: vdata = ga.getInterleavedVertices();
1423: }
1424:
1425: void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
1426: int voffset;
1427: voffset = pi * vstride;
1428: vc.p = new Point3f(vdata[voffset + poffset + 0],
1429: vdata[voffset + poffset + 1], vdata[voffset
1430: + poffset + 2]);
1431:
1432: if (vertexNormals) {
1433: voffset = ni * vstride;
1434: vc.n = new Vector3f(vdata[voffset + noffset + 0],
1435: vdata[voffset + noffset + 1], vdata[voffset
1436: + noffset + 2]);
1437: }
1438: if (vertexColor3) {
1439: voffset = ci * vstride;
1440: vc.c3 = new Color3f(vdata[voffset + coffset + 0],
1441: vdata[voffset + coffset + 1], vdata[voffset
1442: + coffset + 2]);
1443: vc.c = vc.c3;
1444: } else if (vertexColor4) {
1445: voffset = ci * vstride;
1446: vc.c4 = new Color4f(vdata[voffset + coffset + 0],
1447: vdata[voffset + coffset + 1], vdata[voffset
1448: + coffset + 2], vdata[voffset + coffset
1449: + 3]);
1450: vc.c = vc.c4;
1451: }
1452: }
1453: }
1454:
1455: /**
1456: * This class implements the GeometryAccessor interface for indexed
1457: * interleaved geometry arrays.
1458: */
1459: private class IndexedInterleavedGeometryFloat extends
1460: InterleavedGeometryFloat {
1461:
1462: IndexArrays ia = new IndexArrays();
1463: VertexIndices vi = new VertexIndices();
1464:
1465: IndexedInterleavedGeometryFloat(GeometryArray ga) {
1466: super (ga);
1467: getIndexArrays(ga, ia);
1468: }
1469:
1470: public void processVertex(int v, int stripFlag) {
1471: getVertexIndices(v, ia, vi);
1472: copyVertex(vi.pi, vi.ni, vi.ci, vc);
1473: processIndexedVertexCopy(vc, vi, stripFlag);
1474: }
1475: }
1476:
1477: /**
1478: * This class implements the GeometryAccessor interface for
1479: * interleaved NIO geometry arrays.
1480: */
1481: private class InterleavedGeometryNIO extends InterleavedGeometry {
1482: FloatBufferWrapper fbw = null;
1483:
1484: InterleavedGeometryNIO(GeometryArray ga) {
1485: super (ga);
1486: J3DBuffer buffer = ga.getInterleavedVertexBuffer();
1487: if (BufferWrapper.getBufferType(buffer) == BufferWrapper.TYPE_FLOAT) {
1488: fbw = new FloatBufferWrapper(buffer);
1489: } else {
1490: throw new IllegalArgumentException(
1491: "\ninterleaved vertex buffer must be FloatBuffer");
1492: }
1493: }
1494:
1495: void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
1496: int voffset;
1497: voffset = pi * vstride;
1498: vc.p = new Point3f(fbw.get(voffset + poffset + 0), fbw
1499: .get(voffset + poffset + 1), fbw.get(voffset
1500: + poffset + 2));
1501:
1502: if (vertexNormals) {
1503: voffset = ni * vstride;
1504: vc.n = new Vector3f(fbw.get(voffset + noffset + 0), fbw
1505: .get(voffset + noffset + 1), fbw.get(voffset
1506: + noffset + 2));
1507: }
1508: if (vertexColor3) {
1509: voffset = ci * vstride;
1510: vc.c3 = new Color3f(fbw.get(voffset + coffset + 0), fbw
1511: .get(voffset + coffset + 1), fbw.get(voffset
1512: + coffset + 2));
1513: vc.c = vc.c3;
1514: } else if (vertexColor4) {
1515: voffset = ci * vstride;
1516: vc.c4 = new Color4f(fbw.get(voffset + coffset + 0), fbw
1517: .get(voffset + coffset + 1), fbw.get(voffset
1518: + coffset + 2), fbw.get(voffset + coffset + 3));
1519: vc.c = vc.c4;
1520: }
1521: }
1522: }
1523:
1524: /**
1525: * This class implements the GeometryAccessor interface for indexed
1526: * interleaved NIO geometry arrays.
1527: */
1528: private class IndexedInterleavedGeometryNIO extends
1529: InterleavedGeometryNIO {
1530: IndexArrays ia = new IndexArrays();
1531: VertexIndices vi = new VertexIndices();
1532:
1533: IndexedInterleavedGeometryNIO(GeometryArray ga) {
1534: super (ga);
1535: getIndexArrays(ga, ia);
1536: }
1537:
1538: public void processVertex(int v, int stripFlag) {
1539: getVertexIndices(v, ia, vi);
1540: copyVertex(vi.pi, vi.ni, vi.ci, vc);
1541: processIndexedVertexCopy(vc, vi, stripFlag);
1542: }
1543: }
1544:
1545: /**
1546: * This class implements the GeometryAccessor interface for
1547: * non-interleaved geometry arrays accessed with by-reference semantics.
1548: */
1549: private class ByRefGeometry implements GeometryAccessor {
1550: VertexCopy vc = new VertexCopy();
1551:
1552: byte[] colorsB = null;
1553: float[] colorsF = null;
1554: float[] normals = null;
1555: float[] positionsF = null;
1556: double[] positionsD = null;
1557:
1558: int initialPositionIndex = 0;
1559: int initialNormalIndex = 0;
1560: int initialColorIndex = 0;
1561:
1562: ByRefGeometry(GeometryArray ga) {
1563: positionsF = ga.getCoordRefFloat();
1564: if (debug && positionsF != null)
1565: System.out.println("float positions");
1566:
1567: positionsD = ga.getCoordRefDouble();
1568: if (debug && positionsD != null)
1569: System.out.println("double positions");
1570:
1571: if (positionsF == null && positionsD == null)
1572: throw new UnsupportedOperationException(
1573: "\nby-reference access to Point3{d,f} arrays");
1574:
1575: initialPositionIndex = ga.getInitialCoordIndex();
1576:
1577: if (vertexColors) {
1578: colorsB = ga.getColorRefByte();
1579: if (debug && colorsB != null)
1580: System.out.println("byte colors");
1581:
1582: colorsF = ga.getColorRefFloat();
1583: if (debug && colorsF != null)
1584: System.out.println("float colors");
1585:
1586: if (colorsB == null && colorsF == null)
1587: throw new UnsupportedOperationException(
1588: "\nby-reference access to Color{3b,3f,4b,4f} arrays");
1589:
1590: initialColorIndex = ga.getInitialColorIndex();
1591: }
1592:
1593: if (vertexNormals) {
1594: normals = ga.getNormalRefFloat();
1595: if (debug && normals != null)
1596: System.out.println("float normals");
1597:
1598: if (normals == null)
1599: throw new UnsupportedOperationException(
1600: "\nby-reference access to Normal3f array");
1601:
1602: initialNormalIndex = ga.getInitialNormalIndex();
1603: }
1604: }
1605:
1606: void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
1607: pi *= 3;
1608: if (positionsF != null) {
1609: vc.p = new Point3f(positionsF[pi + 0],
1610: positionsF[pi + 1], positionsF[pi + 2]);
1611: } else {
1612: vc.p = new Point3f((float) positionsD[pi + 0],
1613: (float) positionsD[pi + 1],
1614: (float) positionsD[pi + 2]);
1615: }
1616:
1617: ni *= 3;
1618: if (vertexNormals) {
1619: vc.n = new Vector3f(normals[ni + 0], normals[ni + 1],
1620: normals[ni + 2]);
1621: }
1622:
1623: if (vertexColor3) {
1624: ci *= 3;
1625: if (colorsB != null) {
1626: vc.c3 = new Color3f(
1627: (colorsB[ci + 0] & 0xff) * ByteToFloatScale,
1628: (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
1629: (colorsB[ci + 2] & 0xff) * ByteToFloatScale);
1630: } else {
1631: vc.c3 = new Color3f(colorsF[ci + 0],
1632: colorsF[ci + 1], colorsF[ci + 2]);
1633: }
1634: vc.c = vc.c3;
1635: } else if (vertexColor4) {
1636: ci *= 4;
1637: if (colorsB != null) {
1638: vc.c4 = new Color4f(
1639: (colorsB[ci + 0] & 0xff) * ByteToFloatScale,
1640: (colorsB[ci + 1] & 0xff) * ByteToFloatScale,
1641: (colorsB[ci + 2] & 0xff) * ByteToFloatScale,
1642: (colorsB[ci + 3] & 0xff) * ByteToFloatScale);
1643: } else {
1644: vc.c4 = new Color4f(colorsF[ci + 0],
1645: colorsF[ci + 1], colorsF[ci + 2],
1646: colorsF[ci + 3]);
1647: }
1648: vc.c = vc.c4;
1649: }
1650: }
1651:
1652: public void processVertex(int v, int stripFlag) {
1653: copyVertex(v + initialPositionIndex,
1654: v + initialNormalIndex, v + initialColorIndex, vc);
1655:
1656: processVertexCopy(vc, stripFlag);
1657: }
1658: }
1659:
1660: /**
1661: * This class implements the GeometryAccessor interface for indexed
1662: * non-interleaved geometry arrays accessed with by-reference semantics.
1663: */
1664: private class IndexedByRefGeometry extends ByRefGeometry {
1665: IndexArrays ia = new IndexArrays();
1666: VertexIndices vi = new VertexIndices();
1667:
1668: IndexedByRefGeometry(GeometryArray ga) {
1669: super (ga);
1670: getIndexArrays(ga, ia);
1671: }
1672:
1673: public void processVertex(int v, int stripFlag) {
1674: getVertexIndices(v, ia, vi);
1675: copyVertex(vi.pi, vi.ni, vi.ci, vc);
1676: processIndexedVertexCopy(vc, vi, stripFlag);
1677: }
1678: }
1679:
1680: /**
1681: * This class implements the GeometryAccessor interface for
1682: * non-interleaved geometry arrays accessed with NIO.
1683: */
1684: private class ByRefGeometryNIO implements GeometryAccessor {
1685: VertexCopy vc = new VertexCopy();
1686:
1687: ByteBufferWrapper colorsB = null;
1688: FloatBufferWrapper colorsF = null;
1689: FloatBufferWrapper normals = null;
1690: FloatBufferWrapper positionsF = null;
1691: DoubleBufferWrapper positionsD = null;
1692:
1693: int initialPositionIndex = 0;
1694: int initialNormalIndex = 0;
1695: int initialColorIndex = 0;
1696:
1697: ByRefGeometryNIO(GeometryArray ga) {
1698: J3DBuffer buffer;
1699: buffer = ga.getCoordRefBuffer();
1700: initialPositionIndex = ga.getInitialCoordIndex();
1701:
1702: switch (BufferWrapper.getBufferType(buffer)) {
1703: case BufferWrapper.TYPE_FLOAT:
1704: positionsF = new FloatBufferWrapper(buffer);
1705: if (debug)
1706: System.out.println("float positions buffer");
1707: break;
1708: case BufferWrapper.TYPE_DOUBLE:
1709: positionsD = new DoubleBufferWrapper(buffer);
1710: if (debug)
1711: System.out.println("double positions buffer");
1712: break;
1713: default:
1714: throw new IllegalArgumentException(
1715: "\nposition buffer must be FloatBuffer or DoubleBuffer");
1716: }
1717:
1718: if (vertexColors) {
1719: buffer = ga.getColorRefBuffer();
1720: initialColorIndex = ga.getInitialColorIndex();
1721:
1722: switch (BufferWrapper.getBufferType(buffer)) {
1723: case BufferWrapper.TYPE_BYTE:
1724: colorsB = new ByteBufferWrapper(buffer);
1725: if (debug)
1726: System.out.println("byte colors buffer");
1727: break;
1728: case BufferWrapper.TYPE_FLOAT:
1729: colorsF = new FloatBufferWrapper(buffer);
1730: if (debug)
1731: System.out.println("float colors buffer");
1732: break;
1733: default:
1734: throw new IllegalArgumentException(
1735: "\ncolor buffer must be ByteBuffer or FloatBuffer");
1736: }
1737: }
1738:
1739: if (vertexNormals) {
1740: buffer = ga.getNormalRefBuffer();
1741: initialNormalIndex = ga.getInitialNormalIndex();
1742:
1743: switch (BufferWrapper.getBufferType(buffer)) {
1744: case BufferWrapper.TYPE_FLOAT:
1745: normals = new FloatBufferWrapper(buffer);
1746: if (debug)
1747: System.out.println("float normals buffer");
1748: break;
1749: default:
1750: throw new IllegalArgumentException(
1751: "\nnormal buffer must be FloatBuffer");
1752: }
1753: }
1754: }
1755:
1756: void copyVertex(int pi, int ni, int ci, VertexCopy vc) {
1757: pi *= 3;
1758: if (positionsF != null) {
1759: vc.p = new Point3f(positionsF.get(pi + 0), positionsF
1760: .get(pi + 1), positionsF.get(pi + 2));
1761: } else {
1762: vc.p = new Point3f((float) positionsD.get(pi + 0),
1763: (float) positionsD.get(pi + 1),
1764: (float) positionsD.get(pi + 2));
1765: }
1766:
1767: ni *= 3;
1768: if (vertexNormals) {
1769: vc.n = new Vector3f(normals.get(ni + 0), normals
1770: .get(ni + 1), normals.get(ni + 2));
1771: }
1772:
1773: if (vertexColor3) {
1774: ci *= 3;
1775: if (colorsB != null) {
1776: vc.c3 = new Color3f((colorsB.get(ci + 0) & 0xff)
1777: * ByteToFloatScale,
1778: (colorsB.get(ci + 1) & 0xff)
1779: * ByteToFloatScale, (colorsB
1780: .get(ci + 2) & 0xff)
1781: * ByteToFloatScale);
1782: } else {
1783: vc.c3 = new Color3f(colorsF.get(ci + 0), colorsF
1784: .get(ci + 1), colorsF.get(ci + 2));
1785: }
1786: vc.c = vc.c3;
1787: } else if (vertexColor4) {
1788: ci *= 4;
1789: if (colorsB != null) {
1790: vc.c4 = new Color4f((colorsB.get(ci + 0) & 0xff)
1791: * ByteToFloatScale,
1792: (colorsB.get(ci + 1) & 0xff)
1793: * ByteToFloatScale, (colorsB
1794: .get(ci + 2) & 0xff)
1795: * ByteToFloatScale, (colorsB
1796: .get(ci + 3) & 0xff)
1797: * ByteToFloatScale);
1798: } else {
1799: vc.c4 = new Color4f(colorsF.get(ci + 0), colorsF
1800: .get(ci + 1), colorsF.get(ci + 2), colorsF
1801: .get(ci + 3));
1802: }
1803: vc.c = vc.c4;
1804: }
1805: }
1806:
1807: public void processVertex(int v, int stripFlag) {
1808: copyVertex(v + initialPositionIndex,
1809: v + initialNormalIndex, v + initialColorIndex, vc);
1810:
1811: processVertexCopy(vc, stripFlag);
1812: }
1813: }
1814:
1815: /**
1816: * This class implements the GeometryAccessor interface for
1817: * non-interleaved indexed geometry arrays accessed with NIO.
1818: */
1819: private class IndexedByRefGeometryNIO extends ByRefGeometryNIO {
1820: IndexArrays ia = new IndexArrays();
1821: VertexIndices vi = new VertexIndices();
1822:
1823: IndexedByRefGeometryNIO(GeometryArray ga) {
1824: super (ga);
1825: getIndexArrays(ga, ia);
1826: }
1827:
1828: public void processVertex(int v, int stripFlag) {
1829: getVertexIndices(v, ia, vi);
1830: copyVertex(vi.pi, vi.ni, vi.ci, vc);
1831: processIndexedVertexCopy(vc, vi, stripFlag);
1832: }
1833: }
1834:
1835: /**
1836: * Convert a GeometryArray to compression stream elements and add them to
1837: * this stream.
1838: *
1839: * @param ga GeometryArray to convert
1840: * @exception IllegalArgumentException if GeometryArray has a
1841: * dimensionality or vertex format inconsistent with the CompressionStream
1842: */
1843: void addGeometryArray(GeometryArray ga) {
1844: int firstVertex = 0;
1845: int validVertexCount = 0;
1846: int vertexFormat = ga.getVertexFormat();
1847: GeometryAccessor geometryAccessor = null;
1848:
1849: if (streamType != getStreamType(ga))
1850: throw new IllegalArgumentException(
1851: "GeometryArray has inconsistent dimensionality");
1852:
1853: if (vertexComponents != getVertexComponents(vertexFormat))
1854: throw new IllegalArgumentException(
1855: "GeometryArray has inconsistent vertex components");
1856:
1857: // Set up for vertex data access semantics.
1858: boolean NIO = (vertexFormat & GeometryArray.USE_NIO_BUFFER) != 0;
1859: boolean byRef = (vertexFormat & GeometryArray.BY_REFERENCE) != 0;
1860: boolean interleaved = (vertexFormat & GeometryArray.INTERLEAVED) != 0;
1861: boolean indexedGeometry = ga instanceof IndexedGeometryArray;
1862:
1863: if (indexedGeometry) {
1864: if (debug)
1865: System.out.println("indexed");
1866: // Index arrays will be copied such that valid indices start at
1867: // offset 0 in the copied arrays.
1868: firstVertex = 0;
1869: validVertexCount = ((IndexedGeometryArray) ga)
1870: .getValidIndexCount();
1871: }
1872:
1873: if (!byRef) {
1874: if (debug)
1875: System.out.println("by-copy");
1876: if (indexedGeometry) {
1877: geometryAccessor = new IndexedByCopyGeometry(ga);
1878: } else {
1879: firstVertex = 0;
1880: validVertexCount = ga.getValidVertexCount();
1881: geometryAccessor = new ByCopyGeometry(ga);
1882: }
1883: } else if (interleaved && NIO) {
1884: if (debug)
1885: System.out.println("interleaved NIO");
1886: if (indexedGeometry) {
1887: geometryAccessor = new IndexedInterleavedGeometryNIO(ga);
1888: } else {
1889: firstVertex = ga.getInitialVertexIndex();
1890: validVertexCount = ga.getValidVertexCount();
1891: geometryAccessor = new InterleavedGeometryNIO(ga);
1892: }
1893: } else if (interleaved && !NIO) {
1894: if (debug)
1895: System.out.println("interleaved");
1896: if (indexedGeometry) {
1897: geometryAccessor = new IndexedInterleavedGeometryFloat(
1898: ga);
1899: } else {
1900: firstVertex = ga.getInitialVertexIndex();
1901: validVertexCount = ga.getValidVertexCount();
1902: geometryAccessor = new InterleavedGeometryFloat(ga);
1903: }
1904: } else if (!interleaved && NIO) {
1905: if (debug)
1906: System.out.println("non-interleaved NIO");
1907: if (indexedGeometry) {
1908: geometryAccessor = new IndexedByRefGeometryNIO(ga);
1909: } else {
1910: firstVertex = 0;
1911: validVertexCount = ga.getValidVertexCount();
1912: geometryAccessor = new ByRefGeometryNIO(ga);
1913: }
1914: } else if (!interleaved && !NIO) {
1915: if (debug)
1916: System.out.println("non-interleaved by-ref");
1917: if (indexedGeometry) {
1918: geometryAccessor = new IndexedByRefGeometry(ga);
1919: } else {
1920: firstVertex = 0;
1921: validVertexCount = ga.getValidVertexCount();
1922: geometryAccessor = new ByRefGeometry(ga);
1923: }
1924: }
1925:
1926: // Set up for topology.
1927: int stripCount = 0;
1928: int stripCounts[] = null;
1929: int constantStripLength = 0;
1930: int replaceCode = RESTART;
1931: boolean strips = false;
1932: boolean implicitStrips = false;
1933:
1934: if (ga instanceof TriangleStripArray
1935: || ga instanceof IndexedTriangleStripArray
1936: || ga instanceof LineStripArray
1937: || ga instanceof IndexedLineStripArray) {
1938:
1939: strips = true;
1940: replaceCode = REPLACE_OLDEST;
1941: if (debug)
1942: System.out.println("strips");
1943: } else if (ga instanceof TriangleFanArray
1944: || ga instanceof IndexedTriangleFanArray) {
1945:
1946: strips = true;
1947: replaceCode = REPLACE_MIDDLE;
1948: if (debug)
1949: System.out.println("fans");
1950: } else if (ga instanceof QuadArray
1951: || ga instanceof IndexedQuadArray) {
1952:
1953: // Handled as fan arrays with 4 vertices per fan.
1954: implicitStrips = true;
1955: constantStripLength = 4;
1956: replaceCode = REPLACE_MIDDLE;
1957: if (debug)
1958: System.out.println("quads");
1959: }
1960:
1961: // Get strip counts.
1962: if (strips) {
1963: if (indexedGeometry) {
1964: IndexedGeometryStripArray igsa;
1965: igsa = (IndexedGeometryStripArray) ga;
1966:
1967: stripCount = igsa.getNumStrips();
1968: stripCounts = new int[stripCount];
1969: igsa.getStripIndexCounts(stripCounts);
1970:
1971: } else {
1972: GeometryStripArray gsa;
1973: gsa = (GeometryStripArray) ga;
1974:
1975: stripCount = gsa.getNumStrips();
1976: stripCounts = new int[stripCount];
1977: gsa.getStripVertexCounts(stripCounts);
1978: }
1979: }
1980:
1981: // Build the compression stream for this shape's geometry.
1982: int v = firstVertex;
1983: if (strips) {
1984: for (int i = 0; i < stripCount; i++) {
1985: geometryAccessor.processVertex(v++, RESTART);
1986: for (int j = 1; j < stripCounts[i]; j++) {
1987: geometryAccessor.processVertex(v++, replaceCode);
1988: }
1989: }
1990: } else if (implicitStrips) {
1991: while (v < firstVertex + validVertexCount) {
1992: geometryAccessor.processVertex(v++, RESTART);
1993: for (int j = 1; j < constantStripLength; j++) {
1994: geometryAccessor.processVertex(v++, replaceCode);
1995: }
1996: }
1997: } else {
1998: while (v < firstVertex + validVertexCount) {
1999: geometryAccessor.processVertex(v++, RESTART);
2000: }
2001: }
2002: }
2003:
2004: /**
2005: * Print the stream to standard output.
2006: */
2007: void print() {
2008: System.out
2009: .println("\nstream has " + stream.size() + " entries");
2010: System.out.println("uncompressed size " + byteCount + " bytes");
2011: System.out.println("upper position bound: "
2012: + mcBounds[1].toString());
2013: System.out.println("lower position bound: "
2014: + mcBounds[0].toString());
2015: System.out.println("X, Y, Z centers (" + ((float) center[0])
2016: + " " + ((float) center[1]) + " " + ((float) center[2])
2017: + ")\n" + "scale " + ((float) scale) + "\n");
2018:
2019: Iterator i = stream.iterator();
2020: while (i.hasNext()) {
2021: System.out.println(i.next().toString() + "\n");
2022: }
2023: }
2024:
2025: ////////////////////////////////////////////////////////////////////////////
2026: // //
2027: // The following constructors and methods are currently the only public //
2028: // members of this class. All other members are subject to revision. //
2029: // //
2030: ////////////////////////////////////////////////////////////////////////////
2031:
2032: /**
2033: * Creates a CompressionStream from an array of Shape3D scene graph
2034: * objects. These Shape3D objects may only consist of a GeometryArray
2035: * component and an optional Appearance component. The resulting stream
2036: * may be used as input to the GeometryCompressor methods.<p>
2037: *
2038: * Each Shape3D in the array must be of the same dimensionality (point,
2039: * line, or surface) and have the same vertex format as the others.
2040: * Texture coordinates are ignored.<p>
2041: *
2042: * If a color is specified in the material attributes for a Shape3D then
2043: * that color is added to the CompressionStream as the current global
2044: * color. Subsequent colors as well as any colors bundled with vertices
2045: * will override it. Only the material diffuse colors are used; all other
2046: * appearance attributes are ignored.<p>
2047: *
2048: * @param positionQuant
2049: * number of bits to quantize each position's X, Y,
2050: * and Z components, ranging from 1 to 16
2051: *
2052: * @param colorQuant
2053: * number of bits to quantize each color's R, G, B, and
2054: * alpha components, ranging from 2 to 16
2055: *
2056: * @param normalQuant
2057: * number of bits for quantizing each normal's U and V components, ranging
2058: * from 0 to 6
2059: *
2060: * @param shapes
2061: * an array of Shape3D scene graph objects containing
2062: * GeometryArray objects, all with the same vertex format and
2063: * dimensionality
2064: *
2065: * @exception IllegalArgumentException if any Shape3D has an inconsistent
2066: * dimensionality or vertex format, or if any Shape3D contains a geometry
2067: * component that is not a GeometryArray
2068: *
2069: * @see Shape3D
2070: * @see GeometryArray
2071: * @see GeometryCompressor
2072: */
2073: public CompressionStream(int positionQuant, int colorQuant,
2074: int normalQuant, Shape3D shapes[]) {
2075: this ();
2076: if (debug)
2077: System.out.println("CompressionStream(Shape3D[]):");
2078:
2079: if (shapes == null)
2080: throw new IllegalArgumentException("null Shape3D array");
2081:
2082: if (shapes.length == 0)
2083: throw new IllegalArgumentException(
2084: "zero-length Shape3D array");
2085:
2086: if (shapes[0] == null)
2087: throw new IllegalArgumentException(
2088: "Shape3D at index 0 is null");
2089:
2090: long startTime = 0;
2091: if (benchmark)
2092: startTime = System.currentTimeMillis();
2093:
2094: Geometry g = shapes[0].getGeometry();
2095: if (!(g instanceof GeometryArray))
2096: throw new IllegalArgumentException(
2097: "Shape3D at index 0 is not a GeometryArray");
2098:
2099: GeometryArray ga = (GeometryArray) g;
2100: this .streamType = getStreamType(ga);
2101: this .vertexComponents = getVertexComponents(ga
2102: .getVertexFormat());
2103:
2104: // Add global quantization parameters to the start of the stream.
2105: addPositionQuantization(positionQuant);
2106: addColorQuantization(colorQuant);
2107: addNormalQuantization(normalQuant);
2108:
2109: // Loop through all shapes.
2110: for (int s = 0; s < shapes.length; s++) {
2111: if (debug)
2112: System.out.println("\nShape3D " + s + ":");
2113:
2114: g = shapes[s].getGeometry();
2115: if (!(g instanceof GeometryArray))
2116: throw new IllegalArgumentException("Shape3D at index "
2117: + s + " is not a GeometryArray");
2118:
2119: // Check for material color and add it to the stream if it exists.
2120: Appearance a = shapes[s].getAppearance();
2121: if (a != null) {
2122: Material m = a.getMaterial();
2123: if (m != null) {
2124: m.getDiffuseColor(c3f);
2125: if (vertexColor4) {
2126: c4f.set(c3f.x, c3f.y, c3f.z, 1.0f);
2127: addColor(c4f);
2128: } else
2129: addColor(c3f);
2130: }
2131: }
2132:
2133: // Add the geometry array to the stream.
2134: addGeometryArray((GeometryArray) g);
2135: }
2136:
2137: if (benchmark) {
2138: long t = System.currentTimeMillis() - startTime;
2139: System.out.println("\nCompressionStream:\n" + shapes.length
2140: + " shapes in " + (t / 1000f) + " sec");
2141: }
2142: }
2143:
2144: /**
2145: * Creates a CompressionStream from an array of Shape3D scene graph
2146: * objects. These Shape3D objects may only consist of a GeometryArray
2147: * component and an optional Appearance component. The resulting stream
2148: * may be used as input to the GeometryCompressor methods.<p>
2149: *
2150: * Each Shape3D in the array must be of the same dimensionality (point,
2151: * line, or surface) and have the same vertex format as the others.
2152: * Texture coordinates are ignored.<p>
2153: *
2154: * If a color is specified in the material attributes for a Shape3D then
2155: * that color is added to the CompressionStream as the current global
2156: * color. Subsequent colors as well as any colors bundled with vertices
2157: * will override it. Only the material diffuse colors are used; all other
2158: * appearance attributes are ignored.<p>
2159: *
2160: * Defaults of 16, 9, and 6 bits are used as the quantization values for
2161: * positions, colors, and normals respectively. These are the maximum
2162: * resolution values defined for positions and normals; the default of 9
2163: * for color is the equivalent of the 8 bits of RGBA component resolution
2164: * commonly available in graphics frame buffers.<p>
2165: *
2166: * @param shapes
2167: * an array of Shape3D scene graph objects containing
2168: * GeometryArray objects, all with the same vertex format and
2169: * dimensionality.
2170: *
2171: * @exception IllegalArgumentException if any Shape3D has an inconsistent
2172: * dimensionality or vertex format, or if any Shape3D contains a geometry
2173: * component that is not a GeometryArray
2174: *
2175: * @see Shape3D
2176: * @see GeometryArray
2177: * @see GeometryCompressor
2178: */
2179: public CompressionStream(Shape3D shapes[]) {
2180: this (16, 9, 6, shapes);
2181: }
2182:
2183: /**
2184: * Creates a CompressionStream from an array of GeometryInfo objects. The
2185: * resulting stream may be used as input to the GeometryCompressor
2186: * methods.<p>
2187: *
2188: * Each GeometryInfo in the array must be of the same dimensionality
2189: * (point, line, or surface) and have the same vertex format as the
2190: * others. Texture coordinates are ignored.<p>
2191: *
2192: * @param positionQuant
2193: * number of bits to quantize each position's X, Y,
2194: * and Z components, ranging from 1 to 16
2195: *
2196: * @param colorQuant
2197: * number of bits to quantize each color's R, G, B, and
2198: * alpha components, ranging from 2 to 16
2199: *
2200: * @param normalQuant
2201: * number of bits for quantizing each normal's U and V components, ranging
2202: * from 0 to 6
2203: *
2204: * @param geometry
2205: * an array of GeometryInfo objects, all with the same
2206: * vertex format and dimensionality
2207: *
2208: * @exception IllegalArgumentException if any GeometryInfo object has an
2209: * inconsistent dimensionality or vertex format
2210: *
2211: * @see GeometryInfo
2212: * @see GeometryCompressor
2213: */
2214: public CompressionStream(int positionQuant, int colorQuant,
2215: int normalQuant, GeometryInfo geometry[]) {
2216: this ();
2217: if (debug)
2218: System.out.println("CompressionStream(GeometryInfo[])");
2219:
2220: if (geometry == null)
2221: throw new IllegalArgumentException(
2222: "null GeometryInfo array");
2223:
2224: if (geometry.length == 0)
2225: throw new IllegalArgumentException(
2226: "zero-length GeometryInfo array");
2227:
2228: if (geometry[0] == null)
2229: throw new IllegalArgumentException(
2230: "GeometryInfo at index 0 is null");
2231:
2232: long startTime = 0;
2233: if (benchmark)
2234: startTime = System.currentTimeMillis();
2235:
2236: GeometryArray ga = geometry[0].getGeometryArray();
2237: this .streamType = getStreamType(ga);
2238: this .vertexComponents = getVertexComponents(ga
2239: .getVertexFormat());
2240:
2241: // Add global quantization parameters to the start of the stream.
2242: addPositionQuantization(positionQuant);
2243: addColorQuantization(colorQuant);
2244: addNormalQuantization(normalQuant);
2245:
2246: // Loop through all GeometryInfo objects and add them to the stream.
2247: for (int i = 0; i < geometry.length; i++) {
2248: if (debug)
2249: System.out.println("\nGeometryInfo " + i + ":");
2250: addGeometryArray(geometry[i].getGeometryArray());
2251: }
2252:
2253: if (benchmark) {
2254: long t = System.currentTimeMillis() - startTime;
2255: System.out.println("\nCompressionStream:\n"
2256: + geometry.length + " GeometryInfo objects in "
2257: + (t / 1000f) + " sec");
2258: }
2259: }
2260:
2261: /**
2262: * Creates a CompressionStream from an array of GeometryInfo objects. The
2263: * resulting stream may be used as input to the GeometryCompressor
2264: * methods.<p>
2265: *
2266: * Each GeometryInfo in the array must be of the same dimensionality
2267: * (point, line, or surface) and have the same vertex format as the
2268: * others. Texture coordinates are ignored.<p>
2269: *
2270: * Defaults of 16, 9, and 6 bits are used as the quantization values for
2271: * positions, colors, and normals respectively. These are the maximum
2272: * resolution values defined for positions and normals; the default of 9
2273: * for color is the equivalent of the 8 bits of RGBA component resolution
2274: * commonly available in graphics frame buffers.<p>
2275: *
2276: * @param geometry
2277: * an array of GeometryInfo objects, all with the same
2278: * vertex format and dimensionality
2279: *
2280: * @exception IllegalArgumentException if any GeometryInfo object has an
2281: * inconsistent dimensionality or vertex format
2282: *
2283: * @see GeometryInfo
2284: * @see GeometryCompressor
2285: */
2286: public CompressionStream(GeometryInfo geometry[]) {
2287: this (16, 9, 6, geometry);
2288: }
2289:
2290: /**
2291: * Get the original bounds of the coordinate data, in modeling coordinates.
2292: * Coordinate data is positioned and scaled to a normalized cube after
2293: * compression.
2294: *
2295: * @return Point3d array of length 2, where the 1st Point3d is the lower
2296: * bounds and the 2nd Point3d is the upper bounds.
2297: * @since Java 3D 1.3
2298: */
2299: public Point3d[] getModelBounds() {
2300: Point3d[] bounds = new Point3d[2];
2301: bounds[0] = new Point3d(mcBounds[0]);
2302: bounds[1] = new Point3d(mcBounds[1]);
2303: return bounds;
2304: }
2305:
2306: /**
2307: * Get the bounds of the compressed object in normalized coordinates.
2308: * These have an maximum bounds by [-1.0 .. +1.0] across each axis.
2309: *
2310: * @return Point3d array of length 2, where the 1st Point3d is the lower
2311: * bounds and the 2nd Point3d is the upper bounds.
2312: * @since Java 3D 1.3
2313: */
2314: public Point3d[] getNormalizedBounds() {
2315: Point3d[] bounds = new Point3d[2];
2316: bounds[0] = new Point3d(ncBounds[0]);
2317: bounds[1] = new Point3d(ncBounds[1]);
2318: return bounds;
2319: }
2320: }
|