OSDN Git Service

Boost.MSMでメニュー部分を実装
[shooting3/shootinggame.git] / ShootingGame / DDSTextureLoader.cpp
1 //--------------------------------------------------------------------------------------
2 // File: DDSTextureLoader.cpp
3 //
4 // Function for loading a DDS texture and creating a Direct3D 11 runtime resource for it
5 //
6 // Note this function is useful as a light-weight runtime loader for DDS files. For
7 // a full-featured DDS file reader, writer, and texture processing pipeline see
8 // the 'Texconv' sample and the 'DirectXTex' library.
9 //
10 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
11 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
12 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
13 // PARTICULAR PURPOSE.
14 //
15 // Copyright (c) Microsoft Corporation. All rights reserved.
16 //--------------------------------------------------------------------------------------
17
18 #include "pch.h"
19 #include <dxgiformat.h>
20 #include <assert.h>
21 #include <memory>
22 #include <algorithm>
23 #include "DDSTextureLoader.h"
24 #include "DirectXSample.h"
25
26 using namespace Microsoft::WRL;
27
28 //--------------------------------------------------------------------------------------
29 // Macros
30 //--------------------------------------------------------------------------------------
31 #ifndef MAKEFOURCC
32     #define MAKEFOURCC(ch0, ch1, ch2, ch3)                              \
33                 ((uint32)(byte)(ch0) | ((uint32)(byte)(ch1) << 8) |       \
34                 ((uint32)(byte)(ch2) << 16) | ((uint32)(byte)(ch3) << 24))
35 #endif /* defined(MAKEFOURCC) */
36
37 //--------------------------------------------------------------------------------------
38 // DDS file structure definitions
39 //
40 // See DDS.h in the 'Texconv' sample and the 'DirectXTex' library
41 //--------------------------------------------------------------------------------------
42 #pragma pack(push, 1)
43
44 #define DDS_MAGIC 0x20534444 // "DDS "
45
46 struct DDS_PIXELFORMAT
47 {
48     uint32  size;
49     uint32  flags;
50     uint32  fourCC;
51     uint32  RGBBitCount;
52     uint32  RBitMask;
53     uint32  GBitMask;
54     uint32  BBitMask;
55     uint32  ABitMask;
56 };
57
58 #define DDS_FOURCC      0x00000004  // DDPF_FOURCC
59 #define DDS_RGB         0x00000040  // DDPF_RGB
60 #define DDS_RGBA        0x00000041  // DDPF_RGB | DDPF_ALPHAPIXELS
61 #define DDS_LUMINANCE   0x00020000  // DDPF_LUMINANCE
62 #define DDS_LUMINANCEA  0x00020001  // DDPF_LUMINANCE | DDPF_ALPHAPIXELS
63 #define DDS_ALPHA       0x00000002  // DDPF_ALPHA
64 #define DDS_PAL8        0x00000020  // DDPF_PALETTEINDEXED8
65
66 #define DDS_HEADER_FLAGS_TEXTURE        0x00001007  // DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_PIXELFORMAT
67 #define DDS_HEADER_FLAGS_MIPMAP         0x00020000  // DDSD_MIPMAPCOUNT
68 #define DDS_HEADER_FLAGS_VOLUME         0x00800000  // DDSD_DEPTH
69 #define DDS_HEADER_FLAGS_PITCH          0x00000008  // DDSD_PITCH
70 #define DDS_HEADER_FLAGS_LINEARSIZE     0x00080000  // DDSD_LINEARSIZE
71
72 #define DDS_HEIGHT 0x00000002 // DDSD_HEIGHT
73 #define DDS_WIDTH  0x00000004 // DDSD_WIDTH
74
75 #define DDS_SURFACE_FLAGS_TEXTURE 0x00001000 // DDSCAPS_TEXTURE
76 #define DDS_SURFACE_FLAGS_MIPMAP  0x00400008 // DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
77 #define DDS_SURFACE_FLAGS_CUBEMAP 0x00000008 // DDSCAPS_COMPLEX
78
79 #define DDS_CUBEMAP_POSITIVEX 0x00000600 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEX
80 #define DDS_CUBEMAP_NEGATIVEX 0x00000a00 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEX
81 #define DDS_CUBEMAP_POSITIVEY 0x00001200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEY
82 #define DDS_CUBEMAP_NEGATIVEY 0x00002200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEY
83 #define DDS_CUBEMAP_POSITIVEZ 0x00004200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_POSITIVEZ
84 #define DDS_CUBEMAP_NEGATIVEZ 0x00008200 // DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_NEGATIVEZ
85
86 #define DDS_CUBEMAP_ALLFACES (DDS_CUBEMAP_POSITIVEX | DDS_CUBEMAP_NEGATIVEX |\
87                               DDS_CUBEMAP_POSITIVEY | DDS_CUBEMAP_NEGATIVEY |\
88                               DDS_CUBEMAP_POSITIVEZ | DDS_CUBEMAP_NEGATIVEZ)
89
90 #define DDS_CUBEMAP 0x00000200 // DDSCAPS2_CUBEMAP
91
92 #define DDS_FLAGS_VOLUME 0x00200000 // DDSCAPS2_VOLUME
93
94 typedef struct
95 {
96     uint32          size;
97     uint32          flags;
98     uint32          height;
99     uint32          width;
100     uint32          pitchOrLinearSize;
101     uint32          depth; // only if DDS_HEADER_FLAGS_VOLUME is set in flags
102     uint32          mipMapCount;
103     uint32          reserved1[11];
104     DDS_PIXELFORMAT ddspf;
105     uint32          caps;
106     uint32          caps2;
107     uint32          caps3;
108     uint32          caps4;
109     uint32          reserved2;
110 } DDS_HEADER;
111
112 typedef struct
113 {
114     DXGI_FORMAT dxgiFormat;
115     uint32      resourceDimension;
116     uint32      miscFlag; // see D3D11_RESOURCE_MISC_FLAG
117     uint32      arraySize;
118     uint32      reserved;
119 } DDS_HEADER_DXT10;
120
121 #pragma pack(pop)
122
123 //--------------------------------------------------------------------------------------
124 // Return the BPP for a particular format
125 //--------------------------------------------------------------------------------------
126 static size_t BitsPerPixel(_In_ DXGI_FORMAT fmt)
127 {
128     switch (fmt)
129     {
130     case DXGI_FORMAT_R32G32B32A32_TYPELESS:
131     case DXGI_FORMAT_R32G32B32A32_FLOAT:
132     case DXGI_FORMAT_R32G32B32A32_UINT:
133     case DXGI_FORMAT_R32G32B32A32_SINT:
134         return 128;
135
136     case DXGI_FORMAT_R32G32B32_TYPELESS:
137     case DXGI_FORMAT_R32G32B32_FLOAT:
138     case DXGI_FORMAT_R32G32B32_UINT:
139     case DXGI_FORMAT_R32G32B32_SINT:
140         return 96;
141
142     case DXGI_FORMAT_R16G16B16A16_TYPELESS:
143     case DXGI_FORMAT_R16G16B16A16_FLOAT:
144     case DXGI_FORMAT_R16G16B16A16_UNORM:
145     case DXGI_FORMAT_R16G16B16A16_UINT:
146     case DXGI_FORMAT_R16G16B16A16_SNORM:
147     case DXGI_FORMAT_R16G16B16A16_SINT:
148     case DXGI_FORMAT_R32G32_TYPELESS:
149     case DXGI_FORMAT_R32G32_FLOAT:
150     case DXGI_FORMAT_R32G32_UINT:
151     case DXGI_FORMAT_R32G32_SINT:
152     case DXGI_FORMAT_R32G8X24_TYPELESS:
153     case DXGI_FORMAT_D32_FLOAT_S8X24_UINT:
154     case DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS:
155     case DXGI_FORMAT_X32_TYPELESS_G8X24_UINT:
156         return 64;
157
158     case DXGI_FORMAT_R10G10B10A2_TYPELESS:
159     case DXGI_FORMAT_R10G10B10A2_UNORM:
160     case DXGI_FORMAT_R10G10B10A2_UINT:
161     case DXGI_FORMAT_R11G11B10_FLOAT:
162     case DXGI_FORMAT_R8G8B8A8_TYPELESS:
163     case DXGI_FORMAT_R8G8B8A8_UNORM:
164     case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
165     case DXGI_FORMAT_R8G8B8A8_UINT:
166     case DXGI_FORMAT_R8G8B8A8_SNORM:
167     case DXGI_FORMAT_R8G8B8A8_SINT:
168     case DXGI_FORMAT_R16G16_TYPELESS:
169     case DXGI_FORMAT_R16G16_FLOAT:
170     case DXGI_FORMAT_R16G16_UNORM:
171     case DXGI_FORMAT_R16G16_UINT:
172     case DXGI_FORMAT_R16G16_SNORM:
173     case DXGI_FORMAT_R16G16_SINT:
174     case DXGI_FORMAT_R32_TYPELESS:
175     case DXGI_FORMAT_D32_FLOAT:
176     case DXGI_FORMAT_R32_FLOAT:
177     case DXGI_FORMAT_R32_UINT:
178     case DXGI_FORMAT_R32_SINT:
179     case DXGI_FORMAT_R24G8_TYPELESS:
180     case DXGI_FORMAT_D24_UNORM_S8_UINT:
181     case DXGI_FORMAT_R24_UNORM_X8_TYPELESS:
182     case DXGI_FORMAT_X24_TYPELESS_G8_UINT:
183     case DXGI_FORMAT_R9G9B9E5_SHAREDEXP:
184     case DXGI_FORMAT_R8G8_B8G8_UNORM:
185     case DXGI_FORMAT_G8R8_G8B8_UNORM:
186     case DXGI_FORMAT_B8G8R8A8_UNORM:
187     case DXGI_FORMAT_B8G8R8X8_UNORM:
188     case DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM:
189     case DXGI_FORMAT_B8G8R8A8_TYPELESS:
190     case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
191     case DXGI_FORMAT_B8G8R8X8_TYPELESS:
192     case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
193         return 32;
194
195     case DXGI_FORMAT_R8G8_TYPELESS:
196     case DXGI_FORMAT_R8G8_UNORM:
197     case DXGI_FORMAT_R8G8_UINT:
198     case DXGI_FORMAT_R8G8_SNORM:
199     case DXGI_FORMAT_R8G8_SINT:
200     case DXGI_FORMAT_R16_TYPELESS:
201     case DXGI_FORMAT_R16_FLOAT:
202     case DXGI_FORMAT_D16_UNORM:
203     case DXGI_FORMAT_R16_UNORM:
204     case DXGI_FORMAT_R16_UINT:
205     case DXGI_FORMAT_R16_SNORM:
206     case DXGI_FORMAT_R16_SINT:
207     case DXGI_FORMAT_B5G6R5_UNORM:
208     case DXGI_FORMAT_B5G5R5A1_UNORM:
209     case DXGI_FORMAT_B4G4R4A4_UNORM:
210         return 16;
211
212     case DXGI_FORMAT_R8_TYPELESS:
213     case DXGI_FORMAT_R8_UNORM:
214     case DXGI_FORMAT_R8_UINT:
215     case DXGI_FORMAT_R8_SNORM:
216     case DXGI_FORMAT_R8_SINT:
217     case DXGI_FORMAT_A8_UNORM:
218         return 8;
219
220     case DXGI_FORMAT_R1_UNORM:
221         return 1;
222
223     case DXGI_FORMAT_BC1_TYPELESS:
224     case DXGI_FORMAT_BC1_UNORM:
225     case DXGI_FORMAT_BC1_UNORM_SRGB:
226     case DXGI_FORMAT_BC4_TYPELESS:
227     case DXGI_FORMAT_BC4_UNORM:
228     case DXGI_FORMAT_BC4_SNORM:
229         return 4;
230
231     case DXGI_FORMAT_BC2_TYPELESS:
232     case DXGI_FORMAT_BC2_UNORM:
233     case DXGI_FORMAT_BC2_UNORM_SRGB:
234     case DXGI_FORMAT_BC3_TYPELESS:
235     case DXGI_FORMAT_BC3_UNORM:
236     case DXGI_FORMAT_BC3_UNORM_SRGB:
237     case DXGI_FORMAT_BC5_TYPELESS:
238     case DXGI_FORMAT_BC5_UNORM:
239     case DXGI_FORMAT_BC5_SNORM:
240     case DXGI_FORMAT_BC6H_TYPELESS:
241     case DXGI_FORMAT_BC6H_UF16:
242     case DXGI_FORMAT_BC6H_SF16:
243     case DXGI_FORMAT_BC7_TYPELESS:
244     case DXGI_FORMAT_BC7_UNORM:
245     case DXGI_FORMAT_BC7_UNORM_SRGB:
246         return 8;
247
248     default:
249         return 0;
250     }
251 }
252
253
254 //--------------------------------------------------------------------------------------
255 // Get surface information for a particular format
256 //--------------------------------------------------------------------------------------
257 static void GetSurfaceInfo(
258     _In_ size_t width,
259     _In_ size_t height,
260     _In_ DXGI_FORMAT fmt,
261     _Out_opt_ size_t* outNumBytes,
262     _Out_opt_ size_t* outRowBytes,
263     _Out_opt_ size_t* outNumRows
264     )
265 {
266     size_t numBytes = 0;
267     size_t rowBytes = 0;
268     size_t numRows = 0;
269
270     bool bc = false;
271     bool packed  = false;
272     size_t bcnumBytesPerBlock = 0;
273     switch (fmt)
274     {
275     case DXGI_FORMAT_BC1_TYPELESS:
276     case DXGI_FORMAT_BC1_UNORM:
277     case DXGI_FORMAT_BC1_UNORM_SRGB:
278     case DXGI_FORMAT_BC4_TYPELESS:
279     case DXGI_FORMAT_BC4_UNORM:
280     case DXGI_FORMAT_BC4_SNORM:
281         bc = true;
282         bcnumBytesPerBlock = 8;
283         break;
284
285     case DXGI_FORMAT_BC2_TYPELESS:
286     case DXGI_FORMAT_BC2_UNORM:
287     case DXGI_FORMAT_BC2_UNORM_SRGB:
288     case DXGI_FORMAT_BC3_TYPELESS:
289     case DXGI_FORMAT_BC3_UNORM:
290     case DXGI_FORMAT_BC3_UNORM_SRGB:
291     case DXGI_FORMAT_BC5_TYPELESS:
292     case DXGI_FORMAT_BC5_UNORM:
293     case DXGI_FORMAT_BC5_SNORM:
294     case DXGI_FORMAT_BC6H_TYPELESS:
295     case DXGI_FORMAT_BC6H_UF16:
296     case DXGI_FORMAT_BC6H_SF16:
297     case DXGI_FORMAT_BC7_TYPELESS:
298     case DXGI_FORMAT_BC7_UNORM:
299     case DXGI_FORMAT_BC7_UNORM_SRGB:
300         bc = true;
301         bcnumBytesPerBlock = 16;
302         break;
303
304     case DXGI_FORMAT_R8G8_B8G8_UNORM:
305     case DXGI_FORMAT_G8R8_G8B8_UNORM:
306         packed = true;
307         break;
308     }
309
310     if (bc)
311     {
312         size_t numBlocksWide = 0;
313         if (width > 0)
314         {
315             numBlocksWide = std::max<size_t>(1, (width + 3) / 4);
316         }
317         size_t numBlocksHigh = 0;
318         if (height > 0)
319         {
320             numBlocksHigh = std::max<size_t>(1, (height + 3) / 4);
321         }
322         rowBytes = numBlocksWide * bcnumBytesPerBlock;
323         numRows = numBlocksHigh;
324     }
325     else if (packed)
326     {
327         rowBytes = ((width + 1) >> 1) * 4;
328         numRows = height;
329     }
330     else
331     {
332         size_t bpp = BitsPerPixel(fmt);
333         rowBytes = (width * bpp + 7) / 8; // round up to nearest byte
334         numRows = height;
335     }
336
337     numBytes = rowBytes * numRows;
338     if (outNumBytes)
339     {
340         *outNumBytes = numBytes;
341     }
342     if (outRowBytes)
343     {
344         *outRowBytes = rowBytes;
345     }
346     if (outNumRows)
347     {
348         *outNumRows = numRows;
349     }
350 }
351
352
353 //--------------------------------------------------------------------------------------
354 #define ISBITMASK(r, g, b, a) (ddpf.RBitMask == r && ddpf.GBitMask == g && ddpf.BBitMask == b && ddpf.ABitMask == a)
355
356 static DXGI_FORMAT GetDXGIFormat(const DDS_PIXELFORMAT& ddpf)
357 {
358     if (ddpf.flags & DDS_RGB)
359     {
360         // Note that sRGB formats are written using the "DX10" extended header
361
362         switch (ddpf.RGBBitCount)
363         {
364         case 32:
365             if (ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000))
366             {
367                 return DXGI_FORMAT_R8G8B8A8_UNORM;
368             }
369
370             if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000))
371             {
372                 return DXGI_FORMAT_B8G8R8A8_UNORM;
373             }
374
375             if (ISBITMASK(0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000))
376             {
377                 return DXGI_FORMAT_B8G8R8X8_UNORM;
378             }
379
380             // No DXGI format maps to ISBITMASK(0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000) aka D3DFMT_X8B8G8R8
381
382             // Note that many common DDS reader/writers (including D3DX) swap the
383             // the RED/BLUE masks for 10:10:10:2 formats. We assumme
384             // below that the 'backwards' header mask is being used since it is most
385             // likely written by D3DX. The more robust solution is to use the 'DX10'
386             // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
387
388             // For 'correct' writers, this should be 0x000003ff, 0x000ffc00, 0x3ff00000 for RGB data
389             if (ISBITMASK(0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000))
390             {
391                 return DXGI_FORMAT_R10G10B10A2_UNORM;
392             }
393
394             // No DXGI format maps to ISBITMASK(0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000) aka D3DFMT_A2R10G10B10
395
396             if (ISBITMASK(0x0000ffff, 0xffff0000, 0x00000000, 0x00000000))
397             {
398                 return DXGI_FORMAT_R16G16_UNORM;
399             }
400
401             if (ISBITMASK(0xffffffff, 0x00000000, 0x00000000, 0x00000000))
402             {
403                 // Only 32-bit color channel format in D3D9 was R32F
404                 return DXGI_FORMAT_R32_FLOAT; // D3DX writes this out as a FourCC of 114
405             }
406             break;
407
408         case 24:
409             // No 24bpp DXGI formats aka D3DFMT_R8G8B8
410             break;
411
412         case 16:
413             if (ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x8000))
414             {
415                 return DXGI_FORMAT_B5G5R5A1_UNORM;
416             }
417             if (ISBITMASK(0xf800, 0x07e0, 0x001f, 0x0000))
418             {
419                 return DXGI_FORMAT_B5G6R5_UNORM;
420             }
421
422             // No DXGI format maps to ISBITMASK(0x7c00, 0x03e0, 0x001f, 0x0000) aka D3DFMT_X1R5G5B5
423             if (ISBITMASK(0x0f00, 0x00f0, 0x000f, 0xf000))
424             {
425                 return DXGI_FORMAT_B4G4R4A4_UNORM;
426             }
427
428             // No DXGI format maps to ISBITMASK(0x0f00, 0x00f0, 0x000f, 0x0000) aka D3DFMT_X4R4G4B4
429
430             // No 3:3:2, 3:3:2:8, or paletted DXGI formats aka D3DFMT_A8R3G3B2, D3DFMT_R3G3B2, D3DFMT_P8, D3DFMT_A8P8, etc.
431             break;
432         }
433     }
434     else if (ddpf.flags & DDS_LUMINANCE)
435     {
436         if (8 == ddpf.RGBBitCount)
437         {
438             if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x00000000))
439             {
440                 return DXGI_FORMAT_R8_UNORM; // D3DX10/11 writes this out as DX10 extension
441             }
442
443             // No DXGI format maps to ISBITMASK(0x0f, 0x00, 0x00, 0xf0) aka D3DFMT_A4L4
444         }
445
446         if (16 == ddpf.RGBBitCount)
447         {
448             if (ISBITMASK(0x0000ffff, 0x00000000, 0x00000000, 0x00000000))
449             {
450                 return DXGI_FORMAT_R16_UNORM; // D3DX10/11 writes this out as DX10 extension
451             }
452             if (ISBITMASK(0x000000ff, 0x00000000, 0x00000000, 0x0000ff00))
453             {
454                 return DXGI_FORMAT_R8G8_UNORM; // D3DX10/11 writes this out as DX10 extension
455             }
456         }
457     }
458     else if (ddpf.flags & DDS_ALPHA)
459     {
460         if (8 == ddpf.RGBBitCount)
461         {
462             return DXGI_FORMAT_A8_UNORM;
463         }
464     }
465     else if (ddpf.flags & DDS_FOURCC)
466     {
467         if (MAKEFOURCC('D', 'X', 'T', '1') == ddpf.fourCC)
468         {
469             return DXGI_FORMAT_BC1_UNORM;
470         }
471         if (MAKEFOURCC('D', 'X', 'T', '3') == ddpf.fourCC)
472         {
473             return DXGI_FORMAT_BC2_UNORM;
474         }
475         if (MAKEFOURCC('D', 'X', 'T', '5') == ddpf.fourCC)
476         {
477             return DXGI_FORMAT_BC3_UNORM;
478         }
479
480         // While pre-mulitplied alpha isn't directly supported by the DXGI formats,
481         // they are basically the same as these BC formats so they can be mapped
482         if (MAKEFOURCC('D', 'X', 'T', '2') == ddpf.fourCC)
483         {
484             return DXGI_FORMAT_BC2_UNORM;
485         }
486         if (MAKEFOURCC('D', 'X', 'T', '4') == ddpf.fourCC)
487         {
488             return DXGI_FORMAT_BC3_UNORM;
489         }
490
491         if (MAKEFOURCC('A', 'T', 'I', '1') == ddpf.fourCC)
492         {
493             return DXGI_FORMAT_BC4_UNORM;
494         }
495         if (MAKEFOURCC('B', 'C', '4', 'U') == ddpf.fourCC)
496         {
497             return DXGI_FORMAT_BC4_UNORM;
498         }
499         if (MAKEFOURCC('B', 'C', '4', 'S') == ddpf.fourCC)
500         {
501             return DXGI_FORMAT_BC4_SNORM;
502         }
503
504         if (MAKEFOURCC('A', 'T', 'I', '2') == ddpf.fourCC)
505         {
506             return DXGI_FORMAT_BC5_UNORM;
507         }
508         if (MAKEFOURCC('B', 'C', '5', 'U') == ddpf.fourCC)
509         {
510             return DXGI_FORMAT_BC5_UNORM;
511         }
512         if (MAKEFOURCC('B', 'C', '5', 'S') == ddpf.fourCC)
513         {
514             return DXGI_FORMAT_BC5_SNORM;
515         }
516
517         // BC6H and BC7 are written using the "DX10" extended header
518
519         if (MAKEFOURCC('R', 'G', 'B', 'G') == ddpf.fourCC)
520         {
521             return DXGI_FORMAT_R8G8_B8G8_UNORM;
522         }
523         if (MAKEFOURCC('G', 'R', 'G', 'B') == ddpf.fourCC)
524         {
525             return DXGI_FORMAT_G8R8_G8B8_UNORM;
526         }
527
528         // Check for D3DFORMAT enums being set here
529         switch (ddpf.fourCC)
530         {
531         case 36: // D3DFMT_A16B16G16R16
532             return DXGI_FORMAT_R16G16B16A16_UNORM;
533
534         case 110: // D3DFMT_Q16W16V16U16
535             return DXGI_FORMAT_R16G16B16A16_SNORM;
536
537         case 111: // D3DFMT_R16F
538             return DXGI_FORMAT_R16_FLOAT;
539
540         case 112: // D3DFMT_G16R16F
541             return DXGI_FORMAT_R16G16_FLOAT;
542
543         case 113: // D3DFMT_A16B16G16R16F
544             return DXGI_FORMAT_R16G16B16A16_FLOAT;
545
546         case 114: // D3DFMT_R32F
547             return DXGI_FORMAT_R32_FLOAT;
548
549         case 115: // D3DFMT_G32R32F
550             return DXGI_FORMAT_R32G32_FLOAT;
551
552         case 116: // D3DFMT_A32B32G32R32F
553             return DXGI_FORMAT_R32G32B32A32_FLOAT;
554         }
555     }
556
557     return DXGI_FORMAT_UNKNOWN;
558 }
559
560
561 //--------------------------------------------------------------------------------------
562 static void FillInitData(
563     _In_ size_t width,
564     _In_ size_t height,
565     _In_ size_t depth,
566     _In_ size_t mipCount,
567     _In_ size_t arraySize,
568     _In_ DXGI_FORMAT format,
569     _In_ size_t maxsize,
570     _In_ size_t bitSize,
571     _In_reads_bytes_(bitSize) const byte* bitData,
572     _Out_ size_t& twidth,
573     _Out_ size_t& theight,
574     _Out_ size_t& tdepth,
575     _Out_ size_t& skipMip,
576     _Out_writes_(mipCount*arraySize) D3D11_SUBRESOURCE_DATA* initData
577     )
578 {
579     if (!bitData || !initData)
580     {
581         throw ref new Platform::InvalidArgumentException();
582     }
583
584     skipMip = 0;
585     twidth = 0;
586     theight = 0;
587     tdepth = 0;
588
589     size_t NumBytes = 0;
590     size_t RowBytes = 0;
591     size_t NumRows = 0;
592     const byte* pSrcBits = bitData;
593     const byte* pEndBits = bitData + bitSize;
594
595     size_t index = 0;
596     for (size_t j = 0; j < arraySize; j++)
597     {
598         size_t w = width;
599         size_t h = height;
600         size_t d = depth;
601         for (size_t i = 0; i < mipCount; i++)
602         {
603             GetSurfaceInfo(w, h, format, &NumBytes, &RowBytes, &NumRows);
604
605             if ((mipCount <= 1) || !maxsize || (w <= maxsize && h <= maxsize && d <= maxsize))
606             {
607                 if (!twidth)
608                 {
609                     twidth = w;
610                     theight = h;
611                     tdepth = d;
612                 }
613
614                 initData[index].pSysMem = (const void*)pSrcBits;
615                 initData[index].SysMemPitch = static_cast<UINT>(RowBytes);
616                 initData[index].SysMemSlicePitch = static_cast<UINT>(NumBytes);
617                 ++index;
618             }
619             else
620             {
621                 ++skipMip;
622             }
623
624             if (pSrcBits + (NumBytes*d) > pEndBits)
625             {
626                 throw ref new Platform::OutOfBoundsException();
627             }
628
629             pSrcBits += NumBytes * d;
630
631             w = w >> 1;
632             h = h >> 1;
633             d = d >> 1;
634             if (w == 0)
635             {
636                 w = 1;
637             }
638             if (h == 0)
639             {
640                 h = 1;
641             }
642             if (d == 0)
643             {
644                 d = 1;
645             }
646         }
647     }
648
649     if (!index)
650     {
651         throw ref new Platform::FailureException();
652     }
653 }
654
655
656 //--------------------------------------------------------------------------------------
657 static HRESULT CreateD3DResources(
658     _In_ ID3D11Device* d3dDevice,
659     _In_ uint32 resDim,
660     _In_ size_t width,
661     _In_ size_t height,
662     _In_ size_t depth,
663     _In_ size_t mipCount,
664     _In_ size_t arraySize,
665     _In_ DXGI_FORMAT format,
666     _In_ bool isCubeMap,
667     _In_reads_(mipCount*arraySize) D3D11_SUBRESOURCE_DATA* initData,
668     _Out_opt_ ID3D11Resource** texture,
669     _Out_opt_ ID3D11ShaderResourceView** textureView
670     )
671 {
672     if (!d3dDevice || !initData)
673     {
674         return E_INVALIDARG;
675     }
676
677     HRESULT hr = E_FAIL;
678
679     switch (resDim)
680     {
681         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
682             {
683                 D3D11_TEXTURE1D_DESC desc;
684                 desc.Width = static_cast<UINT>(width);
685                 desc.MipLevels = static_cast<UINT>(mipCount);
686                 desc.ArraySize = static_cast<UINT>(arraySize);
687                 desc.Format = format;
688                 desc.Usage = D3D11_USAGE_DEFAULT;
689                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
690                 desc.CPUAccessFlags = 0;
691                 desc.MiscFlags = 0;
692
693                 ID3D11Texture1D* tex = nullptr;
694                 hr = d3dDevice->CreateTexture1D(&desc, initData, &tex);
695
696                 if (SUCCEEDED(hr) && tex != 0)
697                 {
698                     if (textureView != 0)
699                     {
700                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
701                         memset(&SRVDesc, 0, sizeof(SRVDesc));
702                         SRVDesc.Format = format;
703
704                         if (arraySize > 1)
705                         {
706                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1DARRAY;
707                             SRVDesc.Texture1DArray.MipLevels = desc.MipLevels;
708                             SRVDesc.Texture1DArray.ArraySize = static_cast<UINT>(arraySize);
709                         }
710                         else
711                         {
712                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE1D;
713                             SRVDesc.Texture1D.MipLevels = desc.MipLevels;
714                         }
715
716                         hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
717
718                         if (FAILED(hr))
719                         {
720                             tex->Release();
721                             return hr;
722                         }
723                     }
724
725                     if (texture != 0)
726                     {
727                         *texture = tex;
728                     }
729                     else
730                     {
731                         tex->Release();
732                     }
733                 }
734             }
735             break;
736
737         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
738             {
739                 D3D11_TEXTURE2D_DESC desc;
740                 desc.Width = static_cast<UINT>(width);
741                 desc.Height = static_cast<UINT>(height);
742                 desc.MipLevels = static_cast<UINT>(mipCount);
743                 desc.ArraySize = static_cast<UINT>(arraySize);
744                 desc.Format = format;
745                 desc.SampleDesc.Count = 1;
746                 desc.SampleDesc.Quality = 0;
747                 desc.Usage = D3D11_USAGE_DEFAULT;
748                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
749                 desc.CPUAccessFlags = 0;
750                 desc.MiscFlags = (isCubeMap) ? D3D11_RESOURCE_MISC_TEXTURECUBE : 0;
751
752                 ID3D11Texture2D* tex = nullptr;
753                 hr = d3dDevice->CreateTexture2D(&desc, initData, &tex);
754
755                 if (SUCCEEDED(hr) && tex != 0)
756                 {
757                     if (textureView != 0)
758                     {
759                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
760                         memset(&SRVDesc, 0, sizeof(SRVDesc));
761                         SRVDesc.Format = format;
762
763                         if (isCubeMap)
764                         {
765                             if (arraySize > 6)
766                             {
767                                 SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBEARRAY;
768                                 SRVDesc.TextureCubeArray.MipLevels = desc.MipLevels;
769
770                                 // Earlier we set arraySize to (NumCubes * 6)
771                                 SRVDesc.TextureCubeArray.NumCubes = static_cast<UINT>(arraySize / 6);
772                             }
773                             else
774                             {
775                                 SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURECUBE;
776                                 SRVDesc.TextureCube.MipLevels = desc.MipLevels;
777                             }
778                         }
779                         else if (arraySize > 1)
780                         {
781                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2DARRAY;
782                             SRVDesc.Texture2DArray.MipLevels = desc.MipLevels;
783                             SRVDesc.Texture2DArray.ArraySize = static_cast<UINT>(arraySize);
784                         }
785                         else
786                         {
787                             SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE2D;
788                             SRVDesc.Texture2D.MipLevels = desc.MipLevels;
789                         }
790
791                         hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
792
793                         if (FAILED(hr))
794                         {
795                             tex->Release();
796                             return hr;
797                         }
798                     }
799
800                     if (texture != 0)
801                     {
802                         *texture = tex;
803                     }
804                     else
805                     {
806                         tex->Release();
807                     }
808                 }
809             }
810             break;
811
812         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
813             {
814                 D3D11_TEXTURE3D_DESC desc;
815                 desc.Width = static_cast<UINT>(width);
816                 desc.Height = static_cast<UINT>(height);
817                 desc.Depth = static_cast<UINT>(depth);
818                 desc.MipLevels = static_cast<UINT>(mipCount);
819                 desc.Format = format;
820                 desc.Usage = D3D11_USAGE_DEFAULT;
821                 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
822                 desc.CPUAccessFlags = 0;
823                 desc.MiscFlags = 0;
824
825                 ID3D11Texture3D* tex = nullptr;
826                 hr = d3dDevice->CreateTexture3D(&desc, initData, &tex);
827
828                 if (SUCCEEDED(hr) && tex != 0)
829                 {
830                     if (textureView != 0)
831                     {
832                         D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc;
833                         memset(&SRVDesc, 0, sizeof(SRVDesc));
834                         SRVDesc.Format = format;
835                         SRVDesc.ViewDimension = D3D_SRV_DIMENSION_TEXTURE3D;
836                         SRVDesc.Texture3D.MipLevels = desc.MipLevels;
837
838                         hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView);
839
840                         if (FAILED(hr))
841                         {
842                             tex->Release();
843                             return hr;
844                         }
845                     }
846
847                     if (texture != 0)
848                     {
849                         *texture = tex;
850                     }
851                     else
852                     {
853                         tex->Release();
854                     }
855                 }
856             }
857             break;
858     }
859
860     return hr;
861 }
862
863
864 //--------------------------------------------------------------------------------------
865 static void CreateTextureFromDDS(
866     _In_ ID3D11Device* d3dDevice,
867     _In_ const DDS_HEADER* header,
868     _In_reads_bytes_(bitSize) const byte* bitData,
869     _In_ size_t bitSize,
870     _Out_opt_ ID3D11Resource** texture,
871     _Out_opt_ ID3D11ShaderResourceView** textureView,
872     _In_ size_t maxsize
873     )
874 {
875     HRESULT hr = S_OK;
876
877     size_t width = header->width;
878     size_t height = header->height;
879     size_t depth = header->depth;
880
881     uint32 resDim = D3D11_RESOURCE_DIMENSION_UNKNOWN;
882     size_t arraySize = 1;
883     DXGI_FORMAT format = DXGI_FORMAT_UNKNOWN;
884     bool isCubeMap = false;
885
886     size_t mipCount = header->mipMapCount;
887     if (0 == mipCount)
888     {
889         mipCount = 1;
890     }
891
892     if ((header->ddspf.flags & DDS_FOURCC) &&
893         (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))
894     {
895         const DDS_HEADER_DXT10* d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>((const char*)header + sizeof(DDS_HEADER));
896
897         arraySize = d3d10ext->arraySize;
898         if (arraySize == 0)
899         {
900             throw ref new Platform::FailureException();
901         }
902
903         if (BitsPerPixel(d3d10ext->dxgiFormat) == 0)
904         {
905             throw ref new Platform::FailureException();
906         }
907
908         format = d3d10ext->dxgiFormat;
909
910         switch (d3d10ext->resourceDimension)
911         {
912         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
913             // D3DX writes 1D textures with a fixed Height of 1
914             if ((header->flags & DDS_HEIGHT) && height != 1)
915             {
916                 throw ref new Platform::FailureException();
917             }
918             height = depth = 1;
919             break;
920
921         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
922             if (d3d10ext->miscFlag & D3D11_RESOURCE_MISC_TEXTURECUBE)
923             {
924                 arraySize *= 6;
925                 isCubeMap = true;
926             }
927             depth = 1;
928             break;
929
930         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
931             if (!(header->flags & DDS_HEADER_FLAGS_VOLUME))
932             {
933                 throw ref new Platform::FailureException();
934             }
935
936             if (arraySize > 1)
937             {
938                 throw ref new Platform::FailureException();
939             }
940             break;
941
942         default:
943             return throw ref new Platform::FailureException();
944         }
945
946         resDim = d3d10ext->resourceDimension;
947     }
948     else
949     {
950         format = GetDXGIFormat(header->ddspf);
951
952         if (format == DXGI_FORMAT_UNKNOWN)
953         {
954            return throw ref new Platform::FailureException();
955         }
956
957         if (header->flags & DDS_HEADER_FLAGS_VOLUME)
958         {
959             resDim = D3D11_RESOURCE_DIMENSION_TEXTURE3D;
960         }
961         else
962         {
963             if (header->caps2 & DDS_CUBEMAP)
964             {
965                 // We require all six faces to be defined
966                 if ((header->caps2 & DDS_CUBEMAP_ALLFACES) != DDS_CUBEMAP_ALLFACES)
967                 {
968                     return throw ref new Platform::FailureException();
969                 }
970
971                 arraySize = 6;
972                 isCubeMap = true;
973             }
974
975             depth = 1;
976             resDim = D3D11_RESOURCE_DIMENSION_TEXTURE2D;
977
978             // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
979         }
980
981         assert(BitsPerPixel(format) != 0);
982     }
983
984     // Bound sizes (for security purposes we don't trust DDS file metadata larger than the D3D 11.x hardware requirements)
985     if (mipCount > D3D11_REQ_MIP_LEVELS)
986     {
987         return throw ref new Platform::FailureException();
988     }
989
990     switch (resDim)
991     {
992         case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
993             if ((arraySize > D3D11_REQ_TEXTURE1D_ARRAY_AXIS_DIMENSION) ||
994                 (width > D3D11_REQ_TEXTURE1D_U_DIMENSION))
995             {
996                 return throw ref new Platform::FailureException();
997             }
998             break;
999
1000         case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
1001             if (isCubeMap)
1002             {
1003                 // This is the right bound because we set arraySize to (NumCubes*6) above
1004                 if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
1005                     (width > D3D11_REQ_TEXTURECUBE_DIMENSION) ||
1006                     (height > D3D11_REQ_TEXTURECUBE_DIMENSION))
1007                 {
1008                     return throw ref new Platform::FailureException();
1009                 }
1010             }
1011             else if ((arraySize > D3D11_REQ_TEXTURE2D_ARRAY_AXIS_DIMENSION) ||
1012                      (width > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION) ||
1013                      (height > D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION))
1014             {
1015                 return throw ref new Platform::FailureException();
1016             }
1017             break;
1018
1019         case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
1020             if ((arraySize > 1) ||
1021                 (width > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1022                 (height > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION) ||
1023                 (depth > D3D11_REQ_TEXTURE3D_U_V_OR_W_DIMENSION))
1024             {
1025                 return throw ref new Platform::FailureException();
1026             }
1027             break;
1028     }
1029
1030     // Create the texture
1031     std::unique_ptr<D3D11_SUBRESOURCE_DATA> initData(new D3D11_SUBRESOURCE_DATA[mipCount * arraySize]);
1032
1033     size_t skipMip = 0;
1034     size_t twidth = 0;
1035     size_t theight = 0;
1036     size_t tdepth = 0;
1037     FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, twidth, theight, tdepth, skipMip, initData.get());
1038
1039     hr = CreateD3DResources(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, isCubeMap, initData.get(), texture, textureView);
1040
1041     if (FAILED(hr) && !maxsize && (mipCount > 1))
1042     {
1043         // Retry with a maxsize determined by feature level
1044         switch (d3dDevice->GetFeatureLevel())
1045         {
1046         case D3D_FEATURE_LEVEL_9_1:
1047         case D3D_FEATURE_LEVEL_9_2:
1048             if (isCubeMap)
1049             {
1050                 maxsize = D3D_FL9_1_REQ_TEXTURECUBE_DIMENSION;
1051             }
1052             else
1053             {
1054                 maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1055                           ? D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
1056                           : D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1057             }
1058             break;
1059
1060         case D3D_FEATURE_LEVEL_9_3:
1061             maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1062                       ? D3D_FL9_1_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
1063                       : D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1064             break;
1065
1066         default: // D3D_FEATURE_LEVEL_10_0 & D3D_FEATURE_LEVEL_10_1
1067             maxsize = (resDim == D3D11_RESOURCE_DIMENSION_TEXTURE3D)
1068                       ? D3D10_REQ_TEXTURE3D_U_V_OR_W_DIMENSION
1069                       : D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
1070             break;
1071         }
1072
1073         FillInitData(width, height, depth, mipCount, arraySize, format, maxsize, bitSize, bitData, twidth, theight, tdepth, skipMip, initData.get());
1074
1075         hr = CreateD3DResources(d3dDevice, resDim, twidth, theight, tdepth, mipCount - skipMip, arraySize, format, isCubeMap, initData.get(), texture, textureView);
1076     }
1077
1078     DX::ThrowIfFailed(hr);
1079 }
1080
1081 //--------------------------------------------------------------------------------------
1082 void CreateDDSTextureFromMemory(
1083     _In_ ID3D11Device* d3dDevice,
1084     _In_reads_bytes_(ddsDataSize) const byte* ddsData,
1085     _In_ size_t ddsDataSize,
1086     _Out_opt_ ID3D11Resource** texture,
1087     _Out_opt_ ID3D11ShaderResourceView** textureView,
1088     _In_ size_t maxsize
1089     )
1090 {
1091     if (!d3dDevice || !ddsData || (!texture && !textureView))
1092     {
1093         throw ref new Platform::InvalidArgumentException();
1094     }
1095
1096     // Validate DDS file in memory
1097     if (ddsDataSize < (sizeof(uint32) + sizeof(DDS_HEADER)))
1098     {
1099         throw ref new Platform::FailureException();
1100     }
1101
1102     uint32 dwMagicNumber = *(const uint32*)(ddsData);
1103     if (dwMagicNumber != DDS_MAGIC)
1104     {
1105         throw ref new Platform::FailureException();
1106     }
1107
1108     const DDS_HEADER* header = reinterpret_cast<const DDS_HEADER*>(ddsData + sizeof(uint32));
1109
1110     // Verify header to validate DDS file
1111     if (header->size != sizeof(DDS_HEADER) ||
1112         header->ddspf.size != sizeof(DDS_PIXELFORMAT))
1113     {
1114         throw ref new Platform::FailureException();
1115     }
1116
1117     // Check for DX10 extension
1118     bool bDXT10Header = false;
1119     if ((header->ddspf.flags & DDS_FOURCC) &&
1120         (MAKEFOURCC('D', 'X', '1', '0') == header->ddspf.fourCC))
1121     {
1122         // Must be long enough for both headers and magic value
1123         if (ddsDataSize < (sizeof(DDS_HEADER) + sizeof(uint32) + sizeof(DDS_HEADER_DXT10)))
1124         {
1125             throw ref new Platform::FailureException();
1126         }
1127
1128         bDXT10Header = true;
1129     }
1130
1131     ptrdiff_t offset = sizeof(uint32)
1132                        + sizeof(DDS_HEADER)
1133                        + (bDXT10Header ? sizeof(DDS_HEADER_DXT10) : 0);
1134
1135     CreateTextureFromDDS(d3dDevice, header, ddsData + offset, ddsDataSize - offset, texture, textureView, maxsize);
1136 }