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