1 /*
2  * $RCSfile: CompressionStreamColor.java,v $
3  *
4  * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * - Redistribution of source code must retain the above copyright
11  *   notice, this list of conditions and the following disclaimer.
12  *
13  * - Redistribution in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  *
18  * Neither the name of Sun Microsystems, Inc. or the names of
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * This software is provided "AS IS," without a warranty of any
23  * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
24  * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
25  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
26  * EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
27  * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
28  * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
29  * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
30  * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
31  * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
32  * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
33  * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGES.
35  *
36  * You acknowledge that this software is not designed, licensed or
37  * intended for use in the design, construction, operation or
38  * maintenance of any nuclear facility.
39  *
40  * $Revision: 1.3 $
41  * $Date: 2007/02/09 17:20:22 $
42  * $State: Exp $
43  */
44 
45 package com.sun.j3d.utils.geometry.compression;
46 
47 import javax.vecmath.Color3f;
48 import javax.vecmath.Color4f;
49 
50 /**
51  * This class represents a color in a compression stream. It maintains both
52  * floating-point and quantized representations.  This color may be bundled
53  * with a vertex or exist separately as a global color.
54  */
55 class CompressionStreamColor extends CompressionStreamElement {
56     private int R, G, B, A ;
57     private boolean color3 ;
58     private boolean color4 ;
59     private float colorR, colorG, colorB, colorA ;
60 
61     int rAbsolute, gAbsolute, bAbsolute, aAbsolute ;
62 
63     /**
64      * Create a CompressionStreamColor.
65      *
66      * @param stream CompressionStream associated with this element
67      * @param color3 floating-point representation to be encoded
68      */
CompressionStreamColor(CompressionStream stream, Color3f c3)69     CompressionStreamColor(CompressionStream stream, Color3f c3) {
70 	this.color4 = false ;
71 	this.color3 = true ;
72 	colorR = c3.x ;
73 	colorG = c3.y ;
74 	colorB = c3.z ;
75 	colorA = 0.0f ;
76 	stream.byteCount += 12 ;
77     }
78 
79     /**
80      * Create a CompressionStreamColor.
81      *
82      * @param stream CompressionStream associated with this element
83      * @param color4 floating-point representation to be encoded
84      */
CompressionStreamColor(CompressionStream stream, Color4f c4)85     CompressionStreamColor(CompressionStream stream, Color4f c4) {
86 	this.color3 = false ;
87 	this.color4 = true ;
88 	colorR = c4.x ;
89 	colorG = c4.y ;
90 	colorB = c4.z ;
91 	colorA = c4.w ;
92 	stream.byteCount += 16 ;
93     }
94 
95     /**
96      * Quantize a floating point color to fixed point integer components of
97      * the specified number of bits.  The bit length can range from a maximum
98      * of 16 to a minimum of 2 bits since negative colors are not defined.<p>
99      *
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      */
quantize(CompressionStream stream, HuffmanTable huffmanTable)110     void quantize(CompressionStream stream, HuffmanTable huffmanTable) {
111 	// Clamp quantization.
112 	int quant =
113 	    (stream.colorQuant < 2? 2 :
114 	     (stream.colorQuant > 16? 16 : stream.colorQuant)) ;
115 
116 	absolute = false ;
117 	if (stream.firstColor || stream.colorQuantChanged) {
118 	    absolute = true ;
119 	    stream.lastColor[0] = 0 ;
120 	    stream.lastColor[1] = 0 ;
121 	    stream.lastColor[2] = 0 ;
122 	    stream.lastColor[3] = 0 ;
123 	    stream.firstColor = false ;
124 	    stream.colorQuantChanged = false ;
125 	}
126 
127 	// Convert the floating point position to s.15 2's complement.
128 	if (color3) {
129 	    R = (int)(colorR * 32768.0) ;
130 	    G = (int)(colorG * 32768.0) ;
131 	    B = (int)(colorB * 32768.0) ;
132 	    A = 0 ;
133 	} else if (color4) {
134 	    R = (int)(colorR * 32768.0) ;
135 	    G = (int)(colorG * 32768.0) ;
136 	    B = (int)(colorB * 32768.0) ;
137 	    A = (int)(colorA * 32768.0) ;
138 	}
139 
140 	// Clamp color components.
141 	R = (R > 32767? 32767: (R < 0? 0: R)) ;
142 	G = (G > 32767? 32767: (G < 0? 0: G)) ;
143 	B = (B > 32767? 32767: (B < 0? 0: B)) ;
144 	A = (A > 32767? 32767: (A < 0? 0: A)) ;
145 
146 	// Compute quantized values.
147 	R &= quantizationMask[quant] ;
148 	G &= quantizationMask[quant] ;
149 	B &= quantizationMask[quant] ;
150 	A &= quantizationMask[quant] ;
151 
152 	// Copy and retain absolute color for mesh buffer lookup.
153 	rAbsolute = R ;
154 	gAbsolute = G ;
155 	bAbsolute = B ;
156 	aAbsolute = A ;
157 
158 	// Compute deltas.
159 	R -= stream.lastColor[0] ;
160 	G -= stream.lastColor[1] ;
161 	B -= stream.lastColor[2] ;
162 	A -= stream.lastColor[3] ;
163 
164 	// Update last values.
165 	stream.lastColor[0] += R ;
166 	stream.lastColor[1] += G ;
167 	stream.lastColor[2] += B ;
168 	stream.lastColor[3] += A ;
169 
170 	// Compute length and shift common to all components.
171 	if (color3)
172 	    computeLengthShift(R, G, B) ;
173 
174 	else if (color4)
175 	    computeLengthShift(R, G, B, A) ;
176 
177 	// 0-length components are allowed only for normals.
178 	if (length == 0)
179 	    length = 1 ;
180 
181 	// Add this element to the Huffman table associated with this stream.
182 	huffmanTable.addColorEntry(length, shift, absolute) ;
183     }
184 
185     /**
186      * Output a setColor command.
187      *
188      * @param table HuffmanTable mapping quantized representations to
189      * compressed encodings
190      * @param output CommandStream for collecting compressed output
191      */
outputCommand(HuffmanTable table, CommandStream output)192     void outputCommand(HuffmanTable table, CommandStream output) {
193 	outputColor(table, output, CommandStream.SET_COLOR, 8) ;
194     }
195 
196     /**
197      * Output a color subcommand.
198      *
199      * @param table HuffmanTable mapping quantized representations to
200      * compressed encodings
201      * @param output CommandStream for collecting compressed output
202      */
outputSubcommand(HuffmanTable table, CommandStream output)203     void outputSubcommand(HuffmanTable table, CommandStream output) {
204 
205 	outputColor(table, output, 0, 6) ;
206     }
207 
208     //
209     // Output the final compressed bits to the output command stream.
210     //
outputColor(HuffmanTable table, CommandStream output, int header, int headerLength)211     private void outputColor(HuffmanTable table, CommandStream output,
212 			     int header, int headerLength) {
213  	HuffmanNode t ;
214 
215 	// Look up the Huffman token for this compression stream element.
216 	t = table.getColorEntry(length, shift, absolute) ;
217 
218 	// Construct the color subcommand components.  The maximum length of a
219 	// color subcommand is 70 bits (a tag with a length of 6 followed by 4
220 	// components of 16 bits each).  The subcommand is therefore
221 	// constructed initially using just the first 3 components, with the
222 	// 4th component added later after the tag has been shifted into the
223 	// subcommand header.
224 	int componentLength = t.dataLength - t.shift ;
225 	int subcommandLength = t.tagLength + (3 * componentLength) ;
226 
227 	R = (R >> t.shift) & (int)lengthMask[componentLength] ;
228 	G = (G >> t.shift) & (int)lengthMask[componentLength] ;
229 	B = (B >> t.shift) & (int)lengthMask[componentLength] ;
230 
231 	long colorSubcommand =
232 	    (((long)t.tag) << (3 * componentLength)) |
233 	    (((long)R)     << (2 * componentLength)) |
234 	    (((long)G)     << (1 * componentLength)) |
235 	    (((long)B)     << (0 * componentLength)) ;
236 
237 	if (subcommandLength < 6) {
238 	    // The header will have some empty bits.  The Huffman tag
239 	    // computation will prevent this if necessary.
240 	    header |= (int)(colorSubcommand << (6 - subcommandLength)) ;
241 	    subcommandLength = 0 ;
242 	}
243 	else {
244 	    // Move the 1st 6 bits of the subcommand into the header.
245 	    header |= (int)(colorSubcommand >>> (subcommandLength - 6)) ;
246 	    subcommandLength -= 6 ;
247 	}
248 
249 	// Add alpha if present.
250 	if (color4) {
251 	    A = (A >> t.shift) & (int)lengthMask[componentLength] ;
252 	    colorSubcommand = (colorSubcommand << componentLength) | A ;
253 	    subcommandLength += componentLength ;
254 	}
255 
256 	// Add the header and body to the output buffer.
257 	output.addCommand(header, headerLength,
258 			  colorSubcommand, subcommandLength)  ;
259     }
260 
toString()261     public String toString() {
262 	String d = absolute? "" : "delta " ;
263 	String c = (colorR + " " + colorG + " " + colorB +
264 		    (color4? (" " + colorA): "")) ;
265 
266 	return
267 	    "color: " + c + "\n" +
268 	    " fixed point " + d + + R + " " + G + " " + B + "\n" +
269 	    " length " + length + " shift " + shift +
270 	    (absolute? " absolute" : " relative") ;
271     }
272 }
273