improve DDS format support

main
cosmonaut 2022-05-12 11:21:07 -07:00
parent b22d3bed30
commit 66d363459b
1 changed files with 112 additions and 26 deletions

View File

@ -77,24 +77,39 @@ namespace MoonWorks.Graphics
{ {
using (var reader = new BinaryReader(stream)) using (var reader = new BinaryReader(stream))
{ {
ParseDDS(reader, out var format, out var width, out var height, out var levels); Texture texture;
Texture texture = CreateTexture2D(graphicsDevice, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, SampleCount.One, (uint) levels); int faces;
ParseDDS(reader, out var format, out var width, out var height, out var levels, out var isCube);
for (int i = 0; i < levels; i += 1) if (isCube)
{ {
var levelWidth = width >> i; texture = CreateTextureCube(graphicsDevice, (uint) width, format, TextureUsageFlags.Sampler, SampleCount.One, (uint) levels);
var levelHeight = height >> i; faces = 6;
}
else
{
texture = CreateTexture2D(graphicsDevice, (uint) width, (uint) height, format, TextureUsageFlags.Sampler, SampleCount.One, (uint) levels);
faces = 1;
}
var pixels = reader.ReadBytes( for (int i = 0; i < faces; i += 1)
Texture.CalculateDDSLevelSize( {
levelWidth, for (int j = 0; j < levels; j += 1)
levelHeight, {
format var levelWidth = width >> i;
) var levelHeight = height >> i;
);
var textureSlice = new TextureSlice(texture, new Rect(0, 0, levelWidth, levelHeight), 0, 0, (uint) i); var pixels = reader.ReadBytes(
commandBuffer.SetTextureData(textureSlice, pixels); Texture.CalculateDDSLevelSize(
levelWidth,
levelHeight,
format
)
);
var textureSlice = new TextureSlice(texture, new Rect(0, 0, levelWidth, levelHeight), 0, (uint) i, (uint) j);
commandBuffer.SetTextureData(textureSlice, pixels);
}
} }
return texture; return texture;
@ -262,7 +277,8 @@ namespace MoonWorks.Graphics
out TextureFormat format, out TextureFormat format,
out int width, out int width,
out int height, out int height,
out int levels out int levels,
out bool isCube
) { ) {
// A whole bunch of magic numbers, yay DDS! // A whole bunch of magic numbers, yay DDS!
const uint DDS_MAGIC = 0x20534444; const uint DDS_MAGIC = 0x20534444;
@ -285,8 +301,7 @@ namespace MoonWorks.Graphics
const uint FOURCC_DXT1 = 0x31545844; const uint FOURCC_DXT1 = 0x31545844;
const uint FOURCC_DXT3 = 0x33545844; const uint FOURCC_DXT3 = 0x33545844;
const uint FOURCC_DXT5 = 0x35545844; const uint FOURCC_DXT5 = 0x35545844;
const uint FOURCC_BPTC = 0x30315844; const uint FOURCC_DX10 = 0x30315844;
// const uint FOURCC_DX10 = 0x30315844;
const uint pitchAndLinear = ( const uint pitchAndLinear = (
DDSD_PITCH | DDSD_LINEARSIZE DDSD_PITCH | DDSD_LINEARSIZE
); );
@ -341,12 +356,22 @@ namespace MoonWorks.Graphics
{ {
throw new NotSupportedException("Not a texture!"); throw new NotSupportedException("Not a texture!");
} }
isCube = false;
uint caps2 = reader.ReadUInt32(); uint caps2 = reader.ReadUInt32();
if ( caps2 != 0 && if (caps2 != 0)
(caps2 & DDSCAPS2_CUBEMAP) != DDSCAPS2_CUBEMAP )
{ {
throw new NotSupportedException("Invalid caps2!"); if ((caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP)
{
isCube = true;
}
else
{
throw new NotSupportedException("Invalid caps2!");
}
} }
reader.ReadUInt32(); // dwCaps3, unused reader.ReadUInt32(); // dwCaps3, unused
reader.ReadUInt32(); // dwCaps4, unused reader.ReadUInt32(); // dwCaps4, unused
@ -364,10 +389,10 @@ namespace MoonWorks.Graphics
{ {
switch (formatFourCC) switch (formatFourCC)
{ {
case 0x71: case 0x71: // D3DFMT_A16B16G16R16F
format = TextureFormat.R16G16B16A16_SFLOAT; format = TextureFormat.R16G16B16A16_SFLOAT;
break; break;
case 0x74: case 0x74: // D3DFMT_A32B32G32R32F
format = TextureFormat.R32G32B32A32_SFLOAT; format = TextureFormat.R32G32B32A32_SFLOAT;
break; break;
case FOURCC_DXT1: case FOURCC_DXT1:
@ -379,15 +404,76 @@ namespace MoonWorks.Graphics
case FOURCC_DXT5: case FOURCC_DXT5:
format = TextureFormat.BC3; format = TextureFormat.BC3;
break; break;
case FOURCC_BPTC: case FOURCC_DX10:
format = TextureFormat.BC7; // If the fourCC is DX10, there is an extra header with additional format information.
// These next 5 uints are part of the DX10 DDS header.
// They contain a little extra information but aren't that important.
uint dxgiFormat = reader.ReadUInt32(); uint dxgiFormat = reader.ReadUInt32();
// These values are taken from the DXGI_FORMAT enum.
switch (dxgiFormat)
{
case 2:
format = TextureFormat.R32G32B32A32_SFLOAT;
break;
case 10:
format = TextureFormat.R16G16B16A16_SFLOAT;
break;
case 71:
format = TextureFormat.BC1;
break;
case 74:
format = TextureFormat.BC2;
break;
case 77:
format = TextureFormat.BC3;
break;
case 98:
format = TextureFormat.BC7;
break;
default:
throw new NotSupportedException(
"Unsupported DDS texture format"
);
}
uint resourceDimension = reader.ReadUInt32(); uint resourceDimension = reader.ReadUInt32();
// These values are taken from the D3D10_RESOURCE_DIMENSION enum.
switch (resourceDimension)
{
case 0: // Unknown
case 1: // Buffer
throw new NotSupportedException(
"Unsupported DDS texture format"
);
}
/*
* This flag seemingly only indicates if the texture is a cube map.
* This is already determined above. Cool!
*/
uint miscFlag = reader.ReadUInt32(); uint miscFlag = reader.ReadUInt32();
/*
* Indicates the number of elements in the texture array.
* We don't support texture arrays so just throw if it's greater than 1.
*/
uint arraySize = reader.ReadUInt32(); uint arraySize = reader.ReadUInt32();
if (arraySize > 1)
{
throw new NotSupportedException(
"Unsupported DDS texture format"
);
}
reader.ReadUInt32(); // reserved reader.ReadUInt32(); // reserved
break; break;
default: default:
throw new NotSupportedException( throw new NotSupportedException(