private static byte[] DecompressDxt(EndianBinaryReader reader, DxtFormat format, int width, int height) { byte[] pixelData = new byte[width * height * 4]; for (int y = 0; y < height; y += 4) { for (int x = 0; x < width; x += 4) { byte[] decompressedBlock = DecompressDxtBlock(reader, format); for (int py = 0; py < 4; py++) { for (int px = 0; px < 4; px++) { int ix = (x + px); int iy = (y + py); if (ix >= width || iy >= height) { continue; } for (int c = 0; c < 4; c++) { pixelData[(((iy * width) + ix) * 4) + c] = decompressedBlock[(((py * 4) + px) * 4) + c]; } } } } } return(pixelData); }
public DXT(DxtFormat format) { BitDepth = (format == DxtFormat.DXT1) ? 4 : 8; BlockBitDepth = (format == DxtFormat.DXT1) ? 64 : 128; _format = format; FormatName = format.ToString(); }
private static byte[] DecompressDxtBlock(EndianBinaryReader reader, DxtFormat format) { byte[] outputData = new byte[(4 * 4) * 4]; byte[] colorData = null, alphaData = null; if (format != DxtFormat.DXT1) { alphaData = DecompressDxtAlpha(reader, format); } colorData = DecompressDxtColor(reader, format); for (int i = 0; i < colorData.Length; i += 4) { outputData[i] = colorData[i]; outputData[i + 1] = colorData[i + 1]; outputData[i + 2] = colorData[i + 2]; outputData[i + 3] = (alphaData != null ? alphaData[i + 3] : colorData[i + 3]); } return(outputData); }
public ColorFetcherDXT(Stream stream, long blockCount, DxtFormat format) { SourceStream = stream; BlockCount = blockCount; Format = format; }
public ColorFetcherDXT(Stream stream, long width, long height, DxtFormat format) { SourceStream = stream; BlockCount = ((width + 3) / 4) * ((height + 3) / 4); Format = format; }
public Encoder(DxtFormat format) { _queue = new List <Color>(); _format = format; }
private static Bitmap LoadDDS(EndianBinaryReader reader) { DDSHeader header = new DDSHeader(reader); Bitmap bitmap = new Bitmap((int)header.Width, (int)header.Height, PixelFormat.Format32bppArgb); byte[] pixelData = null; if (header.PixelFormat.Flags.HasFlag(DDPF.FourCC)) { DxtFormat dxtFormat = DxtFormat.DXT1; switch (header.PixelFormat.FourCC) { case "DXT1": dxtFormat = DxtFormat.DXT1; break; case "DXT3": dxtFormat = DxtFormat.DXT3; break; case "DXT5": dxtFormat = DxtFormat.DXT5; break; } pixelData = DecompressDxt(reader, dxtFormat, (int)header.Width, (int)header.Height); } else { // TODO: verify all of these, the non-32bit ones especially pixelData = new byte[(header.Width * header.Height) * 4]; int rawLength = (int)(header.Height * (((header.Width * header.PixelFormat.RGBBitCount) + 7) / 8)); if (header.PixelFormat.Flags.HasFlag(DDPF.RGB)) { switch (header.PixelFormat.RGBBitCount) { case 32: if (CheckBitmasks(header.PixelFormat, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000)) { // R8 G8 B8 A8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 4) { pixelData[i + 2] = reader.ReadByte(); pixelData[i + 1] = reader.ReadByte(); pixelData[i + 0] = reader.ReadByte(); pixelData[i + 3] = reader.ReadByte(); } } else if (CheckBitmasks(header.PixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000)) { // B8 G8 R8 A8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 4) { pixelData[i + 0] = reader.ReadByte(); pixelData[i + 1] = reader.ReadByte(); pixelData[i + 2] = reader.ReadByte(); pixelData[i + 3] = reader.ReadByte(); } } else if (CheckBitmasks(header.PixelFormat, 0x00FF0000, 0x0000FF00, 0x000000FF, 0x00000000)) { // B8 G8 R8 X8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 4) { pixelData[i + 0] = reader.ReadByte(); pixelData[i + 1] = reader.ReadByte(); pixelData[i + 2] = reader.ReadByte(); pixelData[i + 3] = 0xFF; reader.ReadByte(); // X } } else if (CheckBitmasks(header.PixelFormat, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)) { // X8 B8 G8 R8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 4) { reader.ReadByte(); // X pixelData[i + 0] = reader.ReadByte(); pixelData[i + 1] = reader.ReadByte(); pixelData[i + 2] = reader.ReadByte(); pixelData[i + 3] = 0xFF; } } break; case 24: if (CheckBitmasks(header.PixelFormat, 0x000000FF, 0x0000FF00, 0x00FF0000, 0x00000000)) { // R8 G8 B8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 3) { pixelData[i + 2] = reader.ReadByte(); pixelData[i + 1] = reader.ReadByte(); pixelData[i + 0] = reader.ReadByte(); pixelData[i + 3] = 0xFF; } } break; case 16: if (CheckBitmasks(header.PixelFormat, 0x7C00, 0x03E0, 0x001F, 0x8000)) { // B5 G5 R5 A1 } else if (CheckBitmasks(header.PixelFormat, 0xF800, 0x07E0, 0x001F, 0x0000)) { // B5 G6 R5 for (int i = 0, j = 0; j < rawLength; i += 4, j += 2) { UnpackRgb565(reader.ReadUInt16(), out byte r, out byte g, out byte b); pixelData[i + 0] = b; pixelData[i + 1] = g; pixelData[i + 2] = r; pixelData[i + 3] = 0xFF; } } else if (CheckBitmasks(header.PixelFormat, 0x0F00, 0x00F0, 0x000F, 0xF000)) { // B4 G4 R4 A4 for (int i = 0, j = 0; j < rawLength; i += 4, j += 2) { byte bg = reader.ReadByte(); byte ra = reader.ReadByte(); pixelData[i + 0] = (byte)((bg & 0xF0) | (bg & 0xF0) >> 4); pixelData[i + 1] = (byte)((bg & 0x0F) << 4 | (bg & 0x0F)); pixelData[i + 2] = (byte)((ra & 0xF0) | (ra & 0xF0) >> 4); pixelData[i + 3] = (byte)((ra & 0x0F) << 4 | (ra & 0x0F)); } } break; } } else if (header.PixelFormat.Flags.HasFlag(DDPF.Luminance)) { switch (header.PixelFormat.RGBBitCount) { case 16: if (CheckBitmasks(header.PixelFormat, 0x00FF, 0x0000, 0x0000, 0x00FF)) { // R8 G8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 2) { byte v = reader.ReadByte(); byte a = reader.ReadByte(); pixelData[i + 2] = v; pixelData[i + 1] = v; pixelData[i + 0] = v; pixelData[i + 3] = a; } } break; case 8: if (CheckBitmasks(header.PixelFormat, 0xFF, 0x00, 0x00, 0x00)) { // R8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 1) { byte v = reader.ReadByte(); pixelData[i + 2] = v; pixelData[i + 1] = v; pixelData[i + 0] = v; pixelData[i + 3] = v; } } else if (CheckBitmasks(header.PixelFormat, 0xF0, 0x00, 0x00, 0x0F)) { // R4 G4 for (int i = 0, j = 0; j < rawLength; i += 4, j += 1) { byte v = reader.ReadByte(); pixelData[i + 2] = (byte)((v & 0xF0) | (v & 0xF0) >> 4); pixelData[i + 1] = (byte)((v & 0xF0) | (v & 0xF0) >> 4); pixelData[i + 0] = (byte)((v & 0xF0) | (v & 0xF0) >> 4); pixelData[i + 3] = (byte)((v & 0x0F) << 4 | (v & 0x0F)); } } break; } } else if (header.PixelFormat.Flags.HasFlag(DDPF.Alpha)) { if (header.PixelFormat.RGBBitCount == 8) { // A8 for (int i = 0, j = 0; j < rawLength; i += 4, j += 1) { pixelData[i + 2] = 0xFF; pixelData[i + 1] = 0xFF; pixelData[i + 0] = 0xFF; pixelData[i + 3] = reader.ReadByte(); } } } } if (pixelData != null) { BitmapData bmpData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat); Marshal.Copy(pixelData, 0, bmpData.Scan0, pixelData.Length); bitmap.UnlockBits(bmpData); } return(bitmap); }
private static byte[] DecompressDxtAlpha(EndianBinaryReader reader, DxtFormat format) { byte[] alphaOut = new byte[(4 * 4) * 4]; switch (format) { case DxtFormat.DXT3: { ulong alpha = reader.ReadUInt64(Endian.LittleEndian); for (int i = 0; i < alphaOut.Length; i += 4) { alphaOut[i + 3] = (byte)(((alpha & 0xF) << 4) | (alpha & 0xF)); alpha >>= 4; } } break; case DxtFormat.DXT5: { byte alpha0 = reader.ReadByte(); byte alpha1 = reader.ReadByte(); byte bits_5 = reader.ReadByte(); byte bits_4 = reader.ReadByte(); byte bits_3 = reader.ReadByte(); byte bits_2 = reader.ReadByte(); byte bits_1 = reader.ReadByte(); byte bits_0 = reader.ReadByte(); ulong bits = (ulong)(((ulong)bits_0 << 40) | ((ulong)bits_1 << 32) | ((ulong)bits_2 << 24) | ((ulong)bits_3 << 16) | ((ulong)bits_4 << 8) | (ulong)bits_5); byte[] bitsExt = new byte[16]; for (int i = 0; i < bitsExt.Length; i++) { bitsExt[i] = (byte)((bits >> (i * 3)) & 0x7); } for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { byte code = bitsExt[(y * 4) + x]; int destOffset = (((y * 4) + x) * 4) + 3; if (alpha0 > alpha1) { switch (code) { case 0x00: alphaOut[destOffset] = alpha0; break; case 0x01: alphaOut[destOffset] = alpha1; break; case 0x02: alphaOut[destOffset] = (byte)((6 * alpha0 + 1 * alpha1) / 7); break; case 0x03: alphaOut[destOffset] = (byte)((5 * alpha0 + 2 * alpha1) / 7); break; case 0x04: alphaOut[destOffset] = (byte)((4 * alpha0 + 3 * alpha1) / 7); break; case 0x05: alphaOut[destOffset] = (byte)((3 * alpha0 + 4 * alpha1) / 7); break; case 0x06: alphaOut[destOffset] = (byte)((2 * alpha0 + 5 * alpha1) / 7); break; case 0x07: alphaOut[destOffset] = (byte)((1 * alpha0 + 6 * alpha1) / 7); break; } } else { switch (code) { case 0x00: alphaOut[destOffset] = alpha0; break; case 0x01: alphaOut[destOffset] = alpha1; break; case 0x02: alphaOut[destOffset] = (byte)((4 * alpha0 + 1 * alpha1) / 5); break; case 0x03: alphaOut[destOffset] = (byte)((3 * alpha0 + 2 * alpha1) / 5); break; case 0x04: alphaOut[destOffset] = (byte)((2 * alpha0 + 3 * alpha1) / 5); break; case 0x05: alphaOut[destOffset] = (byte)((1 * alpha0 + 4 * alpha1) / 5); break; case 0x06: alphaOut[destOffset] = 0x00; break; case 0x07: alphaOut[destOffset] = 0xFF; break; } } } } } break; } return(alphaOut); }
private static byte[] DecompressDxtColor(EndianBinaryReader reader, DxtFormat format) { byte[] colorOut = new byte[(4 * 4) * 4]; ushort color0 = reader.ReadUInt16(Endian.LittleEndian); ushort color1 = reader.ReadUInt16(Endian.LittleEndian); uint bits = reader.ReadUInt32(Endian.LittleEndian); byte c0r, c0g, c0b, c1r, c1g, c1b; UnpackRgb565(color0, out c0r, out c0g, out c0b); UnpackRgb565(color1, out c1r, out c1g, out c1b); byte[] bitsExt = new byte[16]; for (int i = 0; i < bitsExt.Length; i++) { bitsExt[i] = (byte)((bits >> (i * 2)) & 0x3); } for (int y = 0; y < 4; y++) { for (int x = 0; x < 4; x++) { byte code = bitsExt[(y * 4) + x]; int destOffset = ((y * 4) + x) * 4; if (format == DxtFormat.DXT1) { colorOut[destOffset + 3] = (byte)((color0 <= color1 && code == 3) ? 0 : 0xFF); } if (format == DxtFormat.DXT1 && color0 <= color1) { switch (code) { case 0x00: colorOut[destOffset + 0] = c0b; colorOut[destOffset + 1] = c0g; colorOut[destOffset + 2] = c0r; break; case 0x01: colorOut[destOffset + 0] = c1b; colorOut[destOffset + 1] = c1g; colorOut[destOffset + 2] = c1r; break; case 0x02: colorOut[destOffset + 0] = (byte)((c0b + c1b) / 2); colorOut[destOffset + 1] = (byte)((c0g + c1g) / 2); colorOut[destOffset + 2] = (byte)((c0r + c1r) / 2); break; case 0x03: colorOut[destOffset + 0] = 0; colorOut[destOffset + 1] = 0; colorOut[destOffset + 2] = 0; break; } } else { switch (code) { case 0x00: colorOut[destOffset + 0] = c0b; colorOut[destOffset + 1] = c0g; colorOut[destOffset + 2] = c0r; break; case 0x01: colorOut[destOffset + 0] = c1b; colorOut[destOffset + 1] = c1g; colorOut[destOffset + 2] = c1r; break; case 0x02: colorOut[destOffset + 0] = (byte)((2 * c0b + c1b) / 3); colorOut[destOffset + 1] = (byte)((2 * c0g + c1g) / 3); colorOut[destOffset + 2] = (byte)((2 * c0r + c1r) / 3); break; case 0x03: colorOut[destOffset + 0] = (byte)((c0b + 2 * c1b) / 3); colorOut[destOffset + 1] = (byte)((c0g + 2 * c1g) / 3); colorOut[destOffset + 2] = (byte)((c0r + 2 * c1r) / 3); break; } } } } return(colorOut); }
public Decoder(DxtFormat format) { _queue = new Queue <Color>(); _format = format; }