diff --git a/build.bat b/build.bat index 8e84a71..a1cd857 100644 --- a/build.bat +++ b/build.bat @@ -45,6 +45,11 @@ if %target% == orca ( --guest-include graphics.h^ --wasm3-bindings src\canvas_api_bind_gen.c + python3 scripts\bindgen2.py clock src\clock_api.json^ + --guest-stubs sdk\orca_clock.c^ + --guest-include platform_clock.h^ + --wasm3-bindings src\clock_api_bind_gen.c + python3 scripts\bindgen2.py io^ src\io_api.json^ --guest-stubs sdk\io_stubs.c^ diff --git a/build.sh b/build.sh index ee208de..6b2f2b2 100755 --- a/build.sh +++ b/build.sh @@ -67,6 +67,12 @@ elif [ $target = orca ] ; then --guest-include graphics.h \ --wasm3-bindings ./src/canvas_api_bind_gen.c + python3 ./scripts/bindgen2.py clock \ + src/clock_api.json \ + --guest-stubs sdk/orca_clock.c \ + --guest-include platform_clock.h \ + --wasm3-bindings ./src/clock_api_bind_gen.c + python3 ./scripts/bindgen2.py io \ src/io_api.json \ --guest-stubs sdk/io_stubs.c \ diff --git a/samples/pong/.gitignore b/samples/pong/.gitignore index def138d..0742738 100644 --- a/samples/pong/.gitignore +++ b/samples/pong/.gitignore @@ -1,3 +1,3 @@ +Pong profile.dtrace profile.spall - diff --git a/samples/pong/build.sh b/samples/pong/build.sh index cf8ee84..c941ae0 100755 --- a/samples/pong/build.sh +++ b/samples/pong/build.sh @@ -26,7 +26,7 @@ wasmFlags="--target=wasm32 \ -D__ORCA__ \ -I $STDLIB_DIR/include \ -I $ORCA_SDK_DIR \ - -I $MILEPOST_DIR/ext -I $MILEPOST_DIR -I $MILEPOST_DIR/src -I $MILEPOST_DIR/src/util -I $MILEPOST_DIR/src/platform" + -I $MILEPOST_DIR/ext -I $MILEPOST_DIR -I $MILEPOST_DIR/src" $CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c diff --git a/samples/ui/.gitignore b/samples/ui/.gitignore new file mode 100644 index 0000000..f599d5c --- /dev/null +++ b/samples/ui/.gitignore @@ -0,0 +1 @@ +UI \ No newline at end of file diff --git a/samples/ui/build.bat b/samples/ui/build.bat new file mode 100644 index 0000000..768432c --- /dev/null +++ b/samples/ui/build.bat @@ -0,0 +1,17 @@ +@echo off + +:: compile wasm module +set wasmFlags=--target=wasm32^ + --no-standard-libraries ^ + -fno-builtin ^ + -Wl,--no-entry ^ + -Wl,--export-dynamic ^ + -g ^ + -O2 ^ + -mbulk-memory ^ + -D__ORCA__ ^ + -isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src + +clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c + +python3 ..\..\scripts\mkapp.py --orca-dir ..\.. --name UI --resource-dir data module.wasm diff --git a/samples/ui/build.sh b/samples/ui/build.sh new file mode 100644 index 0000000..937eb18 --- /dev/null +++ b/samples/ui/build.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +set -euo pipefail + +if [[ -x /usr/local/opt/llvm/bin/clang ]]; then + CLANG=/usr/local/opt/llvm/bin/clang +elif [[ -x /opt/homebrew/opt/llvm/bin/clang ]]; then + CLANG=/opt/homebrew/opt/llvm/bin/clang +else + echo "Could not find Homebrew clang; this script will probably not work." + CLANG=clang +fi + +wasmFlags="--target=wasm32 \ + --no-standard-libraries \ + -fno-builtin \ + -Wl,--no-entry \ + -Wl,--export-dynamic \ + -g \ + -O2 \ + -mbulk-memory \ + -D__ORCA__ \ + -isystem ../../cstdlib/include -I ../../sdk -I../../milepost/ext -I ../../milepost -I ../../milepost/src" + +$CLANG $wasmFlags -o ./module.wasm ../../sdk/orca.c ../../cstdlib/src/*.c src/main.c + +python3 ../../scripts/mkapp.py --orca-dir ../.. --name UI --resource-dir data module.wasm diff --git a/samples/ui/data/OpenSansLatinSubset.ttf b/samples/ui/data/OpenSansLatinSubset.ttf new file mode 100644 index 0000000..acfe2d8 Binary files /dev/null and b/samples/ui/data/OpenSansLatinSubset.ttf differ diff --git a/samples/ui/src/main.c b/samples/ui/src/main.c new file mode 100644 index 0000000..301280a --- /dev/null +++ b/samples/ui/src/main.c @@ -0,0 +1,407 @@ +#include"keys.h" +#include"graphics.h" +#include"ui.h" + +#include"orca.h" + +vec2 frameSize = {100, 100}; + +mg_surface surface; +mg_canvas canvas; +mg_font font; +ui_context ui; +mem_arena textArena = {0}; + +mg_surface mg_surface_main(void); + +ORCA_EXPORT void OnInit(void) +{ + //TODO create surface for main window + surface = mg_surface_main(); + canvas = mg_canvas_create(); + ui_init(&ui); + + //NOTE: load font + { + file_handle file = file_open(STR8("/OpenSansLatinSubset.ttf"), FILE_ACCESS_READ, 0); + if(file_last_error(file) != IO_OK) + { + log_error("Couldn't open file OpenSansLatinSubset.ttf\n"); + } + u64 size = file_size(file); + char* buffer = mem_arena_alloc(mem_scratch(), size); + file_read(file, size, buffer); + file_close(file); + unicode_range ranges[5] = {UNICODE_RANGE_BASIC_LATIN, + UNICODE_RANGE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT, + UNICODE_RANGE_LATIN_EXTENDED_A, + UNICODE_RANGE_LATIN_EXTENDED_B, + UNICODE_RANGE_SPECIALS}; + // TODO: Decide whether we're using strings or explicit pointer + length + font = mg_font_create_from_memory(size, (byte*)buffer, 5, ranges); + } + + mem_arena_clear(mem_scratch()); + mem_arena_init(&textArena); +} + +ORCA_EXPORT void OnFrameResize(u32 width, u32 height) +{ + log_info("frame resize %u, %u", width, height); + frameSize.x = width; + frameSize.y = height; +} + +ORCA_EXPORT void OnRawEvent(mp_event *event) +{ + ui_process_event(event); +} + +void widget_begin_view(char* str) +{ + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_Y, + .layout.spacing = 10, + .layout.margin.x = 10, + .layout.margin.y = 10, + .layout.align.x = UI_ALIGN_CENTER, + .layout.align.y = UI_ALIGN_START}, + UI_STYLE_LAYOUT); + + ui_box_begin(str, UI_FLAG_DRAW_BORDER); + ui_label(str); + +} + +void widget_end_view(void) +{ + ui_box_end(); +} + +#define widget_view(s) defer_loop(widget_begin_view(s), widget_end_view()) + +ORCA_EXPORT void OnFrameRefresh(void) +{ + ui_style defaultStyle = {.bgColor = {0}, + .color = {1, 1, 1, 1}, + .font = font, + .fontSize = 16, + .borderColor = {0.278, 0.333, 0.412, 1}, + .borderSize = 2}; + + ui_style_mask defaultMask = UI_STYLE_BG_COLOR + | UI_STYLE_COLOR + | UI_STYLE_BORDER_COLOR + | UI_STYLE_BORDER_SIZE + | UI_STYLE_FONT + | UI_STYLE_FONT_SIZE; + + ui_frame(frameSize, &defaultStyle, defaultMask) + { + ui_style_match_before(ui_pattern_all(), &defaultStyle, defaultMask); + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 1}, + .layout.axis = UI_AXIS_Y, + .layout.align.x = UI_ALIGN_CENTER, + .layout.align.y = UI_ALIGN_START, + .layout.spacing = 10, + .layout.margin.x = 10, + .layout.margin.y = 10, + .bgColor = {0.11, 0.11, 0.11, 1}}, + UI_STYLE_SIZE + | UI_STYLE_LAYOUT + | UI_STYLE_BG_COLOR); + + ui_container("background", UI_FLAG_DRAW_BACKGROUND) + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_CHILDREN}, + .layout.align.x = UI_ALIGN_CENTER}, + UI_STYLE_SIZE + |UI_STYLE_LAYOUT_ALIGN_X); + ui_container("title", 0) + { + ui_style_next(&(ui_style){.fontSize = 26}, UI_STYLE_FONT_SIZE); + ui_label("Orca UI Demo"); + + if(ui_box_sig(ui_box_top()).hovering) + { + ui_tooltip("tooltip") + { + ui_style_next(&(ui_style){.bgColor = {1, 0.99, 0.82, 1}}, + UI_STYLE_BG_COLOR); + + ui_container("background", UI_FLAG_DRAW_BACKGROUND) + { + ui_style_next(&(ui_style){.color = {0, 0, 0, 1}}, + UI_STYLE_COLOR); + + ui_label("That is a tooltip!"); + } + } + } + } + + ui_menu_bar("Menu bar") + { + ui_menu("Menu 1") + { + if(ui_menu_button("Option 1.1").pressed) + { + log_info("Pressed option 1.1\n"); + } + ui_menu_button("Option 1.2"); + ui_menu_button("Option 1.3"); + ui_menu_button("Option 1.4"); + } + + ui_menu("Menu 2") + { + ui_menu_button("Option 2.1"); + ui_menu_button("Option 2.2"); + ui_menu_button("Option 2.3"); + ui_menu_button("Option 2.4"); + } + + ui_menu("Menu 3") + { + ui_menu_button("Option 3.1"); + ui_menu_button("Option 3.2"); + ui_menu_button("Option 3.3"); + ui_menu_button("Option 3.4"); + } + } + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 1, 1}}, + UI_STYLE_SIZE); + + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, UI_STYLE_LAYOUT_AXIS); + ui_container("contents", 0) + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, + .size.height = {UI_SIZE_PARENT, 1}}, + UI_STYLE_SIZE); + + ui_container("left", 0) + { + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X, + .layout.spacing = 10, + .layout.margin.x = 10, + .layout.margin.y = 10, + .size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.5}}, + UI_STYLE_LAYOUT_AXIS + |UI_STYLE_LAYOUT_SPACING + |UI_STYLE_LAYOUT_MARGIN_X + |UI_STYLE_LAYOUT_MARGIN_Y + |UI_STYLE_SIZE); + + ui_container("up", 0) + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, + .size.height = {UI_SIZE_PARENT, 1}}, + UI_STYLE_SIZE); + widget_view("Buttons") + { + if(ui_button("Button A").clicked) + { + log_info("A clicked"); + } + + if(ui_button("Button B").clicked) + { + log_info("B clicked"); + } + + if(ui_button("Button C").clicked) + { + log_info("C clicked"); + } + } + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, + .size.height = {UI_SIZE_PARENT, 1}}, + UI_STYLE_SIZE); + + + ui_pattern pattern = {0}; + ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TAG, .tag = ui_tag_make("checkbox")}); + ui_style_match_after(pattern, + &(ui_style){.bgColor = {0, 1, 0, 1}, + .color = {1, 1, 1, 1}}, + UI_STYLE_COLOR | UI_STYLE_BG_COLOR); + + widget_view("checkboxes") + { + static bool check1 = true; + static bool check2 = false; + static bool check3 = false; + + ui_checkbox("check1", &check1); + ui_checkbox("check2", &check2); + ui_checkbox("check3", &check3); + } + } + + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X, + .size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.5}}, + UI_STYLE_LAYOUT_AXIS + |UI_STYLE_SIZE); + + ui_container("down", 0) + { + widget_view("Vertical Sliders") + { + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X, + .layout.spacing = 10}, + UI_STYLE_LAYOUT_AXIS + |UI_STYLE_LAYOUT_SPACING); + ui_container("contents", 0) + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20}, + .size.height = {UI_SIZE_PIXELS, 200}}, + UI_STYLE_SIZE); + static f32 slider1 = 0; + ui_slider("slider1", 0.2, &slider1); + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20}, + .size.height = {UI_SIZE_PIXELS, 200}}, + UI_STYLE_SIZE); + static f32 slider2 = 0; + ui_slider("slider2", 0.2, &slider2); + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 20}, + .size.height = {UI_SIZE_PIXELS, 200}}, + UI_STYLE_SIZE); + static f32 slider3 = 0; + ui_slider("slider3", 0.2, &slider3); + } + } + + widget_view("Horizontal Sliders") + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200}, + .size.height = {UI_SIZE_PIXELS, 20}}, + UI_STYLE_SIZE); + static f32 slider1 = 0; + ui_slider("slider1", 0.2, &slider1); + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200}, + .size.height = {UI_SIZE_PIXELS, 20}}, + UI_STYLE_SIZE); + static f32 slider2 = 0; + ui_slider("slider2", 0.2, &slider2); + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 200}, + .size.height = {UI_SIZE_PIXELS, 20}}, + UI_STYLE_SIZE); + static f32 slider3 = 0; + ui_slider("slider3", 0.2, &slider3); + } + } + } + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 0.5}, + .size.height = {UI_SIZE_PARENT, 1}}, + UI_STYLE_SIZE); + + ui_container("right", 0) + { + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.33}}, + UI_STYLE_SIZE); + widget_view("Text box") + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PIXELS, 300}, + .size.height = {UI_SIZE_TEXT}}, + UI_STYLE_SIZE); + static str8 text = {0}; + ui_text_box_result res = ui_text_box("textbox", mem_scratch(), text); + if(res.changed) + { + mem_arena_clear(&textArena); + text = str8_push_copy(&textArena, res.text); + } + } + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.33}}, + UI_STYLE_SIZE); + widget_view("Test") + { + ui_pattern pattern = {0}; + ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("panel")}); + ui_style_match_after(pattern, &(ui_style){.bgColor = {0.3, 0.3, 1, 1}}, UI_STYLE_BG_COLOR); + + static int selected = 0; + str8 options[] = {STR8("option 1"), + STR8("option 2"), + STR8("long option 3"), + STR8("option 4"), + STR8("option 5")}; + ui_select_popup_info info = {.selectedIndex = selected, + .optionCount = 5, + .options = options}; + + ui_select_popup_info result = ui_select_popup("popup", &info); + selected = result.selectedIndex; + } + + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.33}}, + UI_STYLE_SIZE); + widget_view("Color") + { + ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1}, + .size.height = {UI_SIZE_PARENT, 0.7}, + .layout.axis = UI_AXIS_X}, + UI_STYLE_SIZE + |UI_STYLE_LAYOUT_AXIS); + + ui_panel("Panel", UI_FLAG_DRAW_BORDER) + { + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X}, + UI_STYLE_LAYOUT_AXIS); + ui_container("contents", 0) + { + ui_style_next(&(ui_style){.layout.spacing = 20}, + UI_STYLE_LAYOUT_SPACING); + ui_container("buttons", 0) + { + ui_button("Button A"); + ui_button("Button B"); + ui_button("Button C"); + ui_button("Button D"); + } + + ui_style_next(&(ui_style){.layout.axis = UI_AXIS_X, + .layout.spacing = 20}, + UI_STYLE_LAYOUT_SPACING + |UI_STYLE_LAYOUT_AXIS); + + ui_container("buttons2", 0) + { + ui_button("Button A"); + ui_button("Button B"); + ui_button("Button C"); + ui_button("Button D"); + } + } + } + } + + } + } + } + } + + + mg_canvas_set_current(canvas); + mg_surface_prepare(surface); + ui_draw(); + mg_render(surface, canvas); + mg_surface_present(surface); +} diff --git a/scripts/bindgen2.py b/scripts/bindgen2.py index ea956a7..48baa0e 100644 --- a/scripts/bindgen2.py +++ b/scripts/bindgen2.py @@ -124,7 +124,7 @@ for decl in data: s += '*((i64*)&_sp[0]) = ' elif retTag == 'f': s += '*((f32*)&_sp[0]) = ' - elif retTag == 'd': + elif retTag == 'F': s += '*((f64*)&_sp[0]) = ' elif retTag == 'S': retTypeName = decl['ret']['name'] @@ -147,7 +147,7 @@ for decl in data: s += '*(i64*)&_sp[' + str(firstArgIndex + i) + ']' elif argTag == 'f': s += '*(f32*)&_sp[' + str(firstArgIndex + i) + ']' - elif argTag == 'd': + elif argTag == 'F': s += '*(f64*)&_sp[' + str(firstArgIndex + i) + ']' elif argTag == 'p': s += '(void*)((char*)_mem + *(i32*)&_sp[' + str(firstArgIndex + i) + '])' diff --git a/sdk/orca.c b/sdk/orca.c index 4e8ae5f..c92ab81 100644 --- a/sdk/orca.c +++ b/sdk/orca.c @@ -6,17 +6,22 @@ * *****************************************************************/ +#include"platform/orca_clock.c" #include"platform/orca_memory.c" #include"platform/orca_malloc.c" #include"platform/orca_strings.c" #include"platform/orca_log.c" #include"platform/platform_io_common.c" +#include"util/hash.c" #include"util/memory.c" #include"util/strings.c" #include"util/utf8.c" #include"graphics_common.c" +#include"input_state.c" +#include"orca_exports.c" #include"orca_surface.c" +#include"ui.c" #include"io_stubs.c" diff --git a/sdk/orca.h b/sdk/orca.h index 9f7e8e5..a093c2d 100644 --- a/sdk/orca.h +++ b/sdk/orca.h @@ -16,6 +16,7 @@ #include"platform/platform.h" #include"platform/platform_log.h" #include"platform/platform_assert.h" +#include"platform/platform_clock.h" #include"platform/platform_io.h" #if COMPILER_CLANG diff --git a/sdk/orca_exports.c b/sdk/orca_exports.c new file mode 100644 index 0000000..6f0c477 --- /dev/null +++ b/sdk/orca_exports.c @@ -0,0 +1,3 @@ +#include"orca.h" + +ORCA_EXPORT mp_event _OrcaRawEvent; diff --git a/src/clock_api.json b/src/clock_api.json new file mode 100644 index 0000000..0456c08 --- /dev/null +++ b/src/clock_api.json @@ -0,0 +1,9 @@ +[ +{ + "name": "mp_get_time", + "cname": "mp_get_time", + "ret": {"name": "time", "tag": "F"}, + "args": [ {"name": "clock", + "type": {"name": "mp_clock_kind", "tag": "i"}}] +} +] diff --git a/src/main.c b/src/main.c index e236f53..de6a055 100644 --- a/src/main.c +++ b/src/main.c @@ -300,6 +300,7 @@ void orca_runtime_init(orca_runtime* runtime) #include"bindgen_core_api.c" #include"canvas_api_bind.c" +#include"clock_api_bind_gen.c" #include"io_api_bind_gen.c" #include"bindgen_gles_api.c" @@ -356,6 +357,7 @@ void* orca_runloop(void* user) //NOTE: bind orca APIs bindgen_link_core_api(app->runtime.m3Module); bindgen_link_canvas_api(app->runtime.m3Module); + bindgen_link_clock_api(app->runtime.m3Module); bindgen_link_io_api(app->runtime.m3Module); bindgen_link_gles_api(app->runtime.m3Module); manual_link_gles_api(app->runtime.m3Module); @@ -380,9 +382,9 @@ void* orca_runloop(void* user) } //NOTE: Find and type check event handlers. - for(int i=0; iruntime.m3Runtime, desc->name.ptr); @@ -425,7 +427,7 @@ void* orca_runloop(void* user) if(checked) { - app->runtime.eventHandlers[i] = handler; + app->runtime.exports[i] = handler; } else { @@ -434,6 +436,10 @@ void* orca_runloop(void* user) } } + //NOTE: get location of the raw event slot + IM3Global rawEventGlobal = m3_FindGlobal(app->runtime.m3Module, "_OrcaRawEvent"); + app->runtime.rawEventOffset = (u32)rawEventGlobal->intValue; + //NOTE: preopen the app local root dir { str8 localRootPath = path_executable_relative(mem_scratch(), STR8("../app/data")); @@ -449,12 +455,12 @@ void* orca_runloop(void* user) //NOTE: prepare GL surface mg_surface_prepare(app->surface); - IM3Function* eventHandlers = app->runtime.eventHandlers; + IM3Function* exports = app->runtime.exports; //NOTE: call init handler - if(eventHandlers[G_EVENT_START]) + if(exports[G_EXPORT_ON_INIT]) { - M3Result err = m3_Call(eventHandlers[G_EVENT_START], 0, 0); + M3Result err = m3_Call(exports[G_EXPORT_ON_INIT], 0, 0); if(err != NULL) { log_error("runtime error: %s\n", err); @@ -471,13 +477,13 @@ void* orca_runloop(void* user) } } - if(eventHandlers[G_EVENT_FRAME_RESIZE]) + if(exports[G_EXPORT_FRAME_RESIZE]) { mp_rect frame = mg_surface_get_frame(app->surface); u32 width = (u32)frame.w; u32 height = (u32)frame.h; const void* args[2] = {&width, &height}; - m3_Call(eventHandlers[G_EVENT_FRAME_RESIZE], 2, args); + m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args); } ui_set_context(&app->debugOverlay.ui); @@ -493,6 +499,19 @@ void* orca_runloop(void* user) ui_process_event(event); } + if(exports[G_EXPORT_RAW_EVENT]) + { + #ifndef M3_BIG_ENDIAN + mp_event* eventPtr = (mp_event*)wasm_memory_offset_to_ptr(&app->runtime.wasmMemory, app->runtime.rawEventOffset); + memcpy(eventPtr, event, sizeof(*event)); + + const void* args[1] = {&app->runtime.rawEventOffset}; + m3_Call(exports[G_EXPORT_RAW_EVENT], 1, args); + #else + log_error("OnRawEvent() is not supported on big endian platforms"); + #endif + } + switch(event->type) { case MP_EVENT_WINDOW_CLOSE: @@ -507,12 +526,12 @@ void* orca_runloop(void* user) // mg_surface_set_frame(app->debugOverlay.surface, frame); - if(eventHandlers[G_EVENT_FRAME_RESIZE]) + if(exports[G_EXPORT_FRAME_RESIZE]) { u32 width = (u32)event->frame.rect.w; u32 height = (u32)event->frame.rect.h; const void* args[2] = {&width, &height}; - m3_Call(eventHandlers[G_EVENT_FRAME_RESIZE], 2, args); + m3_Call(exports[G_EXPORT_FRAME_RESIZE], 2, args); } } break; @@ -520,30 +539,30 @@ void* orca_runloop(void* user) { if(event->key.action == MP_KEY_PRESS) { - if(eventHandlers[G_EVENT_MOUSE_DOWN]) + if(exports[G_EXPORT_MOUSE_DOWN]) { int key = event->key.code; const void* args[1] = {&key}; - m3_Call(eventHandlers[G_EVENT_MOUSE_DOWN], 1, args); + m3_Call(exports[G_EXPORT_MOUSE_DOWN], 1, args); } } else { - if(eventHandlers[G_EVENT_MOUSE_UP]) + if(exports[G_EXPORT_MOUSE_UP]) { int key = event->key.code; const void* args[1] = {&key}; - m3_Call(eventHandlers[G_EVENT_MOUSE_UP], 1, args); + m3_Call(exports[G_EXPORT_MOUSE_UP], 1, args); } } } break; case MP_EVENT_MOUSE_MOVE: { - if(eventHandlers[G_EVENT_MOUSE_MOVE]) + if(exports[G_EXPORT_MOUSE_MOVE]) { const void* args[4] = {&event->move.x, &event->move.y, &event->move.deltaX, &event->move.deltaY}; - m3_Call(eventHandlers[G_EVENT_MOUSE_MOVE], 4, args); + m3_Call(exports[G_EXPORT_MOUSE_MOVE], 4, args); } } break; @@ -558,18 +577,18 @@ void* orca_runloop(void* user) #endif } - if(eventHandlers[G_EVENT_KEY_DOWN]) + if(exports[G_EXPORT_KEY_DOWN]) { const void* args[1] = {&event->key.code}; - m3_Call(eventHandlers[G_EVENT_KEY_DOWN], 1, args); + m3_Call(exports[G_EXPORT_KEY_DOWN], 1, args); } } else if(event->key.action == MP_KEY_RELEASE) { - if(eventHandlers[G_EVENT_KEY_UP]) + if(exports[G_EXPORT_KEY_UP]) { const void* args[1] = {&event->key.code}; - m3_Call(eventHandlers[G_EVENT_KEY_UP], 1, args); + m3_Call(exports[G_EXPORT_KEY_UP], 1, args); } } } break; @@ -716,10 +735,10 @@ void* orca_runloop(void* user) mg_render(app->debugOverlay.surface, app->debugOverlay.canvas); } - if(eventHandlers[G_EVENT_FRAME_REFRESH]) + if(exports[G_EXPORT_FRAME_REFRESH]) { mg_surface_prepare(app->surface); - m3_Call(eventHandlers[G_EVENT_FRAME_REFRESH], 0, 0); + m3_Call(exports[G_EXPORT_FRAME_REFRESH], 0, 0); } if(app->debugOverlay.show) diff --git a/src/memory_impl.c b/src/memory_impl.c index d2839ed..f1484f6 100644 --- a/src/memory_impl.c +++ b/src/memory_impl.c @@ -57,3 +57,10 @@ extern u32 orca_mem_grow(u64 size) return(addr); } + +void* wasm_memory_offset_to_ptr(wasm_memory* memory, u32 offset) +{ + M3MemoryHeader* header = (M3MemoryHeader*)(memory->ptr); + DEBUG_ASSERT(offset < header->length, "Wasm offset exceeds memory length") + return memory->ptr + sizeof(M3MemoryHeader) + offset; +} \ No newline at end of file diff --git a/src/orca_app.h b/src/orca_app.h index 7735b9c..f6d74b6 100644 --- a/src/orca_app.h +++ b/src/orca_app.h @@ -14,40 +14,41 @@ #include"m3_env.h" #include"m3_compile.h" -#define G_EVENTS(X) \ - X(G_EVENT_START, "OnInit", "", "") \ - X(G_EVENT_MOUSE_DOWN, "OnMouseDown", "", "i") \ - X(G_EVENT_MOUSE_UP, "OnMouseUp", "", "i") \ - X(G_EVENT_MOUSE_ENTER, "OnMouseEnter", "", "") \ - X(G_EVENT_MOUSE_LEAVE, "OnMouseLeave", "", "") \ - X(G_EVENT_MOUSE_MOVE, "OnMouseMove", "", "ffff") \ - X(G_EVENT_MOUSE_WHEEL, "OnMouseWheel", "", "ff") \ - X(G_EVENT_KEY_DOWN, "OnKeyDown", "", "i") \ - X(G_EVENT_KEY_UP, "OnKeyUp", "", "i") \ - X(G_EVENT_FRAME_REFRESH, "OnFrameRefresh", "", "") \ - X(G_EVENT_FRAME_RESIZE, "OnFrameResize", "", "ii") +#define G_EXPORTS(X) \ + X(G_EXPORT_ON_INIT, "OnInit", "", "") \ + X(G_EXPORT_MOUSE_DOWN, "OnMouseDown", "", "i") \ + X(G_EXPORT_MOUSE_UP, "OnMouseUp", "", "i") \ + X(G_EXPORT_MOUSE_ENTER, "OnMouseEnter", "", "") \ + X(G_EXPORT_MOUSE_LEAVE, "OnMouseLeave", "", "") \ + X(G_EXPORT_MOUSE_MOVE, "OnMouseMove", "", "ffff") \ + X(G_EXPORT_MOUSE_WHEEL, "OnMouseWheel", "", "ff") \ + X(G_EXPORT_KEY_DOWN, "OnKeyDown", "", "i") \ + X(G_EXPORT_KEY_UP, "OnKeyUp", "", "i") \ + X(G_EXPORT_FRAME_REFRESH, "OnFrameRefresh", "", "") \ + X(G_EXPORT_FRAME_RESIZE, "OnFrameResize", "", "ii") \ + X(G_EXPORT_RAW_EVENT, "OnRawEvent", "", "i") \ typedef enum { - #define G_EVENT_KIND(kind, ...) kind, - G_EVENTS(G_EVENT_KIND) - G_EVENT_COUNT -} guest_event_kind; + #define G_EXPORT_KIND(kind, ...) kind, + G_EXPORTS(G_EXPORT_KIND) + G_EXPORT_COUNT +} guest_export_kind; -typedef struct g_event_handler_desc +typedef struct g_export_desc { str8 name; str8 retTags; str8 argTags; -} g_event_handler_desc; +} g_export_desc; -const g_event_handler_desc G_EVENT_HANDLER_DESC[] = { +const g_export_desc G_EXPORT_DESC[] = { #define STR8LIT(s) {sizeof(s)-1, s} //NOTE: msvc doesn't accept STR8(s) as compile-time constant... - #define G_EVENT_HANDLER_DESC_ENTRY(kind, name, rets, args) {STR8LIT(name), STR8LIT(rets), STR8LIT(args)}, + #define G_EXPORT_DESC_ENTRY(kind, name, rets, args) {STR8LIT(name), STR8LIT(rets), STR8LIT(args)}, - G_EVENTS(G_EVENT_HANDLER_DESC_ENTRY) + G_EXPORTS(G_EXPORT_DESC_ENTRY) - #undef G_EVENT_HANDLER_DESC_ENTRY + #undef G_EXPORT_DESC_ENTRY #undef STR8LIT }; @@ -68,7 +69,8 @@ typedef struct orca_runtime IM3Environment m3Env; IM3Runtime m3Runtime; IM3Module m3Module; - IM3Function eventHandlers[G_EVENT_COUNT]; + IM3Function exports[G_EXPORT_COUNT]; + u32 rawEventOffset; } orca_runtime;