Milepost UI demo #18
|
@ -18,4 +18,6 @@ Debug/*
|
|||
|
||||
src/bindgen_core_api.c
|
||||
src/bindgen_gles_api.c
|
||||
*bind_gen.c
|
||||
*bind_gen.c
|
||||
sdk/io_stubs.c
|
||||
sdk/orca_surface.c
|
|
@ -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^
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Pong
|
|
@ -10,7 +10,7 @@ set wasmFlags=--target=wasm32^
|
|||
-O2 ^
|
||||
-mbulk-memory ^
|
||||
-D__ORCA__ ^
|
||||
-isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src
|
||||
-isystem ..\..\cstdlib\include -I ..\..\sdk -I..\..\milepost\ext -I ..\..\milepost -I ..\..\milepost\src -I ..\..\milepost\src\util -I ..\..\milepost\src\platform
|
||||
|
||||
clang %wasmFlags% -o .\module.wasm ..\..\sdk\orca.c ..\..\cstdlib\src\*.c src\main.c
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
UI
|
|
@ -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 -I ..\..\milepost\src\util -I ..\..\milepost\src\platform
|
||||
|
||||
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
|
|
@ -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 -I ../../milepost/src/util -I ../../milepost/src/platform -I../.."
|
||||
|
||||
$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
|
Binary file not shown.
|
@ -0,0 +1,407 @@
|
|||
#include"keys.h"
|
||||
#include"graphics.h"
|
||||
#include"ui.h"
|
||||
|
||||
#include"orca.h"
|
||||
|
||||
vec2 frameSize = {100, 100};
|
||||
|
||||
mg_canvas canvas;
|
||||
mg_surface surface;
|
||||
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);
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
#include"orca.h"
|
||||
|
||||
ORCA_EXPORT mp_event* _OrcaGetRawEventPtr()
|
||||
{
|
||||
static mp_event event;
|
||||
return &event;
|
||||
}
|
||||
|
||||
ORCA_EXPORT void _OrcaClockInit()
|
||||
{
|
||||
mp_clock_init();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
[
|
||||
{
|
||||
"name": "mp_clock_init",
|
||||
"cname": "mp_clock_init",
|
||||
"ret": {"name": "void", "tag": "v"},
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"name": "mp_get_time",
|
||||
"cname": "mp_get_time",
|
||||
"ret": {"name": "time", "tag": "F"},
|
||||
"args": [ {"name": "clock",
|
||||
"type": {"name": "mp_clock_kind", "tag": "i"}}]
|
||||
}
|
||||
]
|
97
src/main.c
97
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);
|
||||
|
@ -379,26 +381,26 @@ void* orca_runloop(void* user)
|
|||
return((void*)-1);
|
||||
}
|
||||
|
||||
//NOTE: Find and type check event handlers.
|
||||
for(int i=0; i<G_EVENT_COUNT; i++)
|
||||
//NOTE: Find and type check exports.
|
||||
for(int i=0; i<G_EXPORT_COUNT; i++)
|
||||
{
|
||||
const g_event_handler_desc* desc = &G_EVENT_HANDLER_DESC[i];
|
||||
IM3Function handler = 0;
|
||||
m3_FindFunction(&handler, app->runtime.m3Runtime, desc->name.ptr);
|
||||
const g_export_desc* desc = &G_EXPORT_DESC[i];
|
||||
IM3Function export = 0;
|
||||
m3_FindFunction(&export, app->runtime.m3Runtime, desc->name.ptr);
|
||||
|
||||
if(handler)
|
||||
if(export)
|
||||
{
|
||||
bool checked = false;
|
||||
|
||||
//NOTE: check function signature
|
||||
int retCount = m3_GetRetCount(handler);
|
||||
int argCount = m3_GetArgCount(handler);
|
||||
int retCount = m3_GetRetCount(export);
|
||||
int argCount = m3_GetArgCount(export);
|
||||
if(retCount == desc->retTags.len && argCount == desc->argTags.len)
|
||||
{
|
||||
checked = true;
|
||||
for(int retIndex = 0; retIndex < retCount; retIndex++)
|
||||
{
|
||||
M3ValueType m3Type = m3_GetRetType(handler, retIndex);
|
||||
M3ValueType m3Type = m3_GetRetType(export, retIndex);
|
||||
char tag = m3_type_to_tag(m3Type);
|
||||
|
||||
if(tag != desc->retTags.ptr[retIndex])
|
||||
|
@ -411,7 +413,7 @@ void* orca_runloop(void* user)
|
|||
{
|
||||
for(int argIndex = 0; argIndex < argCount; argIndex++)
|
||||
{
|
||||
M3ValueType m3Type = m3_GetArgType(handler, argIndex);
|
||||
M3ValueType m3Type = m3_GetArgType(export, argIndex);
|
||||
char tag = m3_type_to_tag(m3Type);
|
||||
|
||||
if(tag != desc->argTags.ptr[argIndex])
|
||||
|
@ -425,14 +427,29 @@ void* orca_runloop(void* user)
|
|||
|
||||
if(checked)
|
||||
{
|
||||
app->runtime.eventHandlers[i] = handler;
|
||||
app->runtime.exports[i] = export;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error("type mismatch for event handler %.*s\n", (int)desc->name.len, desc->name.ptr);
|
||||
log_error("type mismatch for export %.*s\n", (int)desc->name.len, desc->name.ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
IM3Function* exports = app->runtime.exports;
|
||||
|
||||
//NOTE: get location of the raw event slot
|
||||
if (exports[G_EXPORT_GET_RAW_EVENT_PTR])
|
||||
{
|
||||
m3_CallV(exports[G_EXPORT_GET_RAW_EVENT_PTR]);
|
||||
const void* getRawEventPtrResults[1] = {&app->runtime.rawEventOffset};
|
||||
m3_GetResults(exports[G_EXPORT_GET_RAW_EVENT_PTR], 1, getRawEventPtrResults);
|
||||
}
|
||||
|
||||
//NOTE: init clock
|
||||
if (exports[G_EXPORT_CLOCK_INIT])
|
||||
{
|
||||
m3_CallV(exports[G_EXPORT_CLOCK_INIT]);
|
||||
}
|
||||
|
||||
//NOTE: preopen the app local root dir
|
||||
{
|
||||
|
@ -449,12 +466,10 @@ void* orca_runloop(void* user)
|
|||
//NOTE: prepare GL surface
|
||||
mg_surface_prepare(app->surface);
|
||||
|
||||
IM3Function* eventHandlers = app->runtime.eventHandlers;
|
||||
|
||||
//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 +486,13 @@ void* orca_runloop(void* user)
|
|||
}
|
||||
}
|
||||
|
||||
if(eventHandlers[G_EVENT_FRAME_RESIZE])
|
||||
if(exports[G_EXPORT_ON_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_ON_FRAME_RESIZE], 2, args);
|
||||
}
|
||||
|
||||
ui_set_context(&app->debugOverlay.ui);
|
||||
|
@ -493,6 +508,24 @@ void* orca_runloop(void* user)
|
|||
ui_process_event(event);
|
||||
}
|
||||
|
||||
if(exports[G_EXPORT_ON_RAW_EVENT])
|
||||
{
|
||||
if (app->runtime.rawEventOffset == 0)
|
||||
{
|
||||
log_error("expected raw event location to be set");
|
||||
}
|
||||
|
||||
#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_ON_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 +540,12 @@ void* orca_runloop(void* user)
|
|||
|
||||
// mg_surface_set_frame(app->debugOverlay.surface, frame);
|
||||
|
||||
if(eventHandlers[G_EVENT_FRAME_RESIZE])
|
||||
if(exports[G_EXPORT_ON_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_ON_FRAME_RESIZE], 2, args);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -520,30 +553,30 @@ void* orca_runloop(void* user)
|
|||
{
|
||||
if(event->key.action == MP_KEY_PRESS)
|
||||
{
|
||||
if(eventHandlers[G_EVENT_MOUSE_DOWN])
|
||||
if(exports[G_EXPORT_ON_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_ON_MOUSE_DOWN], 1, args);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(eventHandlers[G_EVENT_MOUSE_UP])
|
||||
if(exports[G_EXPORT_ON_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_ON_MOUSE_UP], 1, args);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case MP_EVENT_MOUSE_MOVE:
|
||||
{
|
||||
if(eventHandlers[G_EVENT_MOUSE_MOVE])
|
||||
if(exports[G_EXPORT_ON_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_ON_MOUSE_MOVE], 4, args);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
@ -558,18 +591,18 @@ void* orca_runloop(void* user)
|
|||
#endif
|
||||
}
|
||||
|
||||
if(eventHandlers[G_EVENT_KEY_DOWN])
|
||||
if(exports[G_EXPORT_ON_KEY_DOWN])
|
||||
{
|
||||
const void* args[1] = {&event->key.code};
|
||||
m3_Call(eventHandlers[G_EVENT_KEY_DOWN], 1, args);
|
||||
m3_Call(exports[G_EXPORT_ON_KEY_DOWN], 1, args);
|
||||
}
|
||||
}
|
||||
else if(event->key.action == MP_KEY_RELEASE)
|
||||
{
|
||||
if(eventHandlers[G_EVENT_KEY_UP])
|
||||
if(exports[G_EXPORT_ON_KEY_UP])
|
||||
{
|
||||
const void* args[1] = {&event->key.code};
|
||||
m3_Call(eventHandlers[G_EVENT_KEY_UP], 1, args);
|
||||
m3_Call(exports[G_EXPORT_ON_KEY_UP], 1, args);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -716,10 +749,10 @@ void* orca_runloop(void* user)
|
|||
mg_render(app->debugOverlay.surface, app->debugOverlay.canvas);
|
||||
}
|
||||
|
||||
if(eventHandlers[G_EVENT_FRAME_REFRESH])
|
||||
if(exports[G_EXPORT_ON_FRAME_REFRESH])
|
||||
{
|
||||
mg_surface_prepare(app->surface);
|
||||
m3_Call(eventHandlers[G_EVENT_FRAME_REFRESH], 0, 0);
|
||||
m3_Call(exports[G_EXPORT_ON_FRAME_REFRESH], 0, 0);
|
||||
}
|
||||
|
||||
if(app->debugOverlay.show)
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -14,40 +14,43 @@
|
|||
#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_ON_MOUSE_DOWN, "OnMouseDown", "", "i") \
|
||||
X(G_EXPORT_ON_MOUSE_UP, "OnMouseUp", "", "i") \
|
||||
X(G_EXPORT_ON_MOUSE_ENTER, "OnMouseEnter", "", "") \
|
||||
X(G_EXPORT_ON_MOUSE_LEAVE, "OnMouseLeave", "", "") \
|
||||
X(G_EXPORT_ON_MOUSE_MOVE, "OnMouseMove", "", "ffff") \
|
||||
X(G_EXPORT_ON_MOUSE_WHEEL, "OnMouseWheel", "", "ff") \
|
||||
X(G_EXPORT_ON_KEY_DOWN, "OnKeyDown", "", "i") \
|
||||
X(G_EXPORT_ON_KEY_UP, "OnKeyUp", "", "i") \
|
||||
X(G_EXPORT_ON_FRAME_REFRESH, "OnFrameRefresh", "", "") \
|
||||
X(G_EXPORT_ON_FRAME_RESIZE, "OnFrameResize", "", "ii") \
|
||||
X(G_EXPORT_ON_RAW_EVENT, "OnRawEvent", "", "i") \
|
||||
X(G_EXPORT_GET_RAW_EVENT_PTR, "_OrcaGetRawEventPtr", "i", "") \
|
||||
X(G_EXPORT_CLOCK_INIT, "_OrcaClockInit", "", "")
|
||||
|
||||
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 +71,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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue