1 /* -----------------------------------------------------------------------------
2
3 Copyright (c) 2006 Simon Brown si@sjbrown.co.uk
4
5 Permission is hereby granted, free of charge, to any person obtaining
6 a copy of this software and associated documentation files (the
7 "Software"), to deal in the Software without restriction, including
8 without limitation the rights to use, copy, modify, merge, publish,
9 distribute, sublicense, and/or sell copies of the Software, and to
10 permit persons to whom the Software is furnished to do so, subject to
11 the following conditions:
12
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 -------------------------------------------------------------------------- */
25
26 #include "alpha.h"
27
28 #include <climits>
29 #include <algorithm>
30
31 namespace squish {
32
FloatToInt(float a,int limit)33 static int FloatToInt( float a, int limit )
34 {
35 // use ANSI round-to-zero behaviour to get round-to-nearest
36 int i = ( int )( a + 0.5f );
37
38 // clamp to the limit
39 if( i < 0 )
40 i = 0;
41 else if( i > limit )
42 i = limit;
43
44 // done
45 return i;
46 }
47
CompressAlphaDxt3(u8 const * rgba,int mask,void * block)48 void CompressAlphaDxt3( u8 const* rgba, int mask, void* block )
49 {
50 u8* bytes = reinterpret_cast< u8* >( block );
51
52 // quantise and pack the alpha values pairwise
53 for( int i = 0; i < 8; ++i )
54 {
55 // quantise down to 4 bits
56 float alpha1 = ( float )rgba[8*i + 3] * ( 15.0f/255.0f );
57 float alpha2 = ( float )rgba[8*i + 7] * ( 15.0f/255.0f );
58 int quant1 = FloatToInt( alpha1, 15 );
59 int quant2 = FloatToInt( alpha2, 15 );
60
61 // set alpha to zero where masked
62 int bit1 = 1 << ( 2*i );
63 int bit2 = 1 << ( 2*i + 1 );
64 if( ( mask & bit1 ) == 0 )
65 quant1 = 0;
66 if( ( mask & bit2 ) == 0 )
67 quant2 = 0;
68
69 // pack into the byte
70 bytes[i] = ( u8 )( quant1 | ( quant2 << 4 ) );
71 }
72 }
73
DecompressAlphaDxt3(u8 * rgba,void const * block)74 void DecompressAlphaDxt3( u8* rgba, void const* block )
75 {
76 u8 const* bytes = reinterpret_cast< u8 const* >( block );
77
78 // unpack the alpha values pairwise
79 for( int i = 0; i < 8; ++i )
80 {
81 // quantise down to 4 bits
82 u8 quant = bytes[i];
83
84 // unpack the values
85 u8 lo = quant & 0x0f;
86 u8 hi = quant & 0xf0;
87
88 // convert back up to bytes
89 rgba[8*i + 3] = lo | ( lo << 4 );
90 rgba[8*i + 7] = hi | ( hi >> 4 );
91 }
92 }
93
FixRange(int & min,int & max,int steps)94 static void FixRange( int& min, int& max, int steps )
95 {
96 if( max - min < steps )
97 max = std::min( min + steps, 255 );
98 if( max - min < steps )
99 min = std::max( 0, max - steps );
100 }
101
FitCodes(u8 const * rgba,int mask,u8 const * codes,u8 * indices)102 static int FitCodes( u8 const* rgba, int mask, u8 const* codes, u8* indices )
103 {
104 // fit each alpha value to the codebook
105 int err = 0;
106 for( int i = 0; i < 16; ++i )
107 {
108 // check this pixel is valid
109 int bit = 1 << i;
110 if( ( mask & bit ) == 0 )
111 {
112 // use the first code
113 indices[i] = 0;
114 continue;
115 }
116
117 // find the least error and corresponding index
118 int value = rgba[4*i + 3];
119 int least = INT_MAX;
120 int index = 0;
121 for( int j = 0; j < 8; ++j )
122 {
123 // get the squared error from this code
124 int dist = ( int )value - ( int )codes[j];
125 dist *= dist;
126
127 // compare with the best so far
128 if( dist < least )
129 {
130 least = dist;
131 index = j;
132 }
133 }
134
135 // save this index and accumulate the error
136 indices[i] = ( u8 )index;
137 err += least;
138 }
139
140 // return the total error
141 return err;
142 }
143
WriteAlphaBlock(int alpha0,int alpha1,u8 const * indices,void * block)144 static void WriteAlphaBlock( int alpha0, int alpha1, u8 const* indices, void* block )
145 {
146 u8* bytes = reinterpret_cast< u8* >( block );
147
148 // write the first two bytes
149 bytes[0] = ( u8 )alpha0;
150 bytes[1] = ( u8 )alpha1;
151
152 // pack the indices with 3 bits each
153 u8* dest = bytes + 2;
154 u8 const* src = indices;
155 for( int i = 0; i < 2; ++i )
156 {
157 // pack 8 3-bit values
158 int value = 0;
159 for( int j = 0; j < 8; ++j )
160 {
161 int index = *src++;
162 value |= ( index << 3*j );
163 }
164
165 // store in 3 bytes
166 for( int j = 0; j < 3; ++j )
167 {
168 int byte = ( value >> 8*j ) & 0xff;
169 *dest++ = ( u8 )byte;
170 }
171 }
172 }
173
WriteAlphaBlock5(int alpha0,int alpha1,u8 const * indices,void * block)174 static void WriteAlphaBlock5( int alpha0, int alpha1, u8 const* indices, void* block )
175 {
176 // check the relative values of the endpoints
177 if( alpha0 > alpha1 )
178 {
179 // swap the indices
180 u8 swapped[16];
181 for( int i = 0; i < 16; ++i )
182 {
183 u8 index = indices[i];
184 if( index == 0 )
185 swapped[i] = 1;
186 else if( index == 1 )
187 swapped[i] = 0;
188 else if( index <= 5 )
189 swapped[i] = 7 - index;
190 else
191 swapped[i] = index;
192 }
193
194 // write the block
195 WriteAlphaBlock( alpha1, alpha0, swapped, block );
196 }
197 else
198 {
199 // write the block
200 WriteAlphaBlock( alpha0, alpha1, indices, block );
201 }
202 }
203
WriteAlphaBlock7(int alpha0,int alpha1,u8 const * indices,void * block)204 static void WriteAlphaBlock7( int alpha0, int alpha1, u8 const* indices, void* block )
205 {
206 // check the relative values of the endpoints
207 if( alpha0 < alpha1 )
208 {
209 // swap the indices
210 u8 swapped[16];
211 for( int i = 0; i < 16; ++i )
212 {
213 u8 index = indices[i];
214 if( index == 0 )
215 swapped[i] = 1;
216 else if( index == 1 )
217 swapped[i] = 0;
218 else
219 swapped[i] = 9 - index;
220 }
221
222 // write the block
223 WriteAlphaBlock( alpha1, alpha0, swapped, block );
224 }
225 else
226 {
227 // write the block
228 WriteAlphaBlock( alpha0, alpha1, indices, block );
229 }
230 }
231
CompressAlphaDxt5(u8 const * rgba,int mask,void * block)232 void CompressAlphaDxt5( u8 const* rgba, int mask, void* block )
233 {
234 // get the range for 5-alpha and 7-alpha interpolation
235 int min5 = 255;
236 int max5 = 0;
237 int min7 = 255;
238 int max7 = 0;
239 for( int i = 0; i < 16; ++i )
240 {
241 // check this pixel is valid
242 int bit = 1 << i;
243 if( ( mask & bit ) == 0 )
244 continue;
245
246 // incorporate into the min/max
247 int value = rgba[4*i + 3];
248 if( value < min7 )
249 min7 = value;
250 if( value > max7 )
251 max7 = value;
252 if( value != 0 && value < min5 )
253 min5 = value;
254 if( value != 255 && value > max5 )
255 max5 = value;
256 }
257
258 // handle the case that no valid range was found
259 if( min5 > max5 )
260 min5 = max5;
261 if( min7 > max7 )
262 min7 = max7;
263
264 // fix the range to be the minimum in each case
265 FixRange( min5, max5, 5 );
266 FixRange( min7, max7, 7 );
267
268 // set up the 5-alpha code book
269 u8 codes5[8];
270 codes5[0] = ( u8 )min5;
271 codes5[1] = ( u8 )max5;
272 for( int i = 1; i < 5; ++i )
273 codes5[1 + i] = ( u8 )( ( ( 5 - i )*min5 + i*max5 )/5 );
274 codes5[6] = 0;
275 codes5[7] = 255;
276
277 // set up the 7-alpha code book
278 u8 codes7[8];
279 codes7[0] = ( u8 )min7;
280 codes7[1] = ( u8 )max7;
281 for( int i = 1; i < 7; ++i )
282 codes7[1 + i] = ( u8 )( ( ( 7 - i )*min7 + i*max7 )/7 );
283
284 // fit the data to both code books
285 u8 indices5[16];
286 u8 indices7[16];
287 int err5 = FitCodes( rgba, mask, codes5, indices5 );
288 int err7 = FitCodes( rgba, mask, codes7, indices7 );
289
290 // save the block with least error
291 if( err5 <= err7 )
292 WriteAlphaBlock5( min5, max5, indices5, block );
293 else
294 WriteAlphaBlock7( min7, max7, indices7, block );
295 }
296
DecompressAlphaDxt5(u8 * rgba,void const * block)297 void DecompressAlphaDxt5( u8* rgba, void const* block )
298 {
299 // get the two alpha values
300 u8 const* bytes = reinterpret_cast< u8 const* >( block );
301 int alpha0 = bytes[0];
302 int alpha1 = bytes[1];
303
304 // compare the values to build the codebook
305 u8 codes[8];
306 codes[0] = ( u8 )alpha0;
307 codes[1] = ( u8 )alpha1;
308 if( alpha0 <= alpha1 )
309 {
310 // use 5-alpha codebook
311 for( int i = 1; i < 5; ++i )
312 codes[1 + i] = ( u8 )( ( ( 5 - i )*alpha0 + i*alpha1 )/5 );
313 codes[6] = 0;
314 codes[7] = 255;
315 }
316 else
317 {
318 // use 7-alpha codebook
319 for( int i = 1; i < 7; ++i )
320 codes[1 + i] = ( u8 )( ( ( 7 - i )*alpha0 + i*alpha1 )/7 );
321 }
322
323 // decode the indices
324 u8 indices[16];
325 u8 const* src = bytes + 2;
326 u8* dest = indices;
327 for( int i = 0; i < 2; ++i )
328 {
329 // grab 3 bytes
330 int value = 0;
331 for( int j = 0; j < 3; ++j )
332 {
333 int byte = *src++;
334 value |= ( byte << 8*j );
335 }
336
337 // unpack 8 3-bit values from it
338 for( int j = 0; j < 8; ++j )
339 {
340 int index = ( value >> 3*j ) & 0x7;
341 *dest++ = ( u8 )index;
342 }
343 }
344
345 // write out the indexed codebook values
346 for( int i = 0; i < 16; ++i )
347 rgba[4*i + 3] = codes[indices[i]];
348 }
349
350 } // namespace squish
351