1*2f083884Ss.makeev_local /* -----------------------------------------------------------------------------
2*2f083884Ss.makeev_local 
3*2f083884Ss.makeev_local 	Copyright (c) 2006 Simon Brown                          [email protected]
4*2f083884Ss.makeev_local 
5*2f083884Ss.makeev_local 	Permission is hereby granted, free of charge, to any person obtaining
6*2f083884Ss.makeev_local 	a copy of this software and associated documentation files (the
7*2f083884Ss.makeev_local 	"Software"), to	deal in the Software without restriction, including
8*2f083884Ss.makeev_local 	without limitation the rights to use, copy, modify, merge, publish,
9*2f083884Ss.makeev_local 	distribute, sublicense, and/or sell copies of the Software, and to
10*2f083884Ss.makeev_local 	permit persons to whom the Software is furnished to do so, subject to
11*2f083884Ss.makeev_local 	the following conditions:
12*2f083884Ss.makeev_local 
13*2f083884Ss.makeev_local 	The above copyright notice and this permission notice shall be included
14*2f083884Ss.makeev_local 	in all copies or substantial portions of the Software.
15*2f083884Ss.makeev_local 
16*2f083884Ss.makeev_local 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17*2f083884Ss.makeev_local 	OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18*2f083884Ss.makeev_local 	MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19*2f083884Ss.makeev_local 	IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20*2f083884Ss.makeev_local 	CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21*2f083884Ss.makeev_local 	TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22*2f083884Ss.makeev_local 	SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23*2f083884Ss.makeev_local 
24*2f083884Ss.makeev_local    -------------------------------------------------------------------------- */
25*2f083884Ss.makeev_local 
26*2f083884Ss.makeev_local #include "colourblock.h"
27*2f083884Ss.makeev_local 
28*2f083884Ss.makeev_local namespace squish {
29*2f083884Ss.makeev_local 
FloatToInt(float a,int limit)30*2f083884Ss.makeev_local static int FloatToInt( float a, int limit )
31*2f083884Ss.makeev_local {
32*2f083884Ss.makeev_local 	// use ANSI round-to-zero behaviour to get round-to-nearest
33*2f083884Ss.makeev_local 	int i = ( int )( a + 0.5f );
34*2f083884Ss.makeev_local 
35*2f083884Ss.makeev_local 	// clamp to the limit
36*2f083884Ss.makeev_local 	if( i < 0 )
37*2f083884Ss.makeev_local 		i = 0;
38*2f083884Ss.makeev_local 	else if( i > limit )
39*2f083884Ss.makeev_local 		i = limit;
40*2f083884Ss.makeev_local 
41*2f083884Ss.makeev_local 	// done
42*2f083884Ss.makeev_local 	return i;
43*2f083884Ss.makeev_local }
44*2f083884Ss.makeev_local 
FloatTo565(Vec3::Arg colour)45*2f083884Ss.makeev_local static int FloatTo565( Vec3::Arg colour )
46*2f083884Ss.makeev_local {
47*2f083884Ss.makeev_local 	// get the components in the correct range
48*2f083884Ss.makeev_local 	int r = FloatToInt( 31.0f*colour.X(), 31 );
49*2f083884Ss.makeev_local 	int g = FloatToInt( 63.0f*colour.Y(), 63 );
50*2f083884Ss.makeev_local 	int b = FloatToInt( 31.0f*colour.Z(), 31 );
51*2f083884Ss.makeev_local 
52*2f083884Ss.makeev_local 	// pack into a single value
53*2f083884Ss.makeev_local 	return ( r << 11 ) | ( g << 5 ) | b;
54*2f083884Ss.makeev_local }
55*2f083884Ss.makeev_local 
WriteColourBlock(int a,int b,u8 * indices,void * block)56*2f083884Ss.makeev_local static void WriteColourBlock( int a, int b, u8* indices, void* block )
57*2f083884Ss.makeev_local {
58*2f083884Ss.makeev_local 	// get the block as bytes
59*2f083884Ss.makeev_local 	u8* bytes = ( u8* )block;
60*2f083884Ss.makeev_local 
61*2f083884Ss.makeev_local 	// write the endpoints
62*2f083884Ss.makeev_local 	bytes[0] = ( u8 )( a & 0xff );
63*2f083884Ss.makeev_local 	bytes[1] = ( u8 )( a >> 8 );
64*2f083884Ss.makeev_local 	bytes[2] = ( u8 )( b & 0xff );
65*2f083884Ss.makeev_local 	bytes[3] = ( u8 )( b >> 8 );
66*2f083884Ss.makeev_local 
67*2f083884Ss.makeev_local 	// write the indices
68*2f083884Ss.makeev_local 	for( int i = 0; i < 4; ++i )
69*2f083884Ss.makeev_local 	{
70*2f083884Ss.makeev_local 		u8 const* ind = indices + 4*i;
71*2f083884Ss.makeev_local 		bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 );
72*2f083884Ss.makeev_local 	}
73*2f083884Ss.makeev_local }
74*2f083884Ss.makeev_local 
WriteColourBlock3(Vec3::Arg start,Vec3::Arg end,u8 const * indices,void * block)75*2f083884Ss.makeev_local void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
76*2f083884Ss.makeev_local {
77*2f083884Ss.makeev_local 	// get the packed values
78*2f083884Ss.makeev_local 	int a = FloatTo565( start );
79*2f083884Ss.makeev_local 	int b = FloatTo565( end );
80*2f083884Ss.makeev_local 
81*2f083884Ss.makeev_local 	// remap the indices
82*2f083884Ss.makeev_local 	u8 remapped[16];
83*2f083884Ss.makeev_local 	if( a <= b )
84*2f083884Ss.makeev_local 	{
85*2f083884Ss.makeev_local 		// use the indices directly
86*2f083884Ss.makeev_local 		for( int i = 0; i < 16; ++i )
87*2f083884Ss.makeev_local 			remapped[i] = indices[i];
88*2f083884Ss.makeev_local 	}
89*2f083884Ss.makeev_local 	else
90*2f083884Ss.makeev_local 	{
91*2f083884Ss.makeev_local 		// swap a and b
92*2f083884Ss.makeev_local 		std::swap( a, b );
93*2f083884Ss.makeev_local 		for( int i = 0; i < 16; ++i )
94*2f083884Ss.makeev_local 		{
95*2f083884Ss.makeev_local 			if( indices[i] == 0 )
96*2f083884Ss.makeev_local 				remapped[i] = 1;
97*2f083884Ss.makeev_local 			else if( indices[i] == 1 )
98*2f083884Ss.makeev_local 				remapped[i] = 0;
99*2f083884Ss.makeev_local 			else
100*2f083884Ss.makeev_local 				remapped[i] = indices[i];
101*2f083884Ss.makeev_local 		}
102*2f083884Ss.makeev_local 	}
103*2f083884Ss.makeev_local 
104*2f083884Ss.makeev_local 	// write the block
105*2f083884Ss.makeev_local 	WriteColourBlock( a, b, remapped, block );
106*2f083884Ss.makeev_local }
107*2f083884Ss.makeev_local 
WriteColourBlock4(Vec3::Arg start,Vec3::Arg end,u8 const * indices,void * block)108*2f083884Ss.makeev_local void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
109*2f083884Ss.makeev_local {
110*2f083884Ss.makeev_local 	// get the packed values
111*2f083884Ss.makeev_local 	int a = FloatTo565( start );
112*2f083884Ss.makeev_local 	int b = FloatTo565( end );
113*2f083884Ss.makeev_local 
114*2f083884Ss.makeev_local 	// remap the indices
115*2f083884Ss.makeev_local 	u8 remapped[16];
116*2f083884Ss.makeev_local 	if( a < b )
117*2f083884Ss.makeev_local 	{
118*2f083884Ss.makeev_local 		// swap a and b
119*2f083884Ss.makeev_local 		std::swap( a, b );
120*2f083884Ss.makeev_local 		for( int i = 0; i < 16; ++i )
121*2f083884Ss.makeev_local 			remapped[i] = ( indices[i] ^ 0x1 ) & 0x3;
122*2f083884Ss.makeev_local 	}
123*2f083884Ss.makeev_local 	else if( a == b )
124*2f083884Ss.makeev_local 	{
125*2f083884Ss.makeev_local 		// use index 0
126*2f083884Ss.makeev_local 		for( int i = 0; i < 16; ++i )
127*2f083884Ss.makeev_local 			remapped[i] = 0;
128*2f083884Ss.makeev_local 	}
129*2f083884Ss.makeev_local 	else
130*2f083884Ss.makeev_local 	{
131*2f083884Ss.makeev_local 		// use the indices directly
132*2f083884Ss.makeev_local 		for( int i = 0; i < 16; ++i )
133*2f083884Ss.makeev_local 			remapped[i] = indices[i];
134*2f083884Ss.makeev_local 	}
135*2f083884Ss.makeev_local 
136*2f083884Ss.makeev_local 	// write the block
137*2f083884Ss.makeev_local 	WriteColourBlock( a, b, remapped, block );
138*2f083884Ss.makeev_local }
139*2f083884Ss.makeev_local 
Unpack565(u8 const * packed,u8 * colour)140*2f083884Ss.makeev_local static int Unpack565( u8 const* packed, u8* colour )
141*2f083884Ss.makeev_local {
142*2f083884Ss.makeev_local 	// build the packed value
143*2f083884Ss.makeev_local 	int value = ( int )packed[0] | ( ( int )packed[1] << 8 );
144*2f083884Ss.makeev_local 
145*2f083884Ss.makeev_local 	// get the components in the stored range
146*2f083884Ss.makeev_local 	u8 red = ( u8 )( ( value >> 11 ) & 0x1f );
147*2f083884Ss.makeev_local 	u8 green = ( u8 )( ( value >> 5 ) & 0x3f );
148*2f083884Ss.makeev_local 	u8 blue = ( u8 )( value & 0x1f );
149*2f083884Ss.makeev_local 
150*2f083884Ss.makeev_local 	// scale up to 8 bits
151*2f083884Ss.makeev_local 	colour[0] = ( red << 3 ) | ( red >> 2 );
152*2f083884Ss.makeev_local 	colour[1] = ( green << 2 ) | ( green >> 4 );
153*2f083884Ss.makeev_local 	colour[2] = ( blue << 3 ) | ( blue >> 2 );
154*2f083884Ss.makeev_local 	colour[3] = 255;
155*2f083884Ss.makeev_local 
156*2f083884Ss.makeev_local 	// return the value
157*2f083884Ss.makeev_local 	return value;
158*2f083884Ss.makeev_local }
159*2f083884Ss.makeev_local 
DecompressColour(u8 * rgba,void const * block,bool isDxt1)160*2f083884Ss.makeev_local void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
161*2f083884Ss.makeev_local {
162*2f083884Ss.makeev_local 	// get the block bytes
163*2f083884Ss.makeev_local 	u8 const* bytes = reinterpret_cast< u8 const* >( block );
164*2f083884Ss.makeev_local 
165*2f083884Ss.makeev_local 	// unpack the endpoints
166*2f083884Ss.makeev_local 	u8 codes[16];
167*2f083884Ss.makeev_local 	int a = Unpack565( bytes, codes );
168*2f083884Ss.makeev_local 	int b = Unpack565( bytes + 2, codes + 4 );
169*2f083884Ss.makeev_local 
170*2f083884Ss.makeev_local 	// generate the midpoints
171*2f083884Ss.makeev_local 	for( int i = 0; i < 3; ++i )
172*2f083884Ss.makeev_local 	{
173*2f083884Ss.makeev_local 		int c = codes[i];
174*2f083884Ss.makeev_local 		int d = codes[4 + i];
175*2f083884Ss.makeev_local 
176*2f083884Ss.makeev_local 		if( isDxt1 && a <= b )
177*2f083884Ss.makeev_local 		{
178*2f083884Ss.makeev_local 			codes[8 + i] = ( u8 )( ( c + d )/2 );
179*2f083884Ss.makeev_local 			codes[12 + i] = 0;
180*2f083884Ss.makeev_local 		}
181*2f083884Ss.makeev_local 		else
182*2f083884Ss.makeev_local 		{
183*2f083884Ss.makeev_local 			codes[8 + i] = ( u8 )( ( 2*c + d )/3 );
184*2f083884Ss.makeev_local 			codes[12 + i] = ( u8 )( ( c + 2*d )/3 );
185*2f083884Ss.makeev_local 		}
186*2f083884Ss.makeev_local 	}
187*2f083884Ss.makeev_local 
188*2f083884Ss.makeev_local 	// fill in alpha for the intermediate values
189*2f083884Ss.makeev_local 	codes[8 + 3] = 255;
190*2f083884Ss.makeev_local 	codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255;
191*2f083884Ss.makeev_local 
192*2f083884Ss.makeev_local 	// unpack the indices
193*2f083884Ss.makeev_local 	u8 indices[16];
194*2f083884Ss.makeev_local 	for( int i = 0; i < 4; ++i )
195*2f083884Ss.makeev_local 	{
196*2f083884Ss.makeev_local 		u8* ind = indices + 4*i;
197*2f083884Ss.makeev_local 		u8 packed = bytes[4 + i];
198*2f083884Ss.makeev_local 
199*2f083884Ss.makeev_local 		ind[0] = packed & 0x3;
200*2f083884Ss.makeev_local 		ind[1] = ( packed >> 2 ) & 0x3;
201*2f083884Ss.makeev_local 		ind[2] = ( packed >> 4 ) & 0x3;
202*2f083884Ss.makeev_local 		ind[3] = ( packed >> 6 ) & 0x3;
203*2f083884Ss.makeev_local 	}
204*2f083884Ss.makeev_local 
205*2f083884Ss.makeev_local 	// store out the colours
206*2f083884Ss.makeev_local 	for( int i = 0; i < 16; ++i )
207*2f083884Ss.makeev_local 	{
208*2f083884Ss.makeev_local 		u8 offset = 4*indices[i];
209*2f083884Ss.makeev_local 		for( int j = 0; j < 4; ++j )
210*2f083884Ss.makeev_local 			rgba[4*i + j] = codes[offset + j];
211*2f083884Ss.makeev_local 	}
212*2f083884Ss.makeev_local }
213*2f083884Ss.makeev_local 
214*2f083884Ss.makeev_local } // namespace squish
215