Created
January 11, 2019 18:23
-
-
Save Scobalula/d9474f3fcf3d5a2ca596fceb64e16c98 to your computer and use it in GitHub Desktop.
A quick class to generate headers, useful when dealing with headerless DDS data or converting game-specific headers to DDS without requiring Microsoft's DirectXTex Library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// DirectXTex Utility - A simple class for generating DDS Headers | |
// Copyright(c) 2018 Philip/Scobalula | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
// ------------------------------------------------------------------------ | |
// Author: Philip/Scobalula | |
// Description: DirectXTex DDS Header Utilities | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.IO; | |
namespace DirectXTex | |
{ | |
public class DirectXTexUtility | |
{ | |
#region Enumerators | |
/// <summary> | |
/// DDS Formats | |
/// </summary> | |
public enum DXGIFormat : uint | |
{ | |
UNKNOWN = 0, | |
R32G32B32A32TYPELESS = 1, | |
R32G32B32A32FLOAT = 2, | |
R32G32B32A32UINT = 3, | |
R32G32B32A32SINT = 4, | |
R32G32B32TYPELESS = 5, | |
R32G32B32FLOAT = 6, | |
R32G32B32UINT = 7, | |
R32G32B32SINT = 8, | |
R16G16B16A16TYPELESS = 9, | |
R16G16B16A16FLOAT = 10, | |
R16G16B16A16UNORM = 11, | |
R16G16B16A16UINT = 12, | |
R16G16B16A16SNORM = 13, | |
R16G16B16A16SINT = 14, | |
R32G32TYPELESS = 15, | |
R32G32FLOAT = 16, | |
R32G32UINT = 17, | |
R32G32SINT = 18, | |
R32G8X24TYPELESS = 19, | |
D32FLOATS8X24UINT = 20, | |
R32FLOATX8X24TYPELESS = 21, | |
X32TYPELESSG8X24UINT = 22, | |
R10G10B10A2TYPELESS = 23, | |
R10G10B10A2UNORM = 24, | |
R10G10B10A2UINT = 25, | |
R11G11B10FLOAT = 26, | |
R8G8B8A8TYPELESS = 27, | |
R8G8B8A8UNORM = 28, | |
R8G8B8A8UNORMSRGB = 29, | |
R8G8B8A8UINT = 30, | |
R8G8B8A8SNORM = 31, | |
R8G8B8A8SINT = 32, | |
R16G16TYPELESS = 33, | |
R16G16FLOAT = 34, | |
R16G16UNORM = 35, | |
R16G16UINT = 36, | |
R16G16SNORM = 37, | |
R16G16SINT = 38, | |
R32TYPELESS = 39, | |
D32FLOAT = 40, | |
R32FLOAT = 41, | |
R32UINT = 42, | |
R32SINT = 43, | |
R24G8TYPELESS = 44, | |
D24UNORMS8UINT = 45, | |
R24UNORMX8TYPELESS = 46, | |
X24TYPELESSG8UINT = 47, | |
R8G8TYPELESS = 48, | |
R8G8UNORM = 49, | |
R8G8UINT = 50, | |
R8G8SNORM = 51, | |
R8G8SINT = 52, | |
R16TYPELESS = 53, | |
R16FLOAT = 54, | |
D16UNORM = 55, | |
R16UNORM = 56, | |
R16UINT = 57, | |
R16SNORM = 58, | |
R16SINT = 59, | |
R8TYPELESS = 60, | |
R8UNORM = 61, | |
R8UINT = 62, | |
R8SNORM = 63, | |
R8SINT = 64, | |
A8UNORM = 65, | |
R1UNORM = 66, | |
R9G9B9E5SHAREDEXP = 67, | |
R8G8B8G8UNORM = 68, | |
G8R8G8B8UNORM = 69, | |
BC1TYPELESS = 70, | |
BC1UNORM = 71, | |
BC1UNORMSRGB = 72, | |
BC2TYPELESS = 73, | |
BC2UNORM = 74, | |
BC2UNORMSRGB = 75, | |
BC3TYPELESS = 76, | |
BC3UNORM = 77, | |
BC3UNORMSRGB = 78, | |
BC4TYPELESS = 79, | |
BC4UNORM = 80, | |
BC4SNORM = 81, | |
BC5TYPELESS = 82, | |
BC5UNORM = 83, | |
BC5SNORM = 84, | |
B5G6R5UNORM = 85, | |
B5G5R5A1UNORM = 86, | |
B8G8R8A8UNORM = 87, | |
B8G8R8X8UNORM = 88, | |
R10G10B10XRBIASA2UNORM = 89, | |
B8G8R8A8TYPELESS = 90, | |
B8G8R8A8UNORMSRGB = 91, | |
B8G8R8X8TYPELESS = 92, | |
B8G8R8X8UNORMSRGB = 93, | |
BC6HTYPELESS = 94, | |
BC6HUF16 = 95, | |
BC6HSF16 = 96, | |
BC7TYPELESS = 97, | |
BC7UNORM = 98, | |
BC7UNORMSRGB = 99, | |
AYUV = 100, | |
Y410 = 101, | |
Y416 = 102, | |
NV12 = 103, | |
P010 = 104, | |
P016 = 105, | |
OPAQUE420 = 106, | |
YUY2 = 107, | |
Y210 = 108, | |
Y216 = 109, | |
NV11 = 110, | |
AI44 = 111, | |
IA44 = 112, | |
P8 = 113, | |
A8P8 = 114, | |
B4G4R4A4UNORM = 115, | |
FORCEUINT = 0xffffffff | |
} | |
/// <summary> | |
/// DDS Flags | |
/// </summary> | |
public enum DDSFlags | |
{ | |
NONE = 0x0, | |
LEGACYDWORD = 0x1, | |
NOLEGACYEXPANSION = 0x2, | |
NOR10B10G10A2FIXUP = 0x4, | |
FORCERGB = 0x8, | |
NO16BPP = 0x10, | |
EXPANDLUMINANCE = 0x20, | |
BADDXTNTAILS = 0x40, | |
FORCEDX10EXT = 0x10000, | |
FORCEDX10EXTMISC2 = 0x20000, | |
} | |
/// <summary> | |
/// Texture Dimension | |
/// </summary> | |
public enum TexDimension | |
{ | |
TEXTURE1D = 2, | |
TEXTURE2D = 3, | |
TEXTURE3D = 4, | |
} | |
/// <summary> | |
/// Misc. Texture Flags | |
/// </summary> | |
public enum TexMiscFlags : uint | |
{ | |
TEXTURECUBE = 0x4, | |
}; | |
/// <summary> | |
/// Misc. Texture Flags | |
/// </summary> | |
public enum TexMiscFlags2 : uint | |
{ | |
TEXMISC2ALPHAMODEMASK = 0x7, | |
}; | |
/// <summary> | |
/// Texture Alpha Modes | |
/// </summary> | |
public enum TexAlphaMode | |
{ | |
UNKNOWN = 0, | |
STRAIGHT = 1, | |
PREMULTIPLIED = 2, | |
OPAQUE = 3, | |
CUSTOM = 4, | |
}; | |
/// <summary> | |
/// CP Flags | |
/// </summary> | |
public enum CPFLAGS | |
{ | |
NONE = 0x0, // Normal operation | |
LEGACYDWORD = 0x1, // Assume pitch is DWORD aligned instead of BYTE aligned | |
PARAGRAPH = 0x2, // Assume pitch is 16-byte aligned instead of BYTE aligned | |
YMM = 0x4, // Assume pitch is 32-byte aligned instead of BYTE aligned | |
ZMM = 0x8, // Assume pitch is 64-byte aligned instead of BYTE aligned | |
PAGE4K = 0x200, // Assume pitch is 4096-byte aligned instead of BYTE aligned | |
BADDXTNTAILS = 0x1000, // BC formats with malformed mipchain blocks smaller than 4x4 | |
BPP24 = 0x10000, // Override with a legacy 24 bits-per-pixel format size | |
BPP16 = 0x20000, // Override with a legacy 16 bits-per-pixel format size | |
BPP8 = 0x40000, // Override with a legacy 8 bits-per-pixel format size | |
}; | |
#endregion | |
#region Structs/Classes | |
/// <summary> | |
/// Common Pixel Formats | |
/// </summary> | |
public class PixelFormats | |
{ | |
/// <summary> | |
/// DDS Pixel Format Size | |
/// </summary> | |
public static readonly uint Size = (uint)Marshal.SizeOf<DDSHeader.DDSPixelFormat>(); | |
#region PixelFormatsConstants | |
public const uint DDSFOURCC = 0x00000004; // DDPFFOURCC | |
public const uint DDSRGB = 0x00000040; // DDPFRGB | |
public const uint DDSRGBA = 0x00000041; // DDPFRGB | DDPFALPHAPIXELS | |
public const uint DDSLUMINANCE = 0x00020000; // DDPFLUMINANCE | |
public const uint DDSLUMINANCEA = 0x00020001; // DDPFLUMINANCE | DDPFALPHAPIXELS | |
public const uint DDSALPHAPIXELS = 0x00000001; // DDPFALPHAPIXELS | |
public const uint DDSALPHA = 0x00000002; // DDPFALPHA | |
public const uint DDSPAL8 = 0x00000020; // DDPFPALETTEINDEXED8 | |
public const uint DDSPAL8A = 0x00000021; // DDPFPALETTEINDEXED8 | DDPFALPHAPIXELS | |
public const uint DDSBUMPDUDV = 0x00080000; // DDPFBUMPDUDV | |
#endregion | |
#region DDSPixelFormats | |
public static DDSHeader.DDSPixelFormat DXT1 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', 'T', '1'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat DXT2 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', 'T', '2'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat DXT3 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', 'T', '3'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat DXT4 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', 'T', '4'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat DXT5 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', 'T', '5'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat BC4UNORM = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('B', 'C', '4', 'U'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat BC4SNORM = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('B', 'C', '4', 'S'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat BC5UNORM = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('B', 'C', '5', 'U'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat BC5SNORM = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('B', 'C', '5', 'S'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat R8G8B8G8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('R', 'G', 'B', 'G'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat G8R8G8B8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('G', 'R', 'G', 'B'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat YUY2 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('Y', 'U', 'Y', '2'), 0, 0, 0, 0, 0); | |
public static DDSHeader.DDSPixelFormat A8R8G8B8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGBA, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); | |
public static DDSHeader.DDSPixelFormat X8R8G8B8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGB, 0, 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); | |
public static DDSHeader.DDSPixelFormat A8B8G8R8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGBA, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); | |
public static DDSHeader.DDSPixelFormat X8B8G8R8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGB, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000); | |
public static DDSHeader.DDSPixelFormat G16R16 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGB, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000); | |
public static DDSHeader.DDSPixelFormat R5G6B5 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGB, 0, 16, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000); | |
public static DDSHeader.DDSPixelFormat A1R5G5B5 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGBA, 0, 16, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000); | |
public static DDSHeader.DDSPixelFormat A4R4G4B4 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGBA, 0, 16, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000); | |
public static DDSHeader.DDSPixelFormat R8G8B8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSRGB, 0, 24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000); | |
public static DDSHeader.DDSPixelFormat L8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSLUMINANCE, 0, 8, 0xff, 0x00, 0x00, 0x00); | |
public static DDSHeader.DDSPixelFormat L16 = | |
new DDSHeader.DDSPixelFormat(Size, DDSLUMINANCE, 0, 16, 0xffff, 0x0000, 0x0000, 0x0000); | |
public static DDSHeader.DDSPixelFormat A8L8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSLUMINANCEA, 0, 16, 0x00ff, 0x0000, 0x0000, 0xff00); | |
public static DDSHeader.DDSPixelFormat A8L8ALT = | |
new DDSHeader.DDSPixelFormat(Size, DDSLUMINANCEA, 0, 8, 0x00ff, 0x0000, 0x0000, 0xff00); | |
public static DDSHeader.DDSPixelFormat A8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSALPHA, 0, 8, 0x00, 0x00, 0x00, 0xff); | |
public static DDSHeader.DDSPixelFormat V8U8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSBUMPDUDV, 0, 16, 0x00ff, 0xff00, 0x0000, 0x0000); | |
public static DDSHeader.DDSPixelFormat Q8W8V8U8 = | |
new DDSHeader.DDSPixelFormat(Size, DDSBUMPDUDV, 0, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); | |
public static DDSHeader.DDSPixelFormat V16U16 = | |
new DDSHeader.DDSPixelFormat(Size, DDSBUMPDUDV, 0, 32, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000); | |
public static DDSHeader.DDSPixelFormat DX10 = | |
new DDSHeader.DDSPixelFormat(Size, DDSFOURCC, MakePixelFormatFourCC('D', 'X', '1', '0'), 0, 0, 0, 0, 0); | |
#endregion | |
} | |
/// <summary> | |
/// DDS Header | |
/// </summary> | |
public struct DDSHeader | |
{ | |
/// <summary> | |
/// DDS Header Flags | |
/// </summary> | |
public enum HeaderFlags : uint | |
{ | |
TEXTURE = 0x00001007, // DDSDCAPS | DDSDHEIGHT | DDSDWIDTH | DDSDPIXELFORMAT | |
MIPMAP = 0x00020000, // DDSDMIPMAPCOUNT | |
VOLUME = 0x00800000, // DDSDDEPTH | |
PITCH = 0x00000008, // DDSDPITCH | |
LINEARSIZE = 0x00080000, // DDSDLINEARSIZE | |
} | |
/// <summary> | |
/// DDS Surface Flags | |
/// </summary> | |
public enum SurfaceFlags : uint | |
{ | |
TEXTURE = 0x00001000, // DDSCAPSTEXTURE | |
MIPMAP = 0x00400008, // DDSCAPSCOMPLEX | DDSCAPSMIPMAP | |
CUBEMAP = 0x00000008, // DDSCAPSCOMPLEX | |
} | |
/// <summary> | |
/// DDS Magic/Four CC | |
/// </summary> | |
public const uint DDSMagic = 0x20534444; | |
/// <summary> | |
/// DDS Pixel Format | |
/// </summary> | |
public struct DDSPixelFormat | |
{ | |
public uint Size; | |
public uint Flags; | |
public uint FourCC; | |
public uint RGBBitCount; | |
public uint RBitMask; | |
public uint GBitMask; | |
public uint BBitMask; | |
public uint ABitMask; | |
/// <summary> | |
/// Creates a new DDS Pixel Format | |
/// </summary> | |
public DDSPixelFormat(uint size, uint flags, uint fourCC, uint rgbBitCount, uint rBitMask, uint gBitMask, uint bBitMask, uint aBitMask) | |
{ | |
Size = size; | |
Flags = flags; | |
FourCC = fourCC; | |
RGBBitCount = rgbBitCount; | |
RBitMask = rBitMask; | |
GBitMask = gBitMask; | |
BBitMask = bBitMask; | |
ABitMask = aBitMask; | |
} | |
} | |
public uint Size; | |
public HeaderFlags Flags; | |
public uint Height; | |
public uint Width; | |
public uint PitchOrLinearSize; | |
public uint Depth; // only if DDSHEADERFLAGSVOLUME is set in flags | |
public uint MipMapCount; | |
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] | |
public uint[] Reserved1; | |
public DDSPixelFormat PixelFormat; | |
public uint Caps; | |
public uint Caps2; | |
public uint Caps3; | |
public uint Caps4; | |
public uint Reserved2; | |
} | |
/// <summary> | |
/// DDS DX10 Header | |
/// </summary> | |
public struct DX10Header | |
{ | |
public DXGIFormat Format; | |
public TexDimension ResourceDimension; | |
public TexMiscFlags MiscFlag; // see D3D11RESOURCEMISCFLAG | |
public uint ArraySize; | |
public uint MiscFlags2; // see DDSMISCFLAGS2 | |
} | |
/// <summary> | |
/// Texture Metadata | |
/// </summary> | |
public struct TexMetadata | |
{ | |
#region Properties | |
public long Width; | |
public long Height; // Should be 1 for 1D textures | |
public long Depth; // Should be 1 for 1D or 2D textures | |
public long ArraySize; // For cubemap, this is a multiple of 6 | |
public long MipLevels; | |
public TexMiscFlags MiscFlags; | |
public TexMiscFlags2 MiscFlags2; | |
public DXGIFormat Format; | |
public TexDimension Dimension; | |
#endregion | |
/// <summary> | |
/// Creates a new Texture Metadata Structe | |
/// </summary> | |
public TexMetadata(long width, long height, long depth, long arraySize, long mipLevels, TexMiscFlags flags, TexMiscFlags2 flags2, DXGIFormat format, TexDimension dimension) | |
{ | |
Width = width; | |
Height = height; | |
Depth = depth; | |
ArraySize = arraySize; | |
MipLevels = mipLevels; | |
MiscFlags = flags; | |
MiscFlags2 = flags2; | |
Format = format; | |
Dimension = dimension; | |
} | |
/// <summary> | |
/// Checks Alpha Mode | |
/// </summary> | |
public bool IsPMAlpha() | |
{ | |
return (TexAlphaMode)(MiscFlags2 & TexMiscFlags2.TEXMISC2ALPHAMODEMASK) == TexAlphaMode.PREMULTIPLIED; | |
} | |
public bool IsCubeMap() | |
{ | |
return (MiscFlags & TexMiscFlags.TEXTURECUBE) == TexMiscFlags.TEXTURECUBE; | |
} | |
} | |
#endregion | |
#region HelperMethods | |
/// <summary> | |
/// Clamps Value to a range. | |
/// </summary> | |
/// <param name="value">Value to Clamp</param> | |
/// <param name="max">Max value</param> | |
/// <param name="min">Min value</param> | |
/// <returns>Clamped Value</returns> | |
private static T Clamp<T>(T value, T max, T min) where T : IComparable<T> | |
{ | |
return value.CompareTo(min) < 0 ? min : value.CompareTo(max) > 0 ? max : value; | |
} | |
/// <summary> | |
/// Converts a Struct to a Byte array | |
/// </summary> | |
private static byte[] StructToBytes<T>(T value) | |
{ | |
// Size of Struct | |
int length = Marshal.SizeOf<T>(); | |
// Destination | |
byte[] destination = new byte[length]; | |
// Get Pointer | |
IntPtr pointer = Marshal.AllocHGlobal(length); | |
// Convert it | |
Marshal.StructureToPtr(value, pointer, false); | |
Marshal.Copy(pointer, destination, 0, length); | |
Marshal.FreeHGlobal(pointer); | |
// Done | |
return destination; | |
} | |
/// <summary> | |
/// Generates a FourCC Integer from Pixel Format Characters | |
/// </summary> | |
private static uint MakePixelFormatFourCC(char char1, char char2, char char3, char char4) | |
{ | |
return Convert.ToByte(char1) | (uint)Convert.ToByte(char2) << 8 | (uint)Convert.ToByte(char3) << 16 | (uint)Convert.ToByte(char4) << 24; | |
} | |
/// <summary> | |
/// Gets the Bits Per Pixel for the given format | |
/// </summary> | |
private static long BitsPerPixel(DXGIFormat format) | |
{ | |
switch (format) | |
{ | |
case DXGIFormat.R32G32B32A32TYPELESS: | |
case DXGIFormat.R32G32B32A32FLOAT: | |
case DXGIFormat.R32G32B32A32UINT: | |
case DXGIFormat.R32G32B32A32SINT: | |
return 128; | |
case DXGIFormat.R32G32B32TYPELESS: | |
case DXGIFormat.R32G32B32FLOAT: | |
case DXGIFormat.R32G32B32UINT: | |
case DXGIFormat.R32G32B32SINT: | |
return 96; | |
case DXGIFormat.R16G16B16A16TYPELESS: | |
case DXGIFormat.R16G16B16A16FLOAT: | |
case DXGIFormat.R16G16B16A16UNORM: | |
case DXGIFormat.R16G16B16A16UINT: | |
case DXGIFormat.R16G16B16A16SNORM: | |
case DXGIFormat.R16G16B16A16SINT: | |
case DXGIFormat.R32G32TYPELESS: | |
case DXGIFormat.R32G32FLOAT: | |
case DXGIFormat.R32G32UINT: | |
case DXGIFormat.R32G32SINT: | |
case DXGIFormat.R32G8X24TYPELESS: | |
case DXGIFormat.D32FLOATS8X24UINT: | |
case DXGIFormat.R32FLOATX8X24TYPELESS: | |
case DXGIFormat.X32TYPELESSG8X24UINT: | |
case DXGIFormat.Y416: | |
case DXGIFormat.Y210: | |
case DXGIFormat.Y216: | |
return 64; | |
case DXGIFormat.R10G10B10A2TYPELESS: | |
case DXGIFormat.R10G10B10A2UNORM: | |
case DXGIFormat.R10G10B10A2UINT: | |
case DXGIFormat.R11G11B10FLOAT: | |
case DXGIFormat.R8G8B8A8TYPELESS: | |
case DXGIFormat.R8G8B8A8UNORM: | |
case DXGIFormat.R8G8B8A8UNORMSRGB: | |
case DXGIFormat.R8G8B8A8UINT: | |
case DXGIFormat.R8G8B8A8SNORM: | |
case DXGIFormat.R8G8B8A8SINT: | |
case DXGIFormat.R16G16TYPELESS: | |
case DXGIFormat.R16G16FLOAT: | |
case DXGIFormat.R16G16UNORM: | |
case DXGIFormat.R16G16UINT: | |
case DXGIFormat.R16G16SNORM: | |
case DXGIFormat.R16G16SINT: | |
case DXGIFormat.R32TYPELESS: | |
case DXGIFormat.D32FLOAT: | |
case DXGIFormat.R32FLOAT: | |
case DXGIFormat.R32UINT: | |
case DXGIFormat.R32SINT: | |
case DXGIFormat.R24G8TYPELESS: | |
case DXGIFormat.D24UNORMS8UINT: | |
case DXGIFormat.R24UNORMX8TYPELESS: | |
case DXGIFormat.X24TYPELESSG8UINT: | |
case DXGIFormat.R9G9B9E5SHAREDEXP: | |
case DXGIFormat.R8G8B8G8UNORM: | |
case DXGIFormat.G8R8G8B8UNORM: | |
case DXGIFormat.B8G8R8A8UNORM: | |
case DXGIFormat.B8G8R8X8UNORM: | |
case DXGIFormat.R10G10B10XRBIASA2UNORM: | |
case DXGIFormat.B8G8R8A8TYPELESS: | |
case DXGIFormat.B8G8R8A8UNORMSRGB: | |
case DXGIFormat.B8G8R8X8TYPELESS: | |
case DXGIFormat.B8G8R8X8UNORMSRGB: | |
case DXGIFormat.AYUV: | |
case DXGIFormat.Y410: | |
case DXGIFormat.YUY2: | |
return 32; | |
case DXGIFormat.P010: | |
case DXGIFormat.P016: | |
return 24; | |
case DXGIFormat.R8G8TYPELESS: | |
case DXGIFormat.R8G8UNORM: | |
case DXGIFormat.R8G8UINT: | |
case DXGIFormat.R8G8SNORM: | |
case DXGIFormat.R8G8SINT: | |
case DXGIFormat.R16TYPELESS: | |
case DXGIFormat.R16FLOAT: | |
case DXGIFormat.D16UNORM: | |
case DXGIFormat.R16UNORM: | |
case DXGIFormat.R16UINT: | |
case DXGIFormat.R16SNORM: | |
case DXGIFormat.R16SINT: | |
case DXGIFormat.B5G6R5UNORM: | |
case DXGIFormat.B5G5R5A1UNORM: | |
case DXGIFormat.A8P8: | |
case DXGIFormat.B4G4R4A4UNORM: | |
return 16; | |
case DXGIFormat.NV12: | |
case DXGIFormat.OPAQUE420: | |
case DXGIFormat.NV11: | |
return 12; | |
case DXGIFormat.R8TYPELESS: | |
case DXGIFormat.R8UNORM: | |
case DXGIFormat.R8UINT: | |
case DXGIFormat.R8SNORM: | |
case DXGIFormat.R8SINT: | |
case DXGIFormat.A8UNORM: | |
case DXGIFormat.AI44: | |
case DXGIFormat.IA44: | |
case DXGIFormat.P8: | |
return 8; | |
case DXGIFormat.R1UNORM: | |
return 1; | |
case DXGIFormat.BC1TYPELESS: | |
case DXGIFormat.BC1UNORM: | |
case DXGIFormat.BC1UNORMSRGB: | |
case DXGIFormat.BC4TYPELESS: | |
case DXGIFormat.BC4UNORM: | |
case DXGIFormat.BC4SNORM: | |
return 4; | |
case DXGIFormat.BC2TYPELESS: | |
case DXGIFormat.BC2UNORM: | |
case DXGIFormat.BC2UNORMSRGB: | |
case DXGIFormat.BC3TYPELESS: | |
case DXGIFormat.BC3UNORM: | |
case DXGIFormat.BC3UNORMSRGB: | |
case DXGIFormat.BC5TYPELESS: | |
case DXGIFormat.BC5UNORM: | |
case DXGIFormat.BC5SNORM: | |
case DXGIFormat.BC6HTYPELESS: | |
case DXGIFormat.BC6HUF16: | |
case DXGIFormat.BC6HSF16: | |
case DXGIFormat.BC7TYPELESS: | |
case DXGIFormat.BC7UNORM: | |
case DXGIFormat.BC7UNORMSRGB: | |
return 8; | |
default: | |
return 0; | |
} | |
} | |
/// <summary> | |
/// Computes Row and Slice Pitch | |
/// </summary> | |
private static void ComputePitch(DXGIFormat format, long width, long height, out long rowPitch, out long slicePitch, CPFLAGS flags) | |
{ | |
switch (format) | |
{ | |
case DXGIFormat.BC1TYPELESS: | |
case DXGIFormat.BC1UNORM: | |
case DXGIFormat.BC1UNORMSRGB: | |
case DXGIFormat.BC4TYPELESS: | |
case DXGIFormat.BC4UNORM: | |
case DXGIFormat.BC4SNORM: | |
{ | |
if (flags.HasFlag(CPFLAGS.BADDXTNTAILS)) | |
{ | |
long nbw = width >> 2; | |
long nbh = height >> 2; | |
rowPitch = Clamp(1, nbw * 8, Int64.MaxValue); | |
slicePitch = Clamp(1, rowPitch * nbh, Int64.MaxValue); | |
} | |
else | |
{ | |
long nbw = Clamp(1, (width + 3) / 4, Int64.MaxValue); | |
long nbh = Clamp(1, (height + 3) / 4, Int64.MaxValue); | |
rowPitch = nbw * 8; | |
slicePitch = rowPitch * nbh; | |
} | |
} | |
break; | |
case DXGIFormat.BC2TYPELESS: | |
case DXGIFormat.BC2UNORM: | |
case DXGIFormat.BC2UNORMSRGB: | |
case DXGIFormat.BC3TYPELESS: | |
case DXGIFormat.BC3UNORM: | |
case DXGIFormat.BC3UNORMSRGB: | |
case DXGIFormat.BC5TYPELESS: | |
case DXGIFormat.BC5UNORM: | |
case DXGIFormat.BC5SNORM: | |
case DXGIFormat.BC6HTYPELESS: | |
case DXGIFormat.BC6HUF16: | |
case DXGIFormat.BC6HSF16: | |
case DXGIFormat.BC7TYPELESS: | |
case DXGIFormat.BC7UNORM: | |
case DXGIFormat.BC7UNORMSRGB: | |
{ | |
if (flags.HasFlag(CPFLAGS.BADDXTNTAILS)) | |
{ | |
long nbw = width >> 2; | |
long nbh = height >> 2; | |
rowPitch = Clamp(1, nbw * 16, Int64.MaxValue); | |
slicePitch = Clamp(1, rowPitch * nbh, Int64.MaxValue); | |
} | |
else | |
{ | |
long nbw = Clamp(1, (width + 3) / 4, Int64.MaxValue); | |
long nbh = Clamp(1, (height + 3) / 4, Int64.MaxValue); | |
rowPitch = nbw * 16; | |
slicePitch = rowPitch * nbh; | |
} | |
} | |
break; | |
case DXGIFormat.R8G8B8G8UNORM: | |
case DXGIFormat.G8R8G8B8UNORM: | |
case DXGIFormat.YUY2: | |
rowPitch = ((width + 1) >> 1) * 4; | |
slicePitch = rowPitch * height; | |
break; | |
case DXGIFormat.Y210: | |
case DXGIFormat.Y216: | |
rowPitch = ((width + 1) >> 1) * 8; | |
slicePitch = rowPitch * height; | |
break; | |
case DXGIFormat.NV12: | |
case DXGIFormat.OPAQUE420: | |
rowPitch = ((width + 1) >> 1) * 2; | |
slicePitch = rowPitch * (height + ((height + 1) >> 1)); | |
break; | |
case DXGIFormat.P010: | |
case DXGIFormat.P016: | |
rowPitch = ((width + 1) >> 1) * 4; | |
slicePitch = rowPitch * (height + ((height + 1) >> 1)); | |
break; | |
case DXGIFormat.NV11: | |
rowPitch = ((width + 3) >> 2) * 4; | |
slicePitch = rowPitch * height * 2; | |
break; | |
default: | |
{ | |
long bpp; | |
if (flags.HasFlag(CPFLAGS.BPP24)) | |
bpp = 24; | |
else if (flags.HasFlag(CPFLAGS.BPP16)) | |
bpp = 16; | |
else if (flags.HasFlag(CPFLAGS.BPP8)) | |
bpp = 8; | |
else | |
bpp = BitsPerPixel(format); | |
if (flags.HasFlag(CPFLAGS.LEGACYDWORD | CPFLAGS.PARAGRAPH | CPFLAGS.YMM | CPFLAGS.ZMM | CPFLAGS.PAGE4K)) | |
{ | |
if (flags.HasFlag(CPFLAGS.PAGE4K)) | |
{ | |
rowPitch = ((width * bpp + 32767) / 32768) * 4096; | |
slicePitch = rowPitch * height; | |
} | |
else if (flags.HasFlag(CPFLAGS.ZMM)) | |
{ | |
rowPitch = ((width * bpp + 511) / 512) * 64; | |
slicePitch = rowPitch * height; | |
} | |
else if (flags.HasFlag(CPFLAGS.YMM)) | |
{ | |
rowPitch = ((width * bpp + 255) / 256) * 32; | |
slicePitch = rowPitch * height; | |
} | |
else if (flags.HasFlag(CPFLAGS.PARAGRAPH)) | |
{ | |
rowPitch = ((width * bpp + 127) / 128) * 16; | |
slicePitch = rowPitch * height; | |
} | |
else // DWORD alignment | |
{ | |
// Special computation for some incorrectly created DDS files based on | |
// legacy DirectDraw assumptions about pitch alignment | |
rowPitch = ((width * bpp + 31) / 32) * 4; | |
slicePitch = rowPitch * height; | |
} | |
} | |
else | |
{ | |
// Default byte alignment | |
rowPitch = (width * bpp + 7) / 8; | |
slicePitch = rowPitch * height; | |
} | |
} | |
break; | |
} | |
} | |
/// <summary> | |
/// Checks is the given format compressed | |
/// </summary> | |
private static bool IsCompressed(DXGIFormat format) | |
{ | |
switch (format) | |
{ | |
case DXGIFormat.BC1TYPELESS: | |
case DXGIFormat.BC1UNORM: | |
case DXGIFormat.BC1UNORMSRGB: | |
case DXGIFormat.BC2TYPELESS: | |
case DXGIFormat.BC2UNORM: | |
case DXGIFormat.BC2UNORMSRGB: | |
case DXGIFormat.BC3TYPELESS: | |
case DXGIFormat.BC3UNORM: | |
case DXGIFormat.BC3UNORMSRGB: | |
case DXGIFormat.BC4TYPELESS: | |
case DXGIFormat.BC4UNORM: | |
case DXGIFormat.BC4SNORM: | |
case DXGIFormat.BC5TYPELESS: | |
case DXGIFormat.BC5UNORM: | |
case DXGIFormat.BC5SNORM: | |
case DXGIFormat.BC6HTYPELESS: | |
case DXGIFormat.BC6HUF16: | |
case DXGIFormat.BC6HSF16: | |
case DXGIFormat.BC7TYPELESS: | |
case DXGIFormat.BC7UNORM: | |
case DXGIFormat.BC7UNORMSRGB: | |
return true; | |
default: | |
return false; | |
} | |
} | |
#endregion | |
#region MainMethods | |
/// <summary> | |
/// Encodes the DDS Header and if DX10, the DX10 Header | |
/// </summary> | |
/// <param name="header">DDS Header</param> | |
/// <param name="dx10Header">DX10 Header</param> | |
/// <returns>Resulting DDS File Header in bytes</returns> | |
public static byte[] EncodeDDSHeader(DDSHeader header, DX10Header dx10Header) | |
{ | |
// Create stream | |
using (var output = new BinaryWriter(new MemoryStream())) | |
{ | |
// Write DDS Magic | |
output.Write(DDSHeader.DDSMagic); | |
// Write Header | |
output.Write(StructToBytes(header)); | |
// Check for DX10 Header | |
if (header.PixelFormat.FourCC == PixelFormats.DX10.FourCC) | |
// Write Header | |
output.Write(StructToBytes(dx10Header)); | |
// Done | |
return ((MemoryStream)(output.BaseStream)).ToArray(); | |
} | |
} | |
/// <summary> | |
/// Generates DirectXTex Meta Data | |
/// </summary> | |
/// <param name="width">Image Width</param> | |
/// <param name="height">Image Height</param> | |
/// <param name="mipMapLevels">Number of Mip Maps</param> | |
/// <param name="format">Compression Format</param> | |
/// <param name="isCubeMap">Whether or not this is a cube map</param> | |
/// <returns>Resulting TexMetaData Object</returns> | |
public static TexMetadata GenerateMataData(int width, int height, int mipMapLevels, DXGIFormat format, bool isCubeMap) | |
{ | |
// Create Texture MetaData | |
return new TexMetadata( | |
width, | |
height, | |
1, | |
isCubeMap ? 6 : 1, | |
mipMapLevels, | |
isCubeMap ? TexMiscFlags.TEXTURECUBE : 0, | |
0, | |
format, | |
TexDimension.TEXTURE2D | |
); | |
} | |
/// <summary> | |
/// Generates a DDS Header, and if requires, a DX10 Header | |
/// </summary> | |
/// <param name="metaData">Meta Data</param> | |
/// <param name="flags">Flags</param> | |
/// <param name="header">DDS Header Output</param> | |
/// <param name="dx10Header">DX10 Header Output</param> | |
public static void GenerateDDSHeader(TexMetadata metaData, DDSFlags flags, out DDSHeader header, out DX10Header dx10Header) | |
{ | |
// Check array size | |
if (metaData.ArraySize > 1) | |
// Check if we have an array and whether we're cube maps/non-2D | |
if (metaData.ArraySize != 6 || metaData.Dimension != TexDimension.TEXTURE2D || !metaData.IsCubeMap()) | |
// Texture1D arrays, Texture2D arrays, and Cubemap arrays must be stored using 'DX10' extended header | |
flags |= DDSFlags.FORCEDX10EXT; | |
// Check for DX10 Ext | |
if (flags.HasFlag(DDSFlags.FORCEDX10EXTMISC2)) | |
flags |= DDSFlags.FORCEDX10EXT; | |
// Create DDS Header | |
header = new DDSHeader | |
{ | |
// Set Data | |
Size = (uint)Marshal.SizeOf<DDSHeader>(), | |
Flags = DDSHeader.HeaderFlags.TEXTURE, | |
Caps = (uint)DDSHeader.SurfaceFlags.TEXTURE, | |
PixelFormat = new DDSHeader.DDSPixelFormat(0, 0, 0, 0, 0, 0, 0, 0) | |
}; | |
// Create DX10 Header | |
dx10Header = new DX10Header(); | |
// Switch format | |
switch (metaData.Format) | |
{ | |
case DXGIFormat.R8G8B8A8UNORM: | |
header.PixelFormat = PixelFormats.A8B8G8R8; | |
break; | |
case DXGIFormat.R16G16UNORM: | |
header.PixelFormat = PixelFormats.G16R16; | |
break; | |
case DXGIFormat.R8G8UNORM: | |
header.PixelFormat = PixelFormats.A8L8; | |
break; | |
case DXGIFormat.R16UNORM: | |
header.PixelFormat = PixelFormats.L16; | |
break; | |
case DXGIFormat.R8UNORM: | |
header.PixelFormat = PixelFormats.L8; | |
break; | |
case DXGIFormat.A8UNORM: | |
header.PixelFormat = PixelFormats.A8; | |
break; | |
case DXGIFormat.R8G8B8G8UNORM: | |
header.PixelFormat = PixelFormats.R8G8B8G8; | |
break; | |
case DXGIFormat.G8R8G8B8UNORM: | |
header.PixelFormat = PixelFormats.G8R8G8B8; | |
break; | |
case DXGIFormat.BC1UNORM: | |
header.PixelFormat = PixelFormats.DXT1; | |
break; | |
case DXGIFormat.BC2UNORM: | |
header.PixelFormat = metaData.IsPMAlpha() ? (PixelFormats.DXT2) : (PixelFormats.DXT3); | |
break; | |
case DXGIFormat.BC3UNORM: | |
header.PixelFormat = metaData.IsPMAlpha() ? (PixelFormats.DXT4) : (PixelFormats.DXT5); | |
break; | |
case DXGIFormat.BC4UNORM: | |
header.PixelFormat = PixelFormats.BC4UNORM; | |
break; | |
case DXGIFormat.BC4SNORM: | |
header.PixelFormat = PixelFormats.BC4SNORM; | |
break; | |
case DXGIFormat.BC5UNORM: | |
header.PixelFormat = PixelFormats.BC5UNORM; | |
break; | |
case DXGIFormat.BC5SNORM: | |
header.PixelFormat = PixelFormats.BC5SNORM; | |
break; | |
case DXGIFormat.B5G6R5UNORM: | |
header.PixelFormat = PixelFormats.R5G6B5; | |
break; | |
case DXGIFormat.B5G5R5A1UNORM: | |
header.PixelFormat = PixelFormats.A1R5G5B5; | |
break; | |
case DXGIFormat.R8G8SNORM: | |
header.PixelFormat = PixelFormats.V8U8; | |
break; | |
case DXGIFormat.R8G8B8A8SNORM: | |
header.PixelFormat = PixelFormats.Q8W8V8U8; | |
break; | |
case DXGIFormat.R16G16SNORM: | |
header.PixelFormat = PixelFormats.V16U16; | |
break; | |
case DXGIFormat.B8G8R8A8UNORM: | |
header.PixelFormat = PixelFormats.A8R8G8B8; | |
break; | |
case DXGIFormat.B8G8R8X8UNORM: | |
header.PixelFormat = PixelFormats.X8R8G8B8; | |
break; | |
case DXGIFormat.B4G4R4A4UNORM: | |
header.PixelFormat = PixelFormats.A4R4G4B4; | |
break; | |
case DXGIFormat.YUY2: | |
header.PixelFormat = PixelFormats.YUY2; | |
break; | |
// Legacy D3DX formats using D3DFMT enum value as FourCC | |
case DXGIFormat.R32G32B32A32FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 116; // D3DFMTA32B32G32R32F | |
break; | |
case DXGIFormat.R16G16B16A16FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 113; // D3DFMTA16B16G16R16F | |
break; | |
case DXGIFormat.R16G16B16A16UNORM: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 36; // D3DFMTA16B16G16R16 | |
break; | |
case DXGIFormat.R16G16B16A16SNORM: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 110; // D3DFMTQ16W16V16U16 | |
break; | |
case DXGIFormat.R32G32FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 115; // D3DFMTG32R32F | |
break; | |
case DXGIFormat.R16G16FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 112; // D3DFMTG16R16F | |
break; | |
case DXGIFormat.R32FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 114; // D3DFMTR32F | |
break; | |
case DXGIFormat.R16FLOAT: | |
header.PixelFormat.Flags = PixelFormats.DDSFOURCC; header.PixelFormat.FourCC = 111; // D3DFMTR16F | |
break; | |
default: | |
break; | |
} | |
// Check for mips | |
if (metaData.MipLevels > 0) | |
{ | |
// Set flag | |
header.Flags |= DDSHeader.HeaderFlags.MIPMAP; | |
// Check size | |
if (metaData.MipLevels > UInt16.MaxValue) | |
throw new ArgumentException(String.Format("Too many mipmaps: {0}. Max: {1}", metaData.MipLevels, UInt16.MaxValue)); | |
// Set | |
header.MipMapCount = (uint)metaData.MipLevels; | |
// Check count | |
if (header.MipMapCount > 1) | |
header.Caps |= (uint)DDSHeader.SurfaceFlags.MIPMAP; | |
} | |
// Switch Dimension | |
switch (metaData.Dimension) | |
{ | |
case TexDimension.TEXTURE1D: | |
{ | |
// Check size | |
if (metaData.Width > Int32.MaxValue) | |
throw new ArgumentException(String.Format("Image Width too large: {0}. Max: {1}", metaData.Width, Int32.MaxValue)); | |
// Set | |
header.Width = (uint)metaData.Width; | |
header.Height = header.Depth = 1; | |
// Check size | |
break; | |
} | |
case TexDimension.TEXTURE2D: | |
{ | |
// Check size | |
if (metaData.Width > Int32.MaxValue || metaData.Height > Int32.MaxValue) | |
throw new ArgumentException(String.Format("Image Width and/or Height too large: {0}x{1}. Max: {2}", | |
metaData.Width, | |
metaData.Height, | |
Int32.MaxValue)); | |
// Set | |
header.Width = (uint)metaData.Width; | |
header.Height = (uint)metaData.Height; | |
header.Depth = 1; | |
// Check size | |
break; | |
} | |
case TexDimension.TEXTURE3D: | |
{ | |
// Check size | |
if (metaData.Width > Int32.MaxValue || metaData.Height > Int32.MaxValue) | |
throw new ArgumentException(String.Format("Image Width and/or Height too large: {0}x{1}. Max: {2}", | |
metaData.Width, | |
metaData.Height, | |
Int32.MaxValue)); | |
// Check size | |
if (metaData.Depth > UInt16.MaxValue) | |
throw new ArgumentException(String.Format("Image Depth too large: {0}. Max: {1}", metaData.Depth, UInt16.MaxValue)); | |
// Set | |
header.Flags |= DDSHeader.HeaderFlags.VOLUME; | |
header.Caps2 |= 0x00200000; | |
header.Width = (uint)metaData.Width; | |
header.Height = (uint)metaData.Height; | |
header.Depth = (uint)metaData.Depth; | |
// Check size | |
break; | |
} | |
default: | |
throw new ArgumentException("Invalid Texture Dimension."); | |
} | |
// Calculate the Pitch | |
ComputePitch(metaData.Format, metaData.Width, metaData.Height, out long rowPitch, out long slicePitch, CPFLAGS.NONE); | |
// Validate results | |
if (slicePitch > UInt32.MaxValue || rowPitch > UInt32.MaxValue) | |
throw new ArgumentException("Failed to calculate row and/or slice pitch, values returned were too large"); | |
// Check is it compressed | |
if (IsCompressed(metaData.Format)) | |
{ | |
header.Flags |= DDSHeader.HeaderFlags.LINEARSIZE; | |
header.PitchOrLinearSize = (uint)slicePitch; | |
} | |
else | |
{ | |
header.Flags |= DDSHeader.HeaderFlags.PITCH; | |
header.PitchOrLinearSize = (uint)rowPitch; | |
} | |
// Check for do we need to create the DX10 Header | |
if (header.PixelFormat.Size == 0) | |
{ | |
// Check size | |
if (metaData.ArraySize > UInt16.MaxValue) | |
throw new ArgumentException(String.Format("Array Size too large: {0}. Max: {1}", metaData.ArraySize, UInt16.MaxValue)); | |
// Set Pixel format | |
header.PixelFormat = PixelFormats.DX10; | |
// Set Data | |
dx10Header.Format = metaData.Format; | |
dx10Header.ResourceDimension = metaData.Dimension; | |
dx10Header.MiscFlag = metaData.MiscFlags & ~TexMiscFlags.TEXTURECUBE; | |
dx10Header.ArraySize = (uint)metaData.ArraySize; | |
// Check for Cube Maps | |
if (metaData.MiscFlags.HasFlag(TexMiscFlags.TEXTURECUBE)) | |
{ | |
// Check array size, must be a multiple of 6 for cube maps | |
if ((metaData.ArraySize % 6) != 0) | |
throw new ArgumentException("Array size must be a multiple of 6"); | |
// Set Flag | |
dx10Header.MiscFlag |= TexMiscFlags.TEXTURECUBE; | |
dx10Header.ArraySize /= 6; | |
} | |
// Check for mist flags | |
if (flags.HasFlag(DDSFlags.FORCEDX10EXTMISC2)) | |
// This was formerly 'reserved'. D3DX10 and D3DX11 will fail if this value is anything other than 0 | |
dx10Header.MiscFlags2 = (uint)metaData.MiscFlags2; | |
} | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment