Init new repository

This commit is contained in:
Krzosa Karol
2024-04-13 15:29:53 +02:00
commit 5a2e3dcec4
335 changed files with 61571 additions and 0 deletions

View File

@@ -0,0 +1,7 @@
@echo off
mkdir build
cd build
clang unity_exe.c -o platform.exe -g -O0 -I"../.."
clang unity_dll.c -o game.dll -O0 -shared -g -I"../.." -Wl,-export:APP_Update

View File

@@ -0,0 +1,78 @@
import "shared";
IO_Assertf :: proc(b: bool, s: *char, ...); @foreign
IO_Assert :: proc(b: bool); @foreign
IO_InvalidCodepath :: proc(); @foreign
S8_Lit :: proc(s: *char): S8_String; @foreign
IO_FatalErrorf :: proc(msg: *char, ...); @foreign
IO_FatalError :: proc(msg: *char); @foreign
HashBytes :: proc(data: *void, data_size: u64): u64; @foreign
// @todo: hmm ?
SLL_QUEUE_ADD :: proc(first: *void, last: *void, data: *void); @foreign
Mu: *MU_Context;
Gs: *GameState;
Perm: *MA_Arena;
Temp: *MA_Arena;
R: *R_Render;
GameState :: struct {
render: R_Render;
}
activated: bool;
APP_Update :: proc(event: LibraryEvent, mu: *MU_Context, dll_context: *DLL_Context) {
Mu = mu;
Perm = &dll_context.perm;
Temp = dll_context.temp;
Gs = dll_context.context;
if event == Init {
dll_context.context = MA_PushSize(Perm, :usize(sizeof(:GameState)));
Gs = dll_context.context;
R_Init(&Gs.render);
return;
}
if event == Reload {
R_Reload();
return;
}
if event == Unload {
return;
}
UI_Begin();
Ui.cut = UI_Cut_Top;
UI_PushLayout({});
{
Ui.cut = UI_Cut_Left;
if (UI_Checkbox(&activated, "File")) {
}
UI_Button("Edit");
Ui.cut = UI_Cut_Right;
UI_Button("Memes");
Ui.s.cut_size.x += 100000;
UI_Fill();
UI_PopLayout();
UI_PopStyle();
}
UI_End();
R_Text2D({
pos = {100, 100},
text = S8_Lit("Testing memes"),
color = R_ColorWhite,
do_draw = true,
scale = 1.0,
});
R_Rect2D(R2P_SizeF(200, 200, 100, 100), R.atlas.white_texture_bounding_box, R_ColorWhite);
R_EndFrame();
}

View File

@@ -0,0 +1,122 @@
V2 :: struct { x: f32; y: f32; }
V3 :: struct { x: f32; y: f32; z: f32; }
V4 :: struct { x: f32; y: f32; z: f32; w: f32; }
R2P :: struct { min: V2; max: V2; }
V2I :: struct { x: i32; y: i32; }
V3I :: struct { x: i32; y: i32; z: i32; }
V4I :: struct { x: i32; y: i32; z: i32; w: i32; }
R2P_SizeF :: proc(px: f32, py: f32, sx: f32, sy: f32): R2P {
result: R2P = {{px, py}, {px + sx, py + sy}};
return result;
}
R2P_Size :: proc(pos: V2, size: V2): R2P {
result := :R2P{{pos.x, pos.y}, {pos.x + size.x, pos.y + size.y}};
return result;
}
R2P_GetSize :: proc(r: R2P): V2 {
result := :V2{r.max.x - r.min.x, r.max.y - r.min.y};
return result;
}
V2_Mul :: proc(a: V2, b: V2): V2 {
result := :V2{a.x * b.x, a.y * b.y};
return result;
}
V2_MulF :: proc(a: V2, b: f32): V2 {
result := :V2{a.x * b, a.y * b};
return result;
}
V2_FromV2I :: proc(a: V2I): V2 {
result := :V2{:f32(a.x), :f32(a.y)};
return result;
}
I32_Max :: proc(a: i32, b: i32): i32 {
if a > b return a;
return b;
}
I32_Min :: proc(a: i32, b: i32): i32 {
if a > b return b;
return a;
}
F32_Max :: proc(a: f32, b: f32): f32 {
if a > b return a;
return b;
}
F32_Min :: proc(a: f32, b: f32): f32 {
if a > b return b;
return a;
}
F32_Clamp :: proc(val: f32, min: f32, max: f32): f32 {
if (val > max) return max;
if (val < min) return min;
return val;
}
R2P_CutLeft :: proc(r: *R2P, value: float): R2P {
minx := r.min.x;
r.min.x = F32_Min(r.max.x, r.min.x + value);
return :R2P{
{ minx, r.min.y},
{r.min.x, r.max.y}
};
}
R2P_CutRight :: proc(r: *R2P, value: f32): R2P {
maxx := r.max.x;
r.max.x = F32_Max(r.max.x - value, r.min.x);
return :R2P{
{r.max.x, r.min.y},
{ maxx, r.max.y}
};
}
R2P_CutTop :: proc(r: *R2P, value: f32): R2P { // Y is up
maxy := r.max.y;
r.max.y = F32_Max(r.min.y, r.max.y - value);
return :R2P{
{r.min.x, r.max.y},
{r.max.x, maxy}
};
}
R2P_CutBottom :: proc(r: *R2P, value: f32): R2P { // Y is up
miny := r.min.y;
r.min.y = F32_Min(r.min.y + value, r.max.y);
return :R2P{
{r.min.x, miny},
{r.max.x, r.min.y}
};
}
R2P_Shrink :: proc(r: R2P, size: f32): R2P {
return :R2P{
:V2{r.min.x + size, r.min.y + size},
:V2{r.max.x - size, r.max.y - size}
};
}
R2P_CollidesV2 :: proc(rect: R2P , point: V2): bool {
result := point.x > rect.min.x && point.x < rect.max.x && point.y > rect.min.y && point.y < rect.max.y;
return result;
}
R2P_CollidesR2P :: proc(a: R2P, b: R2P): bool {
result := a.min.x < b.max.x && a.max.x > b.min.x && a.min.y < b.max.y && a.max.y > b.min.y;
return result;
}
V2_Add :: proc(a: V2, b: V2): V2 { return {a.x + b.x, a.y + b.y}; }
V2_Sub :: proc(a: V2, b: V2): V2 { return {a.x - b.x, a.y - b.y}; }
V2_DivF :: proc(a: V2, b: f32): V2 { return {a.x / b, a.y / b}; }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,545 @@
R_CommandBufferSize :: 1024 * 1024;
R_Atlas :: struct {
bitmap : *u32;
sizei : V2I;
size : V2;
inverse_size : V2;
cursor : V2I;
biggest_height : i32;
white_texture_bounding_box : R2P;
texture_id : u32;
padding : V2I;
}
R_FontGlyph :: struct {
size : V2;
offset : V2;
x_advance : f32;
left_side_bearing : f32;
atlas_bounding_box : R2P;
}
R_Font :: struct {
atlas : *R_Atlas;
glyphs : [96]R_FontGlyph;
glyph_count : i32;
first_char : i32;
last_char : i32;
// This is for oversampling
// 0.5 = we draw the font as 2 times smaller then it is.
// Should lead to better quality result.
scaling_transform : f32;
// scaling transform is applied to these
size : f32;
ascent : f32;
descent : f32;
line_gap : f32;
// scaling factor not applied, not sure if these will be useful
scale : f32;
em_scale : f32;
white_texture_bounding_box : R2P;
}
R_Vertex2D :: struct {
pos : V2;
tex : V2;
color: V4;
}
R_CommandKind :: typedef int;
R_CommandKind_Null :: 0;
R_CommandKind_Triangle :: ^;
R_CommandKind_Triangle2D :: ^;
R_Command :: struct {
kind: R_CommandKind;
next: *R_Command;
out : *R_Vertex2D; // user write
data: *R_Vertex2D;
count: i32;
max_count: i32;
}
R_Shader :: struct {
pipeline: u32;
fragment: u32;
vertex : u32;
}
R_Render :: struct {
first_command2d: *R_Command;
last_command2d : *R_Command;
total_vertex_count: u64;
vbo: u32;
vao: u32;
shader2d: R_Shader;
atlas: R_Atlas;
font_medium: R_Font;
font: *R_Font;
}
R_Text2DDesc :: struct {
pos: V2;
text: S8_String;
color: V4;
scale: f32;
do_draw: bool;
rects_arena: *MA_Arena;
}
R_StringMeasure :: struct {
first_rect: *R_RectNode;
last_rect : *R_RectNode;
rect: R2P;
}
R_RectNode :: struct {
next: *R_RectNode;
rect: R2P;
utf8_codepoint_byte_size: i32;
}
R_PackType :: typedef int;
R_PackType_MonoColorFont :: 0;
R_PackType_RGBABitmap :: ^;
R_CreateAtlas :: proc(arena: *MA_Arena, size: V2I, padding: V2I): R_Atlas {
result: R_Atlas;
result.padding = padding;
result.sizei = size;
result.size = V2_FromV2I(size);
result.inverse_size.x = 1.0 / result.size.x;
result.inverse_size.y = 1.0 / result.size.y;
result.bitmap = MA_PushSize(arena, :usize(:i32(sizeof(:u32)) * size.x * size.y));
// Add a whitebox first for rectangle rendering
for y: i32 = 0; y < 16; y += 1 {
for x: i32 = 0; x < 16; x += 1 {
dst := &result.bitmap[x + y * result.sizei.x];
*dst = 0xffffffff;
}
}
// Skipping some pixels to avoid linear interpolation on edges
result.white_texture_bounding_box = :R2P{
{2.0 * result.inverse_size.x, 2.0 / result.size.y},
{14.0 * result.inverse_size.x, 14.0 / result.size.y},
};
result.cursor.x += 16 + padding.x;
result.biggest_height += 16 + padding.y;
return result;
}
R_PackBitmapInvertY :: proc(atlas: *R_Atlas, pack_type: R_PackType, bitmap: *u8, width: i32, height: i32): R2P {
// Packing into a texture atlas
// @Inefficient The algorithm is a simplest thing I had in mind, first we advance
// through the atlas in X packing consecutive glyphs. After we get to the end of the row
// we advance to the next row by the Y size of the biggest packed glyph. If we get to the
// end of atlas and fail to pack everything the app panics.
if (atlas.cursor.x + width > atlas.sizei.x) {
if (atlas.cursor.y + height < atlas.sizei.y) {
atlas.cursor.x = 0;
atlas.cursor.y += atlas.biggest_height + atlas.padding.y;
}
else {
IO_FatalErrorf("Error while packing a font into atlas. Atlas size for this font scale is a bit too small");
}
}
// Write the bitmap with inverted Y
src := bitmap;
// @todo: ambigious syntax, expression parsing doesn't stop at '{', error in wrong place
// for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y++ {
for y := atlas.cursor.y + height - 1; y >= atlas.cursor.y; y -= 1 {
for x := atlas.cursor.x; x < atlas.cursor.x + width; x += 1 {
if (pack_type == R_PackType_RGBABitmap) {
atlas.bitmap[x + y * atlas.sizei.x] = *:*u32(src);
src = &src[4];
continue;
}
if (pack_type == R_PackType_MonoColorFont) {
dst := :*u8(&atlas.bitmap[x + y * atlas.sizei.x]);
dst[0] = 0xFF;
dst[1] = 0xFF;
dst[2] = 0xFF;
dst[3] = *src;
src = &src[1];
continue;
}
IO_InvalidCodepath();
}
}
size := :V2{:f32(width) * atlas.inverse_size.x, :f32(height) * atlas.inverse_size.y};
cursor := V2_FromV2I(atlas.cursor);
pos := V2_Mul(cursor, atlas.inverse_size);
result := R2P_Size(pos, size);
atlas.cursor.x += width + atlas.padding.x;
atlas.biggest_height = I32_Max(atlas.biggest_height, height);
return result;
}
Font_Create :: proc(atlas: *R_Atlas, size: f32, path: S8_String, oversampling: f32): R_Font {
scratch := MA_GetScratch();
font_file := OS_ReadFile(scratch.arena, path);
result: R_Font;
result.scaling_transform = 1.0 / oversampling;
result.size = oversampling * size;
result.first_char = ' ';
result.last_char = '~';
stb_font: stbtt_fontinfo;
if (font_file.len) {
success := stbtt_InitFont(&stb_font, :*uchar(font_file.str), 0);
if (success) {
ascent: int;
descent: int;
gap: int;
stbtt_GetFontVMetrics(&stb_font, &ascent, &descent, &gap);
result.scale = stbtt_ScaleForPixelHeight(&stb_font, result.size);
result.em_scale = stbtt_ScaleForMappingEmToPixels(&stb_font, result.size);
result.ascent = :f32(ascent) * result.scale;
result.descent = :f32(descent) * result.scale;
result.line_gap = :f32(gap) * result.scale;
result.white_texture_bounding_box = atlas.white_texture_bounding_box;
for ascii_symbol := result.first_char; ascii_symbol <= result.last_char; ascii_symbol+=1 {
width: int;
height: int;
xoff: int;
yoff: int;
bitmap := :*u8(stbtt_GetCodepointBitmap(&stb_font, 0, result.scale, :int(ascii_symbol), &width, &height, &xoff, &yoff));
x_advance: int;
left_side_bearing: int;
stbtt_GetCodepointHMetrics(&stb_font, :int(ascii_symbol), &x_advance, &left_side_bearing);
g := &result.glyphs[result.glyph_count];
result.glyph_count += 1;
g.atlas_bounding_box = R_PackBitmapInvertY(atlas, R_PackType_MonoColorFont, bitmap, :i32(width), :i32(height));
g.size = :V2{:f32(width), :f32(height)};
// Offset y needs to be inverted cause bitmap has inverted Y
g.offset = :V2{:f32(xoff), -(g.size.y + :f32(yoff))};
g.x_advance = :f32(x_advance) * result.scale;
g.left_side_bearing = :f32(left_side_bearing) * result.scale;
// Apply scaling transform
g.offset = V2_MulF(g.offset, result.scaling_transform);
g.x_advance = g.x_advance * result.scaling_transform;
g.left_side_bearing = g.left_side_bearing * result.scaling_transform;
g.size = V2_MulF(g.size, result.scaling_transform);
stbtt_FreeBitmap(:*uchar(bitmap), nil);
}
result.ascent *= result.scaling_transform;
result.descent *= result.scaling_transform;
result.size *= result.scaling_transform;
result.line_gap *= result.scaling_transform;
}
}
MA_EndTemp(scratch);
return result;
}
Font_GetGlyph :: proc(font: *R_Font, codepoint: i32): *R_FontGlyph {
is_in_range := codepoint >= font.first_char && codepoint <= font.last_char;
if (is_in_range) {
index := codepoint - font.first_char;
return &font.glyphs[index];
}
else {
index := '?' - font.first_char;
return &font.glyphs[index];
}
}
GL_DebugCallback :: proc(source: GLenum @unused, type: GLenum @unused, id: GLuint @unused, severity: GLenum, length: GLsizei @unused, message: *GLchar, user: *void @unused) {
IO_Printf("%s\n", message);
if (severity == GL_DEBUG_SEVERITY_HIGH || severity == GL_DEBUG_SEVERITY_MEDIUM) {
IO_FatalErrorf("%s", message);
}
}
GL_SetProcAddress :: proc(p: *void, name: *char) {
pp := :**void(p);
*pp = Mu.gl_get_proc_address(name);
}
GL_LoadProcs :: proc() {
load_up_to(4, 5, :*void(GL_SetProcAddress));
glDebugMessageCallback(:*void(GL_DebugCallback), nil);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
}
R_Reload :: proc() {
GL_LoadProcs();
}
R_Init :: proc(render: *R_Render) {
R = render;
GL_LoadProcs();
atlas := R_CreateAtlas(Temp, :V2I{1024, 1024}, :V2I{4, 4});
R.font_medium = Font_Create(&atlas, 32, S8_Lit("C:/windows/fonts/Calibri.ttf"), 1.0);
{
glCreateTextures(GL_TEXTURE_2D, 1, &atlas.texture_id);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(atlas.texture_id, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureStorage2D(atlas.texture_id, 1, GL_RGBA8, :i32(atlas.sizei.x), :i32(atlas.sizei.y));
glTextureSubImage2D(atlas.texture_id, 0, 0, 0, :i32(atlas.sizei.x), :i32(atlas.sizei.y), GL_RGBA, GL_UNSIGNED_BYTE, atlas.bitmap);
}
R.atlas = atlas;
R.font_medium.atlas = &R.atlas;
R.font = &R.font_medium;
glCreateBuffers(1, &R.vbo);
glNamedBufferStorage(R.vbo, R_CommandBufferSize, nil, GL_DYNAMIC_STORAGE_BIT);
{
glCreateVertexArrays(1, &R.vao);
vbuf_index: u32 = 0;
glVertexArrayVertexBuffer(R.vao, vbuf_index, R.vbo, 0, :i32(sizeof(:R_Vertex2D)));
a_pos: u32 = 0;
pos_offset: u32 = #`offsetof(R_Vertex2D, pos)`;
glVertexArrayAttribFormat(R.vao, a_pos, 2, GL_FLOAT, GL_FALSE, pos_offset);
glVertexArrayAttribBinding(R.vao, a_pos, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_pos);
a_tex: u32 = 1;
tex_offset: u32 = #`offsetof(R_Vertex2D, tex)`;
glVertexArrayAttribFormat(R.vao, a_tex, 2, GL_FLOAT, GL_FALSE, tex_offset);
glVertexArrayAttribBinding(R.vao, a_tex, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_tex);
a_color: u32 = 2;
color_offset: u32 = #`offsetof(R_Vertex2D, color)`; // @todo
glVertexArrayAttribFormat(R.vao, a_color, 4, GL_FLOAT, GL_FALSE, color_offset);
glVertexArrayAttribBinding(R.vao, a_color, vbuf_index);
glEnableVertexArrayAttrib(R.vao, a_color);
}
vshader := `#version 450 core
layout(location=0) uniform vec2 U_InvHalfScreenSize;
layout(location=0) in vec2 IN_Pos;
layout(location=1) in vec2 IN_Tex;
layout(location=2) in vec4 IN_Color;
out gl_PerVertex { vec4 gl_Position; }; // required because of ARB_separate_shader_objects
out vec2 OUT_UV;
out vec4 OUT_Color;
void main() {
vec2 pos = IN_Pos * U_InvHalfScreenSize;
pos -= vec2(1, 1);
gl_Position = vec4(pos, 0, 1);
OUT_UV = IN_Tex;
OUT_Color = IN_Color;
}
`;
fshader := `#version 450 core
in vec2 IN_UV;
in vec4 IN_Color;
layout (binding=0) uniform sampler2D S_Texture;
layout (location=0) out vec4 OUT_Color;
void main() {
vec4 c = IN_Color;
vec4 texture_color = texture(S_Texture, IN_UV);
OUT_Color = c * texture_color;
}
`;
R.shader2d = R_CreateShader(vshader, fshader);
}
R_CreateShader :: proc(glsl_vshader: *char, glsl_fshader: *char): R_Shader {
result: R_Shader;
result.vertex = glCreateShaderProgramv(GL_VERTEX_SHADER, 1, &glsl_vshader);
result.fragment = glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &glsl_fshader);
linked: i32;
glGetProgramiv(result.vertex, GL_LINK_STATUS, &linked);
if (!linked) {
message: [1024]char;
glGetProgramInfoLog(result.vertex, :i32(sizeof(message)), nil, :*u8(&message[0]));
IO_FatalErrorf("[GL] Failed to create vertex shader! %s", message);
}
glGetProgramiv(result.fragment, GL_LINK_STATUS, &linked);
if (!linked) {
message: [1024]char;
glGetProgramInfoLog(result.fragment, :i32(sizeof(message)), nil, :*u8(&message[0]));
IO_FatalErrorf("[GL] Failed to create fragment shader! %s", message);
}
glGenProgramPipelines(1, &result.pipeline);
glUseProgramStages(result.pipeline, GL_VERTEX_SHADER_BIT, result.vertex);
glUseProgramStages(result.pipeline, GL_FRAGMENT_SHADER_BIT, result.fragment);
return result;
}
R_GetCommand :: proc(kind: R_CommandKind, vcount_to_add: i32): *R_Command {
make_new := R.last_command2d == 0 ||
R.last_command2d.kind != kind ||
R.last_command2d.count + vcount_to_add > R.last_command2d.max_count;
if make_new {
sizeof_r_command: usize = #`sizeof(R_Command)`;
c: *R_Command = MA_PushSize(Temp, sizeof_r_command);
c.kind = kind;
c.data = MA_PushSizeNonZeroed(Temp, R_CommandBufferSize);
if (kind == R_CommandKind_Triangle2D) {
c.max_count = R_CommandBufferSize / :i32(sizeof(:R_Vertex2D));
SLL_QUEUE_ADD(R.first_command2d, R.last_command2d, c);
}
else IO_InvalidCodepath();
}
c := R.last_command2d;
c.out = &c.data[c.count];
c.count += vcount_to_add;
R.total_vertex_count += :u64(vcount_to_add);
return c;
}
R_Rect2D :: proc(rect: R2P, tex: R2P, color: V4) {
c := R_GetCommand(R_CommandKind_Triangle2D, 6);
c.out[0].pos = :V2{rect.min.x, rect.max.y};
c.out[0].tex = :V2{tex.min.x, tex.max.y};
c.out[0].color = color;
c.out[1].pos = :V2{rect.max.x, rect.max.y};
c.out[1].tex = :V2{tex.max.x, tex.max.y};
c.out[1].color = color;
c.out[2].pos = :V2{rect.min.x, rect.min.y};
c.out[2].tex = :V2{tex.min.x, tex.min.y};
c.out[2].color = color;
c.out[3].pos = :V2{rect.min.x, rect.min.y};
c.out[3].tex = :V2{tex.min.x, tex.min.y};
c.out[3].color = color;
c.out[4].pos = :V2{rect.max.x, rect.max.y};
c.out[4].tex = :V2{tex.max.x, tex.max.y};
c.out[4].color = color;
c.out[5].pos = :V2{rect.max.x, rect.min.y};
c.out[5].tex = :V2{tex.max.x, tex.min.y};
c.out[5].color = color;
}
R_Text2D :: proc(params: R_Text2DDesc): R_StringMeasure {
result: R_StringMeasure;
original_pos := params.pos;
max_pos := params.pos;
pos := params.pos;
scale := params.scale;
for iter := UTF8_IterateEx(params.text.str, :int(params.text.len)); iter.item /*;UTF8_Advance(&iter)@todo*/ {
it: u32 = iter.item;
if it == '\n' {
pos.x = original_pos.x;
pos.y -= R.font.size * scale;
if (pos.x > max_pos.x) max_pos.x = pos.x;
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
continue;
}
g: *R_FontGlyph = Font_GetGlyph(R.font, :i32(it));
sym_pos := pos;
pos.x += g.x_advance * scale;
if (pos.x > max_pos.x) max_pos.x = pos.x;
if (pos.y < max_pos.y) max_pos.y = pos.y; // @warning: min position y actually
sym_pos.x += g.offset.x * scale;
sym_pos.y += g.offset.y * scale;
minp: V2 = {sym_pos.x, sym_pos.y};
rect: R2P = R2P_Size(minp, V2_MulF(g.size, scale));
if (params.do_draw) {
R_Rect2D(rect, g.atlas_bounding_box, params.color);
}
if (params.rects_arena) {
node: *R_RectNode = MA_PushSize(params.rects_arena, :usize(sizeof(:R_RectNode)));
node.rect = rect;
node.utf8_codepoint_byte_size = :i32(iter.utf8_codepoint_byte_size);
SLL_QUEUE_ADD(result.first_rect, result.last_rect, node);
}
UTF8_Advance(&iter); // @todo
}
result.rect = {
{original_pos.x, max_pos.y + R.font.descent * scale}, /* @warning: min position y actually */
{max_pos.x, original_pos.y + R.font.ascent * scale},
};
return result;
}
R_GetTextSize :: proc(text: S8_String): f32 {
m := R_Text2D({text = text, scale = 1.0});
size := R2P_GetSize(m.rect).x;
return size;
}
R_ColorWhite: V4 = {1,1,1,1};
R_ColorBlack: V4 = {0,0,0,1};
R_DrawText :: proc(text: S8_String, pos: V2, color: V4): R_StringMeasure {
result := R_Text2D({text = text, color = color, pos = pos, do_draw = true, scale = 1.0});
return result;
}
R_EndFrame :: proc() {
ws := :V2{:f32(Mu.window.size.x), :f32(Mu.window.size.y)};
wsi := :V2I{:i32(Mu.window.size.x), :i32(Mu.window.size.y)};
x: f32 = 1 / (ws.x / 2);
y: f32 = 1 / (ws.y / 2);
glViewport(0, 0, wsi.x, wsi.y);
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
// Default draw using the font texture
{
glBindProgramPipeline(R.shader2d.pipeline);
glProgramUniform2f(R.shader2d.vertex, 0, x, y);
for it := R.first_command2d; it; it = it.next {
if (it.kind == R_CommandKind_Triangle2D) {
glNamedBufferSubData(R.vbo, 0, :int(it.count) * :int(sizeof(:R_Vertex2D)), it.data);
glBindVertexArray(R.vao);
s_texture: u32 = 0; // texture unit that sampler2D will use in GLSL code
glBindTextureUnit(s_texture, R.font.atlas.texture_id);
glDrawArrays(GL_TRIANGLES, 0, it.count);
continue;
}
IO_InvalidCodepath();
}
}
R.first_command2d = nil;
R.last_command2d = nil;
R.total_vertex_count = 0;
}

