public override byte[] Encode(byte[] source, int sourceIndex, int width, int height) { // Destination data & index byte[] destination = new byte[width * height * (PixelCodec.Bpp >> 3)]; int destinationIndex = 0; // Twiddle map int[] twiddleMap = MakeTwiddleMap(width); // Encode texture data for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { PixelCodec.EncodePixel(source, sourceIndex, destination, destinationIndex); sourceIndex += 4; destinationIndex += (PixelCodec.Bpp >> 3); } } return(destination); }
public byte[] GetEncodedColorData(byte[] color, int index, bool bigEndian, PixelCodec pixelCodec) { byte[] data = new byte[pixelCodec == PixelCodec.ARGB8888 ? 4 : 2]; switch (pixelCodec) { case PixelCodec.ARGB8888: if (bigEndian) { data[0] = color[index]; data[1] = color[index + 1]; data[2] = color[index + 2]; data[3] = color[index + 3]; } else { data[0] = color[index + 3]; data[1] = color[index + 2]; data[2] = color[index + 1]; data[3] = color[index]; } return(data); case PixelCodec.ARGB1555: case PixelCodec.ARGB4444: case PixelCodec.RGB565: default: if (bigEndian) { data[0] = color[index + 1]; data[1] = color[index]; } else { data[0] = color[index]; data[1] = color[index + 1]; } return(data); } }
public TexturePalette(bool gvp = false, PixelCodec codec = PixelCodec.RGB565) { StartBank = 0; StartColor = 0; pixelCodec = codec; IsGVP = gvp; Colors = new List <Color>(); int numcolor = 256; int red; int blue; int green; int gencolor = 0; for (int y = 0; y < 16; y++) { if (gencolor >= numcolor) { break; } for (int x = 0; x < 16; x++) { if (gencolor >= numcolor) { break; } int colorindex = x + 16 * y; green = colorindex; red = x * 16; blue = y * 16; Color rgb8 = Color.FromArgb(red, green, blue); Color result = DecodeColor(EncodeColor(rgb8, pixelCodec), pixelCodec); Colors.Add(result); gencolor++; } } }
public MemoryStream EncodeTexture() { // Calculate what the length of the texture will be int textureLength = 16 + (TextureWidth * TextureHeight * DataCodec.Bpp / 8); if (HasGlobalIndex) { textureLength += 16; } if (DataCodec.PaletteEntries != 0 && !DataCodec.NeedsExternalPalette) { textureLength += (DataCodec.PaletteEntries * PixelCodec.Bpp / 8); } // Calculate the mipmap padding (if the texture contains mipmaps) int mipmapPadding = 0; if (DataCodec.HasMipmaps) { if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap // There are also 4 extra bytes at the end of the file mipmapPadding = (DataCodec.Bpp) >> 3; textureLength += 4; } else if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP_ALT) { // A 1x1 mipmap takes up as much space as a 2x2 mipmap mipmapPadding = (3 * DataCodec.Bpp) >> 3; } textureLength += mipmapPadding; for (int size = 1; size < TextureWidth; size <<= 1) { textureLength += Math.Max((size * size * DataCodec.Bpp) >> 3, 1); } } MemoryStream destination = new MemoryStream(textureLength); // Write out the GBIX header (if we are including one) if (HasGlobalIndex) { destination.WriteByte((byte)'G'); destination.WriteByte((byte)'B'); destination.WriteByte((byte)'I'); destination.WriteByte((byte)'X'); PTStream.WriteUInt32(destination, 8); PTStream.WriteUInt32(destination, GlobalIndex); PTStream.WriteUInt32(destination, 0); } // Write out the PVRT header destination.WriteByte((byte)'P'); destination.WriteByte((byte)'V'); destination.WriteByte((byte)'R'); destination.WriteByte((byte)'T'); if (HasGlobalIndex) { PTStream.WriteInt32(destination, textureLength - 24); } else { PTStream.WriteInt32(destination, textureLength - 8); } destination.WriteByte((byte)PixelFormat); destination.WriteByte((byte)DataFormat); PTStream.WriteUInt16(destination, 0); PTStream.WriteUInt16(destination, TextureWidth); PTStream.WriteUInt16(destination, TextureHeight); // If we have an internal palette, write it if (DataCodec.PaletteEntries != 0 && !DataCodec.NeedsExternalPalette) { byte[] palette = PixelCodec.EncodePalette(m_texturePalette, DataCodec.PaletteEntries); destination.Write(palette, 0, palette.Length); } // Write out any mipmaps if (DataCodec.HasMipmaps) { // Write out any padding bytes before the 1x1 mipmap for (int i = 0; i < mipmapPadding; i++) { destination.WriteByte(0); } for (int size = 1; size < TextureWidth; size <<= 1) { byte[] mipmapDecodedData = null; if (DataCodec.NeedsExternalPalette) { if (DataCodec.VQ) { mipmapDecodedData = BitmapToRawVQResized(m_decodedBitmap, size, 1, m_codeBook); } else { mipmapDecodedData = BitmapToRawIndexedResized(m_decodedBitmap, size, 1, m_palette); } } else { mipmapDecodedData = BitmapToRawResized(m_decodedBitmap, size, 1); } byte[] mipmapTextureData = DataCodec.Encode(mipmapDecodedData, 0, size, size); destination.Write(mipmapTextureData, 0, mipmapTextureData.Length); } } // Write the texture data byte[] textureData = DataCodec.Encode(m_decodedData, TextureWidth, TextureHeight, null); destination.Write(textureData, 0, textureData.Length); // If the data format is square twiddled with mipmaps, write out the extra bytes. if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP) { destination.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); } // Compress the texture if (CompressionFormat != PvrCompressionFormat.NONE) { CompressionCodec = PvrCompressionCodec.GetCompressionCodec(CompressionFormat); if (CompressionCodec != null) { // Ok, we need to convert the current stream to an array, compress it, then write it back to a new stream byte[] buffer = destination.ToArray(); buffer = CompressionCodec.Compress(buffer, (HasGlobalIndex ? 0x20 : 0x10), PixelCodec, DataCodec); destination = new MemoryStream(); destination.Write(buffer, 0, buffer.Length); } } return(destination); }
public Color DecodeColor(byte[] rgb, PixelCodec codec) { int a = 255; int r; int g; int b; switch (codec) { case PixelCodec.ARGB1555: a = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 15) & 0x01) * 0xFF); r = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 10) & 0x1F) * 0xFF / 0x1F); g = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 5) & 0x1F) * 0xFF / 0x1F); b = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 0) & 0x1F) * 0xFF / 0x1F); break; case PixelCodec.ARGB4444: a = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 12) & 0x0F) * 0xFF / 0x0F); r = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 8) & 0x0F) * 0xFF / 0x0F); g = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 4) & 0x0F) * 0xFF / 0x0F); b = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 0) & 0x0F) * 0xFF / 0x0F); break; case PixelCodec.RGB5A3: ushort pixel = BitConverter.ToUInt16(rgb, 0); if ((pixel & 0x8000) != 0) // RGB555 { a = 255; r = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 10) & 0x1F) * 0xFF / 0x1F); g = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 5) & 0x1F) * 0xFF / 0x1F); b = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 0) & 0x1F) * 0xFF / 0x1F); } else // ARGB34444 { a = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 12) & 0x07) * 0xFF / 0x07); r = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 8) & 0x0F) * 0xFF / 0x0F); g = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 4) & 0x0F) * 0xFF / 0x0F); b = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 0) & 0x0F) * 0xFF / 0x0F); } break; case PixelCodec.Intensity8A: a = rgb[0]; r = rgb[1]; g = rgb[1]; b = rgb[1]; break; case PixelCodec.ARGB8888: a = rgb[0]; r = rgb[1]; g = rgb[2]; b = rgb[3]; break; case PixelCodec.RGB565: default: r = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 11) & 0x1F) * 0xFF / 0x1F); g = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 5) & 0x3F) * 0xFF / 0x3F); b = (byte)(((BitConverter.ToUInt16(rgb, 0) >> 0) & 0x1F) * 0xFF / 0x1F); break; } return(Color.FromArgb(a, r, g, b)); }
public byte[] EncodeColor(Color color, PixelCodec pixelCodec) { byte[] result = new byte[pixelCodec == PixelCodec.ARGB8888 ? 4 : 2]; ushort pixel = 0x0000; switch (pixelCodec) { case PixelCodec.ARGB1555: pixel |= (ushort)((color.A >> 7) << 15); pixel |= (ushort)((color.R >> 3) << 10); pixel |= (ushort)((color.G >> 3) << 5); pixel |= (ushort)((color.B >> 3) << 0); result[1] = (byte)((pixel >> 8) & 0xFF); result[0] = (byte)(pixel & 0xFF); break; case PixelCodec.ARGB4444: pixel |= (ushort)((color.A >> 4) << 12); pixel |= (ushort)((color.R >> 4) << 8); pixel |= (ushort)((color.G >> 4) << 4); pixel |= (ushort)((color.B >> 4) << 0); result[1] = (byte)((pixel >> 8) & 0xFF); result[0] = (byte)(pixel & 0xFF); break; case PixelCodec.ARGB8888: result[3] = color.A; result[2] = color.R; result[1] = color.G; result[0] = color.B; break; case PixelCodec.Intensity8A: result[1] = color.A; result[0] = (byte)((0.30 * color.R) + (0.59 * color.G) + (0.11 * color.B)); break; case PixelCodec.RGB5A3: if (color.A <= 0xDA) // Argb3444 { pixel |= (ushort)((color.A >> 5) << 12); pixel |= (ushort)((color.R >> 4) << 8); pixel |= (ushort)((color.G >> 4) << 4); pixel |= (ushort)((color.B >> 4) << 0); } else // Rgb555 { pixel |= 0x8000; pixel |= (ushort)((color.R >> 3) << 10); pixel |= (ushort)((color.G >> 3) << 5); pixel |= (ushort)((color.B >> 3) << 0); } result[1] = (byte)(pixel & 0xFF); result[0] = (byte)((pixel >> 8) & 0xFF); break; case PixelCodec.RGB565: default: pixel |= (ushort)((color.R >> 3) << 11); pixel |= (ushort)((color.G >> 2) << 5); pixel |= (ushort)((color.B >> 3) << 0); result[1] = (byte)((pixel >> 8) & 0xFF); result[0] = (byte)(pixel & 0xFF); break; } return(result); }
/// <summary> /// Internal write implementation of the sub classes. /// </summary> /// <param name="writer"></param> /// <exception cref="Exception">Expected DDS RGB24 or RGBA32 color format!</exception> /// <exception cref="InvalidOperationException"> /// </exception> protected override void _Write(BinaryWriter writer) { long baseOffset = writer.BaseStream.Position; Bitmap bmp = CreateBitmap(); //bmp.RotateFlip(RotateFlipType.RotateNoneFlipY); if (DataFormat == PvrDataFormat.DDS || DataFormat == PvrDataFormat.DDS_2) { if (!(PixelFormat == PvrPixelFormat.DDS_DXT1_RGB24 || PixelFormat == PvrPixelFormat.DDS_DXT3_RGBA32)) { throw new Exception("Expected DDS RGB24 or RGBA32 color format!"); } byte[] ddsBuffer = null; if (PixelFormat == PvrPixelFormat.DDS_DXT1_RGB24) { DDSFormatDetails ddsFormatDetails = new DDSFormatDetails(DDSFormat.DDS_DXT1); ddsBuffer = DDSGeneral.Save(MipMaps, ddsFormatDetails, DDSGeneral.AlphaSettings.KeepAlpha, DDSGeneral.MipHandling.Default); } else if (PixelFormat == PvrPixelFormat.DDS_DXT3_RGBA32) { DDSFormatDetails ddsFormatDetails = new DDSFormatDetails(DDSFormat.DDS_DXT3); ddsBuffer = DDSGeneral.Save(MipMaps, ddsFormatDetails, DDSGeneral.AlphaSettings.KeepAlpha, DDSGeneral.MipHandling.Default); } if (HasGlobalIndex) { writer.Write(m_gbix); writer.Write(GlobalIndexSize); writer.Write(GlobalIndex); } writer.Write(m_pvrt); writer.Write(ddsBuffer.Length + 16); writer.Write((byte)PixelFormat); writer.Write((byte)DataFormat); writer.Write((ushort)0); writer.Write((ushort)Width); writer.Write((ushort)Height); writer.Write(ddsBuffer); } else { // Set the data format and pixel format and load the appropiate codecs PixelCodec = PvrPixelCodec.GetPixelCodec(PixelFormat); DataCodec = PvrDataCodec.GetDataCodec(DataFormat); // Make sure the pixel and data codecs exists and we can encode to it if (PixelCodec == null || !PixelCodec.CanEncode) { throw new InvalidOperationException(); } if (DataCodec == null || !DataCodec.CanEncode) { throw new InvalidOperationException(); } DataCodec.PixelCodec = PixelCodec; byte[] decodedData = null; if (DataCodec.PaletteEntries != 0) { if (DataCodec.VQ) { decodedData = BitmapToRawVQ(bmp, DataCodec.PaletteEntries, out m_texturePalette); } else { // Convert the bitmap to an array containing indicies. decodedData = BitmapToRawIndexed(bmp, DataCodec.PaletteEntries, out m_texturePalette); // If this texture has an external palette file, set up the palette encoder if (DataCodec.NeedsExternalPalette) { PaletteEncoder = new PvpPaletteEncoder(m_texturePalette, (ushort)DataCodec.PaletteEntries, PixelFormat, PixelCodec); } } } else { decodedData = BitmapToRaw(bmp); } // Calculate what the length of the texture will be int textureLength = 16 + (int)(Width * Height * (DataCodec.Bpp / 8.0)); if (HasGlobalIndex) { textureLength += 16; } if (DataCodec.PaletteEntries != 0 && !DataCodec.NeedsExternalPalette) { textureLength += (DataCodec.PaletteEntries * PixelCodec.Bpp / 8); } // Calculate the mipmap padding (if the texture contains mipmaps) int mipmapPadding = 0; if (DataCodec.HasMipmaps) { if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap // There are also 4 extra bytes at the end of the file mipmapPadding = (DataCodec.Bpp) >> 3; textureLength += 4; } else if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP_ALT) { // A 1x1 mipmap takes up as much space as a 2x2 mipmap mipmapPadding = (3 * DataCodec.Bpp) >> 3; } textureLength += mipmapPadding; for (int size = 1; size < Width; size <<= 1) { textureLength += Math.Max((size * size * DataCodec.Bpp) >> 3, 1); } } MemoryStream output = new MemoryStream(textureLength); BinaryWriter outputWriter = new BinaryWriter(output); // Write out the GBIX header (if we are including one) if (HasGlobalIndex) { outputWriter.Write(m_gbix); outputWriter.Write(GlobalIndexSize); outputWriter.Write(GlobalIndex); } // Write out the PVRT header outputWriter.Write(m_pvrt); if (HasGlobalIndex) { outputWriter.Write(textureLength - 24); } else { outputWriter.Write(textureLength - 8); } outputWriter.Write((byte)PixelFormat); outputWriter.Write((byte)DataFormat); outputWriter.Write((ushort)0); outputWriter.Write((ushort)Width); outputWriter.Write((ushort)Height); // If we have an internal palette, write it if (DataCodec.PaletteEntries != 0 && !DataCodec.NeedsExternalPalette) { byte[] palette = PixelCodec.EncodePalette(m_texturePalette, DataCodec.PaletteEntries); output.Write(palette, 0, palette.Length); } // Write out any mipmaps if (DataCodec.HasMipmaps) { // Write out any padding bytes before the 1x1 mipmap for (int i = 0; i < mipmapPadding; i++) { output.WriteByte(0); } for (int size = 1; size < Width; size <<= 1) { byte[] mipmapDecodedData = null; if (DataCodec.NeedsExternalPalette) { if (DataCodec.VQ) { mipmapDecodedData = BitmapToRawVQResized(bmp, size, 1, m_codeBook); } else { mipmapDecodedData = BitmapToRawIndexedResized(bmp, size, 1, m_palette); } } else { mipmapDecodedData = BitmapToRawResized(bmp, size, 1); } byte[] mipmapTextureData = DataCodec.Encode(mipmapDecodedData, 0, size, size); output.Write(mipmapTextureData, 0, mipmapTextureData.Length); } } // Write the texture data byte[] textureData = DataCodec.Encode(decodedData, Width, Height, null); output.Write(textureData, 0, textureData.Length); // If the data format is square twiddled with mipmaps, write out the extra bytes. if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP) { output.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); } // Compress the texture if (CompressionFormat != PvrCompressionFormat.NONE) { CompressionCodec = PvrCompressionCodec.GetCompressionCodec(CompressionFormat); if (CompressionCodec != null) { // Ok, we need to convert the current stream to an array, compress it, then write it back to a new stream byte[] buffer = output.ToArray(); buffer = CompressionCodec.Compress(buffer, (HasGlobalIndex ? 0x20 : 0x10), PixelCodec, DataCodec); writer.Write(buffer); } } else { writer.Write(output.GetBuffer()); } } }