1 // DDS decoders 2 // Based on code from Nvidia's DDS example: 3 // http://www.nvidia.com/object/dxtc_decompression_code.html 4 // 5 // Copyright (c) 2003 Randy Reddig 6 // All rights reserved. 7 // 8 // Redistribution and use in source and binary forms, with or without modification, 9 // are permitted provided that the following conditions are met: 10 // 11 // Redistributions of source code must retain the above copyright notice, this list 12 // of conditions and the following disclaimer. 13 // 14 // Redistributions in binary form must reproduce the above copyright notice, this 15 // list of conditions and the following disclaimer in the documentation and/or 16 // other materials provided with the distribution. 17 // 18 // Neither the names of the copyright holders nor the names of its contributors may 19 // be used to endorse or promote products derived from this software without 20 // specific prior written permission. 21 // 22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 23 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 25 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 // ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 27 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 29 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 31 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 // 33 // D port and further changes by Ketmar // Invisible Vector 34 module arsd.dds; 35 36 import arsd.color : Color, TrueColorImage; 37 38 39 // ////////////////////////////////////////////////////////////////////////// // 40 public bool ddsDetect (const(void)[] buf, int* width=null, int* height=null) nothrow @trusted @nogc { 41 if (buf.length < 128) return false; 42 auto data = cast(const(ubyte)[])buf; 43 44 uint getUInt (uint ofs) nothrow @trusted @nogc { 45 if (ofs >= data.length) return uint.max; 46 if (data.length-ofs < 4) return uint.max; 47 return data.ptr[ofs]|(data.ptr[ofs+1]<<8)|(data.ptr[ofs+2]<<16)|(data.ptr[ofs+3]<<24); 48 } 49 50 // signature 51 if (data.ptr[0] != 'D' || data.ptr[1] != 'D' || data.ptr[2] != 'S' || data.ptr[3] != ' ') return false; 52 // header size check 53 if (getUInt(4) != 124) return false; 54 55 int w = getUInt(4*4); 56 int h = getUInt(3*4); 57 // arbitrary limits 58 if (w < 1 || h < 1 || w > 65500 || h > 65500) return false; 59 if (width !is null) *width = w; 60 if (height !is null) *height = h; 61 62 // check pixel format 63 if (getUInt(76) < 8) return false; // size 64 immutable flags = getUInt(80); 65 if (flags&DDS_FOURCC) { 66 // DXTn 67 if (data.ptr[84+0] != 'D' || data.ptr[84+1] != 'X' || data.ptr[84+2] != 'T') return false; 68 if (data.ptr[84+3] < '1' || data.ptr[84+3] > '5') return false; 69 } else if (flags == DDS_RGB || flags == DDS_RGBA) { 70 immutable bitcount = getUInt(88); 71 if (bitcount != 24 && bitcount != 32) return false; 72 // ARGB8888 73 //if (data.ptr[84+0] == 0 || data.ptr[84+1] == 0 || data.ptr[84+2] == 0 || data.ptr[84+3] == 0) return true; 74 } 75 return true; 76 } 77 78 79 // ////////////////////////////////////////////////////////////////////////// // 80 public TrueColorImage ddsLoadFromMemory (const(void)[] buf) { 81 int w, h; 82 if (!ddsDetect(buf, &w, &h)) throw new Exception("not a DDS image"); 83 84 //FIXME: check for OOB access in decoders 85 const(ddsBuffer_t)* dds = cast(const(ddsBuffer_t)*)buf.ptr; 86 87 auto tc = new TrueColorImage(w, h); 88 scope(failure) .destroy(tc); 89 90 if (!DDSDecompress(dds, tc.imageData.colors)) throw new Exception("invalid dds image"); 91 92 return tc; 93 } 94 95 96 static import std.stdio; 97 public TrueColorImage ddsLoadFromFile() (std.stdio.File fl) { 98 import core.stdc.stdlib : malloc, free; 99 auto fsize = fl.size-fl.tell; 100 if (fsize < 128 || fsize > int.max/8) throw new Exception("invalid dds size"); 101 ddsBuffer_t* dds = cast(ddsBuffer_t*)malloc(cast(uint)fsize); 102 if (dds is null) throw new Exception("out of memory"); 103 scope(exit) free(dds); 104 ubyte[] lb = (cast(ubyte*)dds)[0..cast(uint)fsize]; 105 while (lb.length > 0) { 106 auto rd = fl.rawRead(lb[]); 107 if (rd.length < 1) throw new Exception("read error"); 108 lb = lb[rd.length..$]; 109 } 110 return ddsLoadFromMemory((cast(ubyte*)dds)[0..cast(uint)fsize]); 111 } 112 113 114 static if (__traits(compiles, { import iv.vfs; })) { 115 import iv.vfs; 116 public TrueColorImage ddsLoadFromFile() (VFile fl) { 117 import core.stdc.stdlib : malloc, free; 118 auto fsize = fl.size-fl.tell; 119 if (fsize < 128 || fsize > int.max/8) throw new Exception("invalid dds size"); 120 ddsBuffer_t* dds = cast(ddsBuffer_t*)malloc(cast(uint)fsize); 121 if (dds is null) throw new Exception("out of memory"); 122 scope(exit) free(dds); 123 ubyte[] lb = (cast(ubyte*)dds)[0..cast(uint)fsize]; 124 fl.rawReadExact(lb); 125 return ddsLoadFromMemory(lb); 126 } 127 } 128 129 130 131 // ////////////////////////////////////////////////////////////////////////// // 132 private nothrow @trusted @nogc: 133 134 // dds definition 135 enum DDSPixelFormat { 136 Unknown, 137 RGB888, 138 ARGB8888, 139 DXT1, 140 DXT2, 141 DXT3, 142 DXT4, 143 DXT5, 144 } 145 146 147 // 16bpp stuff 148 enum DDS_LOW_5 = 0x001F; 149 enum DDS_MID_6 = 0x07E0; 150 enum DDS_HIGH_5 = 0xF800; 151 enum DDS_MID_555 = 0x03E0; 152 enum DDS_HI_555 = 0x7C00; 153 154 enum DDS_FOURCC = 0x00000004U; 155 enum DDS_RGB = 0x00000040U; 156 enum DDS_RGBA = 0x00000041U; 157 enum DDS_DEPTH = 0x00800000U; 158 159 enum DDS_COMPLEX = 0x00000008U; 160 enum DDS_CUBEMAP = 0x00000200U; 161 enum DDS_VOLUME = 0x00200000U; 162 163 164 // structures 165 align(1) struct ddsColorKey_t { 166 align(1): 167 uint colorSpaceLowValue; 168 uint colorSpaceHighValue; 169 } 170 171 172 align(1) struct ddsCaps_t { 173 align(1): 174 uint caps1; 175 uint caps2; 176 uint caps3; 177 uint caps4; 178 } 179 180 181 align(1) struct ddsMultiSampleCaps_t { 182 align(1): 183 ushort flipMSTypes; 184 ushort bltMSTypes; 185 } 186 187 188 align(1) struct ddsPixelFormat_t { 189 align(1): 190 uint size; 191 uint flags; 192 char[4] fourCC; 193 union { 194 uint rgbBitCount; 195 uint yuvBitCount; 196 uint zBufferBitDepth; 197 uint alphaBitDepth; 198 uint luminanceBitCount; 199 uint bumpBitCount; 200 uint privateFormatBitCount; 201 } 202 union { 203 uint rBitMask; 204 uint yBitMask; 205 uint stencilBitDepth; 206 uint luminanceBitMask; 207 uint bumpDuBitMask; 208 uint operations; 209 } 210 union { 211 uint gBitMask; 212 uint uBitMask; 213 uint zBitMask; 214 uint bumpDvBitMask; 215 ddsMultiSampleCaps_t multiSampleCaps; 216 } 217 union { 218 uint bBitMask; 219 uint vBitMask; 220 uint stencilBitMask; 221 uint bumpLuminanceBitMask; 222 } 223 union { 224 uint rgbAlphaBitMask; 225 uint yuvAlphaBitMask; 226 uint luminanceAlphaBitMask; 227 uint rgbZBitMask; 228 uint yuvZBitMask; 229 } 230 } 231 //pragma(msg, ddsPixelFormat_t.sizeof); 232 233 234 align(1) struct ddsBuffer_t { 235 align(1): 236 // magic: 'dds ' 237 char[4] magic; 238 239 // directdraw surface 240 uint size; 241 uint flags; 242 uint height; 243 uint width; 244 union { 245 int pitch; 246 uint linearSize; 247 } 248 uint backBufferCount; 249 union { 250 uint mipMapCount; 251 uint refreshRate; 252 uint srcVBHandle; 253 } 254 uint alphaBitDepth; 255 uint reserved; 256 void* surface; 257 union { 258 ddsColorKey_t ckDestOverlay; 259 uint emptyFaceColor; 260 } 261 ddsColorKey_t ckDestBlt; 262 ddsColorKey_t ckSrcOverlay; 263 ddsColorKey_t ckSrcBlt; 264 union { 265 ddsPixelFormat_t pixelFormat; 266 uint fvf; 267 } 268 ddsCaps_t ddsCaps; 269 uint textureStage; 270 271 // data (Varying size) 272 ubyte[0] data; 273 } 274 //pragma(msg, ddsBuffer_t.sizeof); 275 //pragma(msg, ddsBuffer_t.pixelFormat.offsetof+4*2); 276 277 278 align(1) struct ddsColorBlock_t { 279 align(1): 280 ushort[2] colors; 281 ubyte[4] row; 282 } 283 static assert(ddsColorBlock_t.sizeof == 8); 284 285 286 align(1) struct ddsAlphaBlockExplicit_t { 287 align(1): 288 ushort[4] row; 289 } 290 static assert(ddsAlphaBlockExplicit_t.sizeof == 8); 291 292 293 align(1) struct ddsAlphaBlock3BitLinear_t { 294 align(1): 295 ubyte alpha0; 296 ubyte alpha1; 297 ubyte[6] stuff; 298 } 299 static assert(ddsAlphaBlock3BitLinear_t.sizeof == 8); 300 301 302 // ////////////////////////////////////////////////////////////////////////// // 303 //public int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, DDSPixelFormat *pf ); 304 //public int DDSDecompress( ddsBuffer_t *dds, ubyte *pixels ); 305 306 // extracts relevant info from a dds texture, returns `true` on success 307 /*public*/ bool DDSGetInfo (const(ddsBuffer_t)* dds, int* width, int* height, DDSPixelFormat* pf) { 308 // dummy test 309 if (dds is null) return false; 310 311 // test dds header 312 if (dds.magic != "DDS ") return false; 313 if (DDSLittleLong(dds.size) != 124) return false; 314 // arbitrary limits 315 if (DDSLittleLong(dds.width) < 1 || DDSLittleLong(dds.width) > 65535) return false; 316 if (DDSLittleLong(dds.height) < 1 || DDSLittleLong(dds.height) > 65535) return false; 317 318 // extract width and height 319 if (width !is null) *width = DDSLittleLong(dds.width); 320 if (height !is null) *height = DDSLittleLong(dds.height); 321 322 // get pixel format 323 DDSDecodePixelFormat(dds, pf); 324 325 // return ok 326 return true; 327 } 328 329 330 // decompresses a dds texture into an rgba image buffer, returns 0 on success 331 /*public*/ bool DDSDecompress (const(ddsBuffer_t)* dds, Color[] pixels) { 332 int width, height; 333 DDSPixelFormat pf; 334 335 // get dds info 336 if (!DDSGetInfo(dds, &width, &height, &pf)) return false; 337 // arbitrary limits 338 if (DDSLittleLong(dds.width) < 1 || DDSLittleLong(dds.width) > 65535) return false; 339 if (DDSLittleLong(dds.height) < 1 || DDSLittleLong(dds.height) > 65535) return false; 340 if (pixels.length < width*height) return false; 341 342 // decompress 343 final switch (pf) { 344 // FIXME: support other [a]rgb formats 345 case DDSPixelFormat.RGB888: return DDSDecompressRGB888(dds, width, height, pixels.ptr); 346 case DDSPixelFormat.ARGB8888: return DDSDecompressARGB8888(dds, width, height, pixels.ptr); 347 case DDSPixelFormat.DXT1: return DDSDecompressDXT1(dds, width, height, pixels.ptr); 348 case DDSPixelFormat.DXT2: return DDSDecompressDXT2(dds, width, height, pixels.ptr); 349 case DDSPixelFormat.DXT3: return DDSDecompressDXT3(dds, width, height, pixels.ptr); 350 case DDSPixelFormat.DXT4: return DDSDecompressDXT4(dds, width, height, pixels.ptr); 351 case DDSPixelFormat.DXT5: return DDSDecompressDXT5(dds, width, height, pixels.ptr); 352 case DDSPixelFormat.Unknown: break; 353 } 354 355 return false; 356 } 357 358 359 // ////////////////////////////////////////////////////////////////////////// // 360 private: 361 362 version(BigEndian) { 363 int DDSLittleLong (int src) pure nothrow @safe @nogc { 364 pragma(inline, true); 365 return 366 ((src&0xFF000000)>>24)| 367 ((src&0x00FF0000)>>8)| 368 ((src&0x0000FF00)<<8)| 369 ((src&0x000000FF)<<24); 370 } 371 short DDSLittleShort (short src) pure nothrow @safe @nogc { 372 pragma(inline, true); 373 return cast(short)(((src&0xFF00)>>8)|((src&0x00FF)<<8)); 374 } 375 } else { 376 // little endian 377 int DDSLittleLong (int src) pure nothrow @safe @nogc { pragma(inline, true); return src; } 378 short DDSLittleShort (short src) pure nothrow @safe @nogc { pragma(inline, true); return src; } 379 } 380 381 382 // determines which pixel format the dds texture is in 383 private void DDSDecodePixelFormat (const(ddsBuffer_t)* dds, DDSPixelFormat* pf) { 384 // dummy check 385 if (dds is null || pf is null) return; 386 *pf = DDSPixelFormat.Unknown; 387 388 if (dds.pixelFormat.size < 8) return; 389 390 if (dds.pixelFormat.flags&DDS_FOURCC) { 391 // DXTn 392 if (dds.pixelFormat.fourCC == "DXT1") *pf = DDSPixelFormat.DXT1; 393 else if (dds.pixelFormat.fourCC == "DXT2") *pf = DDSPixelFormat.DXT2; 394 else if (dds.pixelFormat.fourCC == "DXT3") *pf = DDSPixelFormat.DXT3; 395 else if (dds.pixelFormat.fourCC == "DXT4") *pf = DDSPixelFormat.DXT4; 396 else if (dds.pixelFormat.fourCC == "DXT5") *pf = DDSPixelFormat.DXT5; 397 else return; 398 } else if (dds.pixelFormat.flags == DDS_RGB || dds.pixelFormat.flags == DDS_RGBA) { 399 //immutable bitcount = getUInt(88); 400 if (dds.pixelFormat.rgbBitCount == 24) *pf = DDSPixelFormat.RGB888; 401 else if (dds.pixelFormat.rgbBitCount == 32) *pf = DDSPixelFormat.ARGB8888; 402 else return; 403 } 404 } 405 406 407 // extracts colors from a dds color block 408 private void DDSGetColorBlockColors (const(ddsColorBlock_t)* block, Color* colors) { 409 ushort word; 410 411 // color 0 412 word = DDSLittleShort(block.colors.ptr[0]); 413 colors[0].a = 0xff; 414 415 // extract rgb bits 416 colors[0].b = cast(ubyte)word; 417 colors[0].b <<= 3; 418 colors[0].b |= (colors[0].b>>5); 419 word >>= 5; 420 colors[0].g = cast(ubyte)word; 421 colors[0].g <<= 2; 422 colors[0].g |= (colors[0].g>>5); 423 word >>= 6; 424 colors[0].r = cast(ubyte)word; 425 colors[0].r <<= 3; 426 colors[0].r |= (colors[0].r>>5); 427 428 // same for color 1 429 word = DDSLittleShort(block.colors.ptr[1]); 430 colors[1].a = 0xff; 431 432 // extract rgb bits 433 colors[1].b = cast(ubyte)word; 434 colors[1].b <<= 3; 435 colors[1].b |= (colors[1].b>>5); 436 word >>= 5; 437 colors[1].g = cast(ubyte)word; 438 colors[1].g <<= 2; 439 colors[1].g |= (colors[1].g>>5); 440 word >>= 6; 441 colors[1].r = cast(ubyte)word; 442 colors[1].r <<= 3; 443 colors[1].r |= (colors[1].r>>5); 444 445 // use this for all but the super-freak math method 446 if (block.colors.ptr[0] > block.colors.ptr[1]) { 447 /* four-color block: derive the other two colors. 448 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 449 these two bit codes correspond to the 2-bit fields 450 stored in the 64-bit block. */ 451 word = (cast(ushort)colors[0].r*2+cast(ushort)colors[1].r)/3; 452 // no +1 for rounding 453 // as bits have been shifted to 888 454 colors[2].r = cast(ubyte) word; 455 word = (cast(ushort)colors[0].g*2+cast(ushort)colors[1].g)/3; 456 colors[2].g = cast(ubyte) word; 457 word = (cast(ushort)colors[0].b*2+cast(ushort)colors[1].b)/3; 458 colors[2].b = cast(ubyte)word; 459 colors[2].a = 0xff; 460 461 word = (cast(ushort)colors[0].r+cast(ushort)colors[1].r*2)/3; 462 colors[3].r = cast(ubyte)word; 463 word = (cast(ushort)colors[0].g+cast(ushort)colors[1].g*2)/3; 464 colors[3].g = cast(ubyte)word; 465 word = (cast(ushort)colors[0].b+cast(ushort)colors[1].b*2)/3; 466 colors[3].b = cast(ubyte)word; 467 colors[3].a = 0xff; 468 } else { 469 /* three-color block: derive the other color. 470 00 = color 0, 01 = color 1, 10 = color 2, 471 11 = transparent. 472 These two bit codes correspond to the 2-bit fields 473 stored in the 64-bit block */ 474 word = (cast(ushort)colors[0].r+cast(ushort)colors[1].r)/2; 475 colors[2].r = cast(ubyte)word; 476 word = (cast(ushort)colors[0].g+cast(ushort)colors[1].g)/2; 477 colors[2].g = cast(ubyte)word; 478 word = (cast(ushort)colors[0].b+cast(ushort)colors[1].b)/2; 479 colors[2].b = cast(ubyte)word; 480 colors[2].a = 0xff; 481 482 // random color to indicate alpha 483 colors[3].r = 0x00; 484 colors[3].g = 0xff; 485 colors[3].b = 0xff; 486 colors[3].a = 0x00; 487 } 488 } 489 490 491 //decodes a dds color block 492 //FIXME: make endian-safe 493 private void DDSDecodeColorBlock (uint* pixel, const(ddsColorBlock_t)* block, int width, const(Color)* colors) { 494 int r, n; 495 uint bits; 496 static immutable uint[4] masks = [ 3, 12, 3<<4, 3<<6 ]; // bit masks = 00000011, 00001100, 00110000, 11000000 497 static immutable ubyte[4] shift = [ 0, 2, 4, 6 ]; 498 // r steps through lines in y 499 // no width * 4 as unsigned int ptr inc will * 4 500 for (r = 0; r < 4; ++r, pixel += width-4) { 501 // width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels 502 // n steps through pixels 503 for (n = 0; n < 4; ++n) { 504 bits = block.row.ptr[r]&masks.ptr[n]; 505 bits >>= shift.ptr[n]; 506 switch (bits) { 507 case 0: *pixel++ = colors[0].asUint; break; 508 case 1: *pixel++ = colors[1].asUint; break; 509 case 2: *pixel++ = colors[2].asUint; break; 510 case 3: *pixel++ = colors[3].asUint; break; 511 default: ++pixel; break; // invalid 512 } 513 } 514 } 515 } 516 517 518 // decodes a dds explicit alpha block 519 //FIXME: endianness 520 private void DDSDecodeAlphaExplicit (uint* pixel, const(ddsAlphaBlockExplicit_t)* alphaBlock, int width, uint alphaZero) { 521 int row, pix; 522 ushort word; 523 Color color; 524 525 // clear color 526 color.r = 0; 527 color.g = 0; 528 color.b = 0; 529 530 // walk rows 531 for (row = 0; row < 4; ++row, pixel += width-4) { 532 word = DDSLittleShort(alphaBlock.row.ptr[row]); 533 // walk pixels 534 for (pix = 0; pix < 4; ++pix) { 535 // zero the alpha bits of image pixel 536 *pixel &= alphaZero; 537 color.a = word&0x000F; 538 color.a = cast(ubyte)(color.a|(color.a<<4)); 539 *pixel |= *(cast(const(uint)*)&color); 540 word >>= 4; // move next bits to lowest 4 541 ++pixel; // move to next pixel in the row 542 } 543 } 544 } 545 546 547 // decodes interpolated alpha block 548 private void DDSDecodeAlpha3BitLinear (uint* pixel, const(ddsAlphaBlock3BitLinear_t)* alphaBlock, int width, uint alphaZero) { 549 int row, pix; 550 uint stuff; 551 ubyte[4][4] bits; 552 ushort[8] alphas; 553 Color[4][4] aColors; 554 555 // get initial alphas 556 alphas.ptr[0] = alphaBlock.alpha0; 557 alphas.ptr[1] = alphaBlock.alpha1; 558 559 if (alphas.ptr[0] > alphas.ptr[1]) { 560 // 8-alpha block 561 // 000 = alpha_0, 001 = alpha_1, others are interpolated 562 alphas.ptr[2] = (6*alphas.ptr[0]+alphas.ptr[1])/7; // bit code 010 563 alphas.ptr[3] = (5*alphas.ptr[0]+2*alphas.ptr[1])/7; // bit code 011 564 alphas.ptr[4] = (4*alphas.ptr[0]+3*alphas.ptr[1])/7; // bit code 100 565 alphas.ptr[5] = (3*alphas.ptr[0]+4*alphas.ptr[1])/7; // bit code 101 566 alphas.ptr[6] = (2*alphas.ptr[0]+5*alphas.ptr[1])/7; // bit code 110 567 alphas.ptr[7] = (alphas.ptr[0]+6*alphas.ptr[1])/7; // bit code 111 568 } else { 569 // 6-alpha block 570 // 000 = alpha_0, 001 = alpha_1, others are interpolated 571 alphas.ptr[2] = (4*alphas.ptr[0]+alphas.ptr[1])/5; // bit code 010 572 alphas.ptr[3] = (3*alphas.ptr[0]+2*alphas.ptr[1])/5; // bit code 011 573 alphas.ptr[4] = (2*alphas.ptr[0]+3*alphas.ptr[1])/5; // bit code 100 574 alphas.ptr[5] = (alphas.ptr[0]+4*alphas.ptr[1])/5; // bit code 101 575 alphas.ptr[6] = 0; // bit code 110 576 alphas.ptr[7] = 255; // bit code 111 577 } 578 579 // decode 3-bit fields into array of 16 bytes with same value 580 581 // first two rows of 4 pixels each 582 stuff = *(cast(const(uint)*)&(alphaBlock.stuff.ptr[0])); 583 584 bits.ptr[0].ptr[0] = cast(ubyte)(stuff&0x00000007); 585 stuff >>= 3; 586 bits.ptr[0].ptr[1] = cast(ubyte)(stuff&0x00000007); 587 stuff >>= 3; 588 bits.ptr[0].ptr[2] = cast(ubyte)(stuff&0x00000007); 589 stuff >>= 3; 590 bits.ptr[0].ptr[3] = cast(ubyte)(stuff&0x00000007); 591 stuff >>= 3; 592 bits.ptr[1].ptr[0] = cast(ubyte)(stuff&0x00000007); 593 stuff >>= 3; 594 bits.ptr[1].ptr[1] = cast(ubyte)(stuff&0x00000007); 595 stuff >>= 3; 596 bits.ptr[1].ptr[2] = cast(ubyte)(stuff&0x00000007); 597 stuff >>= 3; 598 bits.ptr[1].ptr[3] = cast(ubyte)(stuff&0x00000007); 599 600 // last two rows 601 stuff = *(cast(const(uint)*)&(alphaBlock.stuff.ptr[3])); // last 3 bytes 602 603 bits.ptr[2].ptr[0] = cast(ubyte)(stuff&0x00000007); 604 stuff >>= 3; 605 bits.ptr[2].ptr[1] = cast(ubyte)(stuff&0x00000007); 606 stuff >>= 3; 607 bits.ptr[2].ptr[2] = cast(ubyte)(stuff&0x00000007); 608 stuff >>= 3; 609 bits.ptr[2].ptr[3] = cast(ubyte)(stuff&0x00000007); 610 stuff >>= 3; 611 bits.ptr[3].ptr[0] = cast(ubyte)(stuff&0x00000007); 612 stuff >>= 3; 613 bits.ptr[3].ptr[1] = cast(ubyte)(stuff&0x00000007); 614 stuff >>= 3; 615 bits.ptr[3].ptr[2] = cast(ubyte)(stuff&0x00000007); 616 stuff >>= 3; 617 bits.ptr[3].ptr[3] = cast(ubyte)(stuff&0x00000007); 618 619 // decode the codes into alpha values 620 for (row = 0; row < 4; ++row) { 621 for (pix = 0; pix < 4; ++pix) { 622 aColors.ptr[row].ptr[pix].r = 0; 623 aColors.ptr[row].ptr[pix].g = 0; 624 aColors.ptr[row].ptr[pix].b = 0; 625 aColors.ptr[row].ptr[pix].a = cast(ubyte)alphas.ptr[bits.ptr[row].ptr[pix]]; 626 } 627 } 628 629 // write out alpha values to the image bits 630 for (row = 0; row < 4; ++row, pixel += width-4) { 631 for (pix = 0; pix < 4; ++pix) { 632 // zero the alpha bits of image pixel 633 *pixel &= alphaZero; 634 // or the bits into the prev. nulled alpha 635 *pixel |= *(cast(const(uint)*)&(aColors.ptr[row].ptr[pix])); 636 ++pixel; 637 } 638 } 639 } 640 641 642 // decompresses a dxt1 format texture 643 private bool DDSDecompressDXT1 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 644 Color[4] colors; 645 immutable int xBlocks = width/4; 646 immutable int yBlocks = height/4; 647 // 8 bytes per block 648 auto block = cast(const(ddsColorBlock_t)*)dds.data.ptr; 649 foreach (immutable y; 0..yBlocks) { 650 foreach (immutable x; 0..xBlocks) { 651 DDSGetColorBlockColors(block, colors.ptr); 652 auto pixel = cast(uint*)(pixels+x*4+(y*4)*width); 653 DDSDecodeColorBlock(pixel, block, width, colors.ptr); 654 ++block; 655 } 656 } 657 // return ok 658 return true; 659 } 660 661 662 // decompresses a dxt3 format texture 663 private bool DDSDecompressDXT3 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 664 Color[4] colors; 665 666 // setup 667 immutable int xBlocks = width/4; 668 immutable int yBlocks = height/4; 669 670 // create zero alpha 671 colors.ptr[0].a = 0; 672 colors.ptr[0].r = 0xFF; 673 colors.ptr[0].g = 0xFF; 674 colors.ptr[0].b = 0xFF; 675 immutable uint alphaZero = colors.ptr[0].asUint; 676 677 // 8 bytes per block, 1 block for alpha, 1 block for color 678 auto block = cast(const(ddsColorBlock_t)*)dds.data.ptr; 679 foreach (immutable y; 0..yBlocks) { 680 foreach (immutable x; 0..xBlocks) { 681 // get alpha block 682 auto alphaBlock = cast(const(ddsAlphaBlockExplicit_t)*)block++; 683 // get color block 684 DDSGetColorBlockColors(block, colors.ptr); 685 // decode color block 686 auto pixel = cast(uint*)(pixels+x*4+(y*4)*width); 687 DDSDecodeColorBlock(pixel, block, width, colors.ptr); 688 // overwrite alpha bits with alpha block 689 DDSDecodeAlphaExplicit(pixel, alphaBlock, width, alphaZero); 690 ++block; 691 } 692 } 693 694 // return ok 695 return true; 696 } 697 698 699 // decompresses a dxt5 format texture 700 private bool DDSDecompressDXT5 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 701 Color[4] colors; 702 703 // setup 704 immutable int xBlocks = width/4; 705 immutable int yBlocks = height/4; 706 707 // create zero alpha 708 colors.ptr[0].a = 0; 709 colors.ptr[0].r = 0xFF; 710 colors.ptr[0].g = 0xFF; 711 colors.ptr[0].b = 0xFF; 712 immutable uint alphaZero = colors.ptr[0].asUint; 713 714 // 8 bytes per block, 1 block for alpha, 1 block for color 715 auto block = cast(const(ddsColorBlock_t)*)dds.data.ptr; 716 foreach (immutable y; 0..yBlocks) { 717 //block = cast(ddsColorBlock_t*)(dds.data.ptr+y*xBlocks*16); 718 foreach (immutable x; 0..xBlocks) { 719 // get alpha block 720 auto alphaBlock = cast(const(ddsAlphaBlock3BitLinear_t)*)block++; 721 // get color block 722 DDSGetColorBlockColors(block, colors.ptr); 723 // decode color block 724 auto pixel = cast(uint*)(pixels+x*4+(y*4)*width); 725 DDSDecodeColorBlock(pixel, block, width, colors.ptr); 726 // overwrite alpha bits with alpha block 727 DDSDecodeAlpha3BitLinear(pixel, alphaBlock, width, alphaZero); 728 ++block; 729 } 730 } 731 732 // return ok 733 return true; 734 } 735 736 737 private void unmultiply (Color[] pixels) { 738 // premultiplied alpha 739 foreach (ref Color clr; pixels) { 740 if (clr.a != 0) { 741 clr.r = Color.clampToByte(clr.r*255/clr.a); 742 clr.g = Color.clampToByte(clr.g*255/clr.a); 743 clr.b = Color.clampToByte(clr.b*255/clr.a); 744 } 745 } 746 } 747 748 749 // decompresses a dxt2 format texture (FIXME: un-premultiply alpha) 750 private bool DDSDecompressDXT2 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 751 // decompress dxt3 first 752 if (!DDSDecompressDXT3(dds, width, height, pixels)) return false; 753 //FIXME: is un-premultiply correct? 754 unmultiply(pixels[0..width*height]); 755 return true; 756 } 757 758 759 // decompresses a dxt4 format texture (FIXME: un-premultiply alpha) 760 private bool DDSDecompressDXT4 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 761 // decompress dxt5 first 762 if (!DDSDecompressDXT5(dds, width, height, pixels)) return false; 763 //FIXME: is un-premultiply correct? 764 unmultiply(pixels[0..width*height]); 765 return true; 766 } 767 768 769 // decompresses an argb 8888 format texture 770 private bool DDSDecompressARGB8888 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 771 auto zin = cast(const(Color)*)dds.data.ptr; 772 //pixels[0..width*height] = zin[0..width*height]; 773 foreach (immutable idx; 0..width*height) { 774 pixels.r = zin.b; 775 pixels.g = zin.g; 776 pixels.b = zin.r; 777 pixels.a = zin.a; 778 ++pixels; 779 ++zin; 780 } 781 return true; 782 } 783 784 785 // decompresses an rgb 888 format texture 786 private bool DDSDecompressRGB888 (const(ddsBuffer_t)* dds, int width, int height, Color* pixels) { 787 auto zin = cast(const(ubyte)*)dds.data.ptr; 788 //pixels[0..width*height] = zin[0..width*height]; 789 foreach (immutable idx; 0..width*height) { 790 pixels.b = *zin++; 791 pixels.g = *zin++; 792 pixels.r = *zin++; 793 pixels.a = 255; 794 ++pixels; 795 } 796 return true; 797 }