View File

@@ -0,0 +1,183 @@
#`#include "vendor/stb_truetype.c"`;
@foreign stbrp_rect :: struct {f: int;}
@foreign
stbtt__buf :: struct {
data: *uchar;
cursor: int;
size: int;
}
@foreign
stbtt_bakedchar :: struct {
x0: ushort;
y0: ushort;
x1: ushort;
y1: ushort;
xoff: float;
yoff: float;
xadvance: float;
}
@foreign stbtt_BakeFontBitmap :: proc(data: *uchar, offset: int, pixel_height: float, pixels: *uchar, pw: int, ph: int, first_char: int, num_chars: int, chardata: *stbtt_bakedchar): int;
@foreign
stbtt_aligned_quad :: struct {
x0: float;
y0: float;
s0: float;
t0: float;
x1: float;
y1: float;
s1: float;
t1: float;
}
@foreign stbtt_GetBakedQuad :: proc(chardata: *stbtt_bakedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, opengl_fillrule: int);
@foreign stbtt_GetScaledFontVMetrics :: proc(fontdata: *uchar, index: int, size: float, ascent: *float, descent: *float, lineGap: *float);
@foreign
stbtt_packedchar :: struct {
x0: ushort;
y0: ushort;
x1: ushort;
y1: ushort;
xoff: float;
yoff: float;
xadvance: float;
xoff2: float;
yoff2: float;
}
@foreign stbtt_PackBegin :: proc(spc: *stbtt_pack_context, pixels: *uchar, width: int, height: int, stride_in_bytes: int, padding: int, alloc_context: *void): int;
@foreign stbtt_PackEnd :: proc(spc: *stbtt_pack_context);
@foreign stbtt_PackFontRange :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, font_size: float, first_unicode_char_in_range: int, num_chars_in_range: int, chardata_for_range: *stbtt_packedchar): int;
@foreign
stbtt_pack_range :: struct {
font_size: float;
first_unicode_codepoint_in_range: int;
array_of_unicode_codepoints: *int;
num_chars: int;
chardata_for_range: *stbtt_packedchar;
h_oversample: uchar;
v_oversample: uchar;
}
@foreign stbtt_PackFontRanges :: proc(spc: *stbtt_pack_context, fontdata: *uchar, font_index: int, ranges: *stbtt_pack_range, num_ranges: int): int;
@foreign stbtt_PackSetOversampling :: proc(spc: *stbtt_pack_context, h_oversample: uint, v_oversample: uint);
@foreign stbtt_PackSetSkipMissingCodepoints :: proc(spc: *stbtt_pack_context, skip: int);
@foreign stbtt_GetPackedQuad :: proc(chardata: *stbtt_packedchar, pw: int, ph: int, char_index: int, xpos: *float, ypos: *float, q: *stbtt_aligned_quad, align_to_integer: int);
@foreign stbtt_PackFontRangesGatherRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
@foreign stbtt_PackFontRangesPackRects :: proc(spc: *stbtt_pack_context, rects: *stbrp_rect, num_rects: int);
@foreign stbtt_PackFontRangesRenderIntoRects :: proc(spc: *stbtt_pack_context, info: *stbtt_fontinfo, ranges: *stbtt_pack_range, num_ranges: int, rects: *stbrp_rect): int;
@foreign
stbtt_pack_context :: struct {
user_allocator_context: *void;
pack_info: *void;
width: int;
height: int;
stride_in_bytes: int;
padding: int;
skip_missing: int;
h_oversample: uint;
v_oversample: uint;
pixels: *uchar;
nodes: *void;
}
@foreign stbtt_GetNumberOfFonts :: proc(data: *uchar): int;
@foreign stbtt_GetFontOffsetForIndex :: proc(data: *uchar, index: int): int;
@foreign
stbtt_fontinfo :: struct {
userdata: *void;
data: *uchar;
fontstart: int;
numGlyphs: int;
loca: int;
head: int;
glyf: int;
hhea: int;
hmtx: int;
kern: int;
gpos: int;
svg: int;
index_map: int;
indexToLocFormat: int;
cff: stbtt__buf;
charstrings: stbtt__buf;
gsubrs: stbtt__buf;
subrs: stbtt__buf;
fontdicts: stbtt__buf;
fdselect: stbtt__buf;
}
@foreign stbtt_InitFont :: proc(info: *stbtt_fontinfo, data: *uchar, offset: int): int;
@foreign stbtt_FindGlyphIndex :: proc(info: *stbtt_fontinfo, unicode_codepoint: int): int;
@foreign stbtt_ScaleForPixelHeight :: proc(info: *stbtt_fontinfo, pixels: float): float;
@foreign stbtt_ScaleForMappingEmToPixels :: proc(info: *stbtt_fontinfo, pixels: float): float;
@foreign stbtt_GetFontVMetrics :: proc(info: *stbtt_fontinfo, ascent: *int, descent: *int, lineGap: *int);
@foreign stbtt_GetFontVMetricsOS2 :: proc(info: *stbtt_fontinfo, typoAscent: *int, typoDescent: *int, typoLineGap: *int): int;
@foreign stbtt_GetFontBoundingBox :: proc(info: *stbtt_fontinfo, x0: *int, y0: *int, x1: *int, y1: *int);
@foreign stbtt_GetCodepointHMetrics :: proc(info: *stbtt_fontinfo, codepoint: int, advanceWidth: *int, leftSideBearing: *int);
@foreign stbtt_GetCodepointKernAdvance :: proc(info: *stbtt_fontinfo, ch1: int, ch2: int): int;
@foreign stbtt_GetCodepointBox :: proc(info: *stbtt_fontinfo, codepoint: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
@foreign stbtt_GetGlyphHMetrics :: proc(info: *stbtt_fontinfo, glyph_index: int, advanceWidth: *int, leftSideBearing: *int);
@foreign stbtt_GetGlyphKernAdvance :: proc(info: *stbtt_fontinfo, glyph1: int, glyph2: int): int;
@foreign stbtt_GetGlyphBox :: proc(info: *stbtt_fontinfo, glyph_index: int, x0: *int, y0: *int, x1: *int, y1: *int): int;
@foreign
stbtt_kerningentry :: struct {
glyph1: int;
glyph2: int;
advance: int;
}
@foreign stbtt_GetKerningTableLength :: proc(info: *stbtt_fontinfo): int;
@foreign stbtt_GetKerningTable :: proc(info: *stbtt_fontinfo, table: *stbtt_kerningentry, table_length: int): int;
@foreign
stbtt_vertex :: struct {
x: short;
y: short;
cx: short;
cy: short;
cx1: short;
cy1: short;
type: uchar;
padding: uchar;
}
@foreign stbtt_IsGlyphEmpty :: proc(info: *stbtt_fontinfo, glyph_index: int): int;
@foreign stbtt_GetCodepointShape :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, vertices: **stbtt_vertex): int;
@foreign stbtt_GetGlyphShape :: proc(info: *stbtt_fontinfo, glyph_index: int, vertices: **stbtt_vertex): int;
@foreign stbtt_FreeShape :: proc(info: *stbtt_fontinfo, vertices: *stbtt_vertex);
@foreign stbtt_FindSVGDoc :: proc(info: *stbtt_fontinfo, gl: int): *uchar;
@foreign stbtt_GetCodepointSVG :: proc(info: *stbtt_fontinfo, unicode_codepoint: int, svg: **char): int;
@foreign stbtt_GetGlyphSVG :: proc(info: *stbtt_fontinfo, gl: int, svg: **char): int;
@foreign stbtt_FreeBitmap :: proc(bitmap: *uchar, userdata: *void);
@foreign stbtt_GetCodepointBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_MakeCodepointBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, codepoint: int);
@foreign stbtt_MakeCodepointBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, codepoint: int);
@foreign stbtt_MakeCodepointBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, codepoint: int);
@foreign stbtt_GetCodepointBitmapBox :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetCodepointBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, codepoint: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetGlyphBitmap :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_MakeGlyphBitmap :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, glyph: int);
@foreign stbtt_MakeGlyphBitmapSubpixel :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, glyph: int);
@foreign stbtt_MakeGlyphBitmapSubpixelPrefilter :: proc(info: *stbtt_fontinfo, output: *uchar, out_w: int, out_h: int, out_stride: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, oversample_x: int, oversample_y: int, sub_x: *float, sub_y: *float, glyph: int);
@foreign stbtt_GetGlyphBitmapBox :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign stbtt_GetGlyphBitmapBoxSubpixel :: proc(font: *stbtt_fontinfo, glyph: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, ix0: *int, iy0: *int, ix1: *int, iy1: *int);
@foreign
stbtt__bitmap :: struct {
w: int;
h: int;
stride: int;
pixels: *uchar;
}
@foreign stbtt_Rasterize :: proc(result: *stbtt__bitmap, flatness_in_pixels: float, vertices: *stbtt_vertex, num_verts: int, scale_x: float, scale_y: float, shift_x: float, shift_y: float, x_off: int, y_off: int, invert: int, userdata: *void);
@foreign stbtt_FreeSDF :: proc(bitmap: *uchar, userdata: *void);
@foreign stbtt_GetGlyphSDF :: proc(info: *stbtt_fontinfo, scale: float, glyph: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_GetCodepointSDF :: proc(info: *stbtt_fontinfo, scale: float, codepoint: int, padding: int, onedge_value: uchar, pixel_dist_scale: float, width: *int, height: *int, xoff: *int, yoff: *int): *uchar;
@foreign stbtt_FindMatchingFont :: proc(fontdata: *uchar, name: *char, flags: int): int;
@foreign stbtt_CompareUTF8toUTF16_bigendian :: proc(s1: *char, len1: int, s2: *char, len2: int): int;
@foreign stbtt_GetFontNameString :: proc(font: *stbtt_fontinfo, length: *int, platformID: int, encodingID: int, languageID: int, nameID: int): *char;

View File

@@ -0,0 +1,342 @@
Ui: UI_State;
UI_TextAlign :: typedef int;
UI_TextAlign_Center :: 0;
UI_TextAlign_CenterLeft :: ^;
UI_Layout :: struct {
rect: R2P;
}
UI_Widget :: struct {
next: *UI_Widget;
id: u64;
last_touched_frame_index: u64;
}
UI_Cut :: typedef int;
UI_Cut_Left :: 0;
UI_Cut_Right :: ^;
UI_Cut_Top :: ^;
UI_Cut_Bottom :: ^;
UI_Style :: struct {
cut_size: V2;
text_align: UI_TextAlign;
scroll: V2;
absolute: bool;
absolute_rect: R2P;
button_background_color: V4;
hot_button_background_color: V4;
interacting_with_button_background_color: V4;
active_button_background_color: V4;
text_color: V4;
button_border_color: V4;
checked_checkbox_button_background_color: V4;
draw_text_shadow: bool;
}
UI_BaseButtonDesc :: struct {
text: S8_String;
draw_text: bool;
draw_border: bool;
draw_background: bool;
use_checked_checkbox_button_background_colors: bool;
}
UI_Result :: struct {
pressed: bool;
interacting_with: bool;
hot: bool;
drag: V2;
}
UI_LayoutStack :: struct {
data: [256]UI_Layout;
len : i32;
}
UI_State :: struct {
cut: UI_Cut;
s: UI_Style; // current style
base_style: UI_Style;
// @todo: add stack id concept
cached_widgets: LC_Map; // @todo: add removing widgets at end of frame
layouts: UI_LayoutStack;
font: *R_Font;
hot: u64;
interacting_with: u64;
id: u64;
inside_begin_end_pair: bool;
// next cut output
text_width: f32;
text_size: V2;
}
UI_AddLayout :: proc(s: *UI_LayoutStack, layout: UI_Layout) {
if s.len + 1 > lengthof(s.data) {
IO_FatalErrorf("layout stack overflow reached max item count: %d", lengthof(s.data));
}
s.data[s.len] = layout;
s.len += 1;
}
UI_GetLastLayout :: proc(s: *UI_LayoutStack): *UI_Layout {
if (s.len == 0) IO_FatalErrorf("error, trying to get last layout but there are none");
return &s.data[s.len - 1];
}
UI_Begin :: proc() {
IO_Assert(Ui.inside_begin_end_pair == false);
Ui.inside_begin_end_pair = true;
IO_Assert(Ui.layouts.len == 0 || Ui.layouts.len == 1);
Ui.layouts.len = 0;
UI_AddLayout(&Ui.layouts, {R2P_SizeF(0, 0, :f32(Mu.window.size.x), :f32(Mu.window.size.y))});
UI_SetStyle();
}
UI_SetStyle :: proc() {
Ui.font = R.font;
Ui.base_style = {
cut_size = :V2{-1, Ui.font.size + 4},
button_background_color = :V4{0, 0, 0, 1.0},
text_color = :V4{1, 1, 1, 1},
button_border_color = :V4{1, 1, 1, 1},
checked_checkbox_button_background_color = :V4{0.5, 0.5, 0.5, 1.0},
hot_button_background_color = :V4{0.5, 0, 0, 1},
interacting_with_button_background_color = :V4{1.0, 0, 0, 1},
active_button_background_color = :V4{1, 0, 0, 1},
};
Ui.s = Ui.base_style;
}
UI_End :: proc() {
IO_Assert(Ui.inside_begin_end_pair);
Ui.inside_begin_end_pair = false;
if (Mu.window.mouse.left.unpress) {
Ui.interacting_with = NULL;
}
Ui.hot = NULL;
}
R_DrawBorder :: proc(r: R2P, color: V4) {
r = R2P_Shrink(r, 1);
R_Rect2D(R2P_CutLeft(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutRight(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutTop(&r, 1), R.atlas.white_texture_bounding_box, color);
R_Rect2D(R2P_CutBottom(&r, 1), R.atlas.white_texture_bounding_box, color);
}
UI_GetNextRect :: proc(text: S8_String): R2P {
if (Ui.s.absolute) return Ui.s.absolute_rect;
l := UI_GetLastLayout(&Ui.layouts);
cut := Ui.s.cut_size;
font := Ui.font;
if (text.len) {
Ui.text_width = R_GetTextSize(text);
Ui.text_size = :V2{Ui.text_width, font.ascent};
}
if (cut.x < 0) {
cut.x = Ui.text_width + 32;
if (cut.x < 0) {
cut.x = 32;
}
}
if (cut.y < 0) {
cut.y = font.ascent;
}
if (Ui.cut == UI_Cut_Top || Ui.cut == UI_Cut_Bottom) {
scroll_y := F32_Clamp(Ui.s.scroll.y, -cut.y, cut.y);
cut.y -= scroll_y;
Ui.s.scroll.y -= scroll_y;
}
if (Ui.cut == UI_Cut_Left || Ui.cut == UI_Cut_Right) {
scrollx := F32_Clamp(Ui.s.scroll.x, -cut.x, cut.x);
cut.x -= scrollx;
Ui.s.scroll.x -= scrollx;
}
if (Ui.cut == UI_Cut_Left) {
return R2P_CutLeft(&l.rect, cut.x);
}
if (Ui.cut == UI_Cut_Right) {
return R2P_CutRight(&l.rect, cut.x);
}
if (Ui.cut == UI_Cut_Top) {
return R2P_CutTop(&l.rect, cut.y);
}
if (Ui.cut == UI_Cut_Bottom) {
return R2P_CutBottom(&l.rect, cut.y);
}
IO_InvalidCodepath();
return :R2P{};
}
UI_GetWidget :: proc(text: S8_String): *UI_Widget {
if (Ui.cached_widgets.allocator.p == NULL) {
Ui.cached_widgets.allocator = Perm.allocator;
}
hash := HashBytes(text.str, :u64(text.len));
widget: *UI_Widget = LC_MapGetU64(&Ui.cached_widgets, hash);
if (!widget) {
widget = MA_PushSize(Perm, :usize(sizeof(:UI_Widget)));
widget.id = hash;
LC_MapInsertU64(&Ui.cached_widgets, hash, widget);
}
IO_Assert(widget.id == hash);
widget.last_touched_frame_index = :u64(Mu.frame);
return widget;
}
UI_BaseButton :: proc(desc: UI_BaseButtonDesc): UI_Result {
result: UI_Result;
rect := UI_GetNextRect(desc.text);
mouse_pos: V2 = {:f32(Mu.window.mouse.pos.x), :f32(Mu.window.mouse.pos.y)};
delta_mouse_pos: V2 = {:f32(Mu.window.mouse.delta_pos.x), :f32(Mu.window.mouse.delta_pos.y)};
if (rect.min.x == rect.max.x || rect.min.y == rect.max.y) {
return result;
}
widget := UI_GetWidget(desc.text);
if (R2P_CollidesV2(rect, mouse_pos)) {
Ui.hot = widget.id;
}
if (Ui.hot == widget.id) {
result.hot = true;
if (Mu.window.mouse.left.press) {
Ui.interacting_with = widget.id;
}
}
if (Ui.interacting_with == widget.id) {
result.interacting_with = true;
result.drag = delta_mouse_pos;
if (Ui.hot == widget.id && Mu.window.mouse.left.unpress) {
result.pressed = true;
}
}
text_pos := rect.min;
rect_size := R2P_GetSize(rect);
centered_text_pos := V2_Add(text_pos, V2_DivF(V2_Sub(rect_size, Ui.text_size), 2.0));
if (Ui.s.text_align == UI_TextAlign_Center) {
text_pos = centered_text_pos;
}
if (Ui.s.text_align == UI_TextAlign_CenterLeft) {
text_pos.y = centered_text_pos.y;
text_pos.x += 4;
}
button_background_color: V4 = Ui.s.button_background_color;
text_color: V4 = Ui.s.text_color;
button_border_color: V4 = Ui.s.button_border_color;
if (desc.use_checked_checkbox_button_background_colors) {
button_background_color = Ui.s.checked_checkbox_button_background_color;
}
if (Ui.hot == widget.id) {
button_background_color = Ui.s.hot_button_background_color;
}
if (Ui.interacting_with == widget.id) {
button_background_color = Ui.s.interacting_with_button_background_color;
}
if (result.pressed) {
button_background_color = Ui.s.active_button_background_color;
}
if (desc.draw_background) {
R_Rect2D(rect, R.atlas.white_texture_bounding_box, button_background_color);
}
if (desc.draw_border) {
R_DrawBorder(rect, button_border_color);
}
if (desc.draw_text) {
if (Ui.s.draw_text_shadow) {
R_Text2D({
text = desc.text,
color = R_ColorWhite,
pos = :V2{text_pos.x + 2, text_pos.y - 2},
do_draw = true,
scale = 1.0,
});
}
R_DrawText(desc.text, text_pos, text_color);
}
return result;
}
UI_Button :: proc(str: *char): bool {
result := UI_BaseButton({
text = S8_MakeFromChar(str),
draw_text = true,
draw_border = true,
draw_background = true,
});
return result.pressed;
}
UI_Checkbox :: proc(val: *bool, str: *char): bool {
result: UI_Result = UI_BaseButton({
text = S8_MakeFromChar(str),
draw_text = true,
draw_border = true,
draw_background = true,
use_checked_checkbox_button_background_colors = *val,
});
if (result.pressed) {
*val = !*val;
}
return *val;
}
UI_Fill :: proc() {
rect := UI_GetNextRect(S8_MakeEmpty());
R_Rect2D(rect, R.atlas.white_texture_bounding_box, Ui.s.button_background_color);
R_DrawBorder(rect, Ui.s.button_border_color);
}
UI_PopStyle :: proc() {
Ui.s = Ui.base_style;
}
UI_PopLayout :: proc() {
if Ui.layouts.len == 0 {
IO_FatalError("tryign to pop a layout but layout stack is empty");
}
Ui.layouts.len -= 1;
}
UI_PushLayout :: proc(rect_override: R2P): R2P {
rect: R2P;
if (rect_override.min.x != 0 || rect_override.min.y != 0 || rect_override.max.x != 0 || rect_override.max.y != 0) {
rect = rect_override;
}
else {
rect = UI_GetNextRect(S8_MakeEmpty());
}
UI_AddLayout(&Ui.layouts, {rect});
return rect;
}

View File

@@ -0,0 +1,89 @@
import "shared";
Mu: *MU_Context;
TempArena: MA_Arena;
Temp := &TempArena;
@foreign RandomSeed :: struct { a: u64; }
@foreign GetRandomU64 :: proc(state: *RandomSeed): u64;
LibraryHotLoad :: struct {
reload_count: int;
user_context: DLL_Context;
library: LIB_Library;
update_proc: LibraryUpdate;
last_write_time: i64;
seed: RandomSeed;
init_happened_on_this_frame: bool;
}
ReloadUpdate :: proc(lib: *LibraryHotLoad) {
new_write_time := OS_GetFileModTime(S8_MakeFromChar("game.dll"));
if new_write_time == -1 || new_write_time == lib.last_write_time {
return;
}
if lib.update_proc {
lib.update_proc(Unload, Mu, &lib.user_context);
lib.update_proc = nil;
}
if (lib.seed.a == 0) lib.seed.a = 13;
random_value := GetRandomU64(&lib.seed);
out_filename_dll := S8_Format(Temp, "temp_%u.dll", random_value);
out_filename_pdb := S8_Format(Temp, "temp_%u.pdb", random_value);
OS_CopyFile(S8_MakeFromChar("game.dll"), out_filename_dll, true);
OS_CopyFile(S8_MakeFromChar("game.pdb"), out_filename_pdb, true);
library := LIB_LoadLibrary(out_filename_dll.str);
if !library {
IO_Printf("Failed to load library %Q\n", out_filename_dll);
return;
}
update_proc: LibraryUpdate = LIB_LoadSymbol(library, "APP_Update");
if !library {
IO_Printf("Failed to load library %Q\n", out_filename_dll);
return;
}
lib.library = library;
lib.update_proc = update_proc;
lib.last_write_time = new_write_time;
if lib.reload_count == 0 {
lib.update_proc(Init, Mu, &lib.user_context);
lib.init_happened_on_this_frame = true;
}
else {
lib.update_proc(Reload, Mu, &lib.user_context);
}
lib.reload_count += 1;
}
CallUpdate :: proc(lib: *LibraryHotLoad) {
ReloadUpdate(lib);
if lib.update_proc && !lib.init_happened_on_this_frame {
lib.update_proc(Update, Mu, &lib.user_context);
}
lib.init_happened_on_this_frame = false;
}
main :: proc(): int {
Mu = MU_Start({
enable_opengl = true,
window = {
size = {1280, 720}
},
delta_time = 0.0166666
});
lib: LibraryHotLoad = {user_context = {temp = Temp}};
for MU_Update(Mu) {
CallUpdate(&lib);
if (Mu.window.key[MU_KEY_ESCAPE].down) {
MU_Quit(Mu);
}
}
return 0;
}

View File

@@ -0,0 +1,557 @@
#`
#include "core/core.c"
#include "core/map.c"
`;
@foreign
UTF32_Result :: struct {
out_str: u32;
advance: int;
error: int;
}
@foreign
UTF8_Result :: struct {
out_str: [4]u8;
len: int;
error: int;
}
@foreign
UTF16_Result :: struct {
out_str: [2]u16;
len: int;
error: int;
}
@foreign
UTF8_Iter :: struct {
str: *char;
len: int;
utf8_codepoint_byte_size: int;
i: int;
item: u32;
}
@foreign UTF_ConvertUTF16ToUTF32 :: proc(c: *u16, max_advance: int): UTF32_Result;
@foreign UTF_ConvertUTF32ToUTF8 :: proc(codepoint: u32): UTF8_Result;
@foreign UTF_ConvertUTF8ToUTF32 :: proc(c: *char, max_advance: int): UTF32_Result;
@foreign UTF_ConvertUTF32ToUTF16 :: proc(codepoint: u32): UTF16_Result;
@foreign UTF_CreateCharFromWidechar :: proc(buffer: *char, buffer_size: i64, in: *wchar_t, inlen: i64): i64;
@foreign UTF_CreateWidecharFromChar :: proc(buffer: *wchar_t, buffer_size: i64, in: *char, inlen: i64): i64;
@foreign UTF8_Advance :: proc(iter: *UTF8_Iter);
@foreign UTF8_IterateEx :: proc(str: *char, len: int): UTF8_Iter;
@foreign UTF8_Iterate :: proc(str: *char): UTF8_Iter;
@foreign UTF_CreateStringFromWidechar :: proc(arena: *MA_Arena, wstr: *wchar_t, wsize: i64): S8_String;
@foreign
IO_ErrorResult :: typedef int;
IO_ErrorResult_Continue :: 0;
IO_ErrorResult_Break :: ^;
IO_ErrorResult_Exit :: ^;
@foreign IO_Printf :: proc(msg: *char, ...);
@foreign IO_Print :: proc(msg: *char);
@foreign IO_OutputMessage :: proc(str: *char, len: int);
@foreign IO_OutputError :: proc(str: *char, len: int): IO_ErrorResult;
@foreign IO_Exit :: proc(error_code: int);
@foreign IO_IsDebuggerPresent :: proc(): bool;
@foreign
M_AllocatorOp :: typedef int;
M_AllocatorOp_Allocate :: 0;
M_AllocatorOp_Deallocate :: ^;
@foreign M_AllocatorProc :: typedef proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
@foreign
M_Allocator :: struct {
obj: *void;
p: proc(a: *void, b: M_AllocatorOp, c: *void, d: usize): *void;
}
@foreign M_AllocNonZeroed :: proc(allocator: M_Allocator, size: usize): *void;
@foreign M_Alloc :: proc(allocator: M_Allocator, size: usize): *void;
@foreign M_AllocCopy :: proc(allocator: M_Allocator, p: *void, size: usize): *void;
@foreign M_Dealloc :: proc(allocator: M_Allocator, p: *void);
@foreign MA_AllocatorProc :: proc(allocator: M_Allocator, kind: M_AllocatorOp, p: *void, size: usize): *void;
@foreign M_GetSystemAllocator :: proc(): M_Allocator;
@foreign
MV_Memory :: struct {
commit: usize;
reserve: usize;
data: *u8;
}
@foreign
MA_Arena :: struct {
allocator: M_Allocator;
memory: MV_Memory;
alignment: int;
saved_alignment: int;
len: usize;
packed_array_element_size: usize;
packed_array_begin: usize;
}
@foreign
MA_Temp :: struct {
arena: *MA_Arena;
pos: usize;
}
@foreign MA_MemoryZero :: proc(p: *void, size: usize);
@foreign MA_MemoryCopy :: proc(dst: *void, src: *void, size: usize);
@foreign MA_GetAlignOffset :: proc(size: usize, align: usize): usize;
@foreign MA_AlignUp :: proc(size: usize, align: usize): usize;
@foreign MA_AlignDown :: proc(size: usize, align: usize): usize;
@foreign MA_DeallocateStub :: proc(arena: *MA_Arena, p: *void);
@foreign MA_PopToPos :: proc(arena: *MA_Arena, pos: usize);
@foreign MA_PopSize :: proc(arena: *MA_Arena, size: usize): *void;
@foreign MA_DeallocateArena :: proc(arena: *MA_Arena);
@foreign MA_Reset :: proc(arena: *MA_Arena);
@foreign MA__BeginPackedArray :: proc(arena: *MA_Arena, element_size: usize): *void;
@foreign MA_EndPackedArray :: proc(arena: *MA_Arena): int;
@foreign MA_SetAlignment :: proc(arena: *MA_Arena, alignment: int);
@foreign MA_GetTop :: proc(a: *MA_Arena): *u8;
@foreign MA_PushSizeNonZeroed :: proc(a: *MA_Arena, size: usize): *void;
@foreign MA_PushSize :: proc(arena: *MA_Arena, size: usize): *void;
@foreign MA_Init :: proc(a: *MA_Arena, reserve: usize);
@foreign MA_Create :: proc(): MA_Arena;
@foreign MA_InitFromBuffer :: proc(arena: *MA_Arena, buffer: *void, size: usize);
@foreign MA_MakeFromBuffer :: proc(buffer: *void, size: usize): MA_Arena;
@foreign MA_PushStringCopy :: proc(arena: *MA_Arena, p: *char, size: usize): *char;
@foreign MA_PushCopy :: proc(arena: *MA_Arena, p: *void, size: usize): *void;
@foreign MA_IsPointerInside :: proc(arena: *MA_Arena, p: *void): bool;
@foreign MA_PushArena :: proc(arena: *MA_Arena, size: usize): MA_Arena;
@foreign MA_BeginTemp :: proc(arena: *MA_Arena): MA_Temp;
@foreign MA_EndTemp :: proc(checkpoint: MA_Temp);
@foreign MA_GetScratchEx :: proc(conflicts: **MA_Arena, conflict_count: int): MA_Temp;
@foreign MA_GetScratch :: proc(): MA_Temp;
@foreign MA_GetScratch1 :: proc(conflict: *MA_Arena): MA_Temp;
@foreign MV_Reserve :: proc(size: usize): MV_Memory;
@foreign MV_Commit :: proc(m: *MV_Memory, commit: usize): bool;
@foreign MV_Deallocate :: proc(m: *MV_Memory);
@foreign MV_DecommitPos :: proc(m: *MV_Memory, pos: usize): bool;
@foreign
S8_String :: struct {
str: *char;
len: i64;
}
@foreign
S8_Node :: struct {
next: *S8_Node;
string: S8_String;
}
@foreign
S8_List :: struct {
node_count: i64;
char_count: i64;
first: *S8_Node;
last: *S8_Node;
}
@foreign S8_AreEqual :: proc(a: S8_String, b: S8_String, ignore_case: uint): bool;
@foreign S8_EndsWith :: proc(a: S8_String, end: S8_String, ignore_case: uint): bool;
@foreign S8_StartsWith :: proc(a: S8_String, start: S8_String, ignore_case: uint): bool;
@foreign S8_Make :: proc(str: *char, len: i64): S8_String;
@foreign S8_Copy :: proc(allocator: *MA_Arena, string: S8_String): S8_String;
@foreign S8_NormalizePath :: proc(s: S8_String);
@foreign S8_Chop :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_Skip :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_GetPostfix :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_GetPrefix :: proc(string: S8_String, len: i64): S8_String;
@foreign S8_Slice :: proc(string: S8_String, first_index: i64, one_past_last_index: i64): S8_String;
@foreign S8_Trim :: proc(string: S8_String): S8_String;
@foreign S8_TrimEnd :: proc(string: S8_String): S8_String;
@foreign S8_ToLowerCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
@foreign S8_ToUpperCase :: proc(allocator: *MA_Arena, s: S8_String): S8_String;
@foreign S8_Find :: proc(string: S8_String, find: S8_String, flags: uint, index_out: *i64): bool;
@foreign S8_Split :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
@foreign S8_MergeWithSeparator :: proc(allocator: *MA_Arena, list: S8_List, separator: S8_String): S8_String;
@foreign S8_Merge :: proc(allocator: *MA_Arena, list: S8_List): S8_String;
@foreign S8_ReplaceAll :: proc(allocator: *MA_Arena, string: S8_String, replace: S8_String, with: S8_String, flags: uint): S8_String;
@foreign S8_FindAll :: proc(allocator: *MA_Arena, string: S8_String, find: S8_String, flags: uint): S8_List;
@foreign S8_ChopLastSlash :: proc(s: S8_String): S8_String;
@foreign S8_ChopLastPeriod :: proc(s: S8_String): S8_String;
@foreign S8_SkipToLastSlash :: proc(s: S8_String): S8_String;
@foreign S8_SkipToLastPeriod :: proc(s: S8_String): S8_String;
@foreign S8_Length :: proc(string: *char): i64;
@foreign S8_WideLength :: proc(string: *wchar_t): i64;
@foreign S8_MakeFromChar :: proc(string: *char): S8_String;
@foreign S8_MakeEmpty :: proc(): S8_String;
@foreign S8_MakeEmptyList :: proc(): S8_List;
@foreign S8_FormatV :: proc(allocator: *MA_Arena, str: *char, args1: va_list): S8_String;
@foreign S8_Format :: proc(allocator: *MA_Arena, str: *char, ...): S8_String;
@foreign S8_CreateNode :: proc(allocator: *MA_Arena, string: S8_String): *S8_Node;
@foreign S8_ReplaceNodeString :: proc(list: *S8_List, node: *S8_Node, new_string: S8_String);
@foreign S8_AddExistingNode :: proc(list: *S8_List, node: *S8_Node);
@foreign S8_AddArray :: proc(allocator: *MA_Arena, list: *S8_List, array: **char, count: int);
@foreign S8_AddArrayWithPrefix :: proc(allocator: *MA_Arena, list: *S8_List, prefix: *char, array: **char, count: int);
@foreign S8_MakeList :: proc(allocator: *MA_Arena, a: S8_String): S8_List;
@foreign S8_CopyList :: proc(allocator: *MA_Arena, a: S8_List): S8_List;
@foreign S8_ConcatLists :: proc(allocator: *MA_Arena, a: S8_List, b: S8_List): S8_List;
@foreign S8_AddNode :: proc(allocator: *MA_Arena, list: *S8_List, string: S8_String): *S8_Node;
@foreign S8_AddF :: proc(allocator: *MA_Arena, list: *S8_List, str: *char, ...): S8_String;
@foreign
MU__Float2 :: struct {
x: float;
y: float;
}
@foreign
MU__Int2 :: struct {
x: int;
y: int;
}
@foreign MU_glGetProcAddress :: typedef proc(a: *char): *void;
@foreign
MU_Window_Params :: struct {
size: MU__Int2;
pos: MU__Int2;
title: *char;
enable_canvas: bool;
resizable: bool;
borderless: bool;
fps_cursor: bool;
}
@foreign
MU_Params :: struct {
memory: *void;
cap: usize;
enable_opengl: bool;
opengl_major: int;
opengl_minor: int;
delta_time: double;
window: MU_Window_Params;
sound_callback: proc(a: *MU_Context, b: *u16, c: u32): void;
}
@foreign
MU_Key_State :: struct {
down: bool;
press: bool;
unpress: bool;
raw_press: bool;
}
@foreign
MU_Key :: typedef int;
MU_KEY_INVALID :: 0;
MU_KEY_ESCAPE :: ^;
MU_KEY_ENTER :: ^;
MU_KEY_TAB :: ^;
MU_KEY_BACKSPACE :: ^;
MU_KEY_INSERT :: ^;
MU_KEY_DELETE :: ^;
MU_KEY_RIGHT :: ^;
MU_KEY_LEFT :: ^;
MU_KEY_DOWN :: ^;
MU_KEY_UP :: ^;
MU_KEY_PAGE_UP :: ^;
MU_KEY_PAGE_DOWN :: ^;
MU_KEY_HOME :: ^;
MU_KEY_END :: ^;
MU_KEY_F1 :: ^;
MU_KEY_F2 :: ^;
MU_KEY_F3 :: ^;
MU_KEY_F4 :: ^;
MU_KEY_F5 :: ^;
MU_KEY_F6 :: ^;
MU_KEY_F7 :: ^;
MU_KEY_F8 :: ^;
MU_KEY_F9 :: ^;
MU_KEY_F10 :: ^;
MU_KEY_F11 :: ^;
MU_KEY_F12 :: ^;
MU_KEY_SPACE :: 32;
MU_KEY_APOSTROPHE :: 39;
MU_KEY_PLUS :: 43;
MU_KEY_COMMA :: 44;
MU_KEY_MINUS :: 45;
MU_KEY_PERIOD :: 46;
MU_KEY_SLASH :: 47;
MU_KEY_0 :: 48;
MU_KEY_1 :: 49;
MU_KEY_2 :: 50;
MU_KEY_3 :: 51;
MU_KEY_4 :: 52;
MU_KEY_5 :: 53;
MU_KEY_6 :: 54;
MU_KEY_7 :: 55;
MU_KEY_8 :: 56;
MU_KEY_9 :: 57;
MU_KEY_SEMICOLON :: 59;
MU_KEY_EQUAL :: 61;
MU_KEY_A :: 65;
MU_KEY_B :: 66;
MU_KEY_C :: 67;
MU_KEY_D :: 68;
MU_KEY_E :: 69;
MU_KEY_F :: 70;
MU_KEY_G :: 71;
MU_KEY_H :: 72;
MU_KEY_I :: 73;
MU_KEY_J :: 74;
MU_KEY_K :: 75;
MU_KEY_L :: 76;
MU_KEY_M :: 77;
MU_KEY_N :: 78;
MU_KEY_O :: 79;
MU_KEY_P :: 80;
MU_KEY_Q :: 81;
MU_KEY_R :: 82;
MU_KEY_S :: 83;
MU_KEY_T :: 84;
MU_KEY_U :: 85;
MU_KEY_V :: 86;
MU_KEY_W :: 87;
MU_KEY_X :: 88;
MU_KEY_Y :: 89;
MU_KEY_Z :: 90;
MU_KEY_LEFT_BRACKET :: 91;
MU_KEY_BACKSLASH :: 92;
MU_KEY_RIGHT_BRACKET :: 93;
MU_KEY_GRAVE_ACCENT :: 96;
MU_KEY_F13 :: ^;
MU_KEY_F14 :: ^;
MU_KEY_F15 :: ^;
MU_KEY_F16 :: ^;
MU_KEY_F17 :: ^;
MU_KEY_F18 :: ^;
MU_KEY_F19 :: ^;
MU_KEY_F20 :: ^;
MU_KEY_F21 :: ^;
MU_KEY_F22 :: ^;
MU_KEY_F23 :: ^;
MU_KEY_F24 :: ^;
MU_KEY_KP_0 :: ^;
MU_KEY_KP_1 :: ^;
MU_KEY_KP_2 :: ^;
MU_KEY_KP_3 :: ^;
MU_KEY_KP_4 :: ^;
MU_KEY_KP_5 :: ^;
MU_KEY_KP_6 :: ^;
MU_KEY_KP_7 :: ^;
MU_KEY_KP_8 :: ^;
MU_KEY_KP_9 :: ^;
MU_KEY_KP_DECIMAL :: ^;
MU_KEY_KP_DIVIDE :: ^;
MU_KEY_KP_MULTIPLY :: ^;
MU_KEY_KP_SUBTRACT :: ^;
MU_KEY_KP_ADD :: ^;
MU_KEY_KP_ENTER :: ^;
MU_KEY_LEFT_SHIFT :: ^;
MU_KEY_LEFT_CONTROL :: ^;
MU_KEY_LEFT_ALT :: ^;
MU_KEY_LEFT_SUPER :: ^;
MU_KEY_RIGHT_SHIFT :: ^;
MU_KEY_RIGHT_CONTROL :: ^;
MU_KEY_RIGHT_ALT :: ^;
MU_KEY_RIGHT_SUPER :: ^;
MU_KEY_CAPS_LOCK :: ^;
MU_KEY_SCROLL_LOCK :: ^;
MU_KEY_NUM_LOCK :: ^;
MU_KEY_PRINT_SCREEN :: ^;
MU_KEY_PAUSE :: ^;
MU_KEY_SHIFT :: ^;
MU_KEY_CONTROL :: ^;
MU_KEY_COUNT :: ^;
@foreign
MU_Mouse_State :: struct {
pos: MU__Int2;
posf: MU__Float2;
delta_pos: MU__Int2;
delta_pos_normalized: MU__Float2;
left: MU_Key_State;
middle: MU_Key_State;
right: MU_Key_State;
delta_wheel: float;
}
@foreign
MU_DroppedFile :: struct {
next: *MU_DroppedFile;
filename: *char;
filename_size: int;
}
@foreign
MU_Arena :: struct {
memory: *char;
len: usize;
cap: usize;
}
@foreign
MU_Window :: struct {
size: MU__Int2;
sizef: MU__Float2;
pos: MU__Int2;
posf: MU__Float2;
dpi_scale: float;
is_fullscreen: bool;
is_fps_mode: bool;
is_focused: bool;
change_cursor_on_mouse_hold: bool;
processed_events_this_frame: u64;
should_render: bool;
first_dropped_file: *MU_DroppedFile;
canvas: *u32;
canvas_enabled: bool;
mouse: MU_Mouse_State;
key: [140]MU_Key_State;
user_text32: [32]u32;
user_text32_count: int;
user_text8: [32]char;
user_text8_count: int;
next: *MU_Window;
handle: *void;
platform: *void;
}
@foreign
MU_Time :: struct {
app_start: double;
frame_start: double;
update: double;
update_total: double;
delta: double;
deltaf: float;
total: double;
totalf: float;
}
@foreign
MU_Sound :: struct {
initialized: bool;
samples_per_second: uint;
number_of_channels: uint;
bytes_per_sample: uint;
callback: proc(a: *MU_Context, b: *u16, c: u32): void;
}
@foreign
MU_Context :: struct {
quit: bool;
sound: MU_Sound;
time: MU_Time;
first_frame: bool;
_MU_Update_count: int;
frame: usize;
consecutive_missed_frames: usize;
total_missed_frames: usize;
primary_monitor_size: MU__Int2;
opengl_initialized: bool;
opengl_major: int;
opengl_minor: int;
gl_get_proc_address: proc(a: *char): *void;
params: MU_Params;
window: *MU_Window;
all_windows: *MU_Window;
perm_arena: MU_Arena;
frame_arena: MU_Arena;
platform: *void;
}
@foreign MU_Quit :: proc(mu: *MU_Context);
@foreign MU_DefaultSoundCallback :: proc(mu: *MU_Context, buffer: *u16, samples_to_fill: u32);
@foreign MU_GetTime :: proc(): double;
@foreign MU_ToggleFPSMode :: proc(window: *MU_Window);
@foreign MU_DisableFPSMode :: proc(window: *MU_Window);
@foreign MU_EnableFPSMode :: proc(window: *MU_Window);
@foreign MU_ToggleFullscreen :: proc(window: *MU_Window);
@foreign MU_Init :: proc(mu: *MU_Context, params: MU_Params, len: usize);
@foreign MU_AddWindow :: proc(mu: *MU_Context, params: MU_Window_Params): *MU_Window;
@foreign MU_InitWindow :: proc(mu: *MU_Context, window: *MU_Window, params: MU_Window_Params);
@foreign MU_Start :: proc(params: MU_Params): *MU_Context;
@foreign MU_Update :: proc(mu: *MU_Context): bool;
@foreign LIB_Library :: typedef *void;
@foreign LIB_LoadLibrary :: proc(str: *char): LIB_Library;
@foreign LIB_LoadSymbol :: proc(lib: LIB_Library, symbol: *char): *void;
@foreign LIB_UnloadLibrary :: proc(lib: LIB_Library): bool;
@foreign
CTX_Context :: struct {
heap: M_Allocator;
temp_alloc: M_Allocator;
perm_alloc: M_Allocator;
temp: *MA_Arena;
perm: *MA_Arena;
temporary_arena: MA_Arena;
pernament_arena: MA_Arena;
user_context: *void;
}
@foreign CTX_Init :: proc();
@foreign
OS_Result :: typedef int;
OS_SUCCESS :: 0;
OS_ALREADY_EXISTS :: ^;
OS_PATH_NOT_FOUND :: ^;
OS_FAILURE :: ^;
@foreign
OS_Date :: struct {
year: u32;
month: u32;
day: u32;
hour: u32;
minute: u32;
second: u32;
milliseconds: u32;
}
@foreign OS_IsAbsolute :: proc(path: S8_String): bool;
@foreign OS_GetExePath :: proc(arena: *MA_Arena): S8_String;
@foreign OS_GetExeDir :: proc(arena: *MA_Arena): S8_String;
@foreign OS_GetWorkingDir :: proc(arena: *MA_Arena): S8_String;
@foreign OS_SetWorkingDir :: proc(path: S8_String);
@foreign OS_GetAbsolutePath :: proc(arena: *MA_Arena, relative: S8_String): S8_String;
@foreign OS_FileExists :: proc(path: S8_String): bool;
@foreign OS_IsDir :: proc(path: S8_String): bool;
@foreign OS_IsFile :: proc(path: S8_String): bool;
@foreign OS_GetTime :: proc(): double;
@foreign OS_ListDir :: proc(arena: *MA_Arena, path: S8_String, flags: uint): S8_List;
@foreign OS_MakeDir :: proc(path: S8_String): OS_Result;
@foreign OS_CopyFile :: proc(from: S8_String, to: S8_String, overwrite: bool): OS_Result;
@foreign OS_DeleteFile :: proc(path: S8_String): OS_Result;
@foreign OS_DeleteDir :: proc(path: S8_String, flags: uint): OS_Result;
@foreign OS_AppendFile :: proc(path: S8_String, string: S8_String): OS_Result;
@foreign OS_WriteFile :: proc(path: S8_String, string: S8_String): OS_Result;
@foreign OS_ReadFile :: proc(arena: *MA_Arena, path: S8_String): S8_String;
@foreign OS_SystemF :: proc(string: *char, ...): int;
@foreign OS_GetFileModTime :: proc(file: S8_String): i64;
@foreign OS_GetDate :: proc(): OS_Date;
@foreign S8_SplitOnRegex :: proc(arena: *MA_Arena, string: S8_String, regex: S8_String, flags: uint): S8_List;
@foreign OS_ListDirRegex :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_List;
@foreign OS_ListDirRegexAsString :: proc(arena: *MA_Arena, path: S8_String, flags: uint, regex: *char): S8_String;
@foreign OS_ExpandIncludesList :: proc(arena: *MA_Arena, out: *S8_List, filepath: S8_String): bool;
@foreign OS_ExpandIncludes :: proc(arena: *MA_Arena, filepath: S8_String): S8_String;
@foreign
LC_MapEntry :: struct {
key: u64;
value: u64;
}
@foreign
LC_Map :: struct {
allocator: M_Allocator;
entries: *LC_MapEntry;
cap: int;
len: int;
}
@foreign LC_MapReserve :: proc(map: *LC_Map, size: int);
@foreign LC_GetMapEntryEx :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
@foreign LC_InsertMapEntry :: proc(map: *LC_Map, key: u64, value: u64): *LC_MapEntry;
@foreign LC_GetMapEntry :: proc(map: *LC_Map, key: u64): *LC_MapEntry;
@foreign LC_MapInsert :: proc(map: *LC_Map, keystr: S8_String, value: *void);
@foreign LC_MapGet :: proc(map: *LC_Map, keystr: S8_String): *void;
@foreign LC_MapInsertU64 :: proc(map: *LC_Map, keystr: u64, value: *void);
@foreign LC_MapGetU64 :: proc(map: *LC_Map, keystr: u64): *void;
@foreign LC_MapGetP :: proc(map: *LC_Map, key: *void): *void;
@foreign LC_MapInsertP :: proc(map: *LC_Map, key: *void, value: *void);
@foreign Map_Insert2P :: proc(map: *LC_Map, key: *void, value: *void);

View File

@@ -0,0 +1,13 @@
LibraryUpdate :: typedef proc(event: LibraryEvent, mu: *MU_Context, context: *DLL_Context);
LibraryEvent :: typedef int;
Init :: 0;
Reload :: ^;
Unload :: ^;
Update :: ^;
DLL_Context :: struct {
temp: *MA_Arena;
perm: MA_Arena;
context: *void;
}

View File

@@ -0,0 +1,34 @@
#`#include <stdint.h>`;
@foreign(int8_t) i8 :: typedef char;
@foreign(int16_t) i16 :: typedef short;
@foreign(int32_t) i32 :: typedef int;
@foreign(int64_t) i64 :: typedef llong;
@foreign(uint8_t) u8 :: typedef uchar;
@foreign(uint16_t) u16 :: typedef ushort;
@foreign(uint32_t) u32 :: typedef uint;
@foreign(uint64_t) u64 :: typedef ullong;
@foreign(size_t) usize :: typedef u64;
@foreign(intptr_t) isize :: typedef i64;
@foreign(intptr_t) intptr :: typedef i64;
@foreign(uintptr_t) uintptr :: typedef u64;
@weak @foreign f32 :: typedef float;
@weak @foreign f64 :: typedef double;
@foreign wchar_t :: typedef u16;
@foreign va_list :: typedef u64;
NULL :: 0;
@foreign UINT64_MAX: u64;
@foreign UINT32_MAX: u32;
@foreign UINT16_MAX: u16;
@foreign UINT8_MAX: u8;
@foreign INT64_MAX: i64;
@foreign INT32_MAX: i32;
@foreign INT16_MAX: i16;
@foreign INT8_MAX: i8;