//////////////////////////////// //~ Inflator types #define Ase_HuffBitCount 16 Struct(Ase_Bitbuff) { u8 *data; u64 cur_bit; }; typedef i32 Ase_BlockType; enum { 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 typedef i32 Ase_ChunkKind; enum { 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 }; typedef i32 Ase_CelKind; enum { 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; }; //////////////////////////////// //~ Error types Struct(Ase_Error) { String msg; Ase_Error *next; }; Struct(Ase_ErrorList) { u64 count; Ase_Error *first; Ase_Error *last; }; //////////////////////////////// //~ Sheet types Struct(Ase_Slice) { u32 start; i32 x1; i32 y1; i32 x2; i32 y2; Ase_Slice *next; }; Struct(Ase_SliceKey) { String name; u32 num_slices; Ase_Slice *slice_head; Ase_SliceKey *next; }; Struct(Ase_Span) { String name; u32 start; u32 end; Ase_Span *next; }; Struct(Ase_Frame) { u32 index; u32 x1; u32 y1; u32 x2; u32 y2; f64 duration; Ase_Frame *next; }; //////////////////////////////// //~ Decoder result types Struct(Ase_DecodedImage) { u32 width; u32 height; u32 *pixels; /* Array of [width * height] pixels */ Ase_ErrorList errors; b32 success; }; Struct(Ase_DecodedSheet) { Vec2 image_size; Vec2 frame_size; u32 num_frames; u32 num_spans; u32 num_slice_keys; Ase_Frame *frame_head; Ase_Span *span_head; Ase_SliceKey *slice_key_head; Ase_ErrorList errors; b32 success; }; //////////////////////////////// //~ Ase bitbuff operations 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 operations 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 handling operations void Ase_PushError(Arena *arena, Ase_ErrorList *list, String msg_src); //////////////////////////////// //~ Decoder operations //- 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);