//////////////////////////////////////////////////////////// //~ Sheet types Struct(ASE_Slice) { u32 start; Rng2I32 rect; ASE_Slice *next; }; Struct(ASE_Span) { String name; u32 start; u32 end; ASE_Span *next; }; Struct(ASE_Frame) { u32 index; Rng2I32 rect; f64 duration; ASE_Frame *next; }; Struct(ASE_SliceKey) { String name; u32 num_slices; ASE_Slice *first_slice; ASE_SliceKey *next; }; //////////////////////////////////////////////////////////// //~ Decoder result types Struct(ASE_Error) { String msg; ASE_Error *next; }; Struct(ASE_ErrorList) { u64 count; ASE_Error *first; ASE_Error *last; }; Struct(ASE_DecodedImage) { u32 width; u32 height; u32 *pixels; /* Array of [width * height] pixels */ ASE_ErrorList errors; b32 ok; }; Struct(ASE_DecodedSheet) { Vec2 image_size; Vec2 frame_size; u32 num_frames; u32 num_spans; u32 num_slice_keys; ASE_Frame *first_frame; ASE_Span *first_span; ASE_SliceKey *first_slice_key; ASE_ErrorList errors; b32 ok; }; //////////////////////////////////////////////////////////// //~ Inflator types #define ASE_HuffBitCount 16 Struct(ASE_Bitbuff) { u8 *data; u64 cur_bit; }; Enum(ASE_BlockType) { ASE_BlockType_Uncompressed = 0, ASE_BlockType_CompressedFixed = 1, ASE_BlockType_CompressedDynamic = 2, ASE_BlockType_Reserved = 3 }; Struct(ASE_HuffEntry) { u16 symbol; u16 bits_used; }; Struct(ASE_HuffDict) { u32 max_code_bits; u32 entries_count; ASE_HuffEntry *entries; }; //////////////////////////////////////////////////////////// //~ Header types Packed(Struct(ASE_Header) { u32 file_size; u16 magic; u16 frames; u16 width; u16 height; u16 color_depth; u32 flags; u16 speed; u32 _1; u32 _2; u8 palette_entry; u8 _3[3]; u16 num_colors; u8 pixel_width; u8 pixel_height; i16 grid_x; i16 grid_y; u16 grid_width; u16 grid_height; u8 _4[84]; }); Packed(Struct(ASE_FrameHeader) { u32 bytes; u16 magic; u16 chunks_old; u16 frame_duration_ms; u8 _[2]; u32 chunks_new; }); //////////////////////////////////////////////////////////// //~ Image decoder types Enum(ASE_ChunkKind) { ASE_ChunkKind_OldPalette1 = 0x0004, ASE_ChunkKind_OldPalette2 = 0x0011, ASE_ChunkKind_Layer = 0x2004, ASE_ChunkKind_Cel = 0x2005, ASE_ChunkKind_CelExtra = 0x2006, ASE_ChunkKind_ColorProfile = 0x2007, ASE_ChunkKind_ExternalFiles = 0x2008, ASE_ChunkKind_Mask = 0x2016, ASE_ChunkKind_Path = 0x2017, ASE_ChunkKind_Tags = 0x2018, ASE_ChunkKind_Palette = 0x2019, ASE_ChunkKind_Userdata = 0x2020, ASE_ChunkKind_Slice = 0x2022, ASE_ChunkKind_Tileset = 0x2023 }; Enum(ASE_CelKind) { ASE_CelKind_RawImage = 0, ASE_CelKind_Linked = 1, ASE_CelKind_CompressedImage = 2, ASE_CelKind_CompressedTilemap = 3 }; Struct(ASE_Layer) { u16 flags; u16 type; u16 child_level; u16 blend_mode; u8 opacity; String name; u32 tileset_index; u32 index; ASE_Layer *next; }; Struct(Ace_Cel) { u16 layer_index; i16 x_pos; i16 y_pos; u8 opacity; ASE_CelKind type; i16 z_index; /* Linked cel */ u16 frame_pos; /* Compressed image */ u32 width; u32 height; u32 *pixels; u16 frame_index; Ace_Cel *next; }; //////////////////////////////////////////////////////////// //~ Ase bitbuff helpers u32 ASE_PeekBits(ASE_Bitbuff *bb, u32 nbits); u32 ASE_ConsumeBits(ASE_Bitbuff *bb, u32 nbits); void ASE_SkipBits(ASE_Bitbuff *bb, u32 nbits); //////////////////////////////////////////////////////////// //~ Inflate u32 ASE_ReverseBits(u32 v, u32 bit_count); ASE_HuffDict ASE_InitHuffDict(Arena *arena, u32 max_code_bits, u32 *bl_counts, u32 bl_counts_count); u16 ASE_DecodeHuffDict(ASE_HuffDict *huffman, ASE_Bitbuff *bb); void ASE_Inflate(u8 *dst, u8 *encoded); //////////////////////////////////////////////////////////// //~ Error helpers void ASE_PushError(Arena *arena, ASE_ErrorList *list, String msg_src); //////////////////////////////////////////////////////////// //~ Decode helpers u32 ASE_BlendMulU8(u32 a, u32 b); u32 ASE_Blend(u32 src, u32 dst, u8 opacity); void ASE_MakeDimensionsSquareish(ASE_Header *header, u32 *frames_x, u32 *frames_y, u64 *image_width, u64 *image_height); //////////////////////////////////////////////////////////// //~ Decode image ASE_DecodedImage ASE_DecodeImage(Arena *arena, String encoded); //////////////////////////////////////////////////////////// //~ Decode sheet ASE_DecodedSheet ASE_DecodeSheet(Arena *arena, String encoded);