Exemple #1
0
        /// <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());
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// 查找当前类型的图片
        /// </summary>
        /// <param name="byData">当前打开文件的字节数据</param>
        /// <param name="file">当前文件</param>
        /// <param name="imgInfos">查找到的图片的信息</param>
        /// <returns>是否查找成功</returns>
        public override List <byte[]> SearchImg(byte[] byData, string file, List <string> imgInfos)
        {
            List <byte[]> imgList = new List <byte[]>();

            // 分析文件内部是否包括Pvr文件
            for (int i = 0; i < byData.Length - 1024; i++)
            {
                if (byData[i] == 0x50 && byData[i + 1] == 0x56 && byData[i + 2] == 0x52 && byData[i + 3] == 0x54 &&
                    byData[i - 0x10] == 0x47 && byData[i - 0xf] == 0x42 && byData[i - 0xe] == 0x49 && byData[i - 0xd] == 0x58)
                {
                    PvrPixelFormat pixelFormat = (PvrPixelFormat)byData[i + 0x08];
                    PvrDataFormat  dataFormat  = (PvrDataFormat)byData[i + 0x09];

                    PvrPixelCodec pixelCodec = PvrPixelCodec.GetPixelCodec(pixelFormat);
                    PvrDataCodec  dataCodec  = PvrDataCodec.GetDataCodec(dataFormat);
                    if (dataCodec == null)
                    {
                        continue;
                    }
                    dataCodec.PixelCodec = pixelCodec;
                    int byCountPalette = 0;
                    if (pixelCodec == null && byData[i + 0x08] == 0x6)
                    {
                        byCountPalette = 4;
                    }
                    else
                    {
                        byCountPalette = pixelCodec.Bpp >> 3;
                    }

                    // 取得图片大小
                    int width  = (byData[i + 0xD] << 8) | byData[i + 0xC];
                    int height = (byData[i + 0xF] << 8) | byData[i + 0xE];

                    int imgByCount = (width * height * dataCodec.Bpp / 8) + (dataCodec.PaletteEntries * byCountPalette);
                    if (imgByCount == 0 || imgByCount > byData.Length)
                    {
                        throw new Exception("图片容量异常格式 : " + imgByCount);
                    }

                    byte[] byGvrData = new byte[0x20 + imgByCount];
                    Array.Copy(byData, i - 0x10, byGvrData, 0, byGvrData.Length);

                    string imgFileInfo = Util.GetShortName(file) + " " + (i - 0x10).ToString("x") + "--" + (i - 0x10 + byGvrData.Length).ToString("x");
                    imgList.Add(byGvrData);
                    imgInfos.Add(imgFileInfo);

                    // 取得调色板大小
                    if (dataCodec.NeedsExternalPalette)
                    {
                        int    paletteCount     = dataCodec.PaletteEntries * byCountPalette;
                        byte[] byPalette        = new byte[paletteCount + 0x10];
                        int    paletteDataStart = i - 0x30;
                        if (byData[paletteDataStart] == 0x50 && byData[paletteDataStart + 1] == 0x50 &&
                            byData[paletteDataStart + 2] == 0x56 && byData[paletteDataStart + 3] == 0x52)
                        {
                            paletteDataStart = i - 0x20 - paletteCount - 0x10 - 0x20;
                        }
                        else
                        {
                            paletteDataStart = i - 0x20 - paletteCount - 0x10;
                        }
                        Array.Copy(byData, paletteDataStart, byPalette, 0, byPalette.Length);

                        this.paletteData.Add(imgFileInfo + " " + paletteDataStart.ToString(), byPalette);
                    }
                }
            }

            return(imgList);
        }
Exemple #3
0
        /// <summary>
        /// Internal read implementation of the sub classes.
        /// </summary>
        /// <param name="reader"></param>
        /// <exception cref="Exception">Expected DDS RGB24 or RGBA32 color format!</exception>
        /// <exception cref="NotImplementedException">TODO</exception>
        protected override void _Read(BinaryReader reader)
        {
            long baseOffset = reader.BaseStream.Position;

            int gbixOffset = 0;
            int pvrtOffset = 0;

            uint identifier = reader.ReadUInt32();

            if (identifier == m_gbix) //"GBIX"
            {
                HasGlobalIndex  = true;
                GlobalIndexSize = reader.ReadUInt32();
                GlobalIndex     = reader.ReadBytes((int)GlobalIndexSize);

                reader.BaseStream.Seek(4, SeekOrigin.Current); //Skip "PVRT"
                gbixOffset = 0x00;
                pvrtOffset = 0x08 + (int)GlobalIndexSize;
            }
            else
            {
                identifier = reader.ReadUInt32();
                if (identifier == m_gbix)
                {
                    HasGlobalIndex  = true;
                    GlobalIndexSize = reader.ReadUInt32();
                    GlobalIndex     = reader.ReadBytes((int)GlobalIndexSize);
                    gbixOffset      = 0x04;
                    pvrtOffset      = 0x0C + (int)GlobalIndexSize;
                }
                else if (identifier == m_pvrt)
                {
                    gbixOffset = -1;
                    pvrtOffset = 0x04;
                }
                else
                {
                    gbixOffset = -1;
                    pvrtOffset = 0x00;
                    reader.BaseStream.Seek(-4, SeekOrigin.Current);
                }
            }

            // Read information about the texture
            ContentSize = reader.ReadUInt32();
            PixelFormat = (PvrPixelFormat)reader.ReadByte();
            DataFormat  = (PvrDataFormat)reader.ReadByte();
            reader.BaseStream.Seek(2, SeekOrigin.Current);
            Width  = reader.ReadUInt16();
            Height = reader.ReadUInt16();

            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!");
                }

                long             ddsOffset = reader.BaseStream.Position;
                DDS_Header       header    = new DDS_Header(reader.BaseStream);
                DDSFormatDetails format    = new DDSFormatDetails(header.Format, header.DX10_DXGI_AdditionalHeader.dxgiFormat);
                reader.BaseStream.Seek(ddsOffset, SeekOrigin.Begin);

                byte[] ddsBuffer = reader.ReadBytes(header.dwPitchOrLinearSize + header.dwSize + 128);

                MemoryStream memoryStream = new MemoryStream(ddsBuffer, 0, ddsBuffer.Length, true, true);
                MipMaps = DDSGeneral.LoadDDS(memoryStream, header, 0, format);
                memoryStream.Close();

                Width  = header.Width;
                Height = header.Height;
            }
            else
            {
                // 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
                int paletteEntries = DataCodec.PaletteEntries;
                if (DataFormat == PvrDataFormat.VECTOR_QUANTIZATION_SMALL || DataFormat == PvrDataFormat.VECTOR_QUANTIZATION_SMALL_MIPMAP)
                {
                    if (Width <= 16)
                    {
                        paletteEntries = 64; // Actually 16
                    }
                    else if (Width <= 32)
                    {
                        paletteEntries = 256; // Actually 64
                    }
                    else if (Width <= 64)
                    {
                        paletteEntries = 512; // Actually 128
                    }
                    else
                    {
                        paletteEntries = 1024; // Actually 256
                    }
                }

                // Set the palette and data offsets
                int paletteOffset = 0;
                int dataOffset    = 0;
                if (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
                reader.BaseStream.Seek(baseOffset, SeekOrigin.Begin);
                uint first = reader.ReadUInt32();
                reader.BaseStream.Seek(baseOffset + pvrtOffset + 4, SeekOrigin.Begin);
                uint second = reader.ReadUInt32();
                if (first == second - pvrtOffset + dataOffset + 8)
                {
                    CompressionFormat = PvrCompressionFormat.RLE;
                }
                else
                {
                    CompressionFormat = PvrCompressionFormat.NONE;
                }
                CompressionCodec = PvrCompressionCodec.GetCompressionCodec(CompressionFormat);

                if (CompressionFormat != PvrCompressionFormat.NONE && CompressionCodec != null)
                {
                    //TODO: Convert to stream compatible code
                    throw new NotImplementedException("TODO");
                    //m_encodedData = CompressionCodec.Decompress(m_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
                int[] mipmapOffsets;
                if (DataCodec.HasMipmaps)
                {
                    int mipmapOffset = 0;
                    mipmapOffsets = new int[(int)Math.Log(Width, 2) + 1];

                    // Calculate the padding for the first mipmap offset
                    if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP)
                    {
                        mipmapOffset = (DataCodec.Bpp) >> 3; // A 1x1 mipmap takes up as much space as a 2x1 mipmap
                    }
                    else if (DataFormat == PvrDataFormat.SQUARE_TWIDDLED_MIPMAP_ALT)
                    {
                        mipmapOffset = (3 * DataCodec.Bpp) >> 3; // A 1x1 mipmap takes up as much space as a 2x2 mipmap
                    }
                    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);
                    }
                }
                else
                {
                    mipmapOffsets = new int[1] {
                        0
                    };
                }

                //DecodeMipmaps()
                if (paletteOffset != -1) // The texture contains an embedded palette
                {
                    reader.BaseStream.Seek(baseOffset + paletteOffset, SeekOrigin.Begin);
                    DataCodec.SetPalette(reader, paletteEntries);
                }

                MipMaps = new List <MipMap>();
                if (DataCodec.HasMipmaps)
                {
                    for (int i = 0, size = Width; i < mipmapOffsets.Length; i++, size >>= 1)
                    {
                        reader.BaseStream.Seek(baseOffset + dataOffset + mipmapOffsets[i], SeekOrigin.Begin);
                        byte[] pixels = DataCodec.Decode(reader, size, size, PixelCodec);
                        MipMaps.Add(new MipMap(pixels, size, size));
                    }
                }
                else
                {
                    reader.BaseStream.Seek(baseOffset + dataOffset + mipmapOffsets[0], SeekOrigin.Begin);
                    byte[] pixels = DataCodec.Decode(reader, Width, Height, PixelCodec);
                    MipMaps.Add(new MipMap(pixels, Width, Height));
                }
            }
            if (HasGlobalIndex)
            {
                reader.BaseStream.Seek(baseOffset + ContentSize + 0xC, SeekOrigin.Begin);
            }
            else
            {
                reader.BaseStream.Seek(baseOffset + ContentSize, SeekOrigin.Begin);
            }
        }