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