1 /* 2 Copyright (c) 2019 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.resource.dds; 29 30 import std.stdio; 31 import std.file; 32 33 import dlib.core.memory; 34 import dlib.core.stream; 35 import dlib.core.compound; 36 import dlib.image.color; 37 import dlib.image.image; 38 import dlib.image.io.utils; 39 40 import dagon.graphics.compressedimage; 41 42 //version = DDSPDebug; 43 44 struct DDSPixelFormat 45 { 46 uint size; 47 uint flags; 48 uint fourCC; 49 uint bpp; 50 uint redMask; 51 uint greenMask; 52 uint blueMask; 53 uint alphaMask; 54 } 55 56 struct DDSCaps 57 { 58 uint caps; 59 uint caps2; 60 uint caps3; 61 uint caps4; 62 } 63 64 struct DDSColorKey 65 { 66 uint lowVal; 67 uint highVal; 68 } 69 70 struct DDSHeader 71 { 72 uint size; 73 uint flags; 74 uint height; 75 uint width; 76 uint pitch; 77 uint depth; 78 uint mipMapLevels; 79 uint alphaBitDepth; 80 uint reserved; 81 uint surface; 82 83 DDSColorKey ckDestOverlay; 84 DDSColorKey ckDestBlt; 85 DDSColorKey ckSrcOverlay; 86 DDSColorKey ckSrcBlt; 87 88 DDSPixelFormat format; 89 DDSCaps caps; 90 91 uint textureStage; 92 } 93 94 enum DXGIFormat 95 { 96 UNKNOWN = 0, 97 R32G32B32A32_TYPELESS = 1, 98 R32G32B32A32_FLOAT = 2, 99 R32G32B32A32_UINT = 3, 100 R32G32B32A32_SINT = 4, 101 R32G32B32_TYPELESS = 5, 102 R32G32B32_FLOAT = 6, 103 R32G32B32_UINT = 7, 104 R32G32B32_SINT = 8, 105 R16G16B16A16_TYPELESS = 9, 106 R16G16B16A16_FLOAT = 10, 107 R16G16B16A16_UNORM = 11, 108 R16G16B16A16_UINT = 12, 109 R16G16B16A16_SNORM = 13, 110 R16G16B16A16_SINT = 14, 111 R32G32_TYPELESS = 15, 112 R32G32_FLOAT = 16, 113 R32G32_UINT = 17, 114 R32G32_SINT = 18, 115 R32G8X24_TYPELESS = 19, 116 D32_FLOAT_S8X24_UINT = 20, 117 R32_FLOAT_X8X24_TYPELESS = 21, 118 X32_TYPELESS_G8X24_UINT = 22, 119 R10G10B10A2_TYPELESS = 23, 120 R10G10B10A2_UNORM = 24, 121 R10G10B10A2_UINT = 25, 122 R11G11B10_FLOAT = 26, 123 R8G8B8A8_TYPELESS = 27, 124 R8G8B8A8_UNORM = 28, 125 R8G8B8A8_UNORM_SRGB = 29, 126 R8G8B8A8_UINT = 30, 127 R8G8B8A8_SNORM = 31, 128 R8G8B8A8_SINT = 32, 129 R16G16_TYPELESS = 33, 130 R16G16_FLOAT = 34, 131 R16G16_UNORM = 35, 132 R16G16_UINT = 36, 133 R16G16_SNORM = 37, 134 R16G16_SINT = 38, 135 R32_TYPELESS = 39, 136 D32_FLOAT = 40, 137 R32_FLOAT = 41, 138 R32_UINT = 42, 139 R32_SINT = 43, 140 R24G8_TYPELESS = 44, 141 D24_UNORM_S8_UINT = 45, 142 R24_UNORM_X8_TYPELESS = 46, 143 X24_TYPELESS_G8_UINT = 47, 144 R8G8_TYPELESS = 48, 145 R8G8_UNORM = 49, 146 R8G8_UINT = 50, 147 R8G8_SNORM = 51, 148 R8G8_SINT = 52, 149 R16_TYPELESS = 53, 150 R16_FLOAT = 54, 151 D16_UNORM = 55, 152 R16_UNORM = 56, 153 R16_UINT = 57, 154 R16_SNORM = 58, 155 R16_SINT = 59, 156 R8_TYPELESS = 60, 157 R8_UNORM = 61, 158 R8_UINT = 62, 159 R8_SNORM = 63, 160 R8_SINT = 64, 161 A8_UNORM = 65, 162 R1_UNORM = 66, 163 R9G9B9E5_SHAREDEXP = 67, 164 R8G8_B8G8_UNORM = 68, 165 G8R8_G8B8_UNORM = 69, 166 BC1_TYPELESS = 70, 167 BC1_UNORM = 71, 168 BC1_UNORM_SRGB = 72, 169 BC2_TYPELESS = 73, 170 BC2_UNORM = 74, 171 BC2_UNORM_SRGB = 75, 172 BC3_TYPELESS = 76, 173 BC3_UNORM = 77, 174 BC3_UNORM_SRGB = 78, 175 BC4_TYPELESS = 79, 176 BC4_UNORM = 80, 177 BC4_SNORM = 81, 178 BC5_TYPELESS = 82, 179 BC5_UNORM = 83, 180 BC5_SNORM = 84, 181 B5G6R5_UNORM = 85, 182 B5G5R5A1_UNORM = 86, 183 B8G8R8A8_UNORM = 87, 184 B8G8R8X8_UNORM = 88, 185 R10G10B10_XR_BIAS_A2_UNORM = 89, 186 B8G8R8A8_TYPELESS = 90, 187 B8G8R8A8_UNORM_SRGB = 91, 188 B8G8R8X8_TYPELESS = 92, 189 B8G8R8X8_UNORM_SRGB = 93, 190 BC6H_TYPELESS = 94, 191 BC6H_UF16 = 95, 192 BC6H_SF16 = 96, 193 BC7_TYPELESS = 97, 194 BC7_UNORM = 98, 195 BC7_UNORM_SRGB = 99, 196 AYUV = 100, 197 Y410 = 101, 198 Y416 = 102, 199 NV12 = 103, 200 P010 = 104, 201 P016 = 105, 202 OPAQUE_420 = 106, 203 YUY2 = 107, 204 Y210 = 108, 205 Y216 = 109, 206 NV11 = 110, 207 AI44 = 111, 208 IA44 = 112, 209 P8 = 113, 210 A8P8 = 114, 211 B4G4R4A4_UNORM = 115, 212 P208 = 130, 213 V208 = 131, 214 V408 = 132 215 } 216 217 enum D3D10ResourceDimension 218 { 219 Unknown, 220 Buffer, 221 Texture1D, 222 Texture2D, 223 Texture3D 224 } 225 226 struct DDSHeaderDXT10 227 { 228 uint dxgiFormat; 229 uint resourceDimension; 230 uint miscFlag; 231 uint arraySize; 232 uint miscFlags2; 233 } 234 235 uint makeFourCC(char ch0, char ch1, char ch2, char ch3) 236 { 237 return 238 ((cast(uint)ch3 << 24) & 0xFF000000) | 239 ((cast(uint)ch2 << 16) & 0x00FF0000) | 240 ((cast(uint)ch1 << 8) & 0x0000FF00) | 241 ((cast(uint)ch0) & 0x000000FF); 242 } 243 244 enum FOURCC_DXT1 = makeFourCC('D', 'X', 'T', '1'); 245 enum FOURCC_DXT3 = makeFourCC('D', 'X', 'T', '3'); 246 enum FOURCC_DXT5 = makeFourCC('D', 'X', 'T', '5'); 247 enum FOURCC_DX10 = makeFourCC('D', 'X', '1', '0'); 248 249 Compound!(CompressedImage, string) loadDDS(InputStream istrm) 250 { 251 CompressedImage img = null; 252 253 void finalize() 254 { 255 } 256 257 Compound!(CompressedImage, string) error(string errorMsg) 258 { 259 finalize(); 260 if (img) 261 { 262 Delete(img); 263 img = null; 264 } 265 return compound(img, errorMsg); 266 } 267 268 char[4] magic; 269 270 if (!istrm.fillArray(magic)) 271 { 272 return error("loadDDS error: not a DDS file or corrupt data"); 273 } 274 275 version(DDSDebug) 276 { 277 writeln("Signature: ", magic); 278 } 279 280 if (magic != "DDS ") 281 { 282 return error("loadDDS error: not a DDS file"); 283 } 284 285 DDSHeader hdr = readStruct!DDSHeader(istrm); 286 287 version(DDSDebug) 288 { 289 writeln("hdr.size: ", hdr.size); 290 writeln("hdr.flags: ", hdr.flags); 291 writeln("hdr.height: ", hdr.height); 292 writeln("hdr.width: ", hdr.width); 293 writeln("hdr.pitch: ", hdr.pitch); 294 writeln("hdr.depth: ", hdr.depth); 295 writeln("hdr.mipMapLevels: ", hdr.mipMapLevels); 296 writeln("hdr.alphaBitDepth: ", hdr.alphaBitDepth); 297 writeln("hdr.reserved: ", hdr.reserved); 298 writeln("hdr.surface: ", hdr.surface); 299 300 writeln("hdr.ckDestOverlay.lowVal: ", hdr.ckDestOverlay.lowVal); 301 writeln("hdr.ckDestOverlay.highVal: ", hdr.ckDestOverlay.highVal); 302 writeln("hdr.ckDestBlt.lowVal: ", hdr.ckDestBlt.lowVal); 303 writeln("hdr.ckDestBlt.highVal: ", hdr.ckDestBlt.highVal); 304 writeln("hdr.ckSrcOverlay.lowVal: ", hdr.ckSrcOverlay.lowVal); 305 writeln("hdr.ckSrcOverlay.highVal: ", hdr.ckSrcOverlay.highVal); 306 writeln("hdr.ckSrcBlt.lowVal: ", hdr.ckSrcBlt.lowVal); 307 writeln("hdr.ckSrcBlt.highVal: ", hdr.ckSrcBlt.highVal); 308 309 writeln("hdr.format.size: ", hdr.format.size); 310 writeln("hdr.format.flags: ", hdr.format.flags); 311 writeln("hdr.format.fourCC: ", hdr.format.fourCC); 312 writeln("hdr.format.bpp: ", hdr.format.bpp); 313 writeln("hdr.format.redMask: ", hdr.format.redMask); 314 writeln("hdr.format.greenMask: ", hdr.format.greenMask); 315 writeln("hdr.format.blueMask: ", hdr.format.blueMask); 316 writeln("hdr.format.alphaMask: ", hdr.format.alphaMask); 317 318 writeln("hdr.caps.caps: ", hdr.caps.caps); 319 writeln("hdr.caps.caps2: ", hdr.caps.caps2); 320 writeln("hdr.caps.caps3: ", hdr.caps.caps3); 321 writeln("hdr.caps.caps4: ", hdr.caps.caps4); 322 323 writeln("hdr.textureStage: ", hdr.textureStage); 324 } 325 326 CompressedImageFormat format; 327 328 if (hdr.format.fourCC == FOURCC_DX10) 329 { 330 DDSHeaderDXT10 dx10 = readStruct!DDSHeaderDXT10(istrm); 331 332 DXGIFormat fmt = cast(DXGIFormat)dx10.dxgiFormat; 333 version(DDSDebug) writeln(fmt); 334 335 switch(fmt) 336 { 337 case DXGIFormat.BC4_UNORM: 338 format = CompressedImageFormat.RGTC1_R; 339 break; 340 case DXGIFormat.BC4_SNORM: 341 format = CompressedImageFormat.RGTC1_R_S; 342 break; 343 case DXGIFormat.BC5_UNORM: 344 format = CompressedImageFormat.RGTC2_RG; 345 break; 346 case DXGIFormat.BC5_SNORM: 347 format = CompressedImageFormat.RGTC2_RG_S; 348 break; 349 case DXGIFormat.BC7_UNORM: 350 format = CompressedImageFormat.BPTC_RGBA_UNORM; 351 break; 352 case DXGIFormat.BC7_UNORM_SRGB: 353 format = CompressedImageFormat.BPTC_SRGBA_UNORM; 354 break; 355 case DXGIFormat.BC6H_SF16: 356 format = CompressedImageFormat.BPTC_RGB_SF; 357 break; 358 case DXGIFormat.BC6H_UF16: 359 format = CompressedImageFormat.BPTC_RGB_UF; 360 break; 361 default: 362 return error("loadDDS error: unsupported compression type"); 363 } 364 } 365 else 366 { 367 switch(hdr.format.fourCC) 368 { 369 case FOURCC_DXT1: 370 version(DDSDebug) writeln("FOURCC_DXT1"); 371 format = CompressedImageFormat.S3TC_RGB_DXT1; 372 break; 373 case FOURCC_DXT3: 374 version(DDSDebug) writeln("FOURCC_DXT3"); 375 format = CompressedImageFormat.S3TC_RGBA_DXT3; 376 break; 377 case FOURCC_DXT5: 378 version(DDSDebug) writeln("FOURCC_DXT5"); 379 format = CompressedImageFormat.S3TC_RGBA_DXT5; 380 break; 381 default: 382 return error("loadDDS error: unsupported compression type"); 383 } 384 } 385 386 size_t bufferSize = cast(size_t)(istrm.size - istrm.getPosition); 387 version(DDSDebug) writeln("bufferSize: ", bufferSize); 388 389 img = New!CompressedImage(hdr.width, hdr.height, format, hdr.mipMapLevels, bufferSize); 390 istrm.readBytes(img.data.ptr, bufferSize); 391 392 return compound(img, ""); 393 }