Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DirectXTexDDS.cpp
Go to the documentation of this file.
1 //-------------------------------------------------------------------------------------
2 // DirectXTexDDS.cpp
3 //
4 // DirectX Texture Library - Microsoft DirectDraw Surface (DDS) file format reader/writer
5 //
6 // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
7 // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
8 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
9 // PARTICULAR PURPOSE.
10 //
11 // Copyright (c) Microsoft Corporation. All rights reserved.
12 //
13 // http://go.microsoft.com/fwlink/?LinkId=248926
14 //-------------------------------------------------------------------------------------
15 
16 #include "directxtexp.h"
17 
18 #include "dds.h"
19 
20 namespace DirectX
21 {
22 
23 //-------------------------------------------------------------------------------------
24 // Legacy format mapping table (used for DDS files without 'DX10' extended header)
25 //-------------------------------------------------------------------------------------
27 {
29  CONV_FLAGS_EXPAND = 0x1, // Conversion requires expanded pixel size
30  CONV_FLAGS_NOALPHA = 0x2, // Conversion requires setting alpha to known value
31  CONV_FLAGS_SWIZZLE = 0x4, // BGR/RGB order swizzling required
32  CONV_FLAGS_PAL8 = 0x8, // Has an 8-bit palette
33  CONV_FLAGS_888 = 0x10, // Source is an 8:8:8 (24bpp) format
34  CONV_FLAGS_565 = 0x20, // Source is a 5:6:5 (16bpp) format
35  CONV_FLAGS_5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format
36  CONV_FLAGS_4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format
37  CONV_FLAGS_44 = 0x100, // Source is a 4:4 (8bpp) format
38  CONV_FLAGS_332 = 0x200, // Source is a 3:3:2 (8bpp) format
39  CONV_FLAGS_8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format
40  CONV_FLAGS_A8P8 = 0x800, // Has an 8-bit palette with an alpha channel
41  CONV_FLAGS_DX10 = 0x10000, // Has the 'DX10' extension header
42  CONV_FLAGS_PMALPHA = 0x20000, // Contains premultiplied alpha data
43  CONV_FLAGS_L8 = 0x40000, // Source is a 8 luminance format
44  CONV_FLAGS_L16 = 0x80000, // Source is a 16 luminance format
45  CONV_FLAGS_A8L8 = 0x100000, // Source is a 8:8 luminance format
46 };
47 
48 struct LegacyDDS
49 {
50  DXGI_FORMAT format;
51  DWORD convFlags;
53 };
54 
56 {
57  { DXGI_FORMAT_BC1_UNORM, CONV_FLAGS_NONE, DDSPF_DXT1 }, // D3DFMT_DXT1
58  { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_NONE, DDSPF_DXT3 }, // D3DFMT_DXT3
59  { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_NONE, DDSPF_DXT5 }, // D3DFMT_DXT5
60 
61  { DXGI_FORMAT_BC2_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT2 }, // D3DFMT_DXT2
62  { DXGI_FORMAT_BC3_UNORM, CONV_FLAGS_PMALPHA, DDSPF_DXT4 }, // D3DFMT_DXT4
63 
64  { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, DDSPF_BC4_UNORM },
65  { DXGI_FORMAT_BC4_SNORM, CONV_FLAGS_NONE, DDSPF_BC4_SNORM },
66  { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, DDSPF_BC5_UNORM },
67  { DXGI_FORMAT_BC5_SNORM, CONV_FLAGS_NONE, DDSPF_BC5_SNORM },
68 
69  { DXGI_FORMAT_BC4_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC( 'A', 'T', 'I', '1' ), 0, 0, 0, 0, 0 } },
70  { DXGI_FORMAT_BC5_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC( 'A', 'T', 'I', '2' ), 0, 0, 0, 0, 0 } },
71 
72  { DXGI_FORMAT_R8G8_B8G8_UNORM, CONV_FLAGS_NONE, DDSPF_R8G8_B8G8 }, // D3DFMT_R8G8_B8G8
73  { DXGI_FORMAT_G8R8_G8B8_UNORM, CONV_FLAGS_NONE, DDSPF_G8R8_G8B8 }, // D3DFMT_G8R8_G8B8
74 
75  { DXGI_FORMAT_B8G8R8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8R8G8B8 }, // D3DFMT_A8R8G8B8 (uses DXGI 1.1 format)
76  { DXGI_FORMAT_B8G8R8X8_UNORM, CONV_FLAGS_NONE, DDSPF_X8R8G8B8 }, // D3DFMT_X8R8G8B8 (uses DXGI 1.1 format)
77  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8B8G8R8 }, // D3DFMT_A8B8G8R8
78  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_NOALPHA, DDSPF_X8B8G8R8 }, // D3DFMT_X8B8G8R8
79  { DXGI_FORMAT_R16G16_UNORM, CONV_FLAGS_NONE, DDSPF_G16R16 }, // D3DFMT_G16R16
80 
81  { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_SWIZZLE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000 } }, // D3DFMT_A2R10G10B10 (D3DX reversal issue workaround)
82  { DXGI_FORMAT_R10G10B10A2_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000 } }, // D3DFMT_A2B10G10R10 (D3DX reversal issue workaround)
83 
84  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND
86  | CONV_FLAGS_888, DDSPF_R8G8B8 }, // D3DFMT_R8G8B8
87 
88  { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_565, DDSPF_R5G6B5 }, // D3DFMT_R5G6B5
89  { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551, DDSPF_A1R5G5B5 }, // D3DFMT_A1R5G5B5
90  { DXGI_FORMAT_B5G5R5A1_UNORM, CONV_FLAGS_5551
91  | CONV_FLAGS_NOALPHA, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000 } }, // D3DFMT_X1R5G5B5
92 
93  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND
94  | CONV_FLAGS_8332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00 } }, // D3DFMT_A8R3G3B2
95  { DXGI_FORMAT_B5G6R5_UNORM, CONV_FLAGS_EXPAND
96  | CONV_FLAGS_332, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 8, 0xe0, 0x1c, 0x03, 0x00 } }, // D3DFMT_R3G3B2
97 
98  { DXGI_FORMAT_R8_UNORM, CONV_FLAGS_NONE, DDSPF_L8 }, // D3DFMT_L8
99  { DXGI_FORMAT_R16_UNORM, CONV_FLAGS_NONE, DDSPF_L16 }, // D3DFMT_L16
100  { DXGI_FORMAT_R8G8_UNORM, CONV_FLAGS_NONE, DDSPF_A8L8 }, // D3DFMT_A8L8
101 
102  { DXGI_FORMAT_A8_UNORM, CONV_FLAGS_NONE, DDSPF_A8 }, // D3DFMT_A8
103 
104  { DXGI_FORMAT_R16G16B16A16_UNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 36, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16
105  { DXGI_FORMAT_R16G16B16A16_SNORM, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 110, 0, 0, 0, 0, 0 } }, // D3DFMT_Q16W16V16U16
106  { DXGI_FORMAT_R16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 111, 0, 0, 0, 0, 0 } }, // D3DFMT_R16F
107  { DXGI_FORMAT_R16G16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 112, 0, 0, 0, 0, 0 } }, // D3DFMT_G16R16F
108  { DXGI_FORMAT_R16G16B16A16_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 113, 0, 0, 0, 0, 0 } }, // D3DFMT_A16B16G16R16F
109  { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 114, 0, 0, 0, 0, 0 } }, // D3DFMT_R32F
110  { DXGI_FORMAT_R32G32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 115, 0, 0, 0, 0, 0 } }, // D3DFMT_G32R32F
111  { DXGI_FORMAT_R32G32B32A32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, 116, 0, 0, 0, 0, 0 } }, // D3DFMT_A32B32G32R32F
112 
113  { DXGI_FORMAT_R32_FLOAT, CONV_FLAGS_NONE, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 32, 0xffffffff, 0x00000000, 0x00000000, 0x00000000 } }, // D3DFMT_R32F (D3DX uses FourCC 114 instead)
114 
115  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND
117  | CONV_FLAGS_A8P8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 16, 0, 0, 0, 0 } }, // D3DFMT_A8P8
118  { DXGI_FORMAT_R8G8B8A8_UNORM, CONV_FLAGS_EXPAND
119  | CONV_FLAGS_PAL8, { sizeof(DDS_PIXELFORMAT), DDS_PAL8, 0, 8, 0, 0, 0, 0 } }, // D3DFMT_P8
120 
121  { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_4444, DDSPF_A4R4G4B4 }, // D3DFMT_A4R4G4B4 (uses DXGI 1.2 format)
122  { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_NOALPHA
123  | CONV_FLAGS_4444, { sizeof(DDS_PIXELFORMAT), DDS_RGB, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 } }, // D3DFMT_X4R4G4B4 (uses DXGI 1.2 format)
124  { DXGI_FORMAT_B4G4R4A4_UNORM, CONV_FLAGS_EXPAND
125  | CONV_FLAGS_44, { sizeof(DDS_PIXELFORMAT), DDS_LUMINANCE, 0, 8, 0x0f, 0x00, 0x00, 0xf0 } }, // D3DFMT_A4L4 (uses DXGI 1.2 format)
126 
127  { DXGI_FORMAT_YUY2, CONV_FLAGS_NONE, DDSPF_YUY2 }, // D3DFMT_YUY2 (uses DXGI 1.2 format)
128  { DXGI_FORMAT_YUY2, CONV_FLAGS_SWIZZLE, { sizeof(DDS_PIXELFORMAT), DDS_FOURCC, MAKEFOURCC('U','Y','V','Y'), 0, 0, 0, 0, 0 } }, // D3DFMT_UYVY (uses DXGI 1.2 format)
129 };
130 
131 // Note that many common DDS reader/writers (including D3DX) swap the
132 // the RED/BLUE masks for 10:10:10:2 formats. We assumme
133 // below that the 'backwards' header mask is being used since it is most
134 // likely written by D3DX. The more robust solution is to use the 'DX10'
135 // header extension and specify the DXGI_FORMAT_R10G10B10A2_UNORM format directly
136 
137 // We do not support the following legacy Direct3D 9 formats:
138 // BumpDuDv D3DFMT_V8U8, D3DFMT_Q8W8V8U8, D3DFMT_V16U16, D3DFMT_A2W10V10U10
139 // BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8
140 // FourCC 117 D3DFMT_CxV8U8
141 // ZBuffer D3DFMT_D16_LOCKABLE
142 // FourCC 82 D3DFMT_D32F_LOCKABLE
143 
144 static DXGI_FORMAT _GetDXGIFormat( const DDS_PIXELFORMAT& ddpf, DWORD flags, _Inout_ DWORD& convFlags )
145 {
146  const size_t MAP_SIZE = sizeof(g_LegacyDDSMap) / sizeof(LegacyDDS);
147  size_t index = 0;
148  for( index = 0; index < MAP_SIZE; ++index )
149  {
150  const LegacyDDS* entry = &g_LegacyDDSMap[index];
151 
152  if ( ddpf.dwFlags & entry->ddpf.dwFlags )
153  {
154  if ( entry->ddpf.dwFlags & DDS_FOURCC )
155  {
156  if ( ddpf.dwFourCC == entry->ddpf.dwFourCC )
157  break;
158  }
159  else if ( entry->ddpf.dwFlags & DDS_PAL8 )
160  {
161  if ( ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount )
162  break;
163  }
164  else if ( ddpf.dwRGBBitCount == entry->ddpf.dwRGBBitCount )
165  {
166  // RGB, RGBA, ALPHA, LUMINANCE
167  if ( ddpf.dwRBitMask == entry->ddpf.dwRBitMask
168  && ddpf.dwGBitMask == entry->ddpf.dwGBitMask
169  && ddpf.dwBBitMask == entry->ddpf.dwBBitMask
170  && ddpf.dwABitMask == entry->ddpf.dwABitMask )
171  break;
172  }
173  }
174  }
175 
176  if ( index >= MAP_SIZE )
177  return DXGI_FORMAT_UNKNOWN;
178 
179  DWORD cflags = g_LegacyDDSMap[index].convFlags;
180  DXGI_FORMAT format = g_LegacyDDSMap[index].format;
181 
182  if ( (cflags & CONV_FLAGS_EXPAND) && (flags & DDS_FLAGS_NO_LEGACY_EXPANSION) )
183  return DXGI_FORMAT_UNKNOWN;
184 
185  if ( (format == DXGI_FORMAT_R10G10B10A2_UNORM) && (flags & DDS_FLAGS_NO_R10B10G10A2_FIXUP) )
186  {
187  cflags ^= CONV_FLAGS_SWIZZLE;
188  }
189 
190  convFlags = cflags;
191 
192  return format;
193 }
194 
195 
196 //-------------------------------------------------------------------------------------
197 // Decodes DDS header including optional DX10 extended header
198 //-------------------------------------------------------------------------------------
199 static HRESULT _DecodeDDSHeader( _In_reads_bytes_(size) LPCVOID pSource, size_t size, DWORD flags, _Out_ TexMetadata& metadata,
200  _Inout_ DWORD& convFlags )
201 {
202  if ( !pSource )
203  return E_INVALIDARG;
204 
205  memset( &metadata, 0, sizeof(TexMetadata) );
206 
207  if ( size < (sizeof(DDS_HEADER) + sizeof(uint32_t)) )
208  {
209  return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
210  }
211 
212  // DDS files always start with the same magic number ("DDS ")
213  uint32_t dwMagicNumber = *reinterpret_cast<const uint32_t*>(pSource);
214  if ( dwMagicNumber != DDS_MAGIC )
215  {
216  return E_FAIL;
217  }
218 
219  auto pHeader = reinterpret_cast<const DDS_HEADER*>( (const uint8_t*)pSource + sizeof( uint32_t ) );
220 
221  // Verify header to validate DDS file
222  if ( pHeader->dwSize != sizeof(DDS_HEADER)
223  || pHeader->ddspf.dwSize != sizeof(DDS_PIXELFORMAT) )
224  {
225  return E_FAIL;
226  }
227 
228  metadata.mipLevels = pHeader->dwMipMapCount;
229  if ( metadata.mipLevels == 0 )
230  metadata.mipLevels = 1;
231 
232  // Check for DX10 extension
233  if ( (pHeader->ddspf.dwFlags & DDS_FOURCC)
234  && (MAKEFOURCC( 'D', 'X', '1', '0' ) == pHeader->ddspf.dwFourCC) )
235  {
236  // Buffer must be big enough for both headers and magic value
237  if ( size < ( sizeof(DDS_HEADER) + sizeof(uint32_t) + sizeof(DDS_HEADER_DXT10) ) )
238  {
239  return E_FAIL;
240  }
241 
242  auto d3d10ext = reinterpret_cast<const DDS_HEADER_DXT10*>( (const uint8_t*)pSource + sizeof( uint32_t ) + sizeof(DDS_HEADER) );
243  convFlags |= CONV_FLAGS_DX10;
244 
245  metadata.arraySize = d3d10ext->arraySize;
246  if ( metadata.arraySize == 0 )
247  {
248  return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
249  }
250 
251  metadata.format = d3d10ext->dxgiFormat;
252  if ( !IsValid( metadata.format ) || IsPalettized( metadata.format ) )
253  {
254  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
255  }
256 
257  static_assert( TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch");
258 
259  metadata.miscFlags = d3d10ext->miscFlag & ~TEX_MISC_TEXTURECUBE;
260 
261  switch ( d3d10ext->resourceDimension )
262  {
264 
265  // D3DX writes 1D textures with a fixed Height of 1
266  if ( (pHeader->dwFlags & DDS_HEIGHT) && pHeader->dwHeight != 1 )
267  {
268  return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
269  }
270 
271  metadata.width = pHeader->dwWidth;
272  metadata.height = 1;
273  metadata.depth = 1;
274  metadata.dimension = TEX_DIMENSION_TEXTURE1D;
275  break;
276 
278  if ( d3d10ext->miscFlag & DDS_RESOURCE_MISC_TEXTURECUBE )
279  {
280  metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
281  metadata.arraySize *= 6;
282  }
283 
284  metadata.width = pHeader->dwWidth;
285  metadata.height = pHeader->dwHeight;
286  metadata.depth = 1;
287  metadata.dimension = TEX_DIMENSION_TEXTURE2D;
288  break;
289 
291  if ( !(pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME) )
292  {
293  return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
294  }
295 
296  if ( metadata.arraySize > 1 )
297  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
298 
299  metadata.width = pHeader->dwWidth;
300  metadata.height = pHeader->dwHeight;
301  metadata.depth = pHeader->dwDepth;
302  metadata.dimension = TEX_DIMENSION_TEXTURE3D;
303  break;
304 
305  default:
306  return HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
307  }
308 
309  static_assert( TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch");
310 
311  static_assert( TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch");
312  static_assert( TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch");
313  static_assert( TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch");
314  static_assert( TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch");
315  static_assert( TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch");
316 
317  metadata.miscFlags2 = d3d10ext->miscFlags2;
318  }
319  else
320  {
321  metadata.arraySize = 1;
322 
323  if ( pHeader->dwFlags & DDS_HEADER_FLAGS_VOLUME )
324  {
325  metadata.width = pHeader->dwWidth;
326  metadata.height = pHeader->dwHeight;
327  metadata.depth = pHeader->dwDepth;
328  metadata.dimension = TEX_DIMENSION_TEXTURE3D;
329  }
330  else
331  {
332  if ( pHeader->dwCaps2 & DDS_CUBEMAP )
333  {
334  // We require all six faces to be defined
335  if ( (pHeader->dwCaps2 & DDS_CUBEMAP_ALLFACES ) != DDS_CUBEMAP_ALLFACES )
336  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
337 
338  metadata.arraySize = 6;
339  metadata.miscFlags |= TEX_MISC_TEXTURECUBE;
340  }
341 
342  metadata.width = pHeader->dwWidth;
343  metadata.height = pHeader->dwHeight;
344  metadata.depth = 1;
345  metadata.dimension = TEX_DIMENSION_TEXTURE2D;
346 
347  // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
348  }
349 
350  metadata.format = _GetDXGIFormat( pHeader->ddspf, flags, convFlags );
351 
352  if ( metadata.format == DXGI_FORMAT_UNKNOWN )
353  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
354 
355  if ( convFlags & CONV_FLAGS_PMALPHA )
356  metadata.miscFlags2 |= TEX_ALPHA_MODE_PREMULTIPLIED;
357 
358  // Special flag for handling LUMINANCE legacy formats
359  if ( flags & DDS_FLAGS_EXPAND_LUMINANCE )
360  {
361  switch ( metadata.format )
362  {
363  case DXGI_FORMAT_R8_UNORM:
364  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
365  convFlags |= CONV_FLAGS_L8 | CONV_FLAGS_EXPAND;
366  break;
367 
368  case DXGI_FORMAT_R8G8_UNORM:
369  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
370  convFlags |= CONV_FLAGS_A8L8 | CONV_FLAGS_EXPAND;
371  break;
372 
373  case DXGI_FORMAT_R16_UNORM:
374  metadata.format = DXGI_FORMAT_R16G16B16A16_UNORM;
375  convFlags |= CONV_FLAGS_L16 | CONV_FLAGS_EXPAND;
376  break;
377  }
378  }
379  }
380 
381  // Special flag for handling BGR DXGI 1.1 formats
382  if (flags & DDS_FLAGS_FORCE_RGB)
383  {
384  switch ( metadata.format )
385  {
386  case DXGI_FORMAT_B8G8R8A8_UNORM:
387  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
388  convFlags |= CONV_FLAGS_SWIZZLE;
389  break;
390 
391  case DXGI_FORMAT_B8G8R8X8_UNORM:
392  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
393  convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;
394  break;
395 
396  case DXGI_FORMAT_B8G8R8A8_TYPELESS:
397  metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
398  convFlags |= CONV_FLAGS_SWIZZLE;
399  break;
400 
401  case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
402  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
403  convFlags |= CONV_FLAGS_SWIZZLE;
404  break;
405 
406  case DXGI_FORMAT_B8G8R8X8_TYPELESS:
407  metadata.format = DXGI_FORMAT_R8G8B8A8_TYPELESS;
408  convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;
409  break;
410 
411  case DXGI_FORMAT_B8G8R8X8_UNORM_SRGB:
412  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM_SRGB;
413  convFlags |= CONV_FLAGS_SWIZZLE | CONV_FLAGS_NOALPHA;
414  break;
415  }
416  }
417 
418  // Special flag for handling 16bpp formats
419  if (flags & DDS_FLAGS_NO_16BPP)
420  {
421  switch ( metadata.format )
422  {
423  case DXGI_FORMAT_B5G6R5_UNORM:
424  case DXGI_FORMAT_B5G5R5A1_UNORM:
425  case DXGI_FORMAT_B4G4R4A4_UNORM:
426  metadata.format = DXGI_FORMAT_R8G8B8A8_UNORM;
427  convFlags |= CONV_FLAGS_EXPAND;
428  if ( metadata.format == DXGI_FORMAT_B5G6R5_UNORM )
429  convFlags |= CONV_FLAGS_NOALPHA;
430  }
431  }
432 
433  return S_OK;
434 }
435 
436 
437 //-------------------------------------------------------------------------------------
438 // Encodes DDS file header (magic value, header, optional DX10 extended header)
439 //-------------------------------------------------------------------------------------
440 _Use_decl_annotations_
441 HRESULT _EncodeDDSHeader( const TexMetadata& metadata, DWORD flags,
442  LPVOID pDestination, size_t maxsize, size_t& required )
443 {
444  if ( !IsValid( metadata.format ) )
445  return E_INVALIDARG;
446 
447  if ( IsPalettized( metadata.format ) )
448  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
449 
450  if ( metadata.arraySize > 1 )
451  {
452  if ( (metadata.arraySize != 6) || (metadata.dimension != TEX_DIMENSION_TEXTURE2D) || !(metadata.IsCubemap()) )
453  {
454  // Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header
455  flags |= DDS_FLAGS_FORCE_DX10_EXT;
456  }
457  }
458 
459  if ( flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2 )
460  {
461  flags |= DDS_FLAGS_FORCE_DX10_EXT;
462  }
463 
464  DDS_PIXELFORMAT ddpf = { 0 };
465  if ( !(flags & DDS_FLAGS_FORCE_DX10_EXT) )
466  {
467  switch( metadata.format )
468  {
469  case DXGI_FORMAT_R8G8B8A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8B8G8R8, sizeof(DDS_PIXELFORMAT) ); break;
470  case DXGI_FORMAT_R16G16_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_G16R16, sizeof(DDS_PIXELFORMAT) ); break;
471  case DXGI_FORMAT_R8G8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8L8, sizeof(DDS_PIXELFORMAT) ); break;
472  case DXGI_FORMAT_R16_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_L16, sizeof(DDS_PIXELFORMAT) ); break;
473  case DXGI_FORMAT_R8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_L8, sizeof(DDS_PIXELFORMAT) ); break;
474  case DXGI_FORMAT_A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8, sizeof(DDS_PIXELFORMAT) ); break;
475  case DXGI_FORMAT_R8G8_B8G8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_R8G8_B8G8, sizeof(DDS_PIXELFORMAT) ); break;
476  case DXGI_FORMAT_G8R8_G8B8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_G8R8_G8B8, sizeof(DDS_PIXELFORMAT) ); break;
477  case DXGI_FORMAT_BC1_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_DXT1, sizeof(DDS_PIXELFORMAT) ); break;
478  case DXGI_FORMAT_BC2_UNORM: memcpy_s( &ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT2) : (&DDSPF_DXT3), sizeof(DDS_PIXELFORMAT) ); break;
479  case DXGI_FORMAT_BC3_UNORM: memcpy_s( &ddpf, sizeof(ddpf), metadata.IsPMAlpha() ? (&DDSPF_DXT4) : (&DDSPF_DXT5), sizeof(DDS_PIXELFORMAT) ); break;
480  case DXGI_FORMAT_BC4_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC4_UNORM, sizeof(DDS_PIXELFORMAT) ); break;
481  case DXGI_FORMAT_BC4_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC4_SNORM, sizeof(DDS_PIXELFORMAT) ); break;
482  case DXGI_FORMAT_BC5_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC5_UNORM, sizeof(DDS_PIXELFORMAT) ); break;
483  case DXGI_FORMAT_BC5_SNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_BC5_SNORM, sizeof(DDS_PIXELFORMAT) ); break;
484  case DXGI_FORMAT_B5G6R5_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_R5G6B5, sizeof(DDS_PIXELFORMAT) ); break;
485  case DXGI_FORMAT_B5G5R5A1_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A1R5G5B5, sizeof(DDS_PIXELFORMAT) ); break;
486  case DXGI_FORMAT_B8G8R8A8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1
487  case DXGI_FORMAT_B8G8R8X8_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_X8R8G8B8, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.1
488  case DXGI_FORMAT_B4G4R4A4_UNORM: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_A4R4G4B4, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2
489  case DXGI_FORMAT_YUY2: memcpy_s( &ddpf, sizeof(ddpf), &DDSPF_YUY2, sizeof(DDS_PIXELFORMAT) ); break; // DXGI 1.2
490 
491  // Legacy D3DX formats using D3DFMT enum value as FourCC
492  case DXGI_FORMAT_R32G32B32A32_FLOAT:
493  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 116; // D3DFMT_A32B32G32R32F
494  break;
495  case DXGI_FORMAT_R16G16B16A16_FLOAT:
496  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 113; // D3DFMT_A16B16G16R16F
497  break;
498  case DXGI_FORMAT_R16G16B16A16_UNORM:
499  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 36; // D3DFMT_A16B16G16R16
500  break;
501  case DXGI_FORMAT_R16G16B16A16_SNORM:
502  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 110; // D3DFMT_Q16W16V16U16
503  break;
504  case DXGI_FORMAT_R32G32_FLOAT:
505  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 115; // D3DFMT_G32R32F
506  break;
507  case DXGI_FORMAT_R16G16_FLOAT:
508  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 112; // D3DFMT_G16R16F
509  break;
510  case DXGI_FORMAT_R32_FLOAT:
511  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 114; // D3DFMT_R32F
512  break;
513  case DXGI_FORMAT_R16_FLOAT:
514  ddpf.dwSize = sizeof(DDS_PIXELFORMAT); ddpf.dwFlags = DDS_FOURCC; ddpf.dwFourCC = 111; // D3DFMT_R16F
515  break;
516  }
517  }
518 
519  required = sizeof(uint32_t) + sizeof(DDS_HEADER);
520 
521  if ( ddpf.dwSize == 0 )
522  required += sizeof(DDS_HEADER_DXT10);
523 
524  if ( !pDestination )
525  return S_OK;
526 
527  if ( maxsize < required )
528  return E_NOT_SUFFICIENT_BUFFER;
529 
530  *reinterpret_cast<uint32_t*>(pDestination) = DDS_MAGIC;
531 
532  auto header = reinterpret_cast<DDS_HEADER*>( reinterpret_cast<uint8_t*>(pDestination) + sizeof(uint32_t) );
533  assert( header );
534 
535  memset( header, 0, sizeof(DDS_HEADER ) );
536  header->dwSize = sizeof( DDS_HEADER );
537  header->dwFlags = DDS_HEADER_FLAGS_TEXTURE;
538  header->dwCaps = DDS_SURFACE_FLAGS_TEXTURE;
539 
540  if (metadata.mipLevels > 0)
541  {
542  header->dwFlags |= DDS_HEADER_FLAGS_MIPMAP;
543 
544 #ifdef _M_X64
545  if ( metadata.mipLevels > 0xFFFFFFFF )
546  return E_INVALIDARG;
547 #endif
548 
549  header->dwMipMapCount = static_cast<uint32_t>( metadata.mipLevels );
550 
551  if ( header->dwMipMapCount > 1 )
552  header->dwCaps |= DDS_SURFACE_FLAGS_MIPMAP;
553  }
554 
555  switch( metadata.dimension )
556  {
558 #ifdef _M_X64
559  if ( metadata.width > 0xFFFFFFFF )
560  return E_INVALIDARG;
561 #endif
562 
563  header->dwWidth = static_cast<uint32_t>( metadata.width );
564  header->dwHeight = header->dwDepth = 1;
565  break;
566 
568 #ifdef _M_X64
569  if ( metadata.height > 0xFFFFFFFF
570  || metadata.width > 0xFFFFFFFF)
571  return E_INVALIDARG;
572 #endif
573 
574  header->dwHeight = static_cast<uint32_t>( metadata.height );
575  header->dwWidth = static_cast<uint32_t>( metadata.width );
576  header->dwDepth = 1;
577 
578  if ( metadata.IsCubemap() )
579  {
580  header->dwCaps |= DDS_SURFACE_FLAGS_CUBEMAP;
581  header->dwCaps2 |= DDS_CUBEMAP_ALLFACES;
582  }
583  break;
584 
586 #ifdef _M_X64
587  if ( metadata.height > 0xFFFFFFFF
588  || metadata.width > 0xFFFFFFFF
589  || metadata.depth > 0xFFFFFFFF )
590  return E_INVALIDARG;
591 #endif
592 
593  header->dwFlags |= DDS_HEADER_FLAGS_VOLUME;
594  header->dwCaps2 |= DDS_FLAGS_VOLUME;
595  header->dwHeight = static_cast<uint32_t>( metadata.height );
596  header->dwWidth = static_cast<uint32_t>( metadata.width );
597  header->dwDepth = static_cast<uint32_t>( metadata.depth );
598  break;
599 
600  default:
601  return E_FAIL;
602  }
603 
604  size_t rowPitch, slicePitch;
605  ComputePitch( metadata.format, metadata.width, metadata.height, rowPitch, slicePitch, CP_FLAGS_NONE );
606 
607 #ifdef _M_X64
608  if ( slicePitch > 0xFFFFFFFF
609  || rowPitch > 0xFFFFFFFF )
610  return E_FAIL;
611 #endif
612 
613  if ( IsCompressed( metadata.format ) )
614  {
615  header->dwFlags |= DDS_HEADER_FLAGS_LINEARSIZE;
616  header->dwPitchOrLinearSize = static_cast<uint32_t>( slicePitch );
617  }
618  else
619  {
620  header->dwFlags |= DDS_HEADER_FLAGS_PITCH;
621  header->dwPitchOrLinearSize = static_cast<uint32_t>( rowPitch );
622  }
623 
624  if ( ddpf.dwSize == 0 )
625  {
626  memcpy_s( &header->ddspf, sizeof(header->ddspf), &DDSPF_DX10, sizeof(DDS_PIXELFORMAT) );
627 
628  auto ext = reinterpret_cast<DDS_HEADER_DXT10*>( reinterpret_cast<uint8_t*>(header) + sizeof(DDS_HEADER) );
629  assert( ext );
630 
631  memset( ext, 0, sizeof(DDS_HEADER_DXT10) );
632  ext->dxgiFormat = metadata.format;
633  ext->resourceDimension = metadata.dimension;
634 
635 #ifdef _M_X64
636  if ( metadata.arraySize > 0xFFFFFFFF )
637  return E_INVALIDARG;
638 #endif
639 
640  static_assert( TEX_MISC_TEXTURECUBE == DDS_RESOURCE_MISC_TEXTURECUBE, "DDS header mismatch");
641 
642  ext->miscFlag = metadata.miscFlags & ~TEX_MISC_TEXTURECUBE;
643 
644  if ( metadata.miscFlags & TEX_MISC_TEXTURECUBE )
645  {
646  ext->miscFlag |= TEX_MISC_TEXTURECUBE;
647  assert( (metadata.arraySize % 6) == 0 );
648  ext->arraySize = static_cast<UINT>( metadata.arraySize / 6 );
649  }
650  else
651  {
652  ext->arraySize = static_cast<UINT>( metadata.arraySize );
653  }
654 
655  static_assert( TEX_MISC2_ALPHA_MODE_MASK == DDS_MISC_FLAGS2_ALPHA_MODE_MASK, "DDS header mismatch");
656 
657  static_assert( TEX_ALPHA_MODE_UNKNOWN == DDS_ALPHA_MODE_UNKNOWN, "DDS header mismatch");
658  static_assert( TEX_ALPHA_MODE_STRAIGHT == DDS_ALPHA_MODE_STRAIGHT, "DDS header mismatch");
659  static_assert( TEX_ALPHA_MODE_PREMULTIPLIED == DDS_ALPHA_MODE_PREMULTIPLIED, "DDS header mismatch");
660  static_assert( TEX_ALPHA_MODE_OPAQUE == DDS_ALPHA_MODE_OPAQUE, "DDS header mismatch");
661  static_assert( TEX_ALPHA_MODE_CUSTOM == DDS_ALPHA_MODE_CUSTOM, "DDS header mismatch");
662 
663  if ( flags & DDS_FLAGS_FORCE_DX10_EXT_MISC2 )
664  {
665  // This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0
666  ext->miscFlags2 = metadata.miscFlags2;
667  }
668  }
669  else
670  {
671  memcpy_s( &header->ddspf, sizeof(header->ddspf), &ddpf, sizeof(ddpf) );
672  }
673 
674  return S_OK;
675 }
676 
677 
678 //-------------------------------------------------------------------------------------
679 // Converts an image row with optional clearing of alpha value to 1.0
680 // Returns true if supported, false if expansion case not supported
681 //-------------------------------------------------------------------------------------
683 {
695 };
696 
698 {
700 
701  if ( flags & CONV_FLAGS_PAL8 )
702  {
703  lformat = ( flags & CONV_FLAGS_A8P8 ) ? TEXP_LEGACY_A8P8 : TEXP_LEGACY_P8;
704  }
705  else if ( flags & CONV_FLAGS_888 )
706  lformat = TEXP_LEGACY_R8G8B8;
707  else if ( flags & CONV_FLAGS_332 )
708  lformat = TEXP_LEGACY_R3G3B2;
709  else if ( flags & CONV_FLAGS_8332 )
710  lformat = TEXP_LEGACY_A8R3G3B2;
711  else if ( flags & CONV_FLAGS_44 )
712  lformat = TEXP_LEGACY_A4L4;
713  else if ( flags & CONV_FLAGS_4444 )
714  lformat = TEXP_LEGACY_B4G4R4A4;
715  else if ( flags & CONV_FLAGS_L8 )
716  lformat = TEXP_LEGACY_L8;
717  else if ( flags & CONV_FLAGS_L16 )
718  lformat = TEXP_LEGACY_L16;
719  else if ( flags & CONV_FLAGS_A8L8 )
720  lformat = TEXP_LEGACY_A8L8;
721 
722  return lformat;
723 }
724 
725 _Success_(return != false)
726 static bool _LegacyExpandScanline( _Out_writes_bytes_(outSize) LPVOID pDestination, size_t outSize, _In_ DXGI_FORMAT outFormat,
727  _In_reads_bytes_(inSize) LPCVOID pSource, size_t inSize, _In_ TEXP_LEGACY_FORMAT inFormat,
728  _In_reads_opt_(256) const uint32_t* pal8, _In_ DWORD flags )
729 {
730  assert( pDestination && outSize > 0 );
731  assert( pSource && inSize > 0 );
732  assert( IsValid(outFormat) && !IsPlanar(outFormat) && !IsPalettized(outFormat) );
733 
734  switch( inFormat )
735  {
736  case TEXP_LEGACY_R8G8B8:
737  if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
738  return false;
739 
740  // D3DFMT_R8G8B8 -> DXGI_FORMAT_R8G8B8A8_UNORM
741  if ( inSize >= 3 && outSize >= 4 )
742  {
743  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
744  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
745 
746  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 2 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 3, ocount += 4 )
747  {
748  // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well
749  uint32_t t1 = ( *(sPtr) << 16 );
750  uint32_t t2 = ( *(sPtr+1) << 8 );
751  uint32_t t3 = *(sPtr+2);
752 
753  *(dPtr++) = t1 | t2 | t3 | 0xff000000;
754  sPtr += 3;
755  }
756  return true;
757  }
758  return false;
759 
760  case TEXP_LEGACY_R3G3B2:
761  switch( outFormat )
762  {
763  case DXGI_FORMAT_R8G8B8A8_UNORM:
764  // D3DFMT_R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM
765  if ( inSize >= 1 && outSize >= 4 )
766  {
767  const uint8_t* __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
768  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
769 
770  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 )
771  {
772  uint8_t t = *(sPtr++);
773 
774  uint32_t t1 = (t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6);
775  uint32_t t2 = ((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5);
776  uint32_t t3 = ((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16);
777 
778  *(dPtr++) = t1 | t2 | t3 | 0xff000000;
779  }
780  return true;
781  }
782  return false;
783 
784  case DXGI_FORMAT_B5G6R5_UNORM:
785  // D3DFMT_R3G3B2 -> DXGI_FORMAT_B5G6R5_UNORM
786  if ( inSize >= 1 && outSize >= 2 )
787  {
788  const uint8_t* __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
789  uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
790 
791  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 1 ) ) ); ++icount, ocount += 2 )
792  {
793  uint8_t t = *(sPtr++);
794 
795  uint16_t t1 = ((t & 0xe0) << 8) | ((t & 0xc0) << 5);
796  uint16_t t2 = ((t & 0x1c) << 6) | ((t & 0x1c) << 3);
797  uint16_t t3 = ((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1);
798 
799  *(dPtr++) = t1 | t2 | t3;
800  }
801  return true;
802  }
803  return false;
804  }
805  break;
806 
808  if ( outFormat != DXGI_FORMAT_R8G8B8A8_UNORM )
809  return false;
810 
811  // D3DFMT_A8R3G3B2 -> DXGI_FORMAT_R8G8B8A8_UNORM
812  if ( inSize >= 2 && outSize >= 4 )
813  {
814  const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
815  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
816 
817  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 )
818  {
819  uint16_t t = *(sPtr++);
820 
821  uint32_t t1 = (t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6);
822  uint32_t t2 = ((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5);
823  uint32_t t3 = ((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16);
824  uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16);
825 
826  *(dPtr++) = t1 | t2 | t3 | ta;
827  }
828  return true;
829  }
830  return false;
831 
832  case TEXP_LEGACY_P8:
833  if ( (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8 )
834  return false;
835 
836  // D3DFMT_P8 -> DXGI_FORMAT_R8G8B8A8_UNORM
837  if ( inSize >= 1 && outSize >= 4 )
838  {
839  const uint8_t* __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
840  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
841 
842  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 )
843  {
844  uint8_t t = *(sPtr++);
845 
846  *(dPtr++) = pal8[ t ];
847  }
848  return true;
849  }
850  return false;
851 
852  case TEXP_LEGACY_A8P8:
853  if ( (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM) || !pal8 )
854  return false;
855 
856  // D3DFMT_A8P8 -> DXGI_FORMAT_R8G8B8A8_UNORM
857  if ( inSize >= 2 && outSize >= 4 )
858  {
859  const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
860  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
861 
862  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 )
863  {
864  uint16_t t = *(sPtr++);
865 
866  uint32_t t1 = pal8[ t & 0xff ];
867  uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16);
868 
869  *(dPtr++) = t1 | ta;
870  }
871  return true;
872  }
873  return false;
874 
875  case TEXP_LEGACY_A4L4:
876  switch( outFormat )
877  {
878  case DXGI_FORMAT_B4G4R4A4_UNORM :
879  // D3DFMT_A4L4 -> DXGI_FORMAT_B4G4R4A4_UNORM
880  if ( inSize >= 1 && outSize >= 2 )
881  {
882  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
883  uint16_t * __restrict dPtr = reinterpret_cast<uint16_t*>(pDestination);
884 
885  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 1 ) ) ); ++icount, ocount += 2 )
886  {
887  uint8_t t = *(sPtr++);
888 
889  uint16_t t1 = (t & 0x0f);
890  uint16_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xf000 : ((t & 0xf0) << 8);
891 
892  *(dPtr++) = t1 | (t1 << 4) | (t1 << 8) | ta;
893  }
894  return true;
895  }
896  return false;
897 
898  case DXGI_FORMAT_R8G8B8A8_UNORM:
899  // D3DFMT_A4L4 -> DXGI_FORMAT_R8G8B8A8_UNORM
900  if ( inSize >= 1 && outSize >= 4 )
901  {
902  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
903  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
904 
905  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 )
906  {
907  uint8_t t = *(sPtr++);
908 
909  uint32_t t1 = ((t & 0x0f) << 4) | (t & 0x0f);
910  uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf0) << 24) | ((t & 0xf0) << 20));
911 
912  *(dPtr++) = t1 | (t1 << 8) | (t1 << 16) | ta;
913  }
914  return true;
915  }
916  return false;
917  }
918  break;
919 
921  if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
922  return false;
923 
924  // D3DFMT_A4R4G4B4 -> DXGI_FORMAT_R8G8B8A8_UNORM
925  if ( inSize >= 2 && outSize >= 4 )
926  {
927  const uint16_t * __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
928  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
929 
930  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 )
931  {
932  uint16_t t = *(sPtr++);
933 
934  uint32_t t1 = ((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8);
935  uint32_t t2 = ((t & 0x00f0) << 8) | ((t & 0x00f0) << 4);
936  uint32_t t3 = ((t & 0x000f) << 20) | ((t & 0x000f) << 16);
937  uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : (((t & 0xf000) << 16) | ((t & 0xf000) << 12));
938 
939  *(dPtr++) = t1 | t2 | t3 | ta;
940  }
941  return true;
942  }
943  return false;
944 
945  case TEXP_LEGACY_L8:
946  if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
947  return false;
948 
949  // D3DFMT_L8 -> DXGI_FORMAT_R8G8B8A8_UNORM
950  if ( inSize >= 1 && outSize >= 4 )
951  {
952  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(pSource);
953  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
954 
955  for( size_t ocount = 0, icount = 0; ( ( icount < inSize ) && ( ocount < ( outSize - 3 ) ) ); ++icount, ocount += 4 )
956  {
957  uint32_t t1 = *(sPtr++);
958  uint32_t t2 = (t1 << 8);
959  uint32_t t3 = (t1 << 16);
960 
961  *(dPtr++) = t1 | t2 | t3 | 0xff000000;
962  }
963  return true;
964  }
965  return false;
966 
967  case TEXP_LEGACY_L16:
968  if (outFormat != DXGI_FORMAT_R16G16B16A16_UNORM)
969  return false;
970 
971  // D3DFMT_L16 -> DXGI_FORMAT_R16G16B16A16_UNORM
972  if ( inSize >= 2 && outSize >= 8 )
973  {
974  const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
975  uint64_t * __restrict dPtr = reinterpret_cast<uint64_t*>(pDestination);
976 
977  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 7 ) ) ); icount += 2, ocount += 8 )
978  {
979  uint16_t t = *(sPtr++);
980 
981  uint64_t t1 = t;
982  uint64_t t2 = (t1 << 16);
983  uint64_t t3 = (t1 << 32);
984 
985  *(dPtr++) = t1 | t2 | t3 | 0xffff000000000000;
986  }
987  return true;
988  }
989  return false;
990 
991  case TEXP_LEGACY_A8L8:
992  if (outFormat != DXGI_FORMAT_R8G8B8A8_UNORM)
993  return false;
994 
995  // D3DFMT_A8L8 -> DXGI_FORMAT_R8G8B8A8_UNORM
996  if ( inSize >= 2 && outSize >= 4 )
997  {
998  const uint16_t* __restrict sPtr = reinterpret_cast<const uint16_t*>(pSource);
999  uint32_t * __restrict dPtr = reinterpret_cast<uint32_t*>(pDestination);
1000 
1001  for( size_t ocount = 0, icount = 0; ( ( icount < ( inSize - 1 ) ) && ( ocount < ( outSize - 3 ) ) ); icount += 2, ocount += 4 )
1002  {
1003  uint16_t t = *(sPtr++);
1004 
1005  uint32_t t1 = (t & 0xff);
1006  uint32_t t2 = (t1 << 8);
1007  uint32_t t3 = (t1 << 16);
1008  uint32_t ta = ( flags & TEXP_SCANLINE_SETALPHA ) ? 0xff000000 : ((t & 0xff00) << 16);
1009 
1010  *(dPtr++) = t1 | t2 | t3 | ta;
1011  }
1012  return true;
1013  }
1014  return false;
1015  }
1016 
1017  return false;
1018 }
1019 
1020 
1021 //-------------------------------------------------------------------------------------
1022 // Converts or copies image data from pPixels into scratch image data
1023 //-------------------------------------------------------------------------------------
1024 static HRESULT _CopyImage( _In_reads_bytes_(size) const void* pPixels, _In_ size_t size,
1025  _In_ const TexMetadata& metadata, _In_ DWORD cpFlags, _In_ DWORD convFlags, _In_reads_opt_(256) const uint32_t *pal8, _In_ const ScratchImage& image )
1026 {
1027  assert( pPixels );
1028  assert( image.GetPixels() );
1029 
1030  if ( !size )
1031  return E_FAIL;
1032 
1033  if ( convFlags & CONV_FLAGS_EXPAND )
1034  {
1035  if ( convFlags & CONV_FLAGS_888 )
1036  cpFlags |= CP_FLAGS_24BPP;
1038  cpFlags |= CP_FLAGS_16BPP;
1039  else if ( convFlags & (CONV_FLAGS_44 | CONV_FLAGS_332 | CONV_FLAGS_PAL8 | CONV_FLAGS_L8) )
1040  cpFlags |= CP_FLAGS_8BPP;
1041  }
1042 
1043  size_t pixelSize, nimages;
1044  _DetermineImageArray( metadata, cpFlags, nimages, pixelSize );
1045  if ( (nimages == 0) || (nimages != image.GetImageCount()) )
1046  {
1047  return E_FAIL;
1048  }
1049 
1050  assert( pixelSize <= size );
1051 
1052  std::unique_ptr<Image[]> timages( new (std::nothrow) Image[nimages] );
1053  if ( !timages )
1054  {
1055  return E_OUTOFMEMORY;
1056  }
1057 
1058  if ( !_SetupImageArray( (uint8_t*)pPixels, size, metadata, cpFlags, timages.get(), nimages ) )
1059  {
1060  return E_FAIL;
1061  }
1062 
1063  if ( nimages != image.GetImageCount() )
1064  {
1065  return E_FAIL;
1066  }
1067 
1068  const Image* images = image.GetImages();
1069  if ( !images )
1070  {
1071  return E_FAIL;
1072  }
1073 
1074  DWORD tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0;
1075  if ( convFlags & CONV_FLAGS_SWIZZLE )
1076  tflags |= TEXP_SCANLINE_LEGACY;
1077 
1078  switch (metadata.dimension)
1079  {
1082  {
1083  size_t index = 0;
1084  for( size_t item = 0; item < metadata.arraySize; ++item )
1085  {
1086  for( size_t level = 0; level < metadata.mipLevels; ++level, ++index )
1087  {
1088  if ( index >= nimages )
1089  return E_FAIL;
1090 
1091  if ( images[ index ].height != timages[ index ].height )
1092  return E_FAIL;
1093 
1094  size_t dpitch = images[ index ].rowPitch;
1095  size_t spitch = timages[ index ].rowPitch;
1096 
1097  const uint8_t *pSrc = const_cast<const uint8_t*>( timages[ index ].pixels );
1098  if ( !pSrc )
1099  return E_POINTER;
1100 
1101  uint8_t *pDest = images[ index ].pixels;
1102  if ( !pDest )
1103  return E_POINTER;
1104 
1105  if ( IsCompressed( metadata.format ) )
1106  {
1107  size_t csize = std::min<size_t>( images[ index ].slicePitch, timages[ index ].slicePitch );
1108  memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize );
1109  }
1110  else if ( IsPlanar( metadata.format ) )
1111  {
1112  size_t count = ComputeScanlines( metadata.format, images[ index ].height );
1113  if ( !count )
1114  return E_UNEXPECTED;
1115 
1116  size_t csize = std::min<size_t>( dpitch, spitch );
1117  for( size_t h = 0; h < count; ++h )
1118  {
1119  memcpy_s( pDest, dpitch, pSrc, csize );
1120  pSrc += spitch;
1121  pDest += dpitch;
1122  }
1123  }
1124  else
1125  {
1126  for( size_t h = 0; h < images[ index ].height; ++h )
1127  {
1128  if ( convFlags & CONV_FLAGS_EXPAND )
1129  {
1130  if ( convFlags & (CONV_FLAGS_565|CONV_FLAGS_5551|CONV_FLAGS_4444) )
1131  {
1132  if ( !_ExpandScanline( pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM,
1133  pSrc, spitch,
1134  (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM,
1135  tflags ) )
1136  return E_FAIL;
1137  }
1138  else
1139  {
1140  TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat( convFlags );
1141  if ( !_LegacyExpandScanline( pDest, dpitch, metadata.format,
1142  pSrc, spitch, lformat, pal8,
1143  tflags ) )
1144  return E_FAIL;
1145  }
1146  }
1147  else if ( convFlags & CONV_FLAGS_SWIZZLE )
1148  {
1149  _SwizzleScanline( pDest, dpitch, pSrc, spitch,
1150  metadata.format, tflags );
1151  }
1152  else
1153  {
1154  _CopyScanline( pDest, dpitch, pSrc, spitch,
1155  metadata.format, tflags );
1156  }
1157 
1158  pSrc += spitch;
1159  pDest += dpitch;
1160  }
1161  }
1162  }
1163  }
1164  }
1165  break;
1166 
1168  {
1169  size_t index = 0;
1170  size_t d = metadata.depth;
1171 
1172  for( size_t level = 0; level < metadata.mipLevels; ++level )
1173  {
1174  for( size_t slice = 0; slice < d; ++slice, ++index )
1175  {
1176  if ( index >= nimages )
1177  return E_FAIL;
1178 
1179  if ( images[ index ].height != timages[ index ].height )
1180  return E_FAIL;
1181 
1182  size_t dpitch = images[ index ].rowPitch;
1183  size_t spitch = timages[ index ].rowPitch;
1184 
1185  const uint8_t *pSrc = const_cast<const uint8_t*>( timages[ index ].pixels );
1186  if ( !pSrc )
1187  return E_POINTER;
1188 
1189  uint8_t *pDest = images[ index ].pixels;
1190  if ( !pDest )
1191  return E_POINTER;
1192 
1193  if ( IsCompressed( metadata.format ) )
1194  {
1195  size_t csize = std::min<size_t>( images[ index ].slicePitch, timages[ index ].slicePitch );
1196  memcpy_s( pDest, images[ index ].slicePitch, pSrc, csize );
1197  }
1198  else if ( IsPlanar( metadata.format ) )
1199  {
1200  // Direct3D does not support any planar formats for Texture3D
1201  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
1202  }
1203  else
1204  {
1205  for( size_t h = 0; h < images[ index ].height; ++h )
1206  {
1207  if ( convFlags & CONV_FLAGS_EXPAND )
1208  {
1209  if ( convFlags & (CONV_FLAGS_565|CONV_FLAGS_5551|CONV_FLAGS_4444) )
1210  {
1211  if ( !_ExpandScanline( pDest, dpitch, DXGI_FORMAT_R8G8B8A8_UNORM,
1212  pSrc, spitch,
1213  (convFlags & CONV_FLAGS_565) ? DXGI_FORMAT_B5G6R5_UNORM : DXGI_FORMAT_B5G5R5A1_UNORM,
1214  tflags ) )
1215  return E_FAIL;
1216  }
1217  else
1218  {
1219  TEXP_LEGACY_FORMAT lformat = _FindLegacyFormat( convFlags );
1220  if ( !_LegacyExpandScanline( pDest, dpitch, metadata.format,
1221  pSrc, spitch, lformat, pal8,
1222  tflags ) )
1223  return E_FAIL;
1224  }
1225  }
1226  else if ( convFlags & CONV_FLAGS_SWIZZLE )
1227  {
1228  _SwizzleScanline( pDest, dpitch, pSrc, spitch, metadata.format, tflags );
1229  }
1230  else
1231  {
1232  _CopyScanline( pDest, dpitch, pSrc, spitch, metadata.format, tflags );
1233  }
1234 
1235  pSrc += spitch;
1236  pDest += dpitch;
1237  }
1238  }
1239  }
1240 
1241  if ( d > 1 )
1242  d >>= 1;
1243  }
1244  }
1245  break;
1246 
1247  default:
1248  return E_FAIL;
1249  }
1250 
1251  return S_OK;
1252 }
1253 
1254 static HRESULT _CopyImageInPlace( DWORD convFlags, _In_ const ScratchImage& image )
1255 {
1256  if ( !image.GetPixels() )
1257  return E_FAIL;
1258 
1259  const Image* images = image.GetImages();
1260  if ( !images )
1261  return E_FAIL;
1262 
1263  const TexMetadata& metadata = image.GetMetadata();
1264 
1265  if ( IsPlanar( metadata.format ) )
1266  return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
1267 
1268  DWORD tflags = (convFlags & CONV_FLAGS_NOALPHA) ? TEXP_SCANLINE_SETALPHA : 0;
1269  if ( convFlags & CONV_FLAGS_SWIZZLE )
1270  tflags |= TEXP_SCANLINE_LEGACY;
1271 
1272  for( size_t i = 0; i < image.GetImageCount(); ++i )
1273  {
1274  const Image* img = &images[ i ];
1275  uint8_t *pPixels = img->pixels;
1276  if ( !pPixels )
1277  return E_POINTER;
1278 
1279  size_t rowPitch = img->rowPitch;
1280 
1281  for( size_t h = 0; h < img->height; ++h )
1282  {
1283  if ( convFlags & CONV_FLAGS_SWIZZLE )
1284  {
1285  _SwizzleScanline( pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags );
1286  }
1287  else
1288  {
1289  _CopyScanline( pPixels, rowPitch, pPixels, rowPitch, metadata.format, tflags );
1290  }
1291 
1292  pPixels += rowPitch;
1293  }
1294  }
1295 
1296  return S_OK;
1297 }
1298 
1299 
1300 //=====================================================================================
1301 // Entry-points
1302 //=====================================================================================
1303 
1304 //-------------------------------------------------------------------------------------
1305 // Obtain metadata from DDS file in memory/on disk
1306 //-------------------------------------------------------------------------------------
1307 
1308 _Use_decl_annotations_
1309 HRESULT GetMetadataFromDDSMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata& metadata )
1310 {
1311  if ( !pSource || size == 0 )
1312  return E_INVALIDARG;
1313 
1314  DWORD convFlags = 0;
1315  return _DecodeDDSHeader( pSource, size, flags, metadata, convFlags );
1316 }
1317 
1318 _Use_decl_annotations_
1319 HRESULT GetMetadataFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata& metadata )
1320 {
1321  if ( !szFile )
1322  return E_INVALIDARG;
1323 
1324 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
1325  ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) );
1326 #else
1327  ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
1328  FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) );
1329 #endif
1330  if ( !hFile )
1331  {
1332  return HRESULT_FROM_WIN32( GetLastError() );
1333  }
1334 
1335  // Get the file size
1336  LARGE_INTEGER fileSize = {0};
1337 
1338 #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
1339  FILE_STANDARD_INFO fileInfo;
1340  if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) )
1341  {
1342  return HRESULT_FROM_WIN32( GetLastError() );
1343  }
1344  fileSize = fileInfo.EndOfFile;
1345 #else
1346  if ( !GetFileSizeEx( hFile.get(), &fileSize ) )
1347  {
1348  return HRESULT_FROM_WIN32( GetLastError() );
1349  }
1350 #endif
1351 
1352  // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)
1353  if ( fileSize.HighPart > 0 )
1354  {
1355  return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE );
1356  }
1357 
1358  // Need at least enough data to fill the standard header and magic number to be a valid DDS
1359  if ( fileSize.LowPart < ( sizeof(DDS_HEADER) + sizeof(uint32_t) ) )
1360  {
1361  return E_FAIL;
1362  }
1363 
1364  // Read the header in (including extended header if present)
1365  const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
1366  uint8_t header[MAX_HEADER_SIZE];
1367 
1368  DWORD bytesRead = 0;
1369  if ( !ReadFile( hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, 0 ) )
1370  {
1371  return HRESULT_FROM_WIN32( GetLastError() );
1372  }
1373 
1374  DWORD convFlags = 0;
1375  return _DecodeDDSHeader( header, bytesRead, flags, metadata, convFlags );
1376 }
1377 
1378 
1379 //-------------------------------------------------------------------------------------
1380 // Load a DDS file in memory
1381 //-------------------------------------------------------------------------------------
1382 _Use_decl_annotations_
1383 HRESULT LoadFromDDSMemory( LPCVOID pSource, size_t size, DWORD flags, TexMetadata* metadata, ScratchImage& image )
1384 {
1385  if ( !pSource || size == 0 )
1386  return E_INVALIDARG;
1387 
1388  image.Release();
1389 
1390  DWORD convFlags = 0;
1391  TexMetadata mdata;
1392  HRESULT hr = _DecodeDDSHeader( pSource, size, flags, mdata, convFlags );
1393  if ( FAILED(hr) )
1394  return hr;
1395 
1396  size_t offset = sizeof(uint32_t) + sizeof(DDS_HEADER);
1397  if ( convFlags & CONV_FLAGS_DX10 )
1398  offset += sizeof(DDS_HEADER_DXT10);
1399 
1400  assert( offset <= size );
1401 
1402  const uint32_t *pal8 = nullptr;
1403  if ( convFlags & CONV_FLAGS_PAL8 )
1404  {
1405  pal8 = reinterpret_cast<const uint32_t*>( reinterpret_cast<const uint8_t*>(pSource) + offset );
1406  assert( pal8 );
1407  offset += ( 256 * sizeof(uint32_t) );
1408  if ( size < offset )
1409  return E_FAIL;
1410  }
1411 
1412  hr = image.Initialize( mdata );
1413  if ( FAILED(hr) )
1414  return hr;
1415 
1416  auto pPixels = reinterpret_cast<LPCVOID>( reinterpret_cast<const uint8_t*>(pSource) + offset );
1417  assert( pPixels );
1418  hr = _CopyImage( pPixels, size - offset, mdata,
1419  (flags & DDS_FLAGS_LEGACY_DWORD) ? CP_FLAGS_LEGACY_DWORD : CP_FLAGS_NONE, convFlags, pal8, image );
1420  if ( FAILED(hr) )
1421  {
1422  image.Release();
1423  return hr;
1424  }
1425  if ( metadata )
1426  memcpy( metadata, &mdata, sizeof(TexMetadata) );
1427 
1428  return S_OK;
1429 }
1430 
1431 
1432 //-------------------------------------------------------------------------------------
1433 // Load a DDS file from disk
1434 //-------------------------------------------------------------------------------------
1435 _Use_decl_annotations_
1436 HRESULT LoadFromDDSFile( LPCWSTR szFile, DWORD flags, TexMetadata* metadata, ScratchImage& image )
1437 {
1438  if ( !szFile )
1439  return E_INVALIDARG;
1440 
1441  image.Release();
1442 
1443 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
1444  ScopedHandle hFile( safe_handle ( CreateFile2( szFile, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING, 0 ) ) );
1445 #else
1446  ScopedHandle hFile( safe_handle ( CreateFileW( szFile, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING,
1447  FILE_FLAG_SEQUENTIAL_SCAN, 0 ) ) );
1448 #endif
1449 
1450  if ( !hFile )
1451  {
1452  return HRESULT_FROM_WIN32( GetLastError() );
1453  }
1454 
1455  // Get the file size
1456  LARGE_INTEGER fileSize = {0};
1457 
1458 #if (_WIN32_WINNT >= _WIN32_WINNT_VISTA)
1459  FILE_STANDARD_INFO fileInfo;
1460  if ( !GetFileInformationByHandleEx( hFile.get(), FileStandardInfo, &fileInfo, sizeof(fileInfo) ) )
1461  {
1462  return HRESULT_FROM_WIN32( GetLastError() );
1463  }
1464  fileSize = fileInfo.EndOfFile;
1465 #else
1466  if ( !GetFileSizeEx( hFile.get(), &fileSize ) )
1467  {
1468  return HRESULT_FROM_WIN32( GetLastError() );
1469  }
1470 #endif
1471 
1472  // File is too big for 32-bit allocation, so reject read (4 GB should be plenty large enough for a valid DDS file)
1473  if ( fileSize.HighPart > 0 )
1474  {
1475  return HRESULT_FROM_WIN32( ERROR_FILE_TOO_LARGE );
1476  }
1477 
1478  // Need at least enough data to fill the standard header and magic number to be a valid DDS
1479  if ( fileSize.LowPart < ( sizeof(DDS_HEADER) + sizeof(uint32_t) ) )
1480  {
1481  return E_FAIL;
1482  }
1483 
1484  // Read the header in (including extended header if present)
1485  const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
1486  uint8_t header[MAX_HEADER_SIZE];
1487 
1488  DWORD bytesRead = 0;
1489  if ( !ReadFile( hFile.get(), header, MAX_HEADER_SIZE, &bytesRead, 0 ) )
1490  {
1491  return HRESULT_FROM_WIN32( GetLastError() );
1492  }
1493 
1494  DWORD convFlags = 0;
1495  TexMetadata mdata;
1496  HRESULT hr = _DecodeDDSHeader( header, bytesRead, flags, mdata, convFlags );
1497  if ( FAILED(hr) )
1498  return hr;
1499 
1500  DWORD offset = MAX_HEADER_SIZE;
1501 
1502  if ( !(convFlags & CONV_FLAGS_DX10) )
1503  {
1504  // Must reset file position since we read more than the standard header above
1505  LARGE_INTEGER filePos = { sizeof(uint32_t) + sizeof(DDS_HEADER), 0};
1506  if ( !SetFilePointerEx( hFile.get(), filePos, 0, FILE_BEGIN ) )
1507  {
1508  return HRESULT_FROM_WIN32( GetLastError() );
1509  }
1510 
1511  offset = sizeof(uint32_t) + sizeof(DDS_HEADER);
1512  }
1513 
1514  std::unique_ptr<uint32_t[]> pal8;
1515  if ( convFlags & CONV_FLAGS_PAL8 )
1516  {
1517  pal8.reset( new (std::nothrow) uint32_t[256] );
1518  if ( !pal8 )
1519  {
1520  return E_OUTOFMEMORY;
1521  }
1522 
1523  if ( !ReadFile( hFile.get(), pal8.get(), 256 * sizeof(uint32_t), &bytesRead, 0 ) )
1524  {
1525  return HRESULT_FROM_WIN32( GetLastError() );
1526  }
1527 
1528  if ( bytesRead != (256 * sizeof(uint32_t)) )
1529  {
1530  return E_FAIL;
1531  }
1532 
1533  offset += ( 256 * sizeof(uint32_t) );
1534  }
1535 
1536  DWORD remaining = fileSize.LowPart - offset;
1537  if ( remaining == 0 )
1538  return E_FAIL;
1539 
1540  hr = image.Initialize( mdata );
1541  if ( FAILED(hr) )
1542  return hr;
1543 
1544  if ( (convFlags & CONV_FLAGS_EXPAND) || (flags & DDS_FLAGS_LEGACY_DWORD) )
1545  {
1546  std::unique_ptr<uint8_t[]> temp( new (std::nothrow) uint8_t[ remaining ] );
1547  if ( !temp )
1548  {
1549  image.Release();
1550  return E_OUTOFMEMORY;
1551  }
1552 
1553  if ( !ReadFile( hFile.get(), temp.get(), remaining, &bytesRead, 0 ) )
1554  {
1555  image.Release();
1556  return HRESULT_FROM_WIN32( GetLastError() );
1557  }
1558 
1559  if ( bytesRead != remaining )
1560  {
1561  image.Release();
1562  return E_FAIL;
1563  }
1564 
1565  hr = _CopyImage( temp.get(), remaining, mdata,
1567  convFlags, pal8.get(), image );
1568  if ( FAILED(hr) )
1569  {
1570  image.Release();
1571  return hr;
1572  }
1573  }
1574  else
1575  {
1576  if ( remaining > image.GetPixelsSize() )
1577  {
1578  image.Release();
1579  return E_FAIL;
1580  }
1581 
1582  if ( !ReadFile( hFile.get(), image.GetPixels(), static_cast<DWORD>( image.GetPixelsSize() ), &bytesRead, 0 ) )
1583  {
1584  image.Release();
1585  return HRESULT_FROM_WIN32( GetLastError() );
1586  }
1587 
1588  if ( convFlags & (CONV_FLAGS_SWIZZLE|CONV_FLAGS_NOALPHA) )
1589  {
1590  // Swizzle/copy image in place
1591  hr = _CopyImageInPlace( convFlags, image );
1592  if ( FAILED(hr) )
1593  {
1594  image.Release();
1595  return hr;
1596  }
1597  }
1598  }
1599 
1600  if ( metadata )
1601  memcpy( metadata, &mdata, sizeof(TexMetadata) );
1602 
1603  return S_OK;
1604 }
1605 
1606 
1607 //-------------------------------------------------------------------------------------
1608 // Save a DDS file to memory
1609 //-------------------------------------------------------------------------------------
1610 _Use_decl_annotations_
1611 HRESULT SaveToDDSMemory( const Image* images, size_t nimages, const TexMetadata& metadata, DWORD flags, Blob& blob )
1612 {
1613  if ( !images || (nimages == 0) )
1614  return E_INVALIDARG;
1615 
1616  // Determine memory required
1617  size_t required = 0;
1618  HRESULT hr = _EncodeDDSHeader( metadata, flags, 0, 0, required );
1619  if ( FAILED(hr) )
1620  return hr;
1621 
1622  bool fastpath = true;
1623 
1624  for( size_t i = 0; i < nimages; ++i )
1625  {
1626  if ( !images[ i ].pixels )
1627  return E_POINTER;
1628 
1629  if ( images[ i ].format != metadata.format )
1630  return E_FAIL;
1631 
1632  size_t ddsRowPitch, ddsSlicePitch;
1633  ComputePitch( metadata.format, images[ i ].width, images[ i ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE );
1634 
1635  assert( images[ i ].rowPitch > 0 );
1636  assert( images[ i ].slicePitch > 0 );
1637 
1638  if ( ( images[ i ].rowPitch != ddsRowPitch ) || ( images[ i ].slicePitch != ddsSlicePitch ) )
1639  {
1640  fastpath = false;
1641  }
1642 
1643  required += ddsSlicePitch;
1644  }
1645 
1646  assert( required > 0 );
1647 
1648  blob.Release();
1649 
1650  hr = blob.Initialize( required );
1651  if ( FAILED(hr) )
1652  return hr;
1653 
1654  auto pDestination = reinterpret_cast<uint8_t*>( blob.GetBufferPointer() );
1655  assert( pDestination );
1656 
1657  hr = _EncodeDDSHeader( metadata, flags, pDestination, blob.GetBufferSize(), required );
1658  if ( FAILED(hr) )
1659  {
1660  blob.Release();
1661  return hr;
1662  }
1663 
1664  size_t remaining = blob.GetBufferSize() - required;
1665  pDestination += required;
1666 
1667  if ( !remaining )
1668  {
1669  blob.Release();
1670  return E_FAIL;
1671  }
1672 
1673  switch( metadata.dimension )
1674  {
1677  {
1678  size_t index = 0;
1679  for( size_t item = 0; item < metadata.arraySize; ++item )
1680  {
1681  for( size_t level = 0; level < metadata.mipLevels; ++level )
1682  {
1683  if ( index >= nimages )
1684  {
1685  blob.Release();
1686  return E_FAIL;
1687  }
1688 
1689  if ( fastpath )
1690  {
1691  size_t pixsize = images[ index ].slicePitch;
1692  if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) )
1693  {
1694  blob.Release();
1695  return E_FAIL;
1696  }
1697 
1698  pDestination += pixsize;
1699  remaining -= pixsize;
1700  }
1701  else
1702  {
1703  size_t ddsRowPitch, ddsSlicePitch;
1704  ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE );
1705 
1706  size_t rowPitch = images[ index ].rowPitch;
1707 
1708  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(images[ index ].pixels);
1709  uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1710 
1711  size_t lines = ComputeScanlines( metadata.format, images[ index ].height );
1712  size_t csize = std::min<size_t>( rowPitch, ddsRowPitch );
1713  size_t tremaining = remaining;
1714  for( size_t j = 0; j < lines; ++j )
1715  {
1716  if ( memcpy_s( dPtr, tremaining, sPtr, csize ) )
1717  {
1718  blob.Release();
1719  return E_FAIL;
1720  }
1721 
1722  sPtr += rowPitch;
1723  dPtr += ddsRowPitch;
1724  tremaining -= ddsRowPitch;
1725  }
1726 
1727  pDestination += ddsSlicePitch;
1728  remaining -= ddsSlicePitch;
1729  }
1730 
1731  ++index;
1732  }
1733  }
1734  }
1735  break;
1736 
1738  {
1739  if ( metadata.arraySize != 1 )
1740  {
1741  blob.Release();
1742  return E_FAIL;
1743  }
1744 
1745  size_t d = metadata.depth;
1746 
1747  size_t index = 0;
1748  for( size_t level = 0; level < metadata.mipLevels; ++level )
1749  {
1750  for( size_t slice = 0; slice < d; ++slice )
1751  {
1752  if ( index >= nimages )
1753  {
1754  blob.Release();
1755  return E_FAIL;
1756  }
1757 
1758  if ( fastpath )
1759  {
1760  size_t pixsize = images[ index ].slicePitch;
1761  if ( memcpy_s( pDestination, remaining, images[ index ].pixels, pixsize ) )
1762  {
1763  blob.Release();
1764  return E_FAIL;
1765  }
1766 
1767  pDestination += pixsize;
1768  remaining -= pixsize;
1769  }
1770  else
1771  {
1772  size_t ddsRowPitch, ddsSlicePitch;
1773  ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE );
1774 
1775  size_t rowPitch = images[ index ].rowPitch;
1776 
1777  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(images[ index ].pixels);
1778  uint8_t * __restrict dPtr = reinterpret_cast<uint8_t*>(pDestination);
1779 
1780  size_t lines = ComputeScanlines( metadata.format, images[ index ].height );
1781  size_t csize = std::min<size_t>( rowPitch, ddsRowPitch );
1782  size_t tremaining = remaining;
1783  for( size_t j = 0; j < lines; ++j )
1784  {
1785  if ( memcpy_s( dPtr, tremaining, sPtr, csize ) )
1786  {
1787  blob.Release();
1788  return E_FAIL;
1789  }
1790 
1791  sPtr += rowPitch;
1792  dPtr += ddsRowPitch;
1793  tremaining -= ddsRowPitch;
1794  }
1795 
1796  pDestination += ddsSlicePitch;
1797  remaining -= ddsSlicePitch;
1798  }
1799 
1800  ++index;
1801  }
1802 
1803  if ( d > 1 )
1804  d >>= 1;
1805  }
1806  }
1807  break;
1808 
1809  default:
1810  blob.Release();
1811  return E_FAIL;
1812  }
1813 
1814  return S_OK;
1815 }
1816 
1817 
1818 //-------------------------------------------------------------------------------------
1819 // Save a DDS file to disk
1820 //-------------------------------------------------------------------------------------
1821 _Use_decl_annotations_
1822 HRESULT SaveToDDSFile( const Image* images, size_t nimages, const TexMetadata& metadata, DWORD flags, LPCWSTR szFile )
1823 {
1824  if ( !szFile )
1825  return E_INVALIDARG;
1826 
1827  // Create DDS Header
1828  const size_t MAX_HEADER_SIZE = sizeof(uint32_t) + sizeof(DDS_HEADER) + sizeof(DDS_HEADER_DXT10);
1829  uint8_t header[MAX_HEADER_SIZE];
1830  size_t required;
1831  HRESULT hr = _EncodeDDSHeader( metadata, flags, header, MAX_HEADER_SIZE, required );
1832  if ( FAILED(hr) )
1833  return hr;
1834 
1835  // Create file and write header
1836 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
1837  ScopedHandle hFile( safe_handle( CreateFile2( szFile, GENERIC_WRITE, 0, CREATE_ALWAYS, 0 ) ) );
1838 #else
1839  ScopedHandle hFile( safe_handle( CreateFileW( szFile, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0 ) ) );
1840 #endif
1841  if ( !hFile )
1842  {
1843  return HRESULT_FROM_WIN32( GetLastError() );
1844  }
1845 
1846  DWORD bytesWritten;
1847  if ( !WriteFile( hFile.get(), header, static_cast<DWORD>( required ), &bytesWritten, 0 ) )
1848  {
1849  return HRESULT_FROM_WIN32( GetLastError() );
1850  }
1851 
1852  if ( bytesWritten != required )
1853  {
1854  return E_FAIL;
1855  }
1856 
1857  // Write images
1858  switch( metadata.dimension )
1859  {
1862  {
1863  size_t index = 0;
1864  for( size_t item = 0; item < metadata.arraySize; ++item )
1865  {
1866  for( size_t level = 0; level < metadata.mipLevels; ++level, ++index )
1867  {
1868  if ( index >= nimages )
1869  return E_FAIL;
1870 
1871  if ( !images[ index ].pixels )
1872  return E_POINTER;
1873 
1874  assert( images[ index ].rowPitch > 0 );
1875  assert( images[ index ].slicePitch > 0 );
1876 
1877  size_t ddsRowPitch, ddsSlicePitch;
1878  ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE );
1879 
1880  if ( images[ index ].slicePitch == ddsSlicePitch )
1881  {
1882  if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast<DWORD>( ddsSlicePitch ), &bytesWritten, 0 ) )
1883  {
1884  return HRESULT_FROM_WIN32( GetLastError() );
1885  }
1886 
1887  if ( bytesWritten != ddsSlicePitch )
1888  {
1889  return E_FAIL;
1890  }
1891  }
1892  else
1893  {
1894  size_t rowPitch = images[ index ].rowPitch;
1895  if ( rowPitch < ddsRowPitch )
1896  {
1897  // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data
1898  return E_FAIL;
1899  }
1900 
1901  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(images[ index ].pixels);
1902 
1903  size_t lines = ComputeScanlines( metadata.format, images[ index ].height );
1904  for( size_t j = 0; j < lines; ++j )
1905  {
1906  if ( !WriteFile( hFile.get(), sPtr, static_cast<DWORD>( ddsRowPitch ), &bytesWritten, 0 ) )
1907  {
1908  return HRESULT_FROM_WIN32( GetLastError() );
1909  }
1910 
1911  if ( bytesWritten != ddsRowPitch )
1912  {
1913  return E_FAIL;
1914  }
1915 
1916  sPtr += rowPitch;
1917  }
1918  }
1919  }
1920  }
1921  }
1922  break;
1923 
1925  {
1926  if ( metadata.arraySize != 1 )
1927  return E_FAIL;
1928 
1929  size_t d = metadata.depth;
1930 
1931  size_t index = 0;
1932  for( size_t level = 0; level < metadata.mipLevels; ++level )
1933  {
1934  for( size_t slice = 0; slice < d; ++slice, ++index )
1935  {
1936  if ( index >= nimages )
1937  return E_FAIL;
1938 
1939  if ( !images[ index ].pixels )
1940  return E_POINTER;
1941 
1942  assert( images[ index ].rowPitch > 0 );
1943  assert( images[ index ].slicePitch > 0 );
1944 
1945  size_t ddsRowPitch, ddsSlicePitch;
1946  ComputePitch( metadata.format, images[ index ].width, images[ index ].height, ddsRowPitch, ddsSlicePitch, CP_FLAGS_NONE );
1947 
1948  if ( images[ index ].slicePitch == ddsSlicePitch )
1949  {
1950  if ( !WriteFile( hFile.get(), images[ index ].pixels, static_cast<DWORD>( ddsSlicePitch ), &bytesWritten, 0 ) )
1951  {
1952  return HRESULT_FROM_WIN32( GetLastError() );
1953  }
1954 
1955  if ( bytesWritten != ddsSlicePitch )
1956  {
1957  return E_FAIL;
1958  }
1959  }
1960  else
1961  {
1962  size_t rowPitch = images[ index ].rowPitch;
1963  if ( rowPitch < ddsRowPitch )
1964  {
1965  // DDS uses 1-byte alignment, so if this is happening then the input pitch isn't actually a full line of data
1966  return E_FAIL;
1967  }
1968 
1969  const uint8_t * __restrict sPtr = reinterpret_cast<const uint8_t*>(images[ index ].pixels);
1970 
1971  size_t lines = ComputeScanlines( metadata.format, images[ index ].height );
1972  for( size_t j = 0; j < lines; ++j )
1973  {
1974  if ( !WriteFile( hFile.get(), sPtr, static_cast<DWORD>( ddsRowPitch ), &bytesWritten, 0 ) )
1975  {
1976  return HRESULT_FROM_WIN32( GetLastError() );
1977  }
1978 
1979  if ( bytesWritten != ddsRowPitch )
1980  {
1981  return E_FAIL;
1982  }
1983 
1984  sPtr += rowPitch;
1985  }
1986  }
1987  }
1988 
1989  if ( d > 1 )
1990  d >>= 1;
1991  }
1992  }
1993  break;
1994 
1995  default:
1996  return E_FAIL;
1997  }
1998 
1999  return S_OK;
2000 }
2001 
2002 }; // namespace
bool IsCubemap() const
Definition: DirectXTex.h:131
_Use_decl_annotations_ HRESULT _EncodeDDSHeader(const TexMetadata &metadata, DWORD flags, LPVOID pDestination, size_t maxsize, size_t &required)
_In_ size_t _In_ const TexMetadata _In_ DWORD cpFlags
Definition: DirectXTexP.h:116
_Use_decl_annotations_ bool _ExpandScanline(LPVOID pDestination, size_t outSize, DXGI_FORMAT outFormat, LPCVOID pSource, size_t inSize, DXGI_FORMAT inFormat, DWORD flags)
uint8_t * pixels
Definition: DirectXTex.h:230
uint32_t dwBBitMask
Definition: DDS.h:52
uint32_t dwRBitMask
Definition: DDS.h:50
bool IsPlanar(_In_ DXGI_FORMAT fmt)
uint32_t dwGBitMask
Definition: DDS.h:51
uint32_t dwFlags
Definition: DDS.h:47
size_t outSize
#define DDS_CUBEMAP_ALLFACES
Definition: DDS.h:171
public std::unique_ptr< void, handle_closer > ScopedHandle
Definition: scoped.h:32
DXGI_FORMAT format
Definition: DirectXTex.h:125
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
size_t _In_ DXGI_FORMAT size_t _In_ TEXP_LEGACY_FORMAT _In_reads_opt_(256) const uint32_t *pal8
void _CopyScanline(_When_(pDestination==pSource, _Inout_updates_bytes_(outSize)) _When_(pDestination!=pSource, _Out_writes_bytes_(outSize)) LPVOID pDestination, _In_ size_t outSize, _In_reads_bytes_(inSize) LPCVOID pSource, _In_ size_t inSize, _In_ DXGI_FORMAT format, _In_ DWORD flags)
const LegacyDDS g_LegacyDDSMap[]
size_t GetPixelsSize() const
Definition: DirectXTex.h:267
#define DDS_SURFACE_FLAGS_CUBEMAP
Definition: DDS.h:162
size_t _In_ DXGI_FORMAT size_t _In_ TEXP_LEGACY_FORMAT _In_ DWORD flags assert(pDestination &&outSize > 0)
HRESULT Initialize(_In_ size_t size)
#define DDS_PAL8
Definition: DDS.h:62
uint32_t dwRGBBitCount
Definition: DDS.h:49
HRESULT Initialize(_In_ const TexMetadata &mdata, _In_ DWORD flags=CP_FLAGS_NONE)
_In_ size_t pixelSize
Definition: DirectXTexP.h:116
static DXGI_FORMAT _GetDXGIFormat(const DDS_PIXELFORMAT &ddpf, DWORD flags, _Inout_ DWORD &convFlags)
#define DDS_HEADER_FLAGS_MIPMAP
Definition: DDS.h:152
uint32_t dwABitMask
Definition: DDS.h:53
void * GetBufferPointer() const
Definition: DirectXTex.h:298
HRESULT LoadFromDDSFile(_In_z_ LPCWSTR szFile, _In_ DWORD flags, _Out_opt_ TexMetadata *metadata, _Out_ ScratchImage &image)
#define MAKEFOURCC(ch0, ch1, ch2, ch3)
Definition: DDS.h:65
static HRESULT _CopyImage(_In_reads_bytes_(size) const void *pPixels, _In_ size_t size, _In_ const TexMetadata &metadata, _In_ DWORD cpFlags, _In_ DWORD convFlags, _In_reads_opt_(256) const uint32_t *pal8, _In_ const ScratchImage &image)
bool IsCompressed(_In_ DXGI_FORMAT fmt)
size_t rowPitch
Definition: DirectXTex.h:228
#define DDS_HEIGHT
Definition: DDS.h:157
#define DDS_LUMINANCE
Definition: DDS.h:59
_In_ size_t _In_ const TexMetadata & metadata
Definition: DirectXTexP.h:116
#define DDS_HEADER_FLAGS_PITCH
Definition: DDS.h:154
_In_ size_t count
Definition: DirectXTexP.h:174
_Use_decl_annotations_ void _SwizzleScanline(LPVOID pDestination, size_t outSize, LPCVOID pSource, size_t inSize, DXGI_FORMAT format, DWORD flags)
void ComputePitch(_In_ DXGI_FORMAT fmt, _In_ size_t width, _In_ size_t height, _Out_ size_t &rowPitch, _Out_ size_t &slicePitch, _In_ DWORD flags=CP_FLAGS_NONE)
bool IsValid(_In_ DXGI_FORMAT fmt)
size_t _In_ DXGI_FORMAT outFormat
size_t _In_ DXGI_FORMAT size_t _In_ TEXP_LEGACY_FORMAT inFormat
size_t _In_ DXGI_FORMAT size_t inSize
bool IsPalettized(_In_ DXGI_FORMAT fmt)
#define DDS_CUBEMAP
Definition: DDS.h:175
HRESULT SaveToDDSFile(_In_ const Image &image, _In_ DWORD flags, _In_z_ LPCWSTR szFile)
_Use_decl_annotations_ void _DetermineImageArray(const TexMetadata &metadata, DWORD cpFlags, size_t &nImages, size_t &pixelSize)
static HRESULT _DecodeDDSHeader(_In_reads_bytes_(size) LPCVOID pSource, size_t size, DWORD flags, _Out_ TexMetadata &metadata, _Inout_ DWORD &convFlags)
size_t _In_ DXGI_FORMAT _In_reads_bytes_(inSize) LPCVOID pSource
DDS_PIXELFORMAT ddpf
TEX_DIMENSION dimension
Definition: DirectXTex.h:126
#define DDS_HEADER_FLAGS_VOLUME
Definition: DDS.h:153
#define DDS_SURFACE_FLAGS_MIPMAP
Definition: DDS.h:161
#define DDS_HEADER_FLAGS_TEXTURE
Definition: DDS.h:151
uint32_t dwSize
Definition: DDS.h:46
HANDLE safe_handle(HANDLE h)
Definition: scoped.h:34
#define DDS_RGB
Definition: DDS.h:57
uint8_t * GetPixels() const
Definition: DirectXTex.h:266
#define DDS_SURFACE_FLAGS_TEXTURE
Definition: DDS.h:160
HRESULT SaveToDDSMemory(_In_ const Image &image, _In_ DWORD flags, _Out_ Blob &blob)
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
_Success_(return!=false) static bool _LegacyExpandScanline(_Out_writes_bytes_(outSize) LPVOID pDestination
HRESULT GetMetadataFromDDSFile(_In_z_ LPCWSTR szFile, _In_ DWORD flags, _Out_ TexMetadata &metadata)
static HRESULT _CopyImageInPlace(DWORD convFlags, _In_ const ScratchImage &image)
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
const uint32_t DDS_MAGIC
Definition: DDS.h:42
#define DDS_FOURCC
Definition: DDS.h:56
uint32_t dwFourCC
Definition: DDS.h:48
static TEXP_LEGACY_FORMAT _FindLegacyFormat(DWORD flags)
_Use_decl_annotations_ bool _SetupImageArray(uint8_t *pMemory, size_t pixelSize, const TexMetadata &metadata, DWORD cpFlags, Image *images, size_t nImages)
HRESULT GetMetadataFromDDSMemory(_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, _Out_ TexMetadata &metadata)
size_t slicePitch
Definition: DirectXTex.h:229
bool IsPMAlpha() const
Definition: DirectXTex.h:134
#define DDS_FLAGS_VOLUME
Definition: DDS.h:177
HRESULT LoadFromDDSMemory(_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata *metadata, _Out_ ScratchImage &image)
size_t GetBufferSize() const
Definition: DirectXTex.h:299
#define DDS_HEADER_FLAGS_LINEARSIZE
Definition: DDS.h:155
size_t ComputeScanlines(_In_ DXGI_FORMAT fmt, _In_ size_t height)