1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 29 #include "OgreStableHeaders.h" 30 31 #include "OgreDDSCodec.h" 32 #include "OgreImage.h" 33 34 namespace Ogre { 35 // Internal DDS structure definitions 36 #define FOURCC(c0, c1, c2, c3) (c0 | (c1 << 8) | (c2 << 16) | (c3 << 24)) 37 38 #if OGRE_COMPILER == OGRE_COMPILER_MSVC 39 #pragma pack (push, 1) 40 #else 41 #pragma pack (1) 42 #endif 43 44 // Nested structure 45 struct DDSPixelFormat 46 { 47 uint32 size; 48 uint32 flags; 49 uint32 fourCC; 50 uint32 rgbBits; 51 uint32 redMask; 52 uint32 greenMask; 53 uint32 blueMask; 54 uint32 alphaMask; 55 }; 56 57 // Nested structure 58 struct DDSCaps 59 { 60 uint32 caps1; 61 uint32 caps2; 62 uint32 caps3; 63 uint32 caps4; 64 }; 65 // Main header, note preceded by 'DDS ' 66 struct DDSHeader 67 { 68 uint32 size; 69 uint32 flags; 70 uint32 height; 71 uint32 width; 72 uint32 sizeOrPitch; 73 uint32 depth; 74 uint32 mipMapCount; 75 uint32 reserved1[11]; 76 DDSPixelFormat pixelFormat; 77 DDSCaps caps; 78 uint32 reserved2; 79 }; 80 81 // Extended header 82 struct DDSExtendedHeader 83 { 84 uint32 dxgiFormat; 85 uint32 resourceDimension; 86 uint32 miscFlag; // see D3D11_RESOURCE_MISC_FLAG 87 uint32 arraySize; 88 uint32 reserved; 89 }; 90 91 92 // An 8-byte DXT colour block, represents a 4x4 texel area. Used by all DXT formats 93 struct DXTColourBlock 94 { 95 // 2 colour ranges 96 uint16 colour_0; 97 uint16 colour_1; 98 // 16 2-bit indexes, each byte here is one row 99 uint8 indexRow[4]; 100 }; 101 // An 8-byte DXT explicit alpha block, represents a 4x4 texel area. Used by DXT2/3 102 struct DXTExplicitAlphaBlock 103 { 104 // 16 4-bit values, each 16-bit value is one row 105 uint16 alphaRow[4]; 106 }; 107 // An 8-byte DXT interpolated alpha block, represents a 4x4 texel area. Used by DXT4/5 108 struct DXTInterpolatedAlphaBlock 109 { 110 // 2 alpha ranges 111 uint8 alpha_0; 112 uint8 alpha_1; 113 // 16 3-bit indexes. Unfortunately 3 bits doesn't map too well to row bytes 114 // so just stored raw 115 uint8 indexes[6]; 116 }; 117 118 #if OGRE_COMPILER == OGRE_COMPILER_MSVC 119 #pragma pack (pop) 120 #else 121 #pragma pack () 122 #endif 123 124 const uint32 DDS_MAGIC = FOURCC('D', 'D', 'S', ' '); 125 const uint32 DDS_PIXELFORMAT_SIZE = 8 * sizeof(uint32); 126 const uint32 DDS_CAPS_SIZE = 4 * sizeof(uint32); 127 const uint32 DDS_HEADER_SIZE = 19 * sizeof(uint32) + DDS_PIXELFORMAT_SIZE + DDS_CAPS_SIZE; 128 129 const uint32 DDSD_CAPS = 0x00000001; 130 const uint32 DDSD_HEIGHT = 0x00000002; 131 const uint32 DDSD_WIDTH = 0x00000004; 132 const uint32 DDSD_PIXELFORMAT = 0x00001000; 133 const uint32 DDSD_DEPTH = 0x00800000; 134 const uint32 DDPF_ALPHAPIXELS = 0x00000001; 135 const uint32 DDPF_FOURCC = 0x00000004; 136 const uint32 DDPF_RGB = 0x00000040; 137 const uint32 DDSCAPS_COMPLEX = 0x00000008; 138 const uint32 DDSCAPS_TEXTURE = 0x00001000; 139 const uint32 DDSCAPS_MIPMAP = 0x00400000; 140 const uint32 DDSCAPS2_CUBEMAP = 0x00000200; 141 const uint32 DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; 142 const uint32 DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; 143 const uint32 DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; 144 const uint32 DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; 145 const uint32 DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; 146 const uint32 DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; 147 const uint32 DDSCAPS2_VOLUME = 0x00200000; 148 149 // Currently unused 150 // const uint32 DDSD_PITCH = 0x00000008; 151 // const uint32 DDSD_MIPMAPCOUNT = 0x00020000; 152 // const uint32 DDSD_LINEARSIZE = 0x00080000; 153 154 // Special FourCC codes 155 const uint32 D3DFMT_R16F = 111; 156 const uint32 D3DFMT_G16R16F = 112; 157 const uint32 D3DFMT_A16B16G16R16F = 113; 158 const uint32 D3DFMT_R32F = 114; 159 const uint32 D3DFMT_G32R32F = 115; 160 const uint32 D3DFMT_A32B32G32R32F = 116; 161 162 163 //--------------------------------------------------------------------- 164 DDSCodec* DDSCodec::msInstance = 0; 165 //--------------------------------------------------------------------- startup(void)166 void DDSCodec::startup(void) 167 { 168 if (!msInstance) 169 { 170 171 LogManager::getSingleton().logMessage( 172 LML_NORMAL, 173 "DDS codec registering"); 174 175 msInstance = OGRE_NEW DDSCodec(); 176 Codec::registerCodec(msInstance); 177 } 178 179 } 180 //--------------------------------------------------------------------- shutdown(void)181 void DDSCodec::shutdown(void) 182 { 183 if(msInstance) 184 { 185 Codec::unregisterCodec(msInstance); 186 OGRE_DELETE msInstance; 187 msInstance = 0; 188 } 189 190 } 191 //--------------------------------------------------------------------- DDSCodec()192 DDSCodec::DDSCodec(): 193 mType("dds") 194 { 195 } 196 //--------------------------------------------------------------------- encode(const MemoryDataStreamPtr & input,const Codec::CodecDataPtr & pData) const197 DataStreamPtr DDSCodec::encode(const MemoryDataStreamPtr& input, const Codec::CodecDataPtr& pData) const 198 { 199 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, 200 "DDS encoding not supported", 201 "DDSCodec::encode" ) ; 202 } 203 //--------------------------------------------------------------------- encodeToFile(const MemoryDataStreamPtr & input,const String & outFileName,const Codec::CodecDataPtr & pData) const204 void DDSCodec::encodeToFile(const MemoryDataStreamPtr& input, const String& outFileName, 205 const Codec::CodecDataPtr& pData) const 206 { 207 // Unwrap codecDataPtr - data is cleaned by calling function 208 ImageData* imgData = static_cast<ImageData* >(pData.get()); 209 210 211 // Check size for cube map faces 212 bool isCubeMap = (imgData->size == 213 Image::calculateSize(imgData->num_mipmaps, 6, imgData->width, 214 imgData->height, imgData->depth, imgData->format)); 215 216 // Establish texture attributes 217 bool isVolume = (imgData->depth > 1); 218 bool isFloat32r = (imgData->format == PF_FLOAT32_R); 219 bool isFloat16 = (imgData->format == PF_FLOAT16_RGBA); 220 bool isFloat32 = (imgData->format == PF_FLOAT32_RGBA); 221 bool notImplemented = false; 222 String notImplementedString = ""; 223 224 // Check for all the 'not implemented' conditions 225 if ((isVolume == true)&&(imgData->width != imgData->height)) 226 { 227 // Square textures only 228 notImplemented = true; 229 notImplementedString += " non square textures"; 230 } 231 232 uint32 size = 1; 233 while (size < imgData->width) 234 { 235 size <<= 1; 236 } 237 if (size != imgData->width) 238 { 239 // Power two textures only 240 notImplemented = true; 241 notImplementedString += " non power two textures"; 242 } 243 244 switch(imgData->format) 245 { 246 case PF_A8R8G8B8: 247 case PF_X8R8G8B8: 248 case PF_R8G8B8: 249 case PF_A8B8G8R8: 250 case PF_X8B8G8R8: 251 case PF_B8G8R8: 252 case PF_FLOAT32_R: 253 case PF_FLOAT16_RGBA: 254 case PF_FLOAT32_RGBA: 255 break; 256 default: 257 // No crazy FOURCC or 565 et al. file formats at this stage 258 notImplemented = true; 259 notImplementedString = " unsupported pixel format"; 260 break; 261 } 262 263 264 265 // Except if any 'not implemented' conditions were met 266 if (notImplemented) 267 { 268 OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, 269 "DDS encoding for" + notImplementedString + " not supported", 270 "DDSCodec::encodeToFile" ) ; 271 } 272 else 273 { 274 // Build header and write to disk 275 276 // Variables for some DDS header flags 277 bool hasAlpha = false; 278 uint32 ddsHeaderFlags = 0; 279 uint32 ddsHeaderRgbBits = 0; 280 uint32 ddsHeaderSizeOrPitch = 0; 281 uint32 ddsHeaderCaps1 = 0; 282 uint32 ddsHeaderCaps2 = 0; 283 uint32 ddsMagic = DDS_MAGIC; 284 285 // Initalise the header flags 286 ddsHeaderFlags = (isVolume) ? DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_DEPTH|DDSD_PIXELFORMAT : 287 DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT; 288 289 bool flipRgbMasks = false; 290 291 // Initalise the rgbBits flags 292 switch(imgData->format) 293 { 294 case PF_A8B8G8R8: 295 flipRgbMasks = true; 296 OGRE_FALLTHROUGH; 297 case PF_A8R8G8B8: 298 ddsHeaderRgbBits = 8 * 4; 299 hasAlpha = true; 300 break; 301 case PF_X8B8G8R8: 302 flipRgbMasks = true; 303 OGRE_FALLTHROUGH; 304 case PF_X8R8G8B8: 305 ddsHeaderRgbBits = 8 * 4; 306 break; 307 case PF_B8G8R8: 308 case PF_R8G8B8: 309 ddsHeaderRgbBits = 8 * 3; 310 break; 311 case PF_FLOAT32_R: 312 ddsHeaderRgbBits = 32; 313 break; 314 case PF_FLOAT16_RGBA: 315 ddsHeaderRgbBits = 16 * 4; 316 hasAlpha = true; 317 break; 318 case PF_FLOAT32_RGBA: 319 ddsHeaderRgbBits = 32 * 4; 320 hasAlpha = true; 321 break; 322 default: 323 ddsHeaderRgbBits = 0; 324 break; 325 } 326 327 // Initalise the SizeOrPitch flags (power two textures for now) 328 ddsHeaderSizeOrPitch = static_cast<uint32>(ddsHeaderRgbBits * imgData->width); 329 330 // Initalise the caps flags 331 ddsHeaderCaps1 = (isVolume||isCubeMap) ? DDSCAPS_COMPLEX|DDSCAPS_TEXTURE : DDSCAPS_TEXTURE; 332 if (isVolume) 333 { 334 ddsHeaderCaps2 = DDSCAPS2_VOLUME; 335 } 336 else if (isCubeMap) 337 { 338 ddsHeaderCaps2 = DDSCAPS2_CUBEMAP| 339 DDSCAPS2_CUBEMAP_POSITIVEX|DDSCAPS2_CUBEMAP_NEGATIVEX| 340 DDSCAPS2_CUBEMAP_POSITIVEY|DDSCAPS2_CUBEMAP_NEGATIVEY| 341 DDSCAPS2_CUBEMAP_POSITIVEZ|DDSCAPS2_CUBEMAP_NEGATIVEZ; 342 } 343 344 if( imgData->num_mipmaps > 0 ) 345 ddsHeaderCaps1 |= DDSCAPS_MIPMAP; 346 347 // Populate the DDS header information 348 DDSHeader ddsHeader; 349 ddsHeader.size = DDS_HEADER_SIZE; 350 ddsHeader.flags = ddsHeaderFlags; 351 ddsHeader.width = (uint32)imgData->width; 352 ddsHeader.height = (uint32)imgData->height; 353 ddsHeader.depth = (uint32)(isVolume ? imgData->depth : 0); 354 ddsHeader.depth = (uint32)(isCubeMap ? 6 : ddsHeader.depth); 355 ddsHeader.mipMapCount = imgData->num_mipmaps + 1; 356 ddsHeader.sizeOrPitch = ddsHeaderSizeOrPitch; 357 for (uint32 reserved1=0; reserved1<11; reserved1++) // XXX nasty constant 11 358 { 359 ddsHeader.reserved1[reserved1] = 0; 360 } 361 ddsHeader.reserved2 = 0; 362 363 ddsHeader.pixelFormat.size = DDS_PIXELFORMAT_SIZE; 364 ddsHeader.pixelFormat.flags = (hasAlpha) ? DDPF_RGB|DDPF_ALPHAPIXELS : DDPF_RGB; 365 ddsHeader.pixelFormat.flags = (isFloat32r || isFloat16 || isFloat32) ? DDPF_FOURCC : ddsHeader.pixelFormat.flags; 366 if (isFloat32r) { 367 ddsHeader.pixelFormat.fourCC = D3DFMT_R32F; 368 } 369 else if (isFloat16) { 370 ddsHeader.pixelFormat.fourCC = D3DFMT_A16B16G16R16F; 371 } 372 else if (isFloat32) { 373 ddsHeader.pixelFormat.fourCC = D3DFMT_A32B32G32R32F; 374 } 375 else { 376 ddsHeader.pixelFormat.fourCC = 0; 377 } 378 ddsHeader.pixelFormat.rgbBits = ddsHeaderRgbBits; 379 380 ddsHeader.pixelFormat.alphaMask = (hasAlpha) ? 0xFF000000 : 0x00000000; 381 ddsHeader.pixelFormat.alphaMask = (isFloat32r) ? 0x00000000 : ddsHeader.pixelFormat.alphaMask; 382 ddsHeader.pixelFormat.redMask = (isFloat32r) ? 0xFFFFFFFF :0x00FF0000; 383 ddsHeader.pixelFormat.greenMask = (isFloat32r) ? 0x00000000 :0x0000FF00; 384 ddsHeader.pixelFormat.blueMask = (isFloat32r) ? 0x00000000 :0x000000FF; 385 386 if( flipRgbMasks ) 387 std::swap( ddsHeader.pixelFormat.redMask, ddsHeader.pixelFormat.blueMask ); 388 389 ddsHeader.caps.caps1 = ddsHeaderCaps1; 390 ddsHeader.caps.caps2 = ddsHeaderCaps2; 391 // ddsHeader.caps.reserved[0] = 0; 392 // ddsHeader.caps.reserved[1] = 0; 393 394 // Swap endian 395 flipEndian(&ddsMagic, sizeof(uint32)); 396 flipEndian(&ddsHeader, 4, sizeof(DDSHeader) / 4); 397 398 char *tmpData = 0; 399 char const *dataPtr = (char const *)input->getPtr(); 400 401 if( imgData->format == PF_B8G8R8 ) 402 { 403 PixelBox src( imgData->size / 3, 1, 1, PF_B8G8R8, input->getPtr() ); 404 tmpData = new char[imgData->size]; 405 PixelBox dst( imgData->size / 3, 1, 1, PF_R8G8B8, tmpData ); 406 407 PixelUtil::bulkPixelConversion( src, dst ); 408 409 dataPtr = tmpData; 410 } 411 412 try 413 { 414 // Write the file 415 std::ofstream of; 416 of.open(outFileName.c_str(), std::ios_base::binary|std::ios_base::out); 417 of.write((const char *)&ddsMagic, sizeof(uint32)); 418 of.write((const char *)&ddsHeader, DDS_HEADER_SIZE); 419 // XXX flipEndian on each pixel chunk written unless isFloat32r ? 420 of.write(dataPtr, (uint32)imgData->size); 421 of.close(); 422 } 423 catch(...) 424 { 425 delete [] tmpData; 426 } 427 } 428 } 429 //--------------------------------------------------------------------- convertDXToOgreFormat(uint32 dxfmt) const430 PixelFormat DDSCodec::convertDXToOgreFormat(uint32 dxfmt) const 431 { 432 switch (dxfmt) { 433 case 2: // DXGI_FORMAT_R32G32B32A32_FLOAT 434 return PF_FLOAT32_RGBA; 435 case 3: // DXGI_FORMAT_R32G32B32A32_UINT 436 return PF_R32G32B32A32_UINT; 437 case 4: //DXGI_FORMAT_R32G32B32A32_SINT 438 return PF_R32G32B32A32_SINT; 439 case 6: // DXGI_FORMAT_R32G32B32_FLOAT 440 return PF_FLOAT32_RGB; 441 case 7: // DXGI_FORMAT_R32G32B32_UINT 442 return PF_R32G32B32_UINT; 443 case 8: // DXGI_FORMAT_R32G32B32_SINT 444 return PF_R32G32B32_SINT; 445 case 10: // DXGI_FORMAT_R16G16B16A16_FLOAT 446 return PF_FLOAT16_RGBA; 447 case 12: // DXGI_FORMAT_R16G16B16A16_UINT 448 return PF_R16G16B16A16_UINT; 449 case 13: // DXGI_FORMAT_R16G16B16A16_SNORM 450 return PF_R16G16B16A16_SNORM; 451 case 14: // DXGI_FORMAT_R16G16B16A16_SINT 452 return PF_R16G16B16A16_SINT; 453 case 16: // DXGI_FORMAT_R32G32_FLOAT 454 return PF_FLOAT32_GR; 455 case 17: // DXGI_FORMAT_R32G32_UINT 456 return PF_R32G32_UINT; 457 case 18: // DXGI_FORMAT_R32G32_SINT 458 return PF_R32G32_SINT; 459 case 24: // DXGI_FORMAT_R10G10B10A2_UNORM 460 case 25: // DXGI_FORMAT_R10G10B10A2_UINT 461 return PF_A2B10G10R10; 462 case 26: // DXGI_FORMAT_R11G11B10_FLOAT 463 return PF_R11G11B10_FLOAT; 464 case 28: // DXGI_FORMAT_R8G8B8A8_UNORM 465 case 29: // DXGI_FORMAT_R8G8B8A8_UNORM_SRGB 466 return PF_A8B8G8R8; 467 case 30: // DXGI_FORMAT_R8G8B8A8_UINT 468 return PF_R8G8B8A8_UINT; 469 case 31: // DXGI_FORMAT_R8G8B8A8_SNORM 470 return PF_R8G8B8A8_SNORM; 471 case 32: // DXGI_FORMAT_R8G8B8A8_SINT 472 return PF_R8G8B8A8_SINT; 473 case 34: // DXGI_FORMAT_R16G16_FLOAT 474 return PF_FLOAT16_GR; 475 case 35: // DXGI_FORMAT_R16G16_UNORM 476 return PF_SHORT_GR; 477 case 36: // DXGI_FORMAT_R16G16_UINT 478 return PF_R16G16_UINT; 479 case 37: // DXGI_FORMAT_R16G16_SNORM 480 return PF_R16G16_SNORM; 481 case 38: // DXGI_FORMAT_R16G16_SINT 482 return PF_R16G16_SINT; 483 case 41: // DXGI_FORMAT_R32_FLOAT 484 return PF_FLOAT32_R; 485 case 42: // DXGI_FORMAT_R32_UINT 486 return PF_R32_UINT; 487 case 43: // DXGI_FORMAT_R32_SINT 488 return PF_R32_SINT; 489 case 49: // DXGI_FORMAT_R8G8_UNORM 490 case 50: // DXGI_FORMAT_R8G8_UINT 491 return PF_R8G8_UINT; 492 case 52: // DXGI_FORMAT_R8G8_SINT 493 return PF_R8G8_SINT; 494 case 54: // DXGI_FORMAT_R16_FLOAT 495 return PF_FLOAT16_R; 496 case 56: // DXGI_FORMAT_R16_UNORM 497 return PF_L16; 498 case 57: // DXGI_FORMAT_R16_UINT 499 return PF_R16_UINT; 500 case 58: // DXGI_FORMAT_R16_SNORM 501 return PF_R16_SNORM; 502 case 59: // DXGI_FORMAT_R16_SINT 503 return PF_R16_SINT; 504 case 61: // DXGI_FORMAT_R8_UNORM 505 return PF_R8; 506 case 62: // DXGI_FORMAT_R8_UINT 507 return PF_R8_UINT; 508 case 63: // DXGI_FORMAT_R8_SNORM 509 return PF_R8_SNORM; 510 case 64: // DXGI_FORMAT_R8_SINT 511 return PF_R8_SINT; 512 case 65: // DXGI_FORMAT_A8_UNORM 513 return PF_A8; 514 case 80: // DXGI_FORMAT_BC4_UNORM 515 return PF_BC4_UNORM; 516 case 81: // DXGI_FORMAT_BC4_SNORM 517 return PF_BC4_SNORM; 518 case 83: // DXGI_FORMAT_BC5_UNORM 519 return PF_BC5_UNORM; 520 case 84: // DXGI_FORMAT_BC5_SNORM 521 return PF_BC5_SNORM; 522 case 85: // DXGI_FORMAT_B5G6R5_UNORM 523 return PF_R5G6B5; 524 case 86: // DXGI_FORMAT_B5G5R5A1_UNORM 525 return PF_A1R5G5B5; 526 case 87: // DXGI_FORMAT_B8G8R8A8_UNORM 527 return PF_A8R8G8B8; 528 case 88: // DXGI_FORMAT_B8G8R8X8_UNORM 529 return PF_X8R8G8B8; 530 case 95: // DXGI_FORMAT_BC6H_UF16 531 return PF_BC6H_UF16; 532 case 96: // DXGI_FORMAT_BC6H_SF16 533 return PF_BC6H_SF16; 534 case 98: // DXGI_FORMAT_BC7_UNORM 535 case 99: // DXGI_FORMAT_BC7_UNORM_SRGB 536 return PF_BC7_UNORM; 537 case 20: // DXGI_FORMAT_D32_FLOAT_S8X24_UINT 538 case 22: // DXGI_FORMAT_X32_TYPELESS_G8X24_UINT 539 case 40: // DXGI_FORMAT_D32_FLOAT 540 case 45: // DXGI_FORMAT_D24_UNORM_S8_UINT 541 case 47: // DXGI_FORMAT_X24_TYPELESS_G8_UINT 542 case 55: // DXGI_FORMAT_D16_UNORM 543 default: 544 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 545 "Unsupported DirectX format found in DDS file", 546 "DDSCodec::convertDXToOgreFormat"); 547 } 548 } 549 //--------------------------------------------------------------------- convertFourCCFormat(uint32 fourcc) const550 PixelFormat DDSCodec::convertFourCCFormat(uint32 fourcc) const 551 { 552 // convert dxt pixel format 553 switch(fourcc) 554 { 555 case FOURCC('D','X','T','1'): 556 return PF_DXT1; 557 case FOURCC('D','X','T','2'): 558 return PF_DXT2; 559 case FOURCC('D','X','T','3'): 560 return PF_DXT3; 561 case FOURCC('D','X','T','4'): 562 return PF_DXT4; 563 case FOURCC('D','X','T','5'): 564 return PF_DXT5; 565 case FOURCC('A','T','I','1'): 566 case FOURCC('B','C','4','U'): 567 return PF_BC4_UNORM; 568 case FOURCC('B','C','4','S'): 569 return PF_BC4_SNORM; 570 case FOURCC('A','T','I','2'): 571 case FOURCC('B','C','5','U'): 572 return PF_BC5_UNORM; 573 case FOURCC('B','C','5','S'): 574 return PF_BC5_SNORM; 575 case D3DFMT_R16F: 576 return PF_FLOAT16_R; 577 case D3DFMT_G16R16F: 578 return PF_FLOAT16_GR; 579 case D3DFMT_A16B16G16R16F: 580 return PF_FLOAT16_RGBA; 581 case D3DFMT_R32F: 582 return PF_FLOAT32_R; 583 case D3DFMT_G32R32F: 584 return PF_FLOAT32_GR; 585 case D3DFMT_A32B32G32R32F: 586 return PF_FLOAT32_RGBA; 587 // We could support 3Dc here, but only ATI cards support it, not nVidia 588 default: 589 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 590 "Unsupported FourCC format found in DDS file", 591 "DDSCodec::convertFourCCFormat"); 592 }; 593 594 } 595 //--------------------------------------------------------------------- convertPixelFormat(uint32 rgbBits,uint32 rMask,uint32 gMask,uint32 bMask,uint32 aMask) const596 PixelFormat DDSCodec::convertPixelFormat(uint32 rgbBits, uint32 rMask, 597 uint32 gMask, uint32 bMask, uint32 aMask) const 598 { 599 // General search through pixel formats 600 for (int i = PF_UNKNOWN + 1; i < PF_COUNT; ++i) 601 { 602 PixelFormat pf = static_cast<PixelFormat>(i); 603 if (PixelUtil::getNumElemBits(pf) == rgbBits) 604 { 605 uint64 testMasks[4]; 606 PixelUtil::getBitMasks(pf, testMasks); 607 int testBits[4]; 608 PixelUtil::getBitDepths(pf, testBits); 609 if (testMasks[0] == rMask && testMasks[1] == gMask && 610 testMasks[2] == bMask && 611 // for alpha, deal with 'X8' formats by checking bit counts 612 (testMasks[3] == aMask || (aMask == 0 && testBits[3] == 0))) 613 { 614 return pf; 615 } 616 } 617 618 } 619 620 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Cannot determine pixel format", 621 "DDSCodec::convertPixelFormat"); 622 } 623 //--------------------------------------------------------------------- unpackDXTColour(PixelFormat pf,const DXTColourBlock & block,ColourValue * pCol) const624 void DDSCodec::unpackDXTColour(PixelFormat pf, const DXTColourBlock& block, 625 ColourValue* pCol) const 626 { 627 // Note - we assume all values have already been endian swapped 628 629 // Colour lookup table 630 ColourValue derivedColours[4]; 631 632 if (pf == PF_DXT1 && block.colour_0 <= block.colour_1) 633 { 634 // 1-bit alpha 635 PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0)); 636 PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1)); 637 // one intermediate colour, half way between the other two 638 derivedColours[2] = (derivedColours[0] + derivedColours[1]) / 2; 639 // transparent colour 640 derivedColours[3] = ColourValue::ZERO; 641 } 642 else 643 { 644 PixelUtil::unpackColour(&(derivedColours[0]), PF_R5G6B5, &(block.colour_0)); 645 PixelUtil::unpackColour(&(derivedColours[1]), PF_R5G6B5, &(block.colour_1)); 646 // first interpolated colour, 1/3 of the way along 647 derivedColours[2] = (2 * derivedColours[0] + derivedColours[1]) / 3; 648 // second interpolated colour, 2/3 of the way along 649 derivedColours[3] = (derivedColours[0] + 2 * derivedColours[1]) / 3; 650 } 651 652 // Process 4x4 block of texels 653 for (size_t row = 0; row < 4; ++row) 654 { 655 for (size_t x = 0; x < 4; ++x) 656 { 657 // LSB come first 658 uint8 colIdx = static_cast<uint8>(block.indexRow[row] >> (x * 2) & 0x3); 659 if (pf == PF_DXT1) 660 { 661 // Overwrite entire colour 662 pCol[(row * 4) + x] = derivedColours[colIdx]; 663 } 664 else 665 { 666 // alpha has already been read (alpha precedes colour) 667 ColourValue& col = pCol[(row * 4) + x]; 668 col.r = derivedColours[colIdx].r; 669 col.g = derivedColours[colIdx].g; 670 col.b = derivedColours[colIdx].b; 671 } 672 } 673 674 } 675 676 677 } 678 //--------------------------------------------------------------------- unpackDXTAlpha(const DXTExplicitAlphaBlock & block,ColourValue * pCol) const679 void DDSCodec::unpackDXTAlpha( 680 const DXTExplicitAlphaBlock& block, ColourValue* pCol) const 681 { 682 // Note - we assume all values have already been endian swapped 683 684 // This is an explicit alpha block, 4 bits per pixel, LSB first 685 for (size_t row = 0; row < 4; ++row) 686 { 687 for (size_t x = 0; x < 4; ++x) 688 { 689 // Shift and mask off to 4 bits 690 uint8 val = static_cast<uint8>(block.alphaRow[row] >> (x * 4) & 0xF); 691 // Convert to [0,1] 692 pCol->a = (Real)val / (Real)0xF; 693 pCol++; 694 695 } 696 697 } 698 699 } 700 //--------------------------------------------------------------------- unpackDXTAlpha(const DXTInterpolatedAlphaBlock & block,ColourValue * pCol) const701 void DDSCodec::unpackDXTAlpha( 702 const DXTInterpolatedAlphaBlock& block, ColourValue* pCol) const 703 { 704 // Adaptive 3-bit alpha part 705 float derivedAlphas[8]; 706 707 // Explicit extremes 708 derivedAlphas[0] = ((float) block.alpha_0) * (1.0f / 255.0f); 709 derivedAlphas[1] = ((float) block.alpha_1) * (1.0f / 255.0f); 710 711 if(block.alpha_0 > block.alpha_1) 712 { 713 // 6 interpolated alpha values. 714 // full range including extremes at [0] and [7] 715 // we want to fill in [1] through [6] at weights ranging 716 // from 1/7 to 6/7 717 for(size_t i = 1; i < 7; ++i) 718 derivedAlphas[i + 1] = (derivedAlphas[0] * (7 - i) + derivedAlphas[1] * i) * (1.0f / 7.0f); 719 } 720 else 721 { 722 // 4 interpolated alpha values. 723 // full range including extremes at [0] and [5] 724 // we want to fill in [1] through [4] at weights ranging 725 // from 1/5 to 4/5 726 for(size_t i = 1; i < 5; ++i) 727 derivedAlphas[i + 1] = (derivedAlphas[0] * (5 - i) + derivedAlphas[1] * i) * (1.0f / 5.0f); 728 729 derivedAlphas[6] = 0.0f; 730 derivedAlphas[7] = 1.0f; 731 } 732 733 // Ok, now we've built the reference values, process the indexes 734 uint32 dw = block.indexes[0] | (block.indexes[1] << 8) | (block.indexes[2] << 16); 735 736 for(size_t i = 0; i < 8; ++i, dw >>= 3) 737 pCol[i].a = derivedAlphas[dw & 0x7]; 738 739 dw = block.indexes[3] | (block.indexes[4] << 8) | (block.indexes[5] << 16); 740 741 for(size_t i = 8; i < 16; ++i, dw >>= 3) 742 pCol[i].a = derivedAlphas[dw & 0x7]; 743 } 744 //--------------------------------------------------------------------- decode(const DataStreamPtr & stream) const745 Codec::DecodeResult DDSCodec::decode(const DataStreamPtr& stream) const 746 { 747 // Read 4 character code 748 uint32 fileType; 749 stream->read(&fileType, sizeof(uint32)); 750 flipEndian(&fileType, sizeof(uint32)); 751 752 if (FOURCC('D', 'D', 'S', ' ') != fileType) 753 { 754 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 755 "This is not a DDS file!", "DDSCodec::decode"); 756 } 757 758 // Read header in full 759 DDSHeader header; 760 stream->read(&header, sizeof(DDSHeader)); 761 762 // Endian flip if required, all 32-bit values 763 flipEndian(&header, 4, sizeof(DDSHeader) / 4); 764 765 // Check some sizes 766 if (header.size != DDS_HEADER_SIZE) 767 { 768 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 769 "DDS header size mismatch!", "DDSCodec::decode"); 770 } 771 if (header.pixelFormat.size != DDS_PIXELFORMAT_SIZE) 772 { 773 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 774 "DDS header size mismatch!", "DDSCodec::decode"); 775 } 776 777 ImageData* imgData = OGRE_NEW ImageData(); 778 MemoryDataStreamPtr output; 779 780 imgData->depth = 1; // (deal with volume later) 781 imgData->width = header.width; 782 imgData->height = header.height; 783 size_t numFaces = 1; // assume one face until we know otherwise 784 785 if (header.caps.caps1 & DDSCAPS_MIPMAP) 786 { 787 imgData->num_mipmaps = static_cast<uint8>(header.mipMapCount - 1); 788 } 789 else 790 { 791 imgData->num_mipmaps = 0; 792 } 793 imgData->flags = 0; 794 795 bool decompressDXT = false; 796 // Figure out basic image type 797 if (header.caps.caps2 & DDSCAPS2_CUBEMAP) 798 { 799 imgData->flags |= IF_CUBEMAP; 800 numFaces = 6; 801 } 802 else if (header.caps.caps2 & DDSCAPS2_VOLUME) 803 { 804 imgData->flags |= IF_3D_TEXTURE; 805 imgData->depth = header.depth; 806 } 807 // Pixel format 808 PixelFormat sourceFormat = PF_UNKNOWN; 809 810 if (header.pixelFormat.flags & DDPF_FOURCC) 811 { 812 // Check if we have an DX10 style extended header and read it. This is necessary for B6H and B7 formats 813 if(header.pixelFormat.fourCC == FOURCC('D', 'X', '1', '0')) 814 { 815 DDSExtendedHeader extHeader; 816 stream->read(&extHeader, sizeof(DDSExtendedHeader)); 817 818 // Endian flip if required, all 32-bit values 819 flipEndian(&header, sizeof(DDSExtendedHeader)); 820 sourceFormat = convertDXToOgreFormat(extHeader.dxgiFormat); 821 } 822 else 823 { 824 sourceFormat = convertFourCCFormat(header.pixelFormat.fourCC); 825 } 826 } 827 else 828 { 829 sourceFormat = convertPixelFormat(header.pixelFormat.rgbBits, 830 header.pixelFormat.redMask, header.pixelFormat.greenMask, 831 header.pixelFormat.blueMask, 832 header.pixelFormat.flags & DDPF_ALPHAPIXELS ? 833 header.pixelFormat.alphaMask : 0); 834 } 835 836 if (PixelUtil::isCompressed(sourceFormat)) 837 { 838 if (Root::getSingleton().getRenderSystem() == NULL || 839 !Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_TEXTURE_COMPRESSION_DXT) 840 || (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_AUTOMIPMAP_COMPRESSED) 841 && !imgData->num_mipmaps)) 842 { 843 // We'll need to decompress 844 decompressDXT = true; 845 // Convert format 846 switch (sourceFormat) 847 { 848 case PF_DXT1: 849 // source can be either 565 or 5551 depending on whether alpha present 850 // unfortunately you have to read a block to figure out which 851 // Note that we upgrade to 32-bit pixel formats here, even 852 // though the source is 16-bit; this is because the interpolated 853 // values will benefit from the 32-bit results, and the source 854 // from which the 16-bit samples are calculated may have been 855 // 32-bit so can benefit from this. 856 DXTColourBlock block; 857 stream->read(&block, sizeof(DXTColourBlock)); 858 flipEndian(&(block.colour_0), sizeof(uint16)); 859 flipEndian(&(block.colour_1), sizeof(uint16)); 860 // skip back since we'll need to read this again 861 stream->skip(0 - (long)sizeof(DXTColourBlock)); 862 // colour_0 <= colour_1 means transparency in DXT1 863 if (block.colour_0 <= block.colour_1) 864 { 865 imgData->format = PF_BYTE_RGBA; 866 } 867 else 868 { 869 imgData->format = PF_BYTE_RGB; 870 } 871 break; 872 case PF_DXT2: 873 case PF_DXT3: 874 case PF_DXT4: 875 case PF_DXT5: 876 // full alpha present, formats vary only in encoding 877 imgData->format = PF_BYTE_RGBA; 878 break; 879 default: 880 // all other cases need no special format handling 881 break; 882 } 883 } 884 else 885 { 886 // Use original format 887 imgData->format = sourceFormat; 888 // Keep DXT data compressed 889 imgData->flags |= IF_COMPRESSED; 890 } 891 } 892 else // not compressed 893 { 894 // Don't test against DDPF_RGB since greyscale DDS doesn't set this 895 // just derive any other kind of format 896 imgData->format = sourceFormat; 897 } 898 899 // Calculate total size from number of mipmaps, faces and size 900 imgData->size = Image::calculateSize(imgData->num_mipmaps, numFaces, 901 imgData->width, imgData->height, imgData->depth, imgData->format); 902 903 // Bind output buffer 904 output.reset(OGRE_NEW MemoryDataStream(imgData->size)); 905 906 907 // Now deal with the data 908 void* destPtr = output->getPtr(); 909 910 // all mips for a face, then each face 911 for(size_t i = 0; i < numFaces; ++i) 912 { 913 uint32 width = imgData->width; 914 uint32 height = imgData->height; 915 uint32 depth = imgData->depth; 916 917 for(size_t mip = 0; mip <= imgData->num_mipmaps; ++mip) 918 { 919 size_t dstPitch = width * PixelUtil::getNumElemBytes(imgData->format); 920 921 if (PixelUtil::isCompressed(sourceFormat)) 922 { 923 // Compressed data 924 if (decompressDXT) 925 { 926 DXTColourBlock col; 927 DXTInterpolatedAlphaBlock iAlpha; 928 DXTExplicitAlphaBlock eAlpha; 929 // 4x4 block of decompressed colour 930 ColourValue tempColours[16]; 931 size_t destBpp = PixelUtil::getNumElemBytes(imgData->format); 932 933 // slices are done individually 934 for(size_t z = 0; z < depth; ++z) 935 { 936 size_t remainingHeight = height; 937 938 // 4x4 blocks in x/y 939 for (size_t y = 0; y < height; y += 4) 940 { 941 size_t sy = std::min<size_t>( remainingHeight, 4u ); 942 remainingHeight -= sy; 943 944 size_t remainingWidth = width; 945 946 for (size_t x = 0; x < width; x += 4) 947 { 948 size_t sx = std::min<size_t>( remainingWidth, 4u ); 949 size_t destPitchMinus4 = dstPitch - destBpp * sx; 950 951 remainingWidth -= sx; 952 953 if (sourceFormat == PF_DXT2 || 954 sourceFormat == PF_DXT3) 955 { 956 // explicit alpha 957 stream->read(&eAlpha, sizeof(DXTExplicitAlphaBlock)); 958 flipEndian(eAlpha.alphaRow, sizeof(uint16), 4); 959 unpackDXTAlpha(eAlpha, tempColours) ; 960 } 961 else if (sourceFormat == PF_DXT4 || 962 sourceFormat == PF_DXT5) 963 { 964 // interpolated alpha 965 stream->read(&iAlpha, sizeof(DXTInterpolatedAlphaBlock)); 966 flipEndian(&(iAlpha.alpha_0), sizeof(uint16)); 967 flipEndian(&(iAlpha.alpha_1), sizeof(uint16)); 968 unpackDXTAlpha(iAlpha, tempColours) ; 969 } 970 // always read colour 971 stream->read(&col, sizeof(DXTColourBlock)); 972 flipEndian(&(col.colour_0), sizeof(uint16)); 973 flipEndian(&(col.colour_1), sizeof(uint16)); 974 unpackDXTColour(sourceFormat, col, tempColours); 975 976 // write 4x4 block to uncompressed version 977 for (size_t by = 0; by < sy; ++by) 978 { 979 for (size_t bx = 0; bx < sx; ++bx) 980 { 981 PixelUtil::packColour(tempColours[by*4+bx], 982 imgData->format, destPtr); 983 destPtr = static_cast<void*>( 984 static_cast<uchar*>(destPtr) + destBpp); 985 } 986 // advance to next row 987 destPtr = static_cast<void*>( 988 static_cast<uchar*>(destPtr) + destPitchMinus4); 989 } 990 // next block. Our dest pointer is 4 lines down 991 // from where it started 992 if (x + 4 >= width) 993 { 994 // Jump back to the start of the line 995 destPtr = static_cast<void*>( 996 static_cast<uchar*>(destPtr) - destPitchMinus4); 997 } 998 else 999 { 1000 // Jump back up 4 rows and 4 pixels to the 1001 // right to be at the next block to the right 1002 destPtr = static_cast<void*>( 1003 static_cast<uchar*>(destPtr) - dstPitch * sy + destBpp * sx); 1004 1005 } 1006 1007 } 1008 1009 } 1010 } 1011 1012 } 1013 else 1014 { 1015 // load directly 1016 // DDS format lies! sizeOrPitch is not always set for DXT!! 1017 size_t dxtSize = PixelUtil::getMemorySize(width, height, depth, imgData->format); 1018 stream->read(destPtr, dxtSize); 1019 destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dxtSize); 1020 } 1021 1022 } 1023 else 1024 { 1025 // Note: We assume the source and destination have the same pitch 1026 for (size_t z = 0; z < depth; ++z) 1027 { 1028 for (size_t y = 0; y < height; ++y) 1029 { 1030 stream->read(destPtr, dstPitch); 1031 destPtr = static_cast<void*>(static_cast<uchar*>(destPtr) + dstPitch); 1032 } 1033 } 1034 } 1035 1036 /// Next mip 1037 if(width!=1) width /= 2; 1038 if(height!=1) height /= 2; 1039 if(depth!=1) depth /= 2; 1040 } 1041 1042 } 1043 1044 DecodeResult ret; 1045 ret.first = output; 1046 ret.second = CodecDataPtr(imgData); 1047 return ret; 1048 1049 1050 1051 } 1052 //--------------------------------------------------------------------- getType() const1053 String DDSCodec::getType() const 1054 { 1055 return mType; 1056 } 1057 //--------------------------------------------------------------------- flipEndian(void * pData,size_t size,size_t count)1058 void DDSCodec::flipEndian(void * pData, size_t size, size_t count) 1059 { 1060 #if OGRE_ENDIAN == OGRE_ENDIAN_BIG 1061 Bitwise::bswapChunks(pData, size, count); 1062 #endif 1063 } 1064 //--------------------------------------------------------------------- flipEndian(void * pData,size_t size)1065 void DDSCodec::flipEndian(void * pData, size_t size) 1066 { 1067 #if OGRE_ENDIAN == OGRE_ENDIAN_BIG 1068 Bitwise::bswapBuffer(pData, size); 1069 #endif 1070 } 1071 //--------------------------------------------------------------------- magicNumberToFileExt(const char * magicNumberPtr,size_t maxbytes) const1072 String DDSCodec::magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const 1073 { 1074 if (maxbytes >= sizeof(uint32)) 1075 { 1076 uint32 fileType; 1077 memcpy(&fileType, magicNumberPtr, sizeof(uint32)); 1078 flipEndian(&fileType, sizeof(uint32)); 1079 1080 if (DDS_MAGIC == fileType) 1081 { 1082 return String("dds"); 1083 } 1084 } 1085 1086 return BLANKSTRING; 1087 1088 } 1089 1090 } 1091 1092