protected override void Initalize() { // Check to see if what we are dealing with is a PVR texture if (!Is(encodedData)) { throw new NotAValidTextureException("This is not a valid PVR texture."); } // Determine the offsets of the GBIX (if present) and PVRT header chunks. if (PTMethods.Contains(encodedData, 0x00, Encoding.UTF8.GetBytes("GBIX"))) { gbixOffset = 0x00; pvrtOffset = 0x10; } else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("GBIX"))) { gbixOffset = 0x04; pvrtOffset = 0x14; } else if (PTMethods.Contains(encodedData, 0x04, Encoding.UTF8.GetBytes("PVRT"))) { gbixOffset = -1; pvrtOffset = 0x04; } else { gbixOffset = -1; pvrtOffset = 0x00; } // Read the global index (if it is present). If it is not present, just set it to 0. if (gbixOffset != -1) { globalIndex = BitConverter.ToUInt32(encodedData, gbixOffset + 0x08); } else { globalIndex = 0; } // Read information about the texture textureWidth = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0C); textureHeight = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0E); pixelFormat = (PvrPixelFormat)encodedData[pvrtOffset + 0x08]; dataFormat = (PvrDataFormat)encodedData[pvrtOffset + 0x09]; // Get the codecs and make sure we can decode using them pixelCodec = PvrPixelCodec.GetPixelCodec(pixelFormat); dataCodec = PvrDataCodec.GetDataCodec(dataFormat); if (dataCodec != null && pixelCodec != null) { dataCodec.PixelCodec = pixelCodec; canDecode = true; } // Set the palette and data offsets if (!canDecode || dataCodec.PaletteEntries == 0 || dataCodec.NeedsExternalPalette) { paletteOffset = -1; dataOffset = pvrtOffset + 0x10; } else { paletteOffset = pvrtOffset + 0x10; dataOffset = paletteOffset + (dataCodec.PaletteEntries * (pixelCodec.Bpp >> 3)); } // Get the compression format and determine if we need to decompress this texture compressionFormat = GetCompressionFormat(encodedData, pvrtOffset, dataOffset); compressionCodec = PvrCompressionCodec.GetCompressionCodec(compressionFormat); if (compressionFormat != PvrCompressionFormat.None && compressionCodec != null) { encodedData = compressionCodec.Decompress(encodedData, dataOffset, pixelCodec, dataCodec); // Now place the offsets in the appropiate area if (compressionFormat == PvrCompressionFormat.Rle) { if (gbixOffset != -1) { gbixOffset -= 4; } pvrtOffset -= 4; if (paletteOffset != -1) { paletteOffset -= 4; } dataOffset -= 4; } } // If the texture contains mipmaps, gets the offsets of them if (canDecode && dataCodec.HasMipmaps) { mipmapOffsets = new int[(int)Math.Log(textureWidth, 2) + 1]; int mipmapOffset = 0; // Calculate the padding for the first mipmap offset if (dataFormat == PvrDataFormat.SquareTwiddledMipmaps) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap mipmapOffset = (dataCodec.Bpp) >> 3; } if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt) { // A 1x1 mipmap takes up as much space as a 2x2 mipmap mipmapOffset = (3 * dataCodec.Bpp) >> 3; } for (int i = mipmapOffsets.Length - 1, size = 1; i >= 0; i--, size <<= 1) { mipmapOffsets[i] = mipmapOffset; mipmapOffset += Math.Max((size * size * dataCodec.Bpp) >> 3, 1); } } initalized = true; }
protected override void Initalize() { // Check to see if what we are dealing with is a PVR texture if (!Is(encodedData)) { throw new NotAValidTextureException("This is not a valid PVR texture."); } // Determine the offsets of the GBIX (if present) and PVRT header chunks. if (PTMethods.Contains(encodedData, 0x00, gbixFourCC)) { gbixOffset = 0x00; pvrtOffset = 0x08 + BitConverter.ToInt32(encodedData, gbixOffset + 4); } else if (PTMethods.Contains(encodedData, 0x04, gbixFourCC)) { gbixOffset = 0x04; pvrtOffset = 0x0C + BitConverter.ToInt32(encodedData, gbixOffset + 4); } else if (PTMethods.Contains(encodedData, 0x04, pvrtFourCC)) { gbixOffset = -1; pvrtOffset = 0x04; } else { gbixOffset = -1; pvrtOffset = 0x00; } // Read the global index (if it is present). If it is not present, just set it to 0. if (gbixOffset != -1) { globalIndex = BitConverter.ToUInt32(encodedData, gbixOffset + 0x08); } else { globalIndex = 0; } // Read information about the texture textureWidth = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0C); textureHeight = BitConverter.ToUInt16(encodedData, pvrtOffset + 0x0E); pixelFormat = (PvrPixelFormat)encodedData[pvrtOffset + 0x08]; dataFormat = (PvrDataFormat)encodedData[pvrtOffset + 0x09]; // Get the codecs and make sure we can decode using them pixelCodec = PvrPixelCodec.GetPixelCodec(pixelFormat); dataCodec = PvrDataCodec.GetDataCodec(dataFormat); if (dataCodec != null && pixelCodec != null) { dataCodec.PixelCodec = pixelCodec; canDecode = true; } // Set the number of palette entries // The number in a Small Vq encoded texture various based on its size paletteEntries = dataCodec.PaletteEntries; if (dataFormat == PvrDataFormat.SmallVq || dataFormat == PvrDataFormat.SmallVqMipmaps) { if (textureWidth <= 16) { paletteEntries = 64; // Actually 16 } else if (textureWidth <= 32) { paletteEntries = 256; // Actually 64 } else if (textureWidth <= 64) { paletteEntries = 512; // Actually 128 } else { paletteEntries = 1024; // Actually 256 } } // Set the palette and data offsets if (!canDecode || paletteEntries == 0 || dataCodec.NeedsExternalPalette) { paletteOffset = -1; dataOffset = pvrtOffset + 0x10; } else { paletteOffset = pvrtOffset + 0x10; dataOffset = paletteOffset + (paletteEntries * (pixelCodec.Bpp >> 3)); } // Get the compression format and determine if we need to decompress this texture compressionFormat = GetCompressionFormat(encodedData, pvrtOffset, dataOffset); compressionCodec = PvrCompressionCodec.GetCompressionCodec(compressionFormat); if (compressionFormat != PvrCompressionFormat.None && compressionCodec != null) { encodedData = compressionCodec.Decompress(encodedData, dataOffset, pixelCodec, dataCodec); // Now place the offsets in the appropiate area if (compressionFormat == PvrCompressionFormat.Rle) { if (gbixOffset != -1) gbixOffset -= 4; pvrtOffset -= 4; if (paletteOffset != -1) paletteOffset -= 4; dataOffset -= 4; } } // If the texture contains mipmaps, gets the offsets of them if (canDecode && dataCodec.HasMipmaps) { mipmapOffsets = new int[(int)Math.Log(textureWidth, 2) + 1]; int mipmapOffset = 0; // Calculate the padding for the first mipmap offset if (dataFormat == PvrDataFormat.SquareTwiddledMipmaps) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap mipmapOffset = (dataCodec.Bpp) >> 3; } else if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt) { // A 1x1 mipmap takes up as much space as a 2x2 mipmap mipmapOffset = (3 * dataCodec.Bpp) >> 3; } for (int i = mipmapOffsets.Length - 1, size = 1; i >= 0; i--, size <<= 1) { mipmapOffsets[i] = mipmapOffset; mipmapOffset += Math.Max((size * size * dataCodec.Bpp) >> 3, 1); } } initalized = true; }
protected override 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.SquareTwiddledMipmaps) { // 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.SquareTwiddledMipmapsAlt) { // 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(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 = BitmapToRawResized(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(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.SquareTwiddledMipmaps) { 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; }
// Initalize the bitmap private bool Initalize() { // Make sure the width and height are correct if (TextureWidth < 8 || TextureHeight < 8) return false; if ((TextureWidth & (TextureWidth - 1)) != 0 || (TextureHeight & (TextureHeight - 1)) != 0) return false; PixelCodec = PvrCodecList.GetPixelCodec((PvrPixelFormat)PixelFormat); DataCodec = PvrCodecList.GetDataCodec((PvrDataFormat)DataFormat); CompressionFormat = PvrCompressionFormat.None; CompressionCodec = null; if (PixelCodec == null || DataCodec == null) return false; if (!PixelCodec.CanEncode() || !DataCodec.CanEncode()) return false; if (!CanEncode((PvrPixelFormat)PixelFormat, (PvrDataFormat)DataFormat, TextureWidth, TextureHeight)) return false; GbixOffset = 0x00; PvrtOffset = 0x10; // See if we need to palettize the bitmap and raw image data if (DataCodec.GetNumClutEntries() != 0) PalettizeBitmap(); return true; }
/// <summary> /// Set the compression format. /// </summary> /// <param name="CompressionFormat">Compression Format</param> public void SetCompressionFormat(PvrCompressionFormat CompressionFormat) { if (!InitSuccess) return; if (CompressionFormat == PvrCompressionFormat.Rle && DataCodec.GetBpp(PixelCodec) >= 8) { // We want to use Rle compression and our texture has a bpp of at least 8. CompressionCodec = PvrCodecList.GetCompressionCodec(CompressionFormat); if (CompressionCodec != null) this.CompressionFormat = PvrCompressionFormat.Rle; else return; // Can't compress! } }
// Read the header and sets up the appropiate values. // Returns true if successful, otherwise false private bool ReadHeader() { // Make sure this is a Pvr Texture if (!IsPvrTexture(TextureData)) return false; // Get the header offsets if (Compare(TextureData, "GBIX", 0x00)) { GbixOffset = 0x00; PvrtOffset = 0x10; } else if (Compare(TextureData, "GBIX", 0x04)) { GbixOffset = 0x04; PvrtOffset = 0x14; } else if (Compare(TextureData, "PVRT", 0x04)) { GbixOffset = -1; PvrtOffset = 0x04; } else { GbixOffset = -1; PvrtOffset = 0x00; } // Read the file information TextureWidth = BitConverter.ToUInt16(TextureData, PvrtOffset + 0x0C); TextureHeight = BitConverter.ToUInt16(TextureData, PvrtOffset + 0x0E); PixelFormat = TextureData[PvrtOffset + 0x08]; DataFormat = TextureData[PvrtOffset + 0x09]; // Get the codecs and make sure we can decode using them PixelCodec = PvrCodecList.GetPixelCodec((PvrPixelFormat)PixelFormat); DataCodec = PvrCodecList.GetDataCodec((PvrDataFormat)DataFormat); if (PixelCodec == null || !PixelCodec.CanDecode()) return false; if (DataCodec == null || !DataCodec.CanDecode()) return false; // Set the clut and data offsets if (DataCodec.GetNumClutEntries() == 0 || DataCodec.NeedsExternalClut()) { ClutOffset = -1; DataOffset = PvrtOffset + 0x10; } else { ClutOffset = PvrtOffset + 0x10; DataOffset = ClutOffset + (DataCodec.GetNumClutEntries() * (PixelCodec.GetBpp() / 8)); } // Get the compression format & decompress the pvr CompressionFormat = GetCompressionFormat(TextureData, PvrtOffset, DataOffset); CompressionCodec = PvrCodecList.GetCompressionCodec(CompressionFormat); if (CompressionFormat != PvrCompressionFormat.None && CompressionCodec != null) { TextureData = CompressionCodec.Decompress(TextureData, DataOffset, PixelCodec, DataCodec); // Now place the offsets in the appropiate area if (CompressionFormat == PvrCompressionFormat.Rle) { if (GbixOffset != -1) GbixOffset -= 4; PvrtOffset -= 4; if (ClutOffset != -1) ClutOffset -= 4; DataOffset -= 4; } } RawImageData = new byte[TextureWidth * TextureHeight * 4]; return true; }
protected override 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.SquareTwiddledMipmaps) { // A 1x1 mipmap takes up as much space as a 2x1 mipmap mipmapPadding = (dataCodec.Bpp) >> 3; } else if (dataFormat == PvrDataFormat.SquareTwiddledMipmapsAlt) { // 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(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 = BitmapToRawResized(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(decodedData, textureWidth, textureHeight, null); destination.Write(textureData, 0, textureData.Length); // 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); }