001: /*
002: * $RCSfile: CompressionStreamColor.java,v $
003: *
004: * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * - Redistribution of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * - Redistribution in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * Neither the name of Sun Microsystems, Inc. or the names of
019: * contributors may be used to endorse or promote products derived
020: * from this software without specific prior written permission.
021: *
022: * This software is provided "AS IS," without a warranty of any
023: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
024: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
025: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
026: * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
027: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
028: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
029: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
030: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
031: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
032: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
033: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
034: * POSSIBILITY OF SUCH DAMAGES.
035: *
036: * You acknowledge that this software is not designed, licensed or
037: * intended for use in the design, construction, operation or
038: * maintenance of any nuclear facility.
039: *
040: * $Revision: 1.3 $
041: * $Date: 2007/02/09 17:20:22 $
042: * $State: Exp $
043: */
044:
045: package com.sun.j3d.utils.geometry.compression;
046:
047: import javax.vecmath.Color3f;
048: import javax.vecmath.Color4f;
049:
050: /**
051: * This class represents a color in a compression stream. It maintains both
052: * floating-point and quantized representations. This color may be bundled
053: * with a vertex or exist separately as a global color.
054: */
055: class CompressionStreamColor extends CompressionStreamElement {
056: private int R, G, B, A;
057: private boolean color3;
058: private boolean color4;
059: private float colorR, colorG, colorB, colorA;
060:
061: int rAbsolute, gAbsolute, bAbsolute, aAbsolute;
062:
063: /**
064: * Create a CompressionStreamColor.
065: *
066: * @param stream CompressionStream associated with this element
067: * @param color3 floating-point representation to be encoded
068: */
069: CompressionStreamColor(CompressionStream stream, Color3f c3) {
070: this .color4 = false;
071: this .color3 = true;
072: colorR = c3.x;
073: colorG = c3.y;
074: colorB = c3.z;
075: colorA = 0.0f;
076: stream.byteCount += 12;
077: }
078:
079: /**
080: * Create a CompressionStreamColor.
081: *
082: * @param stream CompressionStream associated with this element
083: * @param color4 floating-point representation to be encoded
084: */
085: CompressionStreamColor(CompressionStream stream, Color4f c4) {
086: this .color3 = false;
087: this .color4 = true;
088: colorR = c4.x;
089: colorG = c4.y;
090: colorB = c4.z;
091: colorA = c4.w;
092: stream.byteCount += 16;
093: }
094:
095: /**
096: * Quantize a floating point color to fixed point integer components of
097: * the specified number of bits. The bit length can range from a maximum
098: * of 16 to a minimum of 2 bits since negative colors are not defined.<p>
099: *
100: * The bit length is the total number of bits in the signed version of the
101: * fixed point representation of the input color, which is assumed to
102: * be normalized into the [0..1) range. With the maximum bit length of
103: * 16, 15 bits of positive colors can be represented; a bit length of 9 is
104: * needed to get the 8 bit positive color size in common use.<p>
105: *
106: * @param stream CompressionStream associated with this element
107: * @param table HuffmanTable for collecting data about the quantized
108: * representation of this element
109: */
110: void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
111: // Clamp quantization.
112: int quant = (stream.colorQuant < 2 ? 2
113: : (stream.colorQuant > 16 ? 16 : stream.colorQuant));
114:
115: absolute = false;
116: if (stream.firstColor || stream.colorQuantChanged) {
117: absolute = true;
118: stream.lastColor[0] = 0;
119: stream.lastColor[1] = 0;
120: stream.lastColor[2] = 0;
121: stream.lastColor[3] = 0;
122: stream.firstColor = false;
123: stream.colorQuantChanged = false;
124: }
125:
126: // Convert the floating point position to s.15 2's complement.
127: if (color3) {
128: R = (int) (colorR * 32768.0);
129: G = (int) (colorG * 32768.0);
130: B = (int) (colorB * 32768.0);
131: A = 0;
132: } else if (color4) {
133: R = (int) (colorR * 32768.0);
134: G = (int) (colorG * 32768.0);
135: B = (int) (colorB * 32768.0);
136: A = (int) (colorA * 32768.0);
137: }
138:
139: // Clamp color components.
140: R = (R > 32767 ? 32767 : (R < 0 ? 0 : R));
141: G = (G > 32767 ? 32767 : (G < 0 ? 0 : G));
142: B = (B > 32767 ? 32767 : (B < 0 ? 0 : B));
143: A = (A > 32767 ? 32767 : (A < 0 ? 0 : A));
144:
145: // Compute quantized values.
146: R &= quantizationMask[quant];
147: G &= quantizationMask[quant];
148: B &= quantizationMask[quant];
149: A &= quantizationMask[quant];
150:
151: // Copy and retain absolute color for mesh buffer lookup.
152: rAbsolute = R;
153: gAbsolute = G;
154: bAbsolute = B;
155: aAbsolute = A;
156:
157: // Compute deltas.
158: R -= stream.lastColor[0];
159: G -= stream.lastColor[1];
160: B -= stream.lastColor[2];
161: A -= stream.lastColor[3];
162:
163: // Update last values.
164: stream.lastColor[0] += R;
165: stream.lastColor[1] += G;
166: stream.lastColor[2] += B;
167: stream.lastColor[3] += A;
168:
169: // Compute length and shift common to all components.
170: if (color3)
171: computeLengthShift(R, G, B);
172:
173: else if (color4)
174: computeLengthShift(R, G, B, A);
175:
176: // 0-length components are allowed only for normals.
177: if (length == 0)
178: length = 1;
179:
180: // Add this element to the Huffman table associated with this stream.
181: huffmanTable.addColorEntry(length, shift, absolute);
182: }
183:
184: /**
185: * Output a setColor command.
186: *
187: * @param table HuffmanTable mapping quantized representations to
188: * compressed encodings
189: * @param output CommandStream for collecting compressed output
190: */
191: void outputCommand(HuffmanTable table, CommandStream output) {
192: outputColor(table, output, CommandStream.SET_COLOR, 8);
193: }
194:
195: /**
196: * Output a color subcommand.
197: *
198: * @param table HuffmanTable mapping quantized representations to
199: * compressed encodings
200: * @param output CommandStream for collecting compressed output
201: */
202: void outputSubcommand(HuffmanTable table, CommandStream output) {
203:
204: outputColor(table, output, 0, 6);
205: }
206:
207: //
208: // Output the final compressed bits to the output command stream.
209: //
210: private void outputColor(HuffmanTable table, CommandStream output,
211: int header, int headerLength) {
212: HuffmanNode t;
213:
214: // Look up the Huffman token for this compression stream element.
215: t = table.getColorEntry(length, shift, absolute);
216:
217: // Construct the color subcommand components. The maximum length of a
218: // color subcommand is 70 bits (a tag with a length of 6 followed by 4
219: // components of 16 bits each). The subcommand is therefore
220: // constructed initially using just the first 3 components, with the
221: // 4th component added later after the tag has been shifted into the
222: // subcommand header.
223: int componentLength = t.dataLength - t.shift;
224: int subcommandLength = t.tagLength + (3 * componentLength);
225:
226: R = (R >> t.shift) & (int) lengthMask[componentLength];
227: G = (G >> t.shift) & (int) lengthMask[componentLength];
228: B = (B >> t.shift) & (int) lengthMask[componentLength];
229:
230: long colorSubcommand = (((long) t.tag) << (3 * componentLength))
231: | (((long) R) << (2 * componentLength))
232: | (((long) G) << (1 * componentLength))
233: | (((long) B) << (0 * componentLength));
234:
235: if (subcommandLength < 6) {
236: // The header will have some empty bits. The Huffman tag
237: // computation will prevent this if necessary.
238: header |= (int) (colorSubcommand << (6 - subcommandLength));
239: subcommandLength = 0;
240: } else {
241: // Move the 1st 6 bits of the subcommand into the header.
242: header |= (int) (colorSubcommand >>> (subcommandLength - 6));
243: subcommandLength -= 6;
244: }
245:
246: // Add alpha if present.
247: if (color4) {
248: A = (A >> t.shift) & (int) lengthMask[componentLength];
249: colorSubcommand = (colorSubcommand << componentLength) | A;
250: subcommandLength += componentLength;
251: }
252:
253: // Add the header and body to the output buffer.
254: output.addCommand(header, headerLength, colorSubcommand,
255: subcommandLength);
256: }
257:
258: public String toString() {
259: String d = absolute ? "" : "delta ";
260: String c = (colorR + " " + colorG + " " + colorB + (color4 ? (" " + colorA)
261: : ""));
262:
263: return "color: " + c + "\n" + " fixed point " + d + +R + " "
264: + G + " " + B + "\n" + " length " + length + " shift "
265: + shift + (absolute ? " absolute" : " relative");
266: }
267: }
|