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