Esempio n. 1
0
        private void Parse(Stream stream)
        {
            var reader = new BinaryReader(stream);

            // wrote these to match the documentation names so it's easier (for me, anyway) to parse
            byte BYTE() => reader.ReadByte();
            ushort WORD() => reader.ReadUInt16();
            short SHORT() => reader.ReadInt16();
            uint DWORD() => reader.ReadUInt32();
            long LONG() => reader.ReadInt32();
            string STRING() => Encoding.UTF8.GetString(BYTES(WORD()));

            byte[] BYTES(int number) => reader.ReadBytes(number);
            void SEEK(int number) => reader.BaseStream.Position += number;

            // Header
            {
                // file size
                DWORD();

                // Magic number (0xA5E0)
                var magic = WORD();
                if (magic != 0xA5E0)
                {
                    throw new Exception("File is not in .ase format");
                }

                // Frames / Width / Height / Color Mode
                frameCount = WORD();
                Width      = WORD();
                Height     = WORD();
                Mode       = (Modes)(WORD() / 8);

                // Other Info, Ignored
                DWORD();       // Flags
                WORD();        // Speed (deprecated)
                DWORD();       // Set be 0
                DWORD();       // Set be 0
                BYTE();        // Palette entry
                SEEK(3);       // Ignore these bytes
                WORD();        // Number of colors (0 means 256 for old sprites)
                BYTE();        // Pixel width
                BYTE();        // Pixel height
                SEEK(92);      // For Future
            }

            // temporary variables
            var       temp    = new byte[Width * Height * (int)Mode];
            var       palette = new Color[256];
            IUserData?last    = null;

            // Frames
            for (int i = 0; i < frameCount; i++)
            {
                var frame = new Frame(this);
                Frames.Add(frame);

                long frameStart, frameEnd;
                int  chunkCount;

                // frame header
                {
                    frameStart = reader.BaseStream.Position;
                    frameEnd   = frameStart + DWORD();
                    WORD();                  // Magic number (always 0xF1FA)
                    chunkCount     = WORD(); // Number of "chunks" in this frame
                    frame.Duration = WORD(); // Frame duration (in milliseconds)
                    SEEK(6);                 // For future (set to zero)
                }

                // chunks
                for (int j = 0; j < chunkCount; j++)
                {
                    long   chunkStart, chunkEnd;
                    Chunks chunkType;

                    // chunk header
                    {
                        chunkStart = reader.BaseStream.Position;
                        chunkEnd   = chunkStart + DWORD();
                        chunkType  = (Chunks)WORD();
                    }

                    // LAYER CHUNK
                    if (chunkType == Chunks.Layer)
                    {
                        // create layer
                        var layer = new Layer();

                        // get layer data
                        layer.Flag       = (Layer.Flags)WORD();
                        layer.Type       = (Layer.Types)WORD();
                        layer.ChildLevel = WORD();
                        WORD(); // width (unused)
                        WORD(); // height (unused)
                        layer.BlendMode = WORD();
                        layer.Alpha     = (BYTE() / 255f);
                        SEEK(3); // for future
                        layer.Name = STRING();

                        last = layer;
                        Layers.Add(layer);
                    }
                    // CEL CHUNK
                    else if (chunkType == Chunks.Cel)
                    {
                        var layer   = Layers[WORD()];
                        var x       = SHORT();
                        var y       = SHORT();
                        var alpha   = BYTE() / 255f;
                        var celType = WORD();
                        var width   = 0;
                        var height  = 0;
                        Color[]? pixels = null;
                        Cel?link = null;

                        SEEK(7);

                        // RAW or DEFLATE
                        if (celType == 0 || celType == 2)
                        {
                            width  = WORD();
                            height = WORD();

                            var count = width * height * (int)Mode;
                            if (count > temp.Length)
                            {
                                temp = new byte[count];
                            }

                            // RAW
                            if (celType == 0)
                            {
                                reader.Read(temp, 0, width * height * (int)Mode);
                            }
                            // DEFLATE
                            else
                            {
                                SEEK(2);

                                using var deflate = new DeflateStream(reader.BaseStream, CompressionMode.Decompress, true);
                                deflate.Read(temp, 0, count);
                            }

                            // get pixel data
                            pixels = new Color[width * height];
                            BytesToPixels(temp, pixels, Mode, palette);
                        }
                        // REFERENCE
                        else if (celType == 1)
                        {
                            var linkFrame = Frames[WORD()];
                            var linkCel   = linkFrame.Cels[frame.Cels.Count];

                            width  = linkCel.Width;
                            height = linkCel.Height;
                            pixels = linkCel.Pixels;
                            link   = linkCel;
                        }
                        else
                        {
                            throw new NotImplementedException();
                        }

                        var cel = new Cel(layer, pixels)
                        {
                            X      = x,
                            Y      = y,
                            Width  = width,
                            Height = height,
                            Alpha  = alpha,
                            Link   = link
                        };

                        // draw to frame if visible
                        if (cel.Layer.Visible)
                        {
                            CelToFrame(frame, cel);
                        }

                        last = cel;
                        frame.Cels.Add(cel);
                    }
                    // PALETTE CHUNK
                    else if (chunkType == Chunks.Palette)
                    {
                        var size  = DWORD();
                        var start = DWORD();
                        var end   = DWORD();
                        SEEK(8); // for future

                        for (int p = 0; p < (end - start) + 1; p++)
                        {
                            var hasName = WORD();
                            palette[start + p] = new Color(BYTE(), BYTE(), BYTE(), BYTE()).Premultiply();

                            if (Calc.IsBitSet(hasName, 0))
                            {
                                STRING();
                            }
                        }
                    }
                    // USERDATA
                    else if (chunkType == Chunks.UserData)
                    {
                        if (last != null)
                        {
                            var flags = (int)DWORD();

                            // has text
                            if (Calc.IsBitSet(flags, 0))
                            {
                                last.UserDataText = STRING();
                            }

                            // has color
                            if (Calc.IsBitSet(flags, 1))
                            {
                                last.UserDataColor = new Color(BYTE(), BYTE(), BYTE(), BYTE()).Premultiply();
                            }
                        }
                    }
                    // TAG
                    else if (chunkType == Chunks.FrameTags)
                    {
                        var count = WORD();
                        SEEK(8);

                        for (int t = 0; t < count; t++)
                        {
                            var tag = new Tag();
                            tag.From          = WORD();
                            tag.To            = WORD();
                            tag.LoopDirection = (Tag.LoopDirections)BYTE();
                            SEEK(8);
                            tag.Color = new Color(BYTE(), BYTE(), BYTE(), (byte)255).Premultiply();
                            SEEK(1);
                            tag.Name = STRING();
                            Tags.Add(tag);
                        }
                    }
                    // SLICE
                    else if (chunkType == Chunks.Slice)
                    {
                        var count = DWORD();
                        var flags = (int)DWORD();
                        DWORD(); // reserved
                        var name = STRING();

                        for (int s = 0; s < count; s++)
                        {
                            var slice = new Slice
                            {
                                Name    = name,
                                Frame   = (int)DWORD(),
                                OriginX = (int)LONG(),
                                OriginY = (int)LONG(),
                                Width   = (int)DWORD(),
                                Height  = (int)DWORD()
                            };

                            // 9 slice (ignored atm)
                            if (Calc.IsBitSet(flags, 0))
                            {
                                slice.NineSlice = new RectInt(
                                    (int)LONG(),
                                    (int)LONG(),
                                    (int)DWORD(),
                                    (int)DWORD());
                            }

                            // pivot point
                            if (Calc.IsBitSet(flags, 1))
                            {
                                slice.Pivot = new Point2((int)DWORD(), (int)DWORD());
                            }

                            last = slice;
                            Slices.Add(slice);
                        }
                    }

                    reader.BaseStream.Position = chunkEnd;
                }

                reader.BaseStream.Position = frameEnd;
            }
        }