public DDSImage(CR2WBinaryReader reader, DDSStruct header, bool alpha) { Utils.PixelFormat pixelFormat = Utils.PixelFormat.UNKNOWN; byte[] data = null; if (header.depth == 0) { header.depth = 1; } _isValid = true; _alpha = alpha; uint blocksize = 0; pixelFormat = GetFormat(header, ref blocksize); if (pixelFormat == Utils.PixelFormat.UNKNOWN) { throw new InvalidFileHeaderException(); } data = ReadData(reader, header); if (data != null) { byte[] rawData = DDSDecompressor.Expand(header, data, pixelFormat); _bitmap = CreateBitmap((int)header.width, (int)header.height, rawData); } }
/// <summary> /// Checks for the most common issues and provides an easier to read error message /// </summary> /// <param name="structA"></param> /// <param name="structB"></param> private void handleKnownDDSFields(DDSStruct structA, DDSStruct structB) { var errors = new List <string>(); // If any dw flag is four CC, try to be more precise string formatA = structA.Header.ddspf.dwFlags == DDSPixelFormat.EPixelFlags.DDPF_FOURCC ? structA.Header.ddspf.dwFourCCString.ToString() : structA.Header.ddspf.dwFlags.ToString(); string formatB = structB.Header.ddspf.dwFlags == DDSPixelFormat.EPixelFlags.DDPF_FOURCC ? structB.Header.ddspf.dwFourCCString.ToString() : structB.Header.ddspf.dwFlags.ToString(); if (formatA != formatB) { errors.Add($"Format different: {formatA} not equal to {formatB}"); } if (structA.Header.DwMipMapCount != structB.Header.DwMipMapCount) { errors.Add($"Mips different: {structA.Header.DwMipMapCount} not equal to {structB.Header.DwMipMapCount}"); } if (errors.Any()) { throw new Exception($"Differences found:{Environment.NewLine}{string.Join(Environment.NewLine, errors)}"); } }
public override void ParseBytes(CR2WBinaryReader br, uint size) { base.ParseClass(br, this); var zero = br.ReadUInt32(); var mipCount = br.ReadUInt32(); var width = br.ReadUInt32(); var height = br.ReadUInt32(); var unknown5 = br.ReadUInt32(); var sizeorpitch = br.ReadUInt32(); //var unknown7 = br.ReadUInt32(); Console.WriteLine("zero {0}", zero); Console.WriteLine("mipCount {0}", mipCount); Console.WriteLine("width {0}", width); Console.WriteLine("height {0}", height); Console.WriteLine("unknown5 {0}", unknown5); Console.WriteLine("sizeorpitch {0}", sizeorpitch); //Console.WriteLine("unknown7 {0}", sizeorpitch); var ddsheader = new DDSStruct { size = 124, flags = 659463, width = width, height = height, sizeorpitch = sizeorpitch, depth = 1, mipmapcount = 1, reserved = new uint[10], }; ddsheader.ddscaps.caps1 = 4096; ddsheader.pixelformat.size = 32; ddsheader.pixelformat.flags = 5; ddsheader.pixelformat.fourcc = DDSHelper.FOURCC_DXT1; var dds = new DDSImage(br, ddsheader, true); Form form = new Form { Text = LinkageName, ClientSize = new Size((int)width, (int)height), }; PictureBox pictureBox = new PictureBox { Image = dds.BitmapImage, Width = (int)width, Height = (int)height }; form.Controls.Add(pictureBox); var t = new Task(() => { Application.Run(form); }); t.Start(); }
private byte[] ReadData(BinaryReader reader, DDSStruct header) { byte[] compdata = null; uint compsize = 0; if ((header.flags & Helper.DDSD_LINEARSIZE) > 1) { compdata = reader.ReadBytes((int)header.sizeorpitch); compsize = (uint)compdata.Length; } else { uint bps = header.width * header.pixelformat.rgbbitcount / 8; compsize = bps * header.height * header.depth; compdata = new byte[compsize]; MemoryStream mem = new MemoryStream((int)compsize); byte[] temp; for (int z = 0; z < header.depth; z++) { for (int y = 0; y < header.height; y++) { temp = reader.ReadBytes((int)bps); mem.Write(temp, 0, temp.Length); } } mem.Seek(0, SeekOrigin.Begin); mem.Read(compdata, 0, compdata.Length); mem.Close(); } return(compdata); }
public static byte[] DecompressLum(DDSStruct header, byte[] data, PixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * 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; ComputeMaskParams(header.pixelformat.rbitmask, ref lShift1, ref lMul, ref lShift2); int offset = 0; int pixnum = width * height * depth; int temp = 0; while (pixnum-- > 0) { byte px = data[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); }
public static void PrintHeader(DDSStruct header) { Console.WriteLine("header."); Console.WriteLine("\tsize {0}", header.size); Console.WriteLine("\tflags {0}", header.flags); Console.WriteLine("\twidth {0}", header.width); Console.WriteLine("\theight {0}", header.height); Console.WriteLine("\tsizeorpitch {0}", header.sizeorpitch); Console.WriteLine("\tdepth {0}", header.depth); Console.WriteLine("\tmipmapcount {0}", header.mipmapcount); Console.WriteLine("\talphabitdepth {0}", header.alphabitdepth); for (int i = 0; i < header.reserved.Length; i++) { Console.WriteLine("\treserved[{0}] {1}", i, header.reserved[i]); } Console.WriteLine("header.pixelformat"); Console.WriteLine("\tsize {0}", header.pixelformat.size); Console.WriteLine("\tflags {0}", header.pixelformat.flags); Console.WriteLine("\tfourcc {0}", header.pixelformat.fourcc); Console.WriteLine("\trgbbitcount {0}", header.pixelformat.rgbbitcount); Console.WriteLine("\trbitmask {0}", header.pixelformat.rbitmask); Console.WriteLine("\tgbitmask {0}", header.pixelformat.gbitmask); Console.WriteLine("\tbbitmask {0}", header.pixelformat.bbitmask); Console.WriteLine("\talphabitmask {0}", header.pixelformat.alphabitmask); Console.WriteLine("header.ddscaps"); Console.WriteLine("\tcaps1 {0}", header.ddscaps.caps1); Console.WriteLine("\tcaps2 {0}", header.ddscaps.caps2); Console.WriteLine("\tcaps3 {0}", header.ddscaps.caps3); Console.WriteLine("\tcaps4 {0}", header.ddscaps.caps4); Console.WriteLine(); }
private void Parse(BinaryReader reader) { DDSStruct header = new DDSStruct(); Utils.PixelFormat pixelFormat = Utils.PixelFormat.UNKNOWN; byte[] data = null; if (ReadHeader(reader, ref header)) { _isValid = true; // patches for stuff if (header.depth == 0) { header.depth = 1; } uint blocksize = 0; pixelFormat = GetFormat(header, ref blocksize); if (pixelFormat == Utils.PixelFormat.UNKNOWN) { throw new InvalidFileHeaderException(); } data = ReadData(reader, header); if (data != null) { byte[] rawData = Decompressor.Expand(header, data, pixelFormat); _bitmap = CreateBitmap((int)header.width, (int)header.height, rawData); } } }
public static DDSStruct Create(BinaryReader reader) { DDSStruct header = new DDSStruct(); if (ReadHeader(reader, ref header)) { return(header); } throw new System.Exception("DDS header is invalid."); }
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); }
private bool ReadHeader(BinaryReader reader, ref DDSStruct header) { byte[] signature = reader.ReadBytes(4); if (!(signature[0] == 'D' && signature[1] == 'D' && signature[2] == 'S' && signature[3] == ' ')) { return(false); } header.size = reader.ReadUInt32(); if (header.size != 124) { return(false); } //convert the data header.flags = reader.ReadUInt32(); header.height = reader.ReadUInt32(); header.width = reader.ReadUInt32(); header.sizeorpitch = reader.ReadUInt32(); header.depth = reader.ReadUInt32(); header.mipmapcount = reader.ReadUInt32(); header.alphabitdepth = reader.ReadUInt32(); header.reserved = new uint[10]; for (int i = 0; i < 10; i++) { header.reserved[i] = reader.ReadUInt32(); } //pixelfromat header.pixelformat.size = reader.ReadUInt32(); header.pixelformat.flags = reader.ReadUInt32(); header.pixelformat.fourcc = reader.ReadUInt32(); header.pixelformat.rgbbitcount = reader.ReadUInt32(); header.pixelformat.rbitmask = reader.ReadUInt32(); header.pixelformat.gbitmask = reader.ReadUInt32(); header.pixelformat.bbitmask = reader.ReadUInt32(); header.pixelformat.alphabitmask = reader.ReadUInt32(); //caps header.ddscaps.caps1 = reader.ReadUInt32(); header.ddscaps.caps2 = reader.ReadUInt32(); header.ddscaps.caps3 = reader.ReadUInt32(); header.ddscaps.caps4 = reader.ReadUInt32(); header.texturestage = reader.ReadUInt32(); PrintHeader(header); return(true); }
private static SurfaceFormat GetSurfaceFormat(ref DDSStruct header) { uint blockSize = 0; PixelFormat format = GetFormatInternal(ref header, ref blockSize); switch (format) { case PixelFormat.DXT1: return(SurfaceFormat.Dxt1); case PixelFormat.DXT5: return(SurfaceFormat.Dxt5); default: throw new System.Exception("Unsupported format."); } }
public static byte[] DecompressRGB(DDSStruct header, byte[] data, PixelFormat pixelFormat) { // allocate bitmap int bpp = (int)(PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * 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); uint pixSize = (uint)(((int)header.pixelformat.rgbbitcount + 7) / 8); int rShift1 = 0; int rMul = 0; int rShift2 = 0; ComputeMaskParams(header.pixelformat.rbitmask, ref rShift1, ref rMul, ref rShift2); int gShift1 = 0; int gMul = 0; int gShift2 = 0; ComputeMaskParams(header.pixelformat.gbitmask, ref gShift1, ref gMul, ref gShift2); int bShift1 = 0; int bMul = 0; int bShift2 = 0; ComputeMaskParams(header.pixelformat.bbitmask, ref bShift1, ref bMul, ref bShift2); int offset = 0; int pixnum = width * height * depth; int temp = 0; while (pixnum-- > 0) { uint px = BitConverter.ToUInt32(data, temp) & valMask; temp += (int)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); rawData[offset + 3] = 0xff; offset += 4; } return(rawData); }
internal static bool Check16BitComponents(DDSStruct header) { if (header.pixelformat.rgbbitcount != 32) { return(false); } // a2b10g10r10 format if (header.pixelformat.rbitmask == 0x3FF00000 && header.pixelformat.gbitmask == 0x000FFC00 && header.pixelformat.bbitmask == 0x000003FF && header.pixelformat.alphabitmask == 0xC0000000) { return(true); } // a2r10g10b10 format else if (header.pixelformat.rbitmask == 0x000003FF && header.pixelformat.gbitmask == 0x000FFC00 && header.pixelformat.bbitmask == 0x3FF00000 && header.pixelformat.alphabitmask == 0xC0000000) { return(true); } return(false); }
private void Parse() { var idString = new byte[4]; m_stream.Read(idString, 0, 4); var signature = BitConverter.ToUInt32(idString, 0); if (signature != MAGIC) { throw new InvalidFileHeaderException(); } m_header = ReadHeader(); m_isValid = true; if (m_header.depth == 0) { m_header.depth = 1; } uint blocksize = 0; var pixelFormat = GetFormat(ref blocksize); if (pixelFormat == Utils.DDSPixelFormat.UNKNOWN) { throw new InvalidFileHeaderException(); } var data = ReadData(); if (data == null) { throw new InvalidDataException(); } byte[] rawData = DDSDecompressor.Expand(m_header, data, pixelFormat); m_bitmap = CreateBitmap((int)m_header.width, (int)m_header.height, rawData); }
protected override bool LoadFile(GraphicsDevice gfxDevice, BinaryReader reader, ref SEFileHeader header, out object obj) { if (gfxDevice == null) { throw new HeadlessNotSupportedException($"Texture '{reader}' was not loaded in headless display mode."); } Texture2D tex; if (header.OriginalExtension == ".dds") { DDSStruct ddsHeader = DDSStruct.Create(reader); tex = new Texture2D(gfxDevice, (int)ddsHeader.width, (int)ddsHeader.height, false, ddsHeader.GetSurfaceFormat()); byte[] textureData = reader.ReadBytes((int)header.FileSize); tex.SetData(textureData, 0, textureData.Length); } else { tex = Texture2D.FromStream(gfxDevice, reader.BaseStream); } obj = tex; return(true); }
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[] 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); }
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[] 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); }
public static byte[] DecompressDXT5(DDSStruct header, byte[] data, PixelFormat pixelFormat = PixelFormat.DXT5) { // allocate bitmap int bpp = (int)(PixelFormatToBpp(pixelFormat, header.pixelformat.rgbbitcount)); int bps = (int)(header.width * bpp * 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]; Colour8888[] colours = new Colour8888[4]; ushort[] alphas = new ushort[8]; int temp = 0; 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] = data[temp + 0]; alphas[1] = data[temp + 1]; int alphamask = (temp + 2); temp += 8; DxtcReadColors(data, temp, ref colours); uint bitmask = BitConverter.ToUInt32(data, temp + 4); temp += 8; // 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; k++, i++) { 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] = 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] = (ushort)((6 * alphas[0] + 1 * alphas[1] + 3) / 7); // bit code 010 alphas[3] = (ushort)((5 * alphas[0] + 2 * alphas[1] + 3) / 7); // bit code 011 alphas[4] = (ushort)((4 * alphas[0] + 3 * alphas[1] + 3) / 7); // bit code 100 alphas[5] = (ushort)((3 * alphas[0] + 4 * alphas[1] + 3) / 7); // bit code 101 alphas[6] = (ushort)((2 * alphas[0] + 5 * alphas[1] + 3) / 7); // bit code 110 alphas[7] = (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] = (ushort)((4 * alphas[0] + 1 * alphas[1] + 2) / 5); // Bit code 010 alphas[3] = (ushort)((3 * alphas[0] + 2 * alphas[1] + 2) / 5); // Bit code 011 alphas[4] = (ushort)((2 * alphas[0] + 3 * alphas[1] + 2) / 5); // Bit code 100 alphas[5] = (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 = (uint)((data[alphamask + 0]) | (data[alphamask + 1] << 8) | (data[alphamask + 2] << 16)); 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] = (byte)alphas[bits & 0x07]; } bits >>= 3; } } // Last three bytes //bits = (uint)(alphamask[3]); bits = (uint)((data[alphamask + 3]) | (data[alphamask + 4] << 8) | (data[alphamask + 5] << 16)); 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] = (byte)alphas[bits & 0x07]; } bits >>= 3; } } } } } 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[] 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 Utils.PixelFormat GetFormat(DDSStruct header, ref uint blocksize) { Utils.PixelFormat format = Utils.PixelFormat.UNKNOWN; if ((header.pixelformat.flags & Helper.DDPF_FOURCC) == Helper.DDPF_FOURCC) { blocksize = ((header.width + 3) / 4) * ((header.height + 3) / 4) * header.depth; switch (header.pixelformat.fourcc) { case Helper.FOURCC_DXT1: format = Utils.PixelFormat.DXT1; blocksize *= 8; break; case Helper.FOURCC_DXT2: format = Utils.PixelFormat.DXT2; blocksize *= 16; break; case Helper.FOURCC_DXT3: format = Utils.PixelFormat.DXT3; blocksize *= 16; break; case Helper.FOURCC_DXT4: format = Utils.PixelFormat.DXT4; blocksize *= 16; break; case Helper.FOURCC_DXT5: format = Utils.PixelFormat.DXT5; blocksize *= 16; break; case Helper.FOURCC_ATI1: format = Utils.PixelFormat.ATI1N; blocksize *= 8; break; case Helper.FOURCC_ATI2: format = Utils.PixelFormat.THREEDC; blocksize *= 16; break; case Helper.FOURCC_RXGB: format = Utils.PixelFormat.RXGB; blocksize *= 16; break; case Helper.FOURCC_DOLLARNULL: format = Utils.PixelFormat.A16B16G16R16; blocksize = header.width * header.height * header.depth * 8; break; case Helper.FOURCC_oNULL: format = Utils.PixelFormat.R16F; blocksize = header.width * header.height * header.depth * 2; break; case Helper.FOURCC_pNULL: format = Utils.PixelFormat.G16R16F; blocksize = header.width * header.height * header.depth * 4; break; case Helper.FOURCC_qNULL: format = Utils.PixelFormat.A16B16G16R16F; blocksize = header.width * header.height * header.depth * 8; break; case Helper.FOURCC_rNULL: format = Utils.PixelFormat.R32F; blocksize = header.width * header.height * header.depth * 4; break; case Helper.FOURCC_sNULL: format = Utils.PixelFormat.G32R32F; blocksize = header.width * header.height * header.depth * 8; break; case Helper.FOURCC_tNULL: format = Utils.PixelFormat.A32B32G32R32F; blocksize = header.width * header.height * header.depth * 16; break; default: format = Utils.PixelFormat.UNKNOWN; blocksize *= 16; break; } } else { // uncompressed image if ((header.pixelformat.flags & Helper.DDPF_LUMINANCE) == Helper.DDPF_LUMINANCE) { if ((header.pixelformat.flags & Helper.DDPF_ALPHAPIXELS) == Helper.DDPF_ALPHAPIXELS) { format = Utils.PixelFormat.LUMINANCE_ALPHA; } else { format = Utils.PixelFormat.LUMINANCE; } } else { if ((header.pixelformat.flags & Helper.DDPF_ALPHAPIXELS) == Helper.DDPF_ALPHAPIXELS) { format = Utils.PixelFormat.RGBA; } else { format = Utils.PixelFormat.RGB; } } blocksize = (header.width * header.height * header.depth * (header.pixelformat.rgbbitcount >> 3)); } return(format); }
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); }
public override void ParseBytes(CR2WBinaryReader br, uint size) { base.ParseBytes(br, size); /* * This is a temporary solution for reading the contents of a CBitmapTexture * What this does is contruct a dds header object and parse it and the raw bytes * using the dds library. * * The bitmap bytes from the cr2w has a header 28 bytes long, containing data about the * image such as size and height etc... * There are 4 unknown ones. * * This class should in the end support reading all xbm files with means supporting not just * dds but tga, bmp, png, and jpg. * */ var zero = br.ReadUInt32(); var mipCount = br.ReadUInt32(); var width = br.ReadUInt32(); var height = br.ReadUInt32(); var unknown5 = br.ReadUInt32(); var sizeorpitch = br.ReadUInt32(); Console.WriteLine("zero {0}", zero); Console.WriteLine("mipCount {0}", mipCount); Console.WriteLine("width {0}", width); Console.WriteLine("height {0}", height); Console.WriteLine("unknown5 {0}", unknown5); Console.WriteLine("sizeorpitch {0}", sizeorpitch); var ddsheader = new DDSStruct { size = 124, flags = 659463, width = width, height = height, sizeorpitch = sizeorpitch, depth = 1, mipmapcount = 1, reserved = new uint[10], }; ddsheader.ddscaps.caps1 = 4096; ddsheader.pixelformat.size = 32; ddsheader.pixelformat.flags = 5; ddsheader.pixelformat.fourcc = DDSHelper.FOURCC_DXT1; var dds = new DDSImage(br, ddsheader, true); Form form = new Form { Text = "Image", ClientSize = new Size((int)width, (int)height), }; PictureBox pictureBox = new PictureBox { Image = dds.BitmapImage, Width = (int)width, Height = (int)height }; form.Controls.Add(pictureBox); var t = new Task(() => { Application.Run(form); }); t.Start(); }