77 using System.Diagnostics;
78 using System.Runtime.InteropServices;
79 using SiliconStudio.Core;
81 namespace SiliconStudio.
Paradox.Graphics
83 internal class DDSHelper
86 public enum ConversionFlags
105 [StructLayout(LayoutKind.Sequential, Pack = 1)]
117 ConversionFlags = conversionFlags;
126 private static readonly
LegacyMap[] LegacyMaps =
new[]
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)),
149 new LegacyMap(
PixelFormat.R8G8B8A8_UNorm, ConversionFlags.NoAlpha, DDS.DDSPixelFormat.X8B8G8R8),
152 new LegacyMap(
PixelFormat.R10G10B10A2_UNorm, ConversionFlags.Swizzle,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0x000003ff, 0x000ffc00, 0x3ff00000, 0xc0000000)),
154 new LegacyMap(
PixelFormat.R10G10B10A2_UNorm, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)),
158 | ConversionFlags.NoAlpha
159 | ConversionFlags.Format888, DDS.DDSPixelFormat.R8G8B8),
162 new LegacyMap(
PixelFormat.B5G5R5A1_UNorm, ConversionFlags.Format5551, DDS.DDSPixelFormat.A1R5G5B5),
164 | ConversionFlags.NoAlpha,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x7c00, 0x03e0, 0x001f, 0x0000)),
167 | ConversionFlags.Format8332,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x00e0, 0x001c, 0x0003, 0xff00)),
170 | ConversionFlags.Format332,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 8, 0xe0, 0x1c, 0x03, 0x00)),
178 new LegacyMap(
PixelFormat.R16G16B16A16_UNorm, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 36, 0, 0, 0, 0, 0)),
179 new LegacyMap(
PixelFormat.R16G16B16A16_SNorm, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 110, 0, 0, 0, 0, 0)),
180 new LegacyMap(
PixelFormat.R16_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 111, 0, 0, 0, 0, 0)),
181 new LegacyMap(
PixelFormat.R16G16_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 112, 0, 0, 0, 0, 0)),
182 new LegacyMap(
PixelFormat.R16G16B16A16_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 113, 0, 0, 0, 0, 0)),
183 new LegacyMap(
PixelFormat.R32_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 114, 0, 0, 0, 0, 0)),
184 new LegacyMap(
PixelFormat.R32G32_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 115, 0, 0, 0, 0, 0)),
185 new LegacyMap(
PixelFormat.R32G32B32A32_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.FourCC, 116, 0, 0, 0, 0, 0)),
187 new LegacyMap(
PixelFormat.R32_Float, ConversionFlags.None,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 32, 0xffffffff, 0x00000000, 0x00000000, 0x00000000)),
191 | ConversionFlags.Pal8
192 | ConversionFlags.FormatA8P8,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Pal8, 0, 16, 0, 0, 0, 0)),
194 | ConversionFlags.Pal8,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Pal8, 0, 8, 0, 0, 0, 0)),
196 new LegacyMap(
PixelFormat.B4G4R4A4_UNorm, ConversionFlags.Format4444, DDS.PixelFormat.A4R4G4B4 ),
198 | ConversionFlags.Format4444,
new DDS.PixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000 ) ),
200 | ConversionFlags.Format44,
new DDS.PixelFormat(DDS.PixelFormatFlags.Luminance, 0, 8, 0x0f, 0x00, 0x00, 0xf0 ) ),
204 | ConversionFlags.Format4444, DDS.DDSPixelFormat.A4R4G4B4),
206 | ConversionFlags.NoAlpha
207 | ConversionFlags.Format4444,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Rgb, 0, 16, 0x0f00, 0x00f0, 0x000f, 0x0000)),
210 | ConversionFlags.Format44,
new DDS.DDSPixelFormat(DDS.PixelFormatFlags.Luminance, 0, 8, 0x0f, 0x00, 0x00, 0xf0)),
229 private static PixelFormat GetDXGIFormat(ref DDS.DDSPixelFormat pixelFormat, DDSFlags
flags, out ConversionFlags conversionFlags)
231 conversionFlags = ConversionFlags.None;
234 for (index = 0; index < LegacyMaps.Length; ++index)
236 var entry = LegacyMaps[index];
238 if ((pixelFormat.Flags & entry.PixelFormat.Flags) != 0)
240 if ((entry.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0)
242 if (pixelFormat.FourCC == entry.PixelFormat.FourCC)
245 else if ((entry.PixelFormat.Flags & DDS.PixelFormatFlags.Pal8) != 0)
247 if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount)
250 else if (pixelFormat.RGBBitCount == entry.PixelFormat.RGBBitCount)
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)
262 if (index >= LegacyMaps.Length)
263 return PixelFormat.None;
265 conversionFlags = LegacyMaps[index].ConversionFlags;
266 var
format = LegacyMaps[index].Format;
268 if ((conversionFlags & ConversionFlags.Expand) != 0 && (flags & DDSFlags.NoLegacyExpansion) != 0)
269 return PixelFormat.None;
271 if ((format ==
PixelFormat.R10G10B10A2_UNorm) && (flags & DDSFlags.NoR10B10G10A2Fixup) != 0)
273 conversionFlags ^= ConversionFlags.Swizzle;
291 private static unsafe
bool DecodeDDSHeader(IntPtr headerPtr,
int size, DDSFlags flags, out
ImageDescription description, out ConversionFlags convFlags)
294 convFlags = ConversionFlags.None;
296 if (headerPtr == IntPtr.Zero)
297 throw new ArgumentException(
"Pointer to DDS header cannot be null",
"headerPtr");
299 if (size < (
Utilities.SizeOf<DDS.Header>() + sizeof (uint)))
303 if (*(uint*) (headerPtr) != DDS.MagicHeader)
306 var header = *(
DDS.Header*) ((byte*) headerPtr +
sizeof (int));
313 description.MipLevels = header.MipMapCount;
314 if (description.MipLevels == 0)
315 description.MipLevels = 1;
318 if ((header.PixelFormat.Flags & DDS.PixelFormatFlags.FourCC) != 0 && (
new FourCC(
'D',
'X',
'1',
'0') == header.PixelFormat.FourCC))
321 if (size < (
Utilities.SizeOf<DDS.Header>() +
sizeof (uint) +
Utilities.SizeOf<DDS.HeaderDXT10>()))
325 convFlags |= ConversionFlags.DX10;
327 description.ArraySize = headerDX10.ArraySize;
328 if (description.ArraySize == 0)
329 throw new InvalidOperationException(
"Unexpected ArraySize == 0 from DDS HeaderDX10 ");
331 description.Format = headerDX10.DXGIFormat;
332 if (!description.Format.IsValid())
333 throw new InvalidOperationException(
"Invalid Format from DDS HeaderDX10 ");
335 switch (headerDX10.ResourceDimension)
337 case DDS.ResourceDimension.Texture1D:
340 if ((header.Flags & DDS.HeaderFlags.Height) != 0 && header.Height != 1)
341 throw new InvalidOperationException(
"Unexpected Height != 1 from DDS HeaderDX10 ");
343 description.Width = header.Width;
344 description.Height = 1;
345 description.Depth = 1;
346 description.Dimension = TextureDimension.Texture1D;
349 case DDS.ResourceDimension.Texture2D:
350 if ((headerDX10.MiscFlags & DDS.ResourceOptionFlags.TextureCube) != 0)
352 description.ArraySize *= 6;
353 description.Dimension = TextureDimension.TextureCube;
357 description.Dimension = TextureDimension.Texture2D;
360 description.Width = header.Width;
361 description.Height = header.Height;
362 description.Depth = 1;
365 case DDS.ResourceDimension.Texture3D:
366 if ((header.Flags & DDS.HeaderFlags.Volume) == 0)
367 throw new InvalidOperationException(
"Texture3D missing HeaderFlags.Volume from DDS HeaderDX10");
369 if (description.ArraySize > 1)
370 throw new InvalidOperationException(
"Unexpected ArraySize > 1 for Texture3D from DDS HeaderDX10");
372 description.Width = header.Width;
373 description.Height = header.Height;
374 description.Depth = header.Depth;
375 description.Dimension = TextureDimension.Texture3D;
379 throw new InvalidOperationException(
string.Format(
"Unexpected dimension [{0}] from DDS HeaderDX10", headerDX10.ResourceDimension));
384 description.ArraySize = 1;
386 if ((header.Flags & DDS.HeaderFlags.Volume) != 0)
388 description.Width = header.Width;
389 description.Height = header.Height;
390 description.Depth = header.Depth;
391 description.Dimension = TextureDimension.Texture3D;
395 if ((header.CubemapFlags & DDS.CubemapFlags.CubeMap) != 0)
398 if ((header.CubemapFlags & DDS.CubemapFlags.AllFaces) != DDS.CubemapFlags.AllFaces)
399 throw new InvalidOperationException(
"Unexpected CubeMap, expecting all faces from DDS Header");
401 description.ArraySize = 6;
402 description.Dimension = TextureDimension.TextureCube;
406 description.Dimension = TextureDimension.Texture2D;
409 description.Width = header.Width;
410 description.Height = header.Height;
411 description.Depth = 1;
415 description.Format = GetDXGIFormat(ref header.PixelFormat, flags, out convFlags);
418 throw new InvalidOperationException(
"Unsupported PixelFormat from DDS Header");
422 if ((flags & DDSFlags.ForceRgb) != 0)
426 case PixelFormat.B8G8R8A8_UNorm:
427 description.Format = PixelFormat.R8G8B8A8_UNorm;
428 convFlags |= ConversionFlags.Swizzle;
431 case PixelFormat.B8G8R8X8_UNorm:
432 description.Format = PixelFormat.R8G8B8A8_UNorm;
433 convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
436 case PixelFormat.B8G8R8A8_Typeless:
437 description.Format = PixelFormat.R8G8B8A8_Typeless;
438 convFlags |= ConversionFlags.Swizzle;
441 case PixelFormat.B8G8R8A8_UNorm_SRgb:
442 description.Format = PixelFormat.R8G8B8A8_UNorm_SRgb;
443 convFlags |= ConversionFlags.Swizzle;
446 case PixelFormat.B8G8R8X8_Typeless:
447 description.Format = PixelFormat.R8G8B8A8_Typeless;
448 convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
451 case PixelFormat.B8G8R8X8_UNorm_SRgb:
452 description.Format = PixelFormat.R8G8B8A8_UNorm_SRgb;
453 convFlags |= ConversionFlags.Swizzle | ConversionFlags.NoAlpha;
459 if ((flags & DDSFlags.CopyMemory) != 0)
460 convFlags |= ConversionFlags.CopyMemory;
463 if ((flags & DDSFlags.No16Bpp) != 0)
467 case PixelFormat.B5G6R5_UNorm:
468 case PixelFormat.B5G5R5A1_UNorm:
470 case PixelFormat.B4G4R4A4_UNorm:
472 description.Format = PixelFormat.R8G8B8A8_UNorm;
473 convFlags |= ConversionFlags.Expand;
474 if (description.Format ==
PixelFormat.B5G6R5_UNorm)
475 convFlags |= ConversionFlags.NoAlpha;
493 private unsafe
static void EncodeDDSHeader( ImageDescription description, DDSFlags flags, IntPtr pDestination,
int maxsize, out
int required )
495 if (description.ArraySize > 1)
499 flags |= DDSFlags.ForceDX10Ext;
503 var ddpf =
default(DDS.DDSPixelFormat);
504 if ((flags & DDSFlags.ForceDX10Ext) == 0)
506 switch (description.Format)
508 case PixelFormat.R8G8B8A8_UNorm:
509 ddpf = DDS.DDSPixelFormat.A8B8G8R8;
511 case PixelFormat.R16G16_UNorm:
512 ddpf = DDS.DDSPixelFormat.G16R16;
514 case PixelFormat.R8G8_UNorm:
515 ddpf = DDS.DDSPixelFormat.A8L8;
517 case PixelFormat.R16_UNorm:
518 ddpf = DDS.DDSPixelFormat.L16;
520 case PixelFormat.R8_UNorm:
521 ddpf = DDS.DDSPixelFormat.L8;
523 case PixelFormat.A8_UNorm:
524 ddpf = DDS.DDSPixelFormat.A8;
526 case PixelFormat.R8G8_B8G8_UNorm:
527 ddpf = DDS.DDSPixelFormat.R8G8_B8G8;
529 case PixelFormat.G8R8_G8B8_UNorm:
530 ddpf = DDS.DDSPixelFormat.G8R8_G8B8;
532 case PixelFormat.BC1_UNorm:
533 ddpf = DDS.DDSPixelFormat.DXT1;
535 case PixelFormat.BC2_UNorm:
536 ddpf = DDS.DDSPixelFormat.DXT3;
538 case PixelFormat.BC3_UNorm:
539 ddpf = DDS.DDSPixelFormat.DXT5;
541 case PixelFormat.BC4_UNorm:
542 ddpf = DDS.DDSPixelFormat.BC4_UNorm;
544 case PixelFormat.BC4_SNorm:
545 ddpf = DDS.DDSPixelFormat.BC4_SNorm;
547 case PixelFormat.BC5_UNorm:
548 ddpf = DDS.DDSPixelFormat.BC5_UNorm;
550 case PixelFormat.BC5_SNorm:
551 ddpf = DDS.DDSPixelFormat.BC5_SNorm;
553 case PixelFormat.B5G6R5_UNorm:
554 ddpf = DDS.DDSPixelFormat.R5G6B5;
556 case PixelFormat.B5G5R5A1_UNorm:
557 ddpf = DDS.DDSPixelFormat.A1R5G5B5;
559 case PixelFormat.B8G8R8A8_UNorm:
560 ddpf = DDS.DDSPixelFormat.A8R8G8B8;
562 case PixelFormat.B8G8R8X8_UNorm:
563 ddpf = DDS.DDSPixelFormat.X8R8G8B8;
566 case PixelFormat.B4G4R4A4_UNorm:
567 ddpf = DDS.PixelFormat.A4R4G4B4;
571 case PixelFormat.R32G32B32A32_Float:
572 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
573 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
576 case PixelFormat.R16G16B16A16_Float:
577 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
578 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
581 case PixelFormat.R16G16B16A16_UNorm:
582 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
583 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
586 case PixelFormat.R16G16B16A16_SNorm:
587 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
588 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
591 case PixelFormat.R32G32_Float:
592 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
593 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
596 case PixelFormat.R16G16_Float:
597 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
598 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
601 case PixelFormat.R32_Float:
602 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
603 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
606 case PixelFormat.R16_Float:
607 ddpf.Size = Utilities.SizeOf<DDS.DDSPixelFormat>();
608 ddpf.Flags = DDS.PixelFormatFlags.FourCC;
614 required =
sizeof (int) +
Utilities.SizeOf<DDS.Header>();
617 required += Utilities.SizeOf<DDS.HeaderDXT10>();
619 if (pDestination == IntPtr.Zero)
622 if (maxsize < required)
623 throw new ArgumentException(
"Not enough size for destination buffer",
"maxsize");
625 *(uint*)(pDestination) = DDS.MagicHeader;
627 var header = (DDS.Header*)((byte*)(pDestination) +
sizeof (
int));
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;
634 if (description.MipLevels > 0)
636 header->Flags |= DDS.HeaderFlags.Mipmap;
637 header->MipMapCount = description.MipLevels;
639 if (header->MipMapCount > 1)
640 header->SurfaceFlags |= DDS.SurfaceFlags.Mipmap;
643 switch (description.Dimension)
645 case TextureDimension.Texture1D:
646 header->Height = description.Height;
647 header->Width = header->Depth = 1;
650 case TextureDimension.Texture2D:
651 case TextureDimension.TextureCube:
652 header->Height = description.Height;
653 header->Width = description.Width;
658 header->SurfaceFlags |= DDS.SurfaceFlags.Cubemap;
659 header->CubemapFlags |= DDS.CubemapFlags.AllFaces;
663 case TextureDimension.Texture3D:
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;
673 int rowPitch, slicePitch;
676 Image.ComputePitch(description.Format, description.Width, description.Height, out rowPitch, out slicePitch, out newWidth, out newHeight);
678 if (description.Format.IsCompressed())
680 header->Flags |= DDS.HeaderFlags.LinearSize;
681 header->PitchOrLinearSize = slicePitch;
685 header->Flags |= DDS.HeaderFlags.Pitch;
686 header->PitchOrLinearSize = rowPitch;
691 header->PixelFormat = DDS.DDSPixelFormat.DX10;
693 var ext = (DDS.HeaderDXT10*)((byte*)(header) +
Utilities.SizeOf<DDS.Header>());
695 Utilities.ClearMemory((IntPtr) ext, 0,
Utilities.SizeOf<DDS.HeaderDXT10>());
697 ext->DXGIFormat = description.Format;
698 switch (description.Dimension)
700 case TextureDimension.Texture1D:
701 ext->ResourceDimension = DDS.ResourceDimension.Texture1D;
703 case TextureDimension.Texture2D:
704 case TextureDimension.TextureCube:
705 ext->ResourceDimension = DDS.ResourceDimension.Texture2D;
707 case TextureDimension.Texture3D:
708 ext->ResourceDimension = DDS.ResourceDimension.Texture3D;
715 ext->MiscFlags |= DDS.ResourceOptionFlags.TextureCube;
716 ext->ArraySize = description.ArraySize / 6;
720 ext->ArraySize = description.ArraySize;
725 header->PixelFormat = ddpf;
743 var lformat = TEXP_LEGACY_FORMAT.UNKNOWN;
745 if ((flags & ConversionFlags.Pal8) != 0)
749 else if ((flags & ConversionFlags.Format888) != 0)
751 else if ((flags & ConversionFlags.Format332) != 0)
753 else if ((flags & ConversionFlags.Format8332) != 0)
755 else if ((flags & ConversionFlags.Format44) != 0)
758 else if ((flags & ConversionFlags.Format4444) != 0)
778 uint* pal8, ScanlineFlags flags )
782 case TEXP_LEGACY_FORMAT.R8G8B8:
788 var sPtr = (byte*) (pSource);
789 var dPtr = (uint*) (pDestination);
791 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 3, ocount += 4)
794 uint t1 = (uint)(*(sPtr) << 16);
795 uint t2 = (uint)(*(sPtr + 1) << 8);
796 uint t3 = *(sPtr + 2);
798 *(dPtr++) = (t1 | t2 | t3 | 0xff000000);
804 case TEXP_LEGACY_FORMAT.R3G3B2:
807 case PixelFormat.R8G8B8A8_UNorm:
810 var sPtr = (byte*) (pSource);
811 var dPtr = (uint*) (pDestination);
813 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); ++icount, ocount += 4)
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));
821 *(dPtr++) = (t1 | t2 | t3 | 0xff000000);
826 case PixelFormat.B5G6R5_UNorm:
829 var sPtr = (byte*) (pSource);
830 var dPtr = (
short*) (pDestination);
832 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); ++icount, ocount += 2)
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));
840 *(dPtr++) = (
short) (t1 | t2 | t3);
847 case TEXP_LEGACY_FORMAT.A8R3G3B2:
853 var sPtr = (
short*) (pSource);
854 var dPtr = (uint*) (pDestination);
856 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
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));
865 *(dPtr++) = (t1 | t2 | t3 | ta);
870 case TEXP_LEGACY_FORMAT.P8:
871 if ((outFormat !=
PixelFormat.R8G8B8A8_UNorm) || pal8 == null)
876 byte* sPtr = (byte*) (pSource);
877 var dPtr = (uint*) (pDestination);
879 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); ++icount, ocount += 4)
888 case TEXP_LEGACY_FORMAT.A8P8:
889 if ((outFormat !=
PixelFormat.R8G8B8A8_UNorm) || pal8 == null)
894 short* sPtr = (
short*) (pSource);
895 int* dPtr = (
int*) (pDestination);
897 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
901 uint t1 = pal8[t & 0xff];
902 uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) ((t & 0xff00) << 16));
904 *(dPtr++) = (
int) (t1 | ta);
909 case TEXP_LEGACY_FORMAT.A4L4:
913 case PixelFormat.B4G4R4A4_UNorm :
916 byte * sPtr = (byte*)(pSource);
917 short * dPtr = (
short*)(pDestination);
919 for(
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); ++icount, ocount += 2 )
923 short t1 = (short)(t & 0x0f);
924 ushort ta = (flags & ScanlineFlags.SetAlpha ) != 0 ? (ushort)0xf000 : (ushort)((t & 0xf0) << 8);
926 *(dPtr++) = (
short)(t1 | (t1 << 4) | (t1 << 8) | ta);
933 case PixelFormat.R8G8B8A8_UNorm:
936 byte* sPtr = (byte*) (pSource);
937 var dPtr = (uint*) (pDestination);
939 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); ++icount, ocount += 4)
943 uint t1 = (uint)(((t & 0x0f) << 4) | (t & 0x0f));
944 uint ta = ((flags & ScanlineFlags.SetAlpha) != 0 ? 0xff000000 : (uint) (((t & 0xf0) << 24) | ((t & 0xf0) << 20)));
946 *(dPtr++) = (t1 | (t1 << 8) | (t1 << 16) | ta);
954 case TEXP_LEGACY_FORMAT.B4G4R4A4:
960 short* sPtr = (
short*) (pSource);
961 var dPtr = (uint*) (pDestination);
963 for (
int ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
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)));
972 *(dPtr++) = (t1 | t2 | t3 | ta);
990 var flags = makeACopy ? DDSFlags.CopyMemory : DDSFlags.None;
992 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
994 flags |= DDSFlags.ForceRgb;
997 ConversionFlags convFlags;
998 ImageDescription mdata;
1000 if (!DecodeDDSHeader(pSource, size, flags, out mdata, out convFlags))
1003 int offset =
sizeof (uint) +
Utilities.SizeOf<DDS.Header>();
1004 if ((convFlags & ConversionFlags.DX10) != 0)
1005 offset +=
Utilities.SizeOf<DDS.HeaderDXT10>();
1007 var pal8 = (uint*) 0;
1008 if ((convFlags & ConversionFlags.Pal8) != 0)
1010 pal8 = (uint*) ((byte*) (pSource) + offset);
1011 offset += (256 *
sizeof (uint));
1015 throw new InvalidOperationException();
1017 var image = CreateImageFromDDS(pSource, offset, size - offset, mdata, (flags & DDSFlags.LegacyDword) != 0 ?
Image.PitchFlags.LegacyDword :
Image.PitchFlags.None, convFlags, pal8, handle);
1021 public static void SaveToDDSStream(PixelBuffer[] pixelBuffers,
int count, ImageDescription description,
System.IO.Stream imageStream)
1023 SaveToDDSStream(pixelBuffers, count, description, DDSFlags.None, imageStream);
1029 public unsafe
static void SaveToDDSStream(PixelBuffer[] pixelBuffers,
int count, ImageDescription
metadata, DDSFlags flags,
System.IO.Stream stream)
1034 EncodeDDSHeader(metadata, flags, IntPtr.Zero, 0, out totalSize);
1035 headerSize = totalSize;
1039 for (
int i = 0; i < pixelBuffers.Length; ++i)
1041 int slice = pixelBuffers[i].BufferStride;
1043 if (slice > maxSlice)
1047 Debug.Assert(totalSize > 0);
1050 var buffer =
new byte[Math.Max(maxSlice, headerSize)];
1052 fixed (
void* pbuffer = buffer)
1055 EncodeDDSHeader(metadata, flags, (IntPtr) pbuffer, headerSize, out required);
1056 stream.Write(buffer, 0, headerSize);
1059 int remaining = totalSize - headerSize;
1060 Debug.Assert(remaining > 0);
1063 for (
int item = 0; item < metadata.ArraySize; ++item)
1065 int d = metadata.Depth;
1067 for (
int level = 0; level < metadata.MipLevels; ++level)
1069 for (
int slice = 0; slice < d; ++slice)
1071 int pixsize = pixelBuffers[index].BufferStride;
1072 Utilities.Read(pixelBuffers[index].DataPointer, buffer, 0, pixsize);
1073 stream.Write(buffer, 0, pixsize);
1095 private static unsafe
Image CreateImageFromDDS(IntPtr pDDS,
int offset,
int size, ImageDescription metadata,
Image.PitchFlags
cpFlags, ConversionFlags convFlags, uint* pal8, GCHandle? handle)
1097 if ((convFlags & ConversionFlags.Expand) != 0)
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;
1108 var isCopyNeeded = (convFlags & (ConversionFlags.Expand | ConversionFlags.CopyMemory)) != 0 || ((
cpFlags & Image.PitchFlags.LegacyDword) != 0);
1110 var image =
new Image(metadata, pDDS, offset, handle, !isCopyNeeded,
cpFlags);
1113 Debug.Assert(size >= image.TotalSizeInBytes);
1115 if (!isCopyNeeded && (convFlags & (ConversionFlags.Swizzle | ConversionFlags.NoAlpha)) == 0)
1118 var imageDst = isCopyNeeded ?
new Image(metadata, IntPtr.Zero, 0, null,
false) : image;
1120 var images = image.PixelBuffer;
1121 var imagesDst = imageDst.PixelBuffer;
1123 ScanlineFlags tflags = (convFlags & ConversionFlags.NoAlpha) != 0 ? ScanlineFlags.SetAlpha : ScanlineFlags.None;
1124 if ((convFlags & ConversionFlags.Swizzle) != 0)
1125 tflags |= ScanlineFlags.Legacy;
1129 int checkSize = size;
1131 for (
int arrayIndex = 0; arrayIndex < metadata.ArraySize; arrayIndex++)
1133 int d = metadata.Depth;
1135 for (
int level = 0; level < metadata.MipLevels; ++level)
1137 for (
int slice = 0; slice < d; ++slice, ++index)
1139 IntPtr pSrc = images[index].DataPointer;
1140 IntPtr pDest = imagesDst[index].DataPointer;
1141 checkSize -= images[index].BufferStride;
1143 throw new InvalidOperationException(
"Unexpected end of buffer");
1145 if (metadata.Format.IsCompressed())
1147 Utilities.CopyMemory(pDest, pSrc, Math.Min(images[index].BufferStride, imagesDst[index].BufferStride));
1151 int spitch = images[index].RowStride;
1152 int dpitch = imagesDst[index].RowStride;
1154 for (
int h = 0; h < images[index].Height; ++h)
1156 if ((convFlags & ConversionFlags.Expand) != 0)
1159 if ((convFlags & (ConversionFlags.Format565 | ConversionFlags.Format5551 | ConversionFlags.Format4444)) != 0)
1161 if ((convFlags & (ConversionFlags.Format565 | ConversionFlags.Format5551)) != 0)
1164 ExpandScanline(pDest, dpitch, pSrc, spitch, (convFlags & ConversionFlags.Format565) != 0 ?
PixelFormat.B5G6R5_UNorm :
PixelFormat.B5G5R5A1_UNorm, tflags);
1168 var lformat = FindLegacyFormat(convFlags);
1169 LegacyExpandScanline(pDest, dpitch, metadata.Format, pSrc, spitch, lformat, pal8, tflags);
1172 else if ((convFlags & ConversionFlags.Swizzle) != 0)
1174 SwizzleScanline(pDest, dpitch, pSrc, spitch, metadata.Format, tflags);
1179 CopyScanline(pDest, dpitch, pSrc, spitch, metadata.Format, tflags);
1182 pSrc = (IntPtr) ((byte*) pSrc + spitch);
1183 pDest = (IntPtr) ((byte*) pDest + dpitch);
1204 internal enum ScanlineFlags
1220 private unsafe
static void ExpandScanline(IntPtr pDestination,
int outSize, IntPtr pSource,
int inSize,
PixelFormat inFormat, ScanlineFlags flags)
1224 case PixelFormat.B5G6R5_UNorm:
1227 var sPtr = (ushort*) (pSource);
1228 var dPtr = (uint*) (pDestination);
1230 for (uint ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1232 ushort t = *(sPtr++);
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));
1238 *(dPtr++) = t1 | t2 | t3 | 0xff000000;
1243 case PixelFormat.B5G5R5A1_UNorm:
1246 var sPtr = (ushort*) (pSource);
1247 var dPtr = (uint*) (pDestination);
1249 for (uint ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1251 ushort t = *(sPtr++);
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)));
1258 *(dPtr++) = t1 | t2 | t3 | ta;
1264 case PixelFormat.B4G4R4A4_UNorm:
1267 var sPtr = (ushort*) (pSource);
1268 var dPtr = (uint*) (pDestination);
1270 for (uint ocount = 0, icount = 0; ((icount <
inSize) && (ocount < outSize)); icount += 2, ocount += 4)
1272 ushort t = *(sPtr++);
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)));
1279 *(dPtr++) = t1 | t2 | t3 | ta;
1301 internal static unsafe
void CopyScanline(IntPtr pDestination,
int outSize, IntPtr pSource,
int inSize,
PixelFormat format, ScanlineFlags flags)
1303 if ((flags & ScanlineFlags.SetAlpha) != 0)
1308 case PixelFormat.R32G32B32A32_Typeless:
1309 case PixelFormat.R32G32B32A32_Float:
1310 case PixelFormat.R32G32B32A32_UInt:
1311 case PixelFormat.R32G32B32A32_SInt:
1321 if (pDestination == pSource)
1323 var dPtr = (uint*)(pDestination);
1324 for (
int count = 0; count <
outSize; count += 16)
1332 var sPtr = (uint*)(pSource);
1333 var dPtr = (uint*)(pDestination);
1335 for (
int count = 0; count <
size; count += 16)
1337 *(dPtr++) = *(sPtr++);
1338 *(dPtr++) = *(sPtr++);
1339 *(dPtr++) = *(sPtr++);
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:
1363 if (pDestination == pSource)
1365 var dPtr = (ushort*)(pDestination);
1366 for (
int count = 0; count <
outSize; count += 8)
1374 var sPtr = (ushort*)(pSource);
1375 var dPtr = (ushort*)(pDestination);
1377 for (
int count = 0; count <
size; count += 8)
1379 *(dPtr++) = *(sPtr++);
1380 *(dPtr++) = *(sPtr++);
1381 *(dPtr++) = *(sPtr++);
1390 case PixelFormat.R10G10B10A2_Typeless:
1391 case PixelFormat.R10G10B10A2_UNorm:
1392 case PixelFormat.R10G10B10A2_UInt:
1393 case PixelFormat.R10G10B10_Xr_Bias_A2_UNorm:
1395 if (pDestination == pSource)
1397 var dPtr = (uint*)(pDestination);
1398 for (
int count = 0; count <
outSize; count += 4)
1400 *dPtr |= 0xC0000000;
1406 var sPtr = (uint*)(pSource);
1407 var dPtr = (uint*)(pDestination);
1409 for (
int count = 0; count <
size; count += 4)
1411 *(dPtr++) = *(sPtr++) | 0xC0000000;
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:
1428 uint alpha = (format == PixelFormat.R8G8B8A8_SNorm || format == PixelFormat.R8G8B8A8_SInt) ? 0x7f000000 : 0xff000000;
1430 if (pDestination == pSource)
1432 var dPtr = (uint*)(pDestination);
1433 for (
int count = 0; count <
outSize; count += 4)
1435 uint t = *dPtr & 0xFFFFFF;
1442 var sPtr = (uint*)(pSource);
1443 var dPtr = (uint*)(pDestination);
1445 for (
int count = 0; count <
size; count += 4)
1447 uint t = *(sPtr++) & 0xFFFFFF;
1456 case PixelFormat.B5G5R5A1_UNorm:
1458 if (pDestination == pSource)
1460 var dPtr = (ushort*)(pDestination);
1461 for (
int count = 0; count <
outSize; count += 2)
1463 *(dPtr++) |= 0x8000;
1468 var sPtr = (ushort*)(pSource);
1469 var dPtr = (ushort*)(pDestination);
1471 for (
int count = 0; count <
size; count += 2)
1473 *(dPtr++) = (ushort)(*(sPtr++) | 0x8000);
1480 case PixelFormat.A8_UNorm:
1481 Utilities.ClearMemory(pDestination, 0xff,
outSize);
1486 case PixelFormat.B4G4R4A4_UNorm:
1488 if (pDestination == pSource)
1490 var dPtr = (ushort*) (pDestination);
1491 for (
int count = 0; count <
outSize; count += 2)
1493 *(dPtr++) |= 0xF000;
1498 var sPtr = (ushort*) (pSource);
1499 var dPtr = (ushort*) (pDestination);
1501 for (
int count = 0; count <
size; count += 2)
1503 *(dPtr++) = (ushort) (*(sPtr++) | 0xF000);
1514 if (pDestination == pSource)
1517 Utilities.CopyMemory(pDestination, pSource, Math.Min(
outSize,
inSize));
1532 internal static unsafe
void SwizzleScanline(IntPtr pDestination,
int outSize, IntPtr pSource,
int inSize,
PixelFormat format, ScanlineFlags flags)
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)
1544 if (pDestination == pSource)
1546 var dPtr = (uint*)(pDestination);
1547 for (
int count = 0; count <
outSize; count += 4)
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);
1556 *(dPtr++) = t1 | t2 | t3 | ta;
1561 var sPtr = (uint*)(pSource);
1562 var dPtr = (uint*)(pDestination);
1564 for (
int count = 0; count <
size; count += 4)
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);
1573 *(dPtr++) = t1 | t2 | t3 | ta;
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:
1591 if (pDestination == pSource)
1593 var dPtr = (uint*)(pDestination);
1594 for (
int count = 0; count <
outSize; count += 4)
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);
1603 *(dPtr++) = t1 | t2 | t3 | ta;
1608 var sPtr = (uint*)(pSource);
1609 var dPtr = (uint*)(pDestination);
1611 for (
int count = 0; count <
size; count += 4)
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);
1620 *(dPtr++) = t1 | t2 | t3 | ta;
1627 if (pDestination == pSource)
1630 Utilities.CopyMemory(pDestination, pSource, Math.Min(
outSize,
inSize));
_In_ size_t _In_ const TexMetadata _In_ DWORD cpFlags
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
TextureDimension
Defines the dimension of a texture.
Flags
Enumeration of the new Assimp's flags.
_In_ size_t _In_ const TexMetadata & metadata
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
DDS.DDSPixelFormat PixelFormat
ConversionFlags ConversionFlags
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
_In_ size_t _In_ size_t size
PixelFormat
Defines various types of pixel formats.
LegacyMap(PixelFormat format, ConversionFlags conversionFlags, DDS.DDSPixelFormat pixelFormat)
Initializes a new instance of the LegacyMap struct.
HRESULT LoadFromDDSMemory(_In_reads_bytes_(size) LPCVOID pSource, _In_ size_t size, _In_ DWORD flags, _Out_opt_ TexMetadata *metadata, _Out_ ScratchImage &image)