public DDSHeader CreateHeader(int pixelWidth, int pixelHeight, uint fourCC) { if (pixelHeight < 0 || pixelWidth < 0) { throw new InvalidOperationException("Image width or height is negative."); } var pixelFormat = new DDSPixelFormat { Size = 32, Flags = 0x4, FourCC = fourCC }; var header = new DDSHeader { Size = 124, // has to be 124bytes ¯\_(ツ)_/¯ Flags = Helpers.DDSMinFlags(), Height = (uint)pixelHeight, Width = (uint)pixelWidth, PixelFormat = pixelFormat, MipMapCount = 0, Caps = 0x1000 // texture, we don't handle harder things right now }; header.PitchOrLinearSize = Math.Max(1, (header.Width + 3) / 4) * Math.Max(1, (header.Height + 3) / 4) * 8; return(header); }
internal static DDSHeader Read(BinaryReader br) { var h = new DDSHeader(); h.size = br.ReadInt32(); h.flags = br.ReadInt32(); h.height = br.ReadInt32(); h.width = br.ReadInt32(); h.sizeOrPitch = br.ReadInt32(); h.depth = br.ReadInt32(); h.mipMapCount = br.ReadInt32(); h.reserved1 = new int[11]; for (var i = 0; i < 11; ++i) { h.reserved1[i] = br.ReadInt32(); } h.pixelFormat = DDSPixelFormat.Read(br); h.caps = DDSCaps.Read(br); h.reserved2 = br.ReadInt32(); return(h); }
// iCompFormatToBpp internal static uint PixelFormatToBpp(DDSPixelFormat pf, uint rgbbitcount) { switch (pf) { case DDSPixelFormat.LUMINANCE: case DDSPixelFormat.LUMINANCE_ALPHA: case DDSPixelFormat.RGBA: case DDSPixelFormat.RGB: return(rgbbitcount / 8); case DDSPixelFormat.THREEDC: case DDSPixelFormat.RXGB: return(3); case DDSPixelFormat.ATI1N: return(1); case DDSPixelFormat.R16F: return(2); case DDSPixelFormat.A16B16G16R16: case DDSPixelFormat.A16B16G16R16F: case DDSPixelFormat.G32R32F: return(8); case DDSPixelFormat.A32B32G32R32F: return(16); default: return(4); } }
public static TextureFormat GetTextureFormat(DDSPixelFormat pixelFormat) { switch (pixelFormat.FourCC) { case DDSPixelFormatFourCC.R8G8B8: return(TextureFormat.RGB); case DDSPixelFormatFourCC.A8R8G8B8: return(TextureFormat.RGBA); case DDSPixelFormatFourCC.A4R4G4B4: return(TextureFormat.RGBA4); case DDSPixelFormatFourCC.DXT1: return(TextureFormat.DXT1); case DDSPixelFormatFourCC.DXT3: return(TextureFormat.DXT3); case DDSPixelFormatFourCC.DXT4: return(TextureFormat.DXT4); case DDSPixelFormatFourCC.DXT5: return(TextureFormat.DXT5); case DDSPixelFormatFourCC.ATI1: return(TextureFormat.ATI1); case DDSPixelFormatFourCC.ATI2N_3Dc: return(TextureFormat.ATI2); default: throw new ArgumentException(nameof(pixelFormat)); } }
private void SetPixelFormatData(int pixelFormatID) { ddsPF = new DDSPixelFormat(); ddsPF.caps2 = 0; ddsPF.dwSize = 32; ddsPF.dwFlags = 4; ddsPF.dwFourCC = 0x31545844; ddsPF.dwRGBBitCount = 0; ddsPF.dwRBitMask = 0; ddsPF.dwGBitMask = 0; ddsPF.dwBBitMask = 0; ddsPF.dwABitMask = 0; if (PixelFormatTypes.ContainsKey(pixelFormatID)) { ddsPF.dwFourCC = PixelFormatTypes[pixelFormatID]; if (pixelFormatID == 0x01) { ddsPF.dwFlags |= 0x01; } } else { switch (pixelFormatID) { case 0x0B: case 0x36: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x20; ddsPF.dwRBitMask = 0xFF; ddsPF.dwGBitMask = 0xFF00; ddsPF.dwBBitMask = 0xFF0000; ddsPF.dwABitMask = 0xFF000000; ddsPF.dwFlags = 0x41; if (pixelFormatID == 0x36) { ddsPF.caps2 = 0xFE00; } break; case 0x0C: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x08; ddsPF.dwABitMask = 0xFF; ddsPF.dwFlags = 0x02; break; case 0x0D: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x10; ddsPF.dwRBitMask = 0xFFFF; ddsPF.dwFlags = 0x20000; break; } } }
private static unsafe byte[] DecompressRGBA(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; uint valMask = (uint)((header.pixelformat.rgbbitcount == 32) ? ~0 : (1 << (int)header.pixelformat.rgbbitcount) - 1); // Funny x86s, make 1 << 32 == 1 uint pixSize = (header.pixelformat.rgbbitcount + 7) / 8; int rShift1 = 0; int rMul = 0; int rShift2 = 0; DDSHelper.ComputeMaskParams(header.pixelformat.rbitmask, ref rShift1, ref rMul, ref rShift2); int gShift1 = 0; int gMul = 0; int gShift2 = 0; DDSHelper.ComputeMaskParams(header.pixelformat.gbitmask, ref gShift1, ref gMul, ref gShift2); int bShift1 = 0; int bMul = 0; int bShift2 = 0; DDSHelper.ComputeMaskParams(header.pixelformat.bbitmask, ref bShift1, ref bMul, ref bShift2); int aShift1 = 0; int aMul = 0; int aShift2 = 0; DDSHelper.ComputeMaskParams(header.pixelformat.alphabitmask, ref aShift1, ref aMul, ref aShift2); int offset = 0; int pixnum = width * height * depth; fixed(byte *bytePtr = data) { byte *temp = bytePtr; while (pixnum-- > 0) { uint px = *((uint *)temp) & valMask; temp += pixSize; uint pxc = px & header.pixelformat.rbitmask; rawData[offset + 0] = (byte)(((pxc >> rShift1) * rMul) >> rShift2); pxc = px & header.pixelformat.gbitmask; rawData[offset + 1] = (byte)(((pxc >> gShift1) * gMul) >> gShift2); pxc = px & header.pixelformat.bbitmask; rawData[offset + 2] = (byte)(((pxc >> bShift1) * bMul) >> bShift2); pxc = px & header.pixelformat.alphabitmask; rawData[offset + 3] = (byte)(((pxc >> aShift1) * aMul) >> aShift2); offset += 4; } } return(rawData); }
private static byte[] DecompressDXT4(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; // Can do color & alpha same as dxt5, but color is pre-multiplied // so the result will be wrong unless corrected. byte[] rawData = DecompressDXT5(header, data, pixelFormat); DDSHelper.CorrectPremult((uint)(width * height * depth), ref rawData); return(rawData); }
public void CreateFileHeaderForBC1() { var expectedFlags = DDSFileHeaderFlags.DDSD_CAPS | DDSFileHeaderFlags.DDSD_HEIGHT | DDSFileHeaderFlags.DDSD_WIDTH | DDSFileHeaderFlags.DDSD_PIXELFORMAT; var expectedPixelFormat = new DDSPixelFormat { Size = 32, Flags = DDSPixelFormatFlags.DDPF_FOURCC, FourCC = FourCC.BC1Unorm.Value }; var header = DDSFileWriter.CreateHeader(1024, 512, FourCC.BC1Unorm.Value); Assert.AreEqual(124, header.Size); Assert.AreEqual(expectedFlags, header.Flags); Assert.AreEqual(512, header.Height); Assert.AreEqual(1024, header.Width); Assert.AreEqual(0, header.PitchOrLinearSize); Assert.AreEqual(0, header.Depth); Assert.AreEqual(0, header.MipMapCount); unsafe { Assert.AreEqual(0, header.Reserved1[0]); Assert.AreEqual(0, header.Reserved1[1]); Assert.AreEqual(0, header.Reserved1[2]); Assert.AreEqual(0, header.Reserved1[3]); Assert.AreEqual(0, header.Reserved1[4]); Assert.AreEqual(0, header.Reserved1[5]); Assert.AreEqual(0, header.Reserved1[6]); Assert.AreEqual(0, header.Reserved1[7]); Assert.AreEqual(0, header.Reserved1[8]); Assert.AreEqual(0, header.Reserved1[9]); Assert.AreEqual(0, header.Reserved1[10]); } Assert.AreEqual(DDSCapsFlags.DDSCAPS_TEXTURE, header.Caps); Assert.AreEqual(0, header.Caps2); Assert.AreEqual(0, header.Caps3); Assert.AreEqual(0, header.Caps4); Assert.AreEqual(0, header.Reserved2); Assert.AreEqual(expectedPixelFormat.Size, header.PixelFormat.Size); Assert.AreEqual(expectedPixelFormat.Flags, header.PixelFormat.Flags); Assert.AreEqual(expectedPixelFormat.FourCC, header.PixelFormat.FourCC); Assert.AreEqual(0, header.PixelFormat.RGBBitCount); Assert.AreEqual(0, header.PixelFormat.RBitMask); Assert.AreEqual(0, header.PixelFormat.GBitMask); Assert.AreEqual(0, header.PixelFormat.BBitMask); Assert.AreEqual(0, header.PixelFormat.ABitMask); }
internal static DDSPixelFormat Read(BinaryReader br) { var pf = new DDSPixelFormat(); pf.size = br.ReadInt32(); pf.flags = br.ReadInt32(); pf.fourCC = br.ReadInt32(); pf.rgbBits = br.ReadInt32(); pf.redMask = br.ReadInt32(); pf.greenMask = br.ReadInt32(); pf.blueMask = br.ReadInt32(); pf.alphaMask = br.ReadInt32(); return(pf); }
internal static DDSPixelFormat Read( BinaryReader br ) { var pf = new DDSPixelFormat(); pf.size = br.ReadInt32(); pf.flags = br.ReadInt32(); pf.fourCC = br.ReadInt32(); pf.rgbBits = br.ReadInt32(); pf.redMask = br.ReadInt32(); pf.greenMask = br.ReadInt32(); pf.blueMask = br.ReadInt32(); pf.alphaMask = br.ReadInt32(); return pf; }
public static DDSPixelFormat ToPixelFormat(this TextureType T) { DDSPixelFormat ret = new DDSPixelFormat { size = 32, flags = 4, fourCC = (uint)T, bitCount = 32, redMask = 0x0000FF00, greenMask = 0x00FF0000, blueMask = 0xFF000000, alphaMask = 0x000000FF }; if (T == TextureType.ATI2) { ret.flags |= 0x80000000; } return(ret); }
// iCompFormatToBpc internal static uint PixelFormatToBpc(DDSPixelFormat pf) { switch (pf) { case DDSPixelFormat.R16F: case DDSPixelFormat.G16R16F: case DDSPixelFormat.A16B16G16R16F: return(4); case DDSPixelFormat.R32F: case DDSPixelFormat.G32R32F: case DDSPixelFormat.A32B32G32R32F: return(4); case DDSPixelFormat.A16B16G16R16: return(2); default: return(1); } }
private static unsafe byte[] DecompressLum(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; int lShift1 = 0; int lMul = 0; int lShift2 = 0; DDSHelper.ComputeMaskParams(header.pixelformat.rbitmask, ref lShift1, ref lMul, ref lShift2); int offset = 0; int pixnum = width * height * depth; fixed(byte *bytePtr = data) { byte *temp = bytePtr; while (pixnum-- > 0) { byte px = *(temp++); rawData[offset + 0] = (byte)(((px >> lShift1) * lMul) >> lShift2); rawData[offset + 1] = (byte)(((px >> lShift1) * lMul) >> lShift2); rawData[offset + 2] = (byte)(((px >> lShift1) * lMul) >> lShift2); rawData[offset + 3] = (byte)(((px >> lShift1) * lMul) >> lShift2); offset += 4; } } return(rawData); }
/// <summary> /// Creates a DDS file header data structure with a single RGB surface. /// </summary> /// <param name="pixelWidth">The width of the DDS image described by this header.</param> /// <param name="pixelHeight">The height of the DDS image described by this header.</param> /// <param name="fourCC">The four-character code which specifies the BCn compression format.</param> public static DDSFileHeader CreateHeader(int pixelWidth, int pixelHeight, uint fourCC) { if (pixelHeight < 0 || pixelWidth < 0) { throw new ArgumentException("Received negative image dimension."); } var pixelFormat = new DDSPixelFormat(); pixelFormat.Size = 32; pixelFormat.Flags = DDSPixelFormatFlags.DDPF_FOURCC; pixelFormat.FourCC = fourCC; var header = new DDSFileHeader(); header.Size = 124; header.Flags = MinimumRequiredFlags(); header.Height = (uint)pixelHeight; header.Width = (uint)pixelWidth; header.PixelFormat = pixelFormat; header.Caps = DDSCapsFlags.DDSCAPS_TEXTURE; return(header); }
private static unsafe byte[] DecompressFloat(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; int size = 0; fixed(byte *bytePtr = data) { byte *temp = bytePtr; fixed(byte *destPtr = rawData) { byte *destData = destPtr; switch (pixelFormat) { case DDSPixelFormat.R32F: // Red float, green = blue = max size = width * height * depth * 3; for (int i = 0, j = 0; i < size; i += 3, j++) { ((float *)destData)[i] = ((float *)temp)[j]; ((float *)destData)[i + 1] = 1.0f; ((float *)destData)[i + 2] = 1.0f; } break; case DDSPixelFormat.A32B32G32R32F: // Direct copy of float RGBA data Array.Copy(data, rawData, data.Length); break; case DDSPixelFormat.G32R32F: // Red float, green float, blue = max size = width * height * depth * 3; for (int i = 0, j = 0; i < size; i += 3, j += 2) { ((float *)destData)[i] = ((float *)temp)[j]; ((float *)destData)[i + 1] = ((float *)temp)[j + 1]; ((float *)destData)[i + 2] = 1.0f; } break; case DDSPixelFormat.R16F: // Red float, green = blue = max size = width * height * depth * bpp; DDSHelper.ConvR16ToFloat32((uint *)destData, (ushort *)temp, (uint)size); break; case DDSPixelFormat.A16B16G16R16F: // Just convert from half to float. size = width * height * depth * bpp; DDSHelper.ConvFloat16ToFloat32((uint *)destData, (ushort *)temp, (uint)size); break; case DDSPixelFormat.G16R16F: // Convert from half to float, set blue = max. size = width * height * depth * bpp; DDSHelper.ConvG16R16ToFloat32((uint *)destData, (ushort *)temp, (uint)size); break; default: break; } } } return(rawData); }
internal static byte[] Expand(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { System.Diagnostics.Debug.WriteLine(pixelFormat); // allocate bitmap byte[] rawData = null; switch (pixelFormat) { case DDSPixelFormat.RGBA: rawData = DecompressRGBA(header, data, pixelFormat); break; case DDSPixelFormat.RGB: rawData = DecompressRGB(header, data, pixelFormat); break; case DDSPixelFormat.LUMINANCE: case DDSPixelFormat.LUMINANCE_ALPHA: rawData = DecompressLum(header, data, pixelFormat); break; case DDSPixelFormat.DXT1: rawData = DecompressDXT1(header, data, pixelFormat); break; case DDSPixelFormat.DXT2: rawData = DecompressDXT2(header, data, pixelFormat); break; case DDSPixelFormat.DXT3: rawData = DecompressDXT3(header, data, pixelFormat); break; case DDSPixelFormat.DXT4: rawData = DecompressDXT4(header, data, pixelFormat); break; case DDSPixelFormat.DXT5: rawData = DecompressDXT5(header, data, pixelFormat); break; case DDSPixelFormat.THREEDC: rawData = Decompress3Dc(header, data, pixelFormat); break; case DDSPixelFormat.ATI1N: rawData = DecompressAti1n(header, data, pixelFormat); break; case DDSPixelFormat.RXGB: rawData = DecompressRXGB(header, data, pixelFormat); break; case DDSPixelFormat.R16F: case DDSPixelFormat.G16R16F: case DDSPixelFormat.A16B16G16R16F: case DDSPixelFormat.R32F: case DDSPixelFormat.G32R32F: case DDSPixelFormat.A32B32G32R32F: rawData = DecompressFloat(header, data, pixelFormat); break; default: throw new UnknownFileFormatException(); } return(rawData); }
private static unsafe byte[] DecompressRXGB(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; Colour565 color_0 = new Colour565(); Colour565 color_1 = new Colour565(); Colour8888[] colours = new Colour8888[4]; byte[] alphas = new byte[8]; fixed(byte *bytePtr = data) { byte *temp = bytePtr; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { if (y >= height || x >= width) { break; } alphas[0] = temp[0]; alphas[1] = temp[1]; byte *alphamask = temp + 2; temp += 8; DDSHelper.DxtcReadColors(temp, ref color_0, ref color_1); temp += 4; uint bitmask = ((uint *)temp)[1]; temp += 4; colours[0].red = (byte)(color_0.red << 3); colours[0].green = (byte)(color_0.green << 2); colours[0].blue = (byte)(color_0.blue << 3); colours[0].alpha = 0xFF; colours[1].red = (byte)(color_1.red << 3); colours[1].green = (byte)(color_1.green << 2); colours[1].blue = (byte)(color_1.blue << 3); colours[1].alpha = 0xFF; // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These 2-bit codes correspond to the 2-bit fields // stored in the 64-bit block. colours[2].blue = (byte)((2 * colours[0].blue + colours[1].blue + 1) / 3); colours[2].green = (byte)((2 * colours[0].green + colours[1].green + 1) / 3); colours[2].red = (byte)((2 * colours[0].red + colours[1].red + 1) / 3); colours[2].alpha = 0xFF; colours[3].blue = (byte)((colours[0].blue + 2 * colours[1].blue + 1) / 3); colours[3].green = (byte)((colours[0].green + 2 * colours[1].green + 1) / 3); colours[3].red = (byte)((colours[0].red + 2 * colours[1].red + 1) / 3); colours[3].alpha = 0xFF; int k = 0; for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++, k++) { int select = (int)((bitmask & (0x03 << k * 2)) >> k * 2); Colour8888 col = colours[select]; // only put pixels out < width or height if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp); rawData[offset + 0] = col.red; rawData[offset + 1] = col.green; rawData[offset + 2] = col.blue; } } } // 8-alpha or 6-alpha block? if (alphas[0] > alphas[1]) { // 8-alpha block: derive the other six alphas. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. alphas[2] = (byte)((6 * alphas[0] + 1 * alphas[1] + 3) / 7); // bit code 010 alphas[3] = (byte)((5 * alphas[0] + 2 * alphas[1] + 3) / 7); // bit code 011 alphas[4] = (byte)((4 * alphas[0] + 3 * alphas[1] + 3) / 7); // bit code 100 alphas[5] = (byte)((3 * alphas[0] + 4 * alphas[1] + 3) / 7); // bit code 101 alphas[6] = (byte)((2 * alphas[0] + 5 * alphas[1] + 3) / 7); // bit code 110 alphas[7] = (byte)((1 * alphas[0] + 6 * alphas[1] + 3) / 7); // bit code 111 } else { // 6-alpha block. // Bit code 000 = alpha_0, 001 = alpha_1, others are interpolated. alphas[2] = (byte)((4 * alphas[0] + 1 * alphas[1] + 2) / 5); // Bit code 010 alphas[3] = (byte)((3 * alphas[0] + 2 * alphas[1] + 2) / 5); // Bit code 011 alphas[4] = (byte)((2 * alphas[0] + 3 * alphas[1] + 2) / 5); // Bit code 100 alphas[5] = (byte)((1 * alphas[0] + 4 * alphas[1] + 2) / 5); // Bit code 101 alphas[6] = 0x00; // Bit code 110 alphas[7] = 0xFF; // Bit code 111 } // Note: Have to separate the next two loops, // it operates on a 6-byte system. // First three bytes uint bits = *((uint *)alphamask); for (int j = 0; j < 2; j++) { for (int i = 0; i < 4; i++) { // only put pixels out < width or height if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3); rawData[offset] = alphas[bits & 0x07]; } bits >>= 3; } } // Last three bytes bits = *((uint *)&alphamask[3]); for (int j = 2; j < 4; j++) { for (int i = 0; i < 4; i++) { // only put pixels out < width or height if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3); rawData[offset] = alphas[bits & 0x07]; } bits >>= 3; } } } } } } return(rawData); }
private static unsafe byte[] DecompressDXT1(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; // DXT1 decompressor byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; Colour8888[] colours = new Colour8888[4]; colours[0].alpha = 0xFF; colours[1].alpha = 0xFF; colours[2].alpha = 0xFF; fixed(byte *bytePtr = data) { byte *temp = bytePtr; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { ushort colour0 = *((ushort *)temp); ushort colour1 = *((ushort *)(temp + 2)); DDSHelper.DxtcReadColor(colour0, ref colours[0]); DDSHelper.DxtcReadColor(colour1, ref colours[1]); uint bitmask = ((uint *)temp)[1]; temp += 8; if (colour0 > colour1) { // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These 2-bit codes correspond to the 2-bit fields // stored in the 64-bit block. colours[2].blue = (byte)((2 * colours[0].blue + colours[1].blue + 1) / 3); colours[2].green = (byte)((2 * colours[0].green + colours[1].green + 1) / 3); colours[2].red = (byte)((2 * colours[0].red + colours[1].red + 1) / 3); //colours[2].alpha = 0xFF; colours[3].blue = (byte)((colours[0].blue + 2 * colours[1].blue + 1) / 3); colours[3].green = (byte)((colours[0].green + 2 * colours[1].green + 1) / 3); colours[3].red = (byte)((colours[0].red + 2 * colours[1].red + 1) / 3); colours[3].alpha = 0xFF; } else { // Three-color block: derive the other color. // 00 = color_0, 01 = color_1, 10 = color_2, // 11 = transparent. // These 2-bit codes correspond to the 2-bit fields // stored in the 64-bit block. colours[2].blue = (byte)((colours[0].blue + colours[1].blue) / 2); colours[2].green = (byte)((colours[0].green + colours[1].green) / 2); colours[2].red = (byte)((colours[0].red + colours[1].red) / 2); //colours[2].alpha = 0xFF; colours[3].blue = (byte)((colours[0].blue + 2 * colours[1].blue + 1) / 3); colours[3].green = (byte)((colours[0].green + 2 * colours[1].green + 1) / 3); colours[3].red = (byte)((colours[0].red + 2 * colours[1].red + 1) / 3); colours[3].alpha = 0x00; } for (int j = 0, k = 0; j < 4; j++) { for (int i = 0; i < 4; i++, k++) { int select = (int)((bitmask & (0x03 << k * 2)) >> k * 2); Colour8888 col = colours[select]; if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp); rawData[offset + 0] = (byte)col.red; rawData[offset + 1] = (byte)col.green; rawData[offset + 2] = (byte)col.blue; rawData[offset + 3] = (byte)col.alpha; } } } } } } } return(rawData); }
private static unsafe byte[] DecompressAti1n(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; byte[] colours = new byte[8]; uint offset = 0; fixed(byte *bytePtr = data) { byte *temp = bytePtr; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { //Read palette int t1 = colours[0] = temp[0]; int t2 = colours[1] = temp[1]; temp += 2; if (t1 > t2) { for (int i = 2; i < 8; ++i) { colours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 7); } } else { for (int i = 2; i < 6; ++i) { colours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 5); } colours[6] = 0; colours[7] = 255; } //decompress pixel data uint currOffset = offset; for (int k = 0; k < 4; k += 2) { // First three bytes uint bitmask = ((uint)(temp[0]) << 0) | ((uint)(temp[1]) << 8) | ((uint)(temp[2]) << 16); for (int j = 0; j < 2; j++) { // only put pixels out < height if ((y + k + j) < height) { for (int i = 0; i < 4; i++) { // only put pixels out < width if (((x + i) < width)) { t1 = (int)(currOffset + (x + i)); rawData[t1] = colours[bitmask & 0x07]; } bitmask >>= 3; } currOffset += (uint)bps; } } temp += 3; } } offset += (uint)(bps * 4); } } } return(rawData); }
public DDSHeader(BinaryReader br) { Size = br.ReadUInt32(); Flags = (DDSFlags)br.ReadUInt32(); Height = br.ReadUInt32(); Width = br.ReadUInt32(); PitchOrLinearSize = br.ReadUInt32(); Depth = br.ReadUInt32(); MipMapCount = br.ReadUInt32(); Reserved1 = new uint[11]; for (int i = 0; i < 11; i++) Reserved1[i] = br.ReadUInt32(); PixelFormat = new DDSPixelFormat(br); Caps = (DDSCaps)br.ReadUInt32(); Caps2 = (DDSCaps2)br.ReadUInt32(); Caps3 = br.ReadUInt32(); Caps4 = br.ReadUInt32(); Reserved2 = br.ReadUInt32(); }
private void SetPixelFormatData(int pixelFormatID) { ddsPF = new DDSPixelFormat(); ddsPF.caps2 = 0; ddsPF.dwSize = 32; ddsPF.dwFlags = 4; ddsPF.dwFourCC = 0x31545844; ddsPF.dwRGBBitCount = 0; ddsPF.dwRBitMask = 0; ddsPF.dwGBitMask = 0; ddsPF.dwBBitMask = 0; ddsPF.dwABitMask = 0; if (PixelFormatTypes.ContainsKey(pixelFormatID)) { ddsPF.dwFourCC = PixelFormatTypes[pixelFormatID]; if (pixelFormatID == 0x01) ddsPF.dwFlags |= 0x01; } else { switch (pixelFormatID) { case 0x0B: case 0x36: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x20; ddsPF.dwRBitMask = 0xFF; ddsPF.dwGBitMask = 0xFF00; ddsPF.dwBBitMask = 0xFF0000; ddsPF.dwABitMask = 0xFF000000; ddsPF.dwFlags = 0x41; if (pixelFormatID == 0x36) ddsPF.caps2 = 0xFE00; break; case 0x0C: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x08; ddsPF.dwABitMask = 0xFF; ddsPF.dwFlags = 0x02; break; case 0x0D: ddsPF.dwFourCC = 0x00; ddsPF.dwRGBBitCount = 0x10; ddsPF.dwRBitMask = 0xFFFF; ddsPF.dwFlags = 0x20000; break; } } }
private static unsafe byte[] DecompressDXT3(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; // DXT3 decompressor byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; Colour8888[] colours = new Colour8888[4]; fixed(byte *bytePtr = data) { byte *temp = bytePtr; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { byte *alpha = temp; temp += 8; DDSHelper.DxtcReadColors(temp, ref colours); temp += 4; uint bitmask = ((uint *)temp)[1]; temp += 4; // Four-color block: derive the other two colors. // 00 = color_0, 01 = color_1, 10 = color_2, 11 = color_3 // These 2-bit codes correspond to the 2-bit fields // stored in the 64-bit block. colours[2].blue = (byte)((2 * colours[0].blue + colours[1].blue + 1) / 3); colours[2].green = (byte)((2 * colours[0].green + colours[1].green + 1) / 3); colours[2].red = (byte)((2 * colours[0].red + colours[1].red + 1) / 3); //colours[2].alpha = 0xFF; colours[3].blue = (byte)((colours[0].blue + 2 * colours[1].blue + 1) / 3); colours[3].green = (byte)((colours[0].green + 2 * colours[1].green + 1) / 3); colours[3].red = (byte)((colours[0].red + 2 * colours[1].red + 1) / 3); //colours[3].alpha = 0xFF; for (int j = 0, k = 0; j < 4; j++) { for (int i = 0; i < 4; k++, i++) { int select = (int)((bitmask & (0x03 << k * 2)) >> k * 2); if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp); rawData[offset + 0] = (byte)colours[select].red; rawData[offset + 1] = (byte)colours[select].green; rawData[offset + 2] = (byte)colours[select].blue; } } } for (int j = 0; j < 4; j++) { //ushort word = (ushort)(alpha[2 * j] + 256 * alpha[2 * j + 1]); ushort word = (ushort)(alpha[2 * j] | (alpha[2 * j + 1] << 8)); for (int i = 0; i < 4; i++) { if (((x + i) < width) && ((y + j) < height)) { uint offset = (uint)(z * sizeofplane + (y + j) * bps + (x + i) * bpp + 3); rawData[offset] = (byte)(word & 0x0F); rawData[offset] = (byte)(rawData[offset] | (rawData[offset] << 4)); } word >>= 4; } } } } } } return(rawData); }
private static bool ValidateTexture(HeaderDXT10 header, HeaderFlags flags, out int depth, out PixelFormat format, out ResourceDimension resDim, out int arraySize, out bool isCubeMap) { depth = 0; format = Renderer.PixelFormat.Unknown; resDim = ResourceDimension.Unknown; arraySize = 0x1; isCubeMap = false; arraySize = header.ArraySize; if (arraySize == 0) { return(false); } if (header.MiscFlag2 != FlagsDX10.AlphaModeUnknown) { return(false); } if (DDSPixelFormat.BitsPerPixel(header.DXGIFormat) == 0) { return(false); } format = header.DXGIFormat; switch (header.Dimension) { case ResourceDimension.Texture1D: depth = 1; break; case ResourceDimension.Texture2D: if (header.MiscFlag.HasFlag(ResourceOptionFlags.TextureCube)) { arraySize *= 6; isCubeMap = true; } depth = 1; break; case ResourceDimension.Texture3D: if (!flags.HasFlag(HeaderFlags.Depth)) { return(false); } if (arraySize > 1) { return(false); } break; default: return(false); } resDim = header.Dimension; return(true); }
public DDSHeader() { PixelFormat = new DDSPixelFormat(); }
/// <summary> /// Constructs a new instance of DDS. /// </summary> /// <param name="reader">Reader to construct from.</param> public DDS( BinaryReader reader ) { // Magic number 'DDS ' if ( reader.ReadUInt32() != 0x20534444 ) throw new DDSException( "Invalid DDS magic number" ); if ( reader.ReadUInt32() != 124 ) throw new DDSException( "Invalid DDS_HEADER size" ); uint flags = reader.ReadUInt32(); _Height = reader.ReadInt32(); _Width = reader.ReadInt32(); reader.ReadUInt32(); _VolumeDepth = reader.ReadInt32(); _MipMapLevels = reader.ReadInt32(); // Skip reserved reader.BaseStream.Seek( sizeof( uint ) * 11, SeekOrigin.Current ); // Pixel format _Format = ReadPixelFormat( reader ); uint caps = reader.ReadUInt32(); if ( ( caps & 0x400000 ) > 0 ) _IsMipMap = true; uint caps2 = reader.ReadUInt32(); if ( ( caps2 & 0x200 ) > 0 ) _IsCubeMap = true; if ( ( caps2 & 0x200000 ) > 0 ) _IsVolumeMap = true; // Crap reader.ReadUInt32(); reader.ReadUInt32(); reader.ReadUInt32(); // Extended DX10 uint dxgiFormat = 0; uint dimension = 0; uint cubeFlags = 0; uint arraySize = 0; if ( _Format == DDSPixelFormat.DX10 ) { dxgiFormat = reader.ReadUInt32(); dimension = reader.ReadUInt32(); cubeFlags = reader.ReadUInt32(); arraySize = reader.ReadUInt32(); reader.ReadUInt32(); // crap throw new NotImplementedException(); } if ( _IsVolumeMap ) { _VolumeMaps = new List<VolumeMap>(); if ( _IsMipMap ) { int width = _Width; int height = _Height; int depth = _VolumeDepth; for ( int i = 0; i < _MipMapLevels; i++ ) { _VolumeMaps.Add( ReadVolumeMap( reader, width, height, depth ) ); width = Math.Max( 1, width / 2 ); height = Math.Max( 1, height / 2 ); depth = Math.Max( 1, depth / 2 ); } } else _VolumeMaps.Add( ReadVolumeMap( reader, _Width, _Height, _VolumeDepth ) ); } else if ( _IsCubeMap ) { if ( _IsMipMap ) { if ( ( caps2 & (uint) DDSCubeFace.PositiveX ) > 0 ) _PositiveX = ReadMipMaps( reader, _MipMapLevels ); if ( ( caps2 & (uint) DDSCubeFace.NegativeX ) > 0 ) _NegativeX = ReadMipMaps( reader, _MipMapLevels ); if ( ( caps2 & (uint) DDSCubeFace.PositiveY ) > 0 ) _PositiveY = ReadMipMaps( reader, _MipMapLevels ); if ( ( caps2 & (uint) DDSCubeFace.NegativeY ) > 0 ) _NegativeY = ReadMipMaps( reader, _MipMapLevels ); if ( ( caps2 & (uint) DDSCubeFace.PositiveZ ) > 0 ) _PositiveZ = ReadMipMaps( reader, _MipMapLevels ); if ( ( caps2 & (uint) DDSCubeFace.NegativeZ ) > 0 ) _NegativeZ = ReadMipMaps( reader, _MipMapLevels ); } else { if ( ( caps2 & (uint) DDSCubeFace.PositiveX ) > 0 ) _PositiveX = ReadTexture( reader ); if ( ( caps2 & (uint) DDSCubeFace.NegativeX ) > 0 ) _NegativeX = ReadTexture( reader ); if ( ( caps2 & (uint) DDSCubeFace.PositiveY ) > 0 ) _PositiveY = ReadTexture( reader ); if ( ( caps2 & (uint) DDSCubeFace.NegativeY ) > 0 ) _NegativeY = ReadTexture( reader ); if ( ( caps2 & (uint) DDSCubeFace.PositiveZ ) > 0 ) _PositiveZ = ReadTexture( reader ); if ( ( caps2 & (uint) DDSCubeFace.NegativeZ ) > 0 ) _NegativeZ = ReadTexture( reader ); } } else { if ( _IsMipMap ) _Texture = ReadMipMaps( reader, _MipMapLevels ); else _Texture = ReadTexture( reader ); } }
private static unsafe byte[] Decompress3Dc(DDSStruct header, byte[] data, DDSPixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(DDSHelper.PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * DDSHelper.PixelFormatToBpc(pixelFormat)); int sizeofplane = (int)(bps * header.height); int width = (int)header.width; int height = (int)header.height; int depth = (int)header.depth; byte[] rawData = new byte[depth * sizeofplane + height * bps + width * bpp]; byte[] yColours = new byte[8]; byte[] xColours = new byte[8]; int offset = 0; fixed(byte *bytePtr = data) { byte *temp = bytePtr; for (int z = 0; z < depth; z++) { for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { byte *temp2 = temp + 8; //Read Y palette int t1 = yColours[0] = temp[0]; int t2 = yColours[1] = temp[1]; temp += 2; if (t1 > t2) { for (int i = 2; i < 8; ++i) { yColours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 7); } } else { for (int i = 2; i < 6; ++i) { yColours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 5); } yColours[6] = 0; yColours[7] = 255; } // Read X palette t1 = xColours[0] = temp2[0]; t2 = xColours[1] = temp2[1]; temp2 += 2; if (t1 > t2) { for (int i = 2; i < 8; ++i) { xColours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 7); } } else { for (int i = 2; i < 6; ++i) { xColours[i] = (byte)(t1 + ((t2 - t1) * (i - 1)) / 5); } xColours[6] = 0; xColours[7] = 255; } //decompress pixel data int currentOffset = offset; for (int k = 0; k < 4; k += 2) { // First three bytes uint bitmask = ((uint)(temp[0]) << 0) | ((uint)(temp[1]) << 8) | ((uint)(temp[2]) << 16); uint bitmask2 = ((uint)(temp2[0]) << 0) | ((uint)(temp2[1]) << 8) | ((uint)(temp2[2]) << 16); for (int j = 0; j < 2; j++) { // only put pixels out < height if ((y + k + j) < height) { for (int i = 0; i < 4; i++) { // only put pixels out < width if (((x + i) < width)) { int t; byte tx, ty; t1 = currentOffset + (x + i) * 3; rawData[t1 + 1] = ty = yColours[bitmask & 0x07]; rawData[t1 + 0] = tx = xColours[bitmask2 & 0x07]; //calculate b (z) component ((r/255)^2 + (g/255)^2 + (b/255)^2 = 1 t = 127 * 128 - (tx - 127) * (tx - 128) - (ty - 127) * (ty - 128); if (t > 0) { rawData[t1 + 2] = (byte)(Math.Sqrt(t) + 128); } else { rawData[t1 + 2] = 0x7F; } } bitmask >>= 3; bitmask2 >>= 3; } currentOffset += bps; } } temp += 3; temp2 += 3; } //skip bytes that were read via Temp2 temp += 8; } offset += bps * 4; } } } return(rawData); }