Exemplo n.º 1
0
        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);
        }
Exemplo n.º 2
0
        public void Initalize()
        {
            // Determine the offsets of the GBIX (if present) and PVRT header chunks.
            if (PTMethods.Contains(m_encodedData, 0x00, gbixFourCC))
            {
                GbixOffset = 0x00;
                PvrtOffset = 0x08 + BitConverter.ToInt32(m_encodedData, GbixOffset + 4);
            }
            else if (PTMethods.Contains(m_encodedData, 0x04, gbixFourCC))
            {
                GbixOffset = 0x04;
                PvrtOffset = 0x0C + BitConverter.ToInt32(m_encodedData, GbixOffset + 4);
            }
            else if (PTMethods.Contains(m_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(m_encodedData, GbixOffset + 0x08);
            }
            else
            {
                GlobalIndex = 0;
            }

            // Read information about the texture
            TextureWidth  = BitConverter.ToUInt16(m_encodedData, PvrtOffset + 0x0C);
            TextureHeight = BitConverter.ToUInt16(m_encodedData, PvrtOffset + 0x0E);

            PixelFormat = (PvrPixelFormat)m_encodedData[PvrtOffset + 0x08];
            DataFormat  = (PvrDataFormat)m_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;
            }

            // Set the number of palette entries
            // The number in a Small Vq encoded texture various based on its size
            m_paletteEntries = DataCodec.PaletteEntries;
            if (DataFormat == PvrDataFormat.VECTOR_QUANTIZATION_SMALL || DataFormat == PvrDataFormat.VECTOR_QUANTIZATION_SMALL_MIPMAP)
            {
                if (TextureWidth <= 16)
                {
                    m_paletteEntries = 64; // Actually 16
                }
                else if (TextureWidth <= 32)
                {
                    m_paletteEntries = 256; // Actually 64
                }
                else if (TextureWidth <= 64)
                {
                    m_paletteEntries = 512; // Actually 128
                }
                else
                {
                    m_paletteEntries = 1024; // Actually 256
                }
            }

            // Set the palette and data offsets
            if (m_paletteEntries == 0 || DataCodec.NeedsExternalPalette)
            {
                m_paletteOffset = -1;
                m_dataOffset    = PvrtOffset + 0x10;
            }
            else
            {
                m_paletteOffset = PvrtOffset + 0x10;
                m_dataOffset    = m_paletteOffset + (m_paletteEntries * (PixelCodec.Bpp >> 3));
            }

            // Get the compression format and determine if we need to decompress this texture
            CompressionFormat = GetCompressionFormat(m_encodedData, PvrtOffset, m_dataOffset);
            CompressionCodec  = PvrCompressionCodec.GetCompressionCodec(CompressionFormat);

            if (CompressionFormat != PvrCompressionFormat.NONE && CompressionCodec != null)
            {
                m_encodedData = CompressionCodec.Decompress(m_encodedData, m_dataOffset, PixelCodec, DataCodec);

                // Now place the offsets in the appropiate area
                if (CompressionFormat == PvrCompressionFormat.RLE)
                {
                    if (GbixOffset != -1)
                    {
                        GbixOffset -= 4;
                    }
                    PvrtOffset -= 4;
                    if (m_paletteOffset != -1)
                    {
                        m_paletteOffset -= 4;
                    }
                    m_dataOffset -= 4;
                }
            }

            // If the texture contains mipmaps, gets the offsets of them
            if (DataCodec.HasMipmaps)
            {
                m_mipmapOffsets = new int[(int)Math.Log(TextureWidth, 2) + 1];

                int mipmapOffset = 0;

                // Calculate the padding for the first mipmap offset
                if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP)
                {
                    // A 1x1 mipmap takes up as much space as a 2x1 mipmap
                    mipmapOffset = (DataCodec.Bpp) >> 3;
                }
                else if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP_ALT)
                {
                    // A 1x1 mipmap takes up as much space as a 2x2 mipmap
                    mipmapOffset = (3 * DataCodec.Bpp) >> 3;
                }

                for (int i = m_mipmapOffsets.Length - 1, size = 1; i >= 0; i--, size <<= 1)
                {
                    m_mipmapOffsets[i] = mipmapOffset;

                    mipmapOffset += Math.Max((size * size * DataCodec.Bpp) >> 3, 1);
                }
            }
        }