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 }