reinit repo after broken git

This commit is contained in:
krzosa
2024-12-29 10:10:09 +01:00
commit a30a897272
40 changed files with 13769 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
backup
build/
*.wasm
*.o
MSVC/
multimedia.c
multimedia.h

13
build.bat Normal file
View File

@@ -0,0 +1,13 @@
@echo off
if not exist build\build_tool.exe (
mkdir build
pushd build
cl ..\src\meta\build_tool.c -Fe:build_tool.exe -Fd:build_tool.pdb /Zi /FC /nologo
rem clang ..\src\meta\build_tool.c -o build_tool.exe -g
popd
)
build\build_tool.exe

65
build_file.c Normal file
View File

@@ -0,0 +1,65 @@
#include "src/core/core.h"
#include "src/core/core.c"
#define BUILD_TOOL_LIB
#define S8_String s8_t
#include "src/meta/build_tool.c"
#include "src/meta/parser.c"
#include "src/meta/serialize.c"
#include "src/app/app.meta.c"
int main(int argc, char **argv) {
int ok = 0;
ma_arena_t *arena = ma_create(ma_default_reserve_size);
meta_app(arena);
bool run_server = false;
bool core_test_target = false;
bool wasm_target = true;
bool win32_target = false;
if (run_server) {
os_systemf("start /D ..\\package ..\\package\\run_server.bat");
}
if (win32_target) {
os_delete_file(s8_lit("win32_app.pdb"));
ok = os_systemf(
"cl ../src/app/app_win32.c -Fe:win32_app.exe -Fd:win32_app.pdb"
" -I ../src"
" /Zi /FC /nologo /Oi"
" /WX /W3 /wd4200 /diagnostics:column"
" /link /incremental:no"
);
if (ok != 0) return ok;
}
if (core_test_target) {
os_delete_file(s8_lit("core_test.pdb"));
ok = os_systemf(
"cl ../src/core_test/core_test_entry.c -Fe:core_test.exe -Fd:core_test.pdb"
" -I ../src"
" /Zi /FC /nologo /Oi"
" /WX /W3 /wd4200 /diagnostics:column"
" /link /incremental:no"
);
if (ok != 0) return ok;
}
if (wasm_target) {
ok = os_systemf(
"clang.exe ../src/wasm_app/main.c -o main.wasm"
" -Oz -g -I../src"
" -Wall -Wno-missing-braces"
" -fdiagnostics-absolute-paths -fdiagnostics-format=msvc"
" --target=wasm32 -nostdlib -mbulk-memory -msimd128"
" -Wl,-export-dynamic,--allow-undefined,--import-memory,--no-entry,--initial-memory=131072000,--max-memory=4294967296"
);
os_copy("main.wasm", "../package/main.wasm", os_copy_overwrite);
if (ok != 0) return ok;
}
return ok;
}

Binary file not shown.

153
package/index.html Normal file
View File

@@ -0,0 +1,153 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas class="fill-screen" id="canvas"></canvas>
</body>
<style>
@font-face {
font-family: fira;
src: url(FiraCode-Regular.ttf);
}
* {
margin: 0;
padding: 0;
overflow: hidden;
}
.fill-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
</style>
</html>
<script>
class memory_t {
exports = null; // this is set after wasm module created
constructor(wasm_memory) {
this.mem = wasm_memory;
this.u8 = new Uint8Array(this.mem.buffer);
this.data_view = new DataView(this.mem.buffer);
this.utf8decoder = new TextDecoder("utf-8");
this.utf8encoder = new TextEncoder("utf-8");
}
read_cstr(str, len) {
const arr = this.u8.subarray(str, str+len);
const text = this.utf8decoder.decode(arr);
return text;
}
write_string_into_cmemory(ptr, ptr_len, string) {
const bytes = this.utf8encoder.encode(string);
let i = 0;
for (; i < bytes.length && i < (ptr_len-1); i += 1) {
this.u8[ptr + i] = bytes[i];
}
this.u8[ptr + i] = 0;
}
write_string(temp, string) {
const ptr = this.exports[temp].value;
const len = this.data_view.getInt32(this.exports[temp + "_len"].value, true);
this.write_string_into_cmemory(ptr, len, string);
return ptr;
}
}
const canvas = document.getElementById("canvas");
const ctx2d = canvas.getContext('2d');
const mem = new memory_t(new WebAssembly['Memory']({ initial: 2000, maximum: 65536 }));
(async function main() {
if (!ctx2d) {
alert('Outdated browser, cant draw :(');
return;
}
const request = await fetch('main.wasm');
const binary = await request.arrayBuffer();
const wasm_imports = {
memory: mem.mem,
wasm_write_to_console: (str, len) => console.log(mem.read_cstr(str, len)),
wasm_draw_text: (str, len, x, y, font_str, font_len, font_size, r, g, b, a) => {
ctx2d.font = `${font_size}px ${mem.read_cstr(font_str, font_len)}`;
ctx2d.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
ctx2d.textBaseline = "top"
ctx2d.fillText(mem.read_cstr(str, len), x, y)
},
wasm_measure_text: (str, len, font_str, font_len, font_size) => {
ctx2d.font = `${font_size}px ${mem.read_cstr(font_str, font_len)}`;
ctx2d.textBaseline = "top";
const metrics = ctx2d.measureText(mem.read_cstr(str, len));
return metrics.width;
},
wasm_get_font_height: (font_str, font_len, font_size) => {
ctx2d.font = `${font_size}px ${mem.read_cstr(font_str, font_len)}`;
ctx2d.textBaseline = "top";
return ctx2d.measureText('NothinBelowTheBaseline').actualBoundingBoxDescent;
},
wasm_draw_rect: (x, y, w, h, r, g, b, a) => {
ctx2d.beginPath();
ctx2d.rect(x, y, w, h);
ctx2d.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
ctx2d.fill();
},
wasm_set_clip: (x, y, w, h) => {
ctx2d.restore();
ctx2d.save();
ctx2d.beginPath();
ctx2d.rect(x, y, w, h);
ctx2d.clip();
},
wasm_parse_float: (str, len) => {
return parseFloat(mem.read_cstr(str, len));
},
wasm_trap: () => { throw new Error() },
};
const program = await WebAssembly['instantiate'](binary, { "env": wasm_imports });
const instance = program['instance'];
const wasm_exports = instance['exports'];
mem.exports = wasm_exports;
wasm_exports['wasm_init']();
addEventListener("keydown", (event) => {
wasm_exports["wasm_key_down"](mem.write_string("wasm_temp_buff1", event.key), event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
addEventListener("keyup", (event) => {
wasm_exports["wasm_key_up"](mem.write_string("wasm_temp_buff1", event.key), event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
addEventListener("mousemove", (event) => {
wasm_exports["wasm_mouse_move"](event.clientX, event.clientY, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
addEventListener("mousedown", (event) => {
wasm_exports["wasm_mouse_down"](event.clientX, event.clientY, event.button, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
addEventListener("mouseup", (event) => {
wasm_exports["wasm_mouse_up"](event.clientX, event.clientY, event.button, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
addEventListener("wheel", (event) => {
wasm_exports["wasm_mouse_wheel"](event.deltaX, event.deltaY, event.deltaZ, event.ctrlKey, event.shiftKey, event.altKey, event.metaKey);
});
requestAnimationFrame(function update(time) {
const dpr = window.devicePixelRatio;
canvas.width = canvas.getBoundingClientRect().width * dpr;
canvas.height = canvas.getBoundingClientRect().height * dpr;
wasm_exports['wasm_update'](time / 1000, canvas.width, canvas.height, dpr);
requestAnimationFrame(update);
});
})()
</script>

1
package/run_server.bat Normal file
View File

@@ -0,0 +1 @@
py.exe -m http.server 8080

2
src/app/app.c Normal file
View File

@@ -0,0 +1,2 @@
#include "app.gen.c"
#include "app_wasm.c"

274
src/app/app.gen.c Normal file
View File

@@ -0,0 +1,274 @@
type_t type__app_key_t = { type_kind_enum, s8_const_lit("app_key_t"), sizeof(app_key_t),
.members = (type_member_t[]){
{.name = s8_const_lit("app_key_invalid"), .value = app_key_invalid},
{.name = s8_const_lit("app_key_1"), .value = app_key_1},
{.name = s8_const_lit("app_key_2"), .value = app_key_2},
{.name = s8_const_lit("app_key_3"), .value = app_key_3},
{.name = s8_const_lit("app_key_4"), .value = app_key_4},
{.name = s8_const_lit("app_key_5"), .value = app_key_5},
{.name = s8_const_lit("app_key_6"), .value = app_key_6},
{.name = s8_const_lit("app_key_7"), .value = app_key_7},
{.name = s8_const_lit("app_key_8"), .value = app_key_8},
{.name = s8_const_lit("app_key_9"), .value = app_key_9},
{.name = s8_const_lit("app_key_0"), .value = app_key_0},
{.name = s8_const_lit("app_key_f1"), .value = app_key_f1},
{.name = s8_const_lit("app_key_f2"), .value = app_key_f2},
{.name = s8_const_lit("app_key_f3"), .value = app_key_f3},
{.name = s8_const_lit("app_key_f4"), .value = app_key_f4},
{.name = s8_const_lit("app_key_f5"), .value = app_key_f5},
{.name = s8_const_lit("app_key_f6"), .value = app_key_f6},
{.name = s8_const_lit("app_key_f7"), .value = app_key_f7},
{.name = s8_const_lit("app_key_f8"), .value = app_key_f8},
{.name = s8_const_lit("app_key_f9"), .value = app_key_f9},
{.name = s8_const_lit("app_key_f10"), .value = app_key_f10},
{.name = s8_const_lit("app_key_f11"), .value = app_key_f11},
{.name = s8_const_lit("app_key_f12"), .value = app_key_f12},
{.name = s8_const_lit("app_key_a"), .value = app_key_a},
{.name = s8_const_lit("app_key_b"), .value = app_key_b},
{.name = s8_const_lit("app_key_c"), .value = app_key_c},
{.name = s8_const_lit("app_key_d"), .value = app_key_d},
{.name = s8_const_lit("app_key_e"), .value = app_key_e},
{.name = s8_const_lit("app_key_f"), .value = app_key_f},
{.name = s8_const_lit("app_key_g"), .value = app_key_g},
{.name = s8_const_lit("app_key_h"), .value = app_key_h},
{.name = s8_const_lit("app_key_i"), .value = app_key_i},
{.name = s8_const_lit("app_key_j"), .value = app_key_j},
{.name = s8_const_lit("app_key_k"), .value = app_key_k},
{.name = s8_const_lit("app_key_l"), .value = app_key_l},
{.name = s8_const_lit("app_key_m"), .value = app_key_m},
{.name = s8_const_lit("app_key_n"), .value = app_key_n},
{.name = s8_const_lit("app_key_o"), .value = app_key_o},
{.name = s8_const_lit("app_key_p"), .value = app_key_p},
{.name = s8_const_lit("app_key_q"), .value = app_key_q},
{.name = s8_const_lit("app_key_r"), .value = app_key_r},
{.name = s8_const_lit("app_key_s"), .value = app_key_s},
{.name = s8_const_lit("app_key__t"), .value = app_key__t},
{.name = s8_const_lit("app_key_u"), .value = app_key_u},
{.name = s8_const_lit("app_key_v"), .value = app_key_v},
{.name = s8_const_lit("app_key_w"), .value = app_key_w},
{.name = s8_const_lit("app_key_x"), .value = app_key_x},
{.name = s8_const_lit("app_key_y"), .value = app_key_y},
{.name = s8_const_lit("app_key_z"), .value = app_key_z},
{.name = s8_const_lit("app_key_space"), .value = app_key_space},
{.name = s8_const_lit("app_key_enter"), .value = app_key_enter},
{.name = s8_const_lit("app_key_escape"), .value = app_key_escape},
{.name = s8_const_lit("app_key_left"), .value = app_key_left},
{.name = s8_const_lit("app_key_up"), .value = app_key_up},
{.name = s8_const_lit("app_key_right"), .value = app_key_right},
{.name = s8_const_lit("app_key_down"), .value = app_key_down},
{.name = s8_const_lit("app_key_tab"), .value = app_key_tab},
{.name = s8_const_lit("app_key_backspace"), .value = app_key_backspace},
{.name = s8_const_lit("app_key_control"), .value = app_key_control},
{.name = s8_const_lit("app_key_shift"), .value = app_key_shift},
{.name = s8_const_lit("app_key_alt"), .value = app_key_alt},
{.name = s8_const_lit("app_key_meta"), .value = app_key_meta},
{.name = s8_const_lit("app_key_caps_lock"), .value = app_key_caps_lock},
{.name = s8_const_lit("app_key_delete"), .value = app_key_delete},
{.name = s8_const_lit("app_key_home"), .value = app_key_home},
{.name = s8_const_lit("app_key_end"), .value = app_key_end},
{.name = s8_const_lit("app_key_insert"), .value = app_key_insert},
{.name = s8_const_lit("app_key_page_up"), .value = app_key_page_up},
{.name = s8_const_lit("app_key_page_down"), .value = app_key_page_down},
},
.count = 69,
};
#if PLATFORM_WASM
typedef struct { app_key_t key; b32 filter_out; } wasm_key_map_t;
wasm_key_map_t wasm_map_key_string_to_app_key(s8_t key) {
if (0) {}
else if (s8_equal_ex(key, s8_lit("1"), s8_ignore_case)) return (wasm_key_map_t){app_key_1, 0};
else if (s8_equal_ex(key, s8_lit("2"), s8_ignore_case)) return (wasm_key_map_t){app_key_2, 0};
else if (s8_equal_ex(key, s8_lit("3"), s8_ignore_case)) return (wasm_key_map_t){app_key_3, 0};
else if (s8_equal_ex(key, s8_lit("4"), s8_ignore_case)) return (wasm_key_map_t){app_key_4, 0};
else if (s8_equal_ex(key, s8_lit("5"), s8_ignore_case)) return (wasm_key_map_t){app_key_5, 0};
else if (s8_equal_ex(key, s8_lit("6"), s8_ignore_case)) return (wasm_key_map_t){app_key_6, 0};
else if (s8_equal_ex(key, s8_lit("7"), s8_ignore_case)) return (wasm_key_map_t){app_key_7, 0};
else if (s8_equal_ex(key, s8_lit("8"), s8_ignore_case)) return (wasm_key_map_t){app_key_8, 0};
else if (s8_equal_ex(key, s8_lit("9"), s8_ignore_case)) return (wasm_key_map_t){app_key_9, 0};
else if (s8_equal_ex(key, s8_lit("0"), s8_ignore_case)) return (wasm_key_map_t){app_key_0, 0};
else if (s8_equal_ex(key, s8_lit("F1"), s8_ignore_case)) return (wasm_key_map_t){app_key_f1, 1};
else if (s8_equal_ex(key, s8_lit("F2"), s8_ignore_case)) return (wasm_key_map_t){app_key_f2, 1};
else if (s8_equal_ex(key, s8_lit("F3"), s8_ignore_case)) return (wasm_key_map_t){app_key_f3, 1};
else if (s8_equal_ex(key, s8_lit("F4"), s8_ignore_case)) return (wasm_key_map_t){app_key_f4, 1};
else if (s8_equal_ex(key, s8_lit("F5"), s8_ignore_case)) return (wasm_key_map_t){app_key_f5, 1};
else if (s8_equal_ex(key, s8_lit("F6"), s8_ignore_case)) return (wasm_key_map_t){app_key_f6, 1};
else if (s8_equal_ex(key, s8_lit("F7"), s8_ignore_case)) return (wasm_key_map_t){app_key_f7, 1};
else if (s8_equal_ex(key, s8_lit("F8"), s8_ignore_case)) return (wasm_key_map_t){app_key_f8, 1};
else if (s8_equal_ex(key, s8_lit("F9"), s8_ignore_case)) return (wasm_key_map_t){app_key_f9, 1};
else if (s8_equal_ex(key, s8_lit("F10"), s8_ignore_case)) return (wasm_key_map_t){app_key_f10, 1};
else if (s8_equal_ex(key, s8_lit("F11"), s8_ignore_case)) return (wasm_key_map_t){app_key_f11, 1};
else if (s8_equal_ex(key, s8_lit("F12"), s8_ignore_case)) return (wasm_key_map_t){app_key_f12, 1};
else if (s8_equal_ex(key, s8_lit("a"), s8_ignore_case)) return (wasm_key_map_t){app_key_a, 0};
else if (s8_equal_ex(key, s8_lit("b"), s8_ignore_case)) return (wasm_key_map_t){app_key_b, 0};
else if (s8_equal_ex(key, s8_lit("c"), s8_ignore_case)) return (wasm_key_map_t){app_key_c, 0};
else if (s8_equal_ex(key, s8_lit("d"), s8_ignore_case)) return (wasm_key_map_t){app_key_d, 0};
else if (s8_equal_ex(key, s8_lit("e"), s8_ignore_case)) return (wasm_key_map_t){app_key_e, 0};
else if (s8_equal_ex(key, s8_lit("f"), s8_ignore_case)) return (wasm_key_map_t){app_key_f, 0};
else if (s8_equal_ex(key, s8_lit("g"), s8_ignore_case)) return (wasm_key_map_t){app_key_g, 0};
else if (s8_equal_ex(key, s8_lit("h"), s8_ignore_case)) return (wasm_key_map_t){app_key_h, 0};
else if (s8_equal_ex(key, s8_lit("i"), s8_ignore_case)) return (wasm_key_map_t){app_key_i, 0};
else if (s8_equal_ex(key, s8_lit("j"), s8_ignore_case)) return (wasm_key_map_t){app_key_j, 0};
else if (s8_equal_ex(key, s8_lit("k"), s8_ignore_case)) return (wasm_key_map_t){app_key_k, 0};
else if (s8_equal_ex(key, s8_lit("l"), s8_ignore_case)) return (wasm_key_map_t){app_key_l, 0};
else if (s8_equal_ex(key, s8_lit("m"), s8_ignore_case)) return (wasm_key_map_t){app_key_m, 0};
else if (s8_equal_ex(key, s8_lit("n"), s8_ignore_case)) return (wasm_key_map_t){app_key_n, 0};
else if (s8_equal_ex(key, s8_lit("o"), s8_ignore_case)) return (wasm_key_map_t){app_key_o, 0};
else if (s8_equal_ex(key, s8_lit("p"), s8_ignore_case)) return (wasm_key_map_t){app_key_p, 0};
else if (s8_equal_ex(key, s8_lit("q"), s8_ignore_case)) return (wasm_key_map_t){app_key_q, 0};
else if (s8_equal_ex(key, s8_lit("r"), s8_ignore_case)) return (wasm_key_map_t){app_key_r, 0};
else if (s8_equal_ex(key, s8_lit("s"), s8_ignore_case)) return (wasm_key_map_t){app_key_s, 0};
else if (s8_equal_ex(key, s8_lit("t"), s8_ignore_case)) return (wasm_key_map_t){app_key__t, 0};
else if (s8_equal_ex(key, s8_lit("u"), s8_ignore_case)) return (wasm_key_map_t){app_key_u, 0};
else if (s8_equal_ex(key, s8_lit("v"), s8_ignore_case)) return (wasm_key_map_t){app_key_v, 0};
else if (s8_equal_ex(key, s8_lit("w"), s8_ignore_case)) return (wasm_key_map_t){app_key_w, 0};
else if (s8_equal_ex(key, s8_lit("x"), s8_ignore_case)) return (wasm_key_map_t){app_key_x, 0};
else if (s8_equal_ex(key, s8_lit("y"), s8_ignore_case)) return (wasm_key_map_t){app_key_y, 0};
else if (s8_equal_ex(key, s8_lit("z"), s8_ignore_case)) return (wasm_key_map_t){app_key_z, 0};
else if (s8_equal_ex(key, s8_lit(" "), s8_ignore_case)) return (wasm_key_map_t){app_key_space, 0};
else if (s8_equal_ex(key, s8_lit("Enter"), s8_ignore_case)) return (wasm_key_map_t){app_key_enter, 1};
else if (s8_equal_ex(key, s8_lit("Escape"), s8_ignore_case)) return (wasm_key_map_t){app_key_escape, 1};
else if (s8_equal_ex(key, s8_lit("ArrowLeft"), s8_ignore_case)) return (wasm_key_map_t){app_key_left, 1};
else if (s8_equal_ex(key, s8_lit("ArrowUp"), s8_ignore_case)) return (wasm_key_map_t){app_key_up, 1};
else if (s8_equal_ex(key, s8_lit("ArrowRight"), s8_ignore_case)) return (wasm_key_map_t){app_key_right, 1};
else if (s8_equal_ex(key, s8_lit("ArrowDown"), s8_ignore_case)) return (wasm_key_map_t){app_key_down, 1};
else if (s8_equal_ex(key, s8_lit("Tab"), s8_ignore_case)) return (wasm_key_map_t){app_key_tab, 1};
else if (s8_equal_ex(key, s8_lit("Backspace"), s8_ignore_case)) return (wasm_key_map_t){app_key_backspace, 1};
else if (s8_equal_ex(key, s8_lit("Control"), s8_ignore_case)) return (wasm_key_map_t){app_key_control, 1};
else if (s8_equal_ex(key, s8_lit("Shift"), s8_ignore_case)) return (wasm_key_map_t){app_key_shift, 1};
else if (s8_equal_ex(key, s8_lit("Alt"), s8_ignore_case)) return (wasm_key_map_t){app_key_alt, 1};
else if (s8_equal_ex(key, s8_lit("AltGraph"), s8_ignore_case)) return (wasm_key_map_t){app_key_alt, 1};
else if (s8_equal_ex(key, s8_lit("Meta"), s8_ignore_case)) return (wasm_key_map_t){app_key_meta, 1};
else if (s8_equal_ex(key, s8_lit("CapsLock"), s8_ignore_case)) return (wasm_key_map_t){app_key_caps_lock, 1};
else if (s8_equal_ex(key, s8_lit("Delete"), s8_ignore_case)) return (wasm_key_map_t){app_key_delete, 1};
else if (s8_equal_ex(key, s8_lit("Home"), s8_ignore_case)) return (wasm_key_map_t){app_key_home, 1};
else if (s8_equal_ex(key, s8_lit("End"), s8_ignore_case)) return (wasm_key_map_t){app_key_end, 1};
else if (s8_equal_ex(key, s8_lit("Insert"), s8_ignore_case)) return (wasm_key_map_t){app_key_insert, 1};
else if (s8_equal_ex(key, s8_lit("PageUp"), s8_ignore_case)) return (wasm_key_map_t){app_key_page_up, 1};
else if (s8_equal_ex(key, s8_lit("PageDown"), s8_ignore_case)) return (wasm_key_map_t){app_key_page_down, 1};
return (wasm_key_map_t){0};
}
#endif
#if PLATFORM_WINDOWS
void w32_key_dispatch(WPARAM wparam, void (*handle_key)(app_key_t)) {
switch(wparam) {
case '1': handle_key(app_key_1); break;
case '2': handle_key(app_key_2); break;
case '3': handle_key(app_key_3); break;
case '4': handle_key(app_key_4); break;
case '5': handle_key(app_key_5); break;
case '6': handle_key(app_key_6); break;
case '7': handle_key(app_key_7); break;
case '8': handle_key(app_key_8); break;
case '9': handle_key(app_key_9); break;
case '0': handle_key(app_key_0); break;
case VK_F1: handle_key(app_key_f1); break;
case VK_F2: handle_key(app_key_f2); break;
case VK_F3: handle_key(app_key_f3); break;
case VK_F4: handle_key(app_key_f4); break;
case VK_F5: handle_key(app_key_f5); break;
case VK_F6: handle_key(app_key_f6); break;
case VK_F7: handle_key(app_key_f7); break;
case VK_F8: handle_key(app_key_f8); break;
case VK_F9: handle_key(app_key_f9); break;
case VK_F10: handle_key(app_key_f10); break;
case VK_F11: handle_key(app_key_f11); break;
case VK_F12: handle_key(app_key_f12); break;
case 'A': handle_key(app_key_a); break;
case 'B': handle_key(app_key_b); break;
case 'C': handle_key(app_key_c); break;
case 'D': handle_key(app_key_d); break;
case 'E': handle_key(app_key_e); break;
case 'F': handle_key(app_key_f); break;
case 'G': handle_key(app_key_g); break;
case 'H': handle_key(app_key_h); break;
case 'I': handle_key(app_key_i); break;
case 'J': handle_key(app_key_j); break;
case 'K': handle_key(app_key_k); break;
case 'L': handle_key(app_key_l); break;
case 'M': handle_key(app_key_m); break;
case 'N': handle_key(app_key_n); break;
case 'O': handle_key(app_key_o); break;
case 'P': handle_key(app_key_p); break;
case 'Q': handle_key(app_key_q); break;
case 'R': handle_key(app_key_r); break;
case 'S': handle_key(app_key_s); break;
case 'T': handle_key(app_key__t); break;
case 'U': handle_key(app_key_u); break;
case 'V': handle_key(app_key_v); break;
case 'W': handle_key(app_key_w); break;
case 'X': handle_key(app_key_x); break;
case 'Y': handle_key(app_key_y); break;
case 'Z': handle_key(app_key_z); break;
case VK_SPACE: handle_key(app_key_space); break;
case VK_RETURN: handle_key(app_key_enter); break;
case VK_ESCAPE: handle_key(app_key_escape); break;
case VK_LEFT: handle_key(app_key_left); break;
case VK_UP: handle_key(app_key_up); break;
case VK_RIGHT: handle_key(app_key_right); break;
case VK_DOWN: handle_key(app_key_down); break;
case VK_TAB: handle_key(app_key_tab); break;
case VK_BACK: handle_key(app_key_backspace); break;
case VK_CONTROL: handle_key(app_key_control); break;
case VK_SHIFT: handle_key(app_key_shift); break;
case VK_LMENU: handle_key(app_key_alt); break;
case VK_RMENU: handle_key(app_key_alt); break;
case VK_LWIN: handle_key(app_key_meta); break;
case VK_RWIN: handle_key(app_key_meta); break;
case VK_CAPITAL: handle_key(app_key_caps_lock); break;
case VK_DELETE: handle_key(app_key_delete); break;
case VK_HOME: handle_key(app_key_home); break;
case VK_END: handle_key(app_key_end); break;
case VK_NEXT: handle_key(app_key_insert); break;
case VK_INSERT: handle_key(app_key_page_up); break;
case VK_PRIOR: handle_key(app_key_page_down); break;
default: {} break;
}
}
#endif/*D:\dev\wasm\src/app/app.meta.c*/
type_t type__app_mouse_button_t = { type_kind_enum, s8_const_lit("app_mouse_button_t"), sizeof(app_mouse_button_t),
.members = (type_member_t[]){
{.name = s8_const_lit("app_mouse_button_null"), .value = app_mouse_button_null},
{.name = s8_const_lit("app_mouse_button_left"), .value = app_mouse_button_left},
{.name = s8_const_lit("app_mouse_button_middle"), .value = app_mouse_button_middle},
{.name = s8_const_lit("app_mouse_button_right"), .value = app_mouse_button_right},
{.name = s8_const_lit("app_mouse_button_count"), .value = app_mouse_button_count},
},
.count = 5,
};
type_t type__app_event_kind_t = { type_kind_enum, s8_const_lit("app_event_kind_t"), sizeof(app_event_kind_t),
.members = (type_member_t[]){
{.name = s8_const_lit("app_event_kind_invalid"), .value = app_event_kind_invalid},
{.name = s8_const_lit("app_event_kind_update"), .value = app_event_kind_update},
{.name = s8_const_lit("app_event_kind_text"), .value = app_event_kind_text},
{.name = s8_const_lit("app_event_kind_key_down"), .value = app_event_kind_key_down},
{.name = s8_const_lit("app_event_kind_key_up"), .value = app_event_kind_key_up},
{.name = s8_const_lit("app_event_kind_mouse_down"), .value = app_event_kind_mouse_down},
{.name = s8_const_lit("app_event_kind_mouse_up"), .value = app_event_kind_mouse_up},
{.name = s8_const_lit("app_event_kind_mouse_wheel"), .value = app_event_kind_mouse_wheel},
{.name = s8_const_lit("app_event_kind_mouse_move"), .value = app_event_kind_mouse_move},
{.name = s8_const_lit("app_event_kind_count"), .value = app_event_kind_count},
},
.count = 10,
};
type_t type__app_event_t = { type_kind_struct, s8_const_lit("app_event_t"), sizeof(app_event_t),
.members = (type_member_t[]){
{.name = s8_const_lit("kind"), .type = &type__app_event_kind_t, .offset = offsetof(app_event_t, kind)},
{.name = s8_const_lit("mouse_button"), .type = &type__app_mouse_button_t, .offset = offsetof(app_event_t, mouse_button)},
{.name = s8_const_lit("key"), .type = &type__app_key_t, .offset = offsetof(app_event_t, key)},
{.name = s8_const_lit("text"), .type = &type__s8_t, .offset = offsetof(app_event_t, text)},
{.name = s8_const_lit("ctrl"), .type = &type__b8, .offset = offsetof(app_event_t, ctrl)},
{.name = s8_const_lit("shift"), .type = &type__b8, .offset = offsetof(app_event_t, shift)},
{.name = s8_const_lit("alt"), .type = &type__b8, .offset = offsetof(app_event_t, alt)},
{.name = s8_const_lit("meta"), .type = &type__b8, .offset = offsetof(app_event_t, meta)},
{.name = s8_const_lit("time"), .type = &type__f64, .offset = offsetof(app_event_t, time)},
{.name = s8_const_lit("delta_time"), .type = &type__f64, .offset = offsetof(app_event_t, delta_time)},
{.name = s8_const_lit("dpr"), .type = &type__f64, .offset = offsetof(app_event_t, dpr)},
{.name = s8_const_lit("window_size"), .type = &type__v2f32_t, .offset = offsetof(app_event_t, window_size)},
{.name = s8_const_lit("mouse_pos"), .type = &type__v2f32_t, .offset = offsetof(app_event_t, mouse_pos)},
{.name = s8_const_lit("mouse_wheel_delta"), .type = &type__v3f32_t, .offset = offsetof(app_event_t, mouse_wheel_delta)},
},
.count = 14,
};

110
src/app/app.gen.h Normal file
View File

@@ -0,0 +1,110 @@
typedef enum {
app_key_invalid,
app_key_1,
app_key_2,
app_key_3,
app_key_4,
app_key_5,
app_key_6,
app_key_7,
app_key_8,
app_key_9,
app_key_0,
app_key_f1,
app_key_f2,
app_key_f3,
app_key_f4,
app_key_f5,
app_key_f6,
app_key_f7,
app_key_f8,
app_key_f9,
app_key_f10,
app_key_f11,
app_key_f12,
app_key_a,
app_key_b,
app_key_c,
app_key_d,
app_key_e,
app_key_f,
app_key_g,
app_key_h,
app_key_i,
app_key_j,
app_key_k,
app_key_l,
app_key_m,
app_key_n,
app_key_o,
app_key_p,
app_key_q,
app_key_r,
app_key_s,
app_key__t,
app_key_u,
app_key_v,
app_key_w,
app_key_x,
app_key_y,
app_key_z,
app_key_space,
app_key_enter,
app_key_escape,
app_key_left,
app_key_up,
app_key_right,
app_key_down,
app_key_tab,
app_key_backspace,
app_key_control,
app_key_shift,
app_key_alt,
app_key_meta,
app_key_caps_lock,
app_key_delete,
app_key_home,
app_key_end,
app_key_insert,
app_key_page_up,
app_key_page_down,
app_key_count,
} app_key_t;
/*D:\dev\wasm\src/app/app.meta.c*/
typedef enum {
app_mouse_button_null,
app_mouse_button_left,
app_mouse_button_middle,
app_mouse_button_right,
app_mouse_button_count,
} app_mouse_button_t;
typedef enum {
app_event_kind_invalid,
app_event_kind_update,
app_event_kind_text,
app_event_kind_key_down,
app_event_kind_key_up,
app_event_kind_mouse_down,
app_event_kind_mouse_up,
app_event_kind_mouse_wheel,
app_event_kind_mouse_move,
app_event_kind_count,
} app_event_kind_t;
typedef struct app_event_t app_event_t;
struct app_event_t {
app_event_kind_t kind;
app_mouse_button_t mouse_button;
app_key_t key;
s8_t text;
b8 ctrl;
b8 shift;
b8 alt;
b8 meta;
f64 time;
f64 delta_time;
f64 dpr;
v2f32_t window_size;
v2f32_t mouse_pos;
v3f32_t mouse_wheel_delta;
};

3
src/app/app.h Normal file
View File

@@ -0,0 +1,3 @@
#include "app.gen.h"

189
src/app/app.meta.c Normal file
View File

@@ -0,0 +1,189 @@
void meta_app(ma_arena_t *arena) {
sb8_t *h = sb8_serial_begin(arena);
sb8_t *c = sb8_serial_begin(arena);
ast_t *keys = parse_table(arena, __FILE__, CODE(
// javascript filter out
| name | js1 | js2 | jf | windows1 | windows2 |
| invalid | XXX | XXX | 1 | XXX | XXX |
| 1 | 1 | XXX | 0 | `'1'` | XXX |
| 2 | 2 | XXX | 0 | `'2'` | XXX |
| 3 | 3 | XXX | 0 | `'3'` | XXX |
| 4 | 4 | XXX | 0 | `'4'` | XXX |
| 5 | 5 | XXX | 0 | `'5'` | XXX |
| 6 | 6 | XXX | 0 | `'6'` | XXX |
| 7 | 7 | XXX | 0 | `'7'` | XXX |
| 8 | 8 | XXX | 0 | `'8'` | XXX |
| 9 | 9 | XXX | 0 | `'9'` | XXX |
| 0 | 0 | XXX | 0 | `'0'` | XXX |
| f1 | F1 | XXX | 1 | VK_F1 | XXX |
| f2 | F2 | XXX | 1 | VK_F2 | XXX |
| f3 | F3 | XXX | 1 | VK_F3 | XXX |
| f4 | F4 | XXX | 1 | VK_F4 | XXX |
| f5 | F5 | XXX | 1 | VK_F5 | XXX |
| f6 | F6 | XXX | 1 | VK_F6 | XXX |
| f7 | F7 | XXX | 1 | VK_F7 | XXX |
| f8 | F8 | XXX | 1 | VK_F8 | XXX |
| f9 | F9 | XXX | 1 | VK_F9 | XXX |
| f10 | F10 | XXX | 1 | VK_F10 | XXX |
| f11 | F11 | XXX | 1 | VK_F11 | XXX |
| f12 | F12 | XXX | 1 | VK_F12 | XXX |
| a | a | XXX | 0 | `'A'` | XXX |
| b | b | XXX | 0 | `'B'` | XXX |
| c | c | XXX | 0 | `'C'` | XXX |
| d | d | XXX | 0 | `'D'` | XXX |
| e | e | XXX | 0 | `'E'` | XXX |
| f | f | XXX | 0 | `'F'` | XXX |
| g | g | XXX | 0 | `'G'` | XXX |
| h | h | XXX | 0 | `'H'` | XXX |
| i | i | XXX | 0 | `'I'` | XXX |
| j | j | XXX | 0 | `'J'` | XXX |
| k | k | XXX | 0 | `'K'` | XXX |
| l | l | XXX | 0 | `'L'` | XXX |
| m | m | XXX | 0 | `'M'` | XXX |
| n | n | XXX | 0 | `'N'` | XXX |
| o | o | XXX | 0 | `'O'` | XXX |
| p | p | XXX | 0 | `'P'` | XXX |
| q | q | XXX | 0 | `'Q'` | XXX |
| r | r | XXX | 0 | `'R'` | XXX |
| s | s | XXX | 0 | `'S'` | XXX |
| _t | t | XXX | 0 | `'T'` | XXX |
| u | u | XXX | 0 | `'U'` | XXX |
| v | v | XXX | 0 | `'V'` | XXX |
| w | w | XXX | 0 | `'W'` | XXX |
| x | x | XXX | 0 | `'X'` | XXX |
| y | y | XXX | 0 | `'Y'` | XXX |
| z | z | XXX | 0 | `'Z'` | XXX |
| space | ` ` | XXX | 0 | VK_SPACE | XXX |
| enter | Enter | XXX | 1 | VK_RETURN | XXX |
| escape | Escape | XXX | 1 | VK_ESCAPE | XXX |
| left | ArrowLeft | XXX | 1 | VK_LEFT | XXX |
| up | ArrowUp | XXX | 1 | VK_UP | XXX |
| right | ArrowRight | XXX | 1 | VK_RIGHT | XXX |
| down | ArrowDown | XXX | 1 | VK_DOWN | XXX |
| tab | Tab | XXX | 1 | VK_TAB | XXX |
| backspace | Backspace | XXX | 1 | VK_BACK | XXX |
| control | Control | XXX | 1 | VK_CONTROL | XXX |
| shift | Shift | XXX | 1 | VK_SHIFT | XXX |
| alt | Alt | AltGraph | 1 | VK_LMENU | VK_RMENU |
| meta | Meta | XXX | 1 | VK_LWIN | VK_RWIN |
| caps_lock | CapsLock | XXX | 1 | VK_CAPITAL | XXX |
| delete | Delete | XXX | 1 | VK_DELETE | XXX |
| home | Home | XXX | 1 | VK_HOME | XXX |
| end | End | XXX | 1 | VK_END | XXX |
| insert | Insert | XXX | 1 | VK_NEXT | XXX |
| page_up | PageUp | XXX | 1 | VK_INSERT | XXX |
| page_down | PageDown | XXX | 1 | VK_PRIOR | XXX |
));
sb8_serial_table_enum(c, h, keys, s8_lit("app_key"));
// Javascript
{
int name_idx = row_findi(keys->first, "name");
int js1_idx = row_findi(keys->first, "js1");
int js2_idx = row_findi(keys->first, "js2");
int filter_out_idx = row_findi(keys->first, "jf");
sb8_stmtf(c, "\n#if PLATFORM_WASM");
sb8_stmtf(c, "typedef struct { app_key_t key; b32 filter_out; } wasm_key_map_t;");
sb8_stmtf(c, "wasm_key_map_t wasm_map_key_string_to_app_key(s8_t key) {");
c->indent += 1;
sb8_stmtf(c, "if (0) {}");
for (ast_t *row = keys->first->next; row; row = row->next) {
s8_t name = row_geti(row, name_idx)->string;
i64 filter_out = row_geti(row, filter_out_idx)->integer;
assert(filter_out == 0 || filter_out == 1);
s8_t js[] = {row_geti(row, js1_idx)->string, row_geti(row, js2_idx)->string};
for (i32 i = 0; i < lengthof(js); i += 1) {
if (s8_equal(js[i], s8_lit("XXX"))) continue;
sb8_stmtf(c, "else if (s8_equal_ex(key, s8_lit(\"%S\"), s8_ignore_case)) return (wasm_key_map_t){app_key_%S, %d};", js[i], name, (int)filter_out);
}
}
sb8_stmtf(c, "return (wasm_key_map_t){0};");
c->indent -= 1;
sb8_stmtf(c, "}");
sb8_stmtf(c, "#endif");
}
// Windows
{
int name_idx = row_findi(keys->first, "name");
int w1i = row_findi(keys->first, "windows1");
int w2i = row_findi(keys->first, "windows2");
sb8_stmtf(c, "\n#if PLATFORM_WINDOWS");
sb8_stmtf(c, "void w32_key_dispatch(WPARAM wparam, void (*handle_key)(app_key_t)) {");
c->indent += 1;
sb8_stmtf(c, "switch(wparam) {");
c->indent += 1;
for (ast_t *row = keys->first->next; row; row = row->next) {
s8_t name = row_geti(row, name_idx)->string;
s8_t w[] = {row_geti(row, w1i)->string, row_geti(row, w2i)->string};
for (i32 i = 0; i < lengthof(w); i += 1) {
if (s8_equal(w[i], s8_lit("XXX"))) continue;
sb8_stmtf(c, "case %.*s: handle_key(app_key_%.*s); break;", s8_fmtspec(w[i]), s8_fmtspec(name));
}
}
sb8_stmtf(c, "default: {} break;");
c->indent -= 1;
sb8_stmtf(c, "}");
c->indent -= 1;
sb8_stmtf(c, "}");
sb8_stmtf(c, "#endif");
}
{
ast_t *decls = parse_decls(arena, __FILE__, CODE(
typedef enum {
app_mouse_button_null,
app_mouse_button_left,
app_mouse_button_middle,
app_mouse_button_right,
app_mouse_button_count,
} app_mouse_button_t;
typedef enum {
app_event_kind_invalid,
app_event_kind_update,
app_event_kind_text,
app_event_kind_key_down,
app_event_kind_key_up,
app_event_kind_mouse_down,
app_event_kind_mouse_up,
app_event_kind_mouse_wheel,
app_event_kind_mouse_move,
app_event_kind_count,
} app_event_kind_t;
struct app_event_t {
app_event_kind_t kind;
app_mouse_button_t mouse_button;
app_key_t key;
s8_t text;
b8 ctrl;
b8 shift;
b8 alt;
b8 meta;
f64 time;
f64 delta_time;
f64 dpr;
v2f32_t window_size;
v2f32_t mouse_pos;
v3f32_t mouse_wheel_delta;
};
));
sb8_serial_ast_to_code(h, decls);
sb8_serial_ast_to_type_info(c, decls);
}
os_write_file(gen_c(arena), sb8_merge(c));
os_write_file(gen_h(arena), sb8_merge(h));
}

212
src/app/app_wasm.c Normal file
View File

@@ -0,0 +1,212 @@
#define WASM_EXPORT __attribute__((visibility("default")))
f64 wasm_parse_float(isize str, i32 len);
void wasm_write_to_console(isize str, i32 len);
void wasm_draw_text(isize str, i32 len, f64 x, f64 y, isize font_str, i32 font_len, i32 font_size, f32 r, f32 g, f32 b, f32 a);
void wasm_draw_rect(f64 x, f64 y, f64 w, f64 h, f32 r, f32 g, f32 b, f32 a);
f64 wasm_measure_text(isize str, i32 len, isize font_str, i32 font_len, i32 font_size);
f64 wasm_get_font_height(isize font_str, i32 font_len, i32 font_size);
void wasm_set_clip(f64 x, f64 y, f64 w, f64 h);
void on_update();
void app_update(app_event_t *events);
extern char __heap_base;
ma_arena_t wasm_perm_arena;
WASM_EXPORT char wasm_temp_buff1[128] = {[127] = 0x13};
WASM_EXPORT i32 wasm_temp_buff1_len = 127;
WASM_EXPORT char wasm_temp_buff2[128] = {[127] = 0x13};
WASM_EXPORT i32 wasm_temp_buff2_len = 127;
char *font_face = "fira";
i32 font_face_len = 4;
f64 wasm_dpr;
ma_arena_t *wasm_input_text_arena;
STACK(app_event_t, 64) wasm_events;
b32 wasm_event_failed_to_queue;
f64 wasm_last_time = 0;
void write_to_console(char *string) {
int len = str_len(string);
wasm_write_to_console((isize)string, len);
}
f64 s8_deserial_f64(s8_t string) {
return wasm_parse_float((isize)string.str, (i32)string.len);
}
void clip(r2f64_t rect) {
wasm_set_clip(wasm_dpr * rect.min.x, wasm_dpr * rect.min.y, wasm_dpr * (rect.max.x - rect.min.x), wasm_dpr * (rect.max.y - rect.min.y));
}
f64 get_font_height(void) {
return wasm_get_font_height((isize) font_face, font_face_len, 20*wasm_dpr) / wasm_dpr;
}
f64 measure_text_ex(char *str, int len) {
return wasm_measure_text((isize)str, len, (isize) font_face, font_face_len, 20*wasm_dpr) / wasm_dpr;
}
f64 measure_text(char *str) {
return measure_text_ex(str, str_len(str));
}
void draw_text(v2f64_t pos, v4f32_t color, char *str, int len) {
wasm_draw_text((isize)str, len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face, font_face_len, 20*wasm_dpr, color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a);
}
void draw_textf(v2f64_t pos, char *str, ...) {
char buff[1024];
va_list args;
va_start(args, str);
int len = stbsp_vsnprintf(buff, sizeof(buff), str, args);
va_end(args);
wasm_draw_text((isize)buff, len, wasm_dpr * pos.x, wasm_dpr * pos.y, (isize) font_face, font_face_len, 20*wasm_dpr, 0, 0, 0, 1);
}
void draw_rect(r2f64_t rect, v4f32_t color) {
wasm_draw_rect(wasm_dpr * rect.min.x, wasm_dpr * rect.min.y, wasm_dpr * (rect.max.x - rect.min.x), wasm_dpr * (rect.max.y - rect.min.y), color.r * 255.f, color.g * 255.f, color.b * 255.f, color.a);
}
void wasm_add_event(app_event_t event) {
if (wasm_events.len < lengthof(wasm_events.data)) {
STACK_PUSH(wasm_events, event);
} else if (wasm_event_failed_to_queue == false) {
wasm_event_failed_to_queue = true;
debugf("failed to queue event");
}
}
WASM_EXPORT void wasm_mouse_move(f64 x, f64 y, b32 ctrl, b32 shift, b32 alt, b32 meta) {
wasm_add_event((app_event_t){
.kind = app_event_kind_mouse_move,
.mouse_pos = {x, y},
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
WASM_EXPORT void wasm_mouse_down(f64 x, f64 y, i32 button, b32 ctrl, b32 shift, b32 alt, b32 meta) {
button += 1;
assert(button >= app_mouse_button_left && button <= app_mouse_button_right);
wasm_add_event((app_event_t){
.kind = app_event_kind_mouse_down,
.mouse_pos = {x, y},
.mouse_button = button,
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
WASM_EXPORT void wasm_mouse_up(f64 x, f64 y, i32 button, b32 ctrl, b32 shift, b32 alt, b32 meta) {
button += 1;
assert(button >= app_mouse_button_left && button <= app_mouse_button_right);
wasm_add_event((app_event_t){
.kind = app_event_kind_mouse_up,
.mouse_pos = {x, y},
.mouse_button = button,
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
WASM_EXPORT void wasm_mouse_wheel(f64 delta_x, f64 delta_y, f64 delta_z, b32 ctrl, b32 shift, b32 alt, b32 meta) {
wasm_add_event((app_event_t){
.kind = app_event_kind_mouse_wheel,
.mouse_wheel_delta = {delta_x, delta_y, delta_z},
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
WASM_EXPORT void wasm_key_down(char *key, b32 ctrl, b32 shift, b32 alt, b32 meta) {
assert(wasm_temp_buff1[127] == 0x13); // make sure we didn't overwrite memory in JS
assert(wasm_temp_buff2[127] == 0x13);
s8_t key8 = s8_from_char(key);
wasm_key_map_t map = wasm_map_key_string_to_app_key(key8);
if (map.key != app_key_invalid) {
wasm_add_event((app_event_t){
.kind = app_event_kind_key_down,
.key = map.key,
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
if (map.filter_out) {
return;
}
s8_t text = s8_copy(wasm_input_text_arena, key8);
wasm_add_event((app_event_t){
.kind = app_event_kind_text,
.text = text,
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
WASM_EXPORT void wasm_key_up(char *key, b32 ctrl, b32 shift, b32 alt, b32 meta) {
assert(wasm_temp_buff1[127] == 0x13); // make sure we didn't overwrite memory in JS
assert(wasm_temp_buff2[127] == 0x13);
s8_t key8 = s8_from_char(key);
wasm_key_map_t map = wasm_map_key_string_to_app_key(key8);
if (map.key != app_key_invalid) {
wasm_add_event((app_event_t){
.kind = app_event_kind_key_down,
.key = map.key,
.ctrl = ctrl,
.shift = shift,
.alt = alt,
.meta = meta,
});
}
}
WASM_EXPORT void wasm_update(f64 time, f64 width, f64 height, f64 dpr) {
f64 delta_time = (time - wasm_last_time);
for (i32 i = 0; i < wasm_events.len; i += 1) {
wasm_events.data[i].dpr = dpr;
wasm_events.data[i].window_size = (v2f32_t){width / dpr, height / dpr};
wasm_events.data[i].time = time;
wasm_events.data[i].delta_time = delta_time;
}
wasm_dpr = dpr;
on_update();
wasm_events.len = 0;
wasm_last_time = time;
ma_set0(wasm_input_text_arena);
}
WASM_EXPORT void wasm_init(void) {
isize page_size = kib(64);
isize page_count = __builtin_wasm_memory_size(0);
u8 *memory = (u8 *)&__heap_base;
usize memory_size = page_count * (page_size) - (isize)memory;
wasm_perm_arena.data = memory;
wasm_perm_arena.commit = wasm_perm_arena.reserve = memory_size;
wasm_input_text_arena = ma_push_arena(&wasm_perm_arena, kib(1));
debugf("on_init, __builtin_wasm_memory_size(0) = %d(%d)", page_count, memory_size);
}

132
src/app/app_win32.c Normal file
View File

@@ -0,0 +1,132 @@
#include "core/core.h"
#include "app.gen.h"
#include "core/core.c"
#include "app.gen.c"
#pragma comment(linker, "/subsystem:windows")
#pragma comment(lib, "gdi32.lib")
#pragma comment(lib, "user32.lib")
#pragma comment(lib, "winmm.lib")
b32 w32_good_scheduling = false;
WNDCLASSW w32_wc;
HWND w32_window_handle;
HDC w32_dc;
void w32_on_key_down(app_key_t key) {
}
void w32_on_key_up(app_key_t key) {
}
LRESULT CALLBACK w32_window_proc(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_CLOSE: PostQuitMessage(0); break;
case WM_KEYUP: w32_key_dispatch(wparam, w32_on_key_up); break;
case WM_KEYDOWN: w32_key_dispatch(wparam, w32_on_key_down); break;
default: return DefWindowProcW(wnd, msg, wparam, lparam);
}
return 0;
}
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
typedef enum W32_PROCESS_DPI_AWARENESS {
W32_PROCESS_DPI_UNAWARE = 0,
W32_PROCESS_SYSTEM_DPI_AWARE = 1,
W32_PROCESS_PER_MONITOR_DPI_AWARE = 2
} W32_PROCESS_DPI_AWARENESS;
typedef unsigned MU_TimeBeginPeriod(unsigned);
typedef HRESULT MU_SetProcessDpiAwareness(W32_PROCESS_DPI_AWARENESS);
HMODULE shcore = LoadLibraryA("Shcore.dll");
if (shcore) {
MU_SetProcessDpiAwareness *set_dpi_awr = (MU_SetProcessDpiAwareness *)GetProcAddress(shcore, "SetProcessDpiAwareness");
if (set_dpi_awr) {
HRESULT hr = set_dpi_awr(W32_PROCESS_PER_MONITOR_DPI_AWARE);
assert(SUCCEEDED(hr) && "Failed to set dpi awareness");
}
}
HMODULE winmm = LoadLibraryA("winmm.dll");
if (winmm) {
MU_TimeBeginPeriod *timeBeginPeriod = (MU_TimeBeginPeriod *)GetProcAddress(winmm, "timeBeginPeriod");
if (timeBeginPeriod) {
if (timeBeginPeriod(1) == 0) {
w32_good_scheduling = true;
}
}
}
WNDCLASSW wc = {0};
{
wc.lpfnWndProc = w32_window_proc;
wc.hInstance = GetModuleHandleW(NULL);
wc.lpszClassName = L"HelloClassName";
wc.hCursor = LoadCursor(0, IDC_ARROW);
wc.hIcon = NULL; // LoadIcon(wc.hInstance, IDI_APPLICATION);
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
ATOM result = RegisterClassW(&wc);
assert(result != 0);
w32_wc = wc;
}
RECT window_rect = {0};
{
window_rect.left = 0;
window_rect.right = 1280;
window_rect.bottom = 732;
window_rect.top = 12;
AdjustWindowRectEx(&window_rect, WS_OVERLAPPEDWINDOW, false, 0);
}
w32_window_handle = CreateWindowW(w32_wc.lpszClassName, L"Zzz... Window, hello!", WS_OVERLAPPEDWINDOW, window_rect.left, window_rect.top, window_rect.right - window_rect.left, window_rect.bottom - window_rect.top, NULL, NULL, hInstance, NULL);
assert(w32_window_handle);
w32_dc = GetDC(w32_window_handle);
assert(w32_dc);
ShowWindow(w32_window_handle, SW_SHOW);
// @todo: rebuild on resize
// Create a writable backbuffer bitmap
uint32_t *mem = 0;
BITMAPINFO bminfo = {0};
{
bminfo.bmiHeader.biSize = sizeof(bminfo.bmiHeader);
bminfo.bmiHeader.biWidth = (LONG)1280;
bminfo.bmiHeader.biHeight = (LONG)720;
bminfo.bmiHeader.biPlanes = 1;
bminfo.bmiHeader.biBitCount = 32;
bminfo.bmiHeader.biCompression = BI_RGB; // AA RR GG BB
bminfo.bmiHeader.biXPelsPerMeter = 1;
bminfo.bmiHeader.biYPelsPerMeter = 1;
}
HBITMAP dib = CreateDIBSection(w32_dc, &bminfo, DIB_RGB_COLORS, (void **)&mem, 0, 0);
HDC dib_dc = CreateCompatibleDC(w32_dc);
for (;;) {
MSG msg;
if (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
TranslateMessage(&msg);
DispatchMessageW(&msg);
continue;
}
for (int y = 0; y < 720; y++) {
for (int x = 0; x < 1280; x++) {
mem[x + y * 1280] = 0xFFFF0000;
}
}
SelectObject(dib_dc, dib);
BitBlt(w32_dc, 0, 0, 1280, 720, dib_dc, 0, 0, SRCCOPY);
Sleep(10);
}
return 0;
}

132
src/core/arena.c Normal file
View File

@@ -0,0 +1,132 @@
b32 is_pow2(usize x) {
b32 result = (((x) & ((x)-1)) == 0);
return result;
}
usize get_align_offset(usize size, usize align) {
assert(is_pow2(align));
if (align == 0) return 0;
usize mask = align - 1;
usize val = size & mask;
if (val) {
val = align - val;
}
return val;
}
usize align_up(usize size, usize align) {
usize result = size + get_align_offset(size, align);
return result;
}
usize align_down(usize size, usize align) {
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
usize result = size - (align - get_align_offset(size, align));
return result;
}
void ma_init(ma_arena_t *arena, usize reserve) {
reserve = align_up(reserve, ma_page_size);
arena->align = ma_default_alignment;
arena->data = (u8 *)vmem_reserve(reserve);
if (arena->data) {
arena->reserve = reserve;
}
}
ma_arena_t *ma_create(usize reserve) {
ma_arena_t *result = NULL;
void *data = vmem_reserve(reserve);
if (!data) return result;
b32 success = vmem_commit(data, ma_page_size);
if (!success) {
vmem_release(data);
return result;
}
result = (ma_arena_t *)data;
result->data = (u8 *)data;
result->reserve = reserve;
result->commit = ma_page_size;
result->len = result->base_len = sizeof(ma_arena_t);
result->align = ma_default_alignment;
return result;
}
void *ma_push_size_ex(ma_arena_t *arena, usize size) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
assert(arena->len >= arena->base_len);
usize align_offset = 0;
if (arena->align) {
align_offset = get_align_offset((usize)arena->data + arena->len, arena->align);
}
usize size_with_alignment = size + align_offset;
usize new_len = arena->len + size_with_alignment;
if (new_len > arena->commit) {
if (arena->reserve == 0) {
ma_init(arena, ma_default_reserve_size);
}
usize new_len_aligned_to_page_size = align_up(new_len, ma_page_size);
usize to_commit = new_len_aligned_to_page_size - arena->commit;
usize to_commit_clamped = CLAMP_TOP(to_commit, arena->reserve);
if (to_commit_clamped > 0) {
b32 success = vmem_commit(arena->data + arena->commit, to_commit_clamped);
if (success) {
MA_ASAN_UNPOISON_MEMORY_REGION(arena->data + arena->commit, to_commit_clamped);
arena->commit += to_commit_clamped;
}
}
if (new_len > arena->commit) {
return NULL;
}
}
u8 *result = arena->data + arena->len + align_offset;
arena->len = new_len;
MA_ASAN_UNPOISON_MEMORY_REGION(result, size);
return (void *)result;
}
void *ma_push_size(ma_arena_t *arena, usize size) {
void *result = ma_push_size_ex(arena, size);
if (result) memory_zero(result, size);
return result;
}
ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size) {
ma_arena_t *result = ma_push_type(allocator, ma_arena_t);
result->data = (u8 *)ma_push_size(allocator, size);
result->reserve = size;
result->commit = size;
result->align = ma_default_alignment;
return result;
}
void ma_destroy(ma_arena_t *arena) {
if (arena == NULL || arena->data == NULL) return;
b32 zero_memory = (u8 *)arena != arena->data;
vmem_release(arena->data);
if (zero_memory) memory_zero(arena, sizeof(ma_arena_t));
}
void ma_set_len(ma_arena_t *arena, usize pos) {
// base_len is used for bootstraping arenas, it denotes the
// space occupied by the arena. If len is smaller then base_len then
// we start to overwrite the arena itself - pure barbarism.
assert(arena->len >= arena->base_len);
pos = CLAMP(pos, arena->base_len, arena->len);
usize size = arena->len - pos;
arena->len = pos;
MA_ASAN_POISON_MEMORY_REGION(arena->data + arena->len, size);
}
void ma_pop(ma_arena_t *arena, usize size) { ma_set_len(arena, arena->len - size); }
ma_temp_t ma_begin_temp(ma_arena_t *arena) { return (ma_temp_t){arena, arena->len}; }
void ma_end_temp(ma_temp_t temp) { ma_set_len(temp.arena, temp.len); }
void ma_set0(ma_arena_t *arena) { ma_set_len(arena, 0); }

41
src/core/core.c Normal file
View File

@@ -0,0 +1,41 @@
#include <stdarg.h>
#if PLATFORM_WINDOWS
#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#if PLATFORM_ADDRESS_SANITIZER
#include <sanitizer/asan_interface.h>
#endif
#if !defined(ASAN_POISON_MEMORY_REGION)
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ((void)(addr), (void)(size))
#else
#define MA_ASAN_POISON_MEMORY_REGION(addr, size) ASAN_POISON_MEMORY_REGION(addr, size)
#define MA_ASAN_UNPOISON_MEMORY_REGION(addr, size) ASAN_UNPOISON_MEMORY_REGION(addr, size)
#endif
#if PLATFORM_CL
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#endif
#include "intrinsics.c"
#include "unicode.c"
#include "mathx.c"
#include "mathx.gen.c"
#include "arena.c"
#define STB_SPRINTF_IMPLEMENTATION
#include "stb_sprintf.h"
#include "string.c"
#include "string8.c"
#include "scratch.c"
#include "log.c"
#include "lexer.c"
#include "type_info.c"

5
src/core/core.h Normal file
View File

@@ -0,0 +1,5 @@
#include "platform_defines.h"
#include <stdint.h>
#include <stddef.h>
#include "types.h"
#include "type_info.h"

126
src/core/intrinsics.c Normal file
View File

@@ -0,0 +1,126 @@
void memory_copy(void *dst, void *src, size_t n) {
#if PLATFORM_CLANG
__builtin_memcpy(dst, src, n);
#else
memcpy(dst, src, n);
#endif
}
void memory_move(void *dest, const void *src, size_t n) {
#if PLATFORM_CLANG
__builtin_memmove(dest, src, n);
#else
memmove(dest, src, n);
#endif
}
void memory_set(void *dst, int c, size_t size) {
#if PLATFORM_CLANG
__builtin_memset(dst, c, size);
#else
memset(dst, c, size);
#endif
}
void memory_zero(void *dst, usize size) { memory_set(dst, 0, size); }
#if PLATFORM_CLANG
f32 f32_sqrt(f32 x) { return __builtin_sqrtf(x); }
f64 f64_sqrt(f64 x) { return __builtin_sqrt(x); }
f32 f32_ceil(f32 x) { return __builtin_ceilf(x); }
f64 f64_ceil(f64 x) { return __builtin_ceil(x); }
f32 f32_floor(f32 x) { return __builtin_floorf(x); }
f64 f64_floor(f64 x) { return __builtin_floor(x); }
f32 f32_abs(f32 x) { return __builtin_fabsf(x); }
f64 f64_abs(f64 x) { return __builtin_fabs(x); }
f32 f32_round(f32 x) { return __builtin_roundf(x); }
f64 f64_round(f64 x) { return __builtin_round(x); }
f64 f64_mod(f64 a, f64 b) { return __builtin_fmod(a, b); }
f32 f32_mod(f32 a, f32 b) { return __builtin_fmodf(a, b); }
#else
f32 f32_sqrt(f32 x) { return sqrtf(x); }
f64 f64_sqrt(f64 x) { return sqrt(x); }
f32 f32_ceil(f32 x) { return ceilf(x); }
f64 f64_ceil(f64 x) { return ceil(x); }
f32 f32_floor(f32 x) { return floorf(x); }
f64 f64_floor(f64 x) { return floor(x); }
f32 f32_abs(f32 x) { return fabsf(x); }
f64 f64_abs(f64 x) { return fabs(x); }
f32 f32_round(f32 x) { return roundf(x); }
f64 f64_round(f64 x) { return round(x); }
f64 f64_mod(f64 a, f64 b) { return fmod(a, b); }
f32 f32_mod(f32 a, f32 b) { return fmodf(a, b); }
#endif
#if PLATFORM_WINDOWS
void *vmem_reserve(size_t size) {
void *result = (uint8_t *)VirtualAlloc(0, size, MEM_RESERVE, PAGE_READWRITE);
return result;
}
b32 vmem_commit(void *p, size_t size) {
void *result = VirtualAlloc(p, size, MEM_COMMIT, PAGE_READWRITE);
return result ? true : false;
}
b32 vmem_release(void *p) {
BOOL result = VirtualFree(p, 0, MEM_RELEASE);
return result ? true : false;
}
b32 vmem_decommit(void *p, size_t size) {
BOOL result = VirtualFree(p, size, MEM_DECOMMIT);
return result ? true : false;
}
#else
void *vmem_reserve(size_t size) { return NULL; }
b32 vmem_commit(void *p, size_t size) { return false; }
b32 vmem_release(void *p) { return true; }
b32 vmem_decommit(void *p, size_t size) { return true; }
#endif
#if PLATFORM_WASM
f64 s8_deserial_f64(s8_t string);
#else
f64 s8_deserial_f64(s8_t string) { return strtod(string.str, NULL); }
#endif
#if PLATFORM_WINDOWS
void core_log_message(char *string) {
if (IsDebuggerPresent()) {
OutputDebugStringA(string);
}
printf("%s", string);
fflush(stdout);
}
void core_panic(void) {
if (core_desc.on_exit) core_desc.on_exit();
ExitProcess(1);
}
#elif PLATFORM_WASM
void write_to_console(char *string);
void core_log_message(char *string) {
write_to_console(string);
}
void core_panic(void) {
if (core_desc.on_exit) core_desc.on_exit();
debug_break();
}
#else
void core_log_message(char *string) {
printf("%s");
fflush(stdout);
}
void core_panic(void) {
if (core_desc.on_exit) core_desc.on_exit();
debug_break();
}
#endif
void core_on_exit(void) {
debugf("program panicked! exiting...");
}
THREAD_LOCAL core_desc_t core_desc = {
.print = core_log_message,
.panic = core_panic,
.break_on_panic = true,
};

493
src/core/lexer.c Normal file
View File

@@ -0,0 +1,493 @@
typedef enum lex_kind_t lex_kind_t;
enum lex_kind_t {
#define LEX_KIND_XLIST\
X(eof, "end of file", "---")\
X(int, "integer", "---")\
X(real, "real", "---")\
X(ident, "identifier", "---")\
X(string, "string", "---")\
X(comment, "comment", "---")\
X(open_brace, "'{' open brace", "{")\
X(close_brace, "'}' close brace", "}")\
X(open_paren, "'(' open parenthesis", "(")\
X(close_paren, "')' close parenthesis", ")")\
X(open_bracket, "'[' open bracket", "[")\
X(close_bracket, "']' close bracket", "]")\
X(plus, "'+' plus", "+")\
X(minus, "'-' minus", "-")\
X(divide, "'/' division sign", "/")\
X(multiply, "'*' multiplication sign", "*")\
X(modulo, "'%' modulo", "%")\
X(or, "'||' logical or", "||")\
X(and, "'&&' logical and", "&&")\
X(negation, "'!' logical negation", "!")\
X(bit_negation, "'~' bit negation", "~")\
X(bit_left_shift, "'<<' bit left shift", "<<")\
X(bit_right_shift, "'>>' bit right shift", ">>")\
X(bit_or, "'|' bit or", "|")\
X(bit_and, "'&' bit and", "&")\
X(bit_xor, "'^' bit xor", "^")\
X(decrement, "'--' decrement", "--")\
X(increment, "'++' increment", "++")\
X(post_decrement, "'--' post decrement", "--")\
X(post_increment, "'++' post increment", "++")\
X(assign, "'=' assignment", "=")\
X(divide_assign, "'/=' divide assignment", "/=")\
X(multiply_assign, "'*=' multiply assignment", "*=")\
X(plus_assign, "'+=' plus assignment", "+=")\
X(minus_assign, "'-=' minus assignment", "-=")\
X(modulo_assign, "'%=' modulo assignment", "%=")\
X(bit_and_assign, "&=", "&=")\
X(bit_or_assign, "'|=' bit or assignment", "|=")\
X(bit_xor_assign, "'^=' bit xor assignment", "^=")\
X(bit_left_shift_assign, "'<<=' bit left shift assignment", "<<=")\
X(bit_right_shift_assign, "'>>=' bit right shift assignment", ">>=")\
X(equals, "'==' equals sign", "==")\
X(not_equals, "'!=' not equals sign", "!=")\
X(lesser, "'<' lesser then", "<")\
X(greater, "'>' greater then", ">")\
X(lesser_or_equal, "'<=' lesser then or equal", "<=")\
X(greater_or_equal, "'>=' greater then or equal", ">=")\
X(comma, "',' comma", ",")\
X(dot, "'.' dot", ".")\
X(three_dots, "'...' three dots", "...")\
X(semicolon, "';' semicolon", ";")\
X(colon, "':' colon", ":")\
X(arrow, "'->' arrow", "->")\
X(question, "'?' question mark", "?")\
#define X(KIND, STR, SIMPLE) lex_kind_##KIND,
LEX_KIND_XLIST
#undef X
lex_kind_count,
};
typedef enum lex_suffix_t lex_suffix_t;
enum lex_suffix_t {
#define LEX_SUFFIX_XLIST X(none) X(f) X(d) X(u) X(ul) X(ull) X(l) X(ll)
#define X(KIND) lex_suffix_##KIND,
LEX_SUFFIX_XLIST
#undef X
lex_suffix_count,
};
typedef struct lex_t lex_t;
struct lex_t {
lex_kind_t kind;
lex_suffix_t suffix;
union {
struct {char *str; i64 len;};
s8_t s8;
};
int line;
int column;
char *file_name;
union {
u64 integer;
f64 real;
char *error;
};
};
typedef struct lexer_t lexer_t;
struct lexer_t {
char *at;
char *file_name;
int line;
int column;
};
typedef struct lex_array_t lex_array_t;
struct lex_array_t {
lex_t *data;
int len;
};
void lex_panicf(lex_t *token, const char *str, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, str, str8);
panicf("%s(%d:%d): error: %S", token->file_name, token->line, token->column, str8);
ma_end_scratch(scratch);
}
lexer_t lex_make(char *begin, char *file_name) {
lexer_t result = {.at = begin, .file_name = file_name};
return result;
}
void lex_advance(lexer_t *lex) {
if (lex->at[0] == 0) return;
if (lex->at[0] == '\n') { lex->column = 0; lex->line += 1; }
lex->column += 1;
lex->at += 1;
}
b32 lex_match(lexer_t *lex, char c) {
if (lex->at[0] == c) {
lex_advance(lex);
return true;
}
return false;
}
void lex_eat_whitespace(lexer_t *lex) {
while (char_is_whitespace(lex->at[0])) lex_advance(lex);
}
u64 lex_map_char_to_int(char c) {
switch (c) {
case '0': return 0; break;
case '1': return 1; break;
case '2': return 2; break;
case '3': return 3; break;
case '4': return 4; break;
case '5': return 5; break;
case '6': return 6; break;
case '7': return 7; break;
case '8': return 8; break;
case '9': return 9; break;
case 'a':
case 'A': return 10; break;
case 'b':
case 'B': return 11; break;
case 'c':
case 'C': return 12; break;
case 'd':
case 'D': return 13; break;
case 'e':
case 'E': return 14; break;
case 'f':
case 'F': return 15; break;
default: return 255;
}
}
u64 lex_deserial_u64(char *string, i64 len, u64 base) {
assert(base >= 2 && base <= 16);
u64 acc = 0;
for (i64 i = 0; i < len; i++) {
u64 num = lex_map_char_to_int(string[i]);
if (num >= base) {
panicf("invalid number");
break;
}
acc *= base;
acc += num;
}
return acc;
}
void lex_eat_number(lexer_t *lex, lex_t *token) {
token->kind = lex_kind_int;
for (;;) {
if (char_is_digit(lex->at[0])) {
lex_advance(lex);
continue;
}
if (lex_match(lex, '.')) {
if (token->kind == lex_kind_real) {
lex_panicf(token, "multiple '.' periods in floating point number literal");
}
token->kind = lex_kind_real;
continue;
}
break;
}
if (lex_match(lex, 'f')) {
token->kind = lex_kind_real;
token->suffix = lex_suffix_f;
} else if (lex_match(lex, 'd')) {
token->kind = lex_kind_real;
token->suffix = lex_suffix_d;
} else if (token->kind == lex_kind_int && ((lex->at[0] == 'u' && lex->at[1] == 'l' && lex->at[2] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L' && lex->at[2] == 'L'))) {
token->suffix = lex_suffix_ull;
lex_advance(lex); lex_advance(lex); lex_advance(lex);
} else if (token->kind == lex_kind_int && ((lex->at[0] == 'u' && lex->at[1] == 'l') || (lex->at[0] == 'U' && lex->at[1] == 'L'))) {
token->suffix = lex_suffix_ul;
lex_advance(lex); lex_advance(lex);
} else if (token->kind == lex_kind_int && (lex->at[0] == 'l' || lex->at[0] == 'L')) {
token->suffix = lex_suffix_l;
lex_advance(lex);
} else if (token->kind == lex_kind_int && ((lex->at[0] == 'l' && lex->at[1] == 'l') || (lex->at[0] == 'L' && lex->at[1] == 'L'))) {
token->suffix = lex_suffix_ll;
lex_advance(lex); lex_advance(lex);
}
}
void lex_eat_until(lexer_t *lex, char c) {
while (lex->at[0] != c && lex->at[0] != 0) lex_advance(lex);
}
void lex_eat_string(lexer_t *lex, lex_t *token) {
token->kind = lex_kind_string;
for (;;) {
if (lex_match(lex, token->str[0])) {
break;
}
if (lex->at[0] == 0) {
lex_panicf(token, "unclosed string");
}
lex_advance(lex);
}
}
#define LEX_CASE3(C1, K1, C2, K2, C3, K3)\
case C1: {\
token->kind = K1;\
if (lex_match(lex, C2)) {\
lex_advance(lex);\
token->kind = K2;\
} else if (lex_match(lex, C3)) {\
lex_advance(lex);\
token->kind = K3;\
}\
} break
void lex_token_ex(lexer_t *lex, lex_t *token) {
lex_eat_whitespace(lex);
*token = (lex_t){.str = lex->at, .file_name = lex->file_name, .line = lex->line, .column = lex->column};
lex_advance(lex);
switch (token->str[0]) {
case '\0': token->kind = lex_kind_eof; break;
case '{': token->kind = lex_kind_open_brace; break;
case '}': token->kind = lex_kind_close_brace; break;
case '(': token->kind = lex_kind_open_paren; break;
case ')': token->kind = lex_kind_close_paren; break;
case '[': token->kind = lex_kind_open_bracket; break;
case ']': token->kind = lex_kind_close_bracket; break;
case '~': token->kind = lex_kind_bit_negation; break;
case ';': token->kind = lex_kind_semicolon; break;
case ':': token->kind = lex_kind_colon; break;
case ',': token->kind = lex_kind_comma; break;
case '"': lex_eat_string(lex, token); break;
case '`': lex_eat_string(lex, token); break;
case '\'': lex_eat_string(lex, token); break;
case '.': {
token->kind = lex_kind_dot;
if (lex->at[0] == '.' && lex->at[1] == '.') {
lex_advance(lex);
lex_advance(lex);
token->kind = lex_kind_three_dots;
}
} break;
case '/': {
token->kind = lex_kind_divide;
if (lex_match(lex, '/')) {
token->kind = lex_kind_comment;
lex_eat_until(lex, '\n');
} else if (lex_match(lex, '*')) {
token->kind = lex_kind_comment;
for (;;) {
if (lex->at[0] == '*' && lex->at[1] == '/') {
break;
}
if (lex->at[0] == 0) {
lex_panicf(token, "Unclosed block comment");
return;
}
lex_advance(lex);
}
lex_advance(lex);
lex_advance(lex);
} else if (lex_match(lex, '=')) {
token->kind = lex_kind_divide_assign;
lex_advance(lex);
}
} break;
LEX_CASE3('^', lex_kind_bit_xor, '=', lex_kind_bit_xor_assign, /*ignored option*/'=', lex_kind_bit_xor_assign);
LEX_CASE3('=', lex_kind_assign, '=', lex_kind_equals, /*ignored option*/'=', lex_kind_equals);
LEX_CASE3('!', lex_kind_negation, '=', lex_kind_not_equals, /*ignored option*/'=', lex_kind_not_equals);
LEX_CASE3('%', lex_kind_modulo, '=', lex_kind_modulo_assign, /*ignored option*/'=', lex_kind_modulo_assign);
LEX_CASE3('*', lex_kind_multiply, '=', lex_kind_multiply_assign, /*ignored option*/'=', lex_kind_multiply_assign);
LEX_CASE3('+', lex_kind_plus, '+', lex_kind_increment, '=', lex_kind_plus_assign);
LEX_CASE3('-', lex_kind_minus, '-', lex_kind_decrement, '=', lex_kind_minus_assign);
LEX_CASE3('&', lex_kind_bit_and, '&', lex_kind_and, '=', lex_kind_bit_and_assign);
LEX_CASE3('|', lex_kind_bit_or, '|', lex_kind_or, '=', lex_kind_bit_or_assign);
case '>': {
token->kind = lex_kind_greater;
if (lex_match(lex, '=')) {
token->kind = lex_kind_greater_or_equal;
} else if (lex_match(lex, '>')) {
token->kind = lex_kind_bit_right_shift;
if (lex_match(lex, '=')) {
token->kind = lex_kind_bit_right_shift_assign;
}
}
} break;
case '<': {
token->kind = lex_kind_lesser;
if (lex_match(lex, '=')) {
token->kind = lex_kind_lesser_or_equal;
}
else if (lex_match(lex, '<')) {
token->kind = lex_kind_bit_left_shift;
if (lex_match(lex, '=')) {
token->kind = lex_kind_bit_left_shift_assign;
}
}
} break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': {
lex_eat_number(lex, token);
} break;
case 'A': case 'a': case 'B': case 'b': case 'C': case 'c':
case 'D': case 'd': case 'E': case 'e': case 'F': case 'f':
case 'G': case 'g': case 'H': case 'h': case 'I': case 'i':
case 'J': case 'j': case 'K': case 'k': case 'L': case 'l':
case 'M': case 'm': case 'N': case 'n': case 'O': case 'o':
case 'P': case 'p': case 'Q': case 'q': case 'R': case 'r':
case 'S': case 's': case 'T': case 't': case 'U': case 'u':
case 'V': case 'v': case 'W': case 'w': case 'X': case 'x':
case 'Y': case 'y': case 'Z': case 'z': case '_': {
token->kind = lex_kind_ident;
while (char_is_alphanumeric(lex->at[0]) || lex->at[0] == '_') lex_advance(lex);
} break;
default: {
lex_panicf(token, "found invalid character in the token stream (%d)", token->str[0]);
}
}
token->len = (int)(lex->at - token->str);
if (token->kind == lex_kind_int) {
token->integer = lex_deserial_u64(token->str, token->len, 10);
} else if (token->kind == lex_kind_real) {
token->real = s8_deserial_f64(token->s8);
} else if (token->kind == lex_kind_string) {
token->str += 1;
token->len -= 2;
}
}
lex_t lex_token(lexer_t *lex) {
lex_t result = {0};
lex_token_ex(lex, &result);
return result;
}
// @todo: use s8_t instead
lex_array_t lex_tokens(ma_arena_t *arena, char *file_name, char *stream) {
usize align = arena->align;
arena->align = 0;
lex_array_t token_array = {0};
lexer_t l = lex_make(stream, file_name);
for (;;) {
lex_t *token = ma_push_type(arena, lex_t);
if (token_array.data == NULL) {
token_array.data = token;
}
token_array.len += 1;
do {
lex_token_ex(&l, token);
} while (token->kind == lex_kind_comment);
if (token->kind == lex_kind_eof) break;
}
arena->align = align;
return token_array;
}
s8_t global_lex_kind_simple_strings[] = {
#define X(KIND, STR, SIMPLE) s8_const_lit(SIMPLE),
LEX_KIND_XLIST
#undef X
};
s8_t s8_serial_simple_lex_kind_t(lex_kind_t kind) {
assert(kind >= 0 && kind < lex_kind_count);
return global_lex_kind_simple_strings[kind];
}
s8_t global_lex_kind_strings[] = {
#define X(KIND, STR, SIMPLE) s8_const_lit(STR),
LEX_KIND_XLIST
#undef X
};
s8_t s8_serial_lex_kind_t(lex_kind_t kind) {
assert(kind >= 0 && kind < lex_kind_count);
return global_lex_kind_strings[kind];
}
type_member_t members__lex_kind_t[] = {
#define X(KIND, STR, SIMPLE) {.name = s8_const_lit("lex_kind_" #KIND), .value = lex_kind_##KIND},
LEX_KIND_XLIST
#undef X
};
DEFINE_ENUM(lex_kind_t);
type_member_t members__lex_suffix_t[] = {
#define X(KIND) {.name = s8_const_lit("lex_suffix_" #KIND), .value = lex_suffix_##KIND},
LEX_SUFFIX_XLIST
#undef X
};
DEFINE_ENUM(lex_suffix_t);
//
//
typedef struct parser_t parser_t;
struct parser_t {
ma_arena_t *arena;
lex_t *at;
};
#define parser_make(ARENA, TOKEN) &(parser_t){.arena = ARENA, .at = TOKEN}
lex_t *parser_next(parser_t *par) {
lex_t *result = par->at;
if (result->kind != lex_kind_eof) par->at += 1;
return result;
}
lex_t *parser_match(parser_t *par, lex_kind_t kind) {
if (par->at->kind == kind) {
return parser_next(par);
} else {
return NULL;
}
}
lex_t *parser_matchi(parser_t *par, s8_t str) {
if (par->at->kind == lex_kind_ident && s8_equal(par->at->s8, str)) {
return parser_next(par);
} else {
return NULL;
}
}
lex_t *parser_expect(parser_t *par, lex_kind_t kind) {
lex_t *token = parser_match(par, kind);
if (!token) lex_panicf(par->at, "expected token kind: %S, got instead: %S", s8_serial_lex_kind_t(kind), s8_serial_lex_kind_t(par->at->kind));
return token;
}
void parser_eat_until(parser_t *par, lex_kind_t kind) {
while (par->at->kind != kind && par->at->kind != lex_kind_eof) {
parser_next(par);
}
}
void parser_eat_including(parser_t *par, lex_kind_t kind) {
parser_eat_until(par, kind);
parser_next(par);
}

27
src/core/log.c Normal file
View File

@@ -0,0 +1,27 @@
void panicf(const char *_str, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, _str, str);
core_desc.print(str.str);
core_desc.print("\n");
if (core_desc.break_on_panic) {
debug_break();
} else {
core_desc.panic();
}
ma_end_scratch(scratch);
}
void debugexf(const char *_str, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, _str, str);
core_desc.print(str.str);
ma_end_scratch(scratch);
}
void debugf(const char *_str, ...) {
ma_temp_t scratch = ma_begin_scratch();
S8_FMT(scratch.arena, _str, str);
core_desc.print(str.str);
core_desc.print("\n");
ma_end_scratch(scratch);
}

291
src/core/math_gen.py Normal file
View File

@@ -0,0 +1,291 @@
import sys
op_idx = 0
opname_idx = 1
symbols = [
["+", "add"],
["-", "sub"],
["*", "mul"],
["/", "div"],
]
basic_types = [
"f32",
"f64",
"i32",
"i64",
]
name_idx = 0
member_idx = 1
vec_types = [
["v2", ["x", "y"]],
["v3", ["x", "y", "z"]],
["v4", ["x", "y", "z", "w"]],
]
rect_types = [
["r2", ["x0", "y0", "x1", "y1"]],
["r3", ["x0", "y0", "z0", "x1", "y1", "z1"]],
]
struct_types = vec_types + rect_types
# fd = open("mathx.gen.h", "w")
# sys.stdout = fd
# print("// auto generated using:", __file__)
# for bt in basic_types:
# s = """
# typedef union v2f64_t v2f64_t;
# union v2f64_t {
# struct { f64 x, y; };
# f64 e[2];
# };
# typedef union v3f64_t v3f64_t;
# union v3f64_t {
# struct { f64 x, y, z; };
# struct { v2f64_t xy; };
# struct { f64 _x0; v2f64_t zw; };
# struct { f64 r, g, b; };
# struct { f64 h, s, l; };
# f64 e[3];
# };
# typedef union v4f64_t v4f64_t;
# union v4f64_t {
# struct { f64 x, y, z, w; };
# struct { v2f64_t xy; v2f64_t zw; };
# struct { v3f64_t xyz; };
# struct { f64 _x0; f64 yzw; };
# struct { f64 r, g, b, a; };
# struct { f64 h, s, l, _a; };
# f64 e[4];
# };
# typedef union r1f64_t r1f64_t;
# union r1f64_t {
# struct { f64 min, max; };
# struct { f64 x0, x1; };
# f64 e[2];
# };
# typedef union r2f64_t r2f64_t;
# union r2f64_t {
# struct { v2f64_t min, max; };
# struct { f64 x0, y0, x1, y1; };
# v4f64_t e4;
# f64 e[4];
# };
# typedef union r3f64_t r3f64_t;
# union r3f64_t {
# struct { v3f64_t min, max; };
# struct { f64 x0, y0, z0, x1, y1, z1; };
# f64 e[6];
# };
#
#
# type_t type__v2f64_t = { type_kind_struct, s8_const_lit("v2f64_t"), sizeof(v2f64_t), .count = 2,
# .members = (type_member_t[]){
# {s8_const_lit("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
# {s8_const_lit("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
# }
# };
# type_t type__v3f64_t = { type_kind_struct, s8_const_lit("v3f64_t"), sizeof(v3f64_t), .count = 3,
# .members = (type_member_t[]){
# {s8_const_lit("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
# {s8_const_lit("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
# {s8_const_lit("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
# }
# };
# type_t type__v4f64_t = { type_kind_struct, s8_const_lit("v4f64_t"), sizeof(v4f64_t), .count = 4,
# .members = (type_member_t[]){
# {s8_const_lit("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
# {s8_const_lit("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
# {s8_const_lit("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
# {s8_const_lit("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
# }
# };
# type_t type__r3f64_t = { type_kind_struct, s8_const_lit("r3f64_t"), sizeof(r3f64_t), .count = 6,
# .members = (type_member_t[]){
# {s8_const_lit("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
# {s8_const_lit("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
# {s8_const_lit("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
# {s8_const_lit("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
# {s8_const_lit("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
# {s8_const_lit("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
# }
# };
# type_member_t members__r2f64_t[] = {
# {s8_const_lit("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
# {s8_const_lit("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
# {s8_const_lit("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
# {s8_const_lit("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
# };
# DEFINE_STRUCT(r2f64_t);
# type_member_t members__r1f64_t[] = {
# {s8_const_lit("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
# {s8_const_lit("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
# };
# DEFINE_STRUCT(r1f64_t);
# """
# s = s.replace("f64", bt)
# print(s)
fd = open("mathx.gen.c", "w")
sys.stdout = fd
print("// auto generated using:", __file__)
for basic_type in basic_types:
for st in struct_types:
type = f"{st[name_idx]}{basic_type}"
typedef = f"{type}_t"
members = st[member_idx]
def members_as_func_params(members, basic_type):
result = ""
for i, m in enumerate(members):
result += f"{basic_type} {m}"
if i != len(members) - 1:
result += ", "
return result
print(f"""{type}_t {type}({members_as_func_params(members, basic_type)}) {{ return ({type}_t){{ {members_as_func_params(members, "")} }}; }}""")
for sym in symbols:
op = sym[op_idx]
opname = sym[opname_idx]
def op_str(members, op, skip_right = False):
result = ""
for i in range(len(members)):
mem = members[i]
if skip_right:
result += f"a.{mem} {op} b"
else:
result += f"a.{mem} {op} b.{mem}"
if i != len(members) - 1:
result += ", "
return result
print(f"{type}_t {type}_{opname}({type}_t a, {type}_t b) {{ return ({type}_t){{ {op_str(members, op)} }}; }}")
print(f"{type}_t {type}_{opname}s({type}_t a, {basic_type} b) {{ return ({type}_t){{ {op_str(members, op, skip_right = True)} }}; }}")
for basic_type in basic_types:
for i in range(len(rect_types)):
vec_type = vec_types[i]
rect_type = rect_types[i]
vec_name = vec_type[name_idx] + basic_type
vec_members = vec_type[member_idx]
rect_name = rect_type[name_idx] + basic_type
rect_members = rect_type[member_idx]
print(f"{rect_name}_t {rect_name}_mindim({vec_name}_t pos, {vec_name}_t size) {{ return ({rect_name}_t){{ pos, {vec_name}_add(pos, size) }}; }}")
print(f"{rect_name}_t {rect_name}_center_halfdim({vec_name}_t center, {vec_name}_t halfdim) {{ return ({rect_name}_t){{ {vec_name}_sub(center, halfdim), {vec_name}_add(center, halfdim) }}; }}")
for basic_type in basic_types:
s = """
r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
return (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
}
r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
return (r2f64_t){ .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
}
r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
return (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
}
r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
return (r2f64_t){ .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
}
// get past left
r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
v2f64_t r2f64_get_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_get_size(r), 2)); }
b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
"""
s = s.replace("r2f64", f"r2{basic_type}")
s = s.replace("f64", basic_type)
s = s.replace("v2f64", f"v2{basic_type}")
print(s)
for at in basic_types:
for bt in basic_types:
if at == bt: continue
for st in struct_types:
atype = f"{st[name_idx]}{at}"
btype = f"{st[name_idx]}{bt}"
members = st[member_idx]
def cast_members(members, type):
result = ""
for i in range(len(members)):
result += f"({type})v.{members[i]}"
if i != len(members) - 1:
result += ", "
return result
print(f"{btype}_t {atype}_to_{btype}({atype}_t v) {{ return ({btype}_t){{ {cast_members(members, bt)} }}; }}")

520
src/core/mathx.c Normal file
View File

@@ -0,0 +1,520 @@
#define F64_PI (3.1415926535897932384626433832795028841971693994)
#define F64_DEG2RAD (F64_PI / 180.0); // @Usage: degree * DEG2RAD = radians;
#define F64_RAD2DEG (180.0 / F64_PI);
#define F32_PI ((f32)F64_PI)
#define rgba_macro_const(r, g, b, a) { r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f }
v4f32_t primary_color_global = rgba_macro_const(245, 238, 230, 255);
v4f32_t secondary_color_global = rgba_macro_const(255, 248, 227, 255);
v4f32_t accent1_color_global = rgba_macro_const(243, 215, 202, 255);
v4f32_t accent2_color_global = rgba_macro_const(230, 164, 180, 255);
v4f32_t white_color_global = rgba_macro_const(255, 255, 255, 255);
v4f32_t black_color_global = rgba_macro_const(0, 0, 0, 255);
/*
* Converts an RGB color value to HSL. Conversion formula
* adapted from http://en.wikipedia.org/wiki/HSL_color_space.
* also https://gist.github.com/ciembor/1494530
* alpha is ignored
*/
v3f32_t v3f32_rgb_to_hsl(v3f32_t color) {
v3f32_t result;
f32 max = MAX(MAX(color.r, color.g), color.b);
f32 min = MIN(MIN(color.r, color.g), color.b);
result.h = result.s = result.l = (max + min) / 2.f;
if (max == min) {
result.h = result.s = 0.f; // achromatic
} else {
f32 d = max - min;
result.s = (result.l > 0.5f) ? d / (2.f - max - min) : d / (max + min);
if (max == color.r) {
result.h = (color.g - color.b) / d + (color.g < color.b ? 6.f : 0.f);
} else if (max == color.g) {
result.h = (color.b - color.r) / d + 2.f;
} else if (max == color.b) {
result.h = (color.r - color.g) / d + 4.f;
}
result.h /= 6.f;
}
return result;
}
/*
* Converts an HUE to r, g or b.
* returns f32 in the set [0, 1].
*/
f32 f32_hue_to_rgb(f32 p, f32 q, f32 t) {
if (t < 0.f)
t += 1.f;
if (t > 1.f)
t -= 1.f;
if (t < 1.f / 6.f)
return p + (q - p) * 6.f * t;
if (t < 1.f / 2.f)
return q;
if (t < 2.f / 3.f)
return p + (q - p) * (2.f / 3.f - t) * 6.f;
return p;
}
v3f32_t v3f32_hsl_to_rgb(v3f32_t color) {
v3f32_t result;
if (0 == color.s) {
result.r = result.g = result.b = color.l; // achromatic
} else {
f32 q = color.l < 0.5f ? color.l * (1.f + color.s)
: color.l + color.s - color.l * color.s;
f32 p = 2.f * color.l - q;
result.r = f32_hue_to_rgb(p, q, color.h + 1.f / 3.f);
result.g = f32_hue_to_rgb(p, q, color.h);
result.b = f32_hue_to_rgb(p, q, color.h - 1.f / 3.f);
}
return result;
}
v4f32_t v4f32_rgba_to_hsla(v4f32_t rgba) {
v3f32_t result = v3f32_rgb_to_hsl(rgba.xyz);
return (v4f32_t){result.r, result.g, result.b, rgba.a};
}
v4f32_t v4f32_hsl_to_rgb(v4f32_t color) {
v3f32_t result = v3f32_hsl_to_rgb(color.xyz);
return (v4f32_t){result.r, result.g, result.b, color.a};
}
/*
https://git.musl-libc.org/cgit/musl/tree/src/math
https://gitlab.com/nakst/essence/-/blob/master/shared/math.cpp
*/
f64 f64_lerp(f64 a, f64 b, f64 t) { return (1 - t) * a + t * b; }
f64 f64_smooth_step(f64 t) { return t*t*(3-2*t); }
f64 f64_ease_in_quint(f64 x) { return x * x * x * x * x; }
f64 f64_ease_in_cubic(f64 x) { return x * x * x; }
f64 f64_ping_pong(f64 x) { return 1.0 - f64_abs(1.0 - f64_mod(x,2)); }
f32 f32_lerp(f32 a, f32 b, f32 t) { return (1 - t) * a + t * b; }
f32 f32_smooth_step(f32 t) { return t*t*(3-2*t); }
f32 f32_ease_in_quint(f32 x) { return x * x * x * x * x; }
f32 f32_ease_in_cubic(f32 x) { return x * x * x; }
f32 f32_ping_pong(f32 x) { return 1.0f - f32_abs(1.0f - f32_mod(x,2)); }
v4f32_t v4f32_lerp(v4f32_t a, v4f32_t b, f32 t) {
return (v4f32_t){f32_lerp(a.x, a.y, t), f32_lerp(a.y, b.y, t), f32_lerp(a.z, b.z, t), f32_lerp(a.w, b.w, t)};
}
#if PLATFORM_CL
#pragma warning(disable: 4116)
#endif
#define U64ToF64(x) (((union { f64 d; u64 i; }) { .i = (x) }).d)
#define U32ToF32(x) (((union { f32 f; u32 i; }) { .i = (x) }).f)
f64 _Sine(f64 x) {
// Calculates sin(x) for x in [0, pi/4].
f64 x2 = x * x;
return x * (U64ToF64(0x3FF0000000000000) + x2 * (U64ToF64(0xBFC5555555555540) + x2 * (U64ToF64(0x3F8111111110ED80) + x2 * (U64ToF64(0xBF2A01A019AE6000)
+ x2 * (U64ToF64(0x3EC71DE349280000) + x2 * (U64ToF64(0xBE5AE5DC48000000) + x2 * U64ToF64(0x3DE5D68200000000)))))));
}
f32 _SineFloat(f32 x) {
// Calculates sin(x) for x in [0, pi/4].
f32 x2 = x * x;
return x * (U32ToF32(0x3F800000) + x2 * (U32ToF32(0xBE2AAAA0) + x2 * (U32ToF32(0x3C0882C0) + x2 * U32ToF32(0xB94C6000))));
}
f64 _ArcSine(f64 x) {
// Calculates arcsin(x) for x in [0, 0.5].
f64 x2 = x * x;
return x * (U64ToF64(0x3FEFFFFFFFFFFFE6) + x2 * (U64ToF64(0x3FC555555555FE00) + x2 * (U64ToF64(0x3FB333333292DF90) + x2 * (U64ToF64(0x3FA6DB6DFD3693A0)
+ x2 * (U64ToF64(0x3F9F1C608DE51900) + x2 * (U64ToF64(0x3F96EA0659B9A080) + x2 * (U64ToF64(0x3F91B4ABF1029100)
+ x2 * (U64ToF64(0x3F8DA8DAF31ECD00) + x2 * (U64ToF64(0x3F81C01FD5000C00) + x2 * (U64ToF64(0x3F94BDA038CF6B00)
+ x2 * (U64ToF64(0xBF8E849CA75B1E00) + x2 * U64ToF64(0x3FA146C2D37F2C60))))))))))));
}
f32 _ArcSineFloat(f32 x) {
// Calculates arcsin(x) for x in [0, 0.5].
f32 x2 = x * x;
return x * (U32ToF32(0x3F800004) + x2 * (U32ToF32(0x3E2AA130) + x2 * (U32ToF32(0x3D9B2C28) + x2 * (U32ToF32(0x3D1C1800) + x2 * U32ToF32(0x3D5A97C0)))));
}
f64 _ArcTangent(f64 x) {
// Calculates arctan(x) for x in [0, 0.5].
f64 x2 = x * x;
return x * (U64ToF64(0x3FEFFFFFFFFFFFF8) + x2 * (U64ToF64(0xBFD5555555553B44) + x2 * (U64ToF64(0x3FC9999999803988) + x2 * (U64ToF64(0xBFC249248C882E80)
+ x2 * (U64ToF64(0x3FBC71C5A4E4C220) + x2 * (U64ToF64(0xBFB745B3B75243F0) + x2 * (U64ToF64(0x3FB3AFAE9A2939E0)
+ x2 * (U64ToF64(0xBFB1030C4A4A1B90) + x2 * (U64ToF64(0x3FAD6F65C35579A0) + x2 * (U64ToF64(0xBFA805BCFDAFEDC0)
+ x2 * (U64ToF64(0x3F9FC6B5E115F2C0) + x2 * U64ToF64(0xBF87DCA5AB25BF80))))))))))));
}
f32 _ArcTangentFloat(f32 x) {
// Calculates arctan(x) for x in [0, 0.5].
f32 x2 = x * x;
return x * (U32ToF32(0x3F7FFFF8) + x2 * (U32ToF32(0xBEAAA53C) + x2 * (U32ToF32(0x3E4BC990) + x2 * (U32ToF32(0xBE084A60) + x2 * U32ToF32(0x3D8864B0)))));
}
f64 _Cosine(f64 x) {
// Calculates cos(x) for x in [0, pi/4].
f64 x2 = x * x;
return U64ToF64(0x3FF0000000000000) + x2 * (U64ToF64(0xBFDFFFFFFFFFFFA0) + x2 * (U64ToF64(0x3FA555555554F7C0) + x2 * (U64ToF64(0xBF56C16C16475C00)
+ x2 * (U64ToF64(0x3EFA019F87490000) + x2 * (U64ToF64(0xBE927DF66B000000) + x2 * U64ToF64(0x3E21B949E0000000))))));
}
f32 _CosineFloat(f32 x) {
// Calculates cos(x) for x in [0, pi/4].
f32 x2 = x * x;
return U32ToF32(0x3F800000) + x2 * (U32ToF32(0xBEFFFFDA) + x2 * (U32ToF32(0x3D2A9F60) + x2 * U32ToF32(0xBAB22C00)));
}
f64 _Tangent(f64 x) {
// Calculates tan(x) for x in [0, pi/4].
f64 x2 = x * x;
return x * (U64ToF64(0x3FEFFFFFFFFFFFE8) + x2 * (U64ToF64(0x3FD5555555558000) + x2 * (U64ToF64(0x3FC1111110FACF90) + x2 * (U64ToF64(0x3FABA1BA266BFD20)
+ x2 * (U64ToF64(0x3F9664F30E56E580) + x2 * (U64ToF64(0x3F822703B08BDC00) + x2 * (U64ToF64(0x3F6D698D2E4A4C00)
+ x2 * (U64ToF64(0x3F57FF4F23EA4400) + x2 * (U64ToF64(0x3F424F3BEC845800) + x2 * (U64ToF64(0x3F34C78CA9F61000)
+ x2 * (U64ToF64(0xBF042089F8510000) + x2 * (U64ToF64(0x3F29D7372D3A8000) + x2 * (U64ToF64(0xBF19D1C5EF6F0000)
+ x2 * (U64ToF64(0x3F0980BDF11E8000)))))))))))))));
}
f32 _TangentFloat(f32 x) {
// Calculates tan(x) for x in [0, pi/4].
f32 x2 = x * x;
return x * (U32ToF32(0x3F800001) + x2 * (U32ToF32(0x3EAAA9AA) + x2 * (U32ToF32(0x3E08ABA8) + x2 * (U32ToF32(0x3D58EC90)
+ x2 * (U32ToF32(0x3CD24840) + x2 * (U32ToF32(0x3AC3CA00) + x2 * U32ToF32(0x3C272F00)))))));
}
f64 f64_sin(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = true;
}
// x in 0, infty
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
// x in 0, 2*pi
if (x < F64_PI / 2) {
} else if (x < F64_PI) {
x = F64_PI - x;
} else if (x < 3 * F64_PI / 2) {
x = x - F64_PI;
negate = !negate;
} else {
x = F64_PI * 2 - x;
negate = !negate;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Sine(x) : _Cosine(F64_PI / 2 - x);
return negate ? -y : y;
}
f32 f32_sin(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = true;
}
// x in 0, infty
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
// x in 0, 2*pi
if (x < F32_PI / 2) {
} else if (x < F32_PI) {
x = F32_PI - x;
} else if (x < 3 * F32_PI / 2) {
x = x - F32_PI;
negate = !negate;
} else {
x = F32_PI * 2 - x;
negate = !negate;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _SineFloat(x) : _CosineFloat(F32_PI / 2 - x);
return negate ? -y : y;
}
f64 f64_cos(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
}
// x in 0, infty
x -= 2 * F64_PI * f64_floor(x / (2 * F64_PI));
// x in 0, 2*pi
if (x < F64_PI / 2) {
} else if (x < F64_PI) {
x = F64_PI - x;
negate = !negate;
} else if (x < 3 * F64_PI / 2) {
x = x - F64_PI;
negate = !negate;
} else {
x = F64_PI * 2 - x;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Cosine(x) : _Sine(F64_PI / 2 - x);
return negate ? -y : y;
}
f32 f32_cos(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
}
// x in 0, infty
x -= 2 * F32_PI * f32_floor(x / (2 * F32_PI));
// x in 0, 2*pi
if (x < F32_PI / 2) {
} else if (x < F32_PI) {
x = F32_PI - x;
negate = !negate;
} else if (x < 3 * F32_PI / 2) {
x = x - F32_PI;
negate = !negate;
} else {
x = F32_PI * 2 - x;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _CosineFloat(x) : _SineFloat(F32_PI / 2 - x);
return negate ? -y : y;
}
f64 f64_tan(f64 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = !negate;
}
// x in 0, infty
x -= F64_PI * f64_floor(x / F64_PI);
// x in 0, pi
if (x > F64_PI / 2) {
x = F64_PI - x;
negate = !negate;
}
// x in 0, pi/2
f64 y = x < F64_PI / 4 ? _Tangent(x) : (1.0 / _Tangent(F64_PI / 2 - x));
return negate ? -y : y;
}
f32 f32_tan(f32 x) {
b32 negate = false;
// x in -infty, infty
if (x < 0) {
x = -x;
negate = !negate;
}
// x in 0, infty
x -= F32_PI * f32_floor(x / F32_PI);
// x in 0, pi
if (x > F32_PI / 2) {
x = F32_PI - x;
negate = !negate;
}
// x in 0, pi/2
f32 y = x < F32_PI / 4 ? _TangentFloat(x) : (1.0f / _TangentFloat(F32_PI / 2 - x));
return negate ? -y : y;
}
f64 f64_asin(f64 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
f64 y;
if (x < 0.5) {
y = _ArcSine(x);
} else {
y = F64_PI / 2 - 2 * _ArcSine(f64_sqrt(0.5 - 0.5 * x));
}
return negate ? -y : y;
}
f32 f32_asin(f32 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
f32 y;
if (x < 0.5) {
y = _ArcSineFloat(x);
} else {
y = F32_PI / 2 - 2 * _ArcSineFloat(f32_sqrt(0.5f - 0.5f * x));
}
return negate ? -y : y;
}
f64 f64_acos(f64 x) {
return f64_asin(-x) + F64_PI / 2;
}
f32 f32_acos(f32 x) {
return f32_asin(-x) + F32_PI / 2;
}
f64 f64_atan(f64 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
b32 reciprocalTaken = false;
if (x > 1) {
x = 1 / x;
reciprocalTaken = true;
}
f64 y;
if (x < 0.5) {
y = _ArcTangent(x);
} else {
y = 0.463647609000806116 + _ArcTangent((2 * x - 1) / (2 + x));
}
if (reciprocalTaken) {
y = F64_PI / 2 - y;
}
return negate ? -y : y;
}
f32 f32_atan(f32 x) {
b32 negate = false;
if (x < 0) {
x = -x;
negate = true;
}
b32 reciprocalTaken = false;
if (x > 1) {
x = 1 / x;
reciprocalTaken = true;
}
f32 y;
if (x < 0.5f) {
y = _ArcTangentFloat(x);
} else {
y = 0.463647609000806116f + _ArcTangentFloat((2 * x - 1) / (2 + x));
}
if (reciprocalTaken) {
y = F32_PI / 2 - y;
}
return negate ? -y : y;
}
f64 f64_atan2(f64 y, f64 x) {
if (x == 0) return y > 0 ? F64_PI / 2 : -F64_PI / 2;
else if (x > 0) return f64_atan(y / x);
else if (y >= 0) return F64_PI + f64_atan(y / x);
else return -F64_PI + f64_atan(y / x);
}
f32 f32_atan2(f32 y, f32 x) {
if (x == 0) return y > 0 ? F32_PI / 2 : -F32_PI / 2;
else if (x > 0) return f32_atan(y / x);
else if (y >= 0) return F32_PI + f32_atan(y / x);
else return -F32_PI + f32_atan(y / x);
}

519
src/core/mathx.gen.c Normal file
View File

@@ -0,0 +1,519 @@
// auto generated using: D:\dev\wasm\src\core\math_gen.py
v2f32_t v2f32(f32 x, f32 y) { return (v2f32_t){ x, y }; }
v2f32_t v2f32_add(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x + b.x, a.y + b.y }; }
v2f32_t v2f32_adds(v2f32_t a, f32 b) { return (v2f32_t){ a.x + b, a.y + b }; }
v2f32_t v2f32_sub(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x - b.x, a.y - b.y }; }
v2f32_t v2f32_subs(v2f32_t a, f32 b) { return (v2f32_t){ a.x - b, a.y - b }; }
v2f32_t v2f32_mul(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x * b.x, a.y * b.y }; }
v2f32_t v2f32_muls(v2f32_t a, f32 b) { return (v2f32_t){ a.x * b, a.y * b }; }
v2f32_t v2f32_div(v2f32_t a, v2f32_t b) { return (v2f32_t){ a.x / b.x, a.y / b.y }; }
v2f32_t v2f32_divs(v2f32_t a, f32 b) { return (v2f32_t){ a.x / b, a.y / b }; }
v3f32_t v3f32(f32 x, f32 y, f32 z) { return (v3f32_t){ x, y, z }; }
v3f32_t v3f32_add(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
v3f32_t v3f32_adds(v3f32_t a, f32 b) { return (v3f32_t){ a.x + b, a.y + b, a.z + b }; }
v3f32_t v3f32_sub(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
v3f32_t v3f32_subs(v3f32_t a, f32 b) { return (v3f32_t){ a.x - b, a.y - b, a.z - b }; }
v3f32_t v3f32_mul(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
v3f32_t v3f32_muls(v3f32_t a, f32 b) { return (v3f32_t){ a.x * b, a.y * b, a.z * b }; }
v3f32_t v3f32_div(v3f32_t a, v3f32_t b) { return (v3f32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
v3f32_t v3f32_divs(v3f32_t a, f32 b) { return (v3f32_t){ a.x / b, a.y / b, a.z / b }; }
v4f32_t v4f32(f32 x, f32 y, f32 z, f32 w) { return (v4f32_t){ x, y, z, w }; }
v4f32_t v4f32_add(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
v4f32_t v4f32_adds(v4f32_t a, f32 b) { return (v4f32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
v4f32_t v4f32_sub(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
v4f32_t v4f32_subs(v4f32_t a, f32 b) { return (v4f32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
v4f32_t v4f32_mul(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
v4f32_t v4f32_muls(v4f32_t a, f32 b) { return (v4f32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
v4f32_t v4f32_div(v4f32_t a, v4f32_t b) { return (v4f32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
v4f32_t v4f32_divs(v4f32_t a, f32 b) { return (v4f32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
r2f32_t r2f32(f32 x0, f32 y0, f32 x1, f32 y1) { return (r2f32_t){ x0, y0, x1, y1 }; }
r2f32_t r2f32_add(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
r2f32_t r2f32_adds(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
r2f32_t r2f32_sub(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
r2f32_t r2f32_subs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
r2f32_t r2f32_mul(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
r2f32_t r2f32_muls(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
r2f32_t r2f32_div(r2f32_t a, r2f32_t b) { return (r2f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
r2f32_t r2f32_divs(r2f32_t a, f32 b) { return (r2f32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
r3f32_t r3f32(f32 x0, f32 y0, f32 z0, f32 x1, f32 y1, f32 z1) { return (r3f32_t){ x0, y0, z0, x1, y1, z1 }; }
r3f32_t r3f32_add(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
r3f32_t r3f32_adds(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
r3f32_t r3f32_sub(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
r3f32_t r3f32_subs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
r3f32_t r3f32_mul(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
r3f32_t r3f32_muls(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
r3f32_t r3f32_div(r3f32_t a, r3f32_t b) { return (r3f32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
r3f32_t r3f32_divs(r3f32_t a, f32 b) { return (r3f32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
v2f64_t v2f64(f64 x, f64 y) { return (v2f64_t){ x, y }; }
v2f64_t v2f64_add(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x + b.x, a.y + b.y }; }
v2f64_t v2f64_adds(v2f64_t a, f64 b) { return (v2f64_t){ a.x + b, a.y + b }; }
v2f64_t v2f64_sub(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x - b.x, a.y - b.y }; }
v2f64_t v2f64_subs(v2f64_t a, f64 b) { return (v2f64_t){ a.x - b, a.y - b }; }
v2f64_t v2f64_mul(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x * b.x, a.y * b.y }; }
v2f64_t v2f64_muls(v2f64_t a, f64 b) { return (v2f64_t){ a.x * b, a.y * b }; }
v2f64_t v2f64_div(v2f64_t a, v2f64_t b) { return (v2f64_t){ a.x / b.x, a.y / b.y }; }
v2f64_t v2f64_divs(v2f64_t a, f64 b) { return (v2f64_t){ a.x / b, a.y / b }; }
v3f64_t v3f64(f64 x, f64 y, f64 z) { return (v3f64_t){ x, y, z }; }
v3f64_t v3f64_add(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
v3f64_t v3f64_adds(v3f64_t a, f64 b) { return (v3f64_t){ a.x + b, a.y + b, a.z + b }; }
v3f64_t v3f64_sub(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
v3f64_t v3f64_subs(v3f64_t a, f64 b) { return (v3f64_t){ a.x - b, a.y - b, a.z - b }; }
v3f64_t v3f64_mul(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
v3f64_t v3f64_muls(v3f64_t a, f64 b) { return (v3f64_t){ a.x * b, a.y * b, a.z * b }; }
v3f64_t v3f64_div(v3f64_t a, v3f64_t b) { return (v3f64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
v3f64_t v3f64_divs(v3f64_t a, f64 b) { return (v3f64_t){ a.x / b, a.y / b, a.z / b }; }
v4f64_t v4f64(f64 x, f64 y, f64 z, f64 w) { return (v4f64_t){ x, y, z, w }; }
v4f64_t v4f64_add(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
v4f64_t v4f64_adds(v4f64_t a, f64 b) { return (v4f64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
v4f64_t v4f64_sub(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
v4f64_t v4f64_subs(v4f64_t a, f64 b) { return (v4f64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
v4f64_t v4f64_mul(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
v4f64_t v4f64_muls(v4f64_t a, f64 b) { return (v4f64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
v4f64_t v4f64_div(v4f64_t a, v4f64_t b) { return (v4f64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
v4f64_t v4f64_divs(v4f64_t a, f64 b) { return (v4f64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
r2f64_t r2f64(f64 x0, f64 y0, f64 x1, f64 y1) { return (r2f64_t){ x0, y0, x1, y1 }; }
r2f64_t r2f64_add(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
r2f64_t r2f64_adds(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
r2f64_t r2f64_sub(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
r2f64_t r2f64_subs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
r2f64_t r2f64_mul(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
r2f64_t r2f64_muls(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
r2f64_t r2f64_div(r2f64_t a, r2f64_t b) { return (r2f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
r2f64_t r2f64_divs(r2f64_t a, f64 b) { return (r2f64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
r3f64_t r3f64(f64 x0, f64 y0, f64 z0, f64 x1, f64 y1, f64 z1) { return (r3f64_t){ x0, y0, z0, x1, y1, z1 }; }
r3f64_t r3f64_add(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
r3f64_t r3f64_adds(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
r3f64_t r3f64_sub(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
r3f64_t r3f64_subs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
r3f64_t r3f64_mul(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
r3f64_t r3f64_muls(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
r3f64_t r3f64_div(r3f64_t a, r3f64_t b) { return (r3f64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
r3f64_t r3f64_divs(r3f64_t a, f64 b) { return (r3f64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
v2i32_t v2i32(i32 x, i32 y) { return (v2i32_t){ x, y }; }
v2i32_t v2i32_add(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x + b.x, a.y + b.y }; }
v2i32_t v2i32_adds(v2i32_t a, i32 b) { return (v2i32_t){ a.x + b, a.y + b }; }
v2i32_t v2i32_sub(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x - b.x, a.y - b.y }; }
v2i32_t v2i32_subs(v2i32_t a, i32 b) { return (v2i32_t){ a.x - b, a.y - b }; }
v2i32_t v2i32_mul(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x * b.x, a.y * b.y }; }
v2i32_t v2i32_muls(v2i32_t a, i32 b) { return (v2i32_t){ a.x * b, a.y * b }; }
v2i32_t v2i32_div(v2i32_t a, v2i32_t b) { return (v2i32_t){ a.x / b.x, a.y / b.y }; }
v2i32_t v2i32_divs(v2i32_t a, i32 b) { return (v2i32_t){ a.x / b, a.y / b }; }
v3i32_t v3i32(i32 x, i32 y, i32 z) { return (v3i32_t){ x, y, z }; }
v3i32_t v3i32_add(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
v3i32_t v3i32_adds(v3i32_t a, i32 b) { return (v3i32_t){ a.x + b, a.y + b, a.z + b }; }
v3i32_t v3i32_sub(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
v3i32_t v3i32_subs(v3i32_t a, i32 b) { return (v3i32_t){ a.x - b, a.y - b, a.z - b }; }
v3i32_t v3i32_mul(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
v3i32_t v3i32_muls(v3i32_t a, i32 b) { return (v3i32_t){ a.x * b, a.y * b, a.z * b }; }
v3i32_t v3i32_div(v3i32_t a, v3i32_t b) { return (v3i32_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
v3i32_t v3i32_divs(v3i32_t a, i32 b) { return (v3i32_t){ a.x / b, a.y / b, a.z / b }; }
v4i32_t v4i32(i32 x, i32 y, i32 z, i32 w) { return (v4i32_t){ x, y, z, w }; }
v4i32_t v4i32_add(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
v4i32_t v4i32_adds(v4i32_t a, i32 b) { return (v4i32_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
v4i32_t v4i32_sub(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
v4i32_t v4i32_subs(v4i32_t a, i32 b) { return (v4i32_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
v4i32_t v4i32_mul(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
v4i32_t v4i32_muls(v4i32_t a, i32 b) { return (v4i32_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
v4i32_t v4i32_div(v4i32_t a, v4i32_t b) { return (v4i32_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
v4i32_t v4i32_divs(v4i32_t a, i32 b) { return (v4i32_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
r2i32_t r2i32(i32 x0, i32 y0, i32 x1, i32 y1) { return (r2i32_t){ x0, y0, x1, y1 }; }
r2i32_t r2i32_add(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
r2i32_t r2i32_adds(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
r2i32_t r2i32_sub(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
r2i32_t r2i32_subs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
r2i32_t r2i32_mul(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
r2i32_t r2i32_muls(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
r2i32_t r2i32_div(r2i32_t a, r2i32_t b) { return (r2i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
r2i32_t r2i32_divs(r2i32_t a, i32 b) { return (r2i32_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
r3i32_t r3i32(i32 x0, i32 y0, i32 z0, i32 x1, i32 y1, i32 z1) { return (r3i32_t){ x0, y0, z0, x1, y1, z1 }; }
r3i32_t r3i32_add(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
r3i32_t r3i32_adds(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
r3i32_t r3i32_sub(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
r3i32_t r3i32_subs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
r3i32_t r3i32_mul(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
r3i32_t r3i32_muls(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
r3i32_t r3i32_div(r3i32_t a, r3i32_t b) { return (r3i32_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
r3i32_t r3i32_divs(r3i32_t a, i32 b) { return (r3i32_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
v2i64_t v2i64(i64 x, i64 y) { return (v2i64_t){ x, y }; }
v2i64_t v2i64_add(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x + b.x, a.y + b.y }; }
v2i64_t v2i64_adds(v2i64_t a, i64 b) { return (v2i64_t){ a.x + b, a.y + b }; }
v2i64_t v2i64_sub(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x - b.x, a.y - b.y }; }
v2i64_t v2i64_subs(v2i64_t a, i64 b) { return (v2i64_t){ a.x - b, a.y - b }; }
v2i64_t v2i64_mul(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x * b.x, a.y * b.y }; }
v2i64_t v2i64_muls(v2i64_t a, i64 b) { return (v2i64_t){ a.x * b, a.y * b }; }
v2i64_t v2i64_div(v2i64_t a, v2i64_t b) { return (v2i64_t){ a.x / b.x, a.y / b.y }; }
v2i64_t v2i64_divs(v2i64_t a, i64 b) { return (v2i64_t){ a.x / b, a.y / b }; }
v3i64_t v3i64(i64 x, i64 y, i64 z) { return (v3i64_t){ x, y, z }; }
v3i64_t v3i64_add(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x + b.x, a.y + b.y, a.z + b.z }; }
v3i64_t v3i64_adds(v3i64_t a, i64 b) { return (v3i64_t){ a.x + b, a.y + b, a.z + b }; }
v3i64_t v3i64_sub(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x - b.x, a.y - b.y, a.z - b.z }; }
v3i64_t v3i64_subs(v3i64_t a, i64 b) { return (v3i64_t){ a.x - b, a.y - b, a.z - b }; }
v3i64_t v3i64_mul(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x * b.x, a.y * b.y, a.z * b.z }; }
v3i64_t v3i64_muls(v3i64_t a, i64 b) { return (v3i64_t){ a.x * b, a.y * b, a.z * b }; }
v3i64_t v3i64_div(v3i64_t a, v3i64_t b) { return (v3i64_t){ a.x / b.x, a.y / b.y, a.z / b.z }; }
v3i64_t v3i64_divs(v3i64_t a, i64 b) { return (v3i64_t){ a.x / b, a.y / b, a.z / b }; }
v4i64_t v4i64(i64 x, i64 y, i64 z, i64 w) { return (v4i64_t){ x, y, z, w }; }
v4i64_t v4i64_add(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w }; }
v4i64_t v4i64_adds(v4i64_t a, i64 b) { return (v4i64_t){ a.x + b, a.y + b, a.z + b, a.w + b }; }
v4i64_t v4i64_sub(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w }; }
v4i64_t v4i64_subs(v4i64_t a, i64 b) { return (v4i64_t){ a.x - b, a.y - b, a.z - b, a.w - b }; }
v4i64_t v4i64_mul(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w }; }
v4i64_t v4i64_muls(v4i64_t a, i64 b) { return (v4i64_t){ a.x * b, a.y * b, a.z * b, a.w * b }; }
v4i64_t v4i64_div(v4i64_t a, v4i64_t b) { return (v4i64_t){ a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w }; }
v4i64_t v4i64_divs(v4i64_t a, i64 b) { return (v4i64_t){ a.x / b, a.y / b, a.z / b, a.w / b }; }
r2i64_t r2i64(i64 x0, i64 y0, i64 x1, i64 y1) { return (r2i64_t){ x0, y0, x1, y1 }; }
r2i64_t r2i64_add(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.x1 + b.x1, a.y1 + b.y1 }; }
r2i64_t r2i64_adds(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 + b, a.y0 + b, a.x1 + b, a.y1 + b }; }
r2i64_t r2i64_sub(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.x1 - b.x1, a.y1 - b.y1 }; }
r2i64_t r2i64_subs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 - b, a.y0 - b, a.x1 - b, a.y1 - b }; }
r2i64_t r2i64_mul(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.x1 * b.x1, a.y1 * b.y1 }; }
r2i64_t r2i64_muls(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 * b, a.y0 * b, a.x1 * b, a.y1 * b }; }
r2i64_t r2i64_div(r2i64_t a, r2i64_t b) { return (r2i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.x1 / b.x1, a.y1 / b.y1 }; }
r2i64_t r2i64_divs(r2i64_t a, i64 b) { return (r2i64_t){ a.x0 / b, a.y0 / b, a.x1 / b, a.y1 / b }; }
r3i64_t r3i64(i64 x0, i64 y0, i64 z0, i64 x1, i64 y1, i64 z1) { return (r3i64_t){ x0, y0, z0, x1, y1, z1 }; }
r3i64_t r3i64_add(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 + b.x0, a.y0 + b.y0, a.z0 + b.z0, a.x1 + b.x1, a.y1 + b.y1, a.z1 + b.z1 }; }
r3i64_t r3i64_adds(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 + b, a.y0 + b, a.z0 + b, a.x1 + b, a.y1 + b, a.z1 + b }; }
r3i64_t r3i64_sub(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 - b.x0, a.y0 - b.y0, a.z0 - b.z0, a.x1 - b.x1, a.y1 - b.y1, a.z1 - b.z1 }; }
r3i64_t r3i64_subs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 - b, a.y0 - b, a.z0 - b, a.x1 - b, a.y1 - b, a.z1 - b }; }
r3i64_t r3i64_mul(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 * b.x0, a.y0 * b.y0, a.z0 * b.z0, a.x1 * b.x1, a.y1 * b.y1, a.z1 * b.z1 }; }
r3i64_t r3i64_muls(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 * b, a.y0 * b, a.z0 * b, a.x1 * b, a.y1 * b, a.z1 * b }; }
r3i64_t r3i64_div(r3i64_t a, r3i64_t b) { return (r3i64_t){ a.x0 / b.x0, a.y0 / b.y0, a.z0 / b.z0, a.x1 / b.x1, a.y1 / b.y1, a.z1 / b.z1 }; }
r3i64_t r3i64_divs(r3i64_t a, i64 b) { return (r3i64_t){ a.x0 / b, a.y0 / b, a.z0 / b, a.x1 / b, a.y1 / b, a.z1 / b }; }
r2f32_t r2f32_mindim(v2f32_t pos, v2f32_t size) { return (r2f32_t){ pos, v2f32_add(pos, size) }; }
r2f32_t r2f32_center_halfdim(v2f32_t center, v2f32_t halfdim) { return (r2f32_t){ v2f32_sub(center, halfdim), v2f32_add(center, halfdim) }; }
r3f32_t r3f32_mindim(v3f32_t pos, v3f32_t size) { return (r3f32_t){ pos, v3f32_add(pos, size) }; }
r3f32_t r3f32_center_halfdim(v3f32_t center, v3f32_t halfdim) { return (r3f32_t){ v3f32_sub(center, halfdim), v3f32_add(center, halfdim) }; }
r2f64_t r2f64_mindim(v2f64_t pos, v2f64_t size) { return (r2f64_t){ pos, v2f64_add(pos, size) }; }
r2f64_t r2f64_center_halfdim(v2f64_t center, v2f64_t halfdim) { return (r2f64_t){ v2f64_sub(center, halfdim), v2f64_add(center, halfdim) }; }
r3f64_t r3f64_mindim(v3f64_t pos, v3f64_t size) { return (r3f64_t){ pos, v3f64_add(pos, size) }; }
r3f64_t r3f64_center_halfdim(v3f64_t center, v3f64_t halfdim) { return (r3f64_t){ v3f64_sub(center, halfdim), v3f64_add(center, halfdim) }; }
r2i32_t r2i32_mindim(v2i32_t pos, v2i32_t size) { return (r2i32_t){ pos, v2i32_add(pos, size) }; }
r2i32_t r2i32_center_halfdim(v2i32_t center, v2i32_t halfdim) { return (r2i32_t){ v2i32_sub(center, halfdim), v2i32_add(center, halfdim) }; }
r3i32_t r3i32_mindim(v3i32_t pos, v3i32_t size) { return (r3i32_t){ pos, v3i32_add(pos, size) }; }
r3i32_t r3i32_center_halfdim(v3i32_t center, v3i32_t halfdim) { return (r3i32_t){ v3i32_sub(center, halfdim), v3i32_add(center, halfdim) }; }
r2i64_t r2i64_mindim(v2i64_t pos, v2i64_t size) { return (r2i64_t){ pos, v2i64_add(pos, size) }; }
r2i64_t r2i64_center_halfdim(v2i64_t center, v2i64_t halfdim) { return (r2i64_t){ v2i64_sub(center, halfdim), v2i64_add(center, halfdim) }; }
r3i64_t r3i64_mindim(v3i64_t pos, v3i64_t size) { return (r3i64_t){ pos, v3i64_add(pos, size) }; }
r3i64_t r3i64_center_halfdim(v3i64_t center, v3i64_t halfdim) { return (r3i64_t){ v3i64_sub(center, halfdim), v3i64_add(center, halfdim) }; }
r2f32_t r2f32_cut_left(r2f32_t *r, f32 value) {
f32 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
return (r2f32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
}
r2f32_t r2f32_cut_right(r2f32_t *r, f32 value) {
f32 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
return (r2f32_t){ .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
}
r2f32_t r2f32_cut_top(r2f32_t *r, f32 value) { /* Y is down */
f32 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
return (r2f32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
}
r2f32_t r2f32_cut_bottom(r2f32_t *r, f32 value) { /* Y is down */
f32 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
return (r2f32_t){ .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
}
// get past left
r2f32_t r2f32_getp_left(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
r2f32_t r2f32_getp_right(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
r2f32_t r2f32_getp_bottom(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
r2f32_t r2f32_getp_top(const r2f32_t *rect, f32 value) {
r2f32_t result = r2f32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
r2f32_t r2f32_get_left(const r2f32_t *r, f32 value) {
f32 minx = r->min.x;
r2f32_t result = (r2f32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
r2f32_t r2f32_get_right(const r2f32_t *r, f32 value) {
f32 maxx = r->max.x;
r2f32_t result = (r2f32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
r2f32_t r2f32_get_top(const r2f32_t *r, f32 value) { /* Y is down */
f32 miny = r->min.y;
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
r2f32_t r2f32_get_bottom(const r2f32_t *r, f32 value) { /* Y is down */
f32 maxy = r->max.y;
r2f32_t result = (r2f32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
r2f32_t r2f32_shrink(r2f32_t rect, v2f32_t value) { return (r2f32_t){ v2f32_add(rect.min, value), v2f32_sub(rect.max, value) }; }
v2f32_t r2f32_get_size(r2f32_t r) { return (v2f32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
v2f32_t r2f32_get_mid(r2f32_t r) { return v2f32_add(r.min, v2f32_divs(r2f32_get_size(r), 2)); }
b32 r2f32_contains(r2f32_t rec, v2f32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
r2f64_t r2f64_cut_left(r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
return (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
}
r2f64_t r2f64_cut_right(r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
return (r2f64_t){ .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
}
r2f64_t r2f64_cut_top(r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
return (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
}
r2f64_t r2f64_cut_bottom(r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
return (r2f64_t){ .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
}
// get past left
r2f64_t r2f64_getp_left(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
r2f64_t r2f64_getp_right(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
r2f64_t r2f64_getp_bottom(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
r2f64_t r2f64_getp_top(const r2f64_t *rect, f64 value) {
r2f64_t result = r2f64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
r2f64_t r2f64_get_left(const r2f64_t *r, f64 value) {
f64 minx = r->min.x;
r2f64_t result = (r2f64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
r2f64_t r2f64_get_right(const r2f64_t *r, f64 value) {
f64 maxx = r->max.x;
r2f64_t result = (r2f64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
r2f64_t r2f64_get_top(const r2f64_t *r, f64 value) { /* Y is down */
f64 miny = r->min.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
r2f64_t r2f64_get_bottom(const r2f64_t *r, f64 value) { /* Y is down */
f64 maxy = r->max.y;
r2f64_t result = (r2f64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
r2f64_t r2f64_shrink(r2f64_t rect, v2f64_t value) { return (r2f64_t){ v2f64_add(rect.min, value), v2f64_sub(rect.max, value) }; }
v2f64_t r2f64_get_size(r2f64_t r) { return (v2f64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
v2f64_t r2f64_get_mid(r2f64_t r) { return v2f64_add(r.min, v2f64_divs(r2f64_get_size(r), 2)); }
b32 r2f64_contains(r2f64_t rec, v2f64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
r2i32_t r2i32_cut_left(r2i32_t *r, i32 value) {
i32 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
return (r2i32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
}
r2i32_t r2i32_cut_right(r2i32_t *r, i32 value) {
i32 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
return (r2i32_t){ .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
}
r2i32_t r2i32_cut_top(r2i32_t *r, i32 value) { /* Y is down */
i32 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
return (r2i32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
}
r2i32_t r2i32_cut_bottom(r2i32_t *r, i32 value) { /* Y is down */
i32 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
return (r2i32_t){ .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
}
// get past left
r2i32_t r2i32_getp_left(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
r2i32_t r2i32_getp_right(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
r2i32_t r2i32_getp_bottom(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
r2i32_t r2i32_getp_top(const r2i32_t *rect, i32 value) {
r2i32_t result = r2i32(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
r2i32_t r2i32_get_left(const r2i32_t *r, i32 value) {
i32 minx = r->min.x;
r2i32_t result = (r2i32_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
r2i32_t r2i32_get_right(const r2i32_t *r, i32 value) {
i32 maxx = r->max.x;
r2i32_t result = (r2i32_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
r2i32_t r2i32_get_top(const r2i32_t *r, i32 value) { /* Y is down */
i32 miny = r->min.y;
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
r2i32_t r2i32_get_bottom(const r2i32_t *r, i32 value) { /* Y is down */
i32 maxy = r->max.y;
r2i32_t result = (r2i32_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
r2i32_t r2i32_shrink(r2i32_t rect, v2i32_t value) { return (r2i32_t){ v2i32_add(rect.min, value), v2i32_sub(rect.max, value) }; }
v2i32_t r2i32_get_size(r2i32_t r) { return (v2i32_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
v2i32_t r2i32_get_mid(r2i32_t r) { return v2i32_add(r.min, v2i32_divs(r2i32_get_size(r), 2)); }
b32 r2i32_contains(r2i32_t rec, v2i32_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
r2i64_t r2i64_cut_left(r2i64_t *r, i64 value) {
i64 minx = r->min.x;
r->min.x = MIN(r->min.x + value, r->max.x);
return (r2i64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = r->min.x, .y =r->max.y} };
}
r2i64_t r2i64_cut_right(r2i64_t *r, i64 value) {
i64 maxx = r->max.x;
r->max.x = MAX(r->min.x, r->max.x - value);
return (r2i64_t){ .min = {.x = r->max.x, .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
}
r2i64_t r2i64_cut_top(r2i64_t *r, i64 value) { /* Y is down */
i64 miny = r->min.y;
r->min.y = MIN(r->max.y, r->min.y + value);
return (r2i64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = r->min.y} };
}
r2i64_t r2i64_cut_bottom(r2i64_t *r, i64 value) { /* Y is down */
i64 maxy = r->max.y;
r->max.y = MAX(r->min.y, r->max.y - value);
return (r2i64_t){ .min = {.x = r->min.x, .y = r->max.y}, .max = {.x = r->max.x, .y = maxy} };
}
// get past left
r2i64_t r2i64_getp_left(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x - value, rect->min.y, rect->min.x, rect->max.y);
return result;
}
r2i64_t r2i64_getp_right(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->max.x, rect->min.y, rect->max.x + value, rect->max.y);
return result;
}
r2i64_t r2i64_getp_bottom(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x, rect->max.y, rect->max.x, rect->max.y + value);
return result;
}
r2i64_t r2i64_getp_top(const r2i64_t *rect, i64 value) {
r2i64_t result = r2i64(rect->min.x, rect->min.y - value, rect->max.x, rect->min.y);
return result;
}
r2i64_t r2i64_get_left(const r2i64_t *r, i64 value) {
i64 minx = r->min.x;
r2i64_t result = (r2i64_t){ .min = {.x = minx, .y = r->min.y}, .max = {.x = MIN(r->min.x + value, r->max.x), .y =r->max.y} };
return result;
}
r2i64_t r2i64_get_right(const r2i64_t *r, i64 value) {
i64 maxx = r->max.x;
r2i64_t result = (r2i64_t){ .min = {.x = MAX(r->min.x, r->max.x - value), .y = r->min.y}, .max = {.x = maxx, .y = r->max.y} };
return result;
}
r2i64_t r2i64_get_top(const r2i64_t *r, i64 value) { /* Y is down */
i64 miny = r->min.y;
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = miny}, .max = {.x = r->max.x, .y = MIN(r->max.y, r->min.y + value)} };
return result;
}
r2i64_t r2i64_get_bottom(const r2i64_t *r, i64 value) { /* Y is down */
i64 maxy = r->max.y;
r2i64_t result = (r2i64_t){ .min = {.x = r->min.x, .y = MAX(r->min.y, r->max.y - value)}, .max = {.x = r->max.x, .y = maxy} };
return result;
}
r2i64_t r2i64_shrink(r2i64_t rect, v2i64_t value) { return (r2i64_t){ v2i64_add(rect.min, value), v2i64_sub(rect.max, value) }; }
v2i64_t r2i64_get_size(r2i64_t r) { return (v2i64_t){r.max.x - r.min.x, r.max.y - r.min.y}; }
v2i64_t r2i64_get_mid(r2i64_t r) { return v2i64_add(r.min, v2i64_divs(r2i64_get_size(r), 2)); }
b32 r2i64_contains(r2i64_t rec, v2i64_t point) { return (point.x >= rec.min.x) && (point.x < rec.max.x) && (point.y >= rec.min.y) && (point.y < rec.max.y); }
v2f64_t v2f32_to_v2f64(v2f32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
v3f64_t v3f32_to_v3f64(v3f32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
v4f64_t v4f32_to_v4f64(v4f32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
r2f64_t r2f32_to_r2f64(r2f32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
r3f64_t r3f32_to_r3f64(r3f32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
v2i32_t v2f32_to_v2i32(v2f32_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
v3i32_t v3f32_to_v3i32(v3f32_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
v4i32_t v4f32_to_v4i32(v4f32_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
r2i32_t r2f32_to_r2i32(r2f32_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
r3i32_t r3f32_to_r3i32(r3f32_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
v2i64_t v2f32_to_v2i64(v2f32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
v3i64_t v3f32_to_v3i64(v3f32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
v4i64_t v4f32_to_v4i64(v4f32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
r2i64_t r2f32_to_r2i64(r2f32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
r3i64_t r3f32_to_r3i64(r3f32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
v2f32_t v2f64_to_v2f32(v2f64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
v3f32_t v3f64_to_v3f32(v3f64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
v4f32_t v4f64_to_v4f32(v4f64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
r2f32_t r2f64_to_r2f32(r2f64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
r3f32_t r3f64_to_r3f32(r3f64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
v2i32_t v2f64_to_v2i32(v2f64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
v3i32_t v3f64_to_v3i32(v3f64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
v4i32_t v4f64_to_v4i32(v4f64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
r2i32_t r2f64_to_r2i32(r2f64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
r3i32_t r3f64_to_r3i32(r3f64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }
v2i64_t v2f64_to_v2i64(v2f64_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
v3i64_t v3f64_to_v3i64(v3f64_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
v4i64_t v4f64_to_v4i64(v4f64_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
r2i64_t r2f64_to_r2i64(r2f64_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
r3i64_t r3f64_to_r3i64(r3f64_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
v2f32_t v2i32_to_v2f32(v2i32_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
v3f32_t v3i32_to_v3f32(v3i32_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
v4f32_t v4i32_to_v4f32(v4i32_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
r2f32_t r2i32_to_r2f32(r2i32_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
r3f32_t r3i32_to_r3f32(r3i32_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
v2f64_t v2i32_to_v2f64(v2i32_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
v3f64_t v3i32_to_v3f64(v3i32_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
v4f64_t v4i32_to_v4f64(v4i32_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
r2f64_t r2i32_to_r2f64(r2i32_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
r3f64_t r3i32_to_r3f64(r3i32_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
v2i64_t v2i32_to_v2i64(v2i32_t v) { return (v2i64_t){ (i64)v.x, (i64)v.y }; }
v3i64_t v3i32_to_v3i64(v3i32_t v) { return (v3i64_t){ (i64)v.x, (i64)v.y, (i64)v.z }; }
v4i64_t v4i32_to_v4i64(v4i32_t v) { return (v4i64_t){ (i64)v.x, (i64)v.y, (i64)v.z, (i64)v.w }; }
r2i64_t r2i32_to_r2i64(r2i32_t v) { return (r2i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.x1, (i64)v.y1 }; }
r3i64_t r3i32_to_r3i64(r3i32_t v) { return (r3i64_t){ (i64)v.x0, (i64)v.y0, (i64)v.z0, (i64)v.x1, (i64)v.y1, (i64)v.z1 }; }
v2f32_t v2i64_to_v2f32(v2i64_t v) { return (v2f32_t){ (f32)v.x, (f32)v.y }; }
v3f32_t v3i64_to_v3f32(v3i64_t v) { return (v3f32_t){ (f32)v.x, (f32)v.y, (f32)v.z }; }
v4f32_t v4i64_to_v4f32(v4i64_t v) { return (v4f32_t){ (f32)v.x, (f32)v.y, (f32)v.z, (f32)v.w }; }
r2f32_t r2i64_to_r2f32(r2i64_t v) { return (r2f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.x1, (f32)v.y1 }; }
r3f32_t r3i64_to_r3f32(r3i64_t v) { return (r3f32_t){ (f32)v.x0, (f32)v.y0, (f32)v.z0, (f32)v.x1, (f32)v.y1, (f32)v.z1 }; }
v2f64_t v2i64_to_v2f64(v2i64_t v) { return (v2f64_t){ (f64)v.x, (f64)v.y }; }
v3f64_t v3i64_to_v3f64(v3i64_t v) { return (v3f64_t){ (f64)v.x, (f64)v.y, (f64)v.z }; }
v4f64_t v4i64_to_v4f64(v4i64_t v) { return (v4f64_t){ (f64)v.x, (f64)v.y, (f64)v.z, (f64)v.w }; }
r2f64_t r2i64_to_r2f64(r2i64_t v) { return (r2f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.x1, (f64)v.y1 }; }
r3f64_t r3i64_to_r3f64(r3i64_t v) { return (r3f64_t){ (f64)v.x0, (f64)v.y0, (f64)v.z0, (f64)v.x1, (f64)v.y1, (f64)v.z1 }; }
v2i32_t v2i64_to_v2i32(v2i64_t v) { return (v2i32_t){ (i32)v.x, (i32)v.y }; }
v3i32_t v3i64_to_v3i32(v3i64_t v) { return (v3i32_t){ (i32)v.x, (i32)v.y, (i32)v.z }; }
v4i32_t v4i64_to_v4i32(v4i64_t v) { return (v4i32_t){ (i32)v.x, (i32)v.y, (i32)v.z, (i32)v.w }; }
r2i32_t r2i64_to_r2i32(r2i64_t v) { return (r2i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.x1, (i32)v.y1 }; }
r3i32_t r3i64_to_r3i32(r3i64_t v) { return (r3i32_t){ (i32)v.x0, (i32)v.y0, (i32)v.z0, (i32)v.x1, (i32)v.y1, (i32)v.z1 }; }

View File

@@ -0,0 +1,69 @@
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(__APPLE__) && defined(__MACH__)
#define PLATFORM_MAC_OS 1
#define PLATFORM_POSIX 1
#elif defined(_WIN32)
#define PLATFORM_WINDOWS 1
#elif defined(__linux__)
#define PLATFORM_POSIX 1
#define PLATFORM_LINUX 1
#elif defined(__wasm)
#define PLATFORM_WASM 1
#endif
#if defined(__clang__)
#define PLATFORM_CLANG 1
#elif defined(__GNUC__) || defined(__GNUG__)
#define PLATFORM_GCC 1
#elif defined(_MSC_VER)
#define PLATFORM_CL 1
#elif defined(__TINYC__)
#define PLATFORM_TCC 1
#endif
#ifndef PLATFORM_WASM
#define PLATFORM_WASM 0
#endif
#ifndef PLATFORM_WINDOWS
#define PLATFORM_WINDOWS 0
#endif
#ifndef PLATFORM_LINUX
#define PLATFORM_LINUX 0
#endif
#ifndef PLATFORM_POSIX
#define PLATFORM_POSIX 0
#endif
#ifndef PLATFORM_MAC_OS
#define PLATFORM_MAC_OS 0
#endif
#ifndef PLATFORM_CLANG
#define PLATFORM_CLANG 0
#endif
#ifndef PLATFORM_GCC
#define PLATFORM_GCC 0
#endif
#ifndef PLATFORM_CL
#define PLATFORM_CL 0
#endif
#ifndef PLATFORM_TCC
#define PLATFORM_TCC 0
#endif
#ifndef PLATFORM_ASSERT
#define PLATFORM_ASSERT 1
#endif
#ifndef PLATFORM_ADDRESS_SANITIZER
#define PLATFORM_ADDRESS_SANITIZER 0
#endif

36
src/core/scratch.c Normal file
View File

@@ -0,0 +1,36 @@
ma_temp_t ma_begin_scratch_ex(ma_arena_t **conflicts, int conflict_count) {
ma_arena_t *unoccupied = 0;
for (int i = 0; i < lengthof(core_desc.scratch); i += 1) {
ma_arena_t *from_pool = core_desc.scratch + i;
unoccupied = from_pool;
for (int conflict_i = 0; conflict_i < conflict_count; conflict_i += 1) {
ma_arena_t *from_conflict = conflicts[conflict_i];
if (from_pool == from_conflict) {
unoccupied = 0;
break;
}
}
if (unoccupied) {
break;
}
}
assertf(unoccupied, "Failed to get free scratch memory, this is a fatal error, this shouldnt happen");
ma_temp_t result = ma_begin_temp(unoccupied);
return result;
}
ma_temp_t ma_begin_scratch(void) {
ma_temp_t result = ma_begin_temp(core_desc.scratch + 0);
return result;
}
ma_temp_t ma_begin_scratch1(ma_arena_t *conflict) {
ma_arena_t *conflicts[] = {conflict};
return ma_begin_scratch_ex(conflicts, 1);
}
#define ma_end_scratch(x) ma_end_temp(x)
#define ma_temp_scope(name, InArena) for (ma_temp_t name = ma_begin_temp(InArena); name.arena; (ma_end_temp(name), name.arena = 0))
#define ma_scratch_scope(x) for (ma_temp_t x = ma_begin_scratch(); x.arena; (ma_end_temp(x), x.arena = 0))

1961
src/core/stb_sprintf.h Normal file

File diff suppressed because it is too large Load Diff

59
src/core/string.c Normal file
View File

@@ -0,0 +1,59 @@
#define STR_FMT(buff, str) \
va_list args1; \
va_start(args1, str); \
int len = stbsp_vsnprintf(buff, sizeof(buff), str, args1); \
va_end(args1)
int str_len(char *str) {
int i = 0;
while (str[i]) i += 1;
return i;
}
b32 s8_equal(s8_t a, s8_t b);
s8_t s8_from_char(char *string);
b32 str_eq(char *a, char *b) {
return s8_equal(s8_from_char(a), s8_from_char(b));
}
char char_to_lower_case(char a) {
if (a >= 'A' && a <= 'Z') a += 32;
return a;
}
char char_to_upper_case(char a) {
if (a >= 'a' && a <= 'z') a -= 32;
return a;
}
b32 char_is_whitespace(char w) {
b32 result = w == '\n' || w == ' ' || w == '\t' || w == '\v' || w == '\r';
return result;
}
b32 char_is_alphabetic(char a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z');
return result;
}
b32 char_is_ident(char a) {
b32 result = (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z') || a == '_';
return result;
}
b32 char_is_digit(char a) {
b32 result = a >= '0' && a <= '9';
return result;
}
b32 char_is_alphanumeric(char a) {
b32 result = char_is_digit(a) || char_is_alphabetic(a);
return result;
}
i64 wstr_len(wchar_t *string) {
i64 len = 0;
while (*string++ != 0)
len++;
return len;
}

454
src/core/string8.c Normal file
View File

@@ -0,0 +1,454 @@
#define s8_vsnprintf stbsp_vsnprintf
#define S8_FMT(ma, str, result) \
va_list args1; \
va_start(args1, str); \
s8_t result = s8_vfmt(ma, str, args1); \
va_end(args1)
s8_t s8_range(char *begin, char *end) {
assert(end >= begin);
intptr_t size = (intptr_t)end - (intptr_t)begin;
s8_t result = {begin, size};
return result;
}
b32 s8_equal_ex(s8_t a, s8_t b, b32 ignore_case) {
if (a.len != b.len) return false;
for (int64_t i = 0; i < a.len; i++) {
char A = a.str[i];
char B = b.str[i];
if (ignore_case) {
A = char_to_lower_case(A);
B = char_to_lower_case(B);
}
if (A != B)
return false;
}
return true;
}
b32 s8_equal(s8_t a, s8_t b) {return s8_equal_ex(a, b, false);}
s8_t s8_get_postfix(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
int64_t remain_len = string.len - len;
s8_t result = s8(string.str + remain_len, len);
return result;
}
s8_t s8_get_prefix(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
s8_t result = s8(string.str, len);
return result;
}
s8_t s8_chop(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
s8_t result = s8(string.str, string.len - len);
return result;
}
s8_t s8_skip(s8_t string, int64_t len) {
len = CLAMP_TOP(len, string.len);
int64_t remain = string.len - len;
s8_t result = s8(string.str + len, remain);
return result;
}
b32 s8_ends_with(s8_t a, s8_t end, b32 ignore_case) {
s8_t a_end = s8_get_postfix(a, end.len);
b32 result = s8_equal_ex(end, a_end, ignore_case);
return result;
}
b32 s8_starts_with(s8_t a, s8_t start, b32 ignore_case) {
s8_t a_start = s8_get_prefix(a, start.len);
b32 result = s8_equal_ex(start, a_start, ignore_case);
return result;
}
void s8_normalize_path_unsafe(s8_t s) {
for (int64_t i = 0; i < s.len; i++) {
if (s.str[i] == '\\')
s.str[i] = '/';
}
}
b32 s8_is_pointer_inside(s8_t string, char *p) {
uintptr_t pointer = (uintptr_t)p;
uintptr_t start = (uintptr_t)string.str;
uintptr_t stop = start + (uintptr_t)string.len;
b32 result = pointer >= start && pointer < stop;
return result;
}
s8_t s8_skip_to_p(s8_t string, char *p) {
if (s8_is_pointer_inside(string, p)) {
s8_t result = s8(p, p - string.str);
return result;
}
return string;
}
s8_t s8_skip_past(s8_t string, s8_t a) {
if (s8_is_pointer_inside(string, a.str)) {
s8_t on_p = s8(a.str, a.str - string.str);
s8_t result = s8_skip(on_p, a.len);
return result;
}
return string;
}
s8_t s8_slice(s8_t string, int64_t first_index, int64_t one_past_last_index) {
if (one_past_last_index < 0) one_past_last_index = string.len + one_past_last_index + 1;
if (first_index < 0) first_index = string.len + first_index;
assert(first_index < one_past_last_index && "s8_slice, first_index is bigger then one_past_last_index");
assert(string.len > 0 && "Slicing string of length 0! Might be an error!");
s8_t result = string;
if (string.len > 0) {
if (one_past_last_index > first_index) {
first_index = CLAMP_TOP(first_index, string.len - 1);
one_past_last_index = CLAMP_TOP(one_past_last_index, string.len);
result.str += first_index;
result.len = one_past_last_index - first_index;
}
else {
result.len = 0;
}
}
return result;
}
s8_t s8_trim(s8_t string) {
if (string.len == 0)
return string;
int64_t whitespace_begin = 0;
for (; whitespace_begin < string.len; whitespace_begin++) {
if (!char_is_whitespace(string.str[whitespace_begin])) {
break;
}
}
int64_t whitespace_end = string.len;
for (; whitespace_end != whitespace_begin; whitespace_end--) {
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
if (whitespace_begin == whitespace_end) {
string.len = 0;
}
else {
string = s8_slice(string, whitespace_begin, whitespace_end);
}
return string;
}
s8_t s8_trim_end(s8_t string) {
int64_t whitespace_end = string.len;
for (; whitespace_end != 0; whitespace_end--) {
if (!char_is_whitespace(string.str[whitespace_end - 1])) {
break;
}
}
s8_t result = s8_get_prefix(string, whitespace_end);
return result;
}
typedef int s8_seek_t;
enum {
s8_seek_none = 0,
s8_seek_ignore_case = 1,
s8_seek_match_find_last = 2,
};
b32 s8_seek(s8_t string, s8_t find, s8_seek_t flags, int64_t *index_out) {
b32 ignore_case = flags & s8_seek_ignore_case ? true : false;
b32 result = false;
if (flags & s8_seek_match_find_last) {
for (int64_t i = string.len; i != 0; i--) {
int64_t index = i - 1;
s8_t substring = s8_slice(string, index, index + find.len);
if (s8_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = index;
result = true;
break;
}
}
}
else {
for (int64_t i = 0; i < string.len; i++) {
s8_t substring = s8_slice(string, i, i + find.len);
if (s8_equal_ex(substring, find, ignore_case)) {
if (index_out)
*index_out = i;
result = true;
break;
}
}
}
return result;
}
int64_t s8_find(s8_t string, s8_t find, s8_seek_t flag) {
int64_t result = -1;
s8_seek(string, find, flag, &result);
return result;
}
s8_t s8_chop_last_slash(s8_t s) {
s8_t result = s;
s8_seek(s, s8_lit("/"), s8_seek_match_find_last, &result.len);
return result;
}
s8_t s8_chop_last_period(s8_t s) {
s8_t result = s;
s8_seek(s, s8_lit("."), s8_seek_match_find_last, &result.len);
return result;
}
s8_t s8_skip_to_last_slash(s8_t s) {
int64_t pos;
s8_t result = s;
if (s8_seek(s, s8_lit("/"), s8_seek_match_find_last, &pos)) {
result = s8_skip(result, pos + 1);
}
return result;
}
s8_t s8_skip_to_last_period(s8_t s) {
int64_t pos;
s8_t result = s;
if (s8_seek(s, s8_lit("."), s8_seek_match_find_last, &pos)) {
result = s8_skip(result, pos + 1);
}
return result;
}
s8_t s8_from_char(char *string) {
s8_t result;
result.str = (char *)string;
result.len = str_len(string);
return result;
}
s8_t s8_get_name_no_ext(s8_t s) {
return s8_skip_to_last_slash(s8_chop_last_period(s));
}
s8_t s8_copy(ma_arena_t *ma, s8_t string) {
char *copy = (char *)ma_push_size(ma, sizeof(char) * (string.len + 1));
if (copy) {
memory_copy(copy, string.str, string.len);
copy[string.len] = 0;
s8_t result = s8(copy, string.len);
return result;
}
return (s8_t){0};
}
s8_t s8_copy_char(ma_arena_t *ma, char *s) {
int64_t len = str_len(s);
char *copy = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
memory_copy(copy, s, len);
copy[len] = 0;
s8_t result = s8(copy, len);
return result;
}
s8_t s8_normalize_path(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
if (copy.str[i] == '\\')
copy.str[i] = '/';
}
return copy;
}
s8_t s8_to_lower_case(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char_to_lower_case(copy.str[i]);
}
return copy;
}
s8_t s8_to_upper_case(ma_arena_t *ma, s8_t s) {
s8_t copy = s8_copy(ma, s);
for (int64_t i = 0; i < copy.len; i++) {
copy.str[i] = char_to_upper_case(copy.str[i]);
}
return copy;
}
s8_t s8_vfmt(ma_arena_t *ma, const char *str, va_list args1) {
va_list args2;
va_copy(args2, args1);
int64_t len = s8_vsnprintf(0, 0, str, args2);
va_end(args2);
char *result = (char *)ma_push_size(ma, sizeof(char) * (len + 1));
s8_vsnprintf(result, (int)(len + 1), str, args1);
s8_t res = s8(result, len);
return res;
}
s8_t s8_fmt(ma_arena_t *ma, const char *str, ...) {
S8_FMT(ma, str, result);
return result;
}
//
// sb8_t
//
sb8_node_t *sb8_node(ma_arena_t *ma, s8_t str) {
sb8_node_t *node = ma_push_type(ma, sb8_node_t);
node->s = str;
return node;
}
sb8_node_t *sb8_append(sb8_t *list, s8_t string) {
sb8_node_t *node = sb8_node(list->arena, string);
SLLQ_APPEND(list->first, list->last, node);
return node;
}
s8_t sb8_printf(sb8_t *sb, const char *str, ...) {
S8_FMT(sb->arena, str, result);
sb8_append(sb, result);
return result;
}
void sb8_indent(sb8_t *sb) {
sb8_printf(sb, "\n%.*s", sb->indent*4, " ");
}
s8_t sb8_stmtf(sb8_t *sb, const char *str, ...) {
S8_FMT(sb->arena, str, result);
sb8_indent(sb);
sb8_append(sb, result);
return result;
}
int64_t sb8_char_size(sb8_t *sb) {
int64_t result = 0;
for (sb8_node_t *it = sb->first; it; it = it->next) {
result += it->len;
}
return result;
}
s8_t sb8_merge(sb8_t *sb) {
int64_t size = sb8_char_size(sb) + 1;
char *str = ma_push_size(sb->arena, size);
s8_t result = {str, 0};
for (sb8_node_t *it = sb->first; it; it = it->next) {
memory_copy(result.str + result.len, it->str, it->len);
result.len += it->len;
}
result.str[result.len] = 0;
return result;
}
typedef int s8_split_t;
enum {
s8_split_none = 0,
s8_split_ignore_case = 1,
s8_split_inclusive = 2,
};
sb8_t s8_split(ma_arena_t *ma, s8_t string, s8_t find, s8_split_t flags) {
sb8_t result = (sb8_t){ma};
int64_t index = 0;
s8_seek_t find_flag = flags & s8_split_ignore_case ? s8_seek_ignore_case : s8_seek_none;
while (s8_seek(string, find, find_flag, &index)) {
s8_t before_match = s8(string.str, index);
sb8_append(&result, before_match);
if (flags & s8_split_inclusive) {
s8_t match = s8(string.str + index, find.len);
sb8_append(&result, match);
}
string = s8_skip(string, index + find.len);
}
if (string.len) sb8_append(&result, string);
return result;
}
s16_t s16_from_s8(ma_arena_t *ma, s8_t string) {
u16 *buffer = ma_push_array(ma, u16, string.len + 1);
i64 len = wstr_from_str(buffer, string.len + 1, string.str, string.len);
assert(len < string.len);
return (s16_t){buffer,len};
}
s8_t s8_from_s16(ma_arena_t *ma, s16_t string) {
i64 buffer_size = (string.len + 1) * 2;
char *buffer = ma_push_array(ma, char, buffer_size);
i64 len = str_from_wstr(buffer, buffer_size, string.str, string.len);
assert(len < buffer_size);
return (s8_t){buffer,len};
}
#if 0
s8_t S8_MergeWithSeparator(ma_arena_t *ma, S8_List list, s8_t separator) {
if (list.node_count == 0) return s8_makeEmpty();
if (list.char_count == 0) return s8_makeEmpty();
int64_t base_size = (list.char_count + 1);
int64_t sep_size = (list.node_count - 1) * separator.len;
int64_t size = base_size + sep_size;
char *buff = (char *)ma_push_size(ma, sizeof(char) * (size + 1));
s8_t string = s8(buff, 0);
for (S8_Node *it = list.first; it; it = it->next) {
assert(string.len + it->string.len <= size);
memory_copy(string.str + string.len, it->string.str, it->string.len);
string.len += it->string.len;
if (it != list.last) {
memory_copy(string.str + string.len, separator.str, separator.len);
string.len += separator.len;
}
}
assert(string.len == size - 1);
string.str[size] = 0;
return string;
}
s8_t S8_Merge(ma_arena_t *ma, S8_List list) {
return S8_MergeWithSeparator(ma, list, s8_lit(""));
}
s8_t S8_ReplaceAll(ma_arena_t *ma, s8_t string, s8_t replace, s8_t with, b32 ignore_case) {
s8_split_flag split_flag = ignore_case ? S8_SplitFlag_IgnoreCase : S8_SplitFlag_None;
S8_List list = S8_Split(ma, string, replace, split_flag | S8_SplitFlag_SplitInclusive);
for (S8_Node *it = list.first; it; it = it->next) {
if (s8_equal_ex(it->string, replace, ignore_case)) {
S8_ReplaceNodeString(&list, it, with);
}
}
s8_t result = S8_Merge(ma, list);
return result;
}
S8_List S8_FindAll(ma_arena_t *ma, s8_t string, s8_t find, b32 ignore_case) { // @untested
S8_List result = s8_makeEmptyList();
int64_t index = 0;
s8_seek find_flag = ignore_case ? s8_seek_ignore_case : 0;
while (s8_seek(string, find, find_flag, &index)) {
s8_t match = s8(string.str + index, find.len);
S8_AddNode(ma, &result, match);
string = s8_skip(string, index + find.len);
}
return result;
}
#endif

403
src/core/type_info.c Normal file
View File

@@ -0,0 +1,403 @@
s8_t ti_enum_value_to_name(type_t *type, i64 value) {
assert(type->kind == type_kind_enum);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (value == it->value) {
return it->name;
}
}
return s8_lit("invalid");
}
i64 ti_enum_name_to_value(type_t *type, s8_t name) {
assert(type->kind == type_kind_enum);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (s8_equal(it->name, name)) {
return it->value;
}
}
return -1;
}
type_member_t *ti_get_member(type_t *type, s8_t name) {
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *it = type->members + i;
if (s8_equal(it->name, name)) {
return it;
}
}
return NULL;
}
void sb8_serial_data(sb8_t *sb, void *p, type_t *type) {
assert(type->kind != type_kind_invalid);
switch(type->kind) {
case type_kind_i8: {
i8 n = *(i8 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i16: {
i16 n = *(i16 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i32: {
i32 n = *(i32 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_i64: {
i64 n = *(i64 *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_u8: {
u8 n = *(u8 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u16: {
u16 n = *(u16 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u32: {
u32 n = *(u32 *)p;
sb8_printf(sb, "%u", n);
return;
} break;
case type_kind_u64: {
u64 n = *(u64 *)p;
sb8_printf(sb, "%llu", (unsigned long long)n);
return;
} break;
case type_kind_b8: {
b8 n = *(b8 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b16: {
b16 n = *(b16 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b32: {
b32 n = *(b32 *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_b64: {
b64 n = *(b64 *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_f32: {
f32 n = *(f32 *)p;
sb8_printf(sb, "%f", n);
return;
} break;
case type_kind_f64: {
f64 n = *(f64 *)p;
sb8_printf(sb, "%f", n);
return;
} break;
case type_kind_isize: {
isize n = *(isize *)p;
sb8_printf(sb, "%lld", (long long)n);
return;
} break;
case type_kind_usize: {
usize n = *(usize *)p;
sb8_printf(sb, "%llu", (unsigned long long)n);
return;
} break;
case type_kind_int: {
int n = *(int *)p;
sb8_printf(sb, "%d", n);
return;
} break;
case type_kind_char: {
char n = *(char *)p;
sb8_printf(sb, "%c", n);
return;
} break;
}
if (type == &type__s8_t) {
s8_t n = *(s8_t *)p;
sb8_printf(sb, "\"%S\"", n);
return;
}
if (type->kind == type_kind_pointer) {
sb8_printf(sb, "0x%x", p);
return;
}
if (type->kind == type_kind_enum) {
i64 value = 0;
if (type->size == 1) {
value = *(i8 *)p;
} else if (type->size == 2) {
value = *(i16 *)p;
} else if (type->size == 4) {
value = *(i32 *)p;
} else if (type->size == 8) {
value = *(i64 *)p;
} else {
panicf("invalid size of enum: %d", type->size);
}
s8_t s = ti_enum_value_to_name(type, value);
sb8_append(sb, s);
return;
}
if (type->kind == type_kind_array) {
u8 *p8 = (u8 *)p;
sb8_printf(sb, "{");
sb->indent += 1;
for (i32 i = 0; i < type->count; i += 1) {
type_t *base = type->base;
u8 *mem_p = p8 + base->size * i;
sb8_indent(sb);
sb8_serial_data(sb, mem_p, base);
sb8_printf(sb, ",");
}
sb->indent -= 1;
sb8_stmtf(sb, "}");
return;
}
if (type->kind == type_kind_struct) {
u8 *p8 = (u8 *)p;
sb8_printf(sb, "{");
sb->indent += 1;
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *mem = type->members + i;
u8 *mem_p = p8 + mem->offset;
sb8_indent(sb);
sb8_printf(sb, "%S: ", mem->name);
sb8_serial_data(sb, mem_p, mem->type);
sb8_printf(sb, ",");
}
sb->indent -= 1;
sb8_stmtf(sb, "}");
return;
}
panicf("can't serialize: unhandled type");
}
s8_t s8_serial_data(ma_arena_t *arena, void *p, type_t *type) {
sb8_t *sb = sb8_serial_begin(arena);
sb8_serial_data(sb, p, type);
s8_t string = sb8_serial_end(sb);
return string;
}
i64 parser__match_i64(parser_t *par) {
i64 minus = 1;
if (parser_match(par, lex_kind_minus)) {
minus = -1;
}
lex_t *token = parser_expect(par, lex_kind_int);
i64 result = (i64)token->integer * minus;
return result;
}
void s8_deserial_data_ex(ma_arena_t *arena, parser_t *par, void *p, type_t *type) {
switch(type->kind) {
case type_kind_i8: {
i8 *n = (i8 *)p;
n[0] = (i8)parser__match_i64(par);
return;
} break;
case type_kind_i16: {
i16 *n = (i16 *)p;
n[0] = (i16)parser__match_i64(par);
return;
} break;
case type_kind_i32: {
i32 *n = (i32 *)p;
n[0] = (i32)parser__match_i64(par);
return;
} break;
case type_kind_i64: {
i64 *n = (i64 *)p;
n[0] = (i64)parser__match_i64(par);
return;
} break;
case type_kind_b8: {
b8 *n = (b8 *)p;
n[0] = (b8)parser__match_i64(par);
return;
} break;
case type_kind_b16: {
b16 *n = (b16 *)p;
n[0] = (b16)parser__match_i64(par);
return;
} break;
case type_kind_b32: {
b32 *n = (b32 *)p;
n[0] = (b32)parser__match_i64(par);
return;
} break;
case type_kind_b64: {
b64 *n = (b64 *)p;
n[0] = (b64)parser__match_i64(par);
return;
} break;
case type_kind_u8: {
lex_t *token = parser_expect(par, lex_kind_int);
u8 *n = (u8 *)p;
n[0] = (u8)token->integer;
return;
} break;
case type_kind_u16: {
lex_t *token = parser_expect(par, lex_kind_int);
u16 *n = (u16 *)p;
n[0] = (u16)token->integer;
return;
} break;
case type_kind_u32: {
lex_t *token = parser_expect(par, lex_kind_int);
u32 *n = (u32 *)p;
n[0] = (u32)token->integer;
return;
} break;
case type_kind_u64: {
lex_t *token = parser_expect(par, lex_kind_int);
u64 *n = (u64 *)p;
n[0] = (u64)token->integer;
return;
} break;
case type_kind_f32: {
lex_t *token = parser_expect(par, lex_kind_real);
f32 *n = (f32 *)p;
n[0] = (f32)token->real;
return;
} break;
case type_kind_f64: {
lex_t *token = parser_expect(par, lex_kind_real);
f64 *n = (f64 *)p;
n[0] = token->real;
return;
} break;
case type_kind_isize: {
isize *n = (isize *)p;
n[0] = (isize)parser__match_i64(par);
return;
} break;
case type_kind_usize: {
lex_t *token = parser_expect(par, lex_kind_int);
usize *n = (usize *)p;
n[0] = (usize)token->integer;
return;
} break;
case type_kind_int: {
int *n = (int *)p;
n[0] = (int)parser__match_i64(par);
return;
} break;
case type_kind_char: {
char *n = (char *)p;
n[0] = (char)parser__match_i64(par);
return;
} break;
}
if (type == &type__s8_t) {
lex_t *token = parser_expect(par, lex_kind_string);
s8_t *n = (s8_t *)p;
n[0] = s8_copy(arena, token->s8);
return;
}
if (type->kind == type_kind_enum) {
lex_t *token = parser_expect(par, lex_kind_ident);
i64 value = ti_enum_name_to_value(type, token->s8);
if (value == -1) {
panicf("invalid enum value: %S", token->s8);
}
if (type->size == 1) {
*(i8 *)p = (i8)value;
} else if (type->size == 2) {
*(i16 *)p = (i16)value;
} else if (type->size == 4) {
*(i32 *)p = (i32)value;
} else if (type->size == 8) {
*(i64 *)p = (i64)value;
} else {
panicf("invalid size of enum: %d", type->size);
}
return;
}
if (type->kind == type_kind_struct) {
u8 *p8 = (u8 *)p;
#if 0
parser_expect(par, lex_kind_open_brace);
while (!parser_match(par, lex_kind_close_brace)) {
lex_t *ident = parser_expect(par, lex_kind_ident);
parser_expect(par, lex_kind_colon);
type_member_t *mem = ti_get_member(type, ident->s8);
if (mem) {
u8 *mem_p = p8 + mem->offset;
s8_deserial_data_ex(arena, par, mem_p, mem->type);
} else {
debugf("deserial - skipping field: %S", ident->s8);
parser_eat_until(par, lex_kind_comma);
}
parser_expect(par, lex_kind_comma);
}
#else // strict
parser_expect(par, lex_kind_open_brace);
for (i32 i = 0; i < type->count; i += 1) {
type_member_t *mem = type->members + i;
u8 *mem_p = p8 + mem->offset;
lex_t *ident = parser_expect(par, lex_kind_ident);
parser_expect(par, lex_kind_colon);
assert(s8_equal(ident->s8, mem->name));
s8_deserial_data_ex(arena, par, mem_p, mem->type);
parser_expect(par, lex_kind_comma);
}
parser_expect(par, lex_kind_close_brace);
#endif
}
if (type->kind == type_kind_array) {
u8 *p8 = (u8 *)p;
parser_expect(par, lex_kind_open_brace);
for (i32 i = 0; i < type->count; i += 1) {
type_t *base = type->base;
u8 *mem_p = p8 + base->size * i;
s8_deserial_data_ex(arena, par, mem_p, base);
parser_expect(par, lex_kind_comma);
}
parser_expect(par, lex_kind_close_brace);
}
}
#define s8_deserial_data(ARENA, DATA, TYPE) (TYPE *)s8__deserial_data(ARENA, DATA, &type__##TYPE)
void *s8__deserial_data(ma_arena_t *arena, s8_t data, type_t *type) {
void *p = ma_push_size(arena, type->size);
ma_temp_t scratch = ma_begin_scratch();
lex_array_t tokens = lex_tokens(scratch.arena, "data serializing", data.str);
parser_t *par = parser_make(scratch.arena, tokens.data);
s8_deserial_data_ex(arena, par, p, type);
ma_end_scratch(scratch);
return p;
}

314
src/core/type_info.h Normal file
View File

@@ -0,0 +1,314 @@
typedef int type_kind_t;
enum {
type_kind_invalid,
type_kind_i8,
type_kind_i16,
type_kind_i32,
type_kind_i64,
type_kind_b8,
type_kind_b16,
type_kind_b32,
type_kind_b64,
type_kind_u8,
type_kind_u16,
type_kind_u32,
type_kind_u64,
type_kind_f32,
type_kind_f64,
type_kind_isize,
type_kind_usize,
type_kind_int,
type_kind_char,
type_kind_count,
type_kind_pointer,
type_kind_array,
type_kind_struct,
type_kind_union,
type_kind_enum,
};
typedef struct type_member_t type_member_t;
typedef struct type_t type_t;
struct type_t {
type_kind_t kind;
s8_t name;
i32 size;
i32 count;
type_member_t *members;
type_t *base;
};
struct type_member_t {
s8_t name;
type_t *type;
i64 value;
u64 offset;
};
#define type(X) &type__##X
#define DEFINE_ENUM(x) type_t type__##x = {type_kind_enum, s8_const_lit(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
#define DEFINE_STRUCT(x) type_t type__##x = {type_kind_struct, s8_const_lit(#x), sizeof(x), .members = members__##x, .count = lengthof(members__##x)}
#define POINTER(x) (type_t){type_kind_pointer, s8_const_lit(#x "*"), sizeof(void *), .base = &type__##x}
s8_t ti_enum_value_to_name(type_t *type, i64 value);
i64 ti_enum_name_to_value(type_t *type, s8_t name);
type_member_t *ti_get_member(type_t *type, s8_t name);
type_t type__i8 = {type_kind_i8, s8_const_lit("i8"), sizeof(i8)};
type_t type__i16 = {type_kind_i16, s8_const_lit("i16"), sizeof(i16)};
type_t type__i32 = {type_kind_i32, s8_const_lit("i32"), sizeof(i32)};
type_t type__i64 = {type_kind_i64, s8_const_lit("i64"), sizeof(i64)};
type_t type__u8 = {type_kind_u8, s8_const_lit("u8"), sizeof(u8)};
type_t type__u16 = {type_kind_u16, s8_const_lit("u16"), sizeof(u16)};
type_t type__u32 = {type_kind_u32, s8_const_lit("u32"), sizeof(u32)};
type_t type__u64 = {type_kind_u64, s8_const_lit("u64"), sizeof(u64)};
type_t type__b8 = {type_kind_b8, s8_const_lit("b8"), sizeof(b8)};
type_t type__b16 = {type_kind_b16, s8_const_lit("b16"), sizeof(b16)};
type_t type__b32 = {type_kind_b32, s8_const_lit("b32"), sizeof(b32)};
type_t type__b64 = {type_kind_b64, s8_const_lit("b64"), sizeof(b64)};
type_t type__f32 = {type_kind_f32, s8_const_lit("f32"), sizeof(f32)};
type_t type__f64 = {type_kind_f64, s8_const_lit("f64"), sizeof(f64)};
type_t type__isize = {type_kind_isize, s8_const_lit("isize"), sizeof(isize)};
type_t type__usize = {type_kind_usize, s8_const_lit("usize"), sizeof(usize)};
type_t type__int = {type_kind_int, s8_const_lit("int"), sizeof(int)};
type_t type__char = {type_kind_char, s8_const_lit("char"), sizeof(char)};
type_t type__s8_t = { type_kind_struct, s8_const_lit("s8_t"), sizeof(s8_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("str"), &POINTER(char), .offset = offsetof(s8_t, str)},
{s8_const_lit("len"), &type__i64, .offset = offsetof(s8_t, len)},
}
};
type_t type__s16_t = { type_kind_struct, s8_const_lit("s16_t"), sizeof(s16_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("str"), &POINTER(u16), .offset = offsetof(s16_t, str)},
{s8_const_lit("len"), &type__i64, .offset = offsetof(s16_t, len)},
}
};
type_t type__s32_t = { type_kind_struct, s8_const_lit("s32_t"), sizeof(s32_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("str"), &POINTER(u32), .offset = offsetof(s32_t, str)},
{s8_const_lit("len"), &type__i64, .offset = offsetof(s32_t, len)},
}
};
type_t type__ma_arena_t = { type_kind_struct, s8_const_lit("ma_arena_t"), sizeof(ma_arena_t), .count = 6,
.members = (type_member_t[]){
{s8_const_lit("data"), &POINTER(u8), .offset = offsetof(ma_arena_t, data)},
{s8_const_lit("len"), &type__usize, .offset = offsetof(ma_arena_t, len)},
{s8_const_lit("base_len"), &type__usize, .offset = offsetof(ma_arena_t, base_len)},
{s8_const_lit("reserve"), &type__usize, .offset = offsetof(ma_arena_t, reserve)},
{s8_const_lit("commit"), &type__usize, .offset = offsetof(ma_arena_t, commit)},
{s8_const_lit("align"), &type__usize, .offset = offsetof(ma_arena_t, align)},
}
};
type_t type__ma_temp_t = { type_kind_struct, s8_const_lit("ma_temp_t"), sizeof(ma_temp_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("arena"), &POINTER(ma_arena_t), .offset = offsetof(ma_temp_t, arena)},
{s8_const_lit("len"), &type__usize, .offset = offsetof(ma_temp_t, len)},
}
};
type_t type__v2f32_t = { type_kind_struct, s8_const_lit("v2f32_t"), sizeof(v2f32_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f32, .offset = offsetof(v2f32_t, x)},
{s8_const_lit("y"), &type__f32, .offset = offsetof(v2f32_t, y)},
}
};
type_t type__v3f32_t = { type_kind_struct, s8_const_lit("v3f32_t"), sizeof(v3f32_t), .count = 3,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f32, .offset = offsetof(v3f32_t, x)},
{s8_const_lit("y"), &type__f32, .offset = offsetof(v3f32_t, y)},
{s8_const_lit("z"), &type__f32, .offset = offsetof(v3f32_t, z)},
}
};
type_t type__v4f32_t = { type_kind_struct, s8_const_lit("v4f32_t"), sizeof(v4f32_t), .count = 4,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f32, .offset = offsetof(v4f32_t, x)},
{s8_const_lit("y"), &type__f32, .offset = offsetof(v4f32_t, y)},
{s8_const_lit("z"), &type__f32, .offset = offsetof(v4f32_t, z)},
{s8_const_lit("w"), &type__f32, .offset = offsetof(v4f32_t, w)},
}
};
type_t type__r3f32_t = { type_kind_struct, s8_const_lit("r3f32_t"), sizeof(r3f32_t), .count = 6,
.members = (type_member_t[]){
{s8_const_lit("x0"), &type__f32, .offset = offsetof(r3f32_t, x0)},
{s8_const_lit("y0"), &type__f32, .offset = offsetof(r3f32_t, y0)},
{s8_const_lit("x0"), &type__f32, .offset = offsetof(r3f32_t, z0)},
{s8_const_lit("x1"), &type__f32, .offset = offsetof(r3f32_t, x1)},
{s8_const_lit("y1"), &type__f32, .offset = offsetof(r3f32_t, y1)},
{s8_const_lit("x1"), &type__f32, .offset = offsetof(r3f32_t, z1)},
}
};
type_member_t members__r2f32_t[] = {
{s8_const_lit("x0"), &type__f32, .offset = offsetof(r2f32_t, x0)},
{s8_const_lit("y0"), &type__f32, .offset = offsetof(r2f32_t, y0)},
{s8_const_lit("x1"), &type__f32, .offset = offsetof(r2f32_t, x1)},
{s8_const_lit("y1"), &type__f32, .offset = offsetof(r2f32_t, y1)},
};
DEFINE_STRUCT(r2f32_t);
type_member_t members__r1f32_t[] = {
{s8_const_lit("x0"), &type__f32, .offset = offsetof(r1f32_t, x0)},
{s8_const_lit("x1"), &type__f32, .offset = offsetof(r1f32_t, x1)},
};
DEFINE_STRUCT(r1f32_t);
type_t type__v2f64_t = { type_kind_struct, s8_const_lit("v2f64_t"), sizeof(v2f64_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f64, .offset = offsetof(v2f64_t, x)},
{s8_const_lit("y"), &type__f64, .offset = offsetof(v2f64_t, y)},
}
};
type_t type__v3f64_t = { type_kind_struct, s8_const_lit("v3f64_t"), sizeof(v3f64_t), .count = 3,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f64, .offset = offsetof(v3f64_t, x)},
{s8_const_lit("y"), &type__f64, .offset = offsetof(v3f64_t, y)},
{s8_const_lit("z"), &type__f64, .offset = offsetof(v3f64_t, z)},
}
};
type_t type__v4f64_t = { type_kind_struct, s8_const_lit("v4f64_t"), sizeof(v4f64_t), .count = 4,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__f64, .offset = offsetof(v4f64_t, x)},
{s8_const_lit("y"), &type__f64, .offset = offsetof(v4f64_t, y)},
{s8_const_lit("z"), &type__f64, .offset = offsetof(v4f64_t, z)},
{s8_const_lit("w"), &type__f64, .offset = offsetof(v4f64_t, w)},
}
};
type_t type__r3f64_t = { type_kind_struct, s8_const_lit("r3f64_t"), sizeof(r3f64_t), .count = 6,
.members = (type_member_t[]){
{s8_const_lit("x0"), &type__f64, .offset = offsetof(r3f64_t, x0)},
{s8_const_lit("y0"), &type__f64, .offset = offsetof(r3f64_t, y0)},
{s8_const_lit("x0"), &type__f64, .offset = offsetof(r3f64_t, z0)},
{s8_const_lit("x1"), &type__f64, .offset = offsetof(r3f64_t, x1)},
{s8_const_lit("y1"), &type__f64, .offset = offsetof(r3f64_t, y1)},
{s8_const_lit("x1"), &type__f64, .offset = offsetof(r3f64_t, z1)},
}
};
type_member_t members__r2f64_t[] = {
{s8_const_lit("x0"), &type__f64, .offset = offsetof(r2f64_t, x0)},
{s8_const_lit("y0"), &type__f64, .offset = offsetof(r2f64_t, y0)},
{s8_const_lit("x1"), &type__f64, .offset = offsetof(r2f64_t, x1)},
{s8_const_lit("y1"), &type__f64, .offset = offsetof(r2f64_t, y1)},
};
DEFINE_STRUCT(r2f64_t);
type_member_t members__r1f64_t[] = {
{s8_const_lit("x0"), &type__f64, .offset = offsetof(r1f64_t, x0)},
{s8_const_lit("x1"), &type__f64, .offset = offsetof(r1f64_t, x1)},
};
DEFINE_STRUCT(r1f64_t);
type_t type__v2i32_t = { type_kind_struct, s8_const_lit("v2i32_t"), sizeof(v2i32_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i32, .offset = offsetof(v2i32_t, x)},
{s8_const_lit("y"), &type__i32, .offset = offsetof(v2i32_t, y)},
}
};
type_t type__v3i32_t = { type_kind_struct, s8_const_lit("v3i32_t"), sizeof(v3i32_t), .count = 3,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i32, .offset = offsetof(v3i32_t, x)},
{s8_const_lit("y"), &type__i32, .offset = offsetof(v3i32_t, y)},
{s8_const_lit("z"), &type__i32, .offset = offsetof(v3i32_t, z)},
}
};
type_t type__v4i32_t = { type_kind_struct, s8_const_lit("v4i32_t"), sizeof(v4i32_t), .count = 4,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i32, .offset = offsetof(v4i32_t, x)},
{s8_const_lit("y"), &type__i32, .offset = offsetof(v4i32_t, y)},
{s8_const_lit("z"), &type__i32, .offset = offsetof(v4i32_t, z)},
{s8_const_lit("w"), &type__i32, .offset = offsetof(v4i32_t, w)},
}
};
type_t type__r3i32_t = { type_kind_struct, s8_const_lit("r3i32_t"), sizeof(r3i32_t), .count = 6,
.members = (type_member_t[]){
{s8_const_lit("x0"), &type__i32, .offset = offsetof(r3i32_t, x0)},
{s8_const_lit("y0"), &type__i32, .offset = offsetof(r3i32_t, y0)},
{s8_const_lit("x0"), &type__i32, .offset = offsetof(r3i32_t, z0)},
{s8_const_lit("x1"), &type__i32, .offset = offsetof(r3i32_t, x1)},
{s8_const_lit("y1"), &type__i32, .offset = offsetof(r3i32_t, y1)},
{s8_const_lit("x1"), &type__i32, .offset = offsetof(r3i32_t, z1)},
}
};
type_member_t members__r2i32_t[] = {
{s8_const_lit("x0"), &type__i32, .offset = offsetof(r2i32_t, x0)},
{s8_const_lit("y0"), &type__i32, .offset = offsetof(r2i32_t, y0)},
{s8_const_lit("x1"), &type__i32, .offset = offsetof(r2i32_t, x1)},
{s8_const_lit("y1"), &type__i32, .offset = offsetof(r2i32_t, y1)},
};
DEFINE_STRUCT(r2i32_t);
type_member_t members__r1i32_t[] = {
{s8_const_lit("x0"), &type__i32, .offset = offsetof(r1i32_t, x0)},
{s8_const_lit("x1"), &type__i32, .offset = offsetof(r1i32_t, x1)},
};
DEFINE_STRUCT(r1i32_t);
type_t type__v2i64_t = { type_kind_struct, s8_const_lit("v2i64_t"), sizeof(v2i64_t), .count = 2,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i64, .offset = offsetof(v2i64_t, x)},
{s8_const_lit("y"), &type__i64, .offset = offsetof(v2i64_t, y)},
}
};
type_t type__v3i64_t = { type_kind_struct, s8_const_lit("v3i64_t"), sizeof(v3i64_t), .count = 3,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i64, .offset = offsetof(v3i64_t, x)},
{s8_const_lit("y"), &type__i64, .offset = offsetof(v3i64_t, y)},
{s8_const_lit("z"), &type__i64, .offset = offsetof(v3i64_t, z)},
}
};
type_t type__v4i64_t = { type_kind_struct, s8_const_lit("v4i64_t"), sizeof(v4i64_t), .count = 4,
.members = (type_member_t[]){
{s8_const_lit("x"), &type__i64, .offset = offsetof(v4i64_t, x)},
{s8_const_lit("y"), &type__i64, .offset = offsetof(v4i64_t, y)},
{s8_const_lit("z"), &type__i64, .offset = offsetof(v4i64_t, z)},
{s8_const_lit("w"), &type__i64, .offset = offsetof(v4i64_t, w)},
}
};
type_t type__r3i64_t = { type_kind_struct, s8_const_lit("r3i64_t"), sizeof(r3i64_t), .count = 6,
.members = (type_member_t[]){
{s8_const_lit("x0"), &type__i64, .offset = offsetof(r3i64_t, x0)},
{s8_const_lit("y0"), &type__i64, .offset = offsetof(r3i64_t, y0)},
{s8_const_lit("x0"), &type__i64, .offset = offsetof(r3i64_t, z0)},
{s8_const_lit("x1"), &type__i64, .offset = offsetof(r3i64_t, x1)},
{s8_const_lit("y1"), &type__i64, .offset = offsetof(r3i64_t, y1)},
{s8_const_lit("x1"), &type__i64, .offset = offsetof(r3i64_t, z1)},
}
};
type_member_t members__r2i64_t[] = {
{s8_const_lit("x0"), &type__i64, .offset = offsetof(r2i64_t, x0)},
{s8_const_lit("y0"), &type__i64, .offset = offsetof(r2i64_t, y0)},
{s8_const_lit("x1"), &type__i64, .offset = offsetof(r2i64_t, x1)},
{s8_const_lit("y1"), &type__i64, .offset = offsetof(r2i64_t, y1)},
};
DEFINE_STRUCT(r2i64_t);
type_member_t members__r1i64_t[] = {
{s8_const_lit("x0"), &type__i64, .offset = offsetof(r1i64_t, x0)},
{s8_const_lit("x1"), &type__i64, .offset = offsetof(r1i64_t, x1)},
};
DEFINE_STRUCT(r1i64_t);

538
src/core/types.h Normal file
View File

@@ -0,0 +1,538 @@
typedef uintptr_t usize;
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
typedef intptr_t isize;
typedef int64_t i64;
typedef int32_t i32;
typedef int16_t i16;
typedef int8_t i8;
typedef int64_t b64;
typedef int32_t b32;
typedef int16_t b16;
typedef int8_t b8;
typedef float f32;
typedef double f64;
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#define MIN(x,y) ((x) > (y) ? (y) : (x))
#define MAX(x,y) ((x) > (y) ? (x) : (y))
#define CLAMP_TOP(A,X) MIN(A,X)
#define CLAMP_BOT(X,B) MAX(X,B)
#define CLAMP(x,a,b) (((x)<(a))?(a):((x)>(b))?(b):(x))
#define set_bit(x) (1ULL << (x))
#define lengthof(x) (sizeof((x))/sizeof((x)[0]))
#ifndef offsetof
#define offsetof(st, m) ((usize)&(((st *)0)->m))
#endif
#define kib(x) (1024ULL * (x##ULL))
#define mib(x) (1024ULL * kib(x))
#define gib(x) (1024ULL * mib(x))
#define DEFER_LOOP(begin, end) for (int PASTE(_i_, __LINE__) = (begin, 0); !PASTE(_i_, __LINE__); PASTE(_i_, __LINE__) += (end, 1))
#define STACK(type, size) struct { type data[size]; i32 len; }
#define STACK_PUSH(stack, ...) (assert((stack).len < lengthof((stack).data)), (stack).data[(stack).len++] = __VA_ARGS__)
#define STACK_POP(stack) (assert((stack).len > 0), (stack).data[--(stack).len])
#define STACK_LAST(stack) (assert((stack).len > 0), (stack).data + ((stack).len-1))
#define STRINGIFY_(S) #S
#define STRINGIFY(S) STRINGIFY_(S)
#define PASTE_(a, b) a##b
#define PASTE(a, b) PASTE_(a, b)
#define SWAP(t, a, b) do { t PASTE(temp__, __LINE__) = a; a = b; b = PASTE(temp__, __LINE__); } while(0)
#define CODE(...) #__VA_ARGS__
#define S8_CODE(...) s8_lit(#__VA_ARGS__)
#if PLATFORM_CL
#define FILE_AND_LINE __FILE__"("STRINGIFY(__LINE__)")"
#else
#define FILE_AND_LINE __FILE__":"STRINGIFY(__LINE__)
#endif
#if PLATFORM_CL
#define debug__break() __debugbreak()
#else
#define debug__break() __builtin_trap()
#endif
#define debug_break() (debug__break(), 0)
#if PLATFORM_ASSERT
#define assert(x) (!(x) && debug_break())
#define assertf(x, ...) do {\
debugf(__VA_ARGS__);\
assert(x);\
} while(0)
#else
#define assert(x) ((void)(x))
#define assertf(x,...) ((void)(x))
#endif
#if PLATFORM_WASM
#define THREAD_LOCAL
#elif PLATFORM_GCC | PLATFORM_CLANG
#define THREAD_LOCAL __thread
#elif PLATFORM_CL
#define THREAD_LOCAL __declspec(thread)
#else
#define THREAD_LOCAL _Thread_local
#endif
// Single linked list Queue
#define SLLQ_APPEND_MOD(f, l, n, next) \
do { \
assert((n)->next == NULL); \
if ((f) == 0) { \
(f) = (l) = (n); \
} else { \
(l) = (l)->next = (n); \
} \
} while (0)
#define SLLQ_APPEND(f, l, n) SLLQ_APPEND_MOD(f, l, n, next)
#define SLLQ_PREPEND_MOD(f, l, n, next) \
do { \
assert((n)->next == NULL); \
if ((f) == 0) { \
(f) = (l) = (n); \
} else { \
(n)->next = (f); \
(f) = (n); \
} \
} while (0)
#define SLLQ_PREPEND(f, l, n) SLLQ_PREPEND_MOD(f, l, n, next)
#define SLLQ_REMOVE_FIRST_MOD(f, l, next) \
do { \
if ((f) == (l)) { \
(f) = (l) = 0; \
} else { \
(f) = (f)->next; \
} \
} while (0)
#define SLLQ_REMOVE_FIRST(f, l) SLLQ_REMOVE_FIRST_MOD(f, l, next)
// Singly linked list stack
#define SLLS_PUSH_MOD(stack_base, new_stack_base, next) \
do { \
(new_stack_base)->next = (stack_base); \
(stack_base) = (new_stack_base); \
} while (0)
#define SLLS_PUSH(stack_base, new_stack_base) \
SLLS_PUSH_MOD(stack_base, new_stack_base, next)
#define SLLS_POP_AND_STORE(stack_base, out_node) \
do { \
if (stack_base) { \
(out_node) = (stack_base); \
(stack_base) = (stack_base)->next; \
(out_node)->next = 0; \
} \
} while (0)
// Doubly linked list Queue
#define DLLQ_APPEND_MOD(f, l, node, next, prev) \
do { \
assert((node)->next == NULL); \
assert((node)->prev == NULL); \
if ((f) == 0) { \
(f) = (l) = (node); \
} else { \
(l)->next = (node); \
(node)->prev = (l); \
(l) = (node); \
} \
} while (0)
#define DLLQ_APPEND(f, l, node) DLLQ_APPEND_MOD(f, l, node, next, prev)
#define DLLQ_PREPEND_MOD(f, l, node, next, prev) \
do { \
assert((node)->next == NULL); \
assert((node)->prev == NULL); \
if ((f) == 0) { \
(f) = (l) = (node); \
} else { \
(node)->next = (f); \
(f)->prev = (node); \
(f) = (node); \
} \
} while (0)
#define DLLQ_PREPEND(f, l, node) DLLQ_PREPEND_MOD(f, l, node, next, prev)
#define DLLQ_CONTAINS(f, l, n, next, prev) for (
#define DLLQ_REMOVE_MOD(first, last, node, next, prev) \
do { \
if ((first) == (last)) { \
assert((node) == (first)); \
(first) = (last) = 0; \
} else if ((last) == (node)) { \
(last) = (last)->prev; \
(last)->next = 0; \
} else if ((first) == (node)) { \
(first) = (first)->next; \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLLQ_REMOVE(first, last, node) DLLQ_REMOVE_MOD(first, last, node, next, prev)
// Doubly linked list Stack
#define DLLS_ADD_MOD(first, node, next, prev) \
do { \
assert((node)->next == NULL); \
assert((node)->prev == NULL); \
(node)->next = (first); \
if ((first)) \
(first)->prev = (node); \
(first) = (node); \
} while (0)
#define DLLS_ADD(first, node) DLLS_ADD_MOD(first, node, next, prev)
#define DLLS_REMOVE_MOD(first, node, next, prev) \
do { \
if ((node) == (first)) { \
(first) = (first)->next; \
if ((first)) \
(first)->prev = 0; \
} else { \
(node)->prev->next = (node)->next; \
if ((node)->next) \
(node)->next->prev = (node)->prev; \
} \
if (node) { \
(node)->prev = 0; \
(node)->next = 0; \
} \
} while (0)
#define DLLS_REMOVE(first, node) DLLS_REMOVE_MOD(first, node, next, prev)
const usize ma_page_size = 4096;
const usize ma_default_alignment = sizeof(void *);
const usize ma_default_reserve_size = mib(256);
typedef struct ma_arena_t ma_arena_t;
struct ma_arena_t {
u8 *data;
usize len;
usize base_len; // to prevent self deleting the arena
usize reserve;
usize commit;
usize align;
};
typedef struct ma_temp_t ma_temp_t;
struct ma_temp_t {
ma_arena_t *arena;
usize len;
};
void ma_init(ma_arena_t *arena, usize reserve);
ma_arena_t *ma_create(usize reserve);
void ma_destroy(ma_arena_t *arena);
void *ma_push_size_ex(ma_arena_t *arena, usize size);
void *ma_push_size(ma_arena_t *arena, usize size);
ma_arena_t *ma_push_arena(ma_arena_t *allocator, usize size);
#define ma_push_type(arena, Type) (Type *)ma_push_size((arena), sizeof(Type))
#define ma_push_array(arena, Type, count) (Type *)ma_push_size((arena), sizeof(Type) * (count))
void ma_set_len(ma_arena_t *arena, usize pos);
void ma_pop(ma_arena_t *arena, usize size);
void ma_set0(ma_arena_t *arena);
ma_temp_t ma_begin_temp(ma_arena_t *arena);
void ma_end_temp(ma_temp_t temp);
typedef struct s8_t s8_t;
struct s8_t {
char *str;
int64_t len;
};
typedef struct s16_t s16_t;
struct s16_t {
u16 *str;
i64 len;
};
typedef struct s32_t s32_t;
struct s32_t {
u32 *str;
i64 len;
};
typedef struct sb8_node_t sb8_node_t;
struct sb8_node_t {
sb8_node_t *next;
union {
struct { char *str; int64_t len; };
s8_t s;
};
};
typedef struct sb8_t sb8_t;
struct sb8_t {
ma_arena_t *arena;
sb8_node_t *first;
sb8_node_t *last;
int indent;
};
i64 wstr_len(wchar_t *string);
int str_len(char *str);
char char_to_lower_case(char a);
char char_to_upper_case(char a);
b32 char_is_whitespace(char w);
b32 char_is_alphabetic(char a);
b32 char_is_ident(char a);
b32 char_is_digit(char a);
b32 char_is_alphanumeric(char a);
b32 s8_equal(s8_t a, s8_t b);
enum { s8_ignore_case = 1 };
#define s8(str,len) (s8_t){str, len}
#define s8_nil() (s8_t){0}
#define s8_lit(string) (s8_t){(char *)string, sizeof(string) - 1}
#define s8_const_lit(string) { string, sizeof(string) - 1 }
#define s8_fmtspec(string) (int)(string).len, (string).str
#define sb8_serial_begin(arena) &(sb8_t){.arena = arena}
#define sb8_serial_end(sb) sb8_merge(sb)
typedef struct core_desc_t core_desc_t;
struct core_desc_t {
void (*print)(char *string);
void (*panic)(void);
void (*on_exit)(void);
ma_arena_t scratch[3];
b32 break_on_panic;
};
extern THREAD_LOCAL core_desc_t core_desc;
void debugf(const char *string, ...);
void panicf(const char *string, ...);
typedef union v2f32_t v2f32_t;
union v2f32_t {
struct { f32 x, y; };
f32 e[2];
};
typedef union v3f32_t v3f32_t;
union v3f32_t {
struct { f32 x, y, z; };
struct { v2f32_t xy; };
struct { f32 _x0; v2f32_t zw; };
struct { f32 r, g, b; };
struct { f32 h, s, l; };
f32 e[3];
};
typedef union v4f32_t v4f32_t;
union v4f32_t {
struct { f32 x, y, z, w; };
struct { v2f32_t xy; v2f32_t zw; };
struct { v3f32_t xyz; };
struct { f32 _x0; f32 yzw; };
struct { f32 r, g, b, a; };
struct { f32 h, s, l, _a; };
f32 e[4];
};
typedef union r1f32_t r1f32_t;
union r1f32_t {
struct { f32 min, max; };
struct { f32 x0, x1; };
f32 e[2];
};
typedef union r2f32_t r2f32_t;
union r2f32_t {
struct { v2f32_t min, max; };
struct { f32 x0, y0, x1, y1; };
v4f32_t e4;
f32 e[4];
};
typedef union r3f32_t r3f32_t;
union r3f32_t {
struct { v3f32_t min, max; };
struct { f32 x0, y0, z0, x1, y1, z1; };
f32 e[6];
};
typedef union v2f64_t v2f64_t;
union v2f64_t {
struct { f64 x, y; };
f64 e[2];
};
typedef union v3f64_t v3f64_t;
union v3f64_t {
struct { f64 x, y, z; };
struct { v2f64_t xy; };
struct { f64 _x0; v2f64_t zw; };
struct { f64 r, g, b; };
struct { f64 h, s, l; };
f64 e[3];
};
typedef union v4f64_t v4f64_t;
union v4f64_t {
struct { f64 x, y, z, w; };
struct { v2f64_t xy; v2f64_t zw; };
struct { v3f64_t xyz; };
struct { f64 _x0; f64 yzw; };
struct { f64 r, g, b, a; };
struct { f64 h, s, l, _a; };
f64 e[4];
};
typedef union r1f64_t r1f64_t;
union r1f64_t {
struct { f64 min, max; };
struct { f64 x0, x1; };
f64 e[2];
};
typedef union r2f64_t r2f64_t;
union r2f64_t {
struct { v2f64_t min, max; };
struct { f64 x0, y0, x1, y1; };
v4f64_t e4;
f64 e[4];
};
typedef union r3f64_t r3f64_t;
union r3f64_t {
struct { v3f64_t min, max; };
struct { f64 x0, y0, z0, x1, y1, z1; };
f64 e[6];
};
typedef union v2i32_t v2i32_t;
union v2i32_t {
struct { i32 x, y; };
i32 e[2];
};
typedef union v3i32_t v3i32_t;
union v3i32_t {
struct { i32 x, y, z; };
struct { v2i32_t xy; };
struct { i32 _x0; v2i32_t zw; };
struct { i32 r, g, b; };
struct { i32 h, s, l; };
i32 e[3];
};
typedef union v4i32_t v4i32_t;
union v4i32_t {
struct { i32 x, y, z, w; };
struct { v2i32_t xy; v2i32_t zw; };
struct { v3i32_t xyz; };
struct { i32 _x0; i32 yzw; };
struct { i32 r, g, b, a; };
struct { i32 h, s, l, _a; };
i32 e[4];
};
typedef union r1i32_t r1i32_t;
union r1i32_t {
struct { i32 min, max; };
struct { i32 x0, x1; };
i32 e[2];
};
typedef union r2i32_t r2i32_t;
union r2i32_t {
struct { v2i32_t min, max; };
struct { i32 x0, y0, x1, y1; };
v4i32_t e4;
i32 e[4];
};
typedef union r3i32_t r3i32_t;
union r3i32_t {
struct { v3i32_t min, max; };
struct { i32 x0, y0, z0, x1, y1, z1; };
i32 e[6];
};
typedef union v2i64_t v2i64_t;
union v2i64_t {
struct { i64 x, y; };
i64 e[2];
};
typedef union v3i64_t v3i64_t;
union v3i64_t {
struct { i64 x, y, z; };
struct { v2i64_t xy; };
struct { i64 _x0; v2i64_t zw; };
struct { i64 r, g, b; };
struct { i64 h, s, l; };
i64 e[3];
};
typedef union v4i64_t v4i64_t;
union v4i64_t {
struct { i64 x, y, z, w; };
struct { v2i64_t xy; v2i64_t zw; };
struct { v3i64_t xyz; };
struct { i64 _x0; i64 yzw; };
struct { i64 r, g, b, a; };
struct { i64 h, s, l, _a; };
i64 e[4];
};
typedef union r1i64_t r1i64_t;
union r1i64_t {
struct { i64 min, max; };
struct { i64 x0, x1; };
i64 e[2];
};
typedef union r2i64_t r2i64_t;
union r2i64_t {
struct { v2i64_t min, max; };
struct { i64 x0, y0, x1, y1; };
v4i64_t e4;
i64 e[4];
};
typedef union r3i64_t r3i64_t;
union r3i64_t {
struct { v3i64_t min, max; };
struct { i64 x0, y0, z0, x1, y1, z1; };
i64 e[6];
};

226
src/core/unicode.c Normal file
View File

@@ -0,0 +1,226 @@
typedef struct utf32_result_t utf32_result_t;
struct utf32_result_t {
uint32_t out_str;
int advance;
int error;
};
typedef struct utf16_result_t utf16_result_t;
struct utf16_result_t {
uint16_t out_str[2];
int len;
int error;
};
typedef struct utf8_result_t utf8_result_t;
struct utf8_result_t {
uint8_t out_str[4];
int len;
int error;
};
typedef struct utf8_iter_t utf8_iter_t;
struct utf8_iter_t {
char *str;
int len;
int utf8_codepoint_byte_size;
int i;
uint32_t item;
};
utf32_result_t utf16_to_utf32(uint16_t *c, int max_advance) {
utf32_result_t result = {0};
if (max_advance >= 1) {
result.advance = 1;
result.out_str = c[0];
if (c[0] >= 0xD800 && c[0] <= 0xDBFF && c[1] >= 0xDC00 && c[1] <= 0xDFFF) {
if (max_advance >= 2) {
result.out_str = 0x10000;
result.out_str += (uint32_t)(c[0] & 0x03FF) << 10u | (c[1] & 0x03FF);
result.advance = 2;
}
else
result.error = 2;
}
}
else {
result.error = 1;
}
return result;
}
utf8_result_t utf32_to_utf8(uint32_t codepoint) {
utf8_result_t result = {0};
if (codepoint <= 0x7F) {
result.len = 1;
result.out_str[0] = (char)codepoint;
}
else if (codepoint <= 0x7FF) {
result.len = 2;
result.out_str[0] = 0xc0 | (0x1f & (codepoint >> 6));
result.out_str[1] = 0x80 | (0x3f & codepoint);
}
else if (codepoint <= 0xFFFF) { // 16 bit word
result.len = 3;
result.out_str[0] = 0xe0 | (0xf & (codepoint >> 12)); // 4 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & codepoint); // 6 bits
}
else if (codepoint <= 0x10FFFF) { // 21 bit word
result.len = 4;
result.out_str[0] = 0xf0 | (0x7 & (codepoint >> 18)); // 3 bits
result.out_str[1] = 0x80 | (0x3f & (codepoint >> 12)); // 6 bits
result.out_str[2] = 0x80 | (0x3f & (codepoint >> 6)); // 6 bits
result.out_str[3] = 0x80 | (0x3f & codepoint); // 6 bits
}
else {
result.error = 1;
}
return result;
}
utf32_result_t utf8_to_utf32(char *c, int max_advance) {
utf32_result_t result = {0};
if ((c[0] & 0x80) == 0) { // Check if leftmost zero of first byte is unset
if (max_advance >= 1) {
result.out_str = c[0];
result.advance = 1;
}
else result.error = 1;
}
else if ((c[0] & 0xe0) == 0xc0) {
if ((c[1] & 0xc0) == 0x80) { // Continuation byte required
if (max_advance >= 2) {
result.out_str = (uint32_t)(c[0] & 0x1f) << 6u | (c[1] & 0x3f);
result.advance = 2;
}
else result.error = 2;
}
else result.error = 2;
}
else if ((c[0] & 0xf0) == 0xe0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80) { // Two continuation bytes required
if (max_advance >= 3) {
result.out_str = (uint32_t)(c[0] & 0xf) << 12u | (uint32_t)(c[1] & 0x3f) << 6u | (c[2] & 0x3f);
result.advance = 3;
}
else result.error = 3;
}
else result.error = 3;
}
else if ((c[0] & 0xf8) == 0xf0) {
if ((c[1] & 0xc0) == 0x80 && (c[2] & 0xc0) == 0x80 && (c[3] & 0xc0) == 0x80) { // Three continuation bytes required
if (max_advance >= 4) {
result.out_str = (uint32_t)(c[0] & 0xf) << 18u | (uint32_t)(c[1] & 0x3f) << 12u | (uint32_t)(c[2] & 0x3f) << 6u | (uint32_t)(c[3] & 0x3f);
result.advance = 4;
}
else result.error = 4;
}
else result.error = 4;
}
else result.error = 4;
return result;
}
utf16_result_t utf32_to_utf16(uint32_t codepoint) {
utf16_result_t result = {0};
if (codepoint < 0x10000) {
result.out_str[0] = (uint16_t)codepoint;
result.out_str[1] = 0;
result.len = 1;
}
else if (codepoint <= 0x10FFFF) {
uint32_t code = (codepoint - 0x10000);
result.out_str[0] = (uint16_t)(0xD800 | (code >> 10));
result.out_str[1] = (uint16_t)(0xDC00 | (code & 0x3FF));
result.len = 2;
}
else {
result.error = 1;
}
return result;
}
#define UTF__HANDLE_DECODE_ERROR(question_mark) \
{ \
if (outlen < buffer_size - 1) buffer[outlen++] = (question_mark); \
break; \
}
int64_t str_from_wstr(char *buffer, int64_t buffer_size, uint16_t *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen && in[i];) {
utf32_result_t decode = utf16_to_utf32((uint16_t *)(in + i), (int)(inlen - i));
if (!decode.error) {
i += decode.advance;
utf8_result_t encode = utf32_to_utf8(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
}
else UTF__HANDLE_DECODE_ERROR('?');
}
else UTF__HANDLE_DECODE_ERROR('?');
}
buffer[outlen] = 0;
return outlen;
}
int64_t wstr_from_str(uint16_t *buffer, int64_t buffer_size, char *in, int64_t inlen) {
int64_t outlen = 0;
for (int64_t i = 0; i < inlen;) {
utf32_result_t decode = utf8_to_utf32(in + i, (int)(inlen - i));
if (!decode.error) {
i += decode.advance;
utf16_result_t encode = utf32_to_utf16(decode.out_str);
if (!encode.error) {
for (int64_t j = 0; j < encode.len; j++) {
if (outlen < buffer_size - 1) {
buffer[outlen++] = encode.out_str[j];
}
}
}
else UTF__HANDLE_DECODE_ERROR(0x003f);
}
else UTF__HANDLE_DECODE_ERROR(0x003f);
}
buffer[outlen] = 0;
return outlen;
}
void utf8_advance(utf8_iter_t *iter) {
iter->i += iter->utf8_codepoint_byte_size;
utf32_result_t r = utf8_to_utf32(iter->str + iter->i, iter->len - iter->i);
if (r.error) {
iter->item = 0;
return;
}
iter->utf8_codepoint_byte_size = r.advance;
iter->item = r.out_str;
}
utf8_iter_t utf8_iterate_ex(char *str, int len) {
utf8_iter_t result = {str, len};
if (len) utf8_advance(&result);
return result;
}
utf8_iter_t utf8_iterate(char *str) {
int length = 0;
while (str[length]) length += 1;
return utf8_iterate_ex(str, length);
}

View File

@@ -0,0 +1,110 @@
#include "core/core.h"
#include "core/core.c"
void test_s8(void) {
ma_arena_t *arena = ma_create(ma_default_reserve_size);
{
ma_temp_t temp = ma_begin_temp(arena);
sb8_t *sb = &(sb8_t){arena};
s8_t memes = s8_lit("memes");
sb8_printf(sb, "%S", memes);
assert(sb->first == sb->last);
assert(sb->first->len == 5);
assert(s8_equal(sb->first->s, memes));
sb8_printf(sb, "%S", s8_lit("things are going fine"));
s8_t string = sb8_merge(sb);
assert(s8_equal(string, s8_lit("memesthings are going fine")));
ma_end_temp(temp);
}
{
s8_t str = s8_lit("thing|another|");
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_none);
assert(s8_equal(sb.first->s, s8_lit("thing")));
assert(s8_equal(sb.first->next->s, s8_lit("another")));
assert(sb.first->next->next == NULL);
}
{
s8_t str = s8_lit("thing|another|");
sb8_t sb = s8_split(arena, str, s8_lit("|"), s8_split_inclusive);
assert(s8_equal(sb.first->s, s8_lit("thing")));
assert(s8_equal(sb.first->next->s, s8_lit("|")));
assert(s8_equal(sb.first->next->next->s, s8_lit("another")));
assert(s8_equal(sb.first->next->next->next->s, s8_lit("|")));
assert(sb.first->next->next->next->next == NULL);
}
{
s8_t str = s8_lit("aabaaBaa");
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive | s8_split_ignore_case);
assert(s8_equal(sb.first->s, s8_lit("aa")));
assert(s8_equal(sb.first->next->s, s8_lit("b")));
assert(s8_equal(sb.first->next->next->s, s8_lit("aa")));
assert(s8_equal(sb.first->next->next->next->s, s8_lit("B")));
assert(s8_equal(sb.first->next->next->next->next->s, s8_lit("aa")));
assert(sb.first->next->next->next->next->next == NULL);
}
{
s8_t str = s8_lit("aabaaBaa");
sb8_t sb = s8_split(arena, str, s8_lit("b"), s8_split_inclusive);
assert(s8_equal(sb.first->s, s8_lit("aa")));
assert(s8_equal(sb.first->next->s, s8_lit("b")));
assert(s8_equal(sb.first->next->next->s, s8_lit("aaBaa")));
}
{
s8_t s = s8_lit("0123456789");
assert(s8_equal(s8_slice(s, 0, 4), s8_lit("0123")));
assert(s8_equal(s8_slice(s, -2, -1), s8_lit("89")));
assert(s8_equal(s8_slice(s, -2, 10), s8_lit("89")));
assert(s8_equal(s8_slice(s, 8, 10), s8_lit("89")));
}
{
s8_t s = s8_lit(" a \n");
s = s8_trim(s);
assert(s8_equal(s, s8_lit("a")));
}
{
s8_t s = s8_lit("C:/memes/the_thing.c");
s8_t ss = s8_get_name_no_ext(s);
assert(s8_equal(ss, s8_lit("the_thing")));
}
{
s8_t s = s8_fmt(arena, "%d%Sv%s", 32, s8_lit("|"), ">");
assert(s8_equal(s, s8_lit("32|v>")));
}
ma_destroy(arena);
}
#include <stdio.h>
int main(int argc, char **argv) {
printf("PLATFORM_WASM = %d\n", PLATFORM_WASM);
printf("PLATFORM_WINDOWS = %d\n", PLATFORM_WINDOWS);
printf("PLATFORM_LINUX = %d\n", PLATFORM_LINUX);
printf("PLATFORM_POSIX = %d\n", PLATFORM_POSIX);
printf("PLATFORM_MAC_OS = %d\n", PLATFORM_MAC_OS);
printf("PLATFORM_CLANG = %d\n", PLATFORM_CLANG);
printf("PLATFORM_GCC = %d\n", PLATFORM_GCC);
printf("PLATFORM_CL = %d\n", PLATFORM_CL);
printf("PLATFORM_TCC = %d\n", PLATFORM_TCC);
printf("PLATFORM_ASSERT = %d\n", PLATFORM_ASSERT);
test_s8();
printf("all done!\n");
}

5187
src/meta/build_tool.c Normal file

File diff suppressed because it is too large Load Diff

307
src/meta/parser.c Normal file
View File

@@ -0,0 +1,307 @@
typedef enum {
#define AST_FLAG_XLIST\
X(null)\
X(string)\
X(integer)\
X(real)\
X(binary)\
X(enum)\
X(enum_member)\
X(struct)\
X(struct_member)\
X(var)\
X(type_name)\
X(type_pointer)\
X(type_array)\
#define X(NAME) ast_flag_##NAME,
AST_FLAG_XLIST
#undef X
} ast_flag_t;
typedef struct ast_t ast_t;
struct ast_t {
ast_flag_t flags;
lex_t *pos;
ast_t *next;
ast_t *first;
ast_t *last;
i32 len;
s8_t string;
f64 real;
i64 integer;
};
s8_t s8_serial_ast_flag_t(ma_arena_t *arena, ast_flag_t flag) {
sb8_t *sb = sb8_serial_begin(arena);
#define X(NAME) if (flag & set_bit(ast_flag_##NAME)) sb8_printf(sb, #NAME);
AST_FLAG_XLIST
#undef X
s8_t result = sb8_serial_end(sb);
return result;
}
ast_t *create_ast(parser_t *par, lex_t *pos, ast_flag_t flags) {
ast_t *result = ma_push_type(par->arena, ast_t);
memset(result, 0, sizeof(ast_t));
result->flags = flags;
result->pos = pos;
return result;
}
void ast_append(ast_t *parent, ast_t *node) {
SLLQ_APPEND(parent->first, parent->last, node);
parent->len += 1;
}
ast_t *create_ast_binary(parser_t *par, lex_t *pos, ast_t *left, lex_kind_t op, ast_t *right) {
ast_t *result = create_ast(par, pos, set_bit(ast_flag_string) | set_bit(ast_flag_binary) | set_bit(ast_flag_integer));
ast_append(result, left);
ast_append(result, right);
result->integer = op;
result->string = s8_serial_simple_lex_kind_t(op);
return result;
}
ast_t *parse_expr(parser_t *par);
ast_t *parse_lit_expr(parser_t *par) {
lex_t *token = parser_next(par);
if (token->kind == lex_kind_int) {
ast_t *result = create_ast(par, token, set_bit(ast_flag_integer) | set_bit(ast_flag_string));
result->integer = token->integer;
result->string = token->s8;
return result;
} else if (token->kind == lex_kind_real) {
ast_t *result = create_ast(par, token, set_bit(ast_flag_real) | set_bit(ast_flag_string));
result->real = (double)token->real;
result->string = token->s8;
return result;
} else if (token->kind == lex_kind_open_paren) {
ast_t *result = parse_expr(par);
parser_expect(par, lex_kind_close_paren);
return result;
} else {
lex_panicf(token, "got invalid token of kind: %S while parsing expression", s8_serial_lex_kind_t(token->kind));
return 0;
}
}
ast_t *parse_mul_expr(parser_t *par) {
ast_t *left = parse_lit_expr(par);
while (par->at->kind == lex_kind_multiply || par->at->kind == lex_kind_divide || par->at->kind == lex_kind_modulo) {
lex_t *op = parser_next(par);
left = create_ast_binary(par, op, left, op->kind, parse_lit_expr(par));
}
return left;
}
ast_t *parse_add_expr(parser_t *par) {
ast_t *left = parse_mul_expr(par);
while (par->at->kind == lex_kind_plus || par->at->kind == lex_kind_minus) {
lex_t *op = parser_next(par);
left = create_ast_binary(par, op, left, op->kind, parse_lit_expr(par));
}
return left;
}
ast_t *parse_logical_and_expr(parser_t *par) {
ast_t *left = parse_add_expr(par);
while (par->at->kind == lex_kind_or) {
lex_t *op = parser_next(par);
left = create_ast_binary(par, op, left, op->kind, parse_lit_expr(par));
}
return left;
}
ast_t *parse_logical_or_expr(parser_t *par) {
ast_t *left = parse_logical_and_expr(par);
while (par->at->kind == lex_kind_or) {
lex_t *op = parser_next(par);
left = create_ast_binary(par, op, left, op->kind, parse_lit_expr(par));
}
return left;
}
ast_t *parse_expr(parser_t *par) {
ast_t *expr = parse_logical_or_expr(par);
return expr;
}
ast_t *parse_expr_str(ma_arena_t *arena, char *file_name, char *stream) {
lex_array_t tokens = lex_tokens(arena, file_name, stream);
parser_t *par = parser_make(arena, tokens.data);
ast_t *result = parse_expr(par);
return result;
}
i64 eval_const_expr(ast_t *expr) {
if (expr->flags & set_bit(ast_flag_integer)) {
return expr->integer;
} else if (expr->flags & set_bit(ast_flag_binary)) {
assert(expr->first != expr->last);
i64 left = eval_const_expr(expr->first);
i64 right = eval_const_expr(expr->last);
switch(expr->integer) {
case lex_kind_plus: return left + right;
case lex_kind_minus: return left - right;
case lex_kind_multiply: return left * right;
case lex_kind_divide: return left / right;
case lex_kind_modulo: return left % right;
case lex_kind_and: return left && right;
case lex_kind_or: return left || right;
default: lex_panicf(expr->pos, "unhandled binary operator: %S", s8_serial_lex_kind_t(expr->integer));
}
} else {
ma_temp_t scratch = ma_begin_scratch();
lex_panicf(expr->pos, "unhandled ast in const expression evaluation: %S", s8_serial_ast_flag_t(scratch.arena, expr->flags));
ma_end_scratch(scratch);
}
return 0;
}
#define test_expr(x) do {\
lex_array_t tokens = lex_tokens(scratch.arena, "parser_test", #x);\
parser_t *par = parser_make(scratch.arena, tokens.data);\
ast_t *expr = parse_expr(par);\
assert(expr != NULL);\
i64 value = eval_const_expr(expr);\
assert(value == x);\
} while (0)
void run_parser_test() {
ma_temp_t scratch = ma_begin_scratch();
test_expr(32 + 2 + 5 + 5);
test_expr(32 - 2 + 5 - 5);
test_expr(2 * 2 / 4 * 5 + 2 + 3);
test_expr(2 * 5 * 5 / 2 + 2 - 1 - 1);
test_expr(2 * (5 * 5) / 2 + (2 - 1 - 1));
test_expr((2 * (5 * 5) / (2)) + (2 - 1 - 1));
test_expr(10 % 3);
test_expr(10 % 3 + 4 || 2);
test_expr(10 % 3 + 4 || 2 && (4 && 2) || 3 && 1 || 0);
ma_end_scratch(scratch);
}
ast_t *parse_struct_mem(parser_t *par, s8_t *name) {
lex_t *type_name = parser_expect(par, lex_kind_ident);
ast_t *type = create_ast(par, type_name, set_bit(ast_flag_type_name) | set_bit(ast_flag_string));
type->string = type_name->s8;
while (parser_match(par, lex_kind_multiply)) {
ast_t *pointer = create_ast(par, par->at, set_bit(ast_flag_type_pointer) | set_bit(ast_flag_string));
ast_append(pointer, type);
pointer->string = s8_fmt(par->arena, "%S*", type->string);
type = pointer;
}
*name = parser_expect(par, lex_kind_ident)->s8;
while (parser_match(par, lex_kind_open_bracket)) {
ast_t *array = create_ast(par, par->at, set_bit(ast_flag_type_array) | set_bit(ast_flag_string));
ast_append(array, type);
lex_t *num = parser_match(par, lex_kind_int);
if (num) {
array->flags |= set_bit(ast_flag_integer);
array->integer = (int)num->integer;
array->string = s8_fmt(par->arena, "%S[%d]", type->string, (int)array->integer);
} else {
array->string = s8_fmt(par->arena, "%S[]", type->string);
}
parser_expect(par, lex_kind_close_bracket);
type = array;
}
return type;
}
ast_t *parse_decls(ma_arena_t *arena, char *file, char *code) {
lex_array_t tokens = lex_tokens(arena, file, code);
parser_t *par = parser_make(arena, tokens.data);
ast_t *result = create_ast(par, par->at, set_bit(ast_flag_string));
result->string = s8_copy_char(arena, file);
for (;par->at->kind != lex_kind_eof;) {
lex_t *pos = par->at;
if (parser_matchi(par, s8_lit("enum"))) {
ast_t *n = create_ast(par, pos, set_bit(ast_flag_string) | set_bit(ast_flag_enum));
ast_append(result, n);
parser_expect(par, lex_kind_open_brace);
while (par->at->kind == lex_kind_ident) {
lex_t *val = parser_expect(par, lex_kind_ident);
ast_t *mem = create_ast(par, val, set_bit(ast_flag_enum_member) | set_bit(ast_flag_string));
mem->string = val->s8;
ast_append(n, mem);
// if (parser_match(par, lex_kind_assign)) {
// parse_expr();
// }
if (!parser_match(par, lex_kind_comma)) break;
}
parser_expect(par, lex_kind_close_brace);
n->string = parser_expect(par, lex_kind_ident)->s8;
parser_expect(par, lex_kind_semicolon);
} else if (parser_matchi(par, s8_lit("struct"))) {
ast_t *n = create_ast(par, pos, set_bit(ast_flag_string) | set_bit(ast_flag_struct));
ast_append(result, n);
n->string = parser_expect(par, lex_kind_ident)->s8;
parser_expect(par, lex_kind_open_brace);
while (par->at->kind != lex_kind_close_brace) {
ast_t *mem = create_ast(par, par->at, set_bit(ast_flag_struct_member) | set_bit(ast_flag_var) | set_bit(ast_flag_string));
ast_append(n, mem);
ast_t *type = parse_struct_mem(par, &mem->string);
ast_append(mem, type);
parser_expect(par, lex_kind_semicolon);
}
parser_expect(par, lex_kind_close_brace);
parser_expect(par, lex_kind_semicolon);
} else {
parser_next(par);
}
}
return result;
}
ast_t *parse_table(ma_arena_t *arena, char *file, char *code) {
lex_array_t tokens = lex_tokens(arena, file, code);
parser_t *par = parser_make(arena, tokens.data);
ast_t *table = create_ast(par, par->at, 0);
while (par->at->kind != lex_kind_eof) {
ast_t *row = create_ast(par, par->at, 0);
ast_append(table, row);
while (par->at->kind != lex_kind_eof) {
parser_match(par, lex_kind_bit_or);
lex_t *token = par->at;
if (parser_match(par, lex_kind_ident) || parser_match(par, lex_kind_string)) {
ast_t *col = create_ast(par, par->at, set_bit(ast_flag_string));
ast_append(row, col);
col->string = token->s8;
} else if (parser_match(par, lex_kind_int)) {
ast_t *col = create_ast(par, par->at, set_bit(ast_flag_string) | set_bit(ast_flag_integer));
ast_append(row, col);
col->string = token->s8;
col->integer = token->integer;
} else if (parser_match(par, lex_kind_real)) {
ast_t *col = create_ast(par, par->at, set_bit(ast_flag_string) | set_bit(ast_flag_real));
ast_append(row, col);
col->string = token->s8;
col->real = token->real;
} else if (parser_match(par, lex_kind_bit_or) || parser_match(par, lex_kind_eof)) {
break;
} else {
lex_panicf(par->at, "invalid token: %S", s8_serial_lex_kind_t(par->at->kind));
}
}
}
return table;
}

224
src/meta/serialize.c Normal file
View File

@@ -0,0 +1,224 @@
s8_t s8_ast_to_cvar(ma_arena_t *arena, ast_t *ast, s8_t *name) {
if (ast->flags & set_bit(ast_flag_type_name)) {
return ast->string;
} else if (ast->flags & set_bit(ast_flag_type_pointer)) {
s8_t base = s8_ast_to_cvar(arena, ast->first, name);
return s8_fmt(arena, "%S*", base);
} else if (ast->flags & set_bit(ast_flag_type_array)) {
if (ast->flags & set_bit(ast_flag_integer)) {
*name = s8_fmt(arena, "%S[%d]", *name, ast->integer);
} else {
*name = s8_fmt(arena, "%S[%d]", *name, ast->integer);
}
s8_t base = s8_ast_to_cvar(arena, ast->first, name);
return base;
} else {
assert(!"invalid ast_str case");
return (s8_t){0};
}
}
void sb8_serial_ast(sb8_t *sb, ast_t *n) {
if (n->flags & set_bit(ast_flag_string)) {
sb8_stmtf(sb, "%S", n->string);
}
if (n->first) {
sb8_printf(sb, "{");
sb->indent += 1;
for (ast_t *it = n->first; it; it = it->next) {
sb8_serial_ast(sb, it);
}
sb->indent -= 1;
sb8_stmtf(sb, "}");
}
}
s8_t s8_serial_ast(ma_arena_t *arena, ast_t *n) {
sb8_t *sb = sb8_serial_begin(arena);
sb8_serial_ast(sb, n);
return sb8_serial_end(sb);
}
s8_t s8_serial_ast_to_code(ma_arena_t *arena, ast_t *n);
void sb8_serial_ast_to_code(sb8_t *sb, ast_t *n) {
if (n->flags & set_bit(ast_flag_enum)) {
sb8_printf(sb, "typedef enum {");
sb->indent += 1;
for (ast_t *it = n->first; it; it = it->next) {
sb8_stmtf(sb, "%S,", it->string);
}
sb->indent -= 1;
sb8_stmtf(sb, "} %S;", n->string);
} else if (n->flags & set_bit(ast_flag_struct)) {
sb8_stmtf(sb, "typedef struct %S %S;", n->string, n->string);
sb8_stmtf(sb, "struct %S {", n->string);
sb->indent += 1;
for (ast_t *it = n->first; it; it = it->next) {
s8_t name = it->string;
s8_t type = s8_ast_to_cvar(sb->arena, it->first, &name);
sb8_stmtf(sb, "%S %S;", type, name);
}
sb->indent -= 1;
sb8_stmtf(sb, "};");
} else {
if (n->flags & set_bit(ast_flag_string)) {
sb8_printf(sb, "/*%S*/", n->string);
} else {
sb8_printf(sb, "/*null*/");
}
for (ast_t *it = n->first; it; it = it->next) {
sb8_indent(sb);
sb8_serial_ast_to_code(sb, it);
}
}
}
s8_t s8_serial_ast_to_code(ma_arena_t *arena, ast_t *n) {
sb8_t *sb = sb8_serial_begin(arena);
sb8_serial_ast_to_code(sb, n);
s8_t result = sb8_serial_end(sb);
return result;
}
s8_t s8_serial_ast_type_to_type_info(ma_arena_t *arena, ast_t *n) {
if (n->flags & set_bit(ast_flag_type_name)) {
return s8_fmt(arena, "type__%S", n->string);
} else if (n->flags & set_bit(ast_flag_type_pointer)) {
s8_t base = s8_serial_ast_type_to_type_info(arena, n->first);
return s8_fmt(arena, "(type_t){type_kind_pointer, s8_const_lit(\"%S\"), sizeof(void *), .base = &%S}", n->string, base);
} else if (n->flags & set_bit(ast_flag_type_array)) {
s8_t base = s8_serial_ast_type_to_type_info(arena, n->first);
return s8_fmt(arena, "(type_t){type_kind_array, s8_const_lit(\"%S\"), sizeof(%S), %d, .base = &%S}", n->string, n->string, (int)n->integer, base);
} else {
lex_panicf(n->pos, "expected type");
}
return (s8_t){0};
}
void sb8_serial_ast_to_type_info(sb8_t *sb, ast_t *n) {
if (n->flags & set_bit(ast_flag_enum)) {
sb8_printf(sb, "type_t type__%S = { type_kind_enum, s8_const_lit(\"%S\"), sizeof(%S),", n->string, n->string, n->string);
sb->indent += 1;
sb8_stmtf(sb, ".members = (type_member_t[]){");
sb->indent += 1;
for (ast_t *it = n->first; it; it = it->next) {
sb8_stmtf(sb, "{.name = s8_const_lit(\"%S\"), .value = %S},", it->string, it->string);
}
sb->indent -= 1;
sb8_stmtf(sb, "},");
sb8_stmtf(sb, ".count = %d,", n->len);
sb->indent -= 1;
sb8_stmtf(sb, "};");
} else if (n->flags & set_bit(ast_flag_struct)) {
sb8_printf(sb, "type_t type__%S = { type_kind_struct, s8_const_lit(\"%S\"), sizeof(%S),", n->string, n->string, n->string);
sb->indent += 1;
sb8_stmtf(sb, ".members = (type_member_t[]){");
sb->indent += 1;
for (ast_t *it = n->first; it; it = it->next) {
s8_t name = it->string;
s8_t type_info = s8_serial_ast_type_to_type_info(sb->arena, it->first);
sb8_stmtf(sb, "{.name = s8_const_lit(\"%S\"), .type = &%S, .offset = offsetof(%S, %S)},", name, type_info, n->string, name);
}
sb->indent -= 1;
sb8_stmtf(sb, "},");
sb8_stmtf(sb, ".count = %d,", n->len);
sb->indent -= 1;
sb8_stmtf(sb, "};");
} else {
if (n->flags & set_bit(ast_flag_string)) {
sb8_printf(sb, "/*%S*/", n->string);
} else {
sb8_printf(sb, "/*null*/");
}
for (ast_t *it = n->first; it; it = it->next) {
sb8_indent(sb);
sb8_serial_ast_to_type_info(sb, it);
}
}
}
s8_t s8_serial_ast_to_type_info(ma_arena_t *arena, ast_t *n) {
sb8_t *sb = sb8_serial_begin(arena);
sb8_serial_ast_to_type_info(sb, n);
s8_t result = sb8_serial_end(sb);
return result;
}
//
//
//
int row_findi(ast_t *row, char *name) {
s8_t s = s8_from_char(name);
int i = 0;
for (ast_t *col = row->first; col; col = col->next) {
if (s8_equal(col->string, s)) {
return i;
}
i += 1;
}
return -1;
}
ast_t *row_geti(ast_t *row, int idx) {
if (idx == -1) return NULL;
int i = 0;
for (ast_t *col = row->first; col; col = col->next, i+=1) {
if (i == idx) return col;
}
return false;
}
void sb8_serial_table_enum(sb8_t *c, sb8_t *h, ast_t *table, s8_t decl) {
int name_idx = row_findi(table->first, "name");
int value_idx = row_findi(table->first, "value");
s8_t name_t = s8_fmt(c->arena, "%S_t", decl);
sb8_printf(h, "typedef enum {\n");
for (ast_t *row = table->first->next; row; row = row->next) {
s8_t name = row_geti(row, name_idx)->string;
ast_t *value = row_geti(row, value_idx);
sb8_printf(h, "%S_%S", decl, name);
if (value) sb8_printf(h, " = %S", value->string);
sb8_printf(h, ",\n");
}
sb8_printf(h, "%S_count,\n", decl);
sb8_printf(h, "} %S;\n", name_t);
sb8_stmtf(c, "type_t type__%S = { type_kind_enum, s8_const_lit(\"%S\"), sizeof(%S),", name_t, name_t, name_t);
c->indent += 1;
sb8_stmtf(c, ".members = (type_member_t[]){");
c->indent += 1;
int item_count = 0;
for (ast_t *row = table->first->next; row; row = row->next) {
s8_t name = row_geti(row, name_idx)->string;
ast_t *value = row_geti(row, value_idx);
sb8_stmtf(c, "{.name = s8_const_lit(\"%S_%S\"), .value = %S_%S},", decl, name, decl, name);
item_count += 1;
}
c->indent -= 1;
sb8_stmtf(c, "},");
sb8_stmtf(c, ".count = %d,", item_count);
c->indent -= 1;
sb8_stmtf(c, "};");
}
#define gen_c(arena) _gen_filename(arena, s8_lit(__FILE__), s8_lit("c"))
#define gen_h(arena) _gen_filename(arena, s8_lit(__FILE__), s8_lit("h"))
s8_t _gen_filename(ma_arena_t *arena, s8_t lit_file, s8_t ext) {
s8_t file_noext = s8_chop_last_period(s8_chop_last_period(lit_file));
s8_t file = s8_fmt(arena, "%S.gen.%S", file_noext, ext);
return file;
}

3
src/wasm_app/debug.c Normal file
View File

@@ -0,0 +1,3 @@
void dr2f64(r2f64_t r) {
debugf("[%f %f %f %f]", r.x0, r.y0, r.x1, r.y1);
}

19
src/wasm_app/main.c Normal file
View File

@@ -0,0 +1,19 @@
#include "core/core.h"
#include "core/core.c"
#include "app/app.h"
#include "app/app.c"
// #include "debug.c"
// #include "ui2.c"
void on_update() {
// r2f64_t rect = {0, 0, 200, 200};
// draw_rect(rect, (v4f32_t){0, 0, 0, 1});
// draw_textf((v2f64_t){10 + i, 100}, "time = %f, dt = %f", time_g / 1000, dt_g);
// f64_mod(4, 2);
// i += 1;
// if (i > 200) i = 0;
// ui_demo();
}

280
src/wasm_app/ui.c Normal file
View File

@@ -0,0 +1,280 @@
#if 0
typedef struct ui_id_t ui_id_t;
struct ui_id_t {
u64 value;
};
ui_id_t ui_string_to_id(const char *string) { // FNV HASH (1a?)
u8 *data8 = (u8 *)string;
u64 hash = (u64)14695981039346656037ULL;
for (u64 i = 0; data8[i]; i++) {
hash = hash ^ (u64)(data8[i]);
hash = hash * (u64)1099511628211ULL;
}
return (ui_id_t){ .value = hash };
}
#define ui_location_id() ui_string_to_id(FILE_AND_LINE)
ui_id_t ui_element_pressed;
typedef enum {
cut_left,
cut_right,
cut_bottom,
cut_top,
} cut_t;
typedef struct rcut_t rcut_t;
struct rcut_t {
r2f64_t *rect;
cut_t cut;
};
rcut_t rcut(r2f64_t *rect, cut_t cut) {
return (rcut_t){rect, cut};
}
r2f64_t ui_cut(r2f64_t *rect, f64 value, cut_t cut) {
if (cut == cut_left) return r2f64_cut_left(rect, value);
else if (cut == cut_right) return r2f64_cut_right(rect, value);
else if (cut == cut_bottom) return r2f64_cut_bottom(rect, value);
else if (cut == cut_top) return r2f64_cut_top(rect, value);
else assert(!"invalid codepath");
return (r2f64_t){0};
}
r2f64_t ui_cut2(rcut_t rc, f64 x, f64 y) {
f64 cut_value = 0;
if (rc.cut == cut_left || rc.cut == cut_right) cut_value = x;
else cut_value = y;
r2f64_t result = ui_cut(rc.rect, cut_value, rc.cut);
return result;
}
typedef struct ui_flags_t ui_flags_t;
struct ui_flags_t {
b32 draw_text : 1;
b32 text_centered : 1;
b32 text_y_centered;
b32 draw_rect : 1;
b32 checkable : 1;
b32 draw_checkbox : 1;
b32 draw_checked;
b32 clickable : 1;
b32 slider : 1;
};
typedef struct ui_signal_t ui_signal_t;
struct ui_signal_t {
b32 pressed : 1;
b32 overlapping : 1;
b32 interacting : 1;
};
// TODO(Karol): Don't use inputs as flags! Use only flags.
typedef struct ui_input_t ui_input_t;
struct ui_input_t {
char *title;
b32 *value_b32;
f64 *value_f64;
ui_id_t id;
};
v2f64_t style_padding = {50, 10};
ui_signal_t ui_widget(rcut_t rc, ui_input_t input, ui_flags_t flags) {
// Calculate rectangles
r2f64_t total_rect = {0};
r2f64_t rect = {0};
r2f64_t checkbox_rect = {0};
{
v2f64_t size = style_padding;
f64 font_height = get_font_height();
size.y += font_height;
if (flags.draw_text) {
size.x += measure_text(input.title);
}
total_rect = ui_cut2(rc, size.x, size.y);
rect = total_rect;
if (flags.draw_checkbox) {
checkbox_rect = r2f64_cut_left(&rect, size.y);
}
}
// Solve interactions
ui_signal_t result = {0};
{
if (r2f64_contains(total_rect, mouse_pos_g)) {
result.overlapping = true;
if (mouse_button_press_g[app_mouse_button_left]) {
ui_element_pressed = input.id;
result.pressed = true;
}
}
if (ui_element_pressed.value == input.id.value && mouse_button_down_g[app_mouse_button_left]) {
result.interacting = true;
}
if (flags.checkable && result.pressed) {
*input.value_b32 = !*input.value_b32;
}
if (flags.slider && result.interacting) {
f64 mouse_pos = mouse_pos_g.x;
v2f64_t rect_size = r2f64_get_size(rect);
*input.value_f64 = (mouse_pos - rect.min.x) / rect_size.x;
*input.value_f64 = CLAMP(*input.value_f64, 0, 1.0);
}
}
clip(total_rect);
// Draw
if (flags.draw_rect) {
v4f32_t color = primary_color_global;
if (flags.clickable) {
if (result.overlapping) color = secondary_color_global;
if (flags.draw_checked && input.value_b32[0]) color = accent1_color_global;
}
draw_rect(rect, color);
}
if (flags.slider) {
v2f64_t rect_size = r2f64_get_size(rect);
r2f64_t rect_split = r2f64_get_left(&rect, rect_size.x * input.value_f64[0]);
draw_rect(rect_split, accent1_color_global);
}
if (flags.draw_text) {
v2f64_t text_pos = rect.min;
f64 text_width = measure_text(input.title);
f64 font_height = get_font_height();
v2f64_t rect_size = r2f64_get_size(rect);
v2f64_t offset_to_center = {(rect_size.x - text_width) / 2, (rect_size.y - font_height) / 2};
if (flags.text_y_centered) {
text_pos.y += offset_to_center.y;
}
if (flags.text_centered) {
text_pos = v2f64_add(text_pos, offset_to_center);
}
draw_text(text_pos, input.title);
}
if (flags.draw_checkbox) {
v4f32_t color = accent1_color_global;
if (flags.checkable) {
if (input.value_b32[0]) {
color = accent2_color_global;
}
}
if ((flags.checkable || flags.clickable) && result.overlapping) {
color = v4f32_lerp(color, v4f32(1,1,1,1), 0.25);
}
draw_rect(checkbox_rect, color);
}
clip(r2f64(-1000, -1000, 1000000, 1000000));
return result;
}
b32 ui_button(rcut_t rc, char *title) {
ui_signal_t sig = ui_widget(rc, (ui_input_t){.title = title}, (ui_flags_t){.draw_text = true, .text_centered = true, .draw_rect = true, .clickable = true});
return sig.pressed;
}
b32 ui_checked_button(b32 *value, rcut_t rc, char *title) {
ui_widget(rc, (ui_input_t){.title = title, .value_b32 = value}, (ui_flags_t){.draw_rect = true, .draw_text = true, .text_centered = true, .clickable = true, .checkable = true, .draw_checked = true});
return *value;
}
b32 ui_checkbox(rcut_t rc, b32 *value, char *title) {
ui_widget(rc, (ui_input_t){.value_b32 = value, .title = title}, (ui_flags_t){.draw_checkbox = true, .draw_text = true, .text_y_centered = true, .draw_rect = true, .checkable = true});
return *value;
}
void ui_label(rcut_t rc, char *title) {
ui_widget(rc, (ui_input_t){.title = title}, (ui_flags_t){.draw_text = true, .text_centered = true, .draw_rect = true});
}
void ui_slider(rcut_t rc, ui_id_t id, f64 *value, char *title) {
ui_widget(rc, (ui_input_t){.title = title, .value_f64 = value, .id = id}, (ui_flags_t){.draw_text = true, .text_centered = true, .slider = true, .draw_rect = true, .clickable = true});
}
void ui_begin_frame(void) {
if (mouse_button_release_g[app_mouse_button_left]) {
ui_element_pressed = (ui_id_t){0};
}
}
void ui_demo(void) {
ui_begin_frame();
f64 font_height = get_font_height();
r2f64_t window_rect = r2f64(0, 0, window_size_g.x, window_size_g.y);
{
draw_rect(window_rect, while_color_global);
}
static b32 panel_open = true;
static b32 cool_rect = false;
{
r2f64_t top_rect = r2f64_cut_top(&window_rect, font_height*2);
draw_rect(top_rect, primary_color_global);
if (ui_checked_button(&cool_rect, rcut(&top_rect, cut_left), "file")) {
draw_rect(window_rect, v4f32(0.5, 0.1, 0.1, 1.0));
}
if (ui_button(rcut(&top_rect, cut_left), "edit")) {}
if (ui_button(rcut(&top_rect, cut_left), "view")) {}
if (ui_checked_button(&panel_open, rcut(&top_rect, cut_left), "open panel")) {
}
}
if (panel_open) {
r2f64_t panel_rect = r2f64_cut_left(&window_rect, measure_text("1234567890")*2);
{
v4f32_t color = primary_color_global; color.a = 0.3f;
draw_rect(panel_rect, color);
}
static f64 value = 0.2f;
ui_slider(rcut(&panel_rect, cut_top), ui_location_id(), &value, "value");
ui_widget(rcut(&panel_rect, cut_top), (ui_input_t){.title = "non centered label"}, (ui_flags_t){.draw_rect = true, .draw_text = true});
static b32 checkbox_memes;
ui_checkbox(rcut(&panel_rect, cut_top), &checkbox_memes, "checkbox");
// TODO(Krzosa): Draw arrows / triangles
{
f64 font_height = get_font_height();
f64 cut_size = font_height + style_padding.y;
r2f64_t rect = r2f64_cut_top(&panel_rect, cut_size);
static int counter;
if (ui_widget(rcut(&rect, cut_left), (ui_input_t){0}, (ui_flags_t){.draw_checkbox = true, .clickable = true}).pressed) {
counter -= 1;
}
char buff[256];
stbsp_snprintf(buff, sizeof(buff), "counter: %d", counter);
ui_label(rcut(&rect, cut_left), buff);
if (ui_widget(rcut(&rect, cut_left), (ui_input_t){0}, (ui_flags_t){.draw_checkbox = true, .clickable = true}).pressed) {
counter += 1;
}
}
}
}
#endif

241
src/wasm_app/ui2.c Normal file
View File

@@ -0,0 +1,241 @@
v2f64_t ui_calc_text_pos(r2f64_t rect, char *title) {
f64 font_height = get_font_height();
f64 text_width = measure_text(title);
v2f64_t text_pos = rect.min;
{
v2f64_t rect_size = r2f64_get_size(rect);
v2f64_t offset_to_center = {(rect_size.x - text_width) / 2, (rect_size.y - font_height) / 2};
text_pos = v2f64_add(text_pos, offset_to_center);
}
return text_pos;
}
typedef struct ui_signal_t ui_signal_t;
struct ui_signal_t {
b8 pressed;
b8 overlapping;
};
ui_signal_t ui_interact(r2f64_t rect) {
ui_signal_t sig = {0};
if (r2f64_contains(rect, mouse_pos_g)) {
sig.overlapping = true;
if (mouse_button_press_g[app_mouse_button_left]) {
sig.pressed = true;
}
}
return sig;
}
b32 ui_button(r2f64_t rect, char *title) {
v2f64_t text_pos = ui_calc_text_pos(rect, title);
ui_signal_t sig = ui_interact(rect);
v4f32_t rect_color = secondary_color_global;
v4f32_t text_color = black_color_global;
if (sig.overlapping) {
rect_color = primary_color_global;
}
clip(rect);
draw_rect(rect, rect_color);
draw_text(text_pos, text_color, title, str_len(title));
clip(r2f64(-1000, -1000, 1000000, 1000000));
return sig.pressed;
}
b32 ui_checkbox(r2f64_t rect, b32 *value, char *title) {
v2f64_t text_pos = ui_calc_text_pos(rect, title);
ui_signal_t sig = ui_interact(rect);
if (sig.pressed) *value = !*value;
v4f32_t rect_color = secondary_color_global;
v4f32_t text_color = black_color_global;
if (sig.overlapping) {
rect_color = primary_color_global;
}
if (*value) {
rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.5);
}
clip(rect);
draw_rect(rect, rect_color);
draw_text(text_pos, text_color, title, str_len(title));
clip(r2f64(-1000, -1000, 1000000, 1000000));
return *value;
}
typedef struct ui_id_t ui_id_t;
struct ui_id_t { u64 value; };
ui_id_t ui_string_to_id(const char *string, i32 len) { // FNV HASH (1a?)
u8 *data8 = (u8 *)string;
u64 hash = (u64)14695981039346656037ULL;
for (u64 i = 0; i < len; i++) {
hash = hash ^ (u64)(data8[i]);
hash = hash * (u64)1099511628211ULL;
}
return (ui_id_t){ .value = hash };
}
#define ui_location_id() ui_string_to_id(FILE_AND_LINE, sizeof(FILE_AND_LINE) - 1)
ui_id_t ui_active_element = {0};
void ui_slider(r2f64_t rect, ui_id_t id, f64 *value, char *title) {
v2f64_t text_pos = ui_calc_text_pos(rect, title);
ui_signal_t sig = ui_interact(rect);
b32 interacting = false;
{
if (sig.pressed) {
ui_active_element = id;
}
if (id.value == ui_active_element.value && mouse_button_down_g[app_mouse_button_left]) {
interacting = true;
}
}
if (interacting) {
f64 mouse_pos = mouse_pos_g.x;
v2f64_t rect_size = r2f64_get_size(rect);
*value = (mouse_pos - rect.min.x) / rect_size.x;
*value = CLAMP(*value, 0, 1.0);
}
v2f64_t rect_size = r2f64_get_size(rect);
r2f64_t slider_rect = r2f64_get_left(&rect, rect_size.x * value[0]);
v4f32_t rect_color = secondary_color_global;
if (sig.overlapping) rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.2);
v4f32_t slider_color = accent2_color_global;
if (sig.overlapping) slider_color = v4f32_lerp(slider_color, accent2_color_global, 0.2);
v4f32_t text_color = black_color_global;
clip(rect);
draw_rect(rect, rect_color);
draw_rect(slider_rect, slider_color);
draw_text(text_pos, text_color, title, str_len(title));
clip(r2f64(-1000, -1000, 1000000, 1000000));
}
typedef struct ui_input_state ui_input_state;
struct ui_input_state {
char *buff;
int len;
int cap;
int cursor;
};
void ui_input_text(r2f64_t rect, ui_input_state *in) {
v2f64_t tp = ui_calc_text_pos(rect, "a");
v2f64_t text_pos = {rect.min.x, tp.y};
ui_signal_t sig = ui_interact(rect);
v4f32_t rect_color = secondary_color_global;
if (r2f64_contains(rect, mouse_pos_g)) {
if (key_press_g == app_key_right) in->cursor += 1;
if (key_press_g == app_key_left) in->cursor -= 1;
if (key_press_g == app_key_backspace) {
debugf("a");
}
in->cursor = CLAMP(in->cursor, 0, in->len);
if (sig.overlapping) rect_color = v4f32_lerp(rect_color, accent2_color_global, 0.2);
}
clip(rect);
draw_rect(rect, rect_color);
draw_text(text_pos, black_color_global, in->buff, in->len);
clip(r2f64(-1000, -1000, 1000000, 1000000));
f64 cx = measure_text_ex(in->buff, in->cursor);
v2f64_t cursor_pos = {text_pos.x + cx, text_pos.y};
draw_rect(r2f64_center_halfdim(cursor_pos, v2f64(1, 6)), black_color_global);
}
void ui_demo(void) {
if (mouse_button_release_g[app_mouse_button_left]) {
ui_active_element = (ui_id_t){0};
}
r2f64_t window_rect = (r2f64_t){(v2f64_t){0}, window_size_g};
r2f64_t top_bar_rect = r2f64_cut_top(&window_rect, get_font_height() + 20);
draw_rect(window_rect, primary_color_global);
f64 padding = 50;
draw_rect(top_bar_rect, secondary_color_global);
static b32 open_file_panel;
f64 open_file_panel_xsize = 0;
{
// ▼▲▶◀
char *title = "▶ file";
if (open_file_panel) title = "▼ file";
open_file_panel_xsize = measure_text(title) + padding*2;
r2f64_t rect = r2f64_cut_left(&top_bar_rect, open_file_panel_xsize);
if (ui_checkbox(rect, &open_file_panel, title)) {
}
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
draw_rect(gap_rect, black_color_global);
}
if (open_file_panel) {
f64 item_count = 20;
f64 item_size = get_font_height() + 20;
r2f64_t panel_rect = r2f64_get_top(&window_rect, item_count * item_size);
panel_rect = r2f64_get_left(&panel_rect, open_file_panel_xsize);
{
static f64 slider_value;
char buff[64];
stbsp_snprintf(buff, sizeof(buff), "%f", slider_value);
r2f64_t rect = r2f64_cut_top(&panel_rect, item_size);
ui_slider(rect, ui_location_id(), &slider_value, buff);
}
{
static char buff[64];
static ui_input_state input;
if (input.buff == NULL) {
input.buff = buff;
input.cap = sizeof(buff);
}
r2f64_t rect = r2f64_cut_top(&panel_rect, item_size);
ui_input_text(rect, &input);
}
}
{
char *title = "edit";
r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2);
if (ui_button(rect, title)) {
}
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
draw_rect(gap_rect, black_color_global);
}
{
char *title = "view";
r2f64_t rect = r2f64_cut_left(&top_bar_rect, measure_text(title) + padding*2);
if (ui_button(rect, title)) {
}
r2f64_t gap_rect = r2f64_cut_left(&top_bar_rect, 1);
draw_rect(gap_rect, black_color_global);
}
if (input_text_len_g) {
debugf("%.*s", input_text_len_g, input_text_g);
}
}

23
todo.txt Normal file
View File

@@ -0,0 +1,23 @@
platform
more then 2 platform abstraction
app platform game
in the future event based?
or maybe hybrid?
os functionality
gfx
w32
canvas
dll hot reload
wasm:
input and key down (use KeyA KeyB etc.)
type_info:
serialize
deserialize
app
loop styles:
infinite loop update -> gather all events -> loop event and update -> render (vsync wait) + block when no events
update (render) + other events (don't render) + block when no events