DXTEncoder.cpp (135362B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 /* 29 ================================================================================================ 30 Contains the DxtEncoder implementation. 31 ================================================================================================ 32 */ 33 34 #pragma hdrstop 35 #include "DXTCodec_local.h" 36 #include "DXTCodec.h" 37 38 #define INSET_COLOR_SHIFT 4 // inset the bounding box with ( range >> shift ) 39 #define INSET_ALPHA_SHIFT 5 // inset alpha channel 40 41 #define C565_5_MASK 0xF8 // 0xFF minus last three bits 42 #define C565_6_MASK 0xFC // 0xFF minus last two bits 43 44 #define NVIDIA_7X_HARDWARE_BUG_FIX // keep the DXT5 colors sorted as: max, min 45 46 typedef uint16 word; 47 typedef uint32 dword; 48 49 /* 50 ======================== 51 idDxtEncoder::NV4XHardwareBugFix 52 ======================== 53 */ 54 void idDxtEncoder::NV4XHardwareBugFix( byte *minColor, byte *maxColor ) const { 55 #ifdef ID_WIN_X86_ASM 56 int minq = ( ( minColor[0] << 16 ) | ( minColor[1] << 8 ) | minColor[2] ) & 0x00F8FCF8; 57 int maxq = ( ( maxColor[0] << 16 ) | ( maxColor[1] << 8 ) | maxColor[2] ) & 0x00F8FCF8; 58 int mask = -( minq > maxq ) & 0x00FFFFFF; 59 int min = *(int *)minColor; 60 int max = *(int *)maxColor; 61 min ^= max; 62 max ^= ( min & mask ); 63 min ^= max; 64 *(int *)minColor = min; 65 *(int *)maxColor = max; 66 #else 67 if ( ColorTo565( minColor ) > ColorTo565( maxColor ) ) { 68 SwapValues( minColor[0], maxColor[0] ); 69 SwapValues( minColor[1], maxColor[1] ); 70 SwapValues( minColor[2], maxColor[2] ); 71 } 72 #endif 73 } 74 75 /* 76 ======================== 77 idDxtEncoder::HasConstantValuePer4x4Block 78 ======================== 79 */ 80 bool idDxtEncoder::HasConstantValuePer4x4Block( const byte *inBuf, int width, int height, int channel ) const { 81 if ( width < 4 || height < 4 ) { 82 byte value = inBuf[channel]; 83 for ( int k = 0; k < height; k++ ) { 84 for ( int l = 0; l < width; l++ ) { 85 if ( inBuf[(k*width+l)*4+channel] != value ) { 86 return false; 87 } 88 } 89 } 90 return true; 91 } 92 93 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 94 for ( int i = 0; i < width; i += 4 ) { 95 const byte *inPtr = inBuf + i * 4; 96 byte value = inPtr[channel]; 97 for ( int k = 0; k < 4; k++ ) { 98 for ( int l = 0; l < 4; l++ ) { 99 if ( inPtr[(k*width+l)*4+channel] != value ) { 100 return false; 101 } 102 } 103 } 104 } 105 inBuf += srcPadding; 106 } 107 return true; 108 } 109 110 /* 111 ======================== 112 idDxtEncoder::WriteTinyColorDXT1 113 ======================== 114 */ 115 void idDxtEncoder::WriteTinyColorDXT1( const byte *inBuf, int width, int height ) { 116 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 117 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 118 // example: 2x8 pixels 119 // numBlocks = 2 120 // stride = 32 bytes (8 pixels) 121 122 for ( int i = 0; i < numBlocks; i++ ) { 123 // FIXME: This just emits a fake block based on the color at position 0,0 124 EmitUShort( ColorTo565( inBuf ) ); 125 EmitUShort( 0 ); // dummy, never used 126 EmitUInt( 0 ); // 4 color index bytes all use the first color 127 128 inBuf += stride; 129 } 130 } 131 132 /* 133 ======================== 134 idDxtEncoder::WriteTinyColorDXT5 135 ======================== 136 */ 137 void idDxtEncoder::WriteTinyColorDXT5( const byte *inBuf, int width, int height ) { 138 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 139 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 140 // example: 2x8 pixels 141 // numBlocks = 2 142 // stride = 32 bytes (8 pixels) 143 144 for ( int i = 0; i < numBlocks; i++ ) { 145 // FIXME: This just emits a fake block based on the color at position 0,0 146 EmitByte( inBuf[3] ); 147 EmitByte( 0 ); // dummy, never used 148 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 149 EmitByte( 0 ); 150 EmitByte( 0 ); 151 EmitByte( 0 ); 152 EmitByte( 0 ); 153 EmitByte( 0 ); 154 155 EmitUShort( ColorTo565( inBuf ) ); 156 EmitUShort( 0 ); // dummy, never used 157 EmitUInt( 0 ); // 4 color index bytes all use the first color 158 159 inBuf += stride; 160 } 161 } 162 163 /* 164 ======================== 165 idDxtEncoder::WriteTinyColorCTX1DXT5A 166 ======================== 167 */ 168 void idDxtEncoder::WriteTinyColorCTX1DXT5A( const byte *inBuf, int width, int height ) { 169 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 170 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 171 // example: 2x8 pixels 172 // numBlocks = 2 173 // stride = 32 bytes (8 pixels) 174 175 for ( int i = 0; i < numBlocks; i++ ) { 176 // FIXME: This just emits a fake block based on the color at position 0,0 177 EmitByte( inBuf[0] ); 178 EmitByte( inBuf[1] ); 179 EmitByte( inBuf[0] ); 180 EmitByte( inBuf[1] ); 181 EmitUInt( 0 ); // 4 color index bytes all use the first color 182 183 EmitByte( inBuf[3] ); 184 EmitByte( 0 ); // dummy, never used 185 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 186 EmitByte( 0 ); 187 EmitByte( 0 ); 188 EmitByte( 0 ); 189 EmitByte( 0 ); 190 EmitByte( 0 ); 191 192 inBuf += stride; 193 } 194 } 195 196 /* 197 ======================== 198 idDxtEncoder::WriteTinyNormalMapDXT5 199 ======================== 200 */ 201 void idDxtEncoder::WriteTinyNormalMapDXT5( const byte *inBuf, int width, int height ) { 202 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 203 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 204 // example: 2x8 pixels 205 // numBlocks = 2 206 // stride = 32 bytes (8 pixels) 207 208 for ( int i = 0; i < numBlocks; i++ ) { 209 // FIXME: This just emits a fake block based on the normal at position 0,0 210 EmitByte( inBuf[3] ); 211 EmitByte( 0 ); // dummy, never used 212 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 213 EmitByte( 0 ); 214 EmitByte( 0 ); 215 EmitByte( 0 ); 216 EmitByte( 0 ); 217 EmitByte( 0 ); 218 219 EmitUShort( ColorTo565( inBuf[0], inBuf[1], inBuf[2] ) ); 220 EmitUShort( 0 ); // dummy, never used 221 EmitUInt( 0 ); // 4 color index bytes all use the first color 222 223 inBuf += stride; 224 } 225 } 226 227 /* 228 ======================== 229 idDxtEncoder::WriteTinyNormalMapDXN 230 ======================== 231 */ 232 void idDxtEncoder::WriteTinyNormalMapDXN( const byte *inBuf, int width, int height ) { 233 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 234 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 235 // example: 2x8 pixels 236 // numBlocks = 2 237 // stride = 32 bytes (8 pixels) 238 239 for ( int i = 0; i < numBlocks; i++ ) { 240 // FIXME: This just emits a fake block based on the normal at position 0,0 241 EmitByte( inBuf[0] ); 242 EmitByte( 0 ); // dummy, never used 243 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 244 EmitByte( 0 ); 245 EmitByte( 0 ); 246 EmitByte( 0 ); 247 EmitByte( 0 ); 248 EmitByte( 0 ); 249 250 EmitByte( inBuf[1] ); 251 EmitByte( 0 ); // dummy, never used 252 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 253 EmitByte( 0 ); 254 EmitByte( 0 ); 255 EmitByte( 0 ); 256 EmitByte( 0 ); 257 EmitByte( 0 ); 258 259 inBuf += stride; 260 } 261 } 262 263 /* 264 ======================== 265 idDxtEncoder::WriteTinyDXT5A 266 ======================== 267 */ 268 void idDxtEncoder::WriteTinyDXT5A( const byte *inBuf, int width, int height ) { 269 int numBlocks = ( ( width + 3 ) / 4 ) * ( ( height + 3 ) / 4 ); 270 int stride = ( ( width * height ) / numBlocks ) * 4; // number of bytes from one block to the next 271 // example: 2x8 pixels 272 // numBlocks = 2 273 // stride = 32 bytes (8 pixels) 274 275 for ( int i = 0; i < numBlocks; i++ ) { 276 // FIXME: This just emits a fake block based on the normal at position 0,0 277 EmitByte( inBuf[0] ); 278 EmitByte( 0 ); // dummy, never used 279 EmitByte( 0 ); // 6 alpha index bytes all use the first alpha 280 EmitByte( 0 ); 281 EmitByte( 0 ); 282 EmitByte( 0 ); 283 EmitByte( 0 ); 284 EmitByte( 0 ); 285 286 inBuf += stride; 287 } 288 } 289 290 /* 291 ======================== 292 idDxtEncoder::ExtractBlock 293 294 params: inPtr - input image, 4 bytes per pixel 295 paramO: colorBlock - 4*4 output tile, 4 bytes per pixel 296 ======================== 297 */ 298 ID_INLINE void idDxtEncoder::ExtractBlock( const byte *inPtr, int width, byte *colorBlock ) const { 299 for ( int j = 0; j < 4; j++ ) { 300 memcpy( &colorBlock[j*4*4], inPtr, 4*4 ); 301 inPtr += width * 4; 302 } 303 } 304 305 /* 306 ======================== 307 SwapColors 308 ======================== 309 */ 310 void SwapColors( byte *c1, byte *c2 ) { 311 byte tm[3]; 312 memcpy( tm, c1, 3 ); 313 memcpy( c1, c2, 3 ); 314 memcpy( c2, tm, 3 ); 315 } 316 317 /* 318 ======================== 319 idDxtEncoder::GetMinMaxColorsMaxDist 320 321 Finds the two RGB colors in a 4x4 block furthest apart. Also finds the two alpha values 322 furthest apart. 323 324 params: colorBlock - 4*4 input tile, 4 bytes per pixel 325 paramO: minColor - 4 byte min color 326 paramO: maxColor - 4 byte max color 327 ======================== 328 */ 329 void idDxtEncoder::GetMinMaxColorsMaxDist( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 330 int maxDistC = -1; 331 int maxDistA = -1; 332 333 for ( int i = 0; i < 64 - 4; i += 4 ) { 334 for ( int j = i + 4; j < 64; j += 4 ) { 335 int dc = ColorDistance( &colorBlock[i], &colorBlock[j] ); 336 if ( dc > maxDistC ) { 337 maxDistC = dc; 338 memcpy( minColor, colorBlock+i, 3 ); 339 memcpy( maxColor, colorBlock+j, 3 ); 340 } 341 int da = AlphaDistance( colorBlock[i+3], colorBlock[j+3] ); 342 if ( da > maxDistA ) { 343 maxDistA = da; 344 minColor[3] = colorBlock[i+3]; 345 maxColor[3] = colorBlock[j+3]; 346 } 347 } 348 } 349 if ( maxColor[0] < minColor[0] ) { 350 SwapColors( minColor, maxColor ); 351 } 352 } 353 354 /* 355 ======================== 356 idDxtEncoder::GetMinMaxColorsLuminance 357 358 Finds the two RGB colors in a 4x4 block furthest apart based on luminance. Also finds the two 359 alpha values furthest apart. 360 361 params: colorBlock - 4*4 input tile, 4 bytes per pixel 362 paramO: minColor - 4 byte min color 363 paramO: maxColor - 4 byte max color 364 ======================== 365 */ 366 void idDxtEncoder::GetMinMaxColorsLuminance( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 367 int maxLumC = 0, minLumC = 256 * 4; 368 int maxAlpha = 0, minAlpha = 256 * 4; 369 370 for ( int i = 0; i < 16; i++ ) { 371 int luminance = colorBlock[i*4+0] + colorBlock[i*4+1] * 2 + colorBlock[i*4+2]; 372 if ( luminance > maxLumC ) { 373 maxLumC = luminance; 374 memcpy( maxColor, colorBlock+i*4, 3 ); 375 } 376 if ( luminance < minLumC ) { 377 minLumC = luminance; 378 memcpy( minColor, colorBlock+i*4, 3 ); 379 } 380 int alpha = colorBlock[i*4+3]; 381 if ( alpha > maxAlpha ) { 382 maxAlpha = alpha; 383 maxColor[3] = (byte)alpha; 384 } 385 if ( alpha < minAlpha ) { 386 minAlpha = alpha; 387 minColor[3] = (byte)alpha; 388 } 389 } 390 if ( maxColor[0] < minColor[0] ) { 391 SwapColors( minColor, maxColor ); 392 } 393 } 394 395 /* 396 ======================== 397 idDxtEncoder::GetSquareAlphaError 398 399 params: colorBlock - 16 pixel block for which to find color indexes 400 paramO: minAlpha - Min alpha found 401 paramO: maxAlpha - Max alpha found 402 return: 4 byte color index block 403 ======================== 404 */ 405 int idDxtEncoder::GetSquareAlphaError( const byte *colorBlock, const int alphaOffset, const byte minAlpha, const byte maxAlpha, int lastError ) const { 406 int i, j; 407 byte alphas[8]; 408 409 alphas[0] = maxAlpha; 410 alphas[1] = minAlpha; 411 412 if ( maxAlpha > minAlpha ) { 413 alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7; 414 alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7; 415 alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7; 416 alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7; 417 alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7; 418 alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7; 419 } else { 420 alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5; 421 alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5; 422 alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5; 423 alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5; 424 alphas[6] = 0; 425 alphas[7] = 255; 426 } 427 428 int error = 0; 429 for ( i = 0; i < 16; i++ ) { 430 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 431 byte a = colorBlock[i*4+alphaOffset]; 432 for ( j = 0; j < 8; j++ ) { 433 unsigned int dist = AlphaDistance( a, alphas[j] ); 434 if ( dist < minDist ) { 435 minDist = dist; 436 } 437 } 438 error += minDist; 439 440 if ( error >= lastError ) { 441 return error; 442 } 443 } 444 445 return error; 446 } 447 448 /* 449 ======================== 450 idDxtEncoder::GetMinMaxAlphaHQ 451 452 params: colorBlock - 4*4 input tile, 4 bytes per pixel 453 paramO: minColor - 4 byte min color found 454 paramO: maxColor - 4 byte max color found 455 ======================== 456 */ 457 int idDxtEncoder::GetMinMaxAlphaHQ( const byte *colorBlock, const int alphaOffset, byte *minColor, byte *maxColor ) const { 458 int i, j; 459 byte alphaMin, alphaMax; 460 int error, bestError = MAX_TYPE( int ); 461 462 alphaMin = 255; 463 alphaMax = 0; 464 465 // get alpha min / max 466 for ( i = 0; i < 16; i++ ) { 467 if ( colorBlock[i*4+alphaOffset] < alphaMin ) { 468 alphaMin = colorBlock[i*4+alphaOffset]; 469 } 470 if ( colorBlock[i*4+alphaOffset] > alphaMax ) { 471 alphaMax = colorBlock[i*4+alphaOffset]; 472 } 473 } 474 475 const int ALPHA_EXPAND = 32; 476 477 alphaMin = ( alphaMin <= ALPHA_EXPAND ) ? 0 : alphaMin - ALPHA_EXPAND; 478 alphaMax = ( alphaMax >= 255 - ALPHA_EXPAND ) ? 255 : alphaMax + ALPHA_EXPAND; 479 480 for ( i = alphaMin; i <= alphaMax; i++ ) { 481 for ( j = alphaMax; j >= i; j-- ) { 482 483 error = GetSquareAlphaError( colorBlock, alphaOffset, (byte)i, (byte)j, bestError ); 484 if ( error < bestError ) { 485 bestError = error; 486 minColor[alphaOffset] = (byte)i; 487 maxColor[alphaOffset] = (byte)j; 488 } 489 490 error = GetSquareAlphaError( colorBlock, alphaOffset, (byte)j, (byte)i, bestError ); 491 if ( error < bestError ) { 492 bestError = error; 493 minColor[alphaOffset] = (byte)i; 494 maxColor[alphaOffset] = (byte)j; 495 } 496 } 497 } 498 499 return bestError; 500 } 501 502 /* 503 ======================== 504 idDxtEncoder::GetSquareColorsError 505 506 params: colorBlock - 16 pixel block for which to find color indexes 507 paramO: color0 - 4 byte min color found 508 paramO: color1 - 4 byte max color found 509 return: 4 byte color index block 510 ======================== 511 */ 512 int idDxtEncoder::GetSquareColorsError( const byte *colorBlock, const unsigned short color0, const unsigned short color1, int lastError ) const { 513 int i, j; 514 byte colors[4][4]; 515 516 ColorFrom565( color0, colors[0] ); 517 ColorFrom565( color1, colors[1] ); 518 519 if ( color0 > color1 ) { 520 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 521 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 522 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 523 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 524 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 525 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 526 } else { 527 colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2; 528 colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2; 529 colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2; 530 colors[3][0] = 0; 531 colors[3][1] = 0; 532 colors[3][2] = 0; 533 } 534 535 int error = 0; 536 for ( i = 0; i < 16; i++ ) { 537 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 538 for ( j = 0; j < 4; j++ ) { 539 unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] ); 540 if ( dist < minDist ) { 541 minDist = dist; 542 } 543 } 544 // accumulated error 545 error += minDist; 546 547 if ( error > lastError ) { 548 return error; 549 } 550 } 551 return error; 552 } 553 554 /* 555 ======================== 556 idDxtEncoder::GetSquareNormalYError 557 558 params: colorBlock - 16 pixel block for which to find color indexes 559 paramO: color0 - 4 byte min color found 560 paramO: color1 - 4 byte max color found 561 return: 4 byte color index block 562 ======================== 563 */ 564 int idDxtEncoder::GetSquareNormalYError( const byte *colorBlock, const unsigned short color0, const unsigned short color1, int lastError, int scale ) const { 565 int i, j; 566 byte colors[4][4]; 567 568 ColorFrom565( color0, colors[0] ); 569 ColorFrom565( color1, colors[1] ); 570 571 if ( color0 > color1 ) { 572 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 573 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 574 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 575 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 576 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 577 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 578 } else { 579 colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2; 580 colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2; 581 colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2; 582 colors[3][0] = 0; 583 colors[3][1] = 0; 584 colors[3][2] = 0; 585 } 586 587 int error = 0; 588 for ( i = 0; i < 16; i++ ) { 589 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 590 for ( j = 0; j < 4; j++ ) { 591 float r = (float) colorBlock[i*4+1] / scale; 592 float s = (float) colors[j][1] / scale; 593 unsigned int dist = idMath::Ftoi( ( r - s ) * ( r - s ) ); 594 if ( dist < minDist ) { 595 minDist = dist; 596 } 597 } 598 // accumulated error 599 error += minDist; 600 601 if ( error > lastError ) { 602 return error; 603 } 604 } 605 return error; 606 } 607 608 /* 609 ======================== 610 idDxtEncoder::GetMinMaxColorsHQ 611 612 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 613 compress the 4x4 block. Also finds the minimum and maximum alpha values. 614 615 params: colorBlock - 4*4 input tile, 4 bytes per pixel 616 paramO: minColor - 4 byte min color found 617 paramO: maxColor - 4 byte max color found 618 ======================== 619 */ 620 int idDxtEncoder::GetMinMaxColorsHQ( const byte *colorBlock, byte *minColor, byte *maxColor, bool noBlack ) const { 621 int i; 622 int i0, i1, i2, j0, j1, j2; 623 unsigned short minColor565, maxColor565, bestMinColor565, bestMaxColor565; 624 byte bboxMin[3], bboxMax[3], minAxisDist[3]; 625 int error, bestError = MAX_TYPE( int ); 626 627 bboxMin[0] = bboxMin[1] = bboxMin[2] = 255; 628 bboxMax[0] = bboxMax[1] = bboxMax[2] = 0; 629 630 // get color bbox 631 for ( i = 0; i < 16; i++ ) { 632 if ( colorBlock[i*4+0] < bboxMin[0] ) { 633 bboxMin[0] = colorBlock[i*4+0]; 634 } 635 if ( colorBlock[i*4+1] < bboxMin[1] ) { 636 bboxMin[1] = colorBlock[i*4+1]; 637 } 638 if ( colorBlock[i*4+2] < bboxMin[2] ) { 639 bboxMin[2] = colorBlock[i*4+2]; 640 } 641 if ( colorBlock[i*4+0] > bboxMax[0] ) { 642 bboxMax[0] = colorBlock[i*4+0]; 643 } 644 if ( colorBlock[i*4+1] > bboxMax[1] ) { 645 bboxMax[1] = colorBlock[i*4+1]; 646 } 647 if ( colorBlock[i*4+2] > bboxMax[2] ) { 648 bboxMax[2] = colorBlock[i*4+2]; 649 } 650 } 651 652 // decrease range for 565 encoding 653 bboxMin[0] >>= 3; 654 bboxMin[1] >>= 2; 655 bboxMin[2] >>= 3; 656 bboxMax[0] >>= 3; 657 bboxMax[1] >>= 2; 658 bboxMax[2] >>= 3; 659 660 // get the minimum distance the end points of the line must be apart along each axis 661 for ( i = 0; i < 3; i++ ) { 662 minAxisDist[i] = ( bboxMax[i] - bboxMin[i] ); 663 if ( minAxisDist[i] >= 16 ) { 664 minAxisDist[i] = minAxisDist[i] * 3 / 4; 665 } else if ( minAxisDist[i] >= 8 ) { 666 minAxisDist[i] = minAxisDist[i] * 2 / 4; 667 } else if ( minAxisDist[i] >= 4 ) { 668 minAxisDist[i] = minAxisDist[i] * 1 / 4; 669 } else { 670 minAxisDist[i] = 0; 671 } 672 } 673 674 // expand the bounding box 675 const int C565_BBOX_EXPAND = 1; 676 677 bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND; 678 bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND; 679 bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND; 680 bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND; 681 bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND; 682 bboxMax[2] = ( bboxMax[2] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[2] + C565_BBOX_EXPAND; 683 684 bestMinColor565 = 0; 685 bestMaxColor565 = 0; 686 687 for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) { 688 for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) { 689 if ( abs( i0 - j0 ) < minAxisDist[0] ) { 690 continue; 691 } 692 693 for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 694 for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 695 if ( abs( i1 - j1 ) < minAxisDist[1] ) { 696 continue; 697 } 698 699 for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) { 700 for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) { 701 if ( abs( i2 - j2 ) < minAxisDist[2] ) { 702 continue; 703 } 704 705 minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | ( i2 << 0 ) ); 706 maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | ( j2 << 0 ) ); 707 708 if ( !noBlack ) { 709 error = GetSquareColorsError( colorBlock, maxColor565, minColor565, bestError ); 710 if ( error < bestError ) { 711 bestError = error; 712 bestMinColor565 = minColor565; 713 bestMaxColor565 = maxColor565; 714 } 715 } else { 716 if ( minColor565 <= maxColor565 ) { 717 SwapValues( minColor565, maxColor565 ); 718 } 719 } 720 721 error = GetSquareColorsError( colorBlock, minColor565, maxColor565, bestError ); 722 if ( error < bestError ) { 723 bestError = error; 724 bestMinColor565 = minColor565; 725 bestMaxColor565 = maxColor565; 726 } 727 } 728 } 729 } 730 } 731 } 732 } 733 734 ColorFrom565( bestMinColor565, minColor ); 735 ColorFrom565( bestMaxColor565, maxColor ); 736 737 return bestError; 738 } 739 740 /* 741 ======================== 742 idDxtEncoder::GetSquareCTX1Error 743 744 params: colorBlock - 16 pixel block for which to find color indexes 745 paramO: color0 - Min color found 746 paramO: color1 - Max color found 747 return: 4 byte color index block 748 ======================== 749 */ 750 int idDxtEncoder::GetSquareCTX1Error( const byte *colorBlock, const byte *color0, const byte *color1, int lastError ) const { 751 int i, j; 752 byte colors[4][4]; 753 754 colors[0][0] = color0[0]; 755 colors[0][1] = color0[1]; 756 colors[1][0] = color1[0]; 757 colors[1][1] = color1[1]; 758 759 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 760 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 761 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 762 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 763 764 int error = 0; 765 for ( i = 0; i < 16; i++ ) { 766 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 767 for ( j = 0; j < 4; j++ ) { 768 unsigned int dist = CTX1Distance( &colorBlock[i*4], &colors[j][0] ); 769 if ( dist < minDist ) { 770 minDist = dist; 771 } 772 } 773 // accumulated error 774 error += minDist; 775 776 if ( error > lastError ) { 777 return error; 778 } 779 } 780 return error; 781 } 782 783 /* 784 ======================== 785 idDxtEncoder::GetMinMaxCTX1HQ 786 787 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 788 compress the 4x4 block. Also finds the minimum and maximum alpha values. 789 790 params: colorBlock - 4*4 input tile, 4 bytes per pixel 791 paramO: minColor - 4 byte Min color found 792 paramO: maxColor - 4 byte Max color found 793 ======================== 794 */ 795 int idDxtEncoder::GetMinMaxCTX1HQ( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 796 int i; 797 int i0, i1, j0, j1; 798 byte curMinColor[2], curMaxColor[2]; 799 byte bboxMin[2], bboxMax[2], minAxisDist[2]; 800 int error, bestError = MAX_TYPE( int ); 801 802 bboxMin[0] = bboxMin[1] = 255; 803 bboxMax[0] = bboxMax[1] = 0; 804 805 // get color bbox 806 for ( i = 0; i < 16; i++ ) { 807 if ( colorBlock[i*4+0] < bboxMin[0] ) { 808 bboxMin[0] = colorBlock[i*4+0]; 809 } 810 if ( colorBlock[i*4+1] < bboxMin[1] ) { 811 bboxMin[1] = colorBlock[i*4+1]; 812 } 813 if ( colorBlock[i*4+0] > bboxMax[0] ) { 814 bboxMax[0] = colorBlock[i*4+0]; 815 } 816 if ( colorBlock[i*4+1] > bboxMax[1] ) { 817 bboxMax[1] = colorBlock[i*4+1]; 818 } 819 } 820 821 // get the minimum distance the end points of the line must be apart along each axis 822 for ( i = 0; i < 2; i++ ) { 823 minAxisDist[i] = ( bboxMax[i] - bboxMin[i] ); 824 if ( minAxisDist[i] >= 64 ) { 825 minAxisDist[i] = minAxisDist[i] * 3 / 4; 826 } else if ( minAxisDist[i] >= 32 ) { 827 minAxisDist[i] = minAxisDist[i] * 2 / 4; 828 } else if ( minAxisDist[i] >= 16 ) { 829 minAxisDist[i] = minAxisDist[i] * 1 / 4; 830 } else { 831 minAxisDist[i] = 0; 832 } 833 } 834 835 // expand the bounding box 836 const int CXT1_BBOX_EXPAND = 6; 837 838 bboxMin[0] = ( bboxMin[0] <= CXT1_BBOX_EXPAND ) ? 0 : bboxMin[0] - CXT1_BBOX_EXPAND; 839 bboxMin[1] = ( bboxMin[1] <= CXT1_BBOX_EXPAND ) ? 0 : bboxMin[1] - CXT1_BBOX_EXPAND; 840 bboxMax[0] = ( bboxMax[0] >= 255 - CXT1_BBOX_EXPAND ) ? 255 : bboxMax[0] + CXT1_BBOX_EXPAND; 841 bboxMax[1] = ( bboxMax[1] >= 255 - CXT1_BBOX_EXPAND ) ? 255 : bboxMax[1] + CXT1_BBOX_EXPAND; 842 843 for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) { 844 for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) { 845 if ( abs( i0 - j0 ) < minAxisDist[0] ) { 846 continue; 847 } 848 849 for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 850 for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 851 if ( abs( i1 - j1 ) < minAxisDist[1] ) { 852 continue; 853 } 854 855 curMinColor[0] = (byte)i0; 856 curMinColor[1] = (byte)i1; 857 858 curMaxColor[0] = (byte)j0; 859 curMaxColor[1] = (byte)j1; 860 861 error = GetSquareCTX1Error( colorBlock, curMinColor, curMaxColor, bestError ); 862 if ( error < bestError ) { 863 bestError = error; 864 memcpy( minColor, curMinColor, 2 ); 865 memcpy( maxColor, curMaxColor, 2 ); 866 } 867 } 868 } 869 } 870 } 871 872 return bestError; 873 } 874 875 /* 876 ======================== 877 idDxtEncoder::GetMinMaxNormalYHQ 878 879 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 880 compress the 4x4 block. Also finds the minimum and maximum alpha values. 881 882 params: colorBlock - 4*4 input tile, 4 bytes per pixel 883 paramO: minColor - 4 byte Min color found 884 paramO: maxColor - 4 byte Max color found 885 ======================== 886 */ 887 int idDxtEncoder::GetMinMaxNormalYHQ( const byte *colorBlock, byte *minColor, byte *maxColor, bool noBlack, int scale ) const { 888 unsigned short bestMinColor565, bestMaxColor565; 889 byte bboxMin[3], bboxMax[3]; 890 int error, bestError = MAX_TYPE( int ); 891 892 bboxMin[1] = 255; 893 bboxMax[1] = 0; 894 895 // get color bbox 896 for ( int i = 0; i < 16; i++ ) { 897 if ( colorBlock[i*4+1] < bboxMin[1] ) { 898 bboxMin[1] = colorBlock[i*4+1]; 899 } 900 if ( colorBlock[i*4+1] > bboxMax[1] ) { 901 bboxMax[1] = colorBlock[i*4+1]; 902 } 903 } 904 905 // decrease range for 565 encoding 906 bboxMin[1] >>= 2; 907 bboxMax[1] >>= 2; 908 909 // expand the bounding box 910 const int C565_BBOX_EXPAND = 1; 911 912 bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND; 913 bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND; 914 915 bestMinColor565 = 0; 916 bestMaxColor565 = 0; 917 918 for ( int i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 919 for ( int j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 920 if ( abs( i1 - j1 ) < 0 ) { 921 continue; 922 } 923 924 unsigned short minColor565 = (unsigned short)i1 << 5; 925 unsigned short maxColor565 = (unsigned short)j1 << 5; 926 927 if ( !noBlack ) { 928 error = GetSquareNormalYError( colorBlock, maxColor565, minColor565, bestError, scale ); 929 if ( error < bestError ) { 930 bestError = error; 931 bestMinColor565 = minColor565; 932 bestMaxColor565 = maxColor565; 933 } 934 } else { 935 if ( minColor565 <= maxColor565 ) { 936 SwapValues( minColor565, maxColor565 ); 937 } 938 } 939 940 error = GetSquareNormalYError( colorBlock, minColor565, maxColor565, bestError, scale ); 941 if ( error < bestError ) { 942 bestError = error; 943 bestMinColor565 = minColor565; 944 bestMaxColor565 = maxColor565; 945 } 946 } 947 } 948 949 ColorFrom565( bestMinColor565, minColor ); 950 ColorFrom565( bestMaxColor565, maxColor ); 951 952 int bias = colorBlock[0*4+0]; 953 int size = colorBlock[0*4+2]; 954 955 minColor[0] = maxColor[0] = (byte)bias; 956 minColor[2] = maxColor[2] = (byte)size; 957 958 return bestError; 959 } 960 961 #if defined( ID_WIN_X86_ASM ) 962 ALIGN16( static float SIMD_SSE2_float_scale[4] ) = { 2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f, 2.0f / 255.0f }; 963 ALIGN16( static float SIMD_SSE2_float_descale[4] ) = { 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f, 255.0f / 2.0f }; 964 ALIGN16( static float SIMD_SSE2_float_zero[4] ) = { 0.0f, 0.0f, 0.0f, 0.0f }; 965 ALIGN16( static float SIMD_SSE2_float_one[4] ) = { 1.0f, 1.0f, 1.0f, 1.0f }; 966 ALIGN16( static float SIMD_SSE2_float_half[4] ) = { 0.5f, 0.5f, 0.5f, 0.5f }; 967 ALIGN16( static float SIMD_SSE2_float_255[4] ) = { 255.0f, 255.0f, 255.0f, 255.0f }; 968 ALIGN16( static float SIMD_SP_rsqrt_c0[4] ) = { 3.0f, 3.0f, 3.0f, 3.0f }; 969 ALIGN16( static float SIMD_SP_rsqrt_c1[4] ) = { -0.5f, -0.5f, -0.5f, -0.5f }; 970 ALIGN16( static dword SIMD_SSE2_dword_maskFirstThree[4] ) = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 }; 971 ALIGN16( static dword SIMD_SSE2_dword_maskWords[4] ) = { 0x0000FFFF, 0x0000FFFF, 0x0000FFFF, 0x00000000 }; 972 #define R_SHUFFLE_PS( x, y, z, w ) (( (w) & 3 ) << 6 | ( (z) & 3 ) << 4 | ( (y) & 3 ) << 2 | ( (x) & 3 )) 973 #endif 974 975 /* 976 ======================== 977 NormalDistanceDXT1 978 ======================== 979 */ 980 int NormalDistanceDXT1( const int *vector, const int *normalized ) { 981 #if defined( ID_WIN_X86_ASM ) 982 int result; 983 __asm { 984 mov esi, vector 985 mov edi, normalized 986 cvtdq2ps xmm0, [esi] 987 mulps xmm0, SIMD_SSE2_float_scale 988 subps xmm0, SIMD_SSE2_float_one 989 pand xmm0, SIMD_SSE2_dword_maskFirstThree 990 movaps xmm1, xmm0 991 mulps xmm1, xmm1 992 pshufd xmm2, xmm1, R_SHUFFLE_PS( 2, 3, 0, 1 ) 993 addps xmm2, xmm1 994 pshufd xmm1, xmm2, R_SHUFFLE_PS( 1, 0, 1, 0 ) 995 addps xmm2, xmm1 996 997 rsqrtps xmm1, xmm2 998 mulps xmm2, xmm1 999 mulps xmm2, xmm1 1000 subps xmm2, SIMD_SP_rsqrt_c0 1001 mulps xmm1, SIMD_SP_rsqrt_c1 1002 mulps xmm2, xmm1 1003 1004 mulps xmm0, xmm2 1005 addps xmm0, SIMD_SSE2_float_one 1006 mulps xmm0, SIMD_SSE2_float_descale 1007 addps xmm0, SIMD_SSE2_float_half 1008 maxps xmm0, SIMD_SSE2_float_zero 1009 minps xmm0, SIMD_SSE2_float_255 1010 cvttps2dq xmm0, xmm0 1011 psubd xmm0, [edi] 1012 pand xmm0, SIMD_SSE2_dword_maskWords 1013 pmullw xmm0, xmm0 1014 pshufd xmm1, xmm0, R_SHUFFLE_PS( 2, 3, 0, 1 ) 1015 paddd xmm0, xmm1 1016 pshufd xmm1, xmm0, R_SHUFFLE_PS( 1, 0, 1, 0 ) 1017 paddd xmm0, xmm1 1018 movd result, xmm0 1019 } 1020 return result; 1021 #else 1022 float floatNormal[3]; 1023 byte intNormal[4]; 1024 floatNormal[0] = vector[0] * ( 2.0f / 255.0f ) - 1.0f; 1025 floatNormal[1] = vector[1] * ( 2.0f / 255.0f ) - 1.0f; 1026 floatNormal[2] = vector[2] * ( 2.0f / 255.0f ) - 1.0f; 1027 float rcplen = idMath::InvSqrt( floatNormal[0] * floatNormal[0] + floatNormal[1] * floatNormal[1] + floatNormal[2] * floatNormal[2] ); 1028 floatNormal[0] *= rcplen; 1029 floatNormal[1] *= rcplen; 1030 floatNormal[2] *= rcplen; 1031 intNormal[0] = idMath::Ftob( ( floatNormal[0] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f ); 1032 intNormal[1] = idMath::Ftob( ( floatNormal[1] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f ); 1033 intNormal[2] = idMath::Ftob( ( floatNormal[2] + 1.0f ) * ( 255.0f / 2.0f ) + 0.5f ); 1034 int result = ( ( intNormal[ 0 ] - normalized[ 0 ] ) * ( intNormal[ 0 ] - normalized[ 0 ] ) ) + 1035 ( ( intNormal[ 1 ] - normalized[ 1 ] ) * ( intNormal[ 1 ] - normalized[ 1 ] ) ) + 1036 ( ( intNormal[ 2 ] - normalized[ 2 ] ) * ( intNormal[ 2 ] - normalized[ 2 ] ) ); 1037 return result; 1038 #endif 1039 } 1040 1041 /* 1042 ======================== 1043 NormalDistanceDXT5 1044 ======================== 1045 */ 1046 int NormalDistanceDXT5( const int *vector, const int *normalized ) { 1047 #if defined( ID_WIN_X86_ASM ) 1048 int result; 1049 __asm { 1050 mov esi, vector 1051 mov edi, normalized 1052 #if 0 // object-space 1053 pshufd xmm0, [esi], R_SHUFFLE_PS( 0, 1, 3, 2 ) 1054 #else 1055 pshufd xmm0, [esi], R_SHUFFLE_PS( 1, 2, 3, 0 ) 1056 #endif 1057 cvtdq2ps xmm0, xmm0 1058 mulps xmm0, SIMD_SSE2_float_scale 1059 subps xmm0, SIMD_SSE2_float_one 1060 pand xmm0, SIMD_SSE2_dword_maskFirstThree 1061 movaps xmm1, xmm0 1062 mulps xmm1, xmm1 1063 pshufd xmm2, xmm1, R_SHUFFLE_PS( 2, 3, 0, 1 ) 1064 addps xmm2, xmm1 1065 pshufd xmm1, xmm2, R_SHUFFLE_PS( 1, 0, 1, 0 ) 1066 addps xmm2, xmm1 1067 1068 rsqrtps xmm1, xmm2 1069 mulps xmm2, xmm1 1070 mulps xmm2, xmm1 1071 subps xmm2, SIMD_SP_rsqrt_c0 1072 mulps xmm1, SIMD_SP_rsqrt_c1 1073 mulps xmm2, xmm1 1074 1075 mulps xmm0, xmm2 1076 addps xmm0, SIMD_SSE2_float_one 1077 mulps xmm0, SIMD_SSE2_float_descale 1078 addps xmm0, SIMD_SSE2_float_half 1079 maxps xmm0, SIMD_SSE2_float_zero 1080 minps xmm0, SIMD_SSE2_float_255 1081 cvttps2dq xmm0, xmm0 1082 #if 0 // object-space 1083 pshufd xmm3, [edi], R_SHUFFLE_PS( 0, 1, 3, 2 ) 1084 #else 1085 pshufd xmm3, [edi], R_SHUFFLE_PS( 1, 2, 3, 0 ) 1086 #endif 1087 psubd xmm0, xmm3 1088 pand xmm0, SIMD_SSE2_dword_maskWords 1089 pmullw xmm0, xmm0 1090 pshufd xmm1, xmm0, R_SHUFFLE_PS( 2, 3, 0, 1 ) 1091 paddd xmm0, xmm1 1092 pshufd xmm1, xmm0, R_SHUFFLE_PS( 1, 0, 1, 0 ) 1093 paddd xmm0, xmm1 1094 movd result, xmm0 1095 } 1096 return result; 1097 #else 1098 #if 0 // object-space 1099 const int c0 = 0; 1100 const int c1 = 1; 1101 const int c2 = 3; 1102 #else 1103 const int c0 = 1; 1104 const int c1 = 2; 1105 const int c2 = 3; 1106 #endif 1107 float floatNormal[3]; 1108 byte intNormal[4]; 1109 floatNormal[0] = vector[c0] / 255.0f * 2.0f - 1.0f; 1110 floatNormal[1] = vector[c1] / 255.0f * 2.0f - 1.0f; 1111 floatNormal[2] = vector[c2] / 255.0f * 2.0f - 1.0f; 1112 float rcplen = idMath::InvSqrt( floatNormal[0] * floatNormal[0] + floatNormal[1] * floatNormal[1] + floatNormal[2] * floatNormal[2] ); 1113 floatNormal[0] *= rcplen; 1114 floatNormal[1] *= rcplen; 1115 floatNormal[2] *= rcplen; 1116 intNormal[c0] = idMath::Ftob( ( floatNormal[0] + 1.0f ) / 2.0f * 255.0f + 0.5f ); 1117 intNormal[c1] = idMath::Ftob( ( floatNormal[1] + 1.0f ) / 2.0f * 255.0f + 0.5f ); 1118 intNormal[c2] = idMath::Ftob( ( floatNormal[2] + 1.0f ) / 2.0f * 255.0f + 0.5f ); 1119 int result = ( ( intNormal[ c0 ] - normalized[ c0 ] ) * ( intNormal[ c0 ] - normalized[ c0 ] ) ) + 1120 ( ( intNormal[ c1 ] - normalized[ c1 ] ) * ( intNormal[ c1 ] - normalized[ c1 ] ) ) + 1121 ( ( intNormal[ c2 ] - normalized[ c2 ] ) * ( intNormal[ c2 ] - normalized[ c2 ] ) ); 1122 return result; 1123 #endif 1124 } 1125 1126 /* 1127 ======================== 1128 idDxtEncoder::GetSquareNormalsDXT1Error 1129 1130 params: colorBlock - 4*4 input tile, 4 bytes per pixel 1131 paramO: color0 - 4 byte Min color found 1132 paramO: color1 - 4 byte Max color found 1133 return: 4 byte color index block 1134 ======================== 1135 */ 1136 int idDxtEncoder::GetSquareNormalsDXT1Error( const int *colorBlock, const unsigned short color0, const unsigned short color1, int lastError, unsigned int &colorIndices ) const { 1137 byte byteColors[2][4]; 1138 ALIGN16( int colors[4][4] ); 1139 1140 ColorFrom565( color0, byteColors[0] ); 1141 ColorFrom565( color1, byteColors[1] ); 1142 1143 for ( int i = 0; i < 4; i++ ) { 1144 colors[0][i] = byteColors[0][i]; 1145 colors[1][i] = byteColors[1][i]; 1146 } 1147 1148 if ( color0 > color1 ) { 1149 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 1150 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 1151 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 1152 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 1153 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 1154 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 1155 } else { 1156 assert( color0 == color1 ); 1157 colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2; 1158 colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2; 1159 colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2; 1160 colors[3][0] = 0; 1161 colors[3][1] = 0; 1162 colors[3][2] = 0; 1163 } 1164 1165 int error = 0; 1166 int tempColorIndices[16]; 1167 for ( int i = 0; i < 16; i++ ) { 1168 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 1169 1170 for ( int j = 0; j < 4; j++ ) { 1171 unsigned int dist = NormalDistanceDXT1( &colors[j][0], &colorBlock[i*4] ); 1172 if ( dist < minDist ) { 1173 minDist = dist; 1174 tempColorIndices[i] = j; 1175 } 1176 } 1177 // accumulated error 1178 error += minDist; 1179 1180 if ( error > lastError ) { 1181 return error; 1182 } 1183 } 1184 1185 colorIndices = 0; 1186 for ( int i = 0; i < 16; i++ ) { 1187 colorIndices |= ( tempColorIndices[i] << (unsigned int)( i << 1 ) ); 1188 } 1189 1190 return error; 1191 } 1192 1193 /* 1194 ======================== 1195 idDxtEncoder::GetMinMaxNormalsDXT1HQ 1196 1197 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 1198 compress the 4x4 block. Also finds the minimum and maximum alpha values. 1199 1200 params: colorBlock - 4*4 input tile, 4 bytes per pixel 1201 paramO: minColor - 4 byte Min color found 1202 paramO: maxColor - 4 byte Max color found 1203 ======================== 1204 */ 1205 int idDxtEncoder::GetMinMaxNormalsDXT1HQ( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, bool noBlack ) const { 1206 int i; 1207 int i0, i1, i2, j0, j1, j2; 1208 unsigned short bestMinColor565 = 0; 1209 unsigned short bestMaxColor565 = 0; 1210 byte bboxMin[3], bboxMax[3], minAxisDist[3]; 1211 int error, bestError = MAX_TYPE( int ); 1212 unsigned int tempColorIndices; 1213 ALIGN16( int intColorBlock[16*4] ); 1214 1215 bboxMin[0] = bboxMin[1] = bboxMin[2] = 128; 1216 bboxMax[0] = bboxMax[1] = bboxMax[2] = 128; 1217 1218 // get color bbox 1219 for ( i = 0; i < 16; i++ ) { 1220 if ( colorBlock[i*4+0] < bboxMin[0] ) { 1221 bboxMin[0] = colorBlock[i*4+0]; 1222 } 1223 if ( colorBlock[i*4+1] < bboxMin[1] ) { 1224 bboxMin[1] = colorBlock[i*4+1]; 1225 } 1226 if ( colorBlock[i*4+2] < bboxMin[2] ) { 1227 bboxMin[2] = colorBlock[i*4+2]; 1228 } 1229 if ( colorBlock[i*4+0] > bboxMax[0] ) { 1230 bboxMax[0] = colorBlock[i*4+0]; 1231 } 1232 if ( colorBlock[i*4+1] > bboxMax[1] ) { 1233 bboxMax[1] = colorBlock[i*4+1]; 1234 } 1235 if ( colorBlock[i*4+2] > bboxMax[2] ) { 1236 bboxMax[2] = colorBlock[i*4+2]; 1237 } 1238 } 1239 1240 for ( int i = 0; i < 64; i++ ) { 1241 intColorBlock[i] = colorBlock[i]; 1242 } 1243 1244 // decrease range for 565 encoding 1245 bboxMin[0] >>= 3; 1246 bboxMin[1] >>= 2; 1247 bboxMin[2] >>= 3; 1248 bboxMax[0] >>= 3; 1249 bboxMax[1] >>= 2; 1250 bboxMax[2] >>= 3; 1251 1252 // get the minimum distance the end points of the line must be apart along each axis 1253 for ( i = 0; i < 3; i++ ) { 1254 minAxisDist[i] = 0; 1255 } 1256 1257 // expand the bounding box 1258 const int C565_BBOX_EXPAND = 2; 1259 1260 bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND; 1261 bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND; 1262 bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND; 1263 bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND; 1264 bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND; 1265 bboxMax[2] = ( bboxMax[2] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[2] + C565_BBOX_EXPAND; 1266 1267 for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) { 1268 for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) { 1269 if ( abs( i0 - j0 ) < minAxisDist[0] ) { 1270 continue; 1271 } 1272 1273 for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 1274 for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 1275 if ( abs( i1 - j1 ) < minAxisDist[1] ) { 1276 continue; 1277 } 1278 1279 for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) { 1280 for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) { 1281 if ( abs( i2 - j2 ) < minAxisDist[2] ) { 1282 continue; 1283 } 1284 1285 unsigned short minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | ( i2 << 0 ) ); 1286 unsigned short maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | ( j2 << 0 ) ); 1287 1288 if ( !noBlack ) { 1289 error = GetSquareNormalsDXT1Error( intColorBlock, maxColor565, minColor565, bestError, tempColorIndices ); 1290 if ( error < bestError ) { 1291 bestError = error; 1292 bestMinColor565 = minColor565; 1293 bestMaxColor565 = maxColor565; 1294 colorIndices = tempColorIndices; 1295 } 1296 } else { 1297 if ( minColor565 <= maxColor565 ) { 1298 SwapValues( minColor565, maxColor565 ); 1299 } 1300 } 1301 1302 error = GetSquareNormalsDXT1Error( intColorBlock, minColor565, maxColor565, bestError, tempColorIndices ); 1303 if ( error < bestError ) { 1304 bestError = error; 1305 bestMinColor565 = minColor565; 1306 bestMaxColor565 = maxColor565; 1307 colorIndices = tempColorIndices; 1308 } 1309 } 1310 } 1311 } 1312 } 1313 } 1314 } 1315 1316 ColorFrom565( bestMinColor565, minColor ); 1317 ColorFrom565( bestMaxColor565, maxColor ); 1318 1319 return bestError; 1320 } 1321 1322 /* 1323 ======================== 1324 idDxtEncoder::GetSquareNormalsDXT5Error 1325 1326 params: normalBlock - 16 pixel block for which to find normal indexes 1327 paramO: minNormal - Min normal found 1328 paramO: maxNormal - Max normal found 1329 ======================== 1330 */ 1331 int idDxtEncoder::GetSquareNormalsDXT5Error( const int *normalBlock, const byte *minNormal, const byte *maxNormal, int lastError, unsigned int &colorIndices, byte *alphaIndices ) const { 1332 byte alphas[8]; 1333 byte colors[4][4]; 1334 1335 unsigned short smin = ColorTo565( minNormal ); 1336 unsigned short smax = ColorTo565( maxNormal ); 1337 1338 ColorFrom565( smax, colors[0] ); 1339 ColorFrom565( smin, colors[1] ); 1340 1341 if ( smax > smin ) { 1342 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 1343 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 1344 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 1345 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 1346 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 1347 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 1348 } else { 1349 assert( smax == smin ); 1350 colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2; 1351 colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2; 1352 colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2; 1353 colors[3][0] = 0; 1354 colors[3][1] = 0; 1355 colors[3][2] = 0; 1356 } 1357 1358 alphas[0] = maxNormal[3]; 1359 alphas[1] = minNormal[3]; 1360 1361 if ( maxNormal[3] > minNormal[3] ) { 1362 alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7; 1363 alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7; 1364 alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7; 1365 alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7; 1366 alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7; 1367 alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7; 1368 } else { 1369 alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5; 1370 alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5; 1371 alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5; 1372 alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5; 1373 alphas[6] = 0; 1374 alphas[7] = 255; 1375 } 1376 1377 int error = 0; 1378 int tempColorIndices[16]; 1379 int tempAlphaIndices[16]; 1380 for ( int i = 0; i < 16; i++ ) { 1381 ALIGN16( int normal[4] ); 1382 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 1383 1384 for ( int j = 0; j < 4; j++ ) { 1385 normal[0] = colors[j][0]; 1386 normal[1] = colors[j][1]; 1387 normal[2] = colors[j][2]; 1388 1389 for ( int k = 0; k < 8; k++ ) { 1390 normal[3] = alphas[k]; 1391 unsigned int dist = NormalDistanceDXT5( normal, &normalBlock[i*4] ); 1392 if ( dist < minDist ) { 1393 minDist = dist; 1394 tempColorIndices[i] = j; 1395 tempAlphaIndices[i] = k; 1396 } 1397 } 1398 } 1399 error += minDist; 1400 1401 if ( error >= lastError ) { 1402 return error; 1403 } 1404 } 1405 1406 alphaIndices[0] = byte( (tempAlphaIndices[ 0] >> 0) | (tempAlphaIndices[ 1] << 3) | (tempAlphaIndices[ 2] << 6) ); 1407 alphaIndices[1] = byte( (tempAlphaIndices[ 2] >> 2) | (tempAlphaIndices[ 3] << 1) | (tempAlphaIndices[ 4] << 4) | (tempAlphaIndices[ 5] << 7) ); 1408 alphaIndices[2] = byte( (tempAlphaIndices[ 5] >> 1) | (tempAlphaIndices[ 6] << 2) | (tempAlphaIndices[ 7] << 5) ); 1409 1410 alphaIndices[3] = byte( (tempAlphaIndices[ 8] >> 0) | (tempAlphaIndices[ 9] << 3) | (tempAlphaIndices[10] << 6) ); 1411 alphaIndices[4] = byte( (tempAlphaIndices[10] >> 2) | (tempAlphaIndices[11] << 1) | (tempAlphaIndices[12] << 4) | (tempAlphaIndices[13] << 7) ); 1412 alphaIndices[5] = byte( (tempAlphaIndices[13] >> 1) | (tempAlphaIndices[14] << 2) | (tempAlphaIndices[15] << 5) ); 1413 1414 colorIndices = 0; 1415 for ( int i = 0; i < 16; i++ ) { 1416 colorIndices |= ( tempColorIndices[i] << (unsigned int)( i << 1 ) ); 1417 } 1418 1419 return error; 1420 } 1421 1422 /* 1423 ======================== 1424 idDxtEncoder::GetMinMaxNormalsDXT5HQ 1425 1426 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 1427 compress the 4x4 block. Also finds the minimum and maximum alpha values. 1428 1429 params: colorBlock - 4*4 input tile, 4 bytes per pixel 1430 paramO: minColor - 4 byte Min color found 1431 paramO: maxColor - 4 byte Max color found 1432 ======================== 1433 */ 1434 int idDxtEncoder::GetMinMaxNormalsDXT5HQ( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, byte *alphaIndices ) const { 1435 int i; 1436 int i0, i1, i3, j0, j1, j3; 1437 byte bboxMin[4], bboxMax[4], minAxisDist[4]; 1438 byte tmin[4], tmax[4]; 1439 int error, bestError = MAX_TYPE( int ); 1440 unsigned int tempColorIndices; 1441 byte tempAlphaIndices[6]; 1442 ALIGN16( int intColorBlock[16*4] ); 1443 1444 bboxMin[0] = bboxMin[1] = bboxMin[2] = bboxMin[3] = 255; 1445 bboxMax[0] = bboxMax[1] = bboxMax[2] = bboxMax[3] = 0; 1446 1447 // get color bbox 1448 for ( i = 0; i < 16; i++ ) { 1449 if ( colorBlock[i*4+0] < bboxMin[0] ) { 1450 bboxMin[0] = colorBlock[i*4+0]; 1451 } 1452 if ( colorBlock[i*4+1] < bboxMin[1] ) { 1453 bboxMin[1] = colorBlock[i*4+1]; 1454 } 1455 if ( colorBlock[i*4+2] < bboxMin[2] ) { 1456 bboxMin[2] = colorBlock[i*4+2]; 1457 } 1458 if ( colorBlock[i*4+3] < bboxMin[3] ) { 1459 bboxMin[3] = colorBlock[i*4+3]; 1460 } 1461 if ( colorBlock[i*4+0] > bboxMax[0] ) { 1462 bboxMax[0] = colorBlock[i*4+0]; 1463 } 1464 if ( colorBlock[i*4+1] > bboxMax[1] ) { 1465 bboxMax[1] = colorBlock[i*4+1]; 1466 } 1467 if ( colorBlock[i*4+2] > bboxMax[2] ) { 1468 bboxMax[2] = colorBlock[i*4+2]; 1469 } 1470 if ( colorBlock[i*4+3] > bboxMax[3] ) { 1471 bboxMax[3] = colorBlock[i*4+3]; 1472 } 1473 } 1474 1475 for ( int i = 0; i < 64; i++ ) { 1476 intColorBlock[i] = colorBlock[i]; 1477 } 1478 1479 // decrease range for 565 encoding 1480 bboxMin[0] >>= 3; 1481 bboxMin[1] >>= 2; 1482 bboxMax[0] >>= 3; 1483 bboxMax[1] >>= 2; 1484 1485 // get the minimum distance the end points of the line must be apart along each axis 1486 for ( i = 0; i < 4; i++ ) { 1487 minAxisDist[i] = 0; 1488 } 1489 1490 // expand the bounding box 1491 const int C565_BBOX_EXPAND = 2; 1492 const int ALPHA_BBOX_EXPAND = 32; 1493 1494 bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND; 1495 bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND; 1496 bboxMin[3] = ( bboxMin[3] <= ALPHA_BBOX_EXPAND ) ? 0 : bboxMin[3] - ALPHA_BBOX_EXPAND; 1497 bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND; 1498 bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND; 1499 bboxMax[3] = ( bboxMax[3] >= (255)-ALPHA_BBOX_EXPAND ) ? (255) : bboxMax[3] + ALPHA_BBOX_EXPAND; 1500 1501 for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) { 1502 for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) { 1503 if ( abs( i0 - j0 ) < minAxisDist[0] ) { 1504 continue; 1505 } 1506 1507 for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 1508 for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 1509 if ( abs( i1 - j1 ) < minAxisDist[1] ) { 1510 continue; 1511 } 1512 1513 tmin[0] = (byte)j0 << 3; 1514 tmin[1] = (byte)j1 << 2; 1515 tmin[2] = 0; 1516 1517 tmax[0] = (byte)i0 << 3; 1518 tmax[1] = (byte)i1 << 2; 1519 tmax[2] = 0; 1520 1521 for ( i3 = bboxMin[3]; i3 <= bboxMax[3]; i3++ ) { 1522 for ( j3 = bboxMax[3]; j3 >= bboxMin[3]; j3-- ) { 1523 if ( abs( i3 - j3 ) < minAxisDist[3] ) { 1524 continue; 1525 } 1526 1527 tmin[3] = (byte)j3; 1528 tmax[3] = (byte)i3; 1529 1530 error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices ); 1531 if ( error < bestError ) { 1532 bestError = error; 1533 memcpy( minColor, tmin, 4 ); 1534 memcpy( maxColor, tmax, 4 ); 1535 colorIndices = tempColorIndices; 1536 memcpy( alphaIndices, tempAlphaIndices, 6 ); 1537 } 1538 1539 tmin[3] = (byte)i3; 1540 tmax[3] = (byte)j3; 1541 1542 error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices ); 1543 if ( error < bestError ) { 1544 bestError = error; 1545 memcpy( minColor, tmin, 4 ); 1546 memcpy( maxColor, tmax, 4 ); 1547 colorIndices = tempColorIndices; 1548 memcpy( alphaIndices, tempAlphaIndices, 6 ); 1549 } 1550 } 1551 } 1552 } 1553 } 1554 } 1555 } 1556 1557 return bestError; 1558 } 1559 1560 /* 1561 ======================== 1562 idDxtEncoder::GetMinMaxNormalsDXT5HQFast 1563 1564 Uses an exhaustive search to find the two RGB colors that produce the least error when used to 1565 compress the 4x4 block. Also finds the minimum and maximum alpha values. 1566 1567 params: colorBlock - 4*4 input tile, 4 bytes per pixel 1568 paramO: minColor - 4 byte Min color found 1569 paramO: maxColor - 4 byte Max color found 1570 ======================== 1571 */ 1572 int idDxtEncoder::GetMinMaxNormalsDXT5HQFast( const byte *colorBlock, byte *minColor, byte *maxColor, unsigned int &colorIndices, byte *alphaIndices ) const { 1573 int i0, i1, i2, i3, j0, j1, j2, j3; 1574 byte bboxMin[4], bboxMax[4], minAxisDist[4]; 1575 byte tmin[4], tmax[4]; 1576 int error, bestError = MAX_TYPE( int ); 1577 unsigned int tempColorIndices; 1578 byte tempAlphaIndices[6]; 1579 ALIGN16( int intColorBlock[16*4] ); 1580 1581 bboxMin[0] = bboxMin[1] = bboxMin[2] = bboxMin[3] = 255; 1582 bboxMax[0] = bboxMax[1] = bboxMax[2] = bboxMax[3] = 0; 1583 1584 // get color bbox 1585 for ( int i = 0; i < 16; i++ ) { 1586 if ( colorBlock[i*4+0] < bboxMin[0] ) { 1587 bboxMin[0] = colorBlock[i*4+0]; 1588 } 1589 if ( colorBlock[i*4+1] < bboxMin[1] ) { 1590 bboxMin[1] = colorBlock[i*4+1]; 1591 } 1592 if ( colorBlock[i*4+2] < bboxMin[2] ) { 1593 bboxMin[2] = colorBlock[i*4+2]; 1594 } 1595 if ( colorBlock[i*4+3] < bboxMin[3] ) { 1596 bboxMin[3] = colorBlock[i*4+3]; 1597 } 1598 if ( colorBlock[i*4+0] > bboxMax[0] ) { 1599 bboxMax[0] = colorBlock[i*4+0]; 1600 } 1601 if ( colorBlock[i*4+1] > bboxMax[1] ) { 1602 bboxMax[1] = colorBlock[i*4+1]; 1603 } 1604 if ( colorBlock[i*4+2] > bboxMax[2] ) { 1605 bboxMax[2] = colorBlock[i*4+2]; 1606 } 1607 if ( colorBlock[i*4+3] > bboxMax[3] ) { 1608 bboxMax[3] = colorBlock[i*4+3]; 1609 } 1610 } 1611 1612 for ( int i = 0; i < 64; i++ ) { 1613 intColorBlock[i] = colorBlock[i]; 1614 } 1615 1616 // decrease range for 565 encoding 1617 bboxMin[0] >>= 3; 1618 bboxMin[1] >>= 2; 1619 bboxMin[2] >>= 3; 1620 bboxMax[0] >>= 3; 1621 bboxMax[1] >>= 2; 1622 bboxMax[2] >>= 3; 1623 1624 bboxMin[3] = 0; 1625 bboxMax[3] = 255; 1626 1627 // get the minimum distance the end points of the line must be apart along each axis 1628 for ( int i = 0; i < 4; i++ ) { 1629 minAxisDist[i] = 0; 1630 } 1631 1632 // expand the bounding box 1633 const int C565_BBOX_EXPAND = 1; 1634 const int ALPHA_BBOX_EXPAND = 128; 1635 1636 #if 0 // object-space 1637 bboxMin[0] = ( bboxMin[0] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[0] - C565_BBOX_EXPAND; 1638 bboxMax[0] = ( bboxMax[0] >= (255>>3)-C565_BBOX_EXPAND ) ? (255>>3) : bboxMax[0] + C565_BBOX_EXPAND; 1639 bboxMin[2] = 0; 1640 bboxMax[2] = 0; 1641 #else 1642 bboxMin[0] = 0; 1643 bboxMax[0] = 0; 1644 bboxMin[2] = ( bboxMin[2] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[2] - C565_BBOX_EXPAND; 1645 bboxMax[2] = ( bboxMax[2] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[2] + C565_BBOX_EXPAND; 1646 #endif 1647 1648 bboxMin[1] = ( bboxMin[1] <= C565_BBOX_EXPAND ) ? 0 : bboxMin[1] - C565_BBOX_EXPAND; 1649 bboxMax[1] = ( bboxMax[1] >= (255>>2)-C565_BBOX_EXPAND ) ? (255>>2) : bboxMax[1] + C565_BBOX_EXPAND; 1650 1651 bboxMin[3] = ( bboxMin[3] <= ALPHA_BBOX_EXPAND ) ? 0 : bboxMin[3] - ALPHA_BBOX_EXPAND; 1652 bboxMax[3] = ( bboxMax[3] >= (255)-ALPHA_BBOX_EXPAND ) ? (255) : bboxMax[3] + ALPHA_BBOX_EXPAND; 1653 1654 for ( i0 = bboxMin[0]; i0 <= bboxMax[0]; i0++ ) { 1655 for ( j0 = bboxMax[0]; j0 >= bboxMin[0]; j0-- ) { 1656 if ( abs( i0 - j0 ) < minAxisDist[0] ) { 1657 continue; 1658 } 1659 1660 for ( i1 = bboxMin[1]; i1 <= bboxMax[1]; i1++ ) { 1661 for ( j1 = bboxMax[1]; j1 >= bboxMin[1]; j1-- ) { 1662 if ( abs( i1 - j1 ) < minAxisDist[1] ) { 1663 continue; 1664 } 1665 1666 for ( i2 = bboxMin[2]; i2 <= bboxMax[2]; i2++ ) { 1667 for ( j2 = bboxMax[2]; j2 >= bboxMin[2]; j2-- ) { 1668 if ( abs( i2 - j2 ) < minAxisDist[2] ) { 1669 continue; 1670 } 1671 1672 unsigned short minColor565 = (unsigned short)( ( i0 << 11 ) | ( i1 << 5 ) | i2 ); 1673 unsigned short maxColor565 = (unsigned short)( ( j0 << 11 ) | ( j1 << 5 ) | j2 ); 1674 1675 if ( minColor565 > maxColor565 ) { 1676 SwapValues( minColor565, maxColor565 ); 1677 } 1678 1679 error = GetSquareNormalsDXT1Error( intColorBlock, maxColor565, minColor565, bestError, tempColorIndices ); 1680 if ( error < bestError ) { 1681 bestError = error; 1682 ColorFrom565( minColor565, minColor ); 1683 ColorFrom565( maxColor565, maxColor ); 1684 colorIndices = tempColorIndices; 1685 } 1686 } 1687 } 1688 } 1689 } 1690 } 1691 } 1692 1693 bestError = MAX_TYPE( int ); 1694 1695 memcpy( tmin, minColor, 4 ); 1696 memcpy( tmax, maxColor, 4 ); 1697 1698 for ( i3 = bboxMin[3]; i3 <= bboxMax[3]; i3++ ) { 1699 for ( j3 = bboxMax[3]; j3 >= bboxMin[3]; j3-- ) { 1700 if ( abs( i3 - j3 ) < minAxisDist[3] ) { 1701 continue; 1702 } 1703 1704 tmin[3] = (byte)j3; 1705 tmax[3] = (byte)i3; 1706 1707 error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices ); 1708 if ( error < bestError ) { 1709 bestError = error; 1710 memcpy( minColor, tmin, 4 ); 1711 memcpy( maxColor, tmax, 4 ); 1712 colorIndices = tempColorIndices; 1713 memcpy( alphaIndices, tempAlphaIndices, 6 ); 1714 } 1715 1716 tmin[3] = (byte)i3; 1717 tmax[3] = (byte)j3; 1718 1719 error = GetSquareNormalsDXT5Error( intColorBlock, tmin, tmax, bestError, tempColorIndices, tempAlphaIndices ); 1720 if ( error < bestError ) { 1721 bestError = error; 1722 memcpy( minColor, tmin, 4 ); 1723 memcpy( maxColor, tmax, 4 ); 1724 colorIndices = tempColorIndices; 1725 memcpy( alphaIndices, tempAlphaIndices, 6 ); 1726 } 1727 } 1728 } 1729 1730 return bestError; 1731 } 1732 1733 /* 1734 ======================== 1735 idDxtEncoder::FindColorIndices 1736 1737 params: colorBlock - 16 pixel block for which find color indexes 1738 paramO: color0 - Min color found 1739 paramO: color1 - Max color found 1740 return: 4 byte color index block 1741 ======================== 1742 */ 1743 int idDxtEncoder::FindColorIndices( const byte *colorBlock, const unsigned short color0, const unsigned short color1, unsigned int &result ) const { 1744 int i, j; 1745 unsigned int indexes[16]; 1746 byte colors[4][4]; 1747 1748 ColorFrom565( color0, colors[0] ); 1749 ColorFrom565( color1, colors[1] ); 1750 1751 if ( color0 > color1 ) { 1752 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 1753 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 1754 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 1755 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 1756 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 1757 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 1758 } else { 1759 colors[2][0] = ( 1 * colors[0][0] + 1 * colors[1][0] ) / 2; 1760 colors[2][1] = ( 1 * colors[0][1] + 1 * colors[1][1] ) / 2; 1761 colors[2][2] = ( 1 * colors[0][2] + 1 * colors[1][2] ) / 2; 1762 colors[3][0] = 0; 1763 colors[3][1] = 0; 1764 colors[3][2] = 0; 1765 } 1766 1767 int error = 0; 1768 for ( i = 0; i < 16; i++ ) { 1769 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 1770 for ( j = 0; j < 4; j++ ) { 1771 unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] ); 1772 if ( dist < minDist ) { 1773 minDist = dist; 1774 indexes[i] = j; 1775 } 1776 } 1777 // accumulated error 1778 error += minDist; 1779 } 1780 1781 result = 0; 1782 for ( i = 0; i < 16; i++ ) { 1783 result |= ( indexes[i] << (unsigned int)( i << 1 ) ); 1784 } 1785 1786 return error; 1787 } 1788 1789 /* 1790 ======================== 1791 idDxtEncoder::FindAlphaIndices 1792 1793 params: colorBlock - 16 pixel block for which find alpha indexes 1794 paramO: alpha0 - Min alpha found 1795 paramO: alpha1 - Max alpha found 1796 params: rindexes - 6 byte alpha index block 1797 return: error metric for this compression 1798 ======================== 1799 */ 1800 int idDxtEncoder::FindAlphaIndices( const byte *colorBlock, const int alphaOffset, const byte alpha0, const byte alpha1, byte *rindexes ) const { 1801 int i, j; 1802 unsigned int indexes[16]; 1803 byte alphas[8]; 1804 1805 alphas[0] = alpha0; 1806 alphas[1] = alpha1; 1807 if ( alpha0 > alpha1 ) { 1808 alphas[2] = ( 6 * alpha0 + 1 * alpha1 ) / 7; 1809 alphas[3] = ( 5 * alpha0 + 2 * alpha1 ) / 7; 1810 alphas[4] = ( 4 * alpha0 + 3 * alpha1 ) / 7; 1811 alphas[5] = ( 3 * alpha0 + 4 * alpha1 ) / 7; 1812 alphas[6] = ( 2 * alpha0 + 5 * alpha1 ) / 7; 1813 alphas[7] = ( 1 * alpha0 + 6 * alpha1 ) / 7; 1814 } else { 1815 alphas[2] = ( 4 * alpha0 + 1 * alpha1 ) / 5; 1816 alphas[3] = ( 3 * alpha0 + 2 * alpha1 ) / 5; 1817 alphas[4] = ( 2 * alpha0 + 3 * alpha1 ) / 5; 1818 alphas[5] = ( 1 * alpha0 + 4 * alpha1 ) / 5; 1819 alphas[6] = 0; 1820 alphas[7] = 255; 1821 } 1822 1823 int error = 0; 1824 for ( i = 0; i < 16; i++ ) { 1825 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 1826 byte a = colorBlock[i*4+alphaOffset]; 1827 for ( j = 0; j < 8; j++ ) { 1828 unsigned int dist = AlphaDistance( a, alphas[j] ); 1829 if ( dist < minDist ) { 1830 minDist = dist; 1831 indexes[i] = j; 1832 } 1833 } 1834 error += minDist; 1835 } 1836 1837 rindexes[0] = byte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 1838 rindexes[1] = byte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 1839 rindexes[2] = byte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 1840 1841 rindexes[3] = byte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 1842 rindexes[4] = byte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 1843 rindexes[5] = byte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 1844 1845 return error; 1846 } 1847 1848 /* 1849 ======================== 1850 idDxtEncoder::FindCTX1Indices 1851 1852 params: colorBlock - 16 pixel block for which find color indexes 1853 paramO: color0 - Min color found 1854 paramO: color1 - Max color found 1855 return: 4 byte color index block 1856 ======================== 1857 */ 1858 int idDxtEncoder::FindCTX1Indices( const byte *colorBlock, const byte *color0, const byte *color1, unsigned int &result ) const { 1859 int i, j; 1860 unsigned int indexes[16]; 1861 byte colors[4][4]; 1862 1863 colors[0][0] = color1[0]; 1864 colors[0][1] = color1[1]; 1865 colors[1][0] = color0[0]; 1866 colors[1][1] = color0[1]; 1867 1868 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 1869 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 1870 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 1871 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 1872 1873 int error = 0; 1874 for ( i = 0; i < 16; i++ ) { 1875 unsigned int minDist = MAX_UNSIGNED_TYPE( int ); 1876 for ( j = 0; j < 4; j++ ) { 1877 unsigned int dist = CTX1Distance( &colorBlock[i*4], &colors[j][0] ); 1878 if ( dist < minDist ) { 1879 minDist = dist; 1880 indexes[i] = j; 1881 } 1882 } 1883 // accumulated error 1884 error += minDist; 1885 } 1886 1887 result = 0; 1888 for ( i = 0; i < 16; i++ ) { 1889 result |= ( indexes[i] << (unsigned int)( i << 1 ) ); 1890 } 1891 1892 return error; 1893 } 1894 1895 /* 1896 ======================== 1897 idDxtEncoder::CompressImageDXT1HQ 1898 1899 params: inBuf - image to compress 1900 paramO: outBuf - result of compression 1901 params: width - width of image 1902 params: height - height of image 1903 ======================== 1904 */ 1905 void idDxtEncoder::CompressImageDXT1HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 1906 ALIGN16( byte block[64] ); 1907 unsigned int colorIndices1; 1908 unsigned int colorIndices2; 1909 byte col1[4]; 1910 byte col2[4]; 1911 int error1; 1912 int error2; 1913 1914 this->width = width; 1915 this->height = height; 1916 this->outData = outBuf; 1917 1918 if ( width > 4 && ( width & 3 ) != 0 ) { 1919 return; 1920 } 1921 if ( height > 4 && ( height & 3 ) != 0 ) { 1922 return; 1923 } 1924 1925 if ( width < 4 || height < 4 ) { 1926 WriteTinyColorDXT1( inBuf, width, height ); 1927 return; 1928 } 1929 1930 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 1931 for ( int i = 0; i < width; i += 4 ) { 1932 1933 ExtractBlock( inBuf + i * 4, width, block ); 1934 1935 GetMinMaxColorsHQ( block, col1, col2, false ); 1936 1937 // Write out color data. Try and find minimum error for the two encoding methods. 1938 unsigned short scol1 = ColorTo565( col1 ); 1939 unsigned short scol2 = ColorTo565( col2 ); 1940 1941 error1 = FindColorIndices( block, scol1, scol2, colorIndices1 ); 1942 error2 = FindColorIndices( block, scol2, scol1, colorIndices2 ); 1943 1944 if ( error1 < error2 ) { 1945 1946 EmitUShort( scol1 ); 1947 EmitUShort( scol2 ); 1948 EmitUInt( colorIndices1 ); 1949 1950 } else { 1951 1952 EmitUShort( scol2 ); 1953 EmitUShort( scol1 ); 1954 EmitUInt( colorIndices2 ); 1955 } 1956 1957 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 1958 } 1959 outData += dstPadding; 1960 inBuf += srcPadding; 1961 } 1962 1963 //idLib::Printf( "\r100%%\n" ); 1964 } 1965 1966 /* 1967 ======================== 1968 idDxtEncoder::CompressImageDXT5HQ 1969 1970 params: inBuf - image to compress 1971 paramO: outBuf - result of compression 1972 params: width - width of image 1973 params: height - height of image 1974 ======================== 1975 */ 1976 void idDxtEncoder::CompressImageDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 1977 ALIGN16( byte block[64] ); 1978 byte alphaIndices1[6]; 1979 byte alphaIndices2[6]; 1980 unsigned int colorIndices; 1981 byte col1[4]; 1982 byte col2[4]; 1983 int error1; 1984 int error2; 1985 1986 this->width = width; 1987 this->height = height; 1988 this->outData = outBuf; 1989 1990 if ( width > 4 && ( width & 3 ) != 0 ) { 1991 return; 1992 } 1993 if ( height > 4 && ( height & 3 ) != 0 ) { 1994 return; 1995 } 1996 1997 if ( width < 4 || height < 4 ) { 1998 WriteTinyColorDXT5( inBuf, width, height ); 1999 return; 2000 } 2001 2002 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2003 for ( int i = 0; i < width; i += 4 ) { 2004 2005 ExtractBlock( inBuf + i * 4, width, block ); 2006 2007 GetMinMaxColorsHQ( block, col1, col2, true ); 2008 GetMinMaxAlphaHQ( block, 3, col1, col2 ); 2009 2010 // Write out alpha data. Try and find minimum error for the two encoding methods. 2011 error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 ); 2012 error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 ); 2013 2014 if ( error1 < error2 ) { 2015 2016 EmitByte( col1[3] ); 2017 EmitByte( col2[3] ); 2018 EmitByte( alphaIndices1[0] ); 2019 EmitByte( alphaIndices1[1] ); 2020 EmitByte( alphaIndices1[2] ); 2021 EmitByte( alphaIndices1[3] ); 2022 EmitByte( alphaIndices1[4] ); 2023 EmitByte( alphaIndices1[5] ); 2024 2025 } else { 2026 2027 EmitByte( col2[3] ); 2028 EmitByte( col1[3] ); 2029 EmitByte( alphaIndices2[0] ); 2030 EmitByte( alphaIndices2[1] ); 2031 EmitByte( alphaIndices2[2] ); 2032 EmitByte( alphaIndices2[3] ); 2033 EmitByte( alphaIndices2[4] ); 2034 EmitByte( alphaIndices2[5] ); 2035 } 2036 2037 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 2038 NV4XHardwareBugFix( col2, col1 ); 2039 #endif 2040 2041 // Write out color data. Always take the path with 4 interpolated values. 2042 unsigned short scol1 = ColorTo565( col1 ); 2043 unsigned short scol2 = ColorTo565( col2 ); 2044 2045 EmitUShort( scol1 ); 2046 EmitUShort( scol2 ); 2047 2048 FindColorIndices( block, scol1, scol2, colorIndices ); 2049 EmitUInt( colorIndices ); 2050 2051 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2052 } 2053 outData += dstPadding; 2054 inBuf += srcPadding; 2055 } 2056 2057 //idLib::Printf( "\r100%%\n" ); 2058 } 2059 2060 /* 2061 ======================== 2062 idDxtEncoder::CompressImageCTX1HQ 2063 2064 params: inBuf - image to compress 2065 paramO: outBuf - result of compression 2066 params: width - width of image 2067 params: height - height of image 2068 ======================== 2069 */ 2070 void idDxtEncoder::CompressImageCTX1HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2071 ALIGN16( byte block[64] ); 2072 unsigned int colorIndices; 2073 byte col1[4]; 2074 byte col2[4]; 2075 2076 this->width = width; 2077 this->height = height; 2078 this->outData = outBuf; 2079 2080 if ( width > 4 && ( width & 3 ) != 0 ) { 2081 return; 2082 } 2083 if ( height > 4 && ( height & 3 ) != 0 ) { 2084 return; 2085 } 2086 2087 if ( width < 4 || height < 4 ) { 2088 WriteTinyColorCTX1DXT5A( inBuf, width, height ); 2089 return; 2090 } 2091 2092 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2093 for ( int i = 0; i < width; i += 4 ) { 2094 2095 ExtractBlock( inBuf + i * 4, width, block ); 2096 2097 GetMinMaxCTX1HQ( block, col1, col2 ); 2098 2099 EmitByte( col2[0] ); 2100 EmitByte( col2[1] ); 2101 EmitByte( col1[0] ); 2102 EmitByte( col1[1] ); 2103 2104 FindCTX1Indices( block, col1, col2, colorIndices ); 2105 EmitUInt( colorIndices ); 2106 2107 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2108 } 2109 outData += dstPadding; 2110 inBuf += srcPadding; 2111 } 2112 2113 //idLib::Printf( "\r100%%\n" ); 2114 } 2115 2116 /* 2117 ======================== 2118 idDxtEncoder::ScaleYCoCg 2119 2120 params: colorBlock - 16 pixel block for which find color indexes 2121 ======================== 2122 */ 2123 void idDxtEncoder::ScaleYCoCg( byte *colorBlock ) const { 2124 ALIGN16( byte minColor[4] ); 2125 ALIGN16( byte maxColor[4] ); 2126 2127 minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255; 2128 maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0; 2129 2130 for ( int i = 0; i < 16; i++ ) { 2131 if ( colorBlock[i*4+0] < minColor[0] ) { 2132 minColor[0] = colorBlock[i*4+0]; 2133 } 2134 if ( colorBlock[i*4+1] < minColor[1] ) { 2135 minColor[1] = colorBlock[i*4+1]; 2136 } 2137 if ( colorBlock[i*4+0] > maxColor[0] ) { 2138 maxColor[0] = colorBlock[i*4+0]; 2139 } 2140 if ( colorBlock[i*4+1] > maxColor[1] ) { 2141 maxColor[1] = colorBlock[i*4+1]; 2142 } 2143 } 2144 2145 int m0 = abs( minColor[0] - 128 ); 2146 int m1 = abs( minColor[1] - 128 ); 2147 int m2 = abs( maxColor[0] - 128 ); 2148 int m3 = abs( maxColor[1] - 128 ); 2149 2150 if ( m1 > m0 ) m0 = m1; 2151 if ( m3 > m2 ) m2 = m3; 2152 if ( m2 > m0 ) m0 = m2; 2153 2154 const int s0 = 128 / 2 - 1; 2155 const int s1 = 128 / 4 - 1; 2156 2157 int scale = 1 + ( m0 <= s0 ) + 2 * ( m0 <= s1 ); 2158 2159 for ( int i = 0; i < 16; i++ ) { 2160 colorBlock[i*4+0] = byte( ( colorBlock[i*4+0] - 128 ) * scale + 128 ); 2161 colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - 128 ) * scale + 128 ); 2162 colorBlock[i*4+2] = byte( ( scale - 1 ) << 3 ); 2163 } 2164 } 2165 2166 /* 2167 ======================== 2168 idDxtEncoder::CompressYCoCgDXT5HQ 2169 2170 params: inBuf - image to compress 2171 paramO: outBuf - result of compression 2172 params: width - width of image 2173 params: height - height of image 2174 ======================== 2175 */ 2176 void idDxtEncoder::CompressYCoCgDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2177 ALIGN16( byte block[64] ); 2178 byte alphaIndices1[6]; 2179 byte alphaIndices2[6]; 2180 unsigned int colorIndices; 2181 byte col1[4]; 2182 byte col2[4]; 2183 int error1; 2184 int error2; 2185 2186 assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) ); 2187 2188 this->width = width; 2189 this->height = height; 2190 this->outData = outBuf; 2191 2192 if ( width > 4 && ( width & 3 ) != 0 ) { 2193 return; 2194 } 2195 if ( height > 4 && ( height & 3 ) != 0 ) { 2196 return; 2197 } 2198 2199 if ( width < 4 || height < 4 ) { 2200 WriteTinyColorDXT5( inBuf, width, height ); 2201 return; 2202 } 2203 2204 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2205 for ( int i = 0; i < width; i += 4 ) { 2206 2207 ExtractBlock( inBuf + i * 4, width, block ); 2208 ScaleYCoCg( block ); 2209 2210 GetMinMaxColorsHQ( block, col1, col2, true ); 2211 GetMinMaxAlphaHQ( block, 3, col1, col2 ); 2212 2213 // Write out alpha data. Try and find minimum error for the two encoding methods. 2214 error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 ); 2215 error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 ); 2216 2217 if ( error1 < error2 ) { 2218 2219 EmitByte( col1[3] ); 2220 EmitByte( col2[3] ); 2221 EmitByte( alphaIndices1[0] ); 2222 EmitByte( alphaIndices1[1] ); 2223 EmitByte( alphaIndices1[2] ); 2224 EmitByte( alphaIndices1[3] ); 2225 EmitByte( alphaIndices1[4] ); 2226 EmitByte( alphaIndices1[5] ); 2227 2228 } else { 2229 2230 EmitByte( col2[3] ); 2231 EmitByte( col1[3] ); 2232 EmitByte( alphaIndices2[0] ); 2233 EmitByte( alphaIndices2[1] ); 2234 EmitByte( alphaIndices2[2] ); 2235 EmitByte( alphaIndices2[3] ); 2236 EmitByte( alphaIndices2[4] ); 2237 EmitByte( alphaIndices2[5] ); 2238 } 2239 2240 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 2241 NV4XHardwareBugFix( col2, col1 ); 2242 #endif 2243 2244 // Write out color data. Always take the path with 4 interpolated values. 2245 unsigned short scol1 = ColorTo565( col1 ); 2246 unsigned short scol2 = ColorTo565( col2 ); 2247 2248 EmitUShort( scol1 ); 2249 EmitUShort( scol2 ); 2250 2251 FindColorIndices( block, scol1, scol2, colorIndices ); 2252 EmitUInt( colorIndices ); 2253 2254 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2255 } 2256 outData += dstPadding; 2257 inBuf += srcPadding; 2258 } 2259 2260 //idLib::Printf( "\r100%%\n" ); 2261 } 2262 2263 /* 2264 ======================== 2265 idDxtEncoder::CompressYCoCgCTX1DXT5AHQ 2266 2267 params: inBuf - image to compress 2268 paramO: outBuf - result of compression 2269 params: width - width of image 2270 params: height - height of image 2271 ======================== 2272 */ 2273 void idDxtEncoder::CompressYCoCgCTX1DXT5AHQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2274 ALIGN16( byte block[64] ); 2275 byte alphaIndices1[6]; 2276 byte alphaIndices2[6]; 2277 unsigned int colorIndices; 2278 byte col1[4]; 2279 byte col2[4]; 2280 int error1; 2281 int error2; 2282 2283 assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) ); 2284 2285 this->width = width; 2286 this->height = height; 2287 this->outData = outBuf; 2288 2289 if ( width > 4 && ( width & 3 ) != 0 ) { 2290 return; 2291 } 2292 if ( height > 4 && ( height & 3 ) != 0 ) { 2293 return; 2294 } 2295 2296 if ( width < 4 || height < 4 ) { 2297 WriteTinyColorCTX1DXT5A( inBuf, width, height ); 2298 return; 2299 } 2300 2301 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2302 for ( int i = 0; i < width; i += 4 ) { 2303 2304 ExtractBlock( inBuf + i * 4, width, block ); 2305 2306 GetMinMaxAlphaHQ( block, 3, col1, col2 ); 2307 2308 // Write out alpha data. Try and find minimum error for the two encoding methods. 2309 error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 ); 2310 error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 ); 2311 2312 if ( error1 < error2 ) { 2313 2314 EmitByte( col1[3] ); 2315 EmitByte( col2[3] ); 2316 EmitByte( alphaIndices1[0] ); 2317 EmitByte( alphaIndices1[1] ); 2318 EmitByte( alphaIndices1[2] ); 2319 EmitByte( alphaIndices1[3] ); 2320 EmitByte( alphaIndices1[4] ); 2321 EmitByte( alphaIndices1[5] ); 2322 2323 } else { 2324 2325 EmitByte( col2[3] ); 2326 EmitByte( col1[3] ); 2327 EmitByte( alphaIndices2[0] ); 2328 EmitByte( alphaIndices2[1] ); 2329 EmitByte( alphaIndices2[2] ); 2330 EmitByte( alphaIndices2[3] ); 2331 EmitByte( alphaIndices2[4] ); 2332 EmitByte( alphaIndices2[5] ); 2333 } 2334 2335 GetMinMaxCTX1HQ( block, col1, col2 ); 2336 2337 EmitByte( col2[0] ); 2338 EmitByte( col2[1] ); 2339 EmitByte( col1[0] ); 2340 EmitByte( col1[1] ); 2341 2342 FindCTX1Indices( block, col1, col2, colorIndices ); 2343 EmitUInt( colorIndices ); 2344 2345 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2346 } 2347 outData += dstPadding; 2348 inBuf += srcPadding; 2349 } 2350 2351 //idLib::Printf( "\r100%%\n" ); 2352 } 2353 2354 /* 2355 ======================== 2356 idDxtEncoder::RotateNormalsDXT1 2357 ======================== 2358 */ 2359 void idDxtEncoder::RotateNormalsDXT1( byte *block ) const { 2360 byte rotatedBlock[64]; 2361 byte col1[4]; 2362 byte col2[4]; 2363 int bestError = MAX_TYPE( int ); 2364 int bestRotation = 0; 2365 2366 for ( int i = 0; i < 32; i += 1 ) { 2367 int r = ( i << 3 ) | ( i >> 2 ); 2368 float angle = ( r / 255.0f ) * idMath::PI; 2369 float s = sin( angle ); 2370 float c = cos( angle ); 2371 2372 for ( int j = 0; j < 16; j++ ) { 2373 float x = block[j*4+0] / 255.0f * 2.0f - 1.0f; 2374 float y = block[j*4+1] / 255.0f * 2.0f - 1.0f; 2375 float rx = c * x - s * y; 2376 float ry = s * x + c * y; 2377 rotatedBlock[j*4+0] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f ); 2378 rotatedBlock[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f ); 2379 } 2380 2381 int error = GetMinMaxColorsHQ( rotatedBlock, col1, col2, true ); 2382 if ( error < bestError ) { 2383 bestError = error; 2384 bestRotation = r; 2385 } 2386 } 2387 2388 float angle = ( bestRotation / 255.0f ) * idMath::PI; 2389 float s = sin( angle ); 2390 float c = cos( angle ); 2391 2392 for ( int j = 0; j < 16; j++ ) { 2393 float x = block[j*4+0] / 255.0f * 2.0f - 1.0f; 2394 float y = block[j*4+1] / 255.0f * 2.0f - 1.0f; 2395 float rx = c * x - s * y; 2396 float ry = s * x + c * y; 2397 block[j*4+0] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f ); 2398 block[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f ); 2399 block[j*4+2] = (byte)bestRotation; 2400 } 2401 } 2402 2403 /* 2404 ======================== 2405 idDxtEncoder::CompressNormalMapDXT1HQ 2406 2407 params: inBuf - image to compress 2408 paramO: outBuf - result of compression 2409 params: width - width of image 2410 params: height - height of image 2411 ======================== 2412 */ 2413 void idDxtEncoder::CompressNormalMapDXT1HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2414 ALIGN16( byte block[64] ); 2415 unsigned int colorIndices; 2416 byte col1[4]; 2417 byte col2[4]; 2418 2419 this->width = width; 2420 this->height = height; 2421 this->outData = outBuf; 2422 2423 if ( width > 4 && ( width & 3 ) != 0 ) { 2424 return; 2425 } 2426 if ( height > 4 && ( height & 3 ) != 0 ) { 2427 return; 2428 } 2429 2430 if ( width < 4 || height < 4 ) { 2431 WriteTinyColorDXT1( inBuf, width, height ); 2432 return; 2433 } 2434 2435 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2436 for ( int i = 0; i < width; i += 4 ) { 2437 2438 ExtractBlock( inBuf + i * 4, width, block ); 2439 2440 for ( int k = 0; k < 16; k++ ) { 2441 block[k*4+2] = 0; 2442 } 2443 2444 GetMinMaxColorsHQ( block, col1, col2, true ); 2445 2446 // Write out color data. Always take the path with 4 interpolated values. 2447 unsigned short scol1 = ColorTo565( col1 ); 2448 unsigned short scol2 = ColorTo565( col2 ); 2449 2450 EmitUShort( scol1 ); 2451 EmitUShort( scol2 ); 2452 2453 FindColorIndices( block, scol1, scol2, colorIndices ); 2454 EmitUInt( colorIndices ); 2455 2456 //idLib::Printf( "\r%3d%%", ( j * width + i * 4 ) * 100 / ( width * height ) ); 2457 } 2458 outData += dstPadding; 2459 inBuf += srcPadding; 2460 } 2461 2462 //idLib::Printf( "\r100%%\n" ); 2463 } 2464 2465 /* 2466 ======================== 2467 idDxtEncoder::CompressNormalMapDXT1RenormalizeHQ 2468 2469 params: inBuf - image to compress 2470 paramO: outBuf - result of compression 2471 params: width - width of image 2472 params: height - height of image 2473 ======================== 2474 */ 2475 void idDxtEncoder::CompressNormalMapDXT1RenormalizeHQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2476 ALIGN16( byte block[64] ); 2477 unsigned int colorIndices; 2478 byte col1[4]; 2479 byte col2[4]; 2480 2481 this->width = width; 2482 this->height = height; 2483 this->outData = outBuf; 2484 2485 if ( width > 4 && ( width & 3 ) != 0 ) { 2486 return; 2487 } 2488 if ( height > 4 && ( height & 3 ) != 0 ) { 2489 return; 2490 } 2491 2492 if ( width < 4 || height < 4 ) { 2493 WriteTinyColorDXT1( inBuf, width, height ); 2494 return; 2495 } 2496 2497 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2498 for ( int i = 0; i < width; i += 4 ) { 2499 2500 ExtractBlock( inBuf + i * 4, width, block ); 2501 2502 // clear alpha channel 2503 for ( int k = 0; k < 16; k++ ) { 2504 block[k*4+3] = 0; 2505 } 2506 2507 GetMinMaxNormalsDXT1HQ( block, col1, col2, colorIndices, true ); 2508 2509 // Write out color data. Always take the path with 4 interpolated values. 2510 unsigned short scol1 = ColorTo565( col1 ); 2511 unsigned short scol2 = ColorTo565( col2 ); 2512 2513 EmitUShort( scol1 ); 2514 EmitUShort( scol2 ); 2515 EmitUInt( colorIndices ); 2516 2517 ////idLib::Printf( "\r%3d%%", ( j * width + i * 4 ) * 100 / ( width * height ) ); 2518 } 2519 outData += dstPadding; 2520 inBuf += srcPadding; 2521 } 2522 2523 ////idLib::Printf( "\r100%%\n" ); 2524 } 2525 2526 #define USE_SCALE 1 2527 #define USE_BIAS 1 2528 2529 static int c_blocks; 2530 static int c_scaled; 2531 static int c_scaled2x; 2532 static int c_scaled4x; 2533 static int c_differentBias; 2534 static int c_biasHelped; 2535 2536 /* 2537 ======================== 2538 idDxtEncoder::BiasScaleNormalY 2539 2540 * scale2x = 33% 2541 * scale4x = 23% 2542 * bias + scale2x = 30% 2543 * bias + scale4x = 55% 2544 ======================== 2545 */ 2546 void idDxtEncoder::BiasScaleNormalY( byte *colorBlock ) const { 2547 2548 byte minColor = 255; 2549 byte maxColor = 0; 2550 2551 for ( int i = 0; i < 16; i++ ) { 2552 if ( colorBlock[i*4+1] < minColor ) { 2553 minColor = colorBlock[i*4+1]; 2554 } 2555 if ( colorBlock[i*4+1] > maxColor ) { 2556 maxColor = colorBlock[i*4+1]; 2557 } 2558 } 2559 2560 int bestBias = 128; 2561 int bestRange = Max( abs( minColor - bestBias ), abs( maxColor - bestBias ) ); 2562 #if USE_BIAS 2563 for ( int i = 0; i < 32; i++ ) { 2564 int bias = ( ( i << 3 ) | ( i >> 2 ) ) - 4; 2565 int range = Max( abs( minColor - bias ), abs( maxColor - bias ) ); 2566 if ( range < bestRange ) { 2567 bestRange = range; 2568 bestBias = bias; 2569 } 2570 } 2571 #endif 2572 2573 const int s0 = 128 / 2 - 1; 2574 const int s1 = 128 / 4 - 1; 2575 2576 #if USE_SCALE 2577 int scale = 1 + ( bestRange <= s0 ) + 2 * ( bestRange <= s1 ); 2578 #else 2579 int scale = 1; 2580 #endif 2581 2582 if ( scale == 1 ) { 2583 bestBias = 128; 2584 } else { 2585 c_scaled++; 2586 if ( scale == 2 ) c_scaled2x++; 2587 if ( scale == 4 ) c_scaled4x++; 2588 if ( bestBias != 128 ) { 2589 c_differentBias++; 2590 int r = Max( abs( minColor - 128 ), abs( maxColor - 128 ) ); 2591 int s = 1 + ( r <= s0 ) + 2 * ( r <= s1 ); 2592 if ( scale > s ) { 2593 c_biasHelped++; 2594 } 2595 } 2596 } 2597 2598 c_blocks++; 2599 2600 for ( int i = 0; i < 16; i++ ) { 2601 colorBlock[i*4+0] = byte( bestBias + 4 ); 2602 colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - bestBias ) * scale + 128 ); 2603 colorBlock[i*4+2] = byte( ( scale - 1 ) << 3 ); 2604 } 2605 } 2606 2607 /* 2608 ======================== 2609 idDxtEncoder::RotateNormalsDXT5 2610 ======================== 2611 */ 2612 void idDxtEncoder::RotateNormalsDXT5( byte *block ) const { 2613 byte rotatedBlock[64]; 2614 byte col1[4]; 2615 byte col2[4]; 2616 int bestError = MAX_TYPE( int ); 2617 int bestRotation = 0; 2618 int bestScale = 1; 2619 2620 for ( int i = 0; i < 32; i += 1 ) { 2621 int r = ( i << 3 ) | ( i >> 2 ); 2622 float angle = ( r / 255.0f ) * idMath::PI; 2623 float s = sin( angle ); 2624 float c = cos( angle ); 2625 2626 for ( int j = 0; j < 16; j++ ) { 2627 float x = block[j*4+3] / 255.0f * 2.0f - 1.0f; 2628 float y = block[j*4+1] / 255.0f * 2.0f - 1.0f; 2629 float rx = c * x - s * y; 2630 float ry = s * x + c * y; 2631 rotatedBlock[j*4+3] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f ); 2632 rotatedBlock[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f ); 2633 } 2634 2635 #if USE_SCALE 2636 byte minColor = 255; 2637 byte maxColor = 0; 2638 2639 for ( int j = 0; j < 16; j++ ) { 2640 if ( rotatedBlock[j*4+1] < minColor ) { 2641 minColor = rotatedBlock[j*4+1]; 2642 } 2643 if ( rotatedBlock[j*4+1] > maxColor ) { 2644 maxColor = rotatedBlock[j*4+1]; 2645 } 2646 } 2647 2648 const int s0 = 128 / 2 - 1; 2649 const int s1 = 128 / 4 - 1; 2650 2651 int range = Max( abs( minColor - 128 ), abs( maxColor - 128 ) ); 2652 int scale = 1 + ( range <= s0 ) + 2 * ( range <= s1 ); 2653 2654 for ( int j = 0; j < 16; j++ ) { 2655 rotatedBlock[j*4+1] = byte( ( rotatedBlock[j*4+1] - 128 ) * scale + 128 ); 2656 } 2657 #endif 2658 2659 int errorY = GetMinMaxNormalYHQ( rotatedBlock, col1, col2, true, scale ); 2660 int errorX = GetMinMaxAlphaHQ( rotatedBlock, 3, col1, col2 ); 2661 int error = errorX + errorY; 2662 if ( error < bestError ) { 2663 bestError = error; 2664 bestRotation = r; 2665 bestScale = scale; 2666 } 2667 } 2668 2669 float angle = ( bestRotation / 255.0f ) * idMath::PI; 2670 float s = sin( angle ); 2671 float c = cos( angle ); 2672 2673 for ( int j = 0; j < 16; j++ ) { 2674 float x = block[j*4+3] / 255.0f * 2.0f - 1.0f; 2675 float y = block[j*4+1] / 255.0f * 2.0f - 1.0f; 2676 float rx = c * x - s * y; 2677 float ry = s * x + c * y; 2678 block[j*4+0] = (byte)bestRotation; 2679 block[j*4+1] = idMath::Ftob( ( ry + 1.0f ) / 2.0f * 255.0f ); 2680 block[j*4+3] = idMath::Ftob( ( rx + 1.0f ) / 2.0f * 255.0f ); 2681 2682 #if USE_SCALE 2683 block[j*4+1] = byte( ( block[j*4+1] - 128 ) * bestScale + 128 ); 2684 block[j*4+2] = byte( ( bestScale - 1 ) << 3 ); 2685 #endif 2686 } 2687 } 2688 2689 /* 2690 ======================== 2691 idDxtEncoder::CompressNormalMapDXT5HQ 2692 2693 params: inBuf - image to compress 2694 paramO: outBuf - result of compression 2695 params: width - width of image 2696 params: height - height of image 2697 ======================== 2698 */ 2699 void idDxtEncoder::CompressNormalMapDXT5HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2700 ALIGN16( byte block[64] ); 2701 byte alphaIndices1[6]; 2702 byte alphaIndices2[6]; 2703 unsigned int colorIndices; 2704 byte col1[4]; 2705 byte col2[4]; 2706 int error1; 2707 int error2; 2708 2709 this->width = width; 2710 this->height = height; 2711 this->outData = outBuf; 2712 2713 if ( width > 4 && ( width & 3 ) != 0 ) { 2714 return; 2715 } 2716 if ( height > 4 && ( height & 3 ) != 0 ) { 2717 return; 2718 } 2719 2720 if ( width < 4 || height < 4 ) { 2721 WriteTinyColorDXT5( inBuf, width, height ); 2722 return; 2723 } 2724 2725 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2726 for ( int i = 0; i < width; i += 4 ) { 2727 2728 ExtractBlock( inBuf + i * 4, width, block ); 2729 2730 // swizzle components 2731 for ( int k = 0; k < 16; k++ ) { 2732 block[k*4+3] = block[k*4+0]; 2733 block[k*4+0] = 0; 2734 block[k*4+2] = 0; 2735 } 2736 2737 //BiasScaleNormalY( block ); 2738 //RotateNormalsDXT5( block ); 2739 2740 GetMinMaxNormalYHQ( block, col1, col2, true, 1 ); 2741 GetMinMaxAlphaHQ( block, 3, col1, col2 ); 2742 2743 // Write out alpha data. Try and find minimum error for the two encoding methods. 2744 error1 = FindAlphaIndices( block, 3, col1[3], col2[3], alphaIndices1 ); 2745 error2 = FindAlphaIndices( block, 3, col2[3], col1[3], alphaIndices2 ); 2746 2747 if ( error1 < error2 ) { 2748 2749 EmitByte( col1[3] ); 2750 EmitByte( col2[3] ); 2751 EmitByte( alphaIndices1[0] ); 2752 EmitByte( alphaIndices1[1] ); 2753 EmitByte( alphaIndices1[2] ); 2754 EmitByte( alphaIndices1[3] ); 2755 EmitByte( alphaIndices1[4] ); 2756 EmitByte( alphaIndices1[5] ); 2757 2758 } else { 2759 2760 EmitByte( col2[3] ); 2761 EmitByte( col1[3] ); 2762 EmitByte( alphaIndices2[0] ); 2763 EmitByte( alphaIndices2[1] ); 2764 EmitByte( alphaIndices2[2] ); 2765 EmitByte( alphaIndices2[3] ); 2766 EmitByte( alphaIndices2[4] ); 2767 EmitByte( alphaIndices2[5] ); 2768 } 2769 2770 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 2771 NV4XHardwareBugFix( col2, col1 ); 2772 #endif 2773 2774 // Write out color data. Always take the path with 4 interpolated values. 2775 unsigned short scol1 = ColorTo565( col1 ); 2776 unsigned short scol2 = ColorTo565( col2 ); 2777 2778 EmitUShort( scol1 ); 2779 EmitUShort( scol2 ); 2780 2781 FindColorIndices( block, scol1, scol2, colorIndices ); 2782 EmitUInt( colorIndices ); 2783 2784 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2785 } 2786 outData += dstPadding; 2787 inBuf += srcPadding; 2788 } 2789 2790 //idLib::Printf( "\r100%%\n" ); 2791 } 2792 2793 /* 2794 ======================== 2795 idDxtEncoder::CompressNormalMapDXT5RenormalizeHQ 2796 2797 params: inBuf - image to compress 2798 paramO: outBuf - result of compression 2799 params: width - width of image 2800 params: height - height of image 2801 ======================== 2802 */ 2803 void idDxtEncoder::CompressNormalMapDXT5RenormalizeHQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2804 ALIGN16( byte block[64] ); 2805 unsigned int colorIndices; 2806 byte alphaIndices[6]; 2807 byte col1[4]; 2808 byte col2[4]; 2809 2810 this->width = width; 2811 this->height = height; 2812 this->outData = outBuf; 2813 2814 if ( width > 4 && ( width & 3 ) != 0 ) { 2815 return; 2816 } 2817 if ( height > 4 && ( height & 3 ) != 0 ) { 2818 return; 2819 } 2820 2821 if ( width < 4 || height < 4 ) { 2822 WriteTinyColorDXT5( inBuf, width, height ); 2823 return; 2824 } 2825 2826 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2827 for ( int i = 0; i < width; i += 4 ) { 2828 2829 ExtractBlock( inBuf + i * 4, width, block ); 2830 2831 // swizzle components 2832 for ( int k = 0; k < 16; k++ ) { 2833 #if 0 // object-space 2834 block[k*4+3] = block[k*4+2]; 2835 block[k*4+2] = 0; 2836 #else 2837 block[k*4+3] = block[k*4+0]; 2838 block[k*4+0] = 0; 2839 #endif 2840 } 2841 2842 GetMinMaxNormalsDXT5HQFast( block, col1, col2, colorIndices, alphaIndices ); 2843 2844 EmitByte( col2[3] ); 2845 EmitByte( col1[3] ); 2846 EmitByte( alphaIndices[0] ); 2847 EmitByte( alphaIndices[1] ); 2848 EmitByte( alphaIndices[2] ); 2849 EmitByte( alphaIndices[3] ); 2850 EmitByte( alphaIndices[4] ); 2851 EmitByte( alphaIndices[5] ); 2852 2853 unsigned short scol1 = ColorTo565( col1 ); 2854 unsigned short scol2 = ColorTo565( col2 ); 2855 2856 EmitUShort( scol2 ); 2857 EmitUShort( scol1 ); 2858 EmitUInt( colorIndices ); 2859 2860 ////idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2861 } 2862 outData += dstPadding; 2863 inBuf += srcPadding; 2864 } 2865 2866 ////idLib::Printf( "\r100%%\n" ); 2867 } 2868 2869 /* 2870 ======================== 2871 idDxtEncoder::CompressNormalMapDXN2HQ 2872 2873 params: inBuf - image to compress 2874 paramO: outBuf - result of compression 2875 params: width - width of image 2876 params: height - height of image 2877 ======================== 2878 */ 2879 void idDxtEncoder::CompressNormalMapDXN2HQ( const byte *inBuf, byte *outBuf, int width, int height ) { 2880 ALIGN16( byte block[64] ); 2881 byte alphaIndices1[6]; 2882 byte alphaIndices2[6]; 2883 byte col1[4]; 2884 byte col2[4]; 2885 int error1; 2886 int error2; 2887 2888 this->width = width; 2889 this->height = height; 2890 this->outData = outBuf; 2891 2892 if ( width > 4 && ( width & 3 ) != 0 ) { 2893 return; 2894 } 2895 if ( height > 4 && ( height & 3 ) != 0 ) { 2896 return; 2897 } 2898 2899 if ( width < 4 || height < 4 ) { 2900 WriteTinyColorDXT5( inBuf, width, height ); 2901 return; 2902 } 2903 2904 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 2905 for ( int i = 0; i < width; i += 4 ) { 2906 2907 ExtractBlock( inBuf + i * 4, width, block ); 2908 2909 for ( int k = 0; k < 2; k++ ) { 2910 GetMinMaxAlphaHQ( block, k, col1, col2 ); 2911 2912 // Write out alpha data. Try and find minimum error for the two encoding methods. 2913 error1 = FindAlphaIndices( block, k, col1[k], col2[k], alphaIndices1 ); 2914 error2 = FindAlphaIndices( block, k, col2[k], col1[k], alphaIndices2 ); 2915 2916 if ( error1 < error2 ) { 2917 2918 EmitByte( col1[k] ); 2919 EmitByte( col2[k] ); 2920 EmitByte( alphaIndices1[0] ); 2921 EmitByte( alphaIndices1[1] ); 2922 EmitByte( alphaIndices1[2] ); 2923 EmitByte( alphaIndices1[3] ); 2924 EmitByte( alphaIndices1[4] ); 2925 EmitByte( alphaIndices1[5] ); 2926 2927 } else { 2928 2929 EmitByte( col2[k] ); 2930 EmitByte( col1[k] ); 2931 EmitByte( alphaIndices2[0] ); 2932 EmitByte( alphaIndices2[1] ); 2933 EmitByte( alphaIndices2[2] ); 2934 EmitByte( alphaIndices2[3] ); 2935 EmitByte( alphaIndices2[4] ); 2936 EmitByte( alphaIndices2[5] ); 2937 } 2938 } 2939 2940 //idLib::Printf( "\r%3d%%", ( j * width + i ) * 100 / ( width * height ) ); 2941 } 2942 outData += dstPadding; 2943 inBuf += srcPadding; 2944 } 2945 2946 //idLib::Printf( "\r100%%\n" ); 2947 } 2948 2949 /* 2950 ======================== 2951 idDxtEncoder::GetMinMaxBBox 2952 2953 Takes the extents of the bounding box of the colors in the 4x4 block in RGB space. 2954 Also finds the minimum and maximum alpha values. 2955 2956 params: colorBlock - 4*4 input tile, 4 bytes per pixel 2957 paramO: minColor - 4 byte Min color found 2958 paramO: maxColor - 4 byte Max color found 2959 ======================== 2960 */ 2961 ID_INLINE void idDxtEncoder::GetMinMaxBBox( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 2962 2963 minColor[0] = minColor[1] = minColor[2] = minColor[3] = 255; 2964 maxColor[0] = maxColor[1] = maxColor[2] = maxColor[3] = 0; 2965 2966 for ( int i = 0; i < 16; i++ ) { 2967 if ( colorBlock[i*4+0] < minColor[0] ) { 2968 minColor[0] = colorBlock[i*4+0]; 2969 } 2970 if ( colorBlock[i*4+1] < minColor[1] ) { 2971 minColor[1] = colorBlock[i*4+1]; 2972 } 2973 if ( colorBlock[i*4+2] < minColor[2] ) { 2974 minColor[2] = colorBlock[i*4+2]; 2975 } 2976 if ( colorBlock[i*4+3] < minColor[3] ) { 2977 minColor[3] = colorBlock[i*4+3]; 2978 } 2979 if ( colorBlock[i*4+0] > maxColor[0] ) { 2980 maxColor[0] = colorBlock[i*4+0]; 2981 } 2982 if ( colorBlock[i*4+1] > maxColor[1] ) { 2983 maxColor[1] = colorBlock[i*4+1]; 2984 } 2985 if ( colorBlock[i*4+2] > maxColor[2] ) { 2986 maxColor[2] = colorBlock[i*4+2]; 2987 } 2988 if ( colorBlock[i*4+3] > maxColor[3] ) { 2989 maxColor[3] = colorBlock[i*4+3]; 2990 } 2991 } 2992 } 2993 2994 /* 2995 ======================== 2996 idDxtEncoder::InsetColorsBBox 2997 ======================== 2998 */ 2999 ID_INLINE void idDxtEncoder::InsetColorsBBox( byte *minColor, byte *maxColor ) const { 3000 byte inset[4]; 3001 3002 inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_COLOR_SHIFT; 3003 inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_COLOR_SHIFT; 3004 inset[2] = ( maxColor[2] - minColor[2] ) >> INSET_COLOR_SHIFT; 3005 inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_ALPHA_SHIFT; 3006 3007 minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255; 3008 minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255; 3009 minColor[2] = ( minColor[2] + inset[2] <= 255 ) ? minColor[2] + inset[2] : 255; 3010 minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255; 3011 3012 maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0; 3013 maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0; 3014 maxColor[2] = ( maxColor[2] >= inset[2] ) ? maxColor[2] - inset[2] : 0; 3015 maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0; 3016 } 3017 3018 /* 3019 ======================== 3020 idDxtEncoder::SelectColorsDiagonal 3021 ======================== 3022 */ 3023 void idDxtEncoder::SelectColorsDiagonal( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 3024 3025 byte mid0 = byte( ( (int) minColor[0] + maxColor[0] + 1 ) >> 1 ); 3026 byte mid1 = byte( ( (int) minColor[1] + maxColor[1] + 1 ) >> 1 ); 3027 byte mid2 = byte( ( (int) minColor[2] + maxColor[2] + 1 ) >> 1 ); 3028 3029 #if 0 3030 3031 // using the covariance is the best way to select the diagonal 3032 int side0 = 0; 3033 int side1 = 0; 3034 for ( int i = 0; i < 16; i++ ) { 3035 int b0 = colorBlock[i*4+0] - mid0; 3036 int b1 = colorBlock[i*4+1] - mid1; 3037 int b2 = colorBlock[i*4+2] - mid2; 3038 side0 += ( b0 * b1 ); 3039 side1 += ( b1 * b2 ); 3040 } 3041 byte mask0 = -( side0 < 0 ); 3042 byte mask1 = -( side1 < 0 ); 3043 3044 #else 3045 3046 // calculating the covariance of just the sign bits is much faster and gives almost the same result 3047 int side0 = 0; 3048 int side1 = 0; 3049 for ( int i = 0; i < 16; i++ ) { 3050 byte b0 = colorBlock[i*4+0] >= mid0; 3051 byte b1 = colorBlock[i*4+1] >= mid1; 3052 byte b2 = colorBlock[i*4+2] >= mid2; 3053 side0 += ( b0 ^ b1 ); 3054 side1 += ( b1 ^ b2 ); 3055 } 3056 byte mask0 = -( side0 > 8 ); 3057 byte mask1 = -( side1 > 8 ); 3058 3059 #endif 3060 3061 byte c0 = minColor[0]; 3062 byte c1 = maxColor[0]; 3063 byte c2 = minColor[2]; 3064 byte c3 = maxColor[2]; 3065 3066 c0 ^= c1; 3067 mask0 &= c0; 3068 c1 ^= mask0; 3069 c0 ^= c1; 3070 3071 c2 ^= c3; 3072 mask1 &= c2; 3073 c3 ^= mask1; 3074 c2 ^= c3; 3075 3076 minColor[0] = c0; 3077 maxColor[0] = c1; 3078 minColor[2] = c2; 3079 maxColor[2] = c3; 3080 3081 if ( ColorTo565( minColor ) > ColorTo565( maxColor ) ) { 3082 SwapValues( minColor[0], maxColor[0] ); 3083 SwapValues( minColor[1], maxColor[1] ); 3084 SwapValues( minColor[2], maxColor[2] ); 3085 } 3086 } 3087 3088 /* 3089 ======================== 3090 idDxtEncoder::EmitColorIndices 3091 3092 params: colorBlock - 16 pixel block for which find color indexes 3093 paramO: minColor - Min color found 3094 paramO: maxColor - Max color found 3095 return: 4 byte color index block 3096 ======================== 3097 */ 3098 void idDxtEncoder::EmitColorIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) { 3099 #if 1 3100 3101 ALIGN16( uint16 colors[4][4] ); 3102 unsigned int result = 0; 3103 3104 colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 ); 3105 colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 ); 3106 colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 ); 3107 colors[0][3] = 0; 3108 colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 ); 3109 colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 ); 3110 colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 ); 3111 colors[1][3] = 0; 3112 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 3113 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 3114 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 3115 colors[2][3] = 0; 3116 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 3117 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 3118 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 3119 colors[3][3] = 0; 3120 3121 // uses sum of absolute differences instead of squared distance to find the best match 3122 for ( int i = 15; i >= 0; i-- ) { 3123 int c0, c1, c2, c3, m, d0, d1, d2, d3; 3124 3125 c0 = colorBlock[i*4+0]; 3126 c1 = colorBlock[i*4+1]; 3127 c2 = colorBlock[i*4+2]; 3128 c3 = colorBlock[i*4+3]; 3129 3130 m = colors[0][0] - c0; 3131 d0 = abs( m ); 3132 m = colors[1][0] - c0; 3133 d1 = abs( m ); 3134 m = colors[2][0] - c0; 3135 d2 = abs( m ); 3136 m = colors[3][0] - c0; 3137 d3 = abs( m ); 3138 3139 m = colors[0][1] - c1; 3140 d0 += abs( m ); 3141 m = colors[1][1] - c1; 3142 d1 += abs( m ); 3143 m = colors[2][1] - c1; 3144 d2 += abs( m ); 3145 m = colors[3][1] - c1; 3146 d3 += abs( m ); 3147 3148 m = colors[0][2] - c2; 3149 d0 += abs( m ); 3150 m = colors[1][2] - c2; 3151 d1 += abs( m ); 3152 m = colors[2][2] - c2; 3153 d2 += abs( m ); 3154 m = colors[3][2] - c2; 3155 d3 += abs( m ); 3156 3157 #if 0 3158 int b0 = d0 > d2; 3159 int b1 = d1 > d3; 3160 int b2 = d0 > d3; 3161 int b3 = d1 > d2; 3162 int b4 = d0 > d1; 3163 int b5 = d2 > d3; 3164 3165 result |= ( ( !b3 & b4 ) | ( b2 & b5 ) | ( ( ( b0 & b3 ) | ( b1 & b2 ) ) << 1 ) ) << ( i << 1 ); 3166 #else 3167 bool b0 = d0 > d3; 3168 bool b1 = d1 > d2; 3169 bool b2 = d0 > d2; 3170 bool b3 = d1 > d3; 3171 bool b4 = d2 > d3; 3172 3173 int x0 = b1 & b2; 3174 int x1 = b0 & b3; 3175 int x2 = b0 & b4; 3176 3177 result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 ); 3178 #endif 3179 } 3180 3181 EmitUInt( result ); 3182 3183 #elif 1 3184 3185 byte colors[4][4]; 3186 unsigned int indexes[16]; 3187 3188 colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 6 ); 3189 colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 5 ); 3190 colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 6 ); 3191 colors[0][3] = 0; 3192 colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 6 ); 3193 colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 5 ); 3194 colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 6 ); 3195 colors[1][3] = 0; 3196 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 3197 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 3198 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 3199 colors[2][3] = 0; 3200 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 3201 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 3202 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 3203 colors[3][3] = 0; 3204 3205 for ( int i = 0; i < 16; i++ ) { 3206 int c0, c1, c2, m, d, minDist; 3207 3208 c0 = colorBlock[i*4+0]; 3209 c1 = colorBlock[i*4+1]; 3210 c2 = colorBlock[i*4+2]; 3211 3212 m = colors[0][0] - c0; 3213 d = m * m; 3214 m = colors[0][1] - c1; 3215 d += m * m; 3216 m = colors[0][2] - c2; 3217 d += m * m; 3218 3219 minDist = d; 3220 indexes[i] = 0; 3221 3222 m = colors[1][0] - c0; 3223 d = m * m; 3224 m = colors[1][1] - c1; 3225 d += m * m; 3226 m = colors[1][2] - c2; 3227 d += m * m; 3228 3229 if ( d < minDist ) { 3230 minDist = d; 3231 indexes[i] = 1; 3232 } 3233 3234 m = colors[2][0] - c0; 3235 d = m * m; 3236 m = colors[2][1] - c1; 3237 d += m * m; 3238 m = colors[2][2] - c2; 3239 d += m * m; 3240 3241 if ( d < minDist ) { 3242 minDist = d; 3243 indexes[i] = 2; 3244 } 3245 3246 m = colors[3][0] - c0; 3247 d = m * m; 3248 m = colors[3][1] - c1; 3249 d += m * m; 3250 m = colors[3][2] - c2; 3251 d += m * m; 3252 3253 if ( d < minDist ) { 3254 minDist = d; 3255 indexes[i] = 3; 3256 } 3257 } 3258 3259 unsigned int result = 0; 3260 for ( int i = 0; i < 16; i++ ) { 3261 result |= ( indexes[i] << (unsigned int)( i << 1 ) ); 3262 } 3263 3264 EmitUInt( result ); 3265 3266 #else 3267 3268 byte colors[4][4]; 3269 unsigned int indexes[16]; 3270 3271 colors[0][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 6 ); 3272 colors[0][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 5 ); 3273 colors[0][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 6 ); 3274 colors[0][3] = 0; 3275 colors[1][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 6 ); 3276 colors[1][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 5 ); 3277 colors[1][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 6 ); 3278 colors[1][3] = 0; 3279 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 3280 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 3281 colors[2][2] = ( 2 * colors[0][2] + 1 * colors[1][2] ) / 3; 3282 colors[2][3] = 0; 3283 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 3284 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 3285 colors[3][2] = ( 1 * colors[0][2] + 2 * colors[1][2] ) / 3; 3286 colors[3][3] = 0; 3287 3288 for ( int i = 0; i < 16; i++ ) { 3289 unsigned int minDist = (255*255)*4; 3290 for ( int j = 0; j < 4; j++ ) { 3291 unsigned int dist = ColorDistance( &colorBlock[i*4], &colors[j][0] ); 3292 if ( dist < minDist ) { 3293 minDist = dist; 3294 indexes[i] = j; 3295 } 3296 } 3297 } 3298 3299 unsigned int result = 0; 3300 for ( int i = 0; i < 16; i++ ) { 3301 result |= ( indexes[i] << (unsigned int)( i << 1 ) ); 3302 } 3303 3304 EmitUInt( result ); 3305 3306 #endif 3307 } 3308 3309 /* 3310 ======================== 3311 idDxtEncoder::EmitColorAlphaIndices 3312 3313 params: colorBlock - 16 pixel block for which find color indexes 3314 paramO: minColor - Min color found 3315 paramO: maxColor - Max color found 3316 return: 4 byte color index block 3317 ======================== 3318 */ 3319 void idDxtEncoder::EmitColorAlphaIndices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) { 3320 ALIGN16( uint16 colors[4][4] ); 3321 unsigned int result = 0; 3322 3323 colors[0][0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 ); 3324 colors[0][1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 ); 3325 colors[0][2] = ( minColor[2] & C565_5_MASK ) | ( minColor[2] >> 5 ); 3326 colors[0][3] = 255; 3327 colors[1][0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 ); 3328 colors[1][1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 ); 3329 colors[1][2] = ( maxColor[2] & C565_5_MASK ) | ( maxColor[2] >> 5 ); 3330 colors[1][3] = 255; 3331 colors[2][0] = ( colors[0][0] + colors[1][0] ) / 2; 3332 colors[2][1] = ( colors[0][1] + colors[1][1] ) / 2; 3333 colors[2][2] = ( colors[0][2] + colors[1][2] ) / 2; 3334 colors[2][3] = 255; 3335 colors[3][0] = 0; 3336 colors[3][1] = 0; 3337 colors[3][2] = 0; 3338 colors[3][3] = 0; 3339 3340 // uses sum of absolute differences instead of squared distance to find the best match 3341 for ( int i = 15; i >= 0; i-- ) { 3342 int c0, c1, c2, c3, m, d0, d1, d2; 3343 3344 c0 = colorBlock[i*4+0]; 3345 c1 = colorBlock[i*4+1]; 3346 c2 = colorBlock[i*4+2]; 3347 c3 = colorBlock[i*4+3]; 3348 3349 m = colors[0][0] - c0; 3350 d0 = abs( m ); 3351 m = colors[1][0] - c0; 3352 d1 = abs( m ); 3353 m = colors[2][0] - c0; 3354 d2 = abs( m ); 3355 3356 m = colors[0][1] - c1; 3357 d0 += abs( m ); 3358 m = colors[1][1] - c1; 3359 d1 += abs( m ); 3360 m = colors[2][1] - c1; 3361 d2 += abs( m ); 3362 3363 m = colors[0][2] - c2; 3364 d0 += abs( m ); 3365 m = colors[1][2] - c2; 3366 d1 += abs( m ); 3367 m = colors[2][2] - c2; 3368 d2 += abs( m ); 3369 3370 unsigned int b0 = d2 > d0; 3371 unsigned int b1 = d2 > d1; 3372 unsigned int b2 = d1 > d0; 3373 unsigned int b3 = c3 < 128; 3374 3375 result |= ( ( ( b0 & b1 | b3 ) << 1 ) | ( b2 ^ b1 | b3 ) ) << ( i << 1 ); 3376 } 3377 3378 EmitUInt( result ); 3379 } 3380 3381 /* 3382 ======================== 3383 idDxtEncoder::EmitCTX1Indices 3384 3385 params: colorBlock - 16 pixel block for which find color indexes 3386 paramO: minColor - Min color found 3387 paramO: maxColor - Max color found 3388 return: 4 byte color index block 3389 ======================== 3390 */ 3391 void idDxtEncoder::EmitCTX1Indices( const byte *colorBlock, const byte *minColor, const byte *maxColor ) { 3392 ALIGN16( uint16 colors[4][2] ); 3393 unsigned int result = 0; 3394 3395 colors[0][0] = maxColor[0]; 3396 colors[0][1] = maxColor[1]; 3397 colors[1][0] = minColor[0]; 3398 colors[1][1] = minColor[1]; 3399 3400 colors[2][0] = ( 2 * colors[0][0] + 1 * colors[1][0] ) / 3; 3401 colors[2][1] = ( 2 * colors[0][1] + 1 * colors[1][1] ) / 3; 3402 colors[3][0] = ( 1 * colors[0][0] + 2 * colors[1][0] ) / 3; 3403 colors[3][1] = ( 1 * colors[0][1] + 2 * colors[1][1] ) / 3; 3404 3405 for ( int i = 15; i >= 0; i-- ) { 3406 int c0, c1, m, d0, d1, d2, d3; 3407 3408 c0 = colorBlock[i*4+0]; 3409 c1 = colorBlock[i*4+1]; 3410 3411 m = colors[0][0] - c0; 3412 d0 = abs( m ); 3413 m = colors[1][0] - c0; 3414 d1 = abs( m ); 3415 m = colors[2][0] - c0; 3416 d2 = abs( m ); 3417 m = colors[3][0] - c0; 3418 d3 = abs( m ); 3419 3420 m = colors[0][1] - c1; 3421 d0 += abs( m ); 3422 m = colors[1][1] - c1; 3423 d1 += abs( m ); 3424 m = colors[2][1] - c1; 3425 d2 += abs( m ); 3426 m = colors[3][1] - c1; 3427 d3 += abs( m ); 3428 3429 bool b0 = d0 > d3; 3430 bool b1 = d1 > d2; 3431 bool b2 = d0 > d2; 3432 bool b3 = d1 > d3; 3433 bool b4 = d2 > d3; 3434 3435 int x0 = b1 & b2; 3436 int x1 = b0 & b3; 3437 int x2 = b0 & b4; 3438 3439 result |= ( x2 | ( ( x0 | x1 ) << 1 ) ) << ( i << 1 ); 3440 } 3441 3442 EmitUInt( result ); 3443 } 3444 3445 /* 3446 ======================== 3447 idDxtEncoder::EmitAlphaIndices 3448 3449 params: colorBlock - 16 pixel block for which find alpha indexes 3450 paramO: minAlpha - Min alpha found 3451 paramO: maxAlpha - Max alpha found 3452 ======================== 3453 */ 3454 void idDxtEncoder::EmitAlphaIndices( const byte *colorBlock, const int offset, const byte minAlpha, const byte maxAlpha ) { 3455 3456 assert( maxAlpha >= minAlpha ); 3457 3458 const int ALPHA_RANGE = 7; 3459 3460 #if 1 3461 3462 byte ab1, ab2, ab3, ab4, ab5, ab6, ab7; 3463 ALIGN16( byte indexes[16] ); 3464 3465 ab1 = ( 13 * maxAlpha + 1 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3466 ab2 = ( 11 * maxAlpha + 3 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3467 ab3 = ( 9 * maxAlpha + 5 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3468 ab4 = ( 7 * maxAlpha + 7 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3469 ab5 = ( 5 * maxAlpha + 9 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3470 ab6 = ( 3 * maxAlpha + 11 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3471 ab7 = ( 1 * maxAlpha + 13 * minAlpha + ALPHA_RANGE ) / (ALPHA_RANGE*2); 3472 3473 colorBlock += offset; 3474 3475 for ( int i = 0; i < 16; i++ ) { 3476 byte a = colorBlock[i*4]; 3477 int b1 = ( a >= ab1 ); 3478 int b2 = ( a >= ab2 ); 3479 int b3 = ( a >= ab3 ); 3480 int b4 = ( a >= ab4 ); 3481 int b5 = ( a >= ab5 ); 3482 int b6 = ( a >= ab6 ); 3483 int b7 = ( a >= ab7 ); 3484 int index = ( 8 - b1 - b2 - b3 - b4 - b5 - b6 - b7 ) & 7; 3485 indexes[i] = byte( index ^ ( 2 > index ) ); 3486 } 3487 3488 EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 3489 EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 3490 EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 3491 3492 EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 3493 EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 3494 EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 3495 3496 #elif 0 3497 3498 ALIGN16( byte indexes[16] ); 3499 byte delta = maxAlpha - minAlpha; 3500 byte half = delta >> 1; 3501 byte bias = delta / ( 2 * ALPHA_RANGE ); 3502 byte bottom = minAlpha + bias; 3503 byte top = maxAlpha - bias; 3504 3505 colorBlock += offset; 3506 3507 for ( int i = 0; i < 16; i++ ) { 3508 byte a = colorBlock[i*4]; 3509 if ( a <= bottom ) { 3510 indexes[i] = 1; 3511 } else if ( a >= top ) { 3512 indexes[i] = 0; 3513 } else { 3514 indexes[i] = (ALPHA_RANGE+1) + ( ( minAlpha - a ) * ALPHA_RANGE - half ) / delta; 3515 } 3516 } 3517 3518 EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 3519 EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 3520 EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 3521 3522 EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 3523 EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 3524 EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 3525 3526 #elif 0 3527 3528 ALIGN16( byte indexes[16] ); 3529 byte delta = maxAlpha - minAlpha; 3530 byte half = delta >> 1; 3531 byte bias = delta / ( 2 * ALPHA_RANGE ); 3532 byte bottom = minAlpha + bias; 3533 byte top = maxAlpha - bias; 3534 3535 colorBlock += offset; 3536 3537 for ( int i = 0; i < 16; i++ ) { 3538 byte a = colorBlock[i*4]; 3539 int index = (ALPHA_RANGE+1) + ( ( minAlpha - a ) * ALPHA_RANGE - half ) / delta; 3540 int c0 = a > bottom; 3541 int c1 = a < top; 3542 indexes[i] = ( index & -( c0 & c1 ) ) | ( c0 ^ 1 ); 3543 } 3544 3545 EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 3546 EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 3547 EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 3548 3549 EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 3550 EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 3551 EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 3552 3553 #else 3554 3555 ALIGN16( byte indexes[16] ); 3556 ALIGN16( byte alphas[8] ); 3557 3558 alphas[0] = maxAlpha; 3559 alphas[1] = minAlpha; 3560 alphas[2] = ( 6 * maxAlpha + 1 * minAlpha ) / ALPHA_RANGE; 3561 alphas[3] = ( 5 * maxAlpha + 2 * minAlpha ) / ALPHA_RANGE; 3562 alphas[4] = ( 4 * maxAlpha + 3 * minAlpha ) / ALPHA_RANGE; 3563 alphas[5] = ( 3 * maxAlpha + 4 * minAlpha ) / ALPHA_RANGE; 3564 alphas[6] = ( 2 * maxAlpha + 5 * minAlpha ) / ALPHA_RANGE; 3565 alphas[7] = ( 1 * maxAlpha + 6 * minAlpha ) / ALPHA_RANGE; 3566 3567 colorBlock += offset; 3568 3569 for ( int i = 0; i < 16; i++ ) { 3570 int minDist = INT_MAX; 3571 byte a = colorBlock[i*4]; 3572 for ( int j = 0; j < 8; j++ ) { 3573 int dist = abs( a - alphas[j] ); 3574 if ( dist < minDist ) { 3575 minDist = dist; 3576 indexes[i] = j; 3577 } 3578 } 3579 } 3580 3581 EmitByte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 3582 EmitByte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 3583 EmitByte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 3584 3585 EmitByte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 3586 EmitByte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 3587 EmitByte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 3588 3589 #endif 3590 } 3591 3592 /* 3593 ======================== 3594 idDxtEncoder::CompressImageDXT1Fast_Generic 3595 3596 params: inBuf - image to compress 3597 paramO: outBuf - result of compression 3598 params: width - width of image 3599 params: height - height of image 3600 ======================== 3601 */ 3602 void idDxtEncoder::CompressImageDXT1Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 3603 ALIGN16( byte block[64] ); 3604 ALIGN16( byte minColor[4] ); 3605 ALIGN16( byte maxColor[4] ); 3606 3607 assert( width >= 4 && ( width & 3 ) == 0 ); 3608 assert( height >= 4 && ( height & 3 ) == 0 ); 3609 3610 this->width = width; 3611 this->height = height; 3612 this->outData = outBuf; 3613 3614 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 3615 for ( int i = 0; i < width; i += 4 ) { 3616 3617 ExtractBlock( inBuf + i * 4, width, block ); 3618 3619 GetMinMaxBBox( block, minColor, maxColor ); 3620 //SelectColorsDiagonal( block, minColor, maxColor ); 3621 InsetColorsBBox( minColor, maxColor ); 3622 3623 EmitUShort( ColorTo565( maxColor ) ); 3624 EmitUShort( ColorTo565( minColor ) ); 3625 3626 EmitColorIndices( block, minColor, maxColor ); 3627 } 3628 outData += dstPadding; 3629 inBuf += srcPadding; 3630 } 3631 } 3632 3633 /* 3634 ======================== 3635 idDxtEncoder::CompressImageDXT1AlphaFast_Generic 3636 3637 params: inBuf - image to compress 3638 paramO: outBuf - result of compression 3639 params: width - width of image 3640 params: height - height of image 3641 ======================== 3642 */ 3643 void idDxtEncoder::CompressImageDXT1AlphaFast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 3644 ALIGN16( byte block[64] ); 3645 ALIGN16( byte minColor[4] ); 3646 ALIGN16( byte maxColor[4] ); 3647 3648 assert( width >= 4 && ( width & 3 ) == 0 ); 3649 assert( height >= 4 && ( height & 3 ) == 0 ); 3650 3651 this->width = width; 3652 this->height = height; 3653 this->outData = outBuf; 3654 3655 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 3656 for ( int i = 0; i < width; i += 4 ) { 3657 3658 ExtractBlock( inBuf + i * 4, width, block ); 3659 3660 GetMinMaxBBox( block, minColor, maxColor ); 3661 byte minAlpha = minColor[3]; 3662 //SelectColorsDiagonal( block, minColor, maxColor ); 3663 InsetColorsBBox( minColor, maxColor ); 3664 3665 if ( minAlpha >= 128 ) { 3666 EmitUShort( ColorTo565( maxColor ) ); 3667 EmitUShort( ColorTo565( minColor ) ); 3668 EmitColorIndices( block, minColor, maxColor ); 3669 } else { 3670 EmitUShort( ColorTo565( minColor ) ); 3671 EmitUShort( ColorTo565( maxColor ) ); 3672 EmitColorAlphaIndices( block, minColor, maxColor ); 3673 } 3674 } 3675 outData += dstPadding; 3676 inBuf += srcPadding; 3677 } 3678 } 3679 3680 /* 3681 ======================== 3682 idDxtEncoder::CompressImageDXT5Fast_Generic 3683 3684 params: inBuf - image to compress 3685 paramO: outBuf - result of compression 3686 params: width - width of image 3687 params: height - height of image 3688 ======================== 3689 */ 3690 void idDxtEncoder::CompressImageDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 3691 ALIGN16( byte block[64] ); 3692 ALIGN16( byte minColor[4] ); 3693 ALIGN16( byte maxColor[4] ); 3694 3695 assert( width >= 4 && ( width & 3 ) == 0 ); 3696 assert( height >= 4 && ( height & 3 ) == 0 ); 3697 3698 this->width = width; 3699 this->height = height; 3700 this->outData = outBuf; 3701 3702 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 3703 for ( int i = 0; i < width; i += 4 ) { 3704 3705 ExtractBlock( inBuf + i * 4, width, block ); 3706 3707 GetMinMaxBBox( block, minColor, maxColor ); 3708 //SelectColorsDiagonal( block, minColor, maxColor ); 3709 InsetColorsBBox( minColor, maxColor ); 3710 3711 EmitByte( maxColor[3] ); 3712 EmitByte( minColor[3] ); 3713 3714 EmitAlphaIndices( block, 3, minColor[3], maxColor[3] ); 3715 3716 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 3717 // the colors are already always guaranteed to be sorted properly 3718 #endif 3719 3720 EmitUShort( ColorTo565( maxColor ) ); 3721 EmitUShort( ColorTo565( minColor ) ); 3722 3723 EmitColorIndices( block, minColor, maxColor ); 3724 } 3725 outData += dstPadding; 3726 inBuf += srcPadding; 3727 } 3728 } 3729 3730 /* 3731 ======================== 3732 idDxtEncoder::ScaleYCoCg 3733 ======================== 3734 */ 3735 void idDxtEncoder::ScaleYCoCg( byte *colorBlock, byte *minColor, byte *maxColor ) const { 3736 int m0 = abs( minColor[0] - 128 ); 3737 int m1 = abs( minColor[1] - 128 ); 3738 int m2 = abs( maxColor[0] - 128 ); 3739 int m3 = abs( maxColor[1] - 128 ); 3740 3741 if ( m1 > m0 ) m0 = m1; 3742 if ( m3 > m2 ) m2 = m3; 3743 if ( m2 > m0 ) m0 = m2; 3744 3745 const int s0 = 128 / 2 - 1; 3746 const int s1 = 128 / 4 - 1; 3747 3748 int mask0 = -( m0 <= s0 ); 3749 int mask1 = -( m0 <= s1 ); 3750 int scale = 1 + ( 1 & mask0 ) + ( 2 & mask1 ); 3751 3752 minColor[0] = byte( ( minColor[0] - 128 ) * scale + 128 ); 3753 minColor[1] = byte( ( minColor[1] - 128 ) * scale + 128 ); 3754 minColor[2] = byte( ( scale - 1 ) << 3 ); 3755 maxColor[0] = byte( ( maxColor[0] - 128 ) * scale + 128 ); 3756 maxColor[1] = byte( ( maxColor[1] - 128 ) * scale + 128 ); 3757 maxColor[2] = byte( ( scale - 1 ) << 3 ); 3758 3759 for ( int i = 0; i < 16; i++ ) { 3760 colorBlock[i*4+0] = byte( ( colorBlock[i*4+0] - 128 ) * scale + 128 ); 3761 colorBlock[i*4+1] = byte( ( colorBlock[i*4+1] - 128 ) * scale + 128 ); 3762 } 3763 } 3764 3765 /* 3766 ======================== 3767 idDxtEncoder::InsetYCoCgBBox 3768 ======================== 3769 */ 3770 ID_INLINE void idDxtEncoder::InsetYCoCgBBox( byte *minColor, byte *maxColor ) const { 3771 3772 #if 0 3773 3774 byte inset[4]; 3775 3776 inset[0] = ( maxColor[0] - minColor[0] ) >> INSET_COLOR_SHIFT; 3777 inset[1] = ( maxColor[1] - minColor[1] ) >> INSET_COLOR_SHIFT; 3778 inset[3] = ( maxColor[3] - minColor[3] ) >> INSET_ALPHA_SHIFT; 3779 3780 minColor[0] = ( minColor[0] + inset[0] <= 255 ) ? minColor[0] + inset[0] : 255; 3781 minColor[1] = ( minColor[1] + inset[1] <= 255 ) ? minColor[1] + inset[1] : 255; 3782 minColor[3] = ( minColor[3] + inset[3] <= 255 ) ? minColor[3] + inset[3] : 255; 3783 3784 maxColor[0] = ( maxColor[0] >= inset[0] ) ? maxColor[0] - inset[0] : 0; 3785 maxColor[1] = ( maxColor[1] >= inset[1] ) ? maxColor[1] - inset[1] : 0; 3786 maxColor[3] = ( maxColor[3] >= inset[3] ) ? maxColor[3] - inset[3] : 0; 3787 3788 minColor[0] = ( minColor[0] & C565_5_MASK ) | ( minColor[0] >> 5 ); 3789 minColor[1] = ( minColor[1] & C565_6_MASK ) | ( minColor[1] >> 6 ); 3790 3791 maxColor[0] = ( maxColor[0] & C565_5_MASK ) | ( maxColor[0] >> 5 ); 3792 maxColor[1] = ( maxColor[1] & C565_6_MASK ) | ( maxColor[1] >> 6 ); 3793 3794 #elif 0 3795 3796 float inset[4]; 3797 float minf[4]; 3798 float maxf[4]; 3799 3800 for ( int i = 0; i < 4; i++ ) { 3801 minf[i] = minColor[i] / 255.0f; 3802 maxf[i] = maxColor[i] / 255.0f; 3803 } 3804 3805 inset[0] = ( maxf[0] - minf[0] ) / 16.0f; 3806 inset[1] = ( maxf[1] - minf[1] ) / 16.0f; 3807 inset[2] = ( maxf[2] - minf[2] ) / 16.0f; 3808 inset[3] = ( maxf[3] - minf[3] ) / 32.0f; 3809 3810 for ( int i = 0; i < 4; i++ ) { 3811 minf[i] = ( minf[i] + inset[i] <= 1.0f ) ? minf[i] + inset[i] : 1.0f; 3812 maxf[i] = ( maxf[i] >= inset[i] ) ? maxf[i] - inset[i] : 0; 3813 } 3814 3815 minColor[0] = ((int)floor( minf[0] * 31 )) & ( ( 1 << 5 ) - 1 ); 3816 minColor[1] = ((int)floor( minf[1] * 63 )) & ( ( 1 << 6 ) - 1 ); 3817 3818 maxColor[0] = ((int)ceil( maxf[0] * 31 )) & ( ( 1 << 5 ) - 1 ); 3819 maxColor[1] = ((int)ceil( maxf[1] * 63 )) & ( ( 1 << 6 ) - 1 ); 3820 3821 minColor[0] = ( minColor[0] << 3 ) | ( minColor[0] >> 2 ); 3822 minColor[1] = ( minColor[1] << 2 ) | ( minColor[1] >> 4 ); 3823 3824 maxColor[0] = ( maxColor[0] << 3 ) | ( maxColor[0] >> 2 ); 3825 maxColor[1] = ( maxColor[1] << 2 ) | ( maxColor[1] >> 4 ); 3826 3827 minColor[3] = (int)floor( minf[3] * 255.0f ); 3828 maxColor[3] = (int)ceil( maxf[3] * 255.0f ); 3829 3830 #elif 0 3831 3832 int inset[4]; 3833 int mini[4]; 3834 int maxi[4]; 3835 3836 inset[0] = ( maxColor[0] - minColor[0] ); 3837 inset[1] = ( maxColor[1] - minColor[1] ); 3838 inset[3] = ( maxColor[3] - minColor[3] ); 3839 3840 mini[0] = ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0]; 3841 mini[1] = ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1]; 3842 mini[3] = ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3]; 3843 3844 maxi[0] = ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0]; 3845 maxi[1] = ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1]; 3846 maxi[3] = ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3]; 3847 3848 mini[0] = ( mini[0] - ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+3); 3849 mini[1] = ( mini[1] - ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+2); 3850 mini[3] = ( mini[3] - ((1<<(2))-1) ) >> (INSET_ALPHA_SHIFT+0); 3851 3852 maxi[0] = ( maxi[0] + ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+3); 3853 maxi[1] = ( maxi[1] + ((1<<(3))-1) ) >> (INSET_COLOR_SHIFT+2); 3854 maxi[3] = ( maxi[3] + ((1<<(2))-1) ) >> (INSET_ALPHA_SHIFT+0); 3855 3856 if ( mini[0] < 0 ) mini[0] = 0; 3857 if ( mini[1] < 0 ) mini[1] = 0; 3858 if ( mini[3] < 0 ) mini[3] = 0; 3859 3860 if ( maxi[0] > 31 ) maxi[0] = 31; 3861 if ( maxi[1] > 63 ) maxi[1] = 63; 3862 if ( maxi[3] > 255 ) maxi[3] = 255; 3863 3864 minColor[0] = ( mini[0] << 3 ) | ( mini[0] >> 2 ); 3865 minColor[1] = ( mini[1] << 2 ) | ( mini[1] >> 4 ); 3866 minColor[3] = mini[3]; 3867 3868 maxColor[0] = ( maxi[0] << 3 ) | ( maxi[0] >> 2 ); 3869 maxColor[1] = ( maxi[1] << 2 ) | ( maxi[1] >> 4 ); 3870 maxColor[3] = maxi[3]; 3871 3872 #elif 1 3873 3874 int inset[4]; 3875 int mini[4]; 3876 int maxi[4]; 3877 3878 inset[0] = ( maxColor[0] - minColor[0] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 3879 inset[1] = ( maxColor[1] - minColor[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 3880 inset[3] = ( maxColor[3] - minColor[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1); 3881 3882 mini[0] = ( ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0] ) >> INSET_COLOR_SHIFT; 3883 mini[1] = ( ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT; 3884 mini[3] = ( ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT; 3885 3886 maxi[0] = ( ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0] ) >> INSET_COLOR_SHIFT; 3887 maxi[1] = ( ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT; 3888 maxi[3] = ( ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT; 3889 3890 mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0; 3891 mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0; 3892 mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0; 3893 3894 maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255; 3895 maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255; 3896 maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255; 3897 3898 minColor[0] = byte( ( mini[0] & C565_5_MASK ) | ( mini[0] >> 5 ) ); 3899 minColor[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) ); 3900 minColor[3] = byte( mini[3] ); 3901 3902 maxColor[0] = byte( ( maxi[0] & C565_5_MASK ) | ( maxi[0] >> 5 ) ); 3903 maxColor[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) ); 3904 maxColor[3] = byte( maxi[3] ); 3905 3906 #endif 3907 } 3908 3909 /* 3910 ======================== 3911 idDxtEncoder::InsetYCoCgAlpaBBox 3912 ======================== 3913 */ 3914 ID_INLINE void idDxtEncoder::InsetYCoCgAlpaBBox( byte *minColor, byte *maxColor ) const { 3915 int inset[4]; 3916 int mini[4]; 3917 int maxi[4]; 3918 3919 inset[0] = ( maxColor[0] - minColor[0] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 3920 inset[1] = ( maxColor[1] - minColor[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 3921 inset[2] = ( maxColor[2] - minColor[2] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 3922 inset[3] = ( maxColor[3] - minColor[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1); 3923 3924 mini[0] = ( ( minColor[0] << INSET_COLOR_SHIFT ) + inset[0] ) >> INSET_COLOR_SHIFT; 3925 mini[1] = ( ( minColor[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT; 3926 mini[2] = ( ( minColor[2] << INSET_COLOR_SHIFT ) + inset[2] ) >> INSET_COLOR_SHIFT; 3927 mini[3] = ( ( minColor[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT; 3928 3929 maxi[0] = ( ( maxColor[0] << INSET_COLOR_SHIFT ) - inset[0] ) >> INSET_COLOR_SHIFT; 3930 maxi[1] = ( ( maxColor[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT; 3931 maxi[2] = ( ( maxColor[2] << INSET_COLOR_SHIFT ) - inset[2] ) >> INSET_COLOR_SHIFT; 3932 maxi[3] = ( ( maxColor[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT; 3933 3934 mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0; 3935 mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0; 3936 mini[2] = ( mini[2] >= 0 ) ? mini[2] : 0; 3937 mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0; 3938 3939 maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255; 3940 maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255; 3941 maxi[2] = ( maxi[2] <= 255 ) ? maxi[2] : 255; 3942 maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255; 3943 3944 minColor[0] = byte( ( mini[0] & C565_5_MASK ) | ( mini[0] >> 5 ) ); 3945 minColor[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) ); 3946 minColor[2] = byte( ( mini[2] & C565_5_MASK ) | ( mini[2] >> 5 ) ); 3947 minColor[3] = byte( mini[3] ); 3948 3949 maxColor[0] = byte( ( maxi[0] & C565_5_MASK ) | ( maxi[0] >> 5 ) ); 3950 maxColor[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) ); 3951 maxColor[2] = byte( ( maxi[2] & C565_5_MASK ) | ( maxi[2] >> 5 ) ); 3952 maxColor[3] = byte( maxi[3] ); 3953 } 3954 3955 /* 3956 ======================== 3957 idDxtEncoder::SelectYCoCgDiagonal 3958 ======================== 3959 */ 3960 void idDxtEncoder::SelectYCoCgDiagonal( const byte *colorBlock, byte *minColor, byte *maxColor ) const { 3961 byte side = 0; 3962 3963 byte mid0 = byte( ( (int) minColor[0] + maxColor[0] + 1 ) >> 1 ); 3964 byte mid1 = byte( ( (int) minColor[1] + maxColor[1] + 1 ) >> 1 ); 3965 3966 for ( int i = 0; i < 16; i++ ) { 3967 byte b0 = colorBlock[i*4+0] >= mid0; 3968 byte b1 = colorBlock[i*4+1] >= mid1; 3969 side += ( b0 ^ b1 ); 3970 } 3971 3972 byte mask = -( side > 8 ); 3973 3974 #if defined NVIDIA_7X_HARDWARE_BUG_FIX 3975 mask &= -( minColor[0] != maxColor[0] ); 3976 #endif 3977 3978 byte c0 = minColor[1]; 3979 byte c1 = maxColor[1]; 3980 3981 c0 ^= c1; 3982 mask &= c0; 3983 c1 ^= mask; 3984 c0 ^= c1; 3985 3986 minColor[1] = c0; 3987 maxColor[1] = c1; 3988 } 3989 3990 /* 3991 ======================== 3992 idDxtEncoder::CompressYCoCgDXT5Fast_Generic 3993 3994 params: inBuf - image to compress 3995 paramO: outBuf - result of compression 3996 params: width - width of image 3997 params: height - height of image 3998 ======================== 3999 */ 4000 void idDxtEncoder::CompressYCoCgDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 4001 ALIGN16( byte block[64] ); 4002 ALIGN16( byte minColor[4] ); 4003 ALIGN16( byte maxColor[4] ); 4004 4005 //assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) ); 4006 4007 assert( width >= 4 && ( width & 3 ) == 0 ); 4008 assert( height >= 4 && ( height & 3 ) == 0 ); 4009 4010 this->width = width; 4011 this->height = height; 4012 this->outData = outBuf; 4013 4014 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4015 for ( int i = 0; i < width; i += 4 ) { 4016 4017 ExtractBlock( inBuf + i * 4, width, block ); 4018 4019 GetMinMaxBBox( block, minColor, maxColor ); 4020 ScaleYCoCg( block, minColor, maxColor ); 4021 InsetYCoCgBBox( minColor, maxColor ); 4022 SelectYCoCgDiagonal( block, minColor, maxColor ); 4023 4024 EmitByte( maxColor[3] ); 4025 EmitByte( minColor[3] ); 4026 4027 EmitAlphaIndices( block, 3, minColor[3], maxColor[3] ); 4028 4029 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 4030 // the colors are already sorted when selecting the diagonal 4031 #endif 4032 4033 EmitUShort( ColorTo565( maxColor ) ); 4034 EmitUShort( ColorTo565( minColor ) ); 4035 4036 EmitColorIndices( block, minColor, maxColor ); 4037 } 4038 outData += dstPadding; 4039 inBuf += srcPadding; 4040 } 4041 } 4042 4043 /* 4044 ======================== 4045 idDxtEncoder::CompressYCoCgAlphaDXT5Fast 4046 4047 params: inBuf - image to compress 4048 paramO: outBuf - result of compression 4049 params: width - width of image 4050 params: height - height of image 4051 ======================== 4052 */ 4053 void idDxtEncoder::CompressYCoCgAlphaDXT5Fast( const byte *inBuf, byte *outBuf, int width, int height ) { 4054 ALIGN16( byte block[64] ); 4055 ALIGN16( byte minColor[4] ); 4056 ALIGN16( byte maxColor[4] ); 4057 4058 assert( width >= 4 && ( width & 3 ) == 0 ); 4059 assert( height >= 4 && ( height & 3 ) == 0 ); 4060 4061 this->width = width; 4062 this->height = height; 4063 this->outData = outBuf; 4064 4065 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4066 for ( int i = 0; i < width; i += 4 ) { 4067 4068 ExtractBlock( inBuf + i * 4, width, block ); 4069 4070 // scale down the chroma of texels that are close to gray with low luminance 4071 for ( int k = 0; k < 16; k++ ) { 4072 if ( abs( block[k*4+0] - 132 ) <= 8 && 4073 abs( block[k*4+2] - 132 ) <= 8 && 4074 block[k*4+3] < 96 ) { 4075 block[k*4+0] = ( block[k*4+0] - 132 ) / 2 + 132; 4076 block[k*4+2] = ( block[k*4+2] - 132 ) / 2 + 132; 4077 } 4078 } 4079 4080 GetMinMaxBBox( block, minColor, maxColor ); 4081 InsetYCoCgAlpaBBox( minColor, maxColor ); 4082 SelectColorsDiagonal( block, minColor, maxColor ); 4083 4084 EmitByte( maxColor[3] ); 4085 EmitByte( minColor[3] ); 4086 4087 EmitAlphaIndices( block, 3, minColor[3], maxColor[3] ); 4088 4089 #ifdef NVIDIA_7X_HARDWARE_BUG_FIX 4090 // the colors are already sorted when selecting the diagonal 4091 #endif 4092 4093 EmitUShort( ColorTo565( maxColor ) ); 4094 EmitUShort( ColorTo565( minColor ) ); 4095 4096 EmitColorIndices( block, minColor, maxColor ); 4097 } 4098 outData += dstPadding; 4099 inBuf += srcPadding; 4100 } 4101 } 4102 4103 /* 4104 ======================== 4105 idDxtEncoder::CompressYCoCgCTX1DXT5AFast_Generic 4106 4107 params: inBuf - image to compress 4108 paramO: outBuf - result of compression 4109 params: width - width of image 4110 params: height - height of image 4111 ======================== 4112 */ 4113 void idDxtEncoder::CompressYCoCgCTX1DXT5AFast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 4114 ALIGN16( byte block[64] ); 4115 ALIGN16( byte minColor[4] ); 4116 ALIGN16( byte maxColor[4] ); 4117 4118 assert( HasConstantValuePer4x4Block( inBuf, width, height, 2 ) ); 4119 4120 assert( width >= 4 && ( width & 3 ) == 0 ); 4121 assert( height >= 4 && ( height & 3 ) == 0 ); 4122 4123 this->width = width; 4124 this->height = height; 4125 this->outData = outBuf; 4126 4127 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4128 for ( int i = 0; i < width; i += 4 ) { 4129 4130 ExtractBlock( inBuf + i * 4, width, block ); 4131 4132 GetMinMaxBBox( block, minColor, maxColor ); 4133 SelectYCoCgDiagonal( block, minColor, maxColor ); 4134 InsetColorsBBox( minColor, maxColor ); 4135 4136 EmitByte( maxColor[3] ); 4137 EmitByte( minColor[3] ); 4138 4139 EmitAlphaIndices( block, 3, minColor[3], maxColor[3] ); 4140 4141 EmitByte( maxColor[0] ); 4142 EmitByte( maxColor[1] ); 4143 EmitByte( minColor[0] ); 4144 EmitByte( minColor[1] ); 4145 4146 EmitCTX1Indices( block, minColor, maxColor ); 4147 } 4148 outData += dstPadding; 4149 inBuf += srcPadding; 4150 } 4151 } 4152 4153 /* 4154 ======================== 4155 idDxtEncoder::EmitGreenIndices 4156 4157 params: block - block for which to find green indices 4158 paramO: minGreen - Min green found 4159 paramO: maxGreen - Max green found 4160 ======================== 4161 */ 4162 void idDxtEncoder::EmitGreenIndices( const byte *block, const int offset, const byte minGreen, const byte maxGreen ) { 4163 4164 assert( maxGreen >= minGreen ); 4165 4166 const int COLOR_RANGE = 3; 4167 4168 #if 1 4169 4170 byte yb1 = ( 5 * maxGreen + 1 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE ); 4171 byte yb2 = ( 3 * maxGreen + 3 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE ); 4172 byte yb3 = ( 1 * maxGreen + 5 * minGreen + COLOR_RANGE ) / ( 2 * COLOR_RANGE ); 4173 4174 unsigned int result = 0; 4175 4176 block += offset; 4177 4178 for ( int i = 15; i >= 0; i-- ) { 4179 result <<= 2; 4180 byte y = block[i*4]; 4181 int b1 = ( y >= yb1 ); 4182 int b2 = ( y >= yb2 ); 4183 int b3 = ( y >= yb3 ); 4184 int index = ( 4 - b1 - b2 - b3 ) & 3; 4185 index ^= ( 2 > index ); 4186 result |= index; 4187 } 4188 4189 EmitUInt( result ); 4190 4191 #else 4192 4193 byte green[4]; 4194 4195 green[0] = maxGreen; 4196 green[1] = minGreen; 4197 green[2] = ( 2 * green[0] + 1 * green[1] ) / 3; 4198 green[3] = ( 1 * green[0] + 2 * green[1] ) / 3; 4199 4200 unsigned int result = 0; 4201 4202 block += offset; 4203 4204 for ( int i = 15; i >= 0; i-- ) { 4205 result <<= 2; 4206 byte y = block[i*4]; 4207 int minDist = INT_MAX; 4208 int index; 4209 for ( int j = 0; j < 4; j++ ) { 4210 int dist = abs( y - green[j] ); 4211 if ( dist < minDist ) { 4212 minDist = dist; 4213 index = j; 4214 } 4215 } 4216 result |= index; 4217 } 4218 4219 EmitUInt( result ); 4220 4221 #endif 4222 } 4223 4224 /* 4225 ======================== 4226 idDxtEncoder::InsetNormalsBBoxDXT5 4227 ======================== 4228 */ 4229 void idDxtEncoder::InsetNormalsBBoxDXT5( byte *minNormal, byte *maxNormal ) const { 4230 int inset[4]; 4231 int mini[4]; 4232 int maxi[4]; 4233 4234 inset[3] = ( maxNormal[3] - minNormal[3] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1); 4235 inset[1] = ( maxNormal[1] - minNormal[1] ) - ((1<<(INSET_COLOR_SHIFT-1))-1); 4236 4237 mini[3] = ( ( minNormal[3] << INSET_ALPHA_SHIFT ) + inset[3] ) >> INSET_ALPHA_SHIFT; 4238 mini[1] = ( ( minNormal[1] << INSET_COLOR_SHIFT ) + inset[1] ) >> INSET_COLOR_SHIFT; 4239 4240 maxi[3] = ( ( maxNormal[3] << INSET_ALPHA_SHIFT ) - inset[3] ) >> INSET_ALPHA_SHIFT; 4241 maxi[1] = ( ( maxNormal[1] << INSET_COLOR_SHIFT ) - inset[1] ) >> INSET_COLOR_SHIFT; 4242 4243 mini[3] = ( mini[3] >= 0 ) ? mini[3] : 0; 4244 mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0; 4245 4246 maxi[3] = ( maxi[3] <= 255 ) ? maxi[3] : 255; 4247 maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255; 4248 4249 minNormal[3] = byte( mini[3] ); 4250 minNormal[1] = byte( ( mini[1] & C565_6_MASK ) | ( mini[1] >> 6 ) ); 4251 4252 maxNormal[3] = byte( maxi[3] ); 4253 maxNormal[1] = byte( ( maxi[1] & C565_6_MASK ) | ( maxi[1] >> 6 ) ); 4254 } 4255 4256 /* 4257 ======================== 4258 idDxtEncoder::InsetNormalsBBox3Dc 4259 ======================== 4260 */ 4261 void idDxtEncoder::InsetNormalsBBox3Dc( byte *minNormal, byte *maxNormal ) const { 4262 int inset[4]; 4263 int mini[4]; 4264 int maxi[4]; 4265 4266 inset[0] = ( maxNormal[0] - minNormal[0] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1); 4267 inset[1] = ( maxNormal[1] - minNormal[1] ) - ((1<<(INSET_ALPHA_SHIFT-1))-1); 4268 4269 mini[0] = ( ( minNormal[0] << INSET_ALPHA_SHIFT ) + inset[0] ) >> INSET_ALPHA_SHIFT; 4270 mini[1] = ( ( minNormal[1] << INSET_ALPHA_SHIFT ) + inset[1] ) >> INSET_ALPHA_SHIFT; 4271 4272 maxi[0] = ( ( maxNormal[0] << INSET_ALPHA_SHIFT ) - inset[0] ) >> INSET_ALPHA_SHIFT; 4273 maxi[1] = ( ( maxNormal[1] << INSET_ALPHA_SHIFT ) - inset[1] ) >> INSET_ALPHA_SHIFT; 4274 4275 mini[0] = ( mini[0] >= 0 ) ? mini[0] : 0; 4276 mini[1] = ( mini[1] >= 0 ) ? mini[1] : 0; 4277 4278 maxi[0] = ( maxi[0] <= 255 ) ? maxi[0] : 255; 4279 maxi[1] = ( maxi[1] <= 255 ) ? maxi[1] : 255; 4280 4281 minNormal[0] = (byte)mini[0]; 4282 minNormal[1] = (byte)mini[1]; 4283 4284 maxNormal[0] = (byte)maxi[0]; 4285 maxNormal[1] = (byte)maxi[1]; 4286 } 4287 4288 /* 4289 ======================== 4290 idDxtEncoder::CompressNormalMapDXT5Fast_Generic 4291 4292 params: inBuf - image to compress 4293 paramO: outBuf - result of compression 4294 params: width - width of image 4295 params: height - height of image 4296 ======================== 4297 */ 4298 void idDxtEncoder::CompressNormalMapDXT5Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 4299 ALIGN16( byte block[64] ); 4300 ALIGN16( byte normal1[4] ); 4301 ALIGN16( byte normal2[4] ); 4302 4303 assert( width >= 4 && ( width & 3 ) == 0 ); 4304 assert( height >= 4 && ( height & 3 ) == 0 ); 4305 4306 this->width = width; 4307 this->height = height; 4308 this->outData = outBuf; 4309 4310 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4311 for ( int i = 0; i < width; i += 4 ) { 4312 4313 ExtractBlock( inBuf + i * 4, width, block ); 4314 4315 GetMinMaxBBox( block, normal1, normal2 ); 4316 InsetNormalsBBoxDXT5( normal1, normal2 ); 4317 4318 // Write out Nx into alpha channel. 4319 EmitByte( normal2[3] ); 4320 EmitByte( normal1[3] ); 4321 EmitAlphaIndices( block, 3, normal1[3], normal2[3] ); 4322 4323 // Write out Ny into green channel. 4324 EmitUShort( ColorTo565( block[0], normal2[1], block[2] ) ); 4325 EmitUShort( ColorTo565( block[0], normal1[1], block[2] ) ); 4326 EmitGreenIndices( block, 1, normal1[1], normal2[1] ); 4327 } 4328 outData += dstPadding; 4329 inBuf += srcPadding; 4330 } 4331 } 4332 4333 /* 4334 ======================== 4335 idDxtEncoder::CompressImageDXN1Fast_Generic 4336 4337 params: inBuf - image to compress 4338 paramO: outBuf - result of compression 4339 params: width - width of image 4340 params: height - height of image 4341 ======================== 4342 */ 4343 void idDxtEncoder::CompressImageDXN1Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 4344 ALIGN16( byte block[64] ); 4345 ALIGN16( byte min[4] ); 4346 ALIGN16( byte max[4] ); 4347 4348 assert( width >= 4 && ( width & 3 ) == 0 ); 4349 assert( height >= 4 && ( height & 3 ) == 0 ); 4350 4351 this->width = width; 4352 this->height = height; 4353 this->outData = outBuf; 4354 4355 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4356 for ( int i = 0; i < width; i += 4 ) { 4357 4358 ExtractBlock( inBuf + i * 4, width, block ); 4359 4360 GetMinMaxBBox( block, min, max ); 4361 InsetNormalsBBox3Dc( min, max ); 4362 4363 // Write out an alpha channel. 4364 EmitByte( max[0] ); 4365 EmitByte( min[0] ); 4366 EmitAlphaIndices( block, 0, min[0], max[0] ); 4367 } 4368 outData += dstPadding; 4369 inBuf += srcPadding; 4370 } 4371 } 4372 4373 /* 4374 ======================== 4375 idDxtEncoder::CompressNormalMapDXN2Fast_Generic 4376 4377 params: inBuf - image to compress 4378 paramO: outBuf - result of compression 4379 params: width - width of image 4380 params: height - height of image 4381 ======================== 4382 */ 4383 void idDxtEncoder::CompressNormalMapDXN2Fast_Generic( const byte *inBuf, byte *outBuf, int width, int height ) { 4384 ALIGN16( byte block[64] ); 4385 ALIGN16( byte normal1[4] ); 4386 ALIGN16( byte normal2[4] ); 4387 4388 assert( width >= 4 && ( width & 3 ) == 0 ); 4389 assert( height >= 4 && ( height & 3 ) == 0 ); 4390 4391 this->width = width; 4392 this->height = height; 4393 this->outData = outBuf; 4394 4395 for ( int j = 0; j < height; j += 4, inBuf += width * 4*4 ) { 4396 for ( int i = 0; i < width; i += 4 ) { 4397 4398 ExtractBlock( inBuf + i * 4, width, block ); 4399 4400 GetMinMaxBBox( block, normal1, normal2 ); 4401 InsetNormalsBBox3Dc( normal1, normal2 ); 4402 4403 // Write out Nx as an alpha channel. 4404 EmitByte( normal2[0] ); 4405 EmitByte( normal1[0] ); 4406 EmitAlphaIndices( block, 0, normal1[0], normal2[0] ); 4407 4408 // Write out Ny as an alpha channel. 4409 EmitByte( normal2[1] ); 4410 EmitByte( normal1[1] ); 4411 EmitAlphaIndices( block, 1, normal1[1], normal2[1] ); 4412 } 4413 outData += dstPadding; 4414 inBuf += srcPadding; 4415 } 4416 } 4417 4418 /* 4419 ======================== 4420 idDxtEncoder::DecodeDXNAlphaValues 4421 ======================== 4422 */ 4423 void idDxtEncoder::DecodeDXNAlphaValues( const byte *inBuf, byte *values ) { 4424 int i; 4425 unsigned int indices; 4426 byte alphas[8]; 4427 4428 if ( inBuf[0] <= inBuf[1] ) { 4429 alphas[0] = inBuf[0]; 4430 alphas[1] = inBuf[1]; 4431 alphas[2] = ( 4 * alphas[0] + 1 * alphas[1] ) / 5; 4432 alphas[3] = ( 3 * alphas[0] + 2 * alphas[1] ) / 5; 4433 alphas[4] = ( 2 * alphas[0] + 3 * alphas[1] ) / 5; 4434 alphas[5] = ( 1 * alphas[0] + 4 * alphas[1] ) / 5; 4435 alphas[6] = 0; 4436 alphas[7] = 255; 4437 } else { 4438 alphas[0] = inBuf[0]; 4439 alphas[1] = inBuf[1]; 4440 alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7; 4441 alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7; 4442 alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7; 4443 alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7; 4444 alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7; 4445 alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7; 4446 } 4447 4448 indices = (int)inBuf[2] | ( (int)inBuf[3] << 8 ) | ( (int)inBuf[4] << 16 ); 4449 for ( i = 0; i < 8; i++ ) { 4450 values[i] = alphas[indices & 7]; 4451 indices >>= 3; 4452 } 4453 4454 indices = (int)inBuf[5] | ( (int)inBuf[6] << 8 ) | ( (int)inBuf[7] << 16 ); 4455 for ( i = 8; i < 16; i++ ) { 4456 values[i] = alphas[indices & 7]; 4457 indices >>= 3; 4458 } 4459 } 4460 4461 /* 4462 ======================== 4463 idDxtEncoder::EncodeNormalRGBIndices 4464 4465 params: values - 16 normal block for which to find normal Y indices 4466 paramO: min - Min grayscale value 4467 paramO: max - Max grayscale value 4468 ======================== 4469 */ 4470 void idDxtEncoder::EncodeNormalRGBIndices( byte *outBuf, const byte min, const byte max, const byte *values ) { 4471 4472 const int COLOR_RANGE = 3; 4473 4474 byte maskedMin, maskedMax, mid, yb1, yb2, yb3; 4475 4476 maskedMax = max & C565_6_MASK; 4477 maskedMin = min & C565_6_MASK; 4478 mid = ( maskedMax - maskedMin ) / ( 2 * COLOR_RANGE ); 4479 4480 yb1 = maskedMax - mid; 4481 yb2 = ( 2 * maskedMax + 1 * maskedMin ) / COLOR_RANGE - mid; 4482 yb3 = ( 1 * maskedMax + 2 * maskedMin ) / COLOR_RANGE - mid; 4483 4484 unsigned int result = 0; 4485 4486 for ( int i = 15; i >= 0; i-- ) { 4487 result <<= 2; 4488 byte y = values[i]; 4489 int b1 = ( y >= yb1 ); 4490 int b2 = ( y >= yb2 ); 4491 int b3 = ( y >= yb3 ); 4492 int index = ( 4 - b1 - b2 - b3 ) & 3; 4493 index ^= ( 2 > index ); 4494 result |= index; 4495 } 4496 4497 unsigned short maskedMax5 = (max & C565_5_MASK) >> 3; 4498 unsigned short maskedMin5 = (min & C565_5_MASK) >> 3; 4499 4500 unsigned short smax = (maskedMax5 << 11) | (maskedMax << 3) | maskedMax5; 4501 unsigned short smin = (maskedMin5 << 11) | (maskedMin << 3) | maskedMin5; 4502 4503 outBuf[0] = byte( ( smax >> 0 ) & 0xFF ); 4504 outBuf[1] = byte( ( smax >> 8 ) & 0xFF ); 4505 outBuf[2] = byte( ( smin >> 0 ) & 0xFF ); 4506 outBuf[3] = byte( ( smin >> 8 ) & 0xFF ); 4507 4508 outBuf[4] = byte( ( result >> 0 ) & 0xFF ); 4509 outBuf[5] = byte( ( result >> 8 ) & 0xFF ); 4510 outBuf[6] = byte( ( result >> 16 ) & 0xFF ); 4511 outBuf[7] = byte( ( result >> 24 ) & 0xFF ); 4512 } 4513 4514 /* 4515 ======================== 4516 idDxtEncoder::ConvertNormalMapDXN2_DXT5 4517 4518 params: inBuf - normal map compressed in DXN2 format 4519 paramO: outBuf - result of compression in DXT5 format 4520 params: width - width of image 4521 params: height - height of image 4522 ======================== 4523 */ 4524 void idDxtEncoder::ConvertNormalMapDXN2_DXT5( const byte *inBuf, byte *outBuf, int width, int height ) { 4525 ALIGN16( byte values[16] ); 4526 4527 this->width = width; 4528 this->height = height; 4529 this->outData = outBuf; 4530 4531 if ( width > 4 && ( width & 3 ) != 0 ) { 4532 return; 4533 } 4534 if ( height > 4 && ( height & 3 ) != 0 ) { 4535 return; 4536 } 4537 4538 if ( width < 4 || height < 4 ) { 4539 assert( 0 ); 4540 return; 4541 } 4542 4543 for ( int j = 0; j < height; j += 4 ) { 4544 for ( int i = 0; i < width; i += 4, inBuf += 16, outBuf += 16 ) { 4545 4546 // decode normal Y stored as a DXT5 alpha channel 4547 DecodeDXNAlphaValues( inBuf + 0, values ); 4548 4549 // copy normal X 4550 memcpy( outBuf + 0, inBuf + 8, 8 ); 4551 4552 // get the min/max Y 4553 byte minNormalY = 255; 4554 byte maxNormalY = 0; 4555 for ( int i = 0; i < 16; i++ ) { 4556 if ( values[i] < minNormalY ) { 4557 minNormalY = values[i]; 4558 } 4559 if ( values[i] > maxNormalY ) { 4560 maxNormalY = values[i]; 4561 } 4562 } 4563 4564 // encode normal Y into DXT5 color channels 4565 EncodeNormalRGBIndices( outBuf + 8, minNormalY, maxNormalY, values ); 4566 } 4567 outData += dstPadding; 4568 inBuf += srcPadding; 4569 } 4570 } 4571 4572 /* 4573 ======================== 4574 idDxtEncoder::DecodeNormalYValues 4575 ======================== 4576 */ 4577 void idDxtEncoder::DecodeNormalYValues( const byte *inBuf, byte &min, byte &max, byte *values ) { 4578 int i; 4579 unsigned int indexes; 4580 unsigned short normal0, normal1; 4581 byte normalsY[4]; 4582 4583 normal0 = inBuf[0] | (inBuf[1] << 8); 4584 normal1 = inBuf[2] | (inBuf[3] << 8); 4585 4586 assert( normal0 >= normal1 ); 4587 4588 normalsY[0] = GreenFrom565( normal0 ); 4589 normalsY[1] = GreenFrom565( normal1 ); 4590 normalsY[2] = ( 2 * normalsY[0] + 1 * normalsY[1] ) / 3; 4591 normalsY[3] = ( 1 * normalsY[0] + 2 * normalsY[1] ) / 3; 4592 4593 indexes = (unsigned int)inBuf[4] | ((unsigned int)inBuf[5]<<8) | ((unsigned int)inBuf[6]<<16) | ((unsigned int)inBuf[7]<<24); 4594 for ( i = 0; i < 16; i++ ) { 4595 values[i] = normalsY[indexes & 3]; 4596 indexes >>= 2; 4597 } 4598 4599 max = normalsY[0]; 4600 min = normalsY[1]; 4601 } 4602 4603 /* 4604 ======================== 4605 idDxtEncoder::EncodeDXNAlphaValues 4606 ======================== 4607 */ 4608 void idDxtEncoder::EncodeDXNAlphaValues( byte *outBuf, const byte min, const byte max, const byte *values ) { 4609 int i; 4610 byte alphas[8]; 4611 int j; 4612 unsigned int indexes[16]; 4613 4614 alphas[0] = max; 4615 alphas[1] = min; 4616 alphas[2] = ( 6 * alphas[0] + 1 * alphas[1] ) / 7; 4617 alphas[3] = ( 5 * alphas[0] + 2 * alphas[1] ) / 7; 4618 alphas[4] = ( 4 * alphas[0] + 3 * alphas[1] ) / 7; 4619 alphas[5] = ( 3 * alphas[0] + 4 * alphas[1] ) / 7; 4620 alphas[6] = ( 2 * alphas[0] + 5 * alphas[1] ) / 7; 4621 alphas[7] = ( 1 * alphas[0] + 6 * alphas[1] ) / 7; 4622 4623 int error = 0; 4624 for ( i = 0; i < 16; i++ ) { 4625 int minDist = MAX_TYPE( int ); 4626 byte a = values[i]; 4627 for ( j = 0; j < 8; j++ ) { 4628 int dist = AlphaDistance( a, alphas[j] ); 4629 if ( dist < minDist ) { 4630 minDist = dist; 4631 indexes[i] = j; 4632 } 4633 } 4634 error += minDist; 4635 } 4636 4637 outBuf[0] = max; 4638 outBuf[1] = min; 4639 4640 outBuf[2] = byte( (indexes[ 0] >> 0) | (indexes[ 1] << 3) | (indexes[ 2] << 6) ); 4641 outBuf[3] = byte( (indexes[ 2] >> 2) | (indexes[ 3] << 1) | (indexes[ 4] << 4) | (indexes[ 5] << 7) ); 4642 outBuf[4] = byte( (indexes[ 5] >> 1) | (indexes[ 6] << 2) | (indexes[ 7] << 5) ); 4643 4644 outBuf[5] = byte( (indexes[ 8] >> 0) | (indexes[ 9] << 3) | (indexes[10] << 6) ); 4645 outBuf[6] = byte( (indexes[10] >> 2) | (indexes[11] << 1) | (indexes[12] << 4) | (indexes[13] << 7) ); 4646 outBuf[7] = byte( (indexes[13] >> 1) | (indexes[14] << 2) | (indexes[15] << 5) ); 4647 } 4648 4649 /* 4650 ======================== 4651 idDxtEncoder::ConvertNormalMapDXT5_DXN2 4652 4653 params: inBuf - image to compress 4654 paramO: outBuf - result of compression 4655 params: width - width of image 4656 params: height - height of image 4657 ======================== 4658 */ 4659 void idDxtEncoder::ConvertNormalMapDXT5_DXN2( const byte *inBuf, byte *outBuf, int width, int height ) { 4660 ALIGN16( byte values[16] ); 4661 byte minNormalY, maxNormalY; 4662 4663 this->width = width; 4664 this->height = height; 4665 this->outData = outBuf; 4666 4667 if ( width > 4 && ( width & 3 ) != 0 ) { 4668 return; 4669 } 4670 if ( height > 4 && ( height & 3 ) != 0 ) { 4671 return; 4672 } 4673 4674 if ( width < 4 || height < 4 ) { 4675 assert( 0 ); 4676 return; 4677 } 4678 4679 for ( int j = 0; j < height; j += 4 ) { 4680 for ( int i = 0; i < width; i += 4, inBuf += 16, outBuf += 16 ) { 4681 4682 // decode normal Y stored as a DXT5 alpha channel 4683 DecodeNormalYValues( inBuf + 8, minNormalY, maxNormalY, values ); 4684 4685 memcpy( outBuf + 8, inBuf + 0, 8 ); 4686 4687 // encode normal Y into DXT5 green channel 4688 EncodeDXNAlphaValues( outBuf + 0, minNormalY, maxNormalY, values ); 4689 } 4690 outData += dstPadding; 4691 inBuf += srcPadding; 4692 } 4693 } 4694 4695 /* 4696 ======================== 4697 idDxtEncoder::ConvertImageDXN1_DXT1 4698 4699 params: inBuf - normal map compressed in DXN1 format 4700 paramO: outBuf - result of compression in DXT1 format 4701 params: width - width of image 4702 params: height - height of image 4703 ======================== 4704 */ 4705 void idDxtEncoder::ConvertImageDXN1_DXT1( const byte *inBuf, byte *outBuf, int width, int height ) { 4706 ALIGN16( byte values[16] ); 4707 4708 this->width = width; 4709 this->height = height; 4710 this->outData = outBuf; 4711 4712 if ( width > 4 && ( width & 3 ) != 0 ) { 4713 return; 4714 } 4715 if ( height > 4 && ( height & 3 ) != 0 ) { 4716 return; 4717 } 4718 4719 if ( width < 4 || height < 4 ) { 4720 assert( 0 ); 4721 return; 4722 } 4723 4724 for ( int j = 0; j < height; j += 4 ) { 4725 for ( int i = 0; i < width; i += 4, inBuf += 8, outBuf += 8 ) { 4726 4727 // decode single channel stored as a DXT5 alpha channel 4728 DecodeDXNAlphaValues( inBuf + 0, values ); 4729 4730 // get the min/max 4731 byte min = 255; 4732 byte max = 0; 4733 for ( int i = 0; i < 16; i++ ) { 4734 if ( values[i] < min ) { 4735 min = values[i]; 4736 } 4737 if ( values[i] > max ) { 4738 max = values[i]; 4739 } 4740 } 4741 4742 // encode single channel into DXT1 4743 EncodeNormalRGBIndices( outBuf + 0, min, max, values ); 4744 } 4745 outData += dstPadding; 4746 inBuf += srcPadding; 4747 } 4748 }