Пример #1
0
        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;
        }
Пример #2
0
        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;
        }
Пример #3
0
        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;
        }
Пример #4
0
        // 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;
        }
Пример #5
0
        /// <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!
            }
        }
Пример #6
0
        // 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;
        }
Пример #7
0
        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);
        }