map3drendering/LandblockExtraction/Tools/DDSHeader.cs

187 lines
No EOL
7.3 KiB
C#

using AC2RE.Definitions;
namespace LandblockExtraction.Tools;
public static class DDSHeader {
//MagicNumber for DDS file.
private static readonly uint MAGICNUMBER = 0x20534444;
//Length of header
private static readonly int LENGTH = 125;
public static byte[] Generate(RenderSurface renderSurface) {
if (renderSurface.pixelFormat == PixelFormat.CUSTOM_RAW_JPEG) return renderSurface.sourceData;
DDS_HEADER header = genHeadStruct(renderSurface.pixelFormat, renderSurface.height, renderSurface.width);
using (MemoryStream stream = new MemoryStream(LENGTH + renderSurface.sourceData.Length)) {
stream.Write(BitConverter.GetBytes(MAGICNUMBER));
stream.Write(BitConverter.GetBytes(header.dwSize));
stream.Write(BitConverter.GetBytes((uint)header.dwFlags));
stream.Write(BitConverter.GetBytes(header.dwHeight));
stream.Write(BitConverter.GetBytes(header.dwWidth));
stream.Write(BitConverter.GetBytes(header.dwPitchOrLinearSize));
stream.Write(BitConverter.GetBytes(header.dwDepth));
stream.Write(BitConverter.GetBytes(header.dwMipMapCount));
foreach (var i in header.dwReserved1) stream.Write(BitConverter.GetBytes(i));
stream.Write(BitConverter.GetBytes(header.ddspf.dwSize));
stream.Write(BitConverter.GetBytes((uint)header.ddspf.dwFlags));
stream.Write(BitConverter.GetBytes(header.ddspf.dwFourCC));
stream.Write(BitConverter.GetBytes(header.ddspf.dwRGBBitCount));
stream.Write(BitConverter.GetBytes(header.ddspf.dwRBitMask));
stream.Write(BitConverter.GetBytes(header.ddspf.dwGBitMask));
stream.Write(BitConverter.GetBytes(header.ddspf.dwBBitMask));
stream.Write(BitConverter.GetBytes(header.ddspf.dwABitMask));
stream.Write(BitConverter.GetBytes(header.dwCaps));
stream.Write(BitConverter.GetBytes(header.dwCaps2));
stream.Write(BitConverter.GetBytes(header.dwCaps3));
stream.Write(BitConverter.GetBytes(header.dwCaps4));
stream.Write(BitConverter.GetBytes(header.dwReserved2));
stream.Write(renderSurface.sourceData);
return stream.ToArray();
}
}
private static DDS_HEADER genHeadStruct(PixelFormat format, uint height, uint width) {
//I think always same each format?
DDS_HEADER dDS_HEADER = new DDS_HEADER();
dDS_HEADER.dwFlags |= DDSHeaderFlags.DDSD_CAPS | DDSHeaderFlags.DDSD_HEIGHT | DDSHeaderFlags.DDSD_WIDTH | DDSHeaderFlags.DDSD_PIXELFORMAT;
if (dDS_HEADER.dwFlags.HasFlag(DDSHeaderFlags.DDSD_HEIGHT)) dDS_HEADER.dwHeight = height;
if (dDS_HEADER.dwFlags.HasFlag(DDSHeaderFlags.DDSD_WIDTH)) dDS_HEADER.dwWidth = width;
if (format == PixelFormat.DXT1) {
dDS_HEADER.dwFlags |= DDSHeaderFlags.DDSD_LINEARSIZE;
dDS_HEADER.dwPitchOrLinearSize = CalculateCompressedBlockSize(height, width, (uint)new byte[8].Length);
}
if (format == PixelFormat.DXT3 || format == PixelFormat.DXT2 || format == PixelFormat.DXT4 || format == PixelFormat.DXT5) {
dDS_HEADER.dwFlags |= DDSHeaderFlags.DDSD_LINEARSIZE;
dDS_HEADER.dwPitchOrLinearSize = CalculateCompressedBlockSize(height, width, (uint)new byte[16].Length);
}
if (dDS_HEADER.dwFlags.HasFlag(DDSHeaderFlags.DDSD_PIXELFORMAT)) dDS_HEADER.ddspf = genPixelformatStruct(format);
return dDS_HEADER;
}
private static DDS_PIXELFORMAT genPixelformatStruct(PixelFormat surface) {
DDS_PIXELFORMAT dDS_PIXELFORMAT = new DDS_PIXELFORMAT();
switch (surface) {
case PixelFormat.DXT1:
case PixelFormat.DXT3:
case PixelFormat.DXT4:
case PixelFormat.DXT5:
dDS_PIXELFORMAT.dwFlags |= DDSPixelformatFlags.DDPF_FOURCC;
dDS_PIXELFORMAT.dwFourCC = (uint)surface;
break;
case PixelFormat.A8R8G8B8:
dDS_PIXELFORMAT.dwFlags |= DDSPixelformatFlags.DDPF_ALPHAPIXELS | DDSPixelformatFlags.DDPF_RGB;
dDS_PIXELFORMAT.dwRGBBitCount = 0x20;
dDS_PIXELFORMAT.dwRBitMask = 0x00FF0000;
dDS_PIXELFORMAT.dwGBitMask = 0x0000FF00;
dDS_PIXELFORMAT.dwBBitMask = 0x000000FF;
dDS_PIXELFORMAT.dwABitMask = 0xFF000000;
break;
case PixelFormat.R8G8B8:
dDS_PIXELFORMAT.dwFlags |= DDSPixelformatFlags.DDPF_RGB;
dDS_PIXELFORMAT.dwRGBBitCount = 0x18;
dDS_PIXELFORMAT.dwRBitMask = 0x00FF0000;
dDS_PIXELFORMAT.dwGBitMask = 0x0000FF00;
dDS_PIXELFORMAT.dwBBitMask = 0x000000FF;
break;
case PixelFormat.A8:
dDS_PIXELFORMAT.dwFlags |= DDSPixelformatFlags.DDPF_ALPHAPIXELS;
dDS_PIXELFORMAT.dwRGBBitCount = 0x8;
dDS_PIXELFORMAT.dwABitMask = 0xFF;
break;
default:
dDS_PIXELFORMAT.dwFlags |= DDSPixelformatFlags.DDPF_FOURCC;
break;
}
return dDS_PIXELFORMAT;
}
public static uint CalculateCompressedBlockSize(uint height, uint width, uint blockSize) {
return ((width + 3) / 4) * ((height + 3) / 4) * blockSize;
}
}
public struct DDS_HEADER {
public uint dwSize;
public DDSHeaderFlags dwFlags;
public uint dwHeight;
public uint dwWidth;
public uint dwPitchOrLinearSize;
public uint dwDepth;
public uint dwMipMapCount;
public uint[] dwReserved1;
public DDS_PIXELFORMAT ddspf;
public uint dwCaps;
public uint dwCaps2;
public uint dwCaps3;
public uint dwCaps4;
public uint dwReserved2;
public DDS_HEADER() {
dwSize = 124; //Fixed on 124 octets
dwFlags = 0;
dwHeight = 0;
dwWidth = 0;
dwPitchOrLinearSize = 0;
dwDepth = 0;
dwMipMapCount = 0;
dwReserved1 = new uint[11];
foreach (var i in dwReserved1) dwReserved1[i] = 0x00000000;
ddspf = new DDS_PIXELFORMAT();
dwCaps = 0x1000;
dwCaps2 = 0;
dwCaps3 = 0;
dwCaps4 = 0;
dwReserved2 = 0;
}
}
public struct DDS_PIXELFORMAT {
public uint dwSize;
public DDSPixelformatFlags dwFlags;
public uint dwFourCC;
public uint dwRGBBitCount;
public uint dwRBitMask;
public uint dwGBitMask;
public uint dwBBitMask;
public uint dwABitMask;
public DDS_PIXELFORMAT() {
dwSize = 32; //Fixed on 32 octets
dwFlags = 0;
dwFourCC = 0;
dwRGBBitCount = 0;
dwRBitMask = 0;
dwGBitMask = 0;
dwBBitMask = 0;
dwABitMask = 0;
}
}
[Flags]
public enum DDSHeaderFlags : uint {
NONE = 0,
DDSD_CAPS = 1 << 0, // 0x00000001
DDSD_HEIGHT = 1 << 1, // 0x00000002
DDSD_WIDTH = 1 << 2, // 0x00000004
DDSD_PITCH = 1 << 3, // 0x00000008
DDSD_PIXELFORMAT = 1 << 12, // 0x00001000
DDSD_MIPMAPCOUNT = 1 << 17, // 0x00020000
DDSD_LINEARSIZE = 1 << 19, // 0x00080000
DDSD_DEPTH = 1 << 23, // 0x00800000
}
[Flags]
public enum DDSPixelformatFlags : uint {
NONE = 0,
DDPF_ALPHAPIXELS = 1 << 0, // 0x00000001
DDPF_ALPHA = 1 << 1, // 0x00000002
DDPF_FOURCC = 1 << 2, // 0x00000004
DDPF_RGB = 1 << 6, // 0x00000040
DDPF_YUV = 1 << 9, // 0x00000200
DDPF_LUMINANCE = 1 << 17, // 0x00020000
}