2023-08-19 12:49:23 +00:00
|
|
|
/************************************************************/ /**
|
2023-04-12 14:21:03 +00:00
|
|
|
*
|
2023-08-09 11:06:32 +00:00
|
|
|
* @file: runtime.c
|
2023-04-12 14:21:03 +00:00
|
|
|
* @author: Martin Fouilleul
|
|
|
|
* @date: 11/04/2023
|
|
|
|
*
|
|
|
|
*****************************************************************/
|
2023-08-19 12:49:23 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
#define OC_INCLUDE_GL_API
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "graphics/graphics_common.h"
|
|
|
|
#include "orca.h"
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "runtime.h"
|
|
|
|
#include "runtime_io.c"
|
|
|
|
#include "runtime_memory.c"
|
2023-04-17 16:13:07 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_font orca_font_create(const char* resourcePath)
|
2023-04-14 09:48:36 +00:00
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
//NOTE(martin): create default fonts
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_str8 fontPath = oc_path_executable_relative(oc_scratch(), OC_STR8(resourcePath));
|
|
|
|
|
|
|
|
FILE* fontFile = fopen(fontPath.ptr, "r");
|
|
|
|
if(!fontFile)
|
|
|
|
{
|
|
|
|
oc_log_error("Could not load font file '%s': %s\n", fontPath.ptr, strerror(errno));
|
|
|
|
return (oc_font_nil());
|
|
|
|
}
|
|
|
|
char* fontData = 0;
|
|
|
|
fseek(fontFile, 0, SEEK_END);
|
|
|
|
u32 fontDataSize = ftell(fontFile);
|
|
|
|
rewind(fontFile);
|
|
|
|
fontData = malloc(fontDataSize);
|
|
|
|
fread(fontData, 1, fontDataSize, fontFile);
|
|
|
|
fclose(fontFile);
|
|
|
|
|
|
|
|
oc_unicode_range ranges[5] = { OC_UNICODE_BASIC_LATIN,
|
|
|
|
OC_UNICODE_C1_CONTROLS_AND_LATIN_1_SUPPLEMENT,
|
|
|
|
OC_UNICODE_LATIN_EXTENDED_A,
|
|
|
|
OC_UNICODE_LATIN_EXTENDED_B,
|
|
|
|
OC_UNICODE_SPECIALS };
|
|
|
|
|
|
|
|
oc_font font = oc_font_create_from_memory(oc_str8_from_buffer(fontDataSize, fontData), 5, ranges);
|
|
|
|
|
|
|
|
free(fontData);
|
|
|
|
|
|
|
|
return (font);
|
2023-04-14 09:48:36 +00:00
|
|
|
}
|
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_runtime __orcaApp = { 0 };
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_runtime* oc_runtime_get()
|
2023-04-19 09:28:53 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
return (&__orcaApp);
|
2023-06-11 16:21:04 +00:00
|
|
|
}
|
2023-04-19 09:28:53 +00:00
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_wasm_env* oc_runtime_get_env()
|
2023-04-12 14:21:03 +00:00
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
return (&__orcaApp.env);
|
2023-06-11 16:21:04 +00:00
|
|
|
}
|
2023-05-09 16:44:23 +00:00
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_str8 oc_runtime_get_wasm_memory()
|
|
|
|
{
|
|
|
|
oc_str8 mem = { 0 };
|
|
|
|
u32 size = 0;
|
|
|
|
mem.ptr = (char*)m3_GetMemory(__orcaApp.env.m3Runtime, &size, 0);
|
|
|
|
mem.len = size;
|
|
|
|
return (mem);
|
|
|
|
}
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
void orca_wasm3_abort(IM3Runtime runtime, M3Result res, const char* file, const char* function, int line, const char* msg)
|
|
|
|
{
|
|
|
|
M3ErrorInfo errInfo = { 0 };
|
|
|
|
m3_GetErrorInfo(runtime, &errInfo);
|
|
|
|
if(errInfo.message && res == errInfo.result)
|
|
|
|
{
|
|
|
|
oc_abort_ext(file, function, line, "%s: %s (%s)", msg, res, errInfo.message);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
oc_abort_ext(file, function, line, "%s: %s", msg, res);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
void oc_bridge_window_set_title(oc_wasm_str8 title)
|
2023-08-23 20:00:38 +00:00
|
|
|
{
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_str8 nativeTitle = oc_wasm_str8_to_native(title);
|
|
|
|
if(nativeTitle.ptr)
|
2023-08-23 20:00:38 +00:00
|
|
|
{
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_window_set_title(__orcaApp.window, nativeTitle);
|
2023-08-23 20:00:38 +00:00
|
|
|
}
|
2023-08-23 04:28:37 +00:00
|
|
|
}
|
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
void oc_bridge_window_set_size(oc_vec2 size)
|
2023-08-23 04:28:37 +00:00
|
|
|
{
|
2023-08-23 20:13:38 +00:00
|
|
|
oc_window_set_content_size(__orcaApp.window, size);
|
2023-08-23 04:28:37 +00:00
|
|
|
}
|
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
void oc_bridge_log(oc_log_level level,
|
2023-08-19 12:49:23 +00:00
|
|
|
int fileLen,
|
|
|
|
char* file,
|
|
|
|
int functionLen,
|
|
|
|
char* function,
|
|
|
|
int line,
|
|
|
|
int msgLen,
|
|
|
|
char* msg)
|
2023-04-20 13:47:18 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_debug_overlay* debug = &__orcaApp.debugOverlay;
|
|
|
|
|
|
|
|
//NOTE: recycle first entry if we exceeded the max entry count
|
|
|
|
debug->entryCount++;
|
|
|
|
if(debug->entryCount > debug->maxEntries)
|
|
|
|
{
|
|
|
|
log_entry* e = oc_list_pop_entry(&debug->logEntries, log_entry, listElt);
|
|
|
|
if(e)
|
|
|
|
{
|
|
|
|
oc_list_push(&debug->logFreeList, &e->listElt);
|
|
|
|
debug->entryCount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 cap = sizeof(log_entry) + fileLen + functionLen + msgLen;
|
|
|
|
|
|
|
|
//NOTE: allocate a new entry
|
|
|
|
//TODO: should probably use a buddy allocator over the arena or something
|
|
|
|
log_entry* entry = 0;
|
|
|
|
oc_list_for(&debug->logFreeList, elt, log_entry, listElt)
|
|
|
|
{
|
|
|
|
if(elt->cap >= cap)
|
|
|
|
{
|
|
|
|
oc_list_remove(&debug->logFreeList, &elt->listElt);
|
|
|
|
entry = elt;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!entry)
|
|
|
|
{
|
|
|
|
char* mem = oc_arena_push(&debug->logArena, cap);
|
|
|
|
entry = (log_entry*)mem;
|
|
|
|
entry->cap = cap;
|
|
|
|
}
|
|
|
|
char* payload = (char*)entry + sizeof(log_entry);
|
|
|
|
|
|
|
|
entry->file.len = fileLen;
|
|
|
|
entry->file.ptr = payload;
|
|
|
|
payload += entry->file.len;
|
|
|
|
|
|
|
|
entry->function.len = functionLen;
|
|
|
|
entry->function.ptr = payload;
|
|
|
|
payload += entry->function.len;
|
|
|
|
|
|
|
|
entry->msg.len = msgLen;
|
|
|
|
entry->msg.ptr = payload;
|
|
|
|
payload += entry->msg.len;
|
|
|
|
|
|
|
|
memcpy(entry->file.ptr, file, fileLen);
|
|
|
|
memcpy(entry->function.ptr, function, functionLen);
|
|
|
|
memcpy(entry->msg.ptr, msg, msgLen);
|
|
|
|
|
|
|
|
entry->level = level;
|
|
|
|
entry->line = line;
|
|
|
|
entry->recordIndex = debug->logEntryTotalCount;
|
|
|
|
debug->logEntryTotalCount++;
|
|
|
|
|
|
|
|
oc_list_push_back(&debug->logEntries, &entry->listElt);
|
|
|
|
|
|
|
|
oc_log_ext(level,
|
|
|
|
file,
|
|
|
|
function,
|
|
|
|
line,
|
|
|
|
"%.*s\n",
|
|
|
|
msgLen,
|
|
|
|
msg);
|
2023-04-20 13:47:18 +00:00
|
|
|
}
|
|
|
|
|
2023-08-03 09:37:32 +00:00
|
|
|
typedef struct orca_surface_create_data
|
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_window window;
|
|
|
|
oc_surface_api api;
|
|
|
|
oc_surface surface;
|
2023-08-03 09:37:32 +00:00
|
|
|
|
|
|
|
} orca_surface_create_data;
|
|
|
|
|
|
|
|
i32 orca_surface_callback(void* user)
|
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
orca_surface_create_data* data = (orca_surface_create_data*)user;
|
|
|
|
data->surface = oc_surface_create_for_window(data->window, data->api);
|
2023-08-28 16:28:14 +00:00
|
|
|
oc_surface_swap_interval(data->surface, 0);
|
2023-08-03 09:37:32 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
//NOTE: this will be called on main thread, so we need to deselect the surface here,
|
|
|
|
// and reselect it on the orca thread
|
|
|
|
oc_surface_deselect();
|
2023-08-03 09:37:32 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
return (0);
|
2023-08-03 09:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_surface orca_surface_canvas(void)
|
2023-08-03 09:37:32 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
orca_surface_create_data data = {
|
|
|
|
.surface = oc_surface_nil(),
|
|
|
|
.window = __orcaApp.window,
|
|
|
|
.api = OC_CANVAS
|
|
|
|
};
|
|
|
|
|
|
|
|
oc_dispatch_on_main_thread_sync(__orcaApp.window, orca_surface_callback, (void*)&data);
|
|
|
|
oc_surface_select(data.surface);
|
|
|
|
return (data.surface);
|
2023-08-03 09:37:32 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_surface orca_surface_gles(void)
|
2023-04-26 12:57:12 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
orca_surface_create_data data = {
|
|
|
|
.surface = oc_surface_nil(),
|
|
|
|
.window = __orcaApp.window,
|
|
|
|
.api = OC_GLES
|
|
|
|
};
|
|
|
|
|
|
|
|
oc_dispatch_on_main_thread_sync(__orcaApp.window, orca_surface_callback, (void*)&data);
|
|
|
|
oc_surface_select(data.surface);
|
|
|
|
return (data.surface);
|
2023-04-26 12:57:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void orca_surface_render_commands(oc_surface surface,
|
|
|
|
oc_color clearColor,
|
2023-04-26 12:57:12 +00:00
|
|
|
u32 primitiveCount,
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_primitive* primitives,
|
2023-04-26 12:57:12 +00:00
|
|
|
u32 eltCount,
|
2023-08-14 08:26:11 +00:00
|
|
|
oc_path_elt* elements)
|
2023-04-26 12:57:12 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_runtime* app = &__orcaApp;
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
char* memBase = app->env.wasmMemory.ptr;
|
|
|
|
u32 memSize = app->env.wasmMemory.committed;
|
2023-08-19 12:49:23 +00:00
|
|
|
if(((char*)primitives > memBase)
|
|
|
|
&& ((char*)primitives + primitiveCount * sizeof(oc_primitive) - memBase <= memSize)
|
|
|
|
&& ((char*)elements > memBase)
|
2023-08-21 19:03:45 +00:00
|
|
|
&& ((char*)elements + eltCount * sizeof(oc_path_elt) - memBase <= memSize)
|
|
|
|
&& oc_window_is_minimized(app->window) == false)
|
2023-08-19 12:49:23 +00:00
|
|
|
{
|
|
|
|
oc_surface_render_commands(surface,
|
|
|
|
clearColor,
|
|
|
|
primitiveCount,
|
|
|
|
primitives,
|
|
|
|
eltCount,
|
|
|
|
elements);
|
|
|
|
}
|
2023-04-26 12:57:12 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void debug_overlay_toggle(oc_debug_overlay* overlay)
|
2023-04-20 13:47:18 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
overlay->show = !overlay->show;
|
2023-04-20 13:47:18 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
if(overlay->show)
|
|
|
|
{
|
|
|
|
overlay->logScrollToLast = true;
|
|
|
|
}
|
2023-04-20 13:47:18 +00:00
|
|
|
}
|
|
|
|
|
2023-08-14 08:26:11 +00:00
|
|
|
void log_entry_ui(oc_debug_overlay* overlay, log_entry* entry)
|
2023-04-20 13:47:18 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
static const char* levelNames[] = { "Error: ", "Warning: ", "Info: " };
|
|
|
|
static const oc_color levelColors[] = { { 0.8, 0, 0, 1 },
|
|
|
|
{ 1, 0.5, 0, 1 },
|
|
|
|
{ 0, 0.8, 0, 1 } };
|
|
|
|
|
|
|
|
static const oc_color bgColors[3][2] = { //errors
|
|
|
|
{ { 0.6, 0, 0, 0.5 }, { 0.8, 0, 0, 0.5 } },
|
|
|
|
//warning
|
|
|
|
{ { 0.4, 0.4, 0.4, 0.5 }, { 0.5, 0.5, 0.5, 0.5 } },
|
|
|
|
//info
|
|
|
|
{ { 0.4, 0.4, 0.4, 0.5 }, { 0.5, 0.5, 0.5, 0.5 } }
|
|
|
|
};
|
|
|
|
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_CHILDREN },
|
|
|
|
.layout.axis = OC_UI_AXIS_Y,
|
|
|
|
.layout.margin.x = 10,
|
|
|
|
.layout.margin.y = 5,
|
|
|
|
.bgColor = bgColors[entry->level][entry->recordIndex & 1] },
|
|
|
|
OC_UI_STYLE_SIZE
|
|
|
|
| OC_UI_STYLE_LAYOUT_AXIS
|
|
|
|
| OC_UI_STYLE_LAYOUT_MARGINS
|
|
|
|
| OC_UI_STYLE_BG_COLOR);
|
|
|
|
|
|
|
|
oc_str8 key = oc_str8_pushf(oc_scratch(), "%ull", entry->recordIndex);
|
|
|
|
|
|
|
|
oc_ui_container_str8(key, OC_UI_FLAG_DRAW_BACKGROUND)
|
|
|
|
{
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_CHILDREN },
|
|
|
|
.layout.axis = OC_UI_AXIS_X },
|
|
|
|
OC_UI_STYLE_SIZE
|
|
|
|
| OC_UI_STYLE_LAYOUT_AXIS);
|
|
|
|
|
|
|
|
oc_ui_container("header", 0)
|
|
|
|
{
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .color = levelColors[entry->level],
|
|
|
|
.font = overlay->fontBold },
|
|
|
|
OC_UI_STYLE_COLOR
|
|
|
|
| OC_UI_STYLE_FONT);
|
|
|
|
oc_ui_label(levelNames[entry->level]);
|
|
|
|
|
|
|
|
oc_str8 loc = oc_str8_pushf(oc_scratch(),
|
|
|
|
"%.*s() in %.*s:%i:",
|
|
|
|
oc_str8_ip(entry->file),
|
|
|
|
oc_str8_ip(entry->function),
|
|
|
|
entry->line);
|
|
|
|
oc_ui_label_str8(loc);
|
|
|
|
}
|
|
|
|
oc_ui_label_str8(entry->msg);
|
|
|
|
}
|
2023-04-20 13:47:18 +00:00
|
|
|
}
|
|
|
|
|
2023-04-12 14:21:03 +00:00
|
|
|
char m3_type_to_tag(M3ValueType type)
|
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
switch(type)
|
|
|
|
{
|
|
|
|
case c_m3Type_none:
|
|
|
|
return ('v');
|
|
|
|
case c_m3Type_i32:
|
|
|
|
return ('i');
|
|
|
|
case c_m3Type_i64:
|
|
|
|
return ('I');
|
|
|
|
case c_m3Type_f32:
|
|
|
|
return ('f');
|
|
|
|
case c_m3Type_f64:
|
|
|
|
return ('d');
|
|
|
|
|
|
|
|
case c_m3Type_unknown:
|
|
|
|
default:
|
|
|
|
return ('!');
|
|
|
|
}
|
2023-04-12 14:21:03 +00:00
|
|
|
}
|
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
void oc_wasm_env_init(oc_wasm_env* runtime)
|
2023-04-12 14:21:03 +00:00
|
|
|
{
|
2023-09-02 14:20:22 +00:00
|
|
|
memset(runtime, 0, sizeof(oc_wasm_env));
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_base_allocator* allocator = oc_base_allocator_default();
|
|
|
|
runtime->wasmMemory.committed = 0;
|
|
|
|
runtime->wasmMemory.reserved = 4ULL << 30;
|
|
|
|
runtime->wasmMemory.ptr = oc_base_reserve(allocator, runtime->wasmMemory.reserved);
|
2023-04-12 14:21:03 +00:00
|
|
|
}
|
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "wasmbind/clock_api_bind_gen.c"
|
|
|
|
#include "wasmbind/core_api_bind_gen.c"
|
|
|
|
#include "wasmbind/gles_api_bind_manual.c"
|
2023-08-21 18:50:42 +00:00
|
|
|
#include "wasmbind/gles_api_bind_gen.c"
|
2023-08-19 12:49:23 +00:00
|
|
|
#include "wasmbind/io_api_bind_gen.c"
|
|
|
|
#include "wasmbind/surface_api_bind_gen.c"
|
2023-08-03 09:37:32 +00:00
|
|
|
|
2023-07-31 04:35:08 +00:00
|
|
|
i32 orca_runloop(void* user)
|
2023-04-12 14:21:03 +00:00
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_runtime* app = &__orcaApp;
|
|
|
|
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_wasm_env_init(&app->env);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
//NOTE: loads wasm module
|
|
|
|
const char* bundleNameCString = "module";
|
|
|
|
oc_str8 modulePath = oc_path_executable_relative(oc_scratch(), OC_STR8("../app/wasm/module.wasm"));
|
|
|
|
|
|
|
|
FILE* file = fopen(modulePath.ptr, "rb");
|
|
|
|
if(!file)
|
|
|
|
{
|
|
|
|
OC_ABORT("The application couldn't load: web assembly module not found");
|
|
|
|
}
|
|
|
|
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
|
|
u64 wasmSize = ftell(file);
|
|
|
|
rewind(file);
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
app->env.wasmBytecode.len = wasmSize;
|
|
|
|
app->env.wasmBytecode.ptr = oc_malloc_array(char, wasmSize);
|
|
|
|
fread(app->env.wasmBytecode.ptr, 1, app->env.wasmBytecode.len, file);
|
2023-08-19 12:49:23 +00:00
|
|
|
fclose(file);
|
|
|
|
|
|
|
|
u32 stackSize = 65536;
|
2023-08-30 14:45:56 +00:00
|
|
|
app->env.m3Env = m3_NewEnvironment();
|
2023-08-19 12:49:23 +00:00
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
app->env.m3Runtime = m3_NewRuntime(app->env.m3Env, stackSize, NULL);
|
2023-08-19 12:49:23 +00:00
|
|
|
//NOTE: host memory will be freed when runtime is freed.
|
2023-09-02 14:20:22 +00:00
|
|
|
m3_RuntimeSetMemoryCallbacks(app->env.m3Runtime, oc_wasm_memory_resize_callback, oc_wasm_memory_free_callback, &app->env.wasmMemory);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
M3Result res = m3_ParseModule(app->env.m3Env, &app->env.m3Module, (u8*)app->env.wasmBytecode.ptr, app->env.wasmBytecode.len);
|
2023-08-19 12:49:23 +00:00
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't parse its web assembly module");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
res = m3_LoadModule(app->env.m3Runtime, app->env.m3Module);
|
2023-08-19 12:49:23 +00:00
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't load its web assembly module into the runtime");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
2023-08-30 14:45:56 +00:00
|
|
|
m3_SetModuleName(app->env.m3Module, bundleNameCString);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
oc_arena_clear(oc_scratch());
|
|
|
|
|
|
|
|
//NOTE: bind orca APIs
|
|
|
|
{
|
|
|
|
int err = 0;
|
2023-08-30 14:45:56 +00:00
|
|
|
err |= bindgen_link_core_api(app->env.m3Module);
|
|
|
|
err |= bindgen_link_surface_api(app->env.m3Module);
|
|
|
|
err |= bindgen_link_clock_api(app->env.m3Module);
|
|
|
|
err |= bindgen_link_io_api(app->env.m3Module);
|
|
|
|
err |= bindgen_link_gles_api(app->env.m3Module);
|
|
|
|
err |= manual_link_gles_api(app->env.m3Module);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
if(err)
|
|
|
|
{
|
|
|
|
OC_ABORT("The application couldn't link one or more functions to its web assembly module (see console log for more information)");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//NOTE: compile
|
2023-08-30 14:45:56 +00:00
|
|
|
res = m3_CompileModule(app->env.m3Module);
|
2023-08-19 12:49:23 +00:00
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "The application couldn't compile its web assembly module");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//NOTE: Find and type check event handlers.
|
|
|
|
for(int i = 0; i < OC_EXPORT_COUNT; i++)
|
|
|
|
{
|
|
|
|
const oc_export_desc* desc = &OC_EXPORT_DESC[i];
|
|
|
|
IM3Function handler = 0;
|
2023-08-30 14:45:56 +00:00
|
|
|
m3_FindFunction(&handler, app->env.m3Runtime, desc->name.ptr);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
if(handler)
|
|
|
|
{
|
|
|
|
bool checked = false;
|
|
|
|
|
|
|
|
//NOTE: check function signature
|
|
|
|
int retCount = m3_GetRetCount(handler);
|
|
|
|
int argCount = m3_GetArgCount(handler);
|
|
|
|
if(retCount == desc->retTags.len && argCount == desc->argTags.len)
|
|
|
|
{
|
|
|
|
checked = true;
|
|
|
|
for(int retIndex = 0; retIndex < retCount; retIndex++)
|
|
|
|
{
|
|
|
|
M3ValueType m3Type = m3_GetRetType(handler, retIndex);
|
|
|
|
char tag = m3_type_to_tag(m3Type);
|
|
|
|
|
|
|
|
if(tag != desc->retTags.ptr[retIndex])
|
|
|
|
{
|
|
|
|
checked = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(checked)
|
|
|
|
{
|
|
|
|
for(int argIndex = 0; argIndex < argCount; argIndex++)
|
|
|
|
{
|
|
|
|
M3ValueType m3Type = m3_GetArgType(handler, argIndex);
|
|
|
|
char tag = m3_type_to_tag(m3Type);
|
|
|
|
|
|
|
|
if(tag != desc->argTags.ptr[argIndex])
|
|
|
|
{
|
|
|
|
checked = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(checked)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
app->env.exports[i] = handler;
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
oc_log_error("type mismatch for event handler %.*s\n", (int)desc->name.len, desc->name.ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//NOTE: get location of the raw event slot
|
2023-08-30 14:45:56 +00:00
|
|
|
IM3Global rawEventGlobal = m3_FindGlobal(app->env.m3Module, "oc_rawEvent");
|
|
|
|
app->env.rawEventOffset = (u32)rawEventGlobal->intValue;
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
//NOTE: preopen the app local root dir
|
|
|
|
{
|
|
|
|
oc_str8 localRootPath = oc_path_executable_relative(oc_scratch(), OC_STR8("../app/data"));
|
|
|
|
|
|
|
|
oc_io_req req = { .op = OC_IO_OPEN_AT,
|
|
|
|
.open.rights = OC_FILE_ACCESS_READ | OC_FILE_ACCESS_WRITE,
|
|
|
|
.size = localRootPath.len,
|
|
|
|
.buffer = localRootPath.ptr };
|
2023-08-30 14:45:56 +00:00
|
|
|
oc_io_cmp cmp = oc_io_wait_single_req_for_table(&req, &app->fileTable);
|
2023-08-19 12:49:23 +00:00
|
|
|
app->rootDir = cmp.handle;
|
|
|
|
}
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
IM3Function* exports = app->env.exports;
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
//NOTE: call init handler
|
|
|
|
if(exports[OC_EXPORT_ON_INIT])
|
|
|
|
{
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_ON_INIT], 0, 0);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(exports[OC_EXPORT_FRAME_RESIZE])
|
|
|
|
{
|
|
|
|
oc_rect content = oc_window_get_content_rect(app->window);
|
|
|
|
u32 width = (u32)content.w;
|
|
|
|
u32 height = (u32)content.h;
|
|
|
|
const void* args[2] = { &width, &height };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_ui_set_context(&app->debugOverlay.ui);
|
|
|
|
|
|
|
|
while(!oc_should_quit())
|
|
|
|
{
|
|
|
|
oc_event* event = 0;
|
|
|
|
while((event = oc_next_event(oc_scratch())) != 0)
|
|
|
|
{
|
|
|
|
|
|
|
|
if(app->debugOverlay.show)
|
|
|
|
{
|
|
|
|
oc_ui_process_event(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(exports[OC_EXPORT_RAW_EVENT])
|
|
|
|
{
|
|
|
|
#ifndef M3_BIG_ENDIAN
|
2023-09-02 14:20:22 +00:00
|
|
|
oc_event* eventPtr = (oc_event*)oc_wasm_address_to_ptr(app->env.rawEventOffset, sizeof(oc_event));
|
2023-08-19 12:49:23 +00:00
|
|
|
memcpy(eventPtr, event, sizeof(*event));
|
|
|
|
|
2023-08-30 14:45:56 +00:00
|
|
|
const void* args[1] = { &app->env.rawEventOffset };
|
2023-08-19 12:49:23 +00:00
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_RAW_EVENT], 1, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
oc_log_error("oc_on_raw_event() is not supported on big endian platforms");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(event->type)
|
|
|
|
{
|
|
|
|
case OC_EVENT_WINDOW_CLOSE:
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
oc_request_quit();
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OC_EVENT_WINDOW_RESIZE:
|
|
|
|
{
|
|
|
|
oc_rect frame = { 0, 0, event->move.frame.w, event->move.frame.h };
|
|
|
|
|
|
|
|
if(exports[OC_EXPORT_FRAME_RESIZE])
|
|
|
|
{
|
|
|
|
u32 width = (u32)event->move.content.w;
|
|
|
|
u32 height = (u32)event->move.content.h;
|
|
|
|
const void* args[2] = { &width, &height };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_RESIZE], 2, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OC_EVENT_MOUSE_BUTTON:
|
|
|
|
{
|
|
|
|
if(event->key.action == OC_KEY_PRESS)
|
|
|
|
{
|
|
|
|
if(exports[OC_EXPORT_MOUSE_DOWN])
|
|
|
|
{
|
|
|
|
int key = event->key.code;
|
|
|
|
const void* args[1] = { &key };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_DOWN], 1, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(exports[OC_EXPORT_MOUSE_UP])
|
|
|
|
{
|
|
|
|
int key = event->key.code;
|
|
|
|
const void* args[1] = { &key };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_UP], 1, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OC_EVENT_MOUSE_MOVE:
|
|
|
|
{
|
|
|
|
if(exports[OC_EXPORT_MOUSE_MOVE])
|
|
|
|
{
|
|
|
|
const void* args[4] = { &event->mouse.x, &event->mouse.y, &event->mouse.deltaX, &event->mouse.deltaY };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_MOUSE_MOVE], 4, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case OC_EVENT_KEYBOARD_KEY:
|
|
|
|
{
|
|
|
|
if(event->key.action == OC_KEY_PRESS)
|
|
|
|
{
|
2023-08-28 15:04:55 +00:00
|
|
|
if(event->key.code == OC_KEY_D
|
|
|
|
&& (event->key.mods & OC_KEYMOD_SHIFT)
|
|
|
|
&& (event->key.mods & OC_KEYMOD_MAIN_MODIFIER))
|
2023-08-19 12:49:23 +00:00
|
|
|
{
|
|
|
|
debug_overlay_toggle(&app->debugOverlay);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(exports[OC_EXPORT_KEY_DOWN])
|
|
|
|
{
|
|
|
|
const void* args[1] = { &event->key.code };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_KEY_DOWN], 1, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(event->key.action == OC_KEY_RELEASE)
|
|
|
|
{
|
|
|
|
if(exports[OC_EXPORT_KEY_UP])
|
|
|
|
{
|
|
|
|
const void* args[1] = { &event->key.code };
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_KEY_UP], 1, args);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-28 16:28:14 +00:00
|
|
|
oc_surface_deselect();
|
|
|
|
|
|
|
|
if(exports[OC_EXPORT_FRAME_REFRESH])
|
|
|
|
{
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_FRAME_REFRESH], 0, 0);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-28 16:28:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_surface_select(app->debugOverlay.surface);
|
|
|
|
oc_canvas_set_current(app->debugOverlay.canvas);
|
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
if(app->debugOverlay.show)
|
|
|
|
{
|
2023-08-28 14:11:55 +00:00
|
|
|
oc_surface_bring_to_front(app->debugOverlay.surface);
|
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_ui_style debugUIDefaultStyle = { .bgColor = { 0 },
|
|
|
|
.color = { 1, 1, 1, 1 },
|
|
|
|
.font = app->debugOverlay.fontReg,
|
|
|
|
.fontSize = 16,
|
|
|
|
.borderColor = { 1, 0, 0, 1 },
|
|
|
|
.borderSize = 2 };
|
|
|
|
|
|
|
|
oc_ui_style_mask debugUIDefaultMask = OC_UI_STYLE_BG_COLOR
|
|
|
|
| OC_UI_STYLE_COLOR
|
|
|
|
| OC_UI_STYLE_BORDER_COLOR
|
|
|
|
| OC_UI_STYLE_BORDER_SIZE
|
|
|
|
| OC_UI_STYLE_FONT
|
|
|
|
| OC_UI_STYLE_FONT_SIZE;
|
|
|
|
|
|
|
|
oc_vec2 frameSize = oc_surface_get_size(app->debugOverlay.surface);
|
|
|
|
|
|
|
|
oc_ui_frame(frameSize, &debugUIDefaultStyle, debugUIDefaultMask)
|
|
|
|
{
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_PARENT, 1, 1 } },
|
|
|
|
OC_UI_STYLE_SIZE);
|
|
|
|
|
|
|
|
oc_ui_container("overlay area", 0)
|
|
|
|
{
|
|
|
|
//...
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_PARENT, 0.4 },
|
|
|
|
.layout.axis = OC_UI_AXIS_Y,
|
|
|
|
.bgColor = { 0, 0, 0, 0.5 } },
|
|
|
|
OC_UI_STYLE_SIZE
|
|
|
|
| OC_UI_STYLE_LAYOUT_AXIS
|
|
|
|
| OC_UI_STYLE_BG_COLOR);
|
|
|
|
|
|
|
|
oc_ui_container("log console", OC_UI_FLAG_DRAW_BACKGROUND)
|
|
|
|
{
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_CHILDREN },
|
|
|
|
.layout.axis = OC_UI_AXIS_X,
|
|
|
|
.layout.spacing = 10,
|
|
|
|
.layout.margin.x = 10,
|
|
|
|
.layout.margin.y = 10 },
|
|
|
|
OC_UI_STYLE_SIZE
|
|
|
|
| OC_UI_STYLE_LAYOUT);
|
|
|
|
|
|
|
|
oc_ui_container("log toolbar", 0)
|
|
|
|
{
|
|
|
|
oc_ui_style buttonStyle = { .layout.margin.x = 4,
|
|
|
|
.layout.margin.y = 4,
|
|
|
|
.roundness = 2,
|
|
|
|
.bgColor = { 0, 0, 0, 0.5 },
|
|
|
|
.color = { 1, 1, 1, 1 } };
|
|
|
|
|
|
|
|
oc_ui_style_mask buttonStyleMask = OC_UI_STYLE_LAYOUT_MARGINS
|
|
|
|
| OC_UI_STYLE_ROUNDNESS
|
|
|
|
| OC_UI_STYLE_BG_COLOR
|
|
|
|
| OC_UI_STYLE_COLOR;
|
|
|
|
|
|
|
|
oc_ui_style_match_after(oc_ui_pattern_all(), &buttonStyle, buttonStyleMask);
|
|
|
|
if(oc_ui_button("Clear").clicked)
|
|
|
|
{
|
|
|
|
oc_list_for_safe(&app->debugOverlay.logEntries, entry, log_entry, listElt)
|
|
|
|
{
|
|
|
|
oc_list_remove(&app->debugOverlay.logEntries, &entry->listElt);
|
|
|
|
oc_list_push(&app->debugOverlay.logFreeList, &entry->listElt);
|
|
|
|
app->debugOverlay.entryCount--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_PARENT, 1, 1 } },
|
|
|
|
OC_UI_STYLE_SIZE);
|
|
|
|
|
|
|
|
//TODO: this is annoying to have to do that. Basically there's another 'contents' box inside oc_ui_panel,
|
|
|
|
// and we need to change that to size according to its parent (whereas the default is sizing according
|
|
|
|
// to its children)
|
|
|
|
oc_ui_pattern pattern = { 0 };
|
|
|
|
oc_ui_pattern_push(oc_scratch(), &pattern, (oc_ui_selector){ .kind = OC_UI_SEL_OWNER });
|
|
|
|
oc_ui_pattern_push(oc_scratch(), &pattern, (oc_ui_selector){ .kind = OC_UI_SEL_TEXT, .text = OC_STR8("contents") });
|
|
|
|
oc_ui_style_match_after(pattern, &(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 } }, OC_UI_STYLE_SIZE_WIDTH);
|
|
|
|
|
|
|
|
oc_ui_box* panel = oc_ui_box_lookup("log view");
|
|
|
|
f32 scrollY = 0;
|
|
|
|
if(panel)
|
|
|
|
{
|
|
|
|
scrollY = panel->scroll.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_ui_panel("log view", OC_UI_FLAG_SCROLL_WHEEL_Y)
|
|
|
|
{
|
|
|
|
panel = oc_ui_box_top();
|
|
|
|
|
|
|
|
oc_ui_style_next(&(oc_ui_style){ .size.width = { OC_UI_SIZE_PARENT, 1 },
|
|
|
|
.size.height = { OC_UI_SIZE_CHILDREN },
|
|
|
|
.layout.axis = OC_UI_AXIS_Y,
|
|
|
|
.layout.margin.y = 5 },
|
|
|
|
OC_UI_STYLE_SIZE
|
|
|
|
| OC_UI_STYLE_LAYOUT_AXIS);
|
|
|
|
|
|
|
|
oc_ui_container("contents", 0)
|
|
|
|
{
|
|
|
|
oc_list_for(&app->debugOverlay.logEntries, entry, log_entry, listElt)
|
|
|
|
{
|
|
|
|
log_entry_ui(&app->debugOverlay, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(app->debugOverlay.logScrollToLast)
|
|
|
|
{
|
|
|
|
if(panel->scroll.y >= scrollY)
|
|
|
|
{
|
|
|
|
panel->scroll.y = oc_clamp_low(panel->childrenSum[1] - panel->rect.h, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
app->debugOverlay.logScrollToLast = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(panel->scroll.y >= (panel->childrenSum[1] - panel->rect.h) - 1)
|
|
|
|
{
|
|
|
|
app->debugOverlay.logScrollToLast = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
oc_ui_draw();
|
|
|
|
}
|
2023-08-28 16:28:14 +00:00
|
|
|
else
|
2023-08-19 12:49:23 +00:00
|
|
|
{
|
2023-08-28 16:28:14 +00:00
|
|
|
oc_set_color_rgba(0, 0, 0, 0);
|
|
|
|
oc_clear();
|
2023-08-19 12:49:23 +00:00
|
|
|
}
|
2023-08-28 17:33:02 +00:00
|
|
|
|
2023-08-28 16:28:14 +00:00
|
|
|
oc_render(app->debugOverlay.surface, app->debugOverlay.canvas);
|
|
|
|
oc_surface_present(app->debugOverlay.surface);
|
2023-08-19 12:49:23 +00:00
|
|
|
|
|
|
|
oc_arena_clear(oc_scratch());
|
|
|
|
}
|
|
|
|
|
2023-08-22 20:44:04 +00:00
|
|
|
if(exports[OC_EXPORT_TERMINATE])
|
|
|
|
{
|
|
|
|
M3Result res = m3_Call(exports[OC_EXPORT_TERMINATE], 0, 0);
|
|
|
|
if(res)
|
|
|
|
{
|
2023-08-30 14:45:56 +00:00
|
|
|
ORCA_WASM3_ABORT(app->env.m3Runtime, res, "Runtime error");
|
2023-08-22 20:44:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-30 10:06:32 +00:00
|
|
|
app->quit = true;
|
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
return (0);
|
2023-04-12 14:21:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char** argv)
|
|
|
|
{
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_log_set_level(OC_LOG_LEVEL_INFO);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_init();
|
|
|
|
oc_clock_init();
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_runtime* app = &__orcaApp;
|
2023-04-19 09:28:53 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
//NOTE: create window and surfaces
|
|
|
|
oc_rect windowRect = { .x = 100, .y = 100, .w = 810, .h = 610 };
|
|
|
|
app->window = oc_window_create(windowRect, OC_STR8("orca"), 0);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
app->debugOverlay.show = false;
|
|
|
|
app->debugOverlay.surface = oc_surface_create_for_window(app->window, OC_CANVAS);
|
|
|
|
app->debugOverlay.canvas = oc_canvas_create();
|
|
|
|
app->debugOverlay.fontReg = orca_font_create("../resources/Menlo.ttf");
|
|
|
|
app->debugOverlay.fontBold = orca_font_create("../resources/Menlo Bold.ttf");
|
|
|
|
app->debugOverlay.maxEntries = 200;
|
|
|
|
oc_arena_init(&app->debugOverlay.logArena);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-28 16:28:14 +00:00
|
|
|
oc_surface_swap_interval(app->debugOverlay.surface, 1);
|
2023-06-21 13:49:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_surface_deselect();
|
2023-04-19 09:28:53 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
//WARN: this is a workaround to avoid stalling the first few times we acquire drawables from
|
|
|
|
// the surfaces... This should probably be fixed in the implementation of mtl_surface!
|
2023-06-26 18:00:29 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
for(int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
oc_surface_select(app->debugOverlay.surface);
|
|
|
|
oc_canvas_set_current(app->debugOverlay.canvas);
|
|
|
|
oc_render(app->debugOverlay.surface, app->debugOverlay.canvas);
|
|
|
|
oc_surface_present(app->debugOverlay.surface);
|
|
|
|
}
|
2023-06-26 18:00:29 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_ui_init(&app->debugOverlay.ui);
|
2023-04-14 09:48:36 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
//NOTE: show window and start runloop
|
|
|
|
oc_window_bring_to_front(app->window);
|
|
|
|
oc_window_focus(app->window);
|
|
|
|
oc_window_center(app->window);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_thread* runloopThread = oc_thread_create(orca_runloop, 0);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-30 10:06:32 +00:00
|
|
|
while(!app->quit)
|
2023-08-19 12:49:23 +00:00
|
|
|
{
|
|
|
|
oc_pump_events(-1);
|
|
|
|
//TODO: what to do with mem scratch here?
|
|
|
|
}
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_thread_join(runloopThread, NULL);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_canvas_destroy(app->debugOverlay.canvas);
|
|
|
|
oc_surface_destroy(app->debugOverlay.surface);
|
|
|
|
oc_window_destroy(app->window);
|
2023-04-12 14:21:03 +00:00
|
|
|
|
2023-08-19 12:49:23 +00:00
|
|
|
oc_terminate();
|
|
|
|
return (0);
|
2023-04-12 14:21:03 +00:00
|
|
|
}
|