using System.Runtime.InteropServices; namespace Imaging.DDSReader.Utils { public class Helper { #region Constants // DDSStruct flags public const int DDSD_CAPS = 0x00000001; public const int DDSD_HEIGHT = 0x00000002; public const int DDSD_WIDTH = 0x00000004; public const int DDSD_PITCH = 0x00000008; public const int DDSD_PIXELFORMAT = 0x00001000; public const int DDSD_MIPMAPCOUNT = 0x00020000; public const int DDSD_LINEARSIZE = 0x00080000; public const int DDSD_DEPTH = 0x00800000; // PixelFormat values public const int DDPF_ALPHAPIXELS = 0x00000001; public const int DDPF_FOURCC = 0x00000004; public const int DDPF_RGB = 0x00000040; public const int DDPF_LUMINANCE = 0x00020000; // DDSCaps public const int DDSCAPS_COMPLEX = 0x00000008; public const int DDSCAPS_TEXTURE = 0x00001000; public const int DDSCAPS_MIPMAP = 0x00400000; public const int DDSCAPS2_CUBEMAP = 0x00000200; public const int DDSCAPS2_CUBEMAP_POSITIVEX = 0x00000400; public const int DDSCAPS2_CUBEMAP_NEGATIVEX = 0x00000800; public const int DDSCAPS2_CUBEMAP_POSITIVEY = 0x00001000; public const int DDSCAPS2_CUBEMAP_NEGATIVEY = 0x00002000; public const int DDSCAPS2_CUBEMAP_POSITIVEZ = 0x00004000; public const int DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x00008000; public const int DDSCAPS2_VOLUME = 0x00200000; // FOURCC public const uint FOURCC_DXT1 = 0x31545844; public const uint FOURCC_DXT2 = 0x32545844; public const uint FOURCC_DXT3 = 0x33545844; public const uint FOURCC_DXT4 = 0x34545844; public const uint FOURCC_DXT5 = 0x35545844; public const uint FOURCC_ATI1 = 0x31495441; public const uint FOURCC_ATI2 = 0x32495441; public const uint FOURCC_RXGB = 0x42475852; public const uint FOURCC_DOLLARNULL = 0x24; public const uint FOURCC_oNULL = 0x6f; public const uint FOURCC_pNULL = 0x70; public const uint FOURCC_qNULL = 0x71; public const uint FOURCC_rNULL = 0x72; public const uint FOURCC_sNULL = 0x73; public const uint FOURCC_tNULL = 0x74; #endregion Constants internal static uint PixelFormatToBpp(PixelFormat pf, uint rgbbitcount) { switch (pf) { case PixelFormat.LUMINANCE: case PixelFormat.LUMINANCE_ALPHA: case PixelFormat.RGBA: case PixelFormat.RGB: return rgbbitcount / 8; case PixelFormat.THREEDC: case PixelFormat.RXGB: return 3; case PixelFormat.ATI1N: return 1; case PixelFormat.R16F: return 2; case PixelFormat.A16B16G16R16: case PixelFormat.A16B16G16R16F: case PixelFormat.G32R32F: return 8; case PixelFormat.A32B32G32R32F: return 16; default: return 4; } } internal static uint PixelFormatToBpc(PixelFormat pf) { switch (pf) { case PixelFormat.R16F: case PixelFormat.G16R16F: case PixelFormat.A16B16G16R16F: return 4; case PixelFormat.R32F: case PixelFormat.G32R32F: case PixelFormat.A32B32G32R32F: return 4; case PixelFormat.A16B16G16R16: return 2; default: return 1; } } internal static bool Check16BitComponents(DDSStruct header) { if (header.pixelformat.rgbbitcount != 32) return false; if (header.pixelformat.rbitmask == 0x3FF00000 && header.pixelformat.gbitmask == 0x000FFC00 && header.pixelformat.bbitmask == 0x000003FF && header.pixelformat.alphabitmask == 0xC0000000) return true; else if (header.pixelformat.rbitmask == 0x000003FF && header.pixelformat.gbitmask == 0x000FFC00 && header.pixelformat.bbitmask == 0x3FF00000 && header.pixelformat.alphabitmask == 0xC0000000) return true; return false; } internal static void CorrectPremult(uint pixnum, ref byte[] buffer) { for (uint i = 0; i < pixnum; i++) { byte alpha = buffer[i + 3]; if (alpha == 0) continue; int red = (buffer[i] << 8) / alpha; int green = (buffer[i + 1] << 8) / alpha; int blue = (buffer[i + 2] << 8) / alpha; buffer[i] = (byte)red; buffer[i + 1] = (byte)green; buffer[i + 2] = (byte)blue; } } internal static void ComputeMaskParams(uint mask, ref int shift1, ref int mul, ref int shift2) { shift1 = 0; mul = 1; shift2 = 0; if (mask == 0 || mask == uint.MaxValue) return; while ((mask & 1) == 0) { mask >>= 1; shift1++; } uint bc = 0; while ((mask & (1 << (int)bc)) != 0) bc++; while ((mask * mul) < 255) mul = (mul << (int)bc) + 1; mask *= (uint)mul; while ((mask & ~0xff) != 0) { mask >>= 1; shift2++; } } internal static unsafe void DxtcReadColors(byte* data, ref Colour8888[] op) { byte r0, g0, b0, r1, g1, b1; b0 = (byte)(data[0] & 0x1F); g0 = (byte)(((data[0] & 0xE0) >> 5) | ((data[1] & 0x7) << 3)); r0 = (byte)((data[1] & 0xF8) >> 3); b1 = (byte)(data[2] & 0x1F); g1 = (byte)(((data[2] & 0xE0) >> 5) | ((data[3] & 0x7) << 3)); r1 = (byte)((data[3] & 0xF8) >> 3); op[0].red = (byte)(r0 << 3 | r0 >> 2); op[0].green = (byte)(g0 << 2 | g0 >> 3); op[0].blue = (byte)(b0 << 3 | b0 >> 2); op[1].red = (byte)(r1 << 3 | r1 >> 2); op[1].green = (byte)(g1 << 2 | g1 >> 3); op[1].blue = (byte)(b1 << 3 | b1 >> 2); } internal static void DxtcReadColor(ushort data, ref Colour8888 op) { byte r, g, b; b = (byte)(data & 0x1f); g = (byte)((data & 0x7E0) >> 5); r = (byte)((data & 0xF800) >> 11); op.red = (byte)(r << 3 | r >> 2); op.green = (byte)(g << 2 | g >> 3); op.blue = (byte)(b << 3 | r >> 2); } internal static unsafe void DxtcReadColors(byte* data, ref Colour565 color_0, ref Colour565 color_1) { color_0.blue = (byte)(data[0] & 0x1F); color_0.green = (byte)(((data[0] & 0xE0) >> 5) | ((data[1] & 0x7) << 3)); color_0.red = (byte)((data[1] & 0xF8) >> 3); color_0.blue = (byte)(data[2] & 0x1F); color_0.green = (byte)(((data[2] & 0xE0) >> 5) | ((data[3] & 0x7) << 3)); color_0.red = (byte)((data[3] & 0xF8) >> 3); } internal static void GetBitsFromMask(uint mask, ref uint shiftLeft, ref uint shiftRight) { uint temp, i; if (mask == 0) { shiftLeft = shiftRight = 0; return; } temp = mask; for (i = 0; i < 32; i++, temp >>= 1) { if ((temp & 1) != 0) break; } shiftRight = i; for (i = 0; i < 8; i++, temp >>= 1) { if ((temp & 1) == 0) break; } shiftLeft = 8 - i; } internal static uint CountBitsFromMask(uint mask) { uint i, testBit = 0x01, count = 0; bool foundBit = false; for (i = 0; i < 32; i++, testBit <<= 1) { if ((mask & testBit) != 0) { if (!foundBit) foundBit = true; count++; } else if (foundBit) return count; } return count; } internal static uint HalfToFloat(ushort y) { int s = (y >> 15) & 0x00000001; int e = (y >> 10) & 0x0000001f; int m = y & 0x000003ff; if (e == 0) { if (m == 0) { return (uint)(s << 31); } else { while ((m & 0x00000400) == 0) { m <<= 1; e -= 1; } e += 1; m &= ~0x00000400; } } else if (e == 31) { if (m == 0) { return (uint)((s << 31) | 0x7f800000); } else { return (uint)((s << 31) | 0x7f800000 | (m << 13)); } } e = e + (127 - 15); m = m << 13; return (uint)((s << 31) | (e << 23) | m); } internal static unsafe void ConvFloat16ToFloat32(uint* dest, ushort* src, uint size) { uint i; for (i = 0; i < size; ++i, ++dest, ++src) { *dest = HalfToFloat(*src); } } internal static unsafe void ConvG16R16ToFloat32(uint* dest, ushort* src, uint size) { uint i; for (i = 0; i < size; i += 3) { *dest++ = HalfToFloat(*src++); *dest++ = HalfToFloat(*src++); *((float*)dest++) = 1.0f; } } internal static unsafe void ConvR16ToFloat32(uint* dest, ushort* src, uint size) { uint i; for (i = 0; i < size; i += 3) { *dest++ = HalfToFloat(*src++); *((float*)dest++) = 1.0f; *((float*)dest++) = 1.0f; } } } [StructLayout(LayoutKind.Sequential)] public struct Colour8888 { public byte red; public byte green; public byte blue; public byte alpha; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct Colour565 { public ushort blue; public ushort green; public ushort red; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct DDSStruct { public uint size; public uint flags; public uint height; public uint width; public uint sizeorpitch; public uint depth; public uint mipmapcount; public uint alphabitdepth; public uint[] reserved; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct pixelformatstruct { public uint size; public uint flags; public uint fourcc; public uint rgbbitcount; public uint rbitmask; public uint gbitmask; public uint bbitmask; public uint alphabitmask; } public pixelformatstruct pixelformat; [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct ddscapsstruct { public uint caps1; public uint caps2; public uint caps3; public uint caps4; } public ddscapsstruct ddscaps; public uint texturestage; } public enum PixelFormat { RGBA, RGB, DXT1, DXT2, DXT3, DXT4, DXT5, THREEDC, ATI1N, LUMINANCE, LUMINANCE_ALPHA, RXGB, A16B16G16R16, R16F, G16R16F, A16B16G16R16F, R32F, G32R32F, A32B32G32R32F, UNKNOWN } public class TestHelper { public static int[] ComputeMaskParams(uint mask) { int rShift1 = 0; int rMul = 0; int rShift2 = 0; Helper.ComputeMaskParams(mask, ref rShift1, ref rMul, ref rShift2); return new int[] { rShift1, rMul, rShift2 }; } } }