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