module mqoi; macro rgb_hash(Rgb px) => ((px.r * 3 + px.g * 5 + px.b * 7) & 0b00111111); macro mqoi_rgba_hash(Rgba px) => ((px.r * 3 + px.g * 5 + px.b * 7 + px.a * 11) & 0b00111111); const uint MQOI_HEADER_SIZE = 14; const char MQOI_MASK_OP_2B = 0b11000000; const char MQOI_MASK_OP_8B = 0b11111111; const char MQOI_MASK_OP_LUMA_DG = 0b00111111; const char MQOI_MASK_OP_RUN = 0b00111111; // basic types enum DescErr : uint (uint value) { MQOI_DESC_OK = 0, // The descriptor is valid MQOI_DESC_INVALID_MAGIC = 1, // The magic value isn't correct MQOI_DESC_INVALID_CHANNELS = 2, // The channel number isn't valid MQOI_DESC_INVALID_COLORSPACE = 3, // The colorspace isn't valid } enum Op : char (char value) { MQOI_OP2_INDEX = (0b00 << 6), MQOI_OP2_DIFF = (0b01 << 6), MQOI_OP2_LUMA = (0b10 << 6), MQOI_OP2_RUN = (0b11 << 6), MQOI_OP8_RUN_RGB = (0b11111110), MQOI_OP8_RUN_RGBA = (0b11111111), } enum Channels : char (char value) { MQOI_CHANNELS_RGB = 3, MQOI_CHANNELS_RGBA = 4, } enum Colorspace : char (char value) { MQOI_COLORSPACE_SRGB = 0, MQOI_COLORSPACE_LINEAR = 1, } union Rgb { struct { char r, g, b; } char[3] value; } union Rgba{ struct { char r, g, b, a; } char[4] value; } struct Desc { char head; char[4] magic; char[4] width; // big-endian width char[4] height; // big-endian height char channels; char colorspace; } // ==== chunks ==== union Chunk { struct { char head; union { Rgb rgb; Rgba rgba; char drdb; } } char[5] value; } // ==== codecs ==== struct Encoding { Rgba[64] hashtable; Rgba prev_px; Chunk working_chunk; char working_chunk_size; } struct Dec { Rgba[64] hashtable; Rgba prev_px; Chunk curr_chunk; bitstruct : char { char curr_chunk_head : 0..3; char curr_chunk_size : 4..7; } uint pix_left; } // ==== utilities ==== fn void u32_write(uint * n, char * dest) @extern("mqoi_u32_write"); fn void u32_read(char * src, uint * n) @extern("mqoi_u32_read"); // ==== Desc ==== fn void desc_init(Desc* desc) @extern("mqoi_desc_init"); fn void desc_push(Desc* desc, char byte) @extern("mqoi_desc_push"); fn char* desc_pop(Desc* desc) @extern("mqoi_desc_pop"); fn char desc_verify(Desc* desc, uint* w, uint* h) @extern("mqoi_desc_verify"); fn bool desc_done(Desc* desc) @extern("mqoi_desc_done"); /* the encoder is still WIP void mqoi_enc_init(mqoi_enc_t * enc); void mqoi_enc_push(mqoi_enc_t * enc, Rgba * pix) Chunk * mqoi_enc_pop(mqoi_enc_t * enc, char * size); */ // ==== Dec ==== fn void dec_init(Dec* dec, uint n_pix) @extern("mqoi_dec_init"); fn void dec_push(Dec* dec, char byte) @extern("mqoi_dec_push"); fn char dec_take(Dec* dec, char* bytes) @extern("mqoi_dec_take"); fn Rgba* dec_pop(Dec* dec) @extern("mqoi_dec_pop"); fn bool dec_done(Dec* dec) @extern("mqoi_dec_done");