Last active
August 19, 2022 20:14
-
-
Save tilkinsc/a3af3c2d53e4f78bfad49db0db516fc7 to your computer and use it in GitHub Desktop.
C# rudimentary loading DDS for OpenGL using Silk.NET
This file contains hidden or 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
enum DDSD | |
{ | |
NONE = 0x00, | |
CAPS = 0x01, | |
HEIGHT = 0x02, | |
WIDTH = 0x04, | |
PITCH = 0x08, | |
PIXELFORMAT = 0x1000, | |
MIPMAPCOUNT = 0x20000, | |
LINEARSIZE = 0x80000, | |
DEPTH = 0x800000 | |
} | |
enum DDPF | |
{ | |
NONE = 0x00, | |
ALPHAPIXELS = 0x01, | |
ALPHA = 0x02, | |
FOURCC = 0x04, | |
RGB = 0x40, | |
YUV = 0x200, | |
LUMINANCE = 0x20000 | |
} | |
enum DDSFourCC | |
{ | |
NONE = 0x00, | |
DXT1 = 0x01, | |
DXT2 = 0x02, | |
DXT3 = 0x04, | |
DXT4 = 0x08, | |
DXT5 = 0x10, | |
DX10 = 0x20 | |
} | |
enum DDSCaps | |
{ | |
COMPLEX = 0x8, | |
MIPMAP = 0x400000, | |
TEXTURE = 0x1000 | |
} | |
enum DDSCaps2 | |
{ | |
CUBEMAP = 0x200, | |
CUBEMAP_POSITIVEX = 0x400, | |
CUBEMAP_NEGATIVEX = 0x800, | |
CUBEMAP_POSITIVEY = 0x1000, | |
CUBEMAP_NEGATIVEY = 0x2000, | |
CUBEMAP_POSITIVEZ = 0x4000, | |
CUBEMAP_NEGATIVEZ = 0x8000, | |
VOLUME = 0x200000 | |
} | |
struct DDSPixelFormat | |
{ | |
public uint Size; | |
public DDPF Flags; | |
public DDSFourCC FourCC; | |
public uint RGBBitCount; | |
public uint RBitMask; | |
public uint GBitMask; | |
public uint BBitMask; | |
public uint ABitMask; | |
} | |
enum DDSDXGIFormat | |
{ | |
FORMAT_UNKNOWN = 0, | |
FORMAT_R32G32B32A32_TYPELESS = 1, | |
FORMAT_R32G32B32A32_FLOAT = 2, | |
FORMAT_R32G32B32A32_UINT = 3, | |
FORMAT_R32G32B32A32_SINT = 4, | |
FORMAT_R32G32B32_TYPELESS = 5, | |
FORMAT_R32G32B32_FLOAT = 6, | |
FORMAT_R32G32B32_UINT = 7, | |
FORMAT_R32G32B32_SINT = 8, | |
FORMAT_R16G16B16A16_TYPELESS = 9, | |
FORMAT_R16G16B16A16_FLOAT = 10, | |
FORMAT_R16G16B16A16_UNORM = 11, | |
FORMAT_R16G16B16A16_UINT = 12, | |
FORMAT_R16G16B16A16_SNORM = 13, | |
FORMAT_R16G16B16A16_SINT = 14, | |
FORMAT_R32G32_TYPELESS = 15, | |
FORMAT_R32G32_FLOAT = 16, | |
FORMAT_R32G32_UINT = 17, | |
FORMAT_R32G32_SINT = 18, | |
FORMAT_R32G8X24_TYPELESS = 19, | |
FORMAT_D32_FLOAT_S8X24_UINT = 20, | |
FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, | |
FORMAT_X32_TYPELESS_G8X24_UINT = 22, | |
FORMAT_R10G10B10A2_TYPELESS = 23, | |
FORMAT_R10G10B10A2_UNORM = 24, | |
FORMAT_R10G10B10A2_UINT = 25, | |
FORMAT_R11G11B10_FLOAT = 26, | |
FORMAT_R8G8B8A8_TYPELESS = 27, | |
FORMAT_R8G8B8A8_UNORM = 28, | |
FORMAT_R8G8B8A8_UNORM_SRGB = 29, | |
FORMAT_R8G8B8A8_UINT = 30, | |
FORMAT_R8G8B8A8_SNORM = 31, | |
FORMAT_R8G8B8A8_SINT = 32, | |
FORMAT_R16G16_TYPELESS = 33, | |
FORMAT_R16G16_FLOAT = 34, | |
FORMAT_R16G16_UNORM = 35, | |
FORMAT_R16G16_UINT = 36, | |
FORMAT_R16G16_SNORM = 37, | |
FORMAT_R16G16_SINT = 38, | |
FORMAT_R32_TYPELESS = 39, | |
FORMAT_D32_FLOAT = 40, | |
FORMAT_R32_FLOAT = 41, | |
FORMAT_R32_UINT = 42, | |
FORMAT_R32_SINT = 43, | |
FORMAT_R24G8_TYPELESS = 44, | |
FORMAT_D24_UNORM_S8_UINT = 45, | |
FORMAT_R24_UNORM_X8_TYPELESS = 46, | |
FORMAT_X24_TYPELESS_G8_UINT = 47, | |
FORMAT_R8G8_TYPELESS = 48, | |
FORMAT_R8G8_UNORM = 49, | |
FORMAT_R8G8_UINT = 50, | |
FORMAT_R8G8_SNORM = 51, | |
FORMAT_R8G8_SINT = 52, | |
FORMAT_R16_TYPELESS = 53, | |
FORMAT_R16_FLOAT = 54, | |
FORMAT_D16_UNORM = 55, | |
FORMAT_R16_UNORM = 56, | |
FORMAT_R16_UINT = 57, | |
FORMAT_R16_SNORM = 58, | |
FORMAT_R16_SINT = 59, | |
FORMAT_R8_TYPELESS = 60, | |
FORMAT_R8_UNORM = 61, | |
FORMAT_R8_UINT = 62, | |
FORMAT_R8_SNORM = 63, | |
FORMAT_R8_SINT = 64, | |
FORMAT_A8_UNORM = 65, | |
FORMAT_R1_UNORM = 66, | |
FORMAT_R9G9B9E5_SHAREDEXP = 67, | |
FORMAT_R8G8_B8G8_UNORM = 68, | |
FORMAT_G8R8_G8B8_UNORM = 69, | |
FORMAT_BC1_TYPELESS = 70, | |
FORMAT_BC1_UNORM = 71, | |
FORMAT_BC1_UNORM_SRGB = 72, | |
FORMAT_BC2_TYPELESS = 73, | |
FORMAT_BC2_UNORM = 74, | |
FORMAT_BC2_UNORM_SRGB = 75, | |
FORMAT_BC3_TYPELESS = 76, | |
FORMAT_BC3_UNORM = 77, | |
FORMAT_BC3_UNORM_SRGB = 78, | |
FORMAT_BC4_TYPELESS = 79, | |
FORMAT_BC4_UNORM = 80, | |
FORMAT_BC4_SNORM = 81, | |
FORMAT_BC5_TYPELESS = 82, | |
FORMAT_BC5_UNORM = 83, | |
FORMAT_BC5_SNORM = 84, | |
FORMAT_B5G6R5_UNORM = 85, | |
FORMAT_B5G5R5A1_UNORM = 86, | |
FORMAT_B8G8R8A8_UNORM = 87, | |
FORMAT_B8G8R8X8_UNORM = 88, | |
FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, | |
FORMAT_B8G8R8A8_TYPELESS = 90, | |
FORMAT_B8G8R8A8_UNORM_SRGB = 91, | |
FORMAT_B8G8R8X8_TYPELESS = 92, | |
FORMAT_B8G8R8X8_UNORM_SRGB = 93, | |
FORMAT_BC6H_TYPELESS = 94, | |
FORMAT_BC6H_UF16 = 95, | |
FORMAT_BC6H_SF16 = 96, | |
FORMAT_BC7_TYPELESS = 97, | |
FORMAT_BC7_UNORM = 98, | |
FORMAT_BC7_UNORM_SRGB = 99, | |
FORMAT_AYUV = 100, | |
FORMAT_Y410 = 101, | |
FORMAT_Y416 = 102, | |
FORMAT_NV12 = 103, | |
FORMAT_P010 = 104, | |
FORMAT_P016 = 105, | |
FORMAT_420_OPAQUE = 106, | |
FORMAT_YUY2 = 107, | |
FORMAT_Y210 = 108, | |
FORMAT_Y216 = 109, | |
FORMAT_NV11 = 110, | |
FORMAT_AI44 = 111, | |
FORMAT_IA44 = 112, | |
FORMAT_P8 = 113, | |
FORMAT_A8P8 = 114, | |
FORMAT_B4G4R4A4_UNORM = 115, | |
FORMAT_P208 = 130, | |
FORMAT_V208 = 131, | |
FORMAT_V408 = 132, | |
FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE = 133, | |
FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE = 134, | |
FORMAT_FORCE_UINT = int.MinValue | |
} | |
enum DDSResourceDimension | |
{ | |
UNKNOWN = 0, | |
BUFFER = 1, | |
TEXTURE1D = 2, | |
TEXTURE2D = 3, | |
TEXTURE3D = 4 | |
} | |
enum DDSMisc | |
{ | |
TEXTURECUBE | |
} | |
enum DDSMisc2 | |
{ | |
ALPHA_MODE_UNKNOWN = 0x00, | |
ALPHA_MODE_STRAIGHT = 0x01, | |
ALPHA_MODE_PREMULTIPLIED = 0x02, | |
ALPHA_MODE_OPAQUE = 0x03, | |
ALPHA_MODE_CUSTOM = 0x04 | |
} | |
struct DDSDX10Header | |
{ | |
public DDSDXGIFormat Format; | |
public DDSResourceDimension ResourceDimension; | |
public DDSMisc MiscFlags; | |
public uint ArraySize; | |
public DDSMisc2 MiscFlags2; | |
} | |
class DDSFile | |
{ | |
public uint HeaderSize { get; set; } | |
public DDSD Flags { get; set; } | |
public uint Height { get; set; } | |
public uint Width { get; set; } | |
public uint PitchOrLinearSize { get; set; } | |
public uint Depth { get; set; } | |
public uint MipMapCount { get; set; } | |
public DDSPixelFormat PixelFormat { get; set; } | |
public DDSCaps Caps1 { get; set; } | |
public DDSCaps2 Caps2 { get; set; } | |
public bool IsHasDX10 { get; set; } | |
public DDSDX10Header DX10 { get; set; } | |
public byte[]? Data; | |
} | |
static class DDSLoader | |
{ | |
public static DDSFile? Load(string path) | |
{ | |
try { | |
using (FileStream fs = File.OpenRead(path)) { | |
DDSFile file = new DDSFile(); | |
byte[] header = new byte[128]; | |
fs.Read(header, 0, 128); | |
file.HeaderSize = (uint) ((header[4]) | (header[5] << 8) | (header[6] << 16) | (header[7] << 24)); | |
file.Flags = (DDSD) ((header[4]) | (header[5] << 8) | (header[6] << 16) | (header[7] << 24)); | |
file.Height = (uint) ((header[12]) | (header[13] << 8) | (header[14] << 16) | (header[15] << 24)); | |
file.Width = (uint) ((header[16]) | (header[17] << 8) | (header[18] << 16) | (header[19] << 24)); | |
file.PitchOrLinearSize = (uint) ((header[20]) | (header[21] << 8) | (header[22] << 16) | (header[23] << 24)); | |
file.Depth = (uint) ((header[24]) | (header[25] << 8) | (header[26] << 16) | (header[27] << 24)); | |
file.MipMapCount = (uint) ((header[28]) | (header[29] << 8) | (header[30] << 16) | (header[31] << 24)); | |
DDSPixelFormat format = new DDSPixelFormat(); | |
format.Size = (uint) ((header[76]) | (header[77] << 8) | (header[78] << 16) | (header[79] << 24)); | |
format.Flags = (DDPF) ((header[80]) | (header[81] << 8) | (header[82] << 16) | (header[83] << 24)); | |
format.FourCC = (DDSFourCC) ((header[84]) | (header[85] << 8) | (header[86] << 16) | (header[87] << 24)); | |
format.RGBBitCount = (uint) ((header[88]) | (header[89] << 8) | (header[90] << 16) | (header[91] << 24)); | |
format.RBitMask = (uint) ((header[92]) | (header[93] << 8) | (header[94] << 16) | (header[95] << 24)); | |
format.GBitMask = (uint) ((header[96]) | (header[97] << 8) | (header[98] << 16) | (header[99] << 24)); | |
format.BBitMask = (uint) ((header[100]) | (header[101] << 8) | (header[102] << 16) | (header[103] << 24)); | |
format.ABitMask = (uint) ((header[104]) | (header[105] << 8) | (header[106] << 16) | (header[107] << 24)); | |
file.PixelFormat = format; | |
if (format.FourCC == DDSFourCC.DX10) { | |
byte[] header2 = new byte[20]; | |
fs.Read(header2, 0, 20); | |
DDSDX10Header dx10 = new DDSDX10Header(); | |
dx10.Format = (DDSDXGIFormat) ((header[0]) | (header[1] << 8) | (header[2] << 16) | (header[3] << 24)); | |
dx10.ResourceDimension = (DDSResourceDimension) ((header[4]) | (header[5] << 8) | (header[6] << 16) | (header[7] << 24)); | |
dx10.MiscFlags = (DDSMisc) ((header[8]) | (header[9] << 8) | (header[10] << 16) | (header[11] << 24)); | |
dx10.ArraySize = (uint) ((header[12]) | (header[13] << 8) | (header[14] << 16) | (header[15] << 24)); | |
dx10.MiscFlags2 = (DDSMisc2) ((header[16]) | (header[17] << 8) | (header[18] << 16) | (header[19] << 24)); | |
file.DX10 = dx10; | |
file.IsHasDX10 = true; | |
} | |
file.Caps1 = (DDSCaps) ((header[104]) | (header[105] << 8) | (header[106] << 16) | (header[107] << 24)); | |
file.Caps2 = (DDSCaps2) ((header[108]) | (header[109] << 8) | (header[110] << 16) | (header[111] << 24)); | |
// TODO: not sure if fs.Length is the correct option here | |
byte[] data = new byte[fs.Length]; | |
fs.Read(data, 0, (int) fs.Length); | |
file.Data = data; | |
return file; | |
} | |
} catch (Exception e) { | |
Console.Error.WriteLine(e); | |
} | |
return null; | |
} | |
} | |
class Material | |
{ | |
public uint TextureID { get; private set; } | |
public int Width { get; private set; } | |
public int Height { get; private set; } | |
public int AtlasWidth { get; private set; } | |
public int AtlasHeight { get; private set; } | |
private Material() | |
{ | |
} | |
public static unsafe Material? LoadTextureDDS(DDSFile? dds) | |
{ | |
if (dds == null || dds.Data == null) | |
return null; | |
GL gl = WindowHandler.OpenGL!; | |
Material tex = new Material(); | |
GLEnum format = 0; | |
uint blocksize = 0; | |
switch (dds.PixelFormat.FourCC) | |
{ | |
case DDSFourCC.DXT1: | |
blocksize = 8; | |
format = (GLEnum) GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; | |
break; | |
case DDSFourCC.DXT4: | |
format = (GLEnum) GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; | |
blocksize = 16; | |
break; | |
case DDSFourCC.DX10: | |
case DDSFourCC.DXT5: | |
default: | |
format = (GLEnum) GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; | |
blocksize = 16; | |
break; | |
} | |
uint id = gl.GenTexture(); | |
gl.BindTexture(TextureTarget.Texture2D, id); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBaseLevel, 0); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, dds.MipMapCount - 1); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) GLEnum.LinearMipmapLinear); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) GLEnum.Nearest); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) GLEnum.ClampToEdge); | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) GLEnum.ClampToEdge); | |
uint offset = 0; | |
uint size = 0; | |
uint w = dds.Width; | |
uint h = dds.Height; | |
uint mipmaps = dds.MipMapCount; | |
for (int i=0; i<dds.MipMapCount; i++) | |
{ | |
if (w == 0 || h == 0) { | |
mipmaps--; | |
continue; | |
} | |
size = ((w+3)/4) * ((h+3)/4) * blocksize; | |
fixed (byte* p = &dds.Data[0]) | |
{ | |
gl.CompressedTexImage2D(TextureTarget.Texture2D, i, format, w, h, 0, size, p + offset); | |
} | |
offset += size; | |
w /= 2; | |
h /= 2; | |
} | |
gl.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMaxLevel, mipmaps - 1); | |
gl.BindTexture(TextureTarget.Texture2D, 0); | |
tex.TextureID = id; | |
return tex; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment