public static void ExportDDS(Texture2D texture, Stream destination, Stream source, long length) { DDSContainerParameters @params = new DDSContainerParameters() { DataLength = length, MipMapCount = texture.MipCount, Width = texture.Width, Height = texture.Height, IsPitchOrLinearSize = texture.DDSIsPitchOrLinearSize(), PixelFormatFlags = texture.DDSPixelFormatFlags(), FourCC = (DDSFourCCType)texture.DDSFourCC(), RGBBitCount = texture.DDSRGBBitCount(), RBitMask = texture.DDSRBitMask(), GBitMask = texture.DDSGBitMask(), BBitMask = texture.DDSBBitMask(), ABitMask = texture.DDSABitMask(), Caps = texture.DDSCaps(), }; EndianType endianess = Texture2D.IsSwapBytes(texture.File.Platform, texture.TextureFormat) ? EndianType.BigEndian : EndianType.LittleEndian; using (EndianReader sourceReader = new EndianReader(source, endianess)) { DDSContainer.ExportDDS(sourceReader, destination, @params); } }
public static void DecompressRGB(Stream source, Stream destination, DDSContainerParameters @params) { using (BinaryReader reader = new BinaryReader(source)) { DecompressRGBA(reader, destination, @params, false); } }
public static void DecompressDXT1(Stream source, Stream destination, DDSContainerParameters @params) { using (BinaryReader sourceReader = new BinaryReader(source)) { DecompressDXT1(sourceReader, destination, @params); } }
public static long GetDecompressedSize(DDSContainerParameters @params) { int width = @params.Width; int height = @params.Height; int depth = @params.BitMapDepth; int bpp = GetRGBABytesPerPixel(@params); int bpc = GetBytesPerColor(@params); int bps = width * bpp * bpc; long sizeOfPlane = bps * height; return(depth * sizeOfPlane + height * bps + width * bpp); }
public void CopyTo(DDSContainerParameters dest) { dest.DataLength = DataLength; dest.MipMapCount = MipMapCount; dest.Width = Width; dest.Height = Height; dest.IsPitchOrLinearSize = IsPitchOrLinearSize; dest.PixelFormatFlags = PixelFormatFlags; dest.FourCC = FourCC; dest.RGBBitCount = RGBBitCount; dest.RBitMask = RBitMask; dest.GBitMask = GBitMask; dest.BBitMask = BBitMask; dest.ABitMask = ABitMask; dest.Caps = Caps; }
private static int GetBytesPerPixel(DDSContainerParameters @params) { if (@params.PixelFormatFlags.IsFourCC()) { switch (@params.FourCC) { case DDSFourCCType.DXT1: case DDSFourCCType.DXT2: case DDSFourCCType.DXT3: case DDSFourCCType.DXT4: case DDSFourCCType.DXT5: return(4); case DDSFourCCType.ATI1: return(1); case DDSFourCCType.ATI2: case DDSFourCCType.RXGB: return(3); case DDSFourCCType.oNULL: return(2); case DDSFourCCType.DollarNULL: case DDSFourCCType.qNULL: case DDSFourCCType.sNULL: return(8); case DDSFourCCType.tNULL: return(16); case DDSFourCCType.pNULL: case DDSFourCCType.rNULL: return(4); default: throw new Exception($"Unsupported CCType {@params.FourCC}"); } } else { return(@params.RGBBitCount / 8); } }
public static Bitmap DDSTextureToBitmap(Texture2D texture, byte[] data) { DDSContainerParameters @params = new DDSContainerParameters() { DataLength = data.LongLength, MipMapCount = texture.MipCount, Width = texture.Width, Height = texture.Height, IsPitchOrLinearSize = texture.DDSIsPitchOrLinearSize(), PixelFormatFlags = texture.DDSPixelFormatFlags(), FourCC = (DDSFourCCType)texture.DDSFourCC(), RGBBitCount = texture.DDSRGBBitCount(), RBitMask = texture.DDSRBitMask(), GBitMask = texture.DDSGBitMask(), BBitMask = texture.DDSBBitMask(), ABitMask = texture.DDSABitMask(), Caps = texture.DDSCaps(), }; int width = @params.Width; int height = @params.Height; int size = width * height * 4; byte[] buffer = new byte[size]; using (MemoryStream destination = new MemoryStream(buffer)) { using (MemoryStream source = new MemoryStream(data)) { EndianType endianess = Texture2D.IsSwapBytes(texture.File.Platform, texture.TextureFormat) ? EndianType.BigEndian : EndianType.LittleEndian; using (EndianReader sourceReader = new EndianReader(source, endianess)) { DecompressDDS(sourceReader, destination, @params); } } Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); Rectangle rect = new Rectangle(0, 0, width, height); BitmapData bitData = bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); IntPtr pointer = bitData.Scan0; Marshal.Copy(buffer, 0, pointer, size); bitmap.UnlockBits(bitData); return(bitmap); } }
public static DirectBitmap DDSTextureToBitmap(Texture2D texture, byte[] data) { DDSContainerParameters @params = new DDSContainerParameters() { DataLength = data.LongLength, MipMapCount = texture.MipCount, Width = texture.Width, Height = texture.Height, IsPitchOrLinearSize = texture.DDSIsPitchOrLinearSize(), PixelFormatFlags = texture.DDSPixelFormatFlags(), FourCC = (DDSFourCCType)texture.DDSFourCC(), RGBBitCount = texture.DDSRGBBitCount(), RBitMask = texture.DDSRBitMask(), GBitMask = texture.DDSGBitMask(), BBitMask = texture.DDSBBitMask(), ABitMask = texture.DDSABitMask(), Caps = texture.DDSCaps(), }; int width = @params.Width; int height = @params.Height; DirectBitmap bitmap = new DirectBitmap(width, height); try { using (MemoryStream destination = new MemoryStream(bitmap.Bits)) { using (MemoryStream source = new MemoryStream(data)) { using (EndianReader sourceReader = new EndianReader(source)) { DecompressDDS(sourceReader, destination, @params); } } return(bitmap); } } catch { bitmap.Dispose(); throw; } }
private static void DecompressDDS(BinaryReader reader, Stream destination, DDSContainerParameters @params) { if (@params.PixelFormatFlags.IsFourCC()) { switch (@params.FourCC) { case DDSFourCCType.DXT1: DDSDecompressor.DecompressDXT1(reader, destination, @params); break; case DDSFourCCType.DXT3: DDSDecompressor.DecompressDXT3(reader, destination, @params); break; case DDSFourCCType.DXT5: DDSDecompressor.DecompressDXT5(reader, destination, @params); break; default: throw new NotImplementedException(@params.FourCC.ToString()); } } else { if (@params.PixelFormatFlags.IsLuminace()) { throw new NotSupportedException("Luminace isn't supported"); } else { if (@params.PixelFormatFlags.IsAlphaPixels()) { DDSDecompressor.DecompressRGBA(reader, destination, @params); } else { DDSDecompressor.DecompressRGB(reader, destination, @params); } } } }
private static int GetRGBABytesPerPixel(DDSContainerParameters @params) { if (@params.PixelFormatFlags.IsFourCC()) { switch (@params.FourCC) { case DDSFourCCType.DXT1: case DDSFourCCType.DXT2: case DDSFourCCType.DXT3: case DDSFourCCType.DXT4: case DDSFourCCType.DXT5: return(4); default: throw new Exception($"Unsupported CCType {@params.FourCC}"); } } else { return(4); } }
public static void DecompressDXT1(BinaryReader sourceReader, Stream destination, DDSContainerParameters @params) { int depth = @params.BitMapDepth; int width = @params.Width; int height = @params.Height; int bpp = GetRGBABytesPerPixel(@params); int bpc = GetBytesPerColor(@params); int bps = width * bpp * bpc; long sizeOfPlane = bps * height; Color8888[] colors = new Color8888[4]; long position = destination.Position; for (int z = 0; z < depth; z++) { // mirror Y for (int y = height - 1; y >= 0; y -= 4) { for (int x = 0; x < width; x += 4) { ushort color0 = sourceReader.ReadUInt16(); ushort color1 = sourceReader.ReadUInt16(); uint bitMask0 = sourceReader.ReadUInt16(); uint bitMask1 = sourceReader.ReadUInt16(); uint bitMask = (bitMask0 << 0) | (bitMask1 << 16); colors[0] = DxtcRead3bColor(color0); colors[1] = DxtcRead3bColor(color1); if (color0 > color1) { // 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. colors[2].Blue = unchecked ((byte)((2 * colors[0].Blue + colors[1].Blue + 1) / 3)); colors[2].Green = unchecked ((byte)((2 * colors[0].Green + colors[1].Green + 1) / 3)); colors[2].Red = unchecked ((byte)((2 * colors[0].Red + colors[1].Red + 1) / 3)); colors[2].Alpha = 0xFF; colors[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. colors[2].Blue = unchecked ((byte)((colors[0].Blue + colors[1].Blue) / 2)); colors[2].Green = unchecked ((byte)((colors[0].Green + colors[1].Green) / 2)); colors[2].Red = unchecked ((byte)((colors[0].Red + colors[1].Red) / 2)); colors[2].Alpha = 0xFF; colors[3].Alpha = 0x0; } colors[3].Blue = unchecked ((byte)((colors[0].Blue + 2 * colors[1].Blue + 1) / 3)); colors[3].Green = unchecked ((byte)((colors[0].Green + 2 * colors[1].Green + 1) / 3)); colors[3].Red = unchecked ((byte)((colors[0].Red + 2 * colors[1].Red + 1) / 3)); int bitIndex = 0; for (int ly = 0; ly < 4; ly++) { for (int lx = 0; lx < 4; lx++, bitIndex++) { int colorIndex = unchecked ((int)((bitMask & (3 << bitIndex * 2)) >> bitIndex * 2)); Color8888 color = colors[colorIndex]; if ((x + lx) < width && (y - ly) < height && (y - ly) >= 0) { // mirror Y long offset = z * sizeOfPlane + (y - ly) * bps + (x + lx) * bpp; destination.Position = position + offset; destination.WriteByte(color.Red); destination.WriteByte(color.Green); destination.WriteByte(color.Blue); destination.WriteByte(color.Alpha); } } } } } } }
private static void DecompressRGBA(BinaryReader sourceReader, Stream destination, DDSContainerParameters @params, bool isAlpha) { int depth = @params.BitMapDepth; int width = @params.Width; int height = @params.Height; int bpp = GetRGBABytesPerPixel(@params); int bpc = GetBytesPerColor(@params); int bps = width * bpp * bpc; long sizeOfPlane = bps * height; int pixelSize = (@params.RGBBitCount + 7) / 8; ColorMask rMask = ComputeMaskParams(@params.RBitMask); ColorMask gMask = ComputeMaskParams(@params.GBitMask); ColorMask bMask = ComputeMaskParams(@params.BBitMask); ColorMask aMask = ComputeMaskParams(@params.ABitMask); long position = destination.Position; for (int z = 0; z < depth; z++) { // mirror Y for (int j = height - 1; j >= 0; j--) { long offset = z * sizeOfPlane + j * bps; destination.Position = position + offset; for (int i = 0; i < width; i++) { uint pixel = ReadPixel(sourceReader, pixelSize); uint pixelColor = pixel & @params.RBitMask; byte red = unchecked ((byte)(((pixelColor >> rMask.Shift1) * rMask.Mult) >> rMask.Shift2)); pixelColor = pixel & @params.GBitMask; byte green = unchecked ((byte)(((pixelColor >> gMask.Shift1) * gMask.Mult) >> gMask.Shift2)); pixelColor = pixel & @params.BBitMask; byte blue = unchecked ((byte)(((pixelColor >> bMask.Shift1) * bMask.Mult) >> bMask.Shift2)); byte alpha = 0xFF; if (isAlpha) { pixelColor = pixel & @params.ABitMask; alpha = unchecked ((byte)(((pixelColor >> aMask.Shift1) * aMask.Mult) >> aMask.Shift2)); } destination.WriteByte(blue); destination.WriteByte(green); destination.WriteByte(red); destination.WriteByte(alpha); } } } }
public static void DecompressRGBA(BinaryReader sourceReader, Stream destination, DDSContainerParameters @params) { DecompressRGBA(sourceReader, destination, @params, true); }
public static void DecompressDXT5(BinaryReader sourceReader, Stream destination, DDSContainerParameters @params) { int depth = @params.BitMapDepth; int width = @params.Width; int height = @params.Height; int bpp = GetRGBABytesPerPixel(@params); int bpc = GetBytesPerColor(@params); int bps = width * bpp * bpc; long sizeOfPlane = bps * height; Color8888[] colors = new Color8888[4]; ushort[] alphas = new ushort[8]; byte[] alphaMask = new byte[6]; long position = destination.Position; for (int z = 0; z < depth; z++) { // mirror Y for (int y = height - 1; y >= 0; y -= 4) { for (int x = 0; x < width; x += 4) { ushort alpha = sourceReader.ReadUInt16(); alphas[0] = unchecked ((byte)(alpha >> 0)); alphas[1] = unchecked ((byte)(alpha >> 8)); ushort alphaMask0 = sourceReader.ReadUInt16(); ushort alphaMask1 = sourceReader.ReadUInt16(); ushort alphaMask2 = sourceReader.ReadUInt16(); alphaMask[0] = unchecked ((byte)(alphaMask0 >> 0)); alphaMask[1] = unchecked ((byte)(alphaMask0 >> 8)); alphaMask[2] = unchecked ((byte)(alphaMask1 >> 0)); alphaMask[3] = unchecked ((byte)(alphaMask1 >> 8)); alphaMask[4] = unchecked ((byte)(alphaMask2 >> 0)); alphaMask[5] = unchecked ((byte)(alphaMask2 >> 8)); colors[0] = DxtcRead2bColor(sourceReader); colors[1] = DxtcRead2bColor(sourceReader); uint bitMask0 = sourceReader.ReadUInt16(); uint bitMask1 = sourceReader.ReadUInt16(); uint bitMask = (bitMask0 << 0) | (bitMask1 << 16); // 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. colors[2].Blue = unchecked ((byte)((2 * colors[0].Blue + colors[1].Blue + 1) / 3)); colors[2].Green = unchecked ((byte)((2 * colors[0].Green + colors[1].Green + 1) / 3)); colors[2].Red = unchecked ((byte)((2 * colors[0].Red + colors[1].Red + 1) / 3)); colors[3].Blue = unchecked ((byte)((colors[0].Blue + 2 * colors[1].Blue + 1) / 3)); colors[3].Green = unchecked ((byte)((colors[0].Green + 2 * colors[1].Green + 1) / 3)); colors[3].Red = unchecked ((byte)((colors[0].Red + 2 * colors[1].Red + 1) / 3)); int bitIndex = 0; for (int ly = 0; ly < 4; ly++) { for (int lx = 0; lx < 4; lx++, bitIndex++) { int colorIndex = (int)((bitMask & (0x03 << bitIndex * 2)) >> bitIndex * 2); Color8888 col = colors[colorIndex]; // only put pixels out < width or height if ((x + lx) < width && (y - ly) < height && (y - ly) >= 0) { // mirror Y long offset = z * sizeOfPlane + (y - ly) * bps + (x + lx) * bpp; destination.Position = position + offset; destination.WriteByte(col.Red); destination.WriteByte(col.Green); destination.WriteByte(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] = unchecked ((ushort)((6 * alphas[0] + 1 * alphas[1] + 3) / 7)); // bit code 010 alphas[3] = unchecked ((ushort)((5 * alphas[0] + 2 * alphas[1] + 3) / 7)); // bit code 011 alphas[4] = unchecked ((ushort)((4 * alphas[0] + 3 * alphas[1] + 3) / 7)); // bit code 100 alphas[5] = unchecked ((ushort)((3 * alphas[0] + 4 * alphas[1] + 3) / 7)); // bit code 101 alphas[6] = unchecked ((ushort)((2 * alphas[0] + 5 * alphas[1] + 3) / 7)); // bit code 110 alphas[7] = unchecked ((ushort)((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] = unchecked ((ushort)((4 * alphas[0] + 1 * alphas[1] + 2) / 5)); // Bit code 010 alphas[3] = unchecked ((ushort)((3 * alphas[0] + 2 * alphas[1] + 2) / 5)); // Bit code 011 alphas[4] = unchecked ((ushort)((2 * alphas[0] + 3 * alphas[1] + 2) / 5)); // Bit code 100 alphas[5] = unchecked ((ushort)((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[0]); uint bits = unchecked ((uint)((alphaMask[0]) | (alphaMask[1] << 8) | (alphaMask[2] << 16))); for (int ly = 0; ly < 2; ly++) { for (int lx = 0; lx < 4; lx++, bits >>= 3) { // only put pixels out < width or height if ((x + lx) < width && (y - ly) < height && (y - ly) >= 0) { byte alphaValue = unchecked ((byte)alphas[bits & 0x07]); // mirror Y long offset = z * sizeOfPlane + (y - ly) * bps + (x + lx) * bpp + 3; destination.Position = position + offset; destination.WriteByte(alphaValue); } } } // Last three bytes //bits = (uint)(alphamask[3]); bits = unchecked ((uint)((alphaMask[3]) | (alphaMask[4] << 8) | (alphaMask[5] << 16))); for (int ly = 2; ly < 4; ly++) { for (int lx = 0; lx < 4; lx++, bits >>= 3) { // only put pixels out < width or height if ((x + lx) < width && (y - ly) < height && (y - ly) >= 0) { byte alphaValue = unchecked ((byte)alphas[bits & 0x07]); // mirror Y long offset = z * sizeOfPlane + (y - ly) * bps + (x + lx) * bpp + 3; destination.Position = position + offset; destination.WriteByte(alphaValue); } } } } } } }