Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
DDSHelper.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 //
4 // Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a copy
7 // of this software and associated documentation files (the "Software"), to deal
8 // in the Software without restriction, including without limitation the rights
9 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 // copies of the Software, and to permit persons to whom the Software is
11 // furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 // THE SOFTWARE.
23 // -----------------------------------------------------------------------------
24 // The following code is a port of DirectXTex http://directxtex.codeplex.com
25 // -----------------------------------------------------------------------------
26 // Microsoft Public License (Ms-PL)
27 //
28 // This license governs use of the accompanying software. If you use the
29 // software, you accept this license. If you do not accept the license, do not
30 // use the software.
31 //
32 // 1. Definitions
33 // The terms "reproduce," "reproduction," "derivative works," and
34 // "distribution" have the same meaning here as under U.S. copyright law.
35 // A "contribution" is the original software, or any additions or changes to
36 // the software.
37 // A "contributor" is any person that distributes its contribution under this
38 // license.
39 // "Licensed patents" are a contributor's patent claims that read directly on
40 // its contribution.
41 //
42 // 2. Grant of Rights
43 // (A) Copyright Grant- Subject to the terms of this license, including the
44 // license conditions and limitations in section 3, each contributor grants
45 // you a non-exclusive, worldwide, royalty-free copyright license to reproduce
46 // its contribution, prepare derivative works of its contribution, and
47 // distribute its contribution or any derivative works that you create.
48 // (B) Patent Grant- Subject to the terms of this license, including the license
49 // conditions and limitations in section 3, each contributor grants you a
50 // non-exclusive, worldwide, royalty-free license under its licensed patents to
51 // make, have made, use, sell, offer for sale, import, and/or otherwise dispose
52 // of its contribution in the software or derivative works of the contribution
53 // in the software.
54 //
55 // 3. Conditions and Limitations
56 // (A) No Trademark License- This license does not grant you rights to use any
57 // contributors' name, logo, or trademarks.
58 // (B) If you bring a patent claim against any contributor over patents that
59 // you claim are infringed by the software, your patent license from such
60 // contributor to the software ends automatically.
61 // (C) If you distribute any portion of the software, you must retain all
62 // copyright, patent, trademark, and attribution notices that are present in the
63 // software.
64 // (D) If you distribute any portion of the software in source code form, you
65 // may do so only under this license by including a complete copy of this
66 // license with your distribution. If you distribute any portion of the software
67 // in compiled or object code form, you may only do so under a license that
68 // complies with this license.
69 // (E) The software is licensed "as-is." You bear the risk of using it. The
70 // contributors give no express warranties, guarantees or conditions. You may
71 // have additional consumer rights under your local laws which this license
72 // cannot change. To the extent permitted under your local laws, the
73 // contributors exclude the implied warranties of merchantability, fitness for a
74 // particular purpose and non-infringement.
75 
76 using System;
77 using System.Diagnostics;
78 using System.Runtime.InteropServices;
79 using SiliconStudio.Core;
80 
81 namespace SiliconStudio.Paradox.Graphics
82 {
83  internal class DDSHelper
84  {
85  [Flags]
86  public enum ConversionFlags
87  {
88  None = 0x0,
89  Expand = 0x1, // Conversion requires expanded pixel size
90  NoAlpha = 0x2, // Conversion requires setting alpha to known value
91  Swizzle = 0x4, // BGR/RGB order swizzling required
92  Pal8 = 0x8, // Has an 8-bit palette
93  Format888 = 0x10, // Source is an 8:8:8 (24bpp) format
94  Format565 = 0x20, // Source is a 5:6:5 (16bpp) format
95  Format5551 = 0x40, // Source is a 5:5:5:1 (16bpp) format
96  Format4444 = 0x80, // Source is a 4:4:4:4 (16bpp) format
97  Format44 = 0x100, // Source is a 4:4 (8bpp) format
98  Format332 = 0x200, // Source is a 3:3:2 (8bpp) format
99  Format8332 = 0x400, // Source is a 8:3:3:2 (16bpp) format
100  FormatA8P8 = 0x800, // Has an 8-bit palette with an alpha channel
101  CopyMemory = 0x1000, // The content of the memory passed to the DDS Loader is copied to another internal buffer.
102  DX10 = 0x10000, // Has the 'DX10' extension header
103  };
104 
105  [StructLayout(LayoutKind.Sequential, Pack = 1)]
106  public struct LegacyMap
107  {
108  /// <summary>
109  /// Initializes a new instance of the <see cref="LegacyMap" /> struct.
110  /// </summary>
111  /// <param name="format">The format.</param>
112  /// <param name="conversionFlags">The conversion flags.</param>
113  /// <param name="pixelFormat">The pixel format.</param>
114  public LegacyMap(PixelFormat format, ConversionFlags conversionFlags, DDS.DDSPixelFormat pixelFormat)
115  {
116  Format = format;
117  ConversionFlags = conversionFlags;
118  PixelFormat = pixelFormat;
119  }
120 
122  public ConversionFlags ConversionFlags;
124  };
125 
126  private static readonly LegacyMap[] LegacyMaps = new[]
127  {
128  new LegacyMap(PixelFormat.BC1_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.DXT1), // D3DFMT_DXT1
129  new LegacyMap(PixelFormat.BC2_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.DXT3), // D3DFMT_DXT3
130  new LegacyMap(PixelFormat.BC3_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.DXT5), // D3DFMT_DXT5
131 
132  new LegacyMap(PixelFormat.BC2_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.DXT2), // D3DFMT_DXT2 (ignore premultiply)
133  new LegacyMap(PixelFormat.BC3_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.DXT4), // D3DFMT_DXT4 (ignore premultiply)
134 
135  new LegacyMap(PixelFormat.BC4_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.BC4_UNorm),
136  new LegacyMap(PixelFormat.BC4_SNorm, ConversionFlags.None, DDS.DDSPixelFormat.BC4_SNorm),
137  new LegacyMap(PixelFormat.BC5_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.BC5_UNorm),
138  new LegacyMap(PixelFormat.BC5_SNorm, ConversionFlags.None, DDS.DDSPixelFormat.BC5_SNorm),
139 
140  new LegacyMap(PixelFormat.BC4_UNorm, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, new FourCC('A', 'T', 'I', '1'), 0, 0, 0, 0, 0)),
141  new LegacyMap(PixelFormat.BC5_UNorm, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, new FourCC('A', 'T', 'I', '2'), 0, 0, 0, 0, 0)),
142 
143  new LegacyMap(PixelFormat.R8G8_B8G8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.R8G8_B8G8), // D3DFMT_R8G8_B8G8
144  new LegacyMap(PixelFormat.G8R8_G8B8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.G8R8_G8B8), // D3DFMT_G8R8_G8B8
145 
146  new LegacyMap(PixelFormat.B8G8R8A8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.A8R8G8B8), // D3DFMT_A8R8G8B8 (uses DXGI 1.1 format)
147  new LegacyMap(PixelFormat.B8G8R8X8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.X8R8G8B8), // D3DFMT_X8R8G8B8 (uses DXGI 1.1 format)
148  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.A8B8G8R8), // D3DFMT_A8B8G8R8
149  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.NoAlpha, DDS.DDSPixelFormat.X8B8G8R8), // D3DFMT_X8B8G8R8
150  new LegacyMap(PixelFormat.R16G16_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.G16R16), // D3DFMT_G16R16
151 
152  new LegacyMap(PixelFormat.R10G10B10A2_UNorm, ConversionFlags.Swizzle, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000)),
153  // D3DFMT_A2R10G10B10 (D3DX reversal issue workaround)
154  new LegacyMap(PixelFormat.R10G10B10A2_UNorm, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)),
155  // D3DFMT_A2B10G10R10 (D3DX reversal issue workaround)
156 
157  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
158  | ConversionFlags.NoAlpha
159  | ConversionFlags.Format888, DDS.DDSPixelFormat.R8G8B8), // D3DFMT_R8G8B8
160 
161  new LegacyMap(PixelFormat.B5G6R5_UNorm, ConversionFlags.Format565, DDS.DDSPixelFormat.R5G6B5), // D3DFMT_R5G6B5
162  new LegacyMap(PixelFormat.B5G5R5A1_UNorm, ConversionFlags.Format5551, DDS.DDSPixelFormat.A1R5G5B5), // D3DFMT_A1R5G5B5
163  new LegacyMap(PixelFormat.B5G5R5A1_UNorm, ConversionFlags.Format5551
164  | ConversionFlags.NoAlpha, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000)), // D3DFMT_X1R5G5B5
165 
166  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
167  | ConversionFlags.Format8332, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00)),
168  // D3DFMT_A8R3G3B2
169  new LegacyMap(PixelFormat.B5G6R5_UNorm, ConversionFlags.Expand
170  | ConversionFlags.Format332, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 8, 0xe0, 0x1c, 0x03, 0x00)), // D3DFMT_R3G3B2
171 
172  new LegacyMap(PixelFormat.R8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.L8), // D3DFMT_L8
173  new LegacyMap(PixelFormat.R16_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.L16), // D3DFMT_L16
174  new LegacyMap(PixelFormat.R8G8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.A8L8), // D3DFMT_A8L8
175 
176  new LegacyMap(PixelFormat.A8_UNorm, ConversionFlags.None, DDS.DDSPixelFormat.A8), // D3DFMT_A8
177 
178  new LegacyMap(PixelFormat.R16G16B16A16_UNorm, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 36, 0, 0, 0, 0, 0)), // D3DFMT_A16B16G16R16
179  new LegacyMap(PixelFormat.R16G16B16A16_SNorm, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 110, 0, 0, 0, 0, 0)), // D3DFMT_Q16W16V16U16
180  new LegacyMap(PixelFormat.R16_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 111, 0, 0, 0, 0, 0)), // D3DFMT_R16F
181  new LegacyMap(PixelFormat.R16G16_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 112, 0, 0, 0, 0, 0)), // D3DFMT_G16R16F
182  new LegacyMap(PixelFormat.R16G16B16A16_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 113, 0, 0, 0, 0, 0)), // D3DFMT_A16B16G16R16F
183  new LegacyMap(PixelFormat.R32_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 114, 0, 0, 0, 0, 0)), // D3DFMT_R32F
184  new LegacyMap(PixelFormat.R32G32_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 115, 0, 0, 0, 0, 0)), // D3DFMT_G32R32F
185  new LegacyMap(PixelFormat.R32G32B32A32_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 116, 0, 0, 0, 0, 0)), // D3DFMT_A32B32G32R32F
186 
187  new LegacyMap(PixelFormat.R32_Float, ConversionFlags.None, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0xffffffff, 0x00000000, 0x00000000, 0x00000000)),
188  // D3DFMT_R32F (D3DX uses FourCC 114 instead)
189 
190  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
191  | ConversionFlags.Pal8
192  | ConversionFlags.FormatA8P8, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Pal8, 0, 16, 0, 0, 0, 0)), // D3DFMT_A8P8
193  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
194  | ConversionFlags.Pal8, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Pal8, 0, 8, 0, 0, 0, 0)), // D3DFMT_P8
195 #if DIRECTX11_1
196  new LegacyMap( PixelFormat.B4G4R4A4_UNorm, ConversionFlags.Format4444, DDS.PixelFormat.A4R4G4B4 ), // D3DFMT_A4R4G4B4 (uses DXGI 1.2 format)
197  new LegacyMap( PixelFormat.B4G4R4A4_UNorm, ConversionFlags.NoAlpha
198  | ConversionFlags.Format4444, new DDS.PixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 ) ), // D3DFMT_X4R4G4B4 (uses DXGI 1.2 format)
199  new LegacyMap( PixelFormat.B4G4R4A4_UNorm, ConversionFlags.Expand
200  | ConversionFlags.Format44, new DDS.PixelFormat(DDS.PixelFormatFlags.Luminance, 0, 8, 0x0f, 0x00, 0x00, 0xf0 ) ), // D3DFMT_A4L4 (uses DXGI 1.2 format)
201 #else
202  // !DXGI_1_2_FORMATS
203  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
204  | ConversionFlags.Format4444, DDS.DDSPixelFormat.A4R4G4B4), // D3DFMT_A4R4G4B4
205  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
206  | ConversionFlags.NoAlpha
207  | ConversionFlags.Format4444, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000)),
208  // D3DFMT_X4R4G4B4
209  new LegacyMap(PixelFormat.R8G8B8A8_UNorm, ConversionFlags.Expand
210  | ConversionFlags.Format44, new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Luminance, 0, 8, 0x0f, 0x00, 0x00, 0xf0)), // D3DFMT_A4L4
211 #endif
212  };
213 
214 
215  // Note that many common DDS reader/writers (including D3DX) swap the
216  // the RED/BLUE masks for 10:10:10:2 formats. We assumme
217  // below that the 'backwards' header mask is being used since it is most
218  // likely written by D3DX. The more robust solution is to use the 'DX10'
219  // header extension and specify the PixelFormat.R10G10B10A2_UNorm format directly
220 
221  // We do not support the following legacy Direct3D 9 formats:
222  // BumpDuDv D3DFMT_V8U8, D3DFMT_Q8W8V8U8, D3DFMT_V16U16, D3DFMT_A2W10V10U10
223  // BumpLuminance D3DFMT_L6V5U5, D3DFMT_X8L8V8U8
224  // FourCC "UYVY" D3DFMT_UYVY
225  // FourCC "YUY2" D3DFMT_YUY2
226  // FourCC 117 D3DFMT_CxV8U8
227  // ZBuffer D3DFMT_D16_LOCKABLE
228  // FourCC 82 D3DFMT_D32F_LOCKABLE
229  private static PixelFormat GetDXGIFormat(ref DDS.DDSPixelFormat pixelFormat, DDSFlags flags, out ConversionFlags conversionFlags)
230  {
231  conversionFlags = ConversionFlags.None;
232 
233  int index = 0;
234  for (index = 0; index < LegacyMaps.Length; ++index)
235  {
236  var entry = LegacyMaps[index];
237 
238  if ((pixelFormat.Flags & entry.PixelFormat.Flags) != 0)
239  {
240  if ((entry.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0)
241  {
242  if (pixelFormat.FourCC == entry.PixelFormat.FourCC)
243  break;
244  }
245  else if ((entry.PixelFormat.Flags & DDS.PixelFormatFlags.Pal8) != 0)
246  {
247  if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount)
248  break;
249  }
250  else if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount)
251  {
252  // RGB, RGBA, ALPHA, LUMINANCE
253  if (pixelFormat.RBitMask == entry.PixelFormat.RBitMask
254  && pixelFormat.GBitMask == entry.PixelFormat.GBitMask
255  && pixelFormat.BBitMask == entry.PixelFormat.BBitMask
256  && pixelFormat.ABitMask == entry.PixelFormat.ABitMask)
257  break;
258  }
259  }
260  }
261 
262  if (index >= LegacyMaps.Length)
263  return PixelFormat.None;
264 
265  conversionFlags = LegacyMaps[index].ConversionFlags;
266  var format = LegacyMaps[index].Format;
267 
268  if ((conversionFlags & ConversionFlags.Expand) != 0 && (flags & DDSFlags.NoLegacyExpansion) != 0)
269  return PixelFormat.None;
270 
271  if ((format == PixelFormat.R10G10B10A2_UNorm) && (flags & DDSFlags.NoR10B10G10A2Fixup) != 0)
272  {
273  conversionFlags ^= ConversionFlags.Swizzle;
274  }
275 
276  return format;
277  }
278 
279 
280  /// <summary>
281  /// Decodes DDS header including optional DX10 extended header
282  /// </summary>
283  /// <param name="headerPtr">Pointer to the DDS header.</param>
284  /// <param name="size">Size of the DDS content.</param>
285  /// <param name="flags">Flags used for decoding the DDS header.</param>
286  /// <param name="description">Output texture description.</param>
287  /// <param name="convFlags">Output conversion flags.</param>
288  /// <exception cref="ArgumentException">If the argument headerPtr is null</exception>
289  /// <exception cref="InvalidOperationException">If the DDS header contains invalid datas.</exception>
290  /// <returns>True if the decoding is successfull, false if this is not a DDS header.</returns>
291  private static unsafe bool DecodeDDSHeader(IntPtr headerPtr, int size, DDSFlags flags, out ImageDescription description, out ConversionFlags convFlags)
292  {
293  description = new ImageDescription();
294  convFlags = ConversionFlags.None;
295 
296  if (headerPtr == IntPtr.Zero)
297  throw new ArgumentException("Pointer to DDS header cannot be null", "headerPtr");
298 
299  if (size < (Utilities.SizeOf<DDS.Header>() + sizeof (uint)))
300  return false;
301 
302  // DDS files always start with the same magic number ("DDS ")
303  if (*(uint*) (headerPtr) != DDS.MagicHeader)
304  return false;
305 
306  var header = *(DDS.Header*) ((byte*) headerPtr + sizeof (int));
307 
308  // Verify header to validate DDS file
309  if (header.Size != Utilities.SizeOf<DDS.Header>() || header.PixelFormat.Size != Utilities.SizeOf<DDS.DDSPixelFormat>())
310  return false;
311 
312  // Setup MipLevels
313  description.MipLevels = header.MipMapCount;
314  if (description.MipLevels == 0)
315  description.MipLevels = 1;
316 
317  // Check for DX10 extension
318  if ((header.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0 && (new FourCC('D', 'X', '1', '0') == header.PixelFormat.FourCC))
319  {
320  // Buffer must be big enough for both headers and magic value
321  if (size < (Utilities.SizeOf<DDS.Header>() + sizeof (uint) + Utilities.SizeOf<DDS.HeaderDXT10>()))
322  return false;
323 
324  var headerDX10 = *(DDS.HeaderDXT10*) ((byte*) headerPtr + sizeof (int) + Utilities.SizeOf<DDS.Header>());
325  convFlags |= ConversionFlags.DX10;
326 
327  description.ArraySize = headerDX10.ArraySize;
328  if (description.ArraySize == 0)
329  throw new InvalidOperationException("Unexpected ArraySize == 0 from DDS HeaderDX10 ");
330 
331  description.Format = headerDX10.DXGIFormat;
332  if (!description.Format.IsValid())
333  throw new InvalidOperationException("Invalid Format from DDS HeaderDX10 ");
334 
335  switch (headerDX10.ResourceDimension)
336  {
337  case DDS.ResourceDimension.Texture1D:
338 
339  // D3DX writes 1D textures with a fixed Height of 1
340  if ((header.Flags & DDS.HeaderFlags.Height) != 0 && header.Height != 1)
341  throw new InvalidOperationException("Unexpected Height != 1 from DDS HeaderDX10 ");
342 
343  description.Width = header.Width;
344  description.Height = 1;
345  description.Depth = 1;
346  description.Dimension = TextureDimension.Texture1D;
347  break;
348 
349  case DDS.ResourceDimension.Texture2D:
350  if ((headerDX10.MiscFlags & DDS.ResourceOptionFlags.TextureCube) != 0)
351  {
352  description.ArraySize *= 6;
353  description.Dimension = TextureDimension.TextureCube;
354  }
355  else
356  {
357  description.Dimension = TextureDimension.Texture2D;
358  }
359 
360  description.Width = header.Width;
361  description.Height = header.Height;
362  description.Depth = 1;
363  break;
364 
365  case DDS.ResourceDimension.Texture3D:
366  if ((header.Flags & DDS.HeaderFlags.Volume) == 0)
367  throw new InvalidOperationException("Texture3D missing HeaderFlags.Volume from DDS HeaderDX10");
368 
369  if (description.ArraySize > 1)
370  throw new InvalidOperationException("Unexpected ArraySize > 1 for Texture3D from DDS HeaderDX10");
371 
372  description.Width = header.Width;
373  description.Height = header.Height;
374  description.Depth = header.Depth;
375  description.Dimension = TextureDimension.Texture3D;
376  break;
377 
378  default:
379  throw new InvalidOperationException(string.Format("Unexpected dimension [{0}] from DDS HeaderDX10", headerDX10.ResourceDimension));
380  }
381  }
382  else
383  {
384  description.ArraySize = 1;
385 
386  if ((header.Flags & DDS.HeaderFlags.Volume) != 0)
387  {
388  description.Width = header.Width;
389  description.Height = header.Height;
390  description.Depth = header.Depth;
391  description.Dimension = TextureDimension.Texture3D;
392  }
393  else
394  {
395  if ((header.CubemapFlags & DDS.CubemapFlags.CubeMap) != 0)
396  {
397  // We require all six faces to be defined
398  if ((header.CubemapFlags & DDS.CubemapFlags.AllFaces) != DDS.CubemapFlags.AllFaces)
399  throw new InvalidOperationException("Unexpected CubeMap, expecting all faces from DDS Header");
400 
401  description.ArraySize = 6;
402  description.Dimension = TextureDimension.TextureCube;
403  }
404  else
405  {
406  description.Dimension = TextureDimension.Texture2D;
407  }
408 
409  description.Width = header.Width;
410  description.Height = header.Height;
411  description.Depth = 1;
412  // Note there's no way for a legacy Direct3D 9 DDS to express a '1D' texture
413  }
414 
415  description.Format = GetDXGIFormat(ref header.PixelFormat, flags, out convFlags);
416 
417  if (description.Format == PixelFormat.None)
418  throw new InvalidOperationException("Unsupported PixelFormat from DDS Header");
419  }
420 
421  // Special flag for handling BGR DXGI 1.1 formats
422  if ((flags & DDSFlags.ForceRgb) != 0)
423  {
424  switch ((PixelFormat) description.Format)
425  {
426  case PixelFormat.B8G8R8A8_UNorm:
427  description.Format = PixelFormat.R8G8B8A8_UNorm;
428  convFlags |= ConversionFlags.Swizzle;
429  break;
430 
431  case PixelFormat.B8G8R8X8_UNorm:
432  description.Format = PixelFormat.R8G8B8A8_UNorm;
433  convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
434  break;
435 
436  case PixelFormat.B8G8R8A8_Typeless:
437  description.Format = PixelFormat.R8G8B8A8_Typeless;
438  convFlags |= ConversionFlags.Swizzle;
439  break;
440 
441  case PixelFormat.B8G8R8A8_UNorm_SRgb:
442  description.Format = PixelFormat.R8G8B8A8_UNorm_SRgb;
443  convFlags |= ConversionFlags.Swizzle;
444  break;
445 
446  case PixelFormat.B8G8R8X8_Typeless:
447  description.Format = PixelFormat.R8G8B8A8_Typeless;
448  convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
449  break;
450 
451  case PixelFormat.B8G8R8X8_UNorm_SRgb:
452  description.Format = PixelFormat.R8G8B8A8_UNorm_SRgb;
453  convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
454  break;
455  }
456  }
457 
458  // Pass DDSFlags copy memory to the conversion flags
459  if ((flags & DDSFlags.CopyMemory) != 0)
460  convFlags |= ConversionFlags.CopyMemory;
461 
462  // Special flag for handling 16bpp formats
463  if ((flags & DDSFlags.No16Bpp) != 0)
464  {
465  switch ((PixelFormat) description.Format)
466  {
467  case PixelFormat.B5G6R5_UNorm:
468  case PixelFormat.B5G5R5A1_UNorm:
469 #if DIRECTX11_1
470  case PixelFormat.B4G4R4A4_UNorm:
471 #endif
472  description.Format = PixelFormat.R8G8B8A8_UNorm;
473  convFlags |= ConversionFlags.Expand;
474  if (description.Format == PixelFormat.B5G6R5_UNorm)
475  convFlags |= ConversionFlags.NoAlpha;
476  break;
477  }
478  }
479  return true;
480  }
481 
482  /// <summary>
483  /// Encodes DDS file header (magic value, header, optional DX10 extended header)
484  /// </summary>
485  /// <param name="flags">Flags used for decoding the DDS header.</param>
486  /// <param name="description">Output texture description.</param>
487  /// <param name="pDestination">Pointer to the DDS output header. Can be set to IntPtr.Zero to calculated the required bytes.</param>
488  /// <param name="maxsize">The maximum size of the destination buffer.</param>
489  /// <param name="required">Output the number of bytes required to write the DDS header.</param>
490  /// <exception cref="ArgumentException">If the argument headerPtr is null</exception>
491  /// <exception cref="InvalidOperationException">If the DDS header contains invalid datas.</exception>
492  /// <returns>True if the decoding is successfull, false if this is not a DDS header.</returns>
493  private unsafe static void EncodeDDSHeader( ImageDescription description, DDSFlags flags, IntPtr pDestination, int maxsize, out int required )
494  {
495  if (description.ArraySize > 1)
496  {
497  if ((description.ArraySize != 6) || (description.Dimension != TextureDimension.Texture2D) || (description.Dimension != TextureDimension.TextureCube))
498  {
499  flags |= DDSFlags.ForceDX10Ext;
500  }
501  }
502 
503  var ddpf = default(DDS.DDSPixelFormat);
504  if ((flags & DDSFlags.ForceDX10Ext) == 0)
505  {
506  switch (description.Format)
507  {
508  case PixelFormat.R8G8B8A8_UNorm:
509  ddpf = DDS.DDSPixelFormat.A8B8G8R8;
510  break;
511  case PixelFormat.R16G16_UNorm:
512  ddpf = DDS.DDSPixelFormat.G16R16;
513  break;
514  case PixelFormat.R8G8_UNorm:
515  ddpf = DDS.DDSPixelFormat.A8L8;
516  break;
517  case PixelFormat.R16_UNorm:
518  ddpf = DDS.DDSPixelFormat.L16;
519  break;
520  case PixelFormat.R8_UNorm:
521  ddpf = DDS.DDSPixelFormat.L8;
522  break;
523  case PixelFormat.A8_UNorm:
524  ddpf = DDS.DDSPixelFormat.A8;
525  break;
526  case PixelFormat.R8G8_B8G8_UNorm:
527  ddpf = DDS.DDSPixelFormat.R8G8_B8G8;
528  break;
529  case PixelFormat.G8R8_G8B8_UNorm:
530  ddpf = DDS.DDSPixelFormat.G8R8_G8B8;
531  break;
532  case PixelFormat.BC1_UNorm:
533  ddpf = DDS.DDSPixelFormat.DXT1;
534  break;
535  case PixelFormat.BC2_UNorm:
536  ddpf = DDS.DDSPixelFormat.DXT3;
537  break;
538  case PixelFormat.BC3_UNorm:
539  ddpf = DDS.DDSPixelFormat.DXT5;
540  break;
541  case PixelFormat.BC4_UNorm:
542  ddpf = DDS.DDSPixelFormat.BC4_UNorm;
543  break;
544  case PixelFormat.BC4_SNorm:
545  ddpf = DDS.DDSPixelFormat.BC4_SNorm;
546  break;
547  case PixelFormat.BC5_UNorm:
548  ddpf = DDS.DDSPixelFormat.BC5_UNorm;
549  break;
550  case PixelFormat.BC5_SNorm:
551  ddpf = DDS.DDSPixelFormat.BC5_SNorm;
552  break;
553  case PixelFormat.B5G6R5_UNorm:
554  ddpf = DDS.DDSPixelFormat.R5G6B5;
555  break;
556  case PixelFormat.B5G5R5A1_UNorm:
557  ddpf = DDS.DDSPixelFormat.A1R5G5B5;
558  break;
559  case PixelFormat.B8G8R8A8_UNorm:
560  ddpf = DDS.DDSPixelFormat.A8R8G8B8;
561  break; // DXGI 1.1
562  case PixelFormat.B8G8R8X8_UNorm:
563  ddpf = DDS.DDSPixelFormat.X8R8G8B8;
564  break; // DXGI 1.1
565 #if DIRECTX11_1
566  case PixelFormat.B4G4R4A4_UNorm:
567  ddpf = DDS.PixelFormat.A4R4G4B4;
568  break;
569 #endif
570  // Legacy D3DX formats using D3DFMT enum value as FourCC
571  case PixelFormat.R32G32B32A32_Float:
572  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
573  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
574  ddpf.FourCC = 116; // D3DFMT_A32B32G32R32F
575  break;
576  case PixelFormat.R16G16B16A16_Float:
577  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
578  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
579  ddpf.FourCC = 113; // D3DFMT_A16B16G16R16F
580  break;
581  case PixelFormat.R16G16B16A16_UNorm:
582  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
583  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
584  ddpf.FourCC = 36; // D3DFMT_A16B16G16R16
585  break;
586  case PixelFormat.R16G16B16A16_SNorm:
587  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
588  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
589  ddpf.FourCC = 110; // D3DFMT_Q16W16V16U16
590  break;
591  case PixelFormat.R32G32_Float:
592  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
593  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
594  ddpf.FourCC = 115; // D3DFMT_G32R32F
595  break;
596  case PixelFormat.R16G16_Float:
597  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
598  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
599  ddpf.FourCC = 112; // D3DFMT_G16R16F
600  break;
601  case PixelFormat.R32_Float:
602  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
603  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
604  ddpf.FourCC = 114; // D3DFMT_R32F
605  break;
606  case PixelFormat.R16_Float:
607  ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
608  ddpf.Flags = DDS.PixelFormatFlags.FourCC;
609  ddpf.FourCC = 111; // D3DFMT_R16F
610  break;
611  }
612  }
613 
614  required = sizeof (int) + Utilities.SizeOf<DDS.Header>();
615 
616  if (ddpf.Size == 0)
617  required += Utilities.SizeOf<DDS.HeaderDXT10>();
618 
619  if (pDestination == IntPtr.Zero)
620  return;
621 
622  if (maxsize < required)
623  throw new ArgumentException("Not enough size for destination buffer", "maxsize");
624 
625  *(uint*)(pDestination) = DDS.MagicHeader;
626 
627  var header = (DDS.Header*)((byte*)(pDestination) + sizeof (int));
628 
629  Utilities.ClearMemory((IntPtr)header, 0, Utilities.SizeOf<DDS.Header>());
630  header->Size = Utilities.SizeOf<DDS.Header>();
631  header->Flags = DDS.HeaderFlags.Texture;
632  header->SurfaceFlags = DDS.SurfaceFlags.Texture;
633 
634  if (description.MipLevels > 0)
635  {
636  header->Flags |= DDS.HeaderFlags.Mipmap;
637  header->MipMapCount = description.MipLevels;
638 
639  if (header->MipMapCount > 1)
640  header->SurfaceFlags |= DDS.SurfaceFlags.Mipmap;
641  }
642 
643  switch (description.Dimension)
644  {
645  case TextureDimension.Texture1D:
646  header->Height = description.Height;
647  header->Width = header->Depth = 1;
648  break;
649 
650  case TextureDimension.Texture2D:
651  case TextureDimension.TextureCube:
652  header->Height = description.Height;
653  header->Width = description.Width;
654  header->Depth = 1;
655 
656  if (description.Dimension == TextureDimension.TextureCube)
657  {
658  header->SurfaceFlags |= DDS.SurfaceFlags.Cubemap;
659  header->CubemapFlags |= DDS.CubemapFlags.AllFaces;
660  }
661  break;
662 
663  case TextureDimension.Texture3D:
664 
665  header->Flags |= DDS.HeaderFlags.Volume;
666  header->CubemapFlags |= DDS.CubemapFlags.Volume;
667  header->Height = description.Height;
668  header->Width = description.Width;
669  header->Depth = description.Depth;
670  break;
671  }
672 
673  int rowPitch, slicePitch;
674  int newWidth;
675  int newHeight;
676  Image.ComputePitch(description.Format, description.Width, description.Height, out rowPitch, out slicePitch, out newWidth, out newHeight);
677 
678  if (description.Format.IsCompressed())
679  {
680  header->Flags |= DDS.HeaderFlags.LinearSize;
681  header->PitchOrLinearSize = slicePitch;
682  }
683  else
684  {
685  header->Flags |= DDS.HeaderFlags.Pitch;
686  header->PitchOrLinearSize = rowPitch;
687  }
688 
689  if (ddpf.Size == 0)
690  {
691  header->PixelFormat = DDS.DDSPixelFormat.DX10;
692 
693  var ext = (DDS.HeaderDXT10*)((byte*)(header) + Utilities.SizeOf<DDS.Header>());
694 
695  Utilities.ClearMemory((IntPtr) ext, 0, Utilities.SizeOf<DDS.HeaderDXT10>());
696 
697  ext->DXGIFormat = description.Format;
698  switch (description.Dimension)
699  {
700  case TextureDimension.Texture1D:
701  ext->ResourceDimension = DDS.ResourceDimension.Texture1D;
702  break;
703  case TextureDimension.Texture2D:
704  case TextureDimension.TextureCube:
705  ext->ResourceDimension = DDS.ResourceDimension.Texture2D;
706  break;
707  case TextureDimension.Texture3D:
708  ext->ResourceDimension = DDS.ResourceDimension.Texture3D;
709  break;
710 
711  }
712 
713  if (description.Dimension == TextureDimension.TextureCube)
714  {
715  ext->MiscFlags |= DDS.ResourceOptionFlags.TextureCube;
716  ext->ArraySize = description.ArraySize / 6;
717  }
718  else
719  {
720  ext->ArraySize = description.ArraySize;
721  }
722  }
723  else
724  {
725  header->PixelFormat = ddpf;
726  }
727  }
728 
729  enum TEXP_LEGACY_FORMAT
730  {
731  UNKNOWN = 0,
732  R8G8B8,
733  R3G3B2,
734  A8R3G3B2,
735  P8,
736  A8P8,
737  A4L4,
738  B4G4R4A4,
739  };
740 
741  private static TEXP_LEGACY_FORMAT FindLegacyFormat(ConversionFlags flags)
742  {
743  var lformat = TEXP_LEGACY_FORMAT.UNKNOWN;
744 
745  if ((flags & ConversionFlags.Pal8) != 0)
746  {
747  lformat = (flags & ConversionFlags.FormatA8P8) != 0 ? TEXP_LEGACY_FORMAT.A8P8 : TEXP_LEGACY_FORMAT.P8;
748  }
749  else if ((flags & ConversionFlags.Format888) != 0)
750  lformat = TEXP_LEGACY_FORMAT.R8G8B8;
751  else if ((flags & ConversionFlags.Format332) != 0)
752  lformat = TEXP_LEGACY_FORMAT.R3G3B2;
753  else if ((flags & ConversionFlags.Format8332) != 0)
754  lformat = TEXP_LEGACY_FORMAT.A8R3G3B2;
755  else if ((flags & ConversionFlags.Format44) != 0)
756  lformat = TEXP_LEGACY_FORMAT.A4L4;
757 #if DIRECTX11_1
758  else if ((flags & ConversionFlags.Format4444) != 0)
759  lformat = TEXP_LEGACY_FORMAT.B4G4R4A4;
760 #endif
761  return lformat;
762  }
763 
764  /// <summary>
765  // Converts an image row with optional clearing of alpha value to 1.0
766  /// </summary>
767  /// <param name="pDestination"></param>
768  /// <param name="outSize"></param>
769  /// <param name="outFormat"></param>
770  /// <param name="pSource"></param>
771  /// <param name="inSize"></param>
772  /// <param name="inFormat"></param>
773  /// <param name="pal8"></param>
774  /// <param name="flags"></param>
775  /// <returns></returns>
776  static unsafe bool LegacyExpandScanline( IntPtr pDestination, int outSize, PixelFormat outFormat,
777  IntPtr pSource, int inSize, TEXP_LEGACY_FORMAT inFormat,
778  uint* pal8, ScanlineFlags flags )
779  {
780  switch (inFormat)
781  {
782  case TEXP_LEGACY_FORMAT.R8G8B8:
783  if (outFormat != PixelFormat.R8G8B8A8_UNorm)
784  return false;
785 
786  // D3DFMT_R8G8B8 -> PixelFormat.R8G8B8A8_UNorm
787  {
788  var sPtr = (byte*) (pSource);
789  var dPtr = (uint*) (pDestination);
790 
791  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 3, ocount += 4)
792  {
793  // 24bpp Direct3D 9 files are actually BGR, so need to swizzle as well
794  uint t1 = (uint)(*(sPtr) << 16);
795  uint t2 = (uint)(*(sPtr + 1) << 8);
796  uint t3 = *(sPtr + 2);
797 
798  *(dPtr++) = (t1 | t2 | t3 | 0xff000000);
799  sPtr += 3;
800  }
801  }
802  return true;
803 
804  case TEXP_LEGACY_FORMAT.R3G3B2:
805  switch (outFormat)
806  {
807  case PixelFormat.R8G8B8A8_UNorm:
808  // D3DFMT_R3G3B2 -> PixelFormat.R8G8B8A8_UNorm
809  {
810  var sPtr = (byte*) (pSource);
811  var dPtr = (uint*) (pDestination);
812 
813  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4)
814  {
815  byte t = *(sPtr++);
816 
817  uint t1 = (uint)((t & 0xe0) | ((t & 0xe0) >> 3) | ((t & 0xc0) >> 6));
818  uint t2 = (uint)(((t & 0x1c) << 11) | ((t & 0x1c) << 8) | ((t & 0x18) << 5));
819  uint t3 = (uint)(((t & 0x03) << 22) | ((t & 0x03) << 20) | ((t & 0x03) << 18) | ((t & 0x03) << 16));
820 
821  *(dPtr++) = (t1 | t2 | t3 | 0xff000000);
822  }
823  }
824  return true;
825 
826  case PixelFormat.B5G6R5_UNorm:
827  // D3DFMT_R3G3B2 -> PixelFormat.B5G6R5_UNorm
828  {
829  var sPtr = (byte*) (pSource);
830  var dPtr = (short*) (pDestination);
831 
832  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 2)
833  {
834  byte t = *(sPtr++);
835 
836  var t1 = (uint) (((t & 0xe0) << 8) | ((t & 0xc0) << 5));
837  var t2 = (uint) (((t & 0x1c) << 6) | ((t & 0x1c) << 3));
838  var t3 = (uint) (((t & 0x03) << 3) | ((t & 0x03) << 1) | ((t & 0x02) >> 1));
839 
840  *(dPtr++) = (short) (t1 | t2 | t3);
841  }
842  }
843  return true;
844  }
845  break;
846 
847  case TEXP_LEGACY_FORMAT.A8R3G3B2:
848  if (outFormat != PixelFormat.R8G8B8A8_UNorm)
849  return false;
850 
851  // D3DFMT_A8R3G3B2 -> PixelFormat.R8G8B8A8_UNorm
852  {
853  var sPtr = (short*) (pSource);
854  var dPtr = (uint*) (pDestination);
855 
856  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
857  {
858  short t = *(sPtr++);
859 
860  uint t1 = (uint)((t & 0x00e0) | ((t & 0x00e0) >> 3) | ((t & 0x00c0) >> 6));
861  uint t2 = (uint)(((t & 0x001c) << 11) | ((t & 0x001c) << 8) | ((t & 0x0018) << 5));
862  uint t3 = (uint)(((t & 0x0003) << 22) | ((t & 0x0003) << 20) | ((t & 0x0003) << 18) | ((t & 0x0003) << 16));
863  uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((t & 0xff00) << 16));
864 
865  *(dPtr++) = (t1 | t2 | t3 | ta);
866  }
867  }
868  return true;
869 
870  case TEXP_LEGACY_FORMAT.P8:
871  if ((outFormat != PixelFormat.R8G8B8A8_UNorm) || pal8 == null)
872  return false;
873 
874  // D3DFMT_P8 -> PixelFormat.R8G8B8A8_UNorm
875  {
876  byte* sPtr = (byte*) (pSource);
877  var dPtr = (uint*) (pDestination);
878 
879  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4)
880  {
881  byte t = *(sPtr++);
882 
883  *(dPtr++) = pal8[t];
884  }
885  }
886  return true;
887 
888  case TEXP_LEGACY_FORMAT.A8P8:
889  if ((outFormat != PixelFormat.R8G8B8A8_UNorm) || pal8 == null)
890  return false;
891 
892  // D3DFMT_A8P8 -> PixelFormat.R8G8B8A8_UNorm
893  {
894  short* sPtr = (short*) (pSource);
895  int* dPtr = (int*) (pDestination);
896 
897  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
898  {
899  short t = *(sPtr++);
900 
901  uint t1 = pal8[t & 0xff];
902  uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((t & 0xff00) << 16));
903 
904  *(dPtr++) = (int) (t1 | ta);
905  }
906  }
907  return true;
908 
909  case TEXP_LEGACY_FORMAT.A4L4:
910  switch (outFormat)
911  {
912 #if DIRECTX11_1
913  case PixelFormat.B4G4R4A4_UNorm :
914  // D3DFMT_A4L4 -> PixelFormat.B4G4R4A4_UNorm
915  {
916  byte * sPtr = (byte*)(pSource);
917  short * dPtr = (short*)(pDestination);
918 
919  for( int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 2 )
920  {
921  byte t = *(sPtr++);
922 
923  short t1 = (short)(t & 0x0f);
924  ushort ta = (flags & ScanlineFlags.SetAlpha ) != 0 ? (ushort)0xf000 : (ushort)((t & 0xf0) << 8);
925 
926  *(dPtr++) = (short)(t1 | (t1 << 4) | (t1 << 8) | ta);
927  }
928  }
929  return true;
930 #endif
931  // DXGI_1_2_FORMATS
932 
933  case PixelFormat.R8G8B8A8_UNorm:
934  // D3DFMT_A4L4 -> PixelFormat.R8G8B8A8_UNorm
935  {
936  byte* sPtr = (byte*) (pSource);
937  var dPtr = (uint*) (pDestination);
938 
939  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); ++icount, ocount += 4)
940  {
941  byte t = *(sPtr++);
942 
943  uint t1 = (uint)(((t & 0x0f) << 4) | (t & 0x0f));
944  uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) (((t & 0xf0) << 24) | ((t & 0xf0) << 20)));
945 
946  *(dPtr++) = (t1 | (t1 << 8) | (t1 << 16) | ta);
947  }
948  }
949  return true;
950  }
951  break;
952 
953 #if !DIRECTX11_1
954  case TEXP_LEGACY_FORMAT.B4G4R4A4:
955  if (outFormat != PixelFormat.R8G8B8A8_UNorm)
956  return false;
957 
958  // D3DFMT_A4R4G4B4 -> PixelFormat.R8G8B8A8_UNorm
959  {
960  short* sPtr = (short*) (pSource);
961  var dPtr = (uint*) (pDestination);
962 
963  for (int ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
964  {
965  short t = *(sPtr++);
966 
967  uint t1 = (uint)(((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8));
968  uint t2 = (uint)(((t & 0x00f0) << 8) | ((t & 0x00f0) << 4));
969  uint t3 = (uint)(((t & 0x000f) << 20) | ((t & 0x000f) << 16));
970  uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) (((t & 0xf000) << 16) | ((t & 0xf000) << 12)));
971 
972  *(dPtr++) = (t1 | t2 | t3 | ta);
973  }
974  }
975  return true;
976 #endif
977  }
978  return false;
979  }
980 
981  /// <summary>
982  /// Load a DDS file in memory
983  /// </summary>
984  /// <param name="pSource"></param>
985  /// <param name="size"></param>
986  /// <param name="handle"></param>
987  /// <returns></returns>
988  public unsafe static Image LoadFromDDSMemory(IntPtr pSource, int size, bool makeACopy, GCHandle? handle)
989  {
990  var flags = makeACopy ? DDSFlags.CopyMemory : DDSFlags.None;
991 
992 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
993  // Directly load image as RGBA instead of BGRA, because OpenGL ES devices don't support it out of the box (extension).
994  flags |= DDSFlags.ForceRgb;
995 #endif
996 
997  ConversionFlags convFlags;
998  ImageDescription mdata;
999  // If the memory pointed is not a DDS memory, return null.
1000  if (!DecodeDDSHeader(pSource, size, flags, out mdata, out convFlags))
1001  return null;
1002 
1003  int offset = sizeof (uint) + Utilities.SizeOf<DDS.Header>();
1004  if ((convFlags & ConversionFlags.DX10) != 0)
1005  offset += Utilities.SizeOf<DDS.HeaderDXT10>();
1006 
1007  var pal8 = (uint*) 0;
1008  if ((convFlags & ConversionFlags.Pal8) != 0)
1009  {
1010  pal8 = (uint*) ((byte*) (pSource) + offset);
1011  offset += (256 * sizeof (uint));
1012  }
1013 
1014  if (size < offset)
1015  throw new InvalidOperationException();
1016 
1017  var image = CreateImageFromDDS(pSource, offset, size - offset, mdata, (flags & DDSFlags.LegacyDword) != 0 ? Image.PitchFlags.LegacyDword : Image.PitchFlags.None, convFlags, pal8, handle);
1018  return image;
1019  }
1020 
1021  public static void SaveToDDSStream(PixelBuffer[] pixelBuffers, int count, ImageDescription description, System.IO.Stream imageStream)
1022  {
1023  SaveToDDSStream(pixelBuffers, count, description, DDSFlags.None, imageStream);
1024  }
1025 
1026  //-------------------------------------------------------------------------------------
1027  // Save a DDS to a stream
1028  //-------------------------------------------------------------------------------------
1029  public unsafe static void SaveToDDSStream(PixelBuffer[] pixelBuffers, int count, ImageDescription metadata, DDSFlags flags, System.IO.Stream stream)
1030  {
1031  // Determine memory required
1032  int totalSize = 0;
1033  int headerSize = 0;
1034  EncodeDDSHeader(metadata, flags, IntPtr.Zero, 0, out totalSize);
1035  headerSize = totalSize;
1036 
1037  int maxSlice = 0;
1038 
1039  for (int i = 0; i < pixelBuffers.Length; ++i)
1040  {
1041  int slice = pixelBuffers[i].BufferStride;
1042  totalSize += slice;
1043  if (slice > maxSlice)
1044  maxSlice = slice;
1045  }
1046 
1047  Debug.Assert(totalSize > 0);
1048 
1049  // Allocate a single temporary buffer to save the headers and each slice.
1050  var buffer = new byte[Math.Max(maxSlice, headerSize)];
1051 
1052  fixed (void* pbuffer = buffer)
1053  {
1054  int required;
1055  EncodeDDSHeader(metadata, flags, (IntPtr) pbuffer, headerSize, out required);
1056  stream.Write(buffer, 0, headerSize);
1057  }
1058 
1059  int remaining = totalSize - headerSize;
1060  Debug.Assert(remaining > 0);
1061 
1062  int index = 0;
1063  for (int item = 0; item < metadata.ArraySize; ++item)
1064  {
1065  int d = metadata.Depth;
1066 
1067  for (int level = 0; level < metadata.MipLevels; ++level)
1068  {
1069  for (int slice = 0; slice < d; ++slice)
1070  {
1071  int pixsize = pixelBuffers[index].BufferStride;
1072  Utilities.Read(pixelBuffers[index].DataPointer, buffer, 0, pixsize);
1073  stream.Write(buffer, 0, pixsize);
1074  ++index;
1075  }
1076 
1077  if (d > 1)
1078  d >>= 1;
1079  }
1080  }
1081  }
1082 
1083  /// <summary>
1084  /// Converts or copies image data from pPixels into scratch image data
1085  /// </summary>
1086  /// <param name="pDDS"></param>
1087  /// <param name="offset"></param>
1088  /// <param name="size"></param>
1089  /// <param name="metadata"></param>
1090  /// <param name="cpFlags"></param>
1091  /// <param name="convFlags"></param>
1092  /// <param name="pal8"></param>
1093  /// <param name="handle"></param>
1094  /// <returns></returns>
1095  private static unsafe Image CreateImageFromDDS(IntPtr pDDS, int offset, int size, ImageDescription metadata, Image.PitchFlags cpFlags, ConversionFlags convFlags, uint* pal8, GCHandle? handle)
1096  {
1097  if ((convFlags & ConversionFlags.Expand) != 0)
1098  {
1099  if ((convFlags & ConversionFlags.Format888) != 0)
1100  cpFlags |= Image.PitchFlags.Bpp24;
1101  else if ((convFlags & (ConversionFlags.Format565 | ConversionFlags.Format5551 | ConversionFlags.Format4444 | ConversionFlags.Format8332 | ConversionFlags.FormatA8P8)) != 0)
1102  cpFlags |= Image.PitchFlags.Bpp16;
1103  else if ((convFlags & (ConversionFlags.Format44 | ConversionFlags.Format332 | ConversionFlags.Pal8)) != 0)
1104  cpFlags |= Image.PitchFlags.Bpp8;
1105  }
1106 
1107  // If source image == dest image and no swizzle/alpha is required, we can return it as-is
1108  var isCopyNeeded = (convFlags & (ConversionFlags.Expand | ConversionFlags.CopyMemory)) != 0 || ((cpFlags & Image.PitchFlags.LegacyDword) != 0);
1109 
1110  var image = new Image(metadata, pDDS, offset, handle, !isCopyNeeded, cpFlags);
1111 
1112  // Ensure there is enough data to copy from.
1113  Debug.Assert(size >= image.TotalSizeInBytes);
1114 
1115  if (!isCopyNeeded && (convFlags & (ConversionFlags.Swizzle | ConversionFlags.NoAlpha)) == 0)
1116  return image;
1117 
1118  var imageDst = isCopyNeeded ? new Image(metadata, IntPtr.Zero, 0, null, false) : image;
1119 
1120  var images = image.PixelBuffer;
1121  var imagesDst = imageDst.PixelBuffer;
1122 
1123  ScanlineFlags tflags = (convFlags & ConversionFlags.NoAlpha) != 0 ? ScanlineFlags.SetAlpha : ScanlineFlags.None;
1124  if ((convFlags & ConversionFlags.Swizzle) != 0)
1125  tflags |= ScanlineFlags.Legacy;
1126 
1127  int index = 0;
1128 
1129  int checkSize = size;
1130 
1131  for (int arrayIndex = 0; arrayIndex < metadata.ArraySize; arrayIndex++)
1132  {
1133  int d = metadata.Depth;
1134  // Else we need to go through each mips/depth slice to convert all scanlines.
1135  for (int level = 0; level < metadata.MipLevels; ++level)
1136  {
1137  for (int slice = 0; slice < d; ++slice, ++index)
1138  {
1139  IntPtr pSrc = images[index].DataPointer;
1140  IntPtr pDest = imagesDst[index].DataPointer;
1141  checkSize -= images[index].BufferStride;
1142  if (checkSize < 0)
1143  throw new InvalidOperationException("Unexpected end of buffer");
1144 
1145  if (metadata.Format.IsCompressed())
1146  {
1147  Utilities.CopyMemory(pDest, pSrc, Math.Min(images[index].BufferStride, imagesDst[index].BufferStride));
1148  }
1149  else
1150  {
1151  int spitch = images[index].RowStride;
1152  int dpitch = imagesDst[index].RowStride;
1153 
1154  for (int h = 0; h < images[index].Height; ++h)
1155  {
1156  if ((convFlags & ConversionFlags.Expand) != 0)
1157  {
1158 #if DIRECTX11_1
1159  if ((convFlags & (ConversionFlags.Format565 | ConversionFlags.Format5551 | ConversionFlags.Format4444)) != 0)
1160 #else
1161  if ((convFlags & (ConversionFlags.Format565 | ConversionFlags.Format5551)) != 0)
1162 #endif
1163  {
1164  ExpandScanline(pDest, dpitch, pSrc, spitch, (convFlags & ConversionFlags.Format565) != 0 ? PixelFormat.B5G6R5_UNorm : PixelFormat.B5G5R5A1_UNorm, tflags);
1165  }
1166  else
1167  {
1168  var lformat = FindLegacyFormat(convFlags);
1169  LegacyExpandScanline(pDest, dpitch, metadata.Format, pSrc, spitch, lformat, pal8, tflags);
1170  }
1171  }
1172  else if ((convFlags & ConversionFlags.Swizzle) != 0)
1173  {
1174  SwizzleScanline(pDest, dpitch, pSrc, spitch, metadata.Format, tflags);
1175  }
1176  else
1177  {
1178  if (pSrc != pDest)
1179  CopyScanline(pDest, dpitch, pSrc, spitch, metadata.Format, tflags);
1180  }
1181 
1182  pSrc = (IntPtr) ((byte*) pSrc + spitch);
1183  pDest = (IntPtr) ((byte*) pDest + dpitch);
1184  }
1185  }
1186  }
1187 
1188  if (d > 1)
1189  d >>= 1;
1190  }
1191  }
1192 
1193  // Return the imageDst or the original image
1194  if (isCopyNeeded)
1195  {
1196  image.Dispose();
1197  image = imageDst;
1198  }
1199  return image;
1200  }
1201 
1202 
1203  [Flags]
1204  internal enum ScanlineFlags
1205  {
1206  None = 0,
1207  SetAlpha = 0x1, // Set alpha channel to known opaque value
1208  Legacy = 0x2, // Enables specific legacy format conversion cases
1209  };
1210 
1211  /// <summary>
1212  /// Converts an image row with optional clearing of alpha value to 1.0
1213  /// </summary>
1214  /// <param name="pDestination"></param>
1215  /// <param name="outSize"></param>
1216  /// <param name="pSource"></param>
1217  /// <param name="inSize"></param>
1218  /// <param name="inFormat"></param>
1219  /// <param name="flags"></param>
1220  private unsafe static void ExpandScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat inFormat, ScanlineFlags flags)
1221  {
1222  switch (inFormat)
1223  {
1224  case PixelFormat.B5G6R5_UNorm:
1225  // PixelFormat.B5G6R5_UNorm -> PixelFormat.R8G8B8A8_UNorm
1226  {
1227  var sPtr = (ushort*) (pSource);
1228  var dPtr = (uint*) (pDestination);
1229 
1230  for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1231  {
1232  ushort t = *(sPtr++);
1233 
1234  uint t1 = (uint) (((t & 0xf800) >> 8) | ((t & 0xe000) >> 13));
1235  uint t2 = (uint) (((t & 0x07e0) << 5) | ((t & 0x0600) >> 5));
1236  uint t3 = (uint) (((t & 0x001f) << 19) | ((t & 0x001c) << 14));
1237 
1238  *(dPtr++) = t1 | t2 | t3 | 0xff000000;
1239  }
1240  }
1241  break;
1242 
1243  case PixelFormat.B5G5R5A1_UNorm:
1244  // PixelFormat.B5G5R5A1_UNorm -> PixelFormat.R8G8B8A8_UNorm
1245  {
1246  var sPtr = (ushort*) (pSource);
1247  var dPtr = (uint*) (pDestination);
1248 
1249  for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1250  {
1251  ushort t = *(sPtr++);
1252 
1253  uint t1 = (uint) (((t & 0x7c00) >> 7) | ((t & 0x7000) >> 12));
1254  uint t2 = (uint) (((t & 0x03e0) << 6) | ((t & 0x0380) << 1));
1255  uint t3 = (uint) (((t & 0x001f) << 19) | ((t & 0x001c) << 14));
1256  uint ta = (uint) ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (((t & 0x8000) != 0 ? 0xff000000 : 0)));
1257 
1258  *(dPtr++) = t1 | t2 | t3 | ta;
1259  }
1260  }
1261  break;
1262 
1263 #if DIRECTX11_1
1264  case PixelFormat.B4G4R4A4_UNorm:
1265  // PixelFormat.B4G4R4A4_UNorm -> PixelFormat.R8G8B8A8_UNorm
1266  {
1267  var sPtr = (ushort*) (pSource);
1268  var dPtr = (uint*) (pDestination);
1269 
1270  for (uint ocount = 0, icount = 0; ((icount < inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1271  {
1272  ushort t = *(sPtr++);
1273 
1274  uint t1 = (uint) (((t & 0x0f00) >> 4) | ((t & 0x0f00) >> 8));
1275  uint t2 = (uint) (((t & 0x00f0) << 8) | ((t & 0x00f0) << 4));
1276  uint t3 = (uint) (((t & 0x000f) << 20) | ((t & 0x000f) << 16));
1277  uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((((t & 0xf000) << 16) | ((t & 0xf000) << 12)));
1278 
1279  *(dPtr++) = t1 | t2 | t3 | ta;
1280  }
1281  }
1282  break;
1283 #endif
1284 // DXGI_1_2_FORMATS
1285  }
1286  }
1287 
1288 
1289  /// <summary>
1290  /// Copies an image row with optional clearing of alpha value to 1.0.
1291  /// </summary>
1292  /// <remarks>
1293  /// This method can be used in place as well, otherwise copies the image row unmodified.
1294  /// </remarks>
1295  /// <param name="pDestination">The destination buffer.</param>
1296  /// <param name="outSize">The destination size.</param>
1297  /// <param name="pSource">The source buffer.</param>
1298  /// <param name="inSize">The source size.</param>
1299  /// <param name="format">The <see cref="Format"/> of the source scanline.</param>
1300  /// <param name="flags">Scanline flags used when copying the scanline.</param>
1301  internal static unsafe void CopyScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat format, ScanlineFlags flags)
1302  {
1303  if ((flags & ScanlineFlags.SetAlpha) != 0)
1304  {
1305  switch (format)
1306  {
1307  //-----------------------------------------------------------------------------
1308  case PixelFormat.R32G32B32A32_Typeless:
1309  case PixelFormat.R32G32B32A32_Float:
1310  case PixelFormat.R32G32B32A32_UInt:
1311  case PixelFormat.R32G32B32A32_SInt:
1312  {
1313  uint alpha;
1314  if (format == PixelFormat.R32G32B32A32_Float)
1315  alpha = 0x3f800000;
1316  else if (format == PixelFormat.R32G32B32A32_SInt)
1317  alpha = 0x7fffffff;
1318  else
1319  alpha = 0xffffffff;
1320 
1321  if (pDestination == pSource)
1322  {
1323  var dPtr = (uint*)(pDestination);
1324  for (int count = 0; count < outSize; count += 16)
1325  {
1326  dPtr += 3;
1327  *(dPtr++) = alpha;
1328  }
1329  }
1330  else
1331  {
1332  var sPtr = (uint*)(pSource);
1333  var dPtr = (uint*)(pDestination);
1334  int size = Math.Min(outSize, inSize);
1335  for (int count = 0; count < size; count += 16)
1336  {
1337  *(dPtr++) = *(sPtr++);
1338  *(dPtr++) = *(sPtr++);
1339  *(dPtr++) = *(sPtr++);
1340  *(dPtr++) = alpha;
1341  sPtr++;
1342  }
1343  }
1344  }
1345  return;
1346 
1347  //-----------------------------------------------------------------------------
1348  case PixelFormat.R16G16B16A16_Typeless:
1349  case PixelFormat.R16G16B16A16_Float:
1350  case PixelFormat.R16G16B16A16_UNorm:
1351  case PixelFormat.R16G16B16A16_UInt:
1352  case PixelFormat.R16G16B16A16_SNorm:
1353  case PixelFormat.R16G16B16A16_SInt:
1354  {
1355  ushort alpha;
1356  if (format == PixelFormat.R16G16B16A16_Float)
1357  alpha = 0x3c00;
1358  else if (format == PixelFormat.R16G16B16A16_SNorm || format == PixelFormat.R16G16B16A16_SInt)
1359  alpha = 0x7fff;
1360  else
1361  alpha = 0xffff;
1362 
1363  if (pDestination == pSource)
1364  {
1365  var dPtr = (ushort*)(pDestination);
1366  for (int count = 0; count < outSize; count += 8)
1367  {
1368  dPtr += 3;
1369  *(dPtr++) = alpha;
1370  }
1371  }
1372  else
1373  {
1374  var sPtr = (ushort*)(pSource);
1375  var dPtr = (ushort*)(pDestination);
1376  int size = Math.Min(outSize, inSize);
1377  for (int count = 0; count < size; count += 8)
1378  {
1379  *(dPtr++) = *(sPtr++);
1380  *(dPtr++) = *(sPtr++);
1381  *(dPtr++) = *(sPtr++);
1382  *(dPtr++) = alpha;
1383  sPtr++;
1384  }
1385  }
1386  }
1387  return;
1388 
1389  //-----------------------------------------------------------------------------
1390  case PixelFormat.R10G10B10A2_Typeless:
1391  case PixelFormat.R10G10B10A2_UNorm:
1392  case PixelFormat.R10G10B10A2_UInt:
1393  case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm:
1394  {
1395  if (pDestination == pSource)
1396  {
1397  var dPtr = (uint*)(pDestination);
1398  for (int count = 0; count < outSize; count += 4)
1399  {
1400  *dPtr |= 0xC0000000;
1401  ++dPtr;
1402  }
1403  }
1404  else
1405  {
1406  var sPtr = (uint*)(pSource);
1407  var dPtr = (uint*)(pDestination);
1408  int size = Math.Min(outSize, inSize);
1409  for (int count = 0; count < size; count += 4)
1410  {
1411  *(dPtr++) = *(sPtr++) | 0xC0000000;
1412  }
1413  }
1414  }
1415  return;
1416 
1417  //-----------------------------------------------------------------------------
1418  case PixelFormat.R8G8B8A8_Typeless:
1419  case PixelFormat.R8G8B8A8_UNorm:
1420  case PixelFormat.R8G8B8A8_UNorm_SRgb:
1421  case PixelFormat.R8G8B8A8_UInt:
1422  case PixelFormat.R8G8B8A8_SNorm:
1423  case PixelFormat.R8G8B8A8_SInt:
1424  case PixelFormat.B8G8R8A8_UNorm:
1425  case PixelFormat.B8G8R8A8_Typeless:
1426  case PixelFormat.B8G8R8A8_UNorm_SRgb:
1427  {
1428  uint alpha = (format == PixelFormat.R8G8B8A8_SNorm || format == PixelFormat.R8G8B8A8_SInt) ? 0x7f000000 : 0xff000000;
1429 
1430  if (pDestination == pSource)
1431  {
1432  var dPtr = (uint*)(pDestination);
1433  for (int count = 0; count < outSize; count += 4)
1434  {
1435  uint t = *dPtr & 0xFFFFFF;
1436  t |= alpha;
1437  *(dPtr++) = t;
1438  }
1439  }
1440  else
1441  {
1442  var sPtr = (uint*)(pSource);
1443  var dPtr = (uint*)(pDestination);
1444  int size = Math.Min(outSize, inSize);
1445  for (int count = 0; count < size; count += 4)
1446  {
1447  uint t = *(sPtr++) & 0xFFFFFF;
1448  t |= alpha;
1449  *(dPtr++) = t;
1450  }
1451  }
1452  }
1453  return;
1454 
1455  //-----------------------------------------------------------------------------
1456  case PixelFormat.B5G5R5A1_UNorm:
1457  {
1458  if (pDestination == pSource)
1459  {
1460  var dPtr = (ushort*)(pDestination);
1461  for (int count = 0; count < outSize; count += 2)
1462  {
1463  *(dPtr++) |= 0x8000;
1464  }
1465  }
1466  else
1467  {
1468  var sPtr = (ushort*)(pSource);
1469  var dPtr = (ushort*)(pDestination);
1470  int size = Math.Min(outSize, inSize);
1471  for (int count = 0; count < size; count += 2)
1472  {
1473  *(dPtr++) = (ushort)(*(sPtr++) | 0x8000);
1474  }
1475  }
1476  }
1477  return;
1478 
1479  //-----------------------------------------------------------------------------
1480  case PixelFormat.A8_UNorm:
1481  Utilities.ClearMemory(pDestination, 0xff, outSize);
1482  return;
1483 
1484 #if DIRECTX11_1
1485  //-----------------------------------------------------------------------------
1486  case PixelFormat.B4G4R4A4_UNorm:
1487  {
1488  if (pDestination == pSource)
1489  {
1490  var dPtr = (ushort*) (pDestination);
1491  for (int count = 0; count < outSize; count += 2)
1492  {
1493  *(dPtr++) |= 0xF000;
1494  }
1495  }
1496  else
1497  {
1498  var sPtr = (ushort*) (pSource);
1499  var dPtr = (ushort*) (pDestination);
1500  int size = Math.Min(outSize, inSize);
1501  for (int count = 0; count < size; count += 2)
1502  {
1503  *(dPtr++) = (ushort) (*(sPtr++) | 0xF000);
1504  }
1505  }
1506  }
1507  return;
1508 #endif
1509  // DXGI_1_2_FORMATS
1510  }
1511  }
1512 
1513  // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
1514  if (pDestination == pSource)
1515  return;
1516 
1517  Utilities.CopyMemory(pDestination, pSource, Math.Min(outSize, inSize));
1518  }
1519 
1520  /// <summary>
1521  /// Swizzles (RGB &lt;-&gt; BGR) an image row with optional clearing of alpha value to 1.0.
1522  /// </summary>
1523  /// <param name="pDestination">The destination buffer.</param>
1524  /// <param name="outSize">The destination size.</param>
1525  /// <param name="pSource">The source buffer.</param>
1526  /// <param name="inSize">The source size.</param>
1527  /// <param name="format">The <see cref="Format"/> of the source scanline.</param>
1528  /// <param name="flags">Scanline flags used when copying the scanline.</param>
1529  /// <remarks>
1530  /// This method can be used in place as well, otherwise copies the image row unmodified.
1531  /// </remarks>
1532  internal static unsafe void SwizzleScanline(IntPtr pDestination, int outSize, IntPtr pSource, int inSize, PixelFormat format, ScanlineFlags flags)
1533  {
1534  switch (format)
1535  {
1536  //---------------------------------------------------------------------------------
1537  case PixelFormat.R10G10B10A2_Typeless:
1538  case PixelFormat.R10G10B10A2_UNorm:
1539  case PixelFormat.R10G10B10A2_UInt:
1540  case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm:
1541  if ((flags & ScanlineFlags.Legacy) != 0)
1542  {
1543  // Swap Red (R) and Blue (B) channel (used for D3DFMT_A2R10G10B10 legacy sources)
1544  if (pDestination == pSource)
1545  {
1546  var dPtr = (uint*)(pDestination);
1547  for (int count = 0; count < outSize; count += 4)
1548  {
1549  uint t = *dPtr;
1550 
1551  uint t1 = (t & 0x3ff00000) >> 20;
1552  uint t2 = (t & 0x000003ff) << 20;
1553  uint t3 = (t & 0x000ffc00);
1554  uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xC0000000 : (t & 0xC0000000);
1555 
1556  *(dPtr++) = t1 | t2 | t3 | ta;
1557  }
1558  }
1559  else
1560  {
1561  var sPtr = (uint*)(pSource);
1562  var dPtr = (uint*)(pDestination);
1563  int size = Math.Min(outSize, inSize);
1564  for (int count = 0; count < size; count += 4)
1565  {
1566  uint t = *(sPtr++);
1567 
1568  uint t1 = (t & 0x3ff00000) >> 20;
1569  uint t2 = (t & 0x000003ff) << 20;
1570  uint t3 = (t & 0x000ffc00);
1571  uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xC0000000 : (t & 0xC0000000);
1572 
1573  *(dPtr++) = t1 | t2 | t3 | ta;
1574  }
1575  }
1576  return;
1577  }
1578  break;
1579 
1580  //---------------------------------------------------------------------------------
1581  case PixelFormat.R8G8B8A8_Typeless:
1582  case PixelFormat.R8G8B8A8_UNorm:
1583  case PixelFormat.R8G8B8A8_UNorm_SRgb:
1584  case PixelFormat.B8G8R8A8_UNorm:
1585  case PixelFormat.B8G8R8X8_UNorm:
1586  case PixelFormat.B8G8R8A8_Typeless:
1587  case PixelFormat.B8G8R8A8_UNorm_SRgb:
1588  case PixelFormat.B8G8R8X8_Typeless:
1589  case PixelFormat.B8G8R8X8_UNorm_SRgb:
1590  // Swap Red (R) and Blue (B) channels (used to convert from DXGI 1.1 BGR formats to DXGI 1.0 RGB)
1591  if (pDestination == pSource)
1592  {
1593  var dPtr = (uint*)(pDestination);
1594  for (int count = 0; count < outSize; count += 4)
1595  {
1596  uint t = *dPtr;
1597 
1598  uint t1 = (t & 0x00ff0000) >> 16;
1599  uint t2 = (t & 0x000000ff) << 16;
1600  uint t3 = (t & 0x0000ff00);
1601  uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (t & 0xFF000000);
1602 
1603  *(dPtr++) = t1 | t2 | t3 | ta;
1604  }
1605  }
1606  else
1607  {
1608  var sPtr = (uint*)(pSource);
1609  var dPtr = (uint*)(pDestination);
1610  int size = Math.Min(outSize, inSize);
1611  for (int count = 0; count < size; count += 4)
1612  {
1613  uint t = *(sPtr++);
1614 
1615  uint t1 = (t & 0x00ff0000) >> 16;
1616  uint t2 = (t & 0x000000ff) << 16;
1617  uint t3 = (t & 0x0000ff00);
1618  uint ta = (flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (t & 0xFF000000);
1619 
1620  *(dPtr++) = t1 | t2 | t3 | ta;
1621  }
1622  }
1623  return;
1624  }
1625 
1626  // Fall-through case is to just use memcpy (assuming this is not an in-place operation)
1627  if (pDestination == pSource)
1628  return;
1629 
1630  Utilities.CopyMemory(pDestination, pSource, Math.Min(outSize, inSize));
1631  }
1632 
1633  }
1634 }
_In_ size_t _In_ const TexMetadata _In_ DWORD cpFlags
Definition: DirectXTexP.h:116
size_t outSize
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Definition: DirectXTexP.h:170
TextureDimension
Defines the dimension of a texture.
Flags
Enumeration of the new Assimp's flags.
_In_ size_t _In_ const TexMetadata & metadata
Definition: DirectXTexP.h:116
_In_ size_t count
Definition: DirectXTexP.h:174
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
Internal structure used to describe a DDS pixel format.
Definition: DDS.cs:93
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
Definition: DirectXTexP.h:175
_In_ size_t _In_ size_t size
Definition: DirectXTexP.h:175
PixelFormat
Defines various types of pixel formats.
Definition: PixelFormat.cs:32
LegacyMap(PixelFormat format, ConversionFlags conversionFlags, DDS.DDSPixelFormat pixelFormat)
Initializes a new instance of the LegacyMap struct.
Definition: DDSHelper.cs:114
HRESULT LoadFromDDSMemory(_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata *metadata, _Out_ ScratchImage &image)