private void ApplyColorPalette(Bitmap bitmap, byte[] paletteData, TxfDataFormat paletteFormat) { ColorPalette palette = bitmap.Palette; switch (paletteFormat) { case TxfDataFormat.Argb8888: { for (int i = 0, j = 0; i < palette.Entries.Length; i++, j += 4) { palette.Entries[i] = Color.FromArgb(paletteData[j + 3], paletteData[j + 2], paletteData[j + 1], paletteData[j]); } } break; case TxfDataFormat.Argb4444: { for (int i = 0, j = 0; i < palette.Entries.Length; i++, j += 2) { palette.Entries[i] = Color.FromArgb( (byte)((paletteData[j] & 0xF0) | ((paletteData[j] & 0xF0) >> 4)), (byte)((paletteData[j + 1] & 0x0F) | ((paletteData[j + 1] & 0x0F) << 4)), (byte)((paletteData[j + 1] & 0xF0) | ((paletteData[j + 1] & 0xF0) >> 4)), (byte)((paletteData[j] & 0x0F) | ((paletteData[j] & 0x0F) << 4))); } } break; default: throw new Exception(string.Format("Cannot generate color palette from data format '{0}'.", paletteFormat)); } bitmap.Palette = palette; }
private byte[] DecompressDxt(EndianBinaryReader reader, TxfDataFormat format, int width, int height) { byte[] pixelData = new byte[CalculatePixelDataSize(TxfDataFormat.Argb8888, width, height)]; 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); }
private byte[] GetPixelData(EndianBinaryReader reader, TxfDataFormat format, uint dataSize) { byte[] pixelData = new byte[dataSize]; int bytesPerPixel = (BitsPerPixel[format] >> 3); for (int i = 0; i < pixelData.Length; i += bytesPerPixel) { for (int j = bytesPerPixel - 1; j >= 0; j--) { pixelData[i + j] = reader.ReadByte(); } } return(pixelData); }
private byte[] DecompressDxtBlock(EndianBinaryReader reader, TxfDataFormat format) { byte[] outputData = new byte[(4 * 4) * 4]; byte[] colorData = null, alphaData = null; if (format != TxfDataFormat.RgbaDxt1) { 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); }
private uint CalculatePaletteDataSize(TxfDataFormat pixelFormat, TxfDataFormat paletteFormat) { uint colorCount, bytesPerColor; switch (pixelFormat) { case TxfDataFormat.Indexed8bpp: colorCount = 256; break; default: throw new Exception(string.Format("Unknown color count for pixel format '{0}'.", pixelFormat)); } switch (paletteFormat) { case TxfDataFormat.Argb8888: bytesPerColor = 4; break; case TxfDataFormat.Argb4444: bytesPerColor = 2; break; default: throw new Exception(string.Format("Unknown bytes/color for palette format '{0}'.", paletteFormat)); } return(colorCount * bytesPerColor); }
private byte[] DecompressDxtAlpha(EndianBinaryReader reader, TxfDataFormat format) { byte[] alphaOut = new byte[(4 * 4) * 4]; switch (format) { case TxfDataFormat.RgbaDxt3: { ulong alpha = reader.ReadUInt64(); for (int i = 0; i < alphaOut.Length; i += 4) { alphaOut[i + 3] = (byte)(((alpha & 0xF) << 4) | (alpha & 0xF)); alpha >>= 4; } } break; case TxfDataFormat.RgbaDxt5: { 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 byte[] DecompressDxtColor(EndianBinaryReader reader, TxfDataFormat 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 == TxfDataFormat.RgbaDxt1) { colorOut[destOffset + 3] = (byte)((color0 <= color1 && code == 3) ? 0 : 0xFF); } if (format == TxfDataFormat.RgbaDxt1 && 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); }
private uint CalculatePixelDataSize(TxfDataFormat pixelFormat, int width, int height) { return((uint)(width * height * (BitsPerPixel[pixelFormat] >> 3))); }