parent
9aa0d58d68
commit
b317951c32
@ -0,0 +1,6 @@ |
||||
all: thirdparty/mini-qoi/mqoi.a |
||||
cp thirdparty/mini-qoi/mqoi.a linux-x64/libmqoi.a
|
||||
|
||||
thirdparty/mini-qoi/mqoi.a: |
||||
gcc -O2 -c -o thirdparty/mini-qoi/mqoi.o thirdparty/mini-qoi/src/mini_qoi.c
|
||||
ar -rc thirdparty/mini-qoi/mqoi.a thirdparty/mini-qoi/mqoi.o
|
@ -0,0 +1,122 @@ |
||||
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"); |
||||
|
@ -0,0 +1,9 @@ |
||||
{ |
||||
"provides" : "mqoi", |
||||
"targets" : { |
||||
"linux-x64" : { |
||||
"dependencies" : [], |
||||
"linked-libraries" : ["mqoi", "c"] |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
{ |
||||
// Language version of C3. |
||||
"langrev": "1", |
||||
// Warnings used for all targets. |
||||
"warnings": [ "no-unused" ], |
||||
// Directories where C3 library files may be found. |
||||
"dependency-search-paths": [ ".." ], |
||||
// Libraries to use for all targets. |
||||
"dependencies": [ "mqoi" ], |
||||
// Authors, optionally with email. |
||||
"authors": [ "Alessandro Mauri <alemauri001@gmail.com" ], |
||||
// Version using semantic versioning. |
||||
"version": "0.1.0", |
||||
// Sources compiled for all targets. |
||||
"sources": [ ], |
||||
// C sources if the project also compiles C sources |
||||
// relative to the project file. |
||||
// "c-sources": [ "csource/**" ], |
||||
// Output location, relative to project file. |
||||
"output": "build", |
||||
// Architecture and OS target. |
||||
// You can use 'c3c --list-targets' to list all valid targets. |
||||
// "target": "windows-x64", |
||||
"features": [], |
||||
// Global settings. |
||||
// CPU name, used for optimizations in the LLVM backend. |
||||
"cpu": "generic", |
||||
// Optimization: "O0", "O1", "O2", "O3", "O4", "O5", "Os", "Oz". |
||||
"opt": "O0", |
||||
// See resources/examples/project_all_settings.json and 'c3c --list-project-properties' to see more properties. |
||||
} |
@ -0,0 +1 @@ |
||||
Subproject commit f8b5a8a4d2eeee68b52e143060b7412ba78b5077 |
Binary file not shown.
@ -0,0 +1,130 @@ |
||||
module ugui; |
||||
|
||||
import std::collections::map; |
||||
import std::io; |
||||
import mqoi; |
||||
|
||||
const usz SRITES_PER_ATLAS = 64; |
||||
|
||||
struct Sprite { |
||||
Id id; |
||||
ushort u, v; |
||||
ushort w, h; |
||||
} |
||||
|
||||
def SpriteMap = map::HashMap(<Id, Sprite>); |
||||
|
||||
struct SpriteAtlas { |
||||
Id id; |
||||
Atlas atlas; |
||||
SpriteMap sprites; |
||||
bool should_update; |
||||
} |
||||
|
||||
|
||||
// name: some examples are "icons" or "images" |
||||
fn void! SpriteAtlas.init(&this, String name, AtlasType type, ushort width, ushort height) |
||||
{ |
||||
// FIXME: for now only RGBA32 format is supported |
||||
if (type != ATLAS_RGBA32) { |
||||
return UgAtlasError.INVALID_TYPE?; |
||||
} |
||||
|
||||
this.id = name.hash(); |
||||
this.atlas.new(this.id, AtlasType.ATLAS_RGBA32, width, height)!; |
||||
this.sprites.new_init(capacity: SRITES_PER_ATLAS); |
||||
this.should_update = false; |
||||
} |
||||
|
||||
fn void! SpriteAtlas.free(&this) |
||||
{ |
||||
this.atlas.free(); |
||||
this.sprites.free(); |
||||
} |
||||
|
||||
// FIXME: this should throw an error when a different pixel format than the atlas' is used |
||||
fn Sprite*! SpriteAtlas.insert(&this, String name, char[] pixels, ushort w, ushort h, ushort stride) |
||||
{ |
||||
Sprite s; |
||||
s.id = name.hash(); |
||||
Point uv = this.atlas.place(pixels, w, h, stride)!; |
||||
s.w = w; |
||||
s.h = h; |
||||
s.u = uv.x; |
||||
s.v = uv.y; |
||||
this.sprites.set(s.id, s); |
||||
this.should_update = true; |
||||
return this.sprites.get_ref(s.id); |
||||
} |
||||
|
||||
fn Sprite*! SpriteAtlas.get(&this, String name) |
||||
{ |
||||
Id id = name.hash(); |
||||
return this.sprites.get_ref(id); |
||||
} |
||||
|
||||
fn Sprite*! SpriteAtlas.get_by_id(&this, Id id) |
||||
{ |
||||
return this.sprites.get_ref(id); |
||||
} |
||||
|
||||
fn void! Ctx.sprite_atlas_create(&ctx, String name, AtlasType type, ushort w, ushort h) |
||||
{ |
||||
ctx.sprite_atlas.init(name, type, w, h)!; |
||||
} |
||||
|
||||
fn Id Ctx.get_sprite_atlas_id(&ctx, String name) |
||||
{ |
||||
return name.hash(); |
||||
} |
||||
|
||||
fn void! Ctx.import_sprite_memory(&ctx, String name, char[] pixels, ushort w, ushort h, ushort stride) |
||||
{ |
||||
ctx.sprite_atlas.insert(name, pixels, w, h, stride)!; |
||||
} |
||||
|
||||
fn void! Ctx.import_sprite_file_qoi(&ctx, String name, String path) |
||||
{ |
||||
mqoi::Desc image_desc; |
||||
uint w, h; |
||||
|
||||
File file = file::open(path, "rb")!; |
||||
defer (void) file.close(); |
||||
|
||||
while (!mqoi::desc_done(&image_desc)) { |
||||
mqoi::desc_push(&image_desc, file.read_byte()!); |
||||
} |
||||
if (mqoi::desc_verify(&image_desc, &w, &h) != 0) { |
||||
return IoError.FILE_NOT_VALID?; |
||||
} |
||||
|
||||
mqoi::Dec dec; |
||||
mqoi::Rgba* px; |
||||
|
||||
usz idx; |
||||
char[] pixels = mem::new_array(char, (usz)w*h*4); |
||||
defer mem::free(pixels); |
||||
|
||||
mqoi::dec_init(&dec, w*h); |
||||
while (!mqoi::dec_done(&dec)) { |
||||
mqoi::dec_push(&dec, file.read_byte()!); |
||||
|
||||
while ((px = mqoi::dec_pop(&dec)) != null) { |
||||
pixels[idx..idx+3] = px.value; |
||||
idx += 4; |
||||
} |
||||
} |
||||
|
||||
ctx.sprite_atlas.insert(name, pixels, (ushort)w, (ushort)h, (ushort)w)!; |
||||
} |
||||
|
||||
// FIXME: test function, very different from every other function here |
||||
fn void! Ctx.draw_sprite(&ctx, String name) |
||||
{ |
||||
Sprite* sprite = ctx.sprite_atlas.get(name)!; |
||||
Rect bounds = { 100, 100, sprite.w, sprite.h }; |
||||
Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h }; |
||||
Id tex_id = ctx.sprite_atlas.id; |
||||
|
||||
return ctx.push_sprite(bounds, uv, tex_id)!; |
||||
} |
Loading…
Reference in new issue