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 "colourblock.h"
27 
28 namespace squish {
29 
FloatToInt(float a,int limit)30 static int FloatToInt( float a, int limit )
31 {
32 	// use ANSI round-to-zero behaviour to get round-to-nearest
33 	int i = ( int )( a + 0.5f );
34 
35 	// clamp to the limit
36 	if( i < 0 )
37 		i = 0;
38 	else if( i > limit )
39 		i = limit;
40 
41 	// done
42 	return i;
43 }
44 
FloatTo565(Vec3::Arg colour)45 static int FloatTo565( Vec3::Arg colour )
46 {
47 	// get the components in the correct range
48 	int r = FloatToInt( 31.0f*colour.X(), 31 );
49 	int g = FloatToInt( 63.0f*colour.Y(), 63 );
50 	int b = FloatToInt( 31.0f*colour.Z(), 31 );
51 
52 	// pack into a single value
53 	return ( r << 11 ) | ( g << 5 ) | b;
54 }
55 
WriteColourBlock(int a,int b,u8 * indices,void * block)56 static void WriteColourBlock( int a, int b, u8* indices, void* block )
57 {
58 	// get the block as bytes
59 	u8* bytes = ( u8* )block;
60 
61 	// write the endpoints
62 	bytes[0] = ( u8 )( a & 0xff );
63 	bytes[1] = ( u8 )( a >> 8 );
64 	bytes[2] = ( u8 )( b & 0xff );
65 	bytes[3] = ( u8 )( b >> 8 );
66 
67 	// write the indices
68 	for( int i = 0; i < 4; ++i )
69 	{
70 		u8 const* ind = indices + 4*i;
71 		bytes[4 + i] = ind[0] | ( ind[1] << 2 ) | ( ind[2] << 4 ) | ( ind[3] << 6 );
72 	}
73 }
74 
WriteColourBlock3(Vec3::Arg start,Vec3::Arg end,u8 const * indices,void * block)75 void WriteColourBlock3( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
76 {
77 	// get the packed values
78 	int a = FloatTo565( start );
79 	int b = FloatTo565( end );
80 
81 	// remap the indices
82 	u8 remapped[16];
83 	if( a <= b )
84 	{
85 		// use the indices directly
86 		for( int i = 0; i < 16; ++i )
87 			remapped[i] = indices[i];
88 	}
89 	else
90 	{
91 		// swap a and b
92 		std::swap( a, b );
93 		for( int i = 0; i < 16; ++i )
94 		{
95 			if( indices[i] == 0 )
96 				remapped[i] = 1;
97 			else if( indices[i] == 1 )
98 				remapped[i] = 0;
99 			else
100 				remapped[i] = indices[i];
101 		}
102 	}
103 
104 	// write the block
105 	WriteColourBlock( a, b, remapped, block );
106 }
107 
WriteColourBlock4(Vec3::Arg start,Vec3::Arg end,u8 const * indices,void * block)108 void WriteColourBlock4( Vec3::Arg start, Vec3::Arg end, u8 const* indices, void* block )
109 {
110 	// get the packed values
111 	int a = FloatTo565( start );
112 	int b = FloatTo565( end );
113 
114 	// remap the indices
115 	u8 remapped[16];
116 	if( a < b )
117 	{
118 		// swap a and b
119 		std::swap( a, b );
120 		for( int i = 0; i < 16; ++i )
121 			remapped[i] = ( indices[i] ^ 0x1 ) & 0x3;
122 	}
123 	else if( a == b )
124 	{
125 		// use index 0
126 		for( int i = 0; i < 16; ++i )
127 			remapped[i] = 0;
128 	}
129 	else
130 	{
131 		// use the indices directly
132 		for( int i = 0; i < 16; ++i )
133 			remapped[i] = indices[i];
134 	}
135 
136 	// write the block
137 	WriteColourBlock( a, b, remapped, block );
138 }
139 
Unpack565(u8 const * packed,u8 * colour)140 static int Unpack565( u8 const* packed, u8* colour )
141 {
142 	// build the packed value
143 	int value = ( int )packed[0] | ( ( int )packed[1] << 8 );
144 
145 	// get the components in the stored range
146 	u8 red = ( u8 )( ( value >> 11 ) & 0x1f );
147 	u8 green = ( u8 )( ( value >> 5 ) & 0x3f );
148 	u8 blue = ( u8 )( value & 0x1f );
149 
150 	// scale up to 8 bits
151 	colour[0] = ( red << 3 ) | ( red >> 2 );
152 	colour[1] = ( green << 2 ) | ( green >> 4 );
153 	colour[2] = ( blue << 3 ) | ( blue >> 2 );
154 	colour[3] = 255;
155 
156 	// return the value
157 	return value;
158 }
159 
DecompressColour(u8 * rgba,void const * block,bool isDxt1)160 void DecompressColour( u8* rgba, void const* block, bool isDxt1 )
161 {
162 	// get the block bytes
163 	u8 const* bytes = reinterpret_cast< u8 const* >( block );
164 
165 	// unpack the endpoints
166 	u8 codes[16];
167 	int a = Unpack565( bytes, codes );
168 	int b = Unpack565( bytes + 2, codes + 4 );
169 
170 	// generate the midpoints
171 	for( int i = 0; i < 3; ++i )
172 	{
173 		int c = codes[i];
174 		int d = codes[4 + i];
175 
176 		if( isDxt1 && a <= b )
177 		{
178 			codes[8 + i] = ( u8 )( ( c + d )/2 );
179 			codes[12 + i] = 0;
180 		}
181 		else
182 		{
183 			codes[8 + i] = ( u8 )( ( 2*c + d )/3 );
184 			codes[12 + i] = ( u8 )( ( c + 2*d )/3 );
185 		}
186 	}
187 
188 	// fill in alpha for the intermediate values
189 	codes[8 + 3] = 255;
190 	codes[12 + 3] = ( isDxt1 && a <= b ) ? 0 : 255;
191 
192 	// unpack the indices
193 	u8 indices[16];
194 	for( int i = 0; i < 4; ++i )
195 	{
196 		u8* ind = indices + 4*i;
197 		u8 packed = bytes[4 + i];
198 
199 		ind[0] = packed & 0x3;
200 		ind[1] = ( packed >> 2 ) & 0x3;
201 		ind[2] = ( packed >> 4 ) & 0x3;
202 		ind[3] = ( packed >> 6 ) & 0x3;
203 	}
204 
205 	// store out the colours
206 	for( int i = 0; i < 16; ++i )
207 	{
208 		u8 offset = 4*indices[i];
209 		for( int j = 0; j < 4; ++j )
210 			rgba[4*i + j] = codes[offset + j];
211 	}
212 }
213 
214 } // namespace squish
215