Пример #1
0
        private static SpriteIndexInfo[] WriteSprites(BinaryWriter writer, SpriteSetHeader header, List <SpriteEntry> sprites)
        {
            List <SpriteIndexInfo> spriteIndexData = new List <SpriteIndexInfo>();

            int spriteIndex = 0;
            int listIndex   = 0;

            while (listIndex < sprites.Count)
            {
                if (sprites[listIndex].Index == spriteIndex)
                {
                    SpriteIndexInfo spriteWritten = WriteSprite(writer, header, sprites[listIndex].Sprite);
                    spriteIndexData.Add(spriteWritten);
                    ++listIndex;
                }
                else
                {
                    SpriteIndexInfo spriteEmpty = new SpriteIndexInfo(writer.BaseStream.Position);
                    spriteIndexData.Add(spriteEmpty);
                    writer.Write((UInt16)0);
                }

                ++spriteIndex;
            }

            return(spriteIndexData.ToArray());
        }
Пример #2
0
        private static Bitmap ReadSprite(BinaryReader reader, SpriteSetHeader header)
        {
            // TODO(adm244): maybe return PixelFormat instead of bytesPerPixel?
            byte[] buffer = ReadSprite(reader, header, out int width, out int height, out int bytesPerPixel);
            if (buffer == null)
            {
                return(null);
            }

            PixelFormat format = PixelFormatExtension.FromBytesPerPixel(bytesPerPixel);

            if (format == PixelFormat.Indexed)
            {
                return(new Bitmap(width, height, buffer, format, header.Palette));
            }

            Bitmap bitmap = new Bitmap(width, height, buffer, format);

            // NOTE(adm244): since AGS doesn't support 24bpp RLE images it converts them to 32bpp
            // (even if it won't be compressed, you know, 'just in case' case...)
            // in the process alpha channel gets set to 0 (transparent) instead of 255 (opaque)
            // which leads to a problem of fully transparent images (and "features" in GDI decoders)
            //
            // to resolve this issue, we check if alpha channel is used and if not discard it
            if (format == PixelFormat.Argb32 && !IsAlphaChannelUsed(buffer))
            {
                bitmap = bitmap.Convert(PixelFormat.Rgb24);
            }

            return(bitmap);
        }
Пример #3
0
        private static void WriteSpriteSetHeader(BinaryWriter writer, SpriteSetHeader header, int spritesCount)
        {
            writer.Write((UInt16)header.Version);
            writer.Write((char[])SpriteSetSignature.ToCharArray());

            if (header.Version >= 6)
            {
                writer.Write((byte)header.Compression);
                writer.Write((UInt32)header.FileID);
            }

            if (header.Version < 5)
            {
                AGSGraphics.WritePalette(writer, header.Palette);
            }

            if (header.Version < 11)
            {
                writer.Write((UInt16)spritesCount);
            }
            else
            {
                writer.Write((Int32)spritesCount);
            }
        }
Пример #4
0
        public static SpriteSetHeader ReadFromFile(string filepath)
        {
            SpriteSetHeader header = new SpriteSetHeader();

            using (FileStream stream = new FileStream(filepath, FileMode.Open))
            {
                using (BinaryReader reader = new BinaryReader(stream, Encoding.Latin1))
                {
                    header.Version = reader.ReadInt16();

                    header.Compression = CompressionType.Unknown;
                    byte compressionType = reader.ReadByte();
                    if (Enum.IsDefined(typeof(CompressionType), (int)compressionType))
                    {
                        header.Compression = (CompressionType)compressionType;
                    }

                    header.FileID       = reader.ReadUInt32();
                    header.SpritesCount = reader.ReadUInt16();

                    if (header.Version < 5)
                    {
                        header.Palette = AGSGraphics.ReadPalette(reader);
                    }
                }
            }

            return(header);
        }
Пример #5
0
        private static bool UnpackSpritesInternal(string spriteFilePath, string targetFolderPath)
        {
            Console.Write("Opening {0}...", spriteFilePath);

            SpriteSetHeader header = null;

            using (FileStream stream = new FileStream(spriteFilePath, FileMode.Open))
            {
                using (BinaryReader reader = new BinaryReader(stream, Encoding.Latin1))
                {
                    Console.WriteLine(" Done!");
                    Console.Write("Parsing {0}...", spriteFilePath);

                    header = ReadSpriteSetHeader(reader);

                    Console.WriteLine(" Done!");
                    Console.WriteLine("Extracting...");

                    //TODO(adm244): read sprindex.dat

                    for (int index = 0; index <= header.SpritesCount; ++index)
                    {
                        Console.Write(string.Format("\tExtracting spr{0:D5}...", index));

                        Bitmap sprite = ReadSprite(reader, header);
                        if (sprite == null)
                        {
                            Console.WriteLine(" Skipping (empty).");
                            continue;
                        }

                        SaveSprite(sprite, targetFolderPath, index);

                        Console.WriteLine(" Done!");
                    }
                }
            }

            //TODO(adm244): should probably check if file were _actually_ read
            if (header == null)
            {
                Console.WriteLine("Error! Could not read a file.");
                return(false);
            }

            Console.WriteLine("Done!");
            Console.Write("Writting meta file...");

            header.WriteMetaFile(targetFolderPath);

            Console.WriteLine(" Done!");

            return(header.SpritesCount > 0);
        }
Пример #6
0
        //TODO(adm244): ReadSpriteIndexFile

        private static void WriteSpriteIndexFile(string outputFolder, SpriteSetHeader header, SpriteIndexInfo[] spriteIndexInfo, int version)
        {
            // FIXME(adm244): check all filepaths so that they ALL are either RELATIVE or ABSOLUTE
            // because for now some files are saved in a working directory (relative paths)
            // and some in other places (absolute paths)
            string targetFilepath = Path.Combine(outputFolder, SpriteSetIndexFileName);

            using (FileStream stream = new FileStream(targetFilepath, FileMode.Create))
            {
                using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Latin1))
                {
                    writer.Write((char[])SpriteSetIndexSignature.ToCharArray());

                    writer.Write((UInt32)version);

                    if (version >= 2)
                    {
                        writer.Write((UInt32)(header.FileID));
                    }

                    writer.Write((UInt32)(spriteIndexInfo.Length - 1));
                    writer.Write((UInt32)(spriteIndexInfo.Length));

                    for (int i = 0; i < spriteIndexInfo.Length; ++i)
                    {
                        writer.Write((UInt16)spriteIndexInfo[i].Width);
                    }

                    for (int i = 0; i < spriteIndexInfo.Length; ++i)
                    {
                        writer.Write((UInt16)spriteIndexInfo[i].Height);
                    }

                    if (version <= 2)
                    {
                        for (int i = 0; i < spriteIndexInfo.Length; ++i)
                        {
                            writer.Write((UInt32)spriteIndexInfo[i].Offset);
                        }
                    }
                    else
                    {
                        for (int i = 0; i < spriteIndexInfo.Length; ++i)
                        {
                            writer.Write((UInt64)spriteIndexInfo[i].Offset);
                        }
                    }
                }
            }
        }
Пример #7
0
        private static SpriteIndexInfo WriteSprite(BinaryWriter writer, SpriteSetHeader header, Bitmap sprite)
        {
            SpriteIndexInfo spriteIndexData = new SpriteIndexInfo();

            spriteIndexData.Width  = sprite.Width;
            spriteIndexData.Height = sprite.Height;
            spriteIndexData.Offset = writer.BaseStream.Position;

            //NOTE(adm244): AGS doesn't support 24bpp RLE compressed images, so we convert them to 32bpp (null alpha)
            // ALSO, AGS seems to treat 24bpp images as RGB while all others as BGR (!)
            // so let's just NOT use 24bpp and convert them to 32bpp
            if (sprite.Format == PixelFormat.Rgb24)
            {
                sprite = sprite.Convert(PixelFormat.Argb32, discardAlpha: true);
            }

            writer.Write((UInt16)sprite.BytesPerPixel);
            writer.Write((UInt16)sprite.Width);
            writer.Write((UInt16)sprite.Height);

            byte[] buffer = sprite.GetPixels();

            if (header.Compression == CompressionType.RLE)
            {
                buffer = CompressRLE(buffer, sprite.Width, sprite.Height, sprite.BytesPerPixel);
            }

            if (header.Version >= 6)
            {
                if (header.Compression == CompressionType.RLE)
                {
                    writer.Write((UInt32)buffer.Length);
                }
            }
            else if (header.Version == 5)
            {
                writer.Write((UInt32)buffer.Length);
            }

            writer.Write((byte[])buffer);

            return(spriteIndexData);
        }
Пример #8
0
        private static void PackSpritesInternal(string outputFilepath, string headerFilepath, params string[] filepaths)
        {
            SpriteSetHeader    header  = SpriteSetHeader.ReadFromFile(headerFilepath);
            List <SpriteEntry> sprites = GetSortedSpritesList(filepaths);

            using (FileStream stream = new FileStream(outputFilepath, FileMode.Create))
            {
                using (BinaryWriter writer = new BinaryWriter(stream, Encoding.Latin1))
                {
                    int spritesCount = GetLargestIndex(sprites);
                    WriteSpriteSetHeader(writer, header, spritesCount);
                    SpriteIndexInfo[] spritesWritten = WriteSprites(writer, header, sprites);

                    // HACK(adm244): temp solution
                    string indexFilepath = Path.GetDirectoryName(outputFilepath);

                    int version = GetSpriteIndexVersion(header);
                    WriteSpriteIndexFile(indexFilepath, header, spritesWritten, version);
                }
            }
        }
Пример #9
0
        private static int GetSpriteIndexVersion(SpriteSetHeader header)
        {
            switch (header.Version)
            {
            // NOTE(adm244): version 5 is between 3.1.0 and 3.1.2
            // 3.1.0 has version 4; 3.1.2 has version 6
            // guess it was never released? why bump it then?
            case 4:
            case 5:
                return(1);

            case 6:
                return(2);

            case 10:
            case 11:
                return(header.Version);

            default:
                throw new NotSupportedException(
                          $"Cannot determine sprite index file version.\n\nUnknown sprite set version: {header.Version}");
            }
        }
Пример #10
0
        private static byte[] ReadSprite(BinaryReader reader, SpriteSetHeader header, out int width, out int height, out int bytesPerPixel)
        {
            width  = 0;
            height = 0;

            bytesPerPixel = reader.ReadUInt16();
            if (bytesPerPixel == 0)
            {
                return(null);
            }

            width  = reader.ReadUInt16();
            height = reader.ReadUInt16();

            long size             = (long)width * height * bytesPerPixel;
            long sizeUncompressed = size;

            if (header.Version >= 6)
            {
                if (header.Compression == CompressionType.RLE)
                {
                    size = reader.ReadUInt32();
                }
            }
            else if (header.Version == 5)
            {
                size = reader.ReadUInt32();
            }

            if (header.Compression == CompressionType.RLE)
            {
                return(DecompressRLE(reader, size, sizeUncompressed, bytesPerPixel));
            }

            return(reader.ReadBytes((int)size));
        }