📄 geometrydecompressor.java
字号:
/* * $RCSfile: GeometryDecompressor.java,v $ * * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * * Use is subject to license terms. * * $Revision: 1.6 $ * $Date: 2007/04/12 17:34:04 $ * $State: Exp $ */package javax.media.j3d;import javax.vecmath.* ;/** * This abstract class provides the base methods needed to create a geometry * decompressor. Subclasses must implement a backend to handle the output, * consisting of a generalized triangle strip, line strip, or point array, * along with possible global color and normal changes. */abstract class GeometryDecompressor { private static final boolean debug = false ; private static final boolean benchmark = false ; /** * Compressed geometry format version supported. */ static final int majorVersionNumber = 1 ; static final int minorVersionNumber = 0 ; static final int minorMinorVersionNumber = 2 ; /** * This method is called when a SetState command is encountered in the * decompression stream. * * @param bundlingNorm true indicates normals are bundled with vertices * @param bundlingColor true indicates colors are bundled with vertices * @param doingAlpha true indicates alpha values are bundled with vertices */ abstract void outputVertexFormat(boolean bundlingNorm, boolean bundlingColor, boolean doingAlpha) ; /** * This method captures the vertex output of the decompressor. The normal * or color references may be null if the corresponding data is not * bundled with the vertices in the compressed geometry buffer. Alpha * values may be included in the color. * * @param position The coordinates of the vertex. * @param normal The normal bundled with the vertex. May be null. * @param color The color bundled with the vertex. May be null. * Alpha may be present. * @param vertexReplaceCode Specifies the generalized strip flag * that is bundled with each vertex. * @see GeneralizedStripFlags * @see CompressedGeometryHeader */ abstract void outputVertex(Point3f position, Vector3f normal, Color4f color, int vertexReplaceCode) ; /** * This method captures the global color output of the decompressor. It * is only invoked if colors are not bundled with the vertex data. The * global color applies to all succeeding vertices until the next time the * method is invoked. * * @param color The current global color. */ abstract void outputColor(Color4f color) ; /** * This method captures the global normal output of the decompressor. It * is only invoked if normals are not bundled with the vertex data. The * global normal applies to all succeeding vertices until the next time the * method is invoked. * * @param normal The current global normal. */ abstract void outputNormal(Vector3f normal) ; // Geometry compression opcodes. private static final int GC_VERTEX = 0x40 ; private static final int GC_SET_NORM = 0xC0 ; private static final int GC_SET_COLOR = 0x80 ; private static final int GC_MESH_B_R = 0x20 ; private static final int GC_SET_STATE = 0x18 ; private static final int GC_SET_TABLE = 0x10 ; private static final int GC_PASS_THROUGH = 0x08 ; private static final int GC_EOS = 0x00 ; private static final int GC_V_NO_OP = 0x01 ; private static final int GC_SKIP_8 = 0x07 ; // Three 64-entry decompression tables are used: gctables[0] for // positions, gctables[1] for colors, and gctables[2] for normals. private HuffmanTableEntry gctables[][] ; /** * Decompression table entry. */ static class HuffmanTableEntry { int tagLength, dataLength ; int rightShift, absolute ; public String toString() { return " tag length: " + tagLength + " data length: " + dataLength + " shift: " + rightShift + " abs/rel: " + absolute ; } } // A 16-entry mesh buffer is used. private MeshBufferEntry meshBuffer[] ; private int meshIndex = 15 ; private int meshState ; // meshState values. These are needed to determine if colors and/or // normals should come from meshBuffer or from SetColor or SetNormal. private static final int USE_MESH_NORMAL = 0x1 ; private static final int USE_MESH_COLOR = 0x2 ; /** * Mesh buffer entry containing position, normal, and color. */ static class MeshBufferEntry { short x, y, z ; short octant, sextant, u, v ; short r, g, b, a ; } // Geometry compression state variables. private short curX, curY, curZ ; private short curR, curG, curB, curA ; private int curSex, curOct, curU, curV ; // Current vertex data. private Point3f curPos ; private Vector3f curNorm ; private Color4f curColor ; private int repCode ; // Flags indicating what data is bundled with the vertex. private boolean bundlingNorm ; private boolean bundlingColor ; private boolean doingAlpha ; // Internal decompression buffering variables. private int currentHeader = 0 ; private int nextHeader = 0 ; private int bitBuffer = 0 ; private int bitBufferCount = 32 ; // Used for benchmarking if so configured. private long startTime ; private int vertexCount ; // Bit-field masks: BMASK[i] = (1<<i)-1 private static final int BMASK[] = { 0x0, 0x1, 0x3, 0x7, 0xF, 0x1F, 0x3F, 0x7F, 0xFF, 0x1FF, 0x3FF, 0x7FF, 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF, } ; // A reference to the compressed data and the current offset. private byte gcData[] ; private int gcIndex ; // The normals table for decoding 6-bit [u,v] spherical sextant coordinates. private static final double gcNormals[][][] ; private static final double NORMAL_MAX_Y_ANG = 0.615479709 ; private static final boolean printNormalTable = false ; /** * Initialize the normals table. */ static { int i, j, inx, iny, inz ; double th, psi, qnx, qny, qnz ; gcNormals = new double[65][65][3] ; for (i = 0 ; i < 65 ; i++) { for (j = 0 ; j < 65 ; j++) { if (i+j > 64) continue ; psi = NORMAL_MAX_Y_ANG * (i / 64.0) ; th = Math.asin(Math.tan(NORMAL_MAX_Y_ANG * ((64-j)/64.0))) ; qnx = Math.cos(th) * Math.cos(psi) ; qny = Math.sin(psi) ; qnz = Math.sin(th) * Math.cos(psi) ; // Convert the floating point normal to s1.14 bit notation, // then back again. qnx = qnx*16384.0 ; inx = (int)qnx ; qnx = (double)inx ; qnx = qnx/16384.0 ; qny = qny*16384.0 ; iny = (int)qny ; qny = (double)iny ; qny = qny/16384.0 ; qnz = qnz*16384.0 ; inz = (int)qnz ; qnz = (double)inz ; qnz = qnz/16384.0 ; gcNormals[i][j][0] = qnx ; gcNormals[i][j][1] = qny ; gcNormals[i][j][2] = qnz ; } } if (printNormalTable) { System.err.println("struct {") ; System.err.println(" double nx, ny, nz ;") ; System.err.println("} gcNormals[65][65] = {"); for (i = 0 ; i <= 64 ; i++) { System.err.println("{") ; for (j = 0 ; j <= 64 ; j++) { if (j+i > 64) continue ; System.err.println("{ " + gcNormals[i][j][0] + ", " + gcNormals[i][j][1] + ", " + gcNormals[i][j][2] + " }") ; } System.err.println("},") ; } System.err.println("}") ; } } // // The constructor. // GeometryDecompressor() { curPos = new Point3f() ; curNorm = new Vector3f() ; curColor = new Color4f() ; gctables = new HuffmanTableEntry[3][64] ; for (int i = 0 ; i < 64 ; i++) { gctables[0][i] = new HuffmanTableEntry() ; gctables[1][i] = new HuffmanTableEntry() ; gctables[2][i] = new HuffmanTableEntry() ; } meshBuffer = new MeshBufferEntry[16] ; for (int i = 0 ; i < 16 ; i++) meshBuffer[i] = new MeshBufferEntry() ; } /** * Check version numbers and return true if compatible. */ boolean checkVersion(int majorVersionNumber, int minorVersionNumber) { return ((majorVersionNumber < this.majorVersionNumber) || ((majorVersionNumber == this.majorVersionNumber) && (minorVersionNumber <= this.minorVersionNumber))) ; } /** * Decompress data and invoke abstract output methods. * * @param start byte offset to start of compressed geometry in data array * @param length size of compressed geometry in bytes * @param data array containing compressed geometry buffer of the * specified length at the given offset from the start of the array * @exception ArrayIndexOutOfBoundsException if start+length > data size */ void decompress(int start, int length, byte data[]) { if (debug) System.err.println("GeometryDecompressor.decompress\n" + " start: " + start + " length: " + length + " data array size: " + data.length) ; if (benchmark) benchmarkStart(length) ; if (start+length > data.length) throw new ArrayIndexOutOfBoundsException (J3dI18N.getString("GeometryDecompressor0")) ; // Set reference to compressed data and skip to start of data. gcData = data ; gcIndex = start ; // Initialize state. bitBufferCount = 0 ; meshState = 0 ; bundlingNorm = false ; bundlingColor = false ; doingAlpha = false ; repCode = 0 ; // Headers are interleaved for hardware implementations, so the // first is always a nullop. nextHeader = GC_V_NO_OP ; // Enter decompression loop. while (gcIndex < start+length) processDecompression() ; // Finish out any bits left in bitBuffer. while (bitBufferCount > 0) processDecompression() ; if (benchmark) benchmarkPrint(length) ; } // // Return the next bitCount bits of compressed data. // private int getBits(int bitCount, String d) { int bits ; if (debug) System.err.print(" getBits(" + bitCount + ") " + d + ", " + bitBufferCount + " available at gcIndex " + gcIndex) ; if (bitCount == 0) { if (debug) System.err.println(": got 0x0") ; return 0 ; } if (bitBufferCount == 0) { bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | ((gcData[gcIndex++] & 0xff) << 16) | ((gcData[gcIndex++] & 0xff) << 8) | ((gcData[gcIndex++] & 0xff))) ; bitBufferCount = 32 ; } if (bitBufferCount >= bitCount) { bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; bitBuffer = bitBuffer << bitCount ; bitBufferCount -= bitCount ; } else { bits = (bitBuffer >>> (32 - bitCount)) & BMASK[bitCount] ; bits = bits >>> (bitCount - bitBufferCount) ; bits = bits << (bitCount - bitBufferCount) ; bitBuffer = (((gcData[gcIndex++] & 0xff) << 24) | ((gcData[gcIndex++] & 0xff) << 16) | ((gcData[gcIndex++] & 0xff) << 8) | ((gcData[gcIndex++] & 0xff))) ; bits = bits | ((bitBuffer >>> (32 - (bitCount - bitBufferCount))) & BMASK[bitCount - bitBufferCount]) ; bitBuffer = bitBuffer << (bitCount - bitBufferCount) ; bitBufferCount = 32 - (bitCount - bitBufferCount) ; } if (debug) System.err.println(": got 0x" + Integer.toHexString(bits)) ; return bits ; } // // Shuffle interleaved headers and opcodes. // private void processDecompression() { int mbp ; currentHeader = nextHeader ; if ((currentHeader & 0xC0) == GC_VERTEX) { // Process a vertex. if (!bundlingNorm && !bundlingColor) { // get next opcode, process current position opcode nextHeader = getBits(8, "header") ; mbp = processDecompressionOpcode(0) ; } else if (bundlingNorm && !bundlingColor) { // get normal header, process current position opcode nextHeader = getBits(6, "normal") ; mbp = processDecompressionOpcode(0) ; currentHeader = nextHeader | GC_SET_NORM ; // get next opcode, process current normal opcode nextHeader = getBits(8, "header") ; processDecompressionOpcode(mbp) ; } else if (!bundlingNorm && bundlingColor) { // get color header, process current position opcode nextHeader = getBits(6, "color") ; mbp = processDecompressionOpcode(0) ; currentHeader = nextHeader | GC_SET_COLOR ; // get next opcode, process current color opcode nextHeader = getBits(8, "header") ; processDecompressionOpcode(mbp) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -