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 #include <climits>
28 #include <algorithm>
29
30 namespace squish {
31
FloatToInt(float a,int limit)32 static int FloatToInt( float a, int limit )
33 {
34 // use ANSI round-to-zero behaviour to get round-to-nearest
35 int i = ( int )( a + 0.5f );
36
37 // clamp to the limit
38 if( i < 0 )
39 i = 0;
40 else if( i > limit )
41 i = limit;
42
43 // done
44 return i;
45 }
46
CompressAlphaDxt3(u8 const * rgba,int mask,void * block)47 void CompressAlphaDxt3( u8 const* rgba, int mask, void* block )
48 {
49 u8* bytes = reinterpret_cast< u8* >( block );
50
51 // quantise and pack the alpha values pairwise
52 for( int i = 0; i < 8; ++i )
53 {
54 // quantise down to 4 bits
55 float alpha1 = ( float )rgba[8*i + 3] * ( 15.0f/255.0f );
56 float alpha2 = ( float )rgba[8*i + 7] * ( 15.0f/255.0f );
57 int quant1 = FloatToInt( alpha1, 15 );
58 int quant2 = FloatToInt( alpha2, 15 );
59
60 // set alpha to zero where masked
61 int bit1 = 1 << ( 2*i );
62 int bit2 = 1 << ( 2*i + 1 );
63 if( ( mask & bit1 ) == 0 )
64 quant1 = 0;
65 if( ( mask & bit2 ) == 0 )
66 quant2 = 0;
67
68 // pack into the byte
69 bytes[i] = ( u8 )( quant1 | ( quant2 << 4 ) );
70 }
71 }
72
DecompressAlphaDxt3(u8 * rgba,void const * block)73 void DecompressAlphaDxt3( u8* rgba, void const* block )
74 {
75 u8 const* bytes = reinterpret_cast< u8 const* >( block );
76
77 // unpack the alpha values pairwise
78 for( int i = 0; i < 8; ++i )
79 {
80 // quantise down to 4 bits
81 u8 quant = bytes[i];
82
83 // unpack the values
84 u8 lo = quant & 0x0f;
85 u8 hi = quant & 0xf0;
86
87 // convert back up to bytes
88 rgba[8*i + 3] = lo | ( lo << 4 );
89 rgba[8*i + 7] = hi | ( hi >> 4 );
90 }
91 }
92
FixRange(int & min,int & max,int steps)93 static void FixRange( int& min, int& max, int steps )
94 {
95 if( max - min < steps )
96 max = std::min( min + steps, 255 );
97 if( max - min < steps )
98 min = std::max( 0, max - steps );
99 }
100
FitCodes(u8 const * rgba,int mask,u8 const * codes,u8 * indices)101 static int FitCodes( u8 const* rgba, int mask, u8 const* codes, u8* indices )
102 {
103 // fit each alpha value to the codebook
104 int err = 0;
105 for( int i = 0; i < 16; ++i )
106 {
107 // check this pixel is valid
108 int bit = 1 << i;
109 if( ( mask & bit ) == 0 )
110 {
111 // use the first code
112 indices[i] = 0;
113 continue;
114 }
115
116 // find the least error and corresponding index
117 int value = rgba[4*i + 3];
118 int least = INT_MAX;
119 int index = 0;
120 for( int j = 0; j < 8; ++j )
121 {
122 // get the squared error from this code
123 int dist = ( int )value - ( int )codes[j];
124 dist *= dist;
125
126 // compare with the best so far
127 if( dist < least )
128 {
129 least = dist;
130 index = j;
131 }
132 }
133
134 // save this index and accumulate the error
135 indices[i] = ( u8 )index;
136 err += least;
137 }
138
139 // return the total error
140 return err;
141 }
142
WriteAlphaBlock(int alpha0,int alpha1,u8 const * indices,void * block)143 static void WriteAlphaBlock( int alpha0, int alpha1, u8 const* indices, void* block )
144 {
145 u8* bytes = reinterpret_cast< u8* >( block );
146
147 // write the first two bytes
148 bytes[0] = ( u8 )alpha0;
149 bytes[1] = ( u8 )alpha1;
150
151 // pack the indices with 3 bits each
152 u8* dest = bytes + 2;
153 u8 const* src = indices;
154 for( int i = 0; i < 2; ++i )
155 {
156 // pack 8 3-bit values
157 int value = 0;
158 for( int j = 0; j < 8; ++j )
159 {
160 int index = *src++;
161 value |= ( index << 3*j );
162 }
163
164 // store in 3 bytes
165 for( int j = 0; j < 3; ++j )
166 {
167 int byte = ( value >> 8*j ) & 0xff;
168 *dest++ = ( u8 )byte;
169 }
170 }
171 }
172
WriteAlphaBlock5(int alpha0,int alpha1,u8 const * indices,void * block)173 static void WriteAlphaBlock5( int alpha0, int alpha1, u8 const* indices, void* block )
174 {
175 // check the relative values of the endpoints
176 if( alpha0 > alpha1 )
177 {
178 // swap the indices
179 u8 swapped[16];
180 for( int i = 0; i < 16; ++i )
181 {
182 u8 index = indices[i];
183 if( index == 0 )
184 swapped[i] = 1;
185 else if( index == 1 )
186 swapped[i] = 0;
187 else if( index <= 5 )
188 swapped[i] = 7 - index;
189 else
190 swapped[i] = index;
191 }
192
193 // write the block
194 WriteAlphaBlock( alpha1, alpha0, swapped, block );
195 }
196 else
197 {
198 // write the block
199 WriteAlphaBlock( alpha0, alpha1, indices, block );
200 }
201 }
202
WriteAlphaBlock7(int alpha0,int alpha1,u8 const * indices,void * block)203 static void WriteAlphaBlock7( int alpha0, int alpha1, u8 const* indices, void* block )
204 {
205 // check the relative values of the endpoints
206 if( alpha0 < alpha1 )
207 {
208 // swap the indices
209 u8 swapped[16];
210 for( int i = 0; i < 16; ++i )
211 {
212 u8 index = indices[i];
213 if( index == 0 )
214 swapped[i] = 1;
215 else if( index == 1 )
216 swapped[i] = 0;
217 else
218 swapped[i] = 9 - index;
219 }
220
221 // write the block
222 WriteAlphaBlock( alpha1, alpha0, swapped, block );
223 }
224 else
225 {
226 // write the block
227 WriteAlphaBlock( alpha0, alpha1, indices, block );
228 }
229 }
230
CompressAlphaDxt5(u8 const * rgba,int mask,void * block)231 void CompressAlphaDxt5( u8 const* rgba, int mask, void* block )
232 {
233 // get the range for 5-alpha and 7-alpha interpolation
234 int min5 = 255;
235 int max5 = 0;
236 int min7 = 255;
237 int max7 = 0;
238 for( int i = 0; i < 16; ++i )
239 {
240 // check this pixel is valid
241 int bit = 1 << i;
242 if( ( mask & bit ) == 0 )
243 continue;
244
245 // incorporate into the min/max
246 int value = rgba[4*i + 3];
247 if( value < min7 )
248 min7 = value;
249 if( value > max7 )
250 max7 = value;
251 if( value != 0 && value < min5 )
252 min5 = value;
253 if( value != 255 && value > max5 )
254 max5 = value;
255 }
256
257 // handle the case that no valid range was found
258 if( min5 > max5 )
259 min5 = max5;
260 if( min7 > max7 )
261 min7 = max7;
262
263 // fix the range to be the minimum in each case
264 FixRange( min5, max5, 5 );
265 FixRange( min7, max7, 7 );
266
267 // set up the 5-alpha code book
268 u8 codes5[8];
269 codes5[0] = ( u8 )min5;
270 codes5[1] = ( u8 )max5;
271 for( int i = 1; i < 5; ++i )
272 codes5[1 + i] = ( u8 )( ( ( 5 - i )*min5 + i*max5 )/5 );
273 codes5[6] = 0;
274 codes5[7] = 255;
275
276 // set up the 7-alpha code book
277 u8 codes7[8];
278 codes7[0] = ( u8 )min7;
279 codes7[1] = ( u8 )max7;
280 for( int i = 1; i < 7; ++i )
281 codes7[1 + i] = ( u8 )( ( ( 7 - i )*min7 + i*max7 )/7 );
282
283 // fit the data to both code books
284 u8 indices5[16];
285 u8 indices7[16];
286 int err5 = FitCodes( rgba, mask, codes5, indices5 );
287 int err7 = FitCodes( rgba, mask, codes7, indices7 );
288
289 // save the block with least error
290 if( err5 <= err7 )
291 WriteAlphaBlock5( min5, max5, indices5, block );
292 else
293 WriteAlphaBlock7( min7, max7, indices7, block );
294 }
295
DecompressAlphaDxt5(u8 * rgba,void const * block)296 void DecompressAlphaDxt5( u8* rgba, void const* block )
297 {
298 // get the two alpha values
299 u8 const* bytes = reinterpret_cast< u8 const* >( block );
300 int alpha0 = bytes[0];
301 int alpha1 = bytes[1];
302
303 // compare the values to build the codebook
304 u8 codes[8];
305 codes[0] = ( u8 )alpha0;
306 codes[1] = ( u8 )alpha1;
307 if( alpha0 <= alpha1 )
308 {
309 // use 5-alpha codebook
310 for( int i = 1; i < 5; ++i )
311 codes[1 + i] = ( u8 )( ( ( 5 - i )*alpha0 + i*alpha1 )/5 );
312 codes[6] = 0;
313 codes[7] = 255;
314 }
315 else
316 {
317 // use 7-alpha codebook
318 for( int i = 1; i < 7; ++i )
319 codes[1 + i] = ( u8 )( ( ( 7 - i )*alpha0 + i*alpha1 )/7 );
320 }
321
322 // decode the indices
323 u8 indices[16];
324 u8 const* src = bytes + 2;
325 u8* dest = indices;
326 for( int i = 0; i < 2; ++i )
327 {
328 // grab 3 bytes
329 int value = 0;
330 for( int j = 0; j < 3; ++j )
331 {
332 int byte = *src++;
333 value |= ( byte << 8*j );
334 }
335
336 // unpack 8 3-bit values from it
337 for( int j = 0; j < 8; ++j )
338 {
339 int index = ( value >> 3*j ) & 0x7;
340 *dest++ = ( u8 )index;
341 }
342 }
343
344 // write out the indexed codebook values
345 for( int i = 0; i < 16; ++i )
346 rgba[4*i + 3] = codes[indices[i]];
347 }
348
349 } // namespace squish
350