First draft of in-app debug console

This commit is contained in:
Martin Fouilleul 2023-04-20 15:47:18 +02:00
parent eb09d73fa8
commit 28a4fe0579
8 changed files with 292 additions and 49 deletions

@ -1 +1 @@
Subproject commit bb6b68ad73b89e0481c3c684e65ac5b10ee1732c
Subproject commit 7c273f494bd3a4141ff9a085d888616f959c7938

BIN
resources/Menlo Bold.ttf Normal file

Binary file not shown.

BIN
resources/Menlo Italics.ttf Normal file

Binary file not shown.

BIN
resources/Menlo.ttf Normal file

Binary file not shown.

View File

@ -56,11 +56,24 @@ void OnFrameResize(u32 width, u32 height)
void OnMouseDown(int button)
{
log_info("mouse down!");
rotationDir *= -1;
}
void OnKeyDown(int key)
{
if(key == KEY_SPACE)
{
log_error("(this is just for testing errors)");
return;
}
if(key == KEY_ENTER)
{
log_warning("(this is just for testing warning)");
return;
}
log_info("key down: %i", key);
if(key == KEY_LEFT)
{
leftDown = true;
@ -73,6 +86,12 @@ void OnKeyDown(int key)
void OnKeyUp(int key)
{
if(key == KEY_ENTER || key == KEY_SPACE)
{
return;
}
log_info("key up: %i", key);
if(key == KEY_LEFT)
{
leftDown = false;
@ -124,6 +143,8 @@ void OnFrameRefresh(void)
{
velocity.y *= -1;
ball.y = paddle.y + paddle.h;
log_info("PONG!");
}
if(ball.y <= 0)

View File

@ -78,7 +78,9 @@ if args.res_dirs != None:
# default fonts
shutil.copy(args.orca_dir + '/resources/OpenSansLatinSubset.ttf', res_dir)
shutil.copy(args.orca_dir + '/resources/Andale Mono.ttf', res_dir)
shutil.copy(args.orca_dir + '/resources/Menlo.ttf', res_dir)
shutil.copy(args.orca_dir + '/resources/Menlo Bold.ttf', res_dir)
shutil.copy(args.orca_dir + '/resources/Menlo Italics.ttf', res_dir)
#-----------------------------------------------------------
#NOTE make icon
#-----------------------------------------------------------

View File

@ -1,7 +1,7 @@
orca_log_entry v(iipipiip)
orca_log v(iipipiip)
cosf f(f)
sinf f(f)
floorf f(f)
sqrtf f(f)
orca_mem_grow i(I)
orca_assert i(ppipp)
orca_assert i(ppipp)

View File

@ -19,30 +19,6 @@
#define LOG_SUBSYSTEM "Orca"
/*
void orca_log(int len, const char* ptr)
{
log_info("%.*s", len, ptr);
}
*/
void orca_log_entry(log_level level,
int fileLen,
char* file,
int functionLen,
char* function,
int line,
int msgLen,
char* msg)
{
log_entry(level,
str8_from_buffer(fileLen, file),
str8_from_buffer(functionLen, function),
line,
"%.*s\n",
msgLen,
msg);
}
void mg_matrix_push_flat(float a11, float a12, float a13,
float a21, float a22, float a23)
@ -111,26 +87,40 @@ mg_font mg_font_create_default()
}
#include"bindgen_core_api.c"
#include"canvas_api_bind.c"
#include"bindgen_gles_api.c"
#include"manual_gles_api.c"
typedef struct log_entry
{
list_elt listElt;
u64 cap;
log_level level;
str8 file;
str8 function;
int line;
str8 msg;
u64 recordIndex;
} log_entry;
typedef struct orca_debug_overlay
{
bool show;
mg_surface surface;
mg_canvas canvas;
mg_font font;
mg_font fontReg;
mg_font fontBold;
ui_context ui;
} orca_debug_overlay;
void debug_overlay_toogle(orca_debug_overlay* overlay)
{
overlay->show = !overlay->show;
mg_surface_set_hidden(overlay->surface, !overlay->show);
}
mem_arena logArena;
list_info logEntries;
list_info logFreeList;
u32 entryCount;
u32 maxEntries;
u64 logEntryTotalCount;
bool logScrollToLast;
} orca_debug_overlay;
typedef struct orca_app
{
@ -144,6 +134,153 @@ typedef struct orca_app
} orca_app;
orca_app __orcaApp = {0};
void orca_log(log_level level,
int fileLen,
char* file,
int functionLen,
char* function,
int line,
int msgLen,
char* msg)
{
orca_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 = list_pop_entry(&debug->logEntries, log_entry, listElt);
if(e)
{
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;
for_list(&debug->logFreeList, elt, log_entry, listElt)
{
if(elt->cap >= cap)
{
list_remove(&debug->logFreeList, &elt->listElt);
entry = elt;
break;
}
}
if(!entry)
{
char* mem = mem_arena_alloc(&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, fileLen);
memcpy(entry->msg.ptr, msg, msgLen);
entry->level = level;
entry->line = line;
entry->recordIndex = debug->logEntryTotalCount;
debug->logEntryTotalCount++;
list_push_back(&debug->logEntries, &entry->listElt);
log_push(level,
str8_from_buffer(fileLen, file),
str8_from_buffer(functionLen, function),
line,
"%.*s\n",
msgLen,
msg);
}
void debug_overlay_toggle(orca_debug_overlay* overlay)
{
overlay->show = !overlay->show;
mg_surface_set_hidden(overlay->surface, !overlay->show);
if(overlay->show)
{
overlay->logScrollToLast = true;
}
}
void log_entry_ui(orca_debug_overlay* overlay, log_entry* entry)
{
static const char* levelNames[] = {"Error: ", "Warning: ", "Info: "};
static const mg_color levelColors[] = {{0.8, 0, 0, 1},
{1, 0.5, 0, 1},
{0, 0.8, 0, 1}};
static const mg_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}}};
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_CHILDREN},
.layout.axis = UI_AXIS_Y,
.layout.margin.x = 10,
.layout.margin.y = 5,
.bgColor = bgColors[entry->level][entry->recordIndex & 1]},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_AXIS
|UI_STYLE_LAYOUT_MARGINS
|UI_STYLE_BG_COLOR);
str8 key = str8_pushf(mem_scratch(), "%ull", entry->recordIndex);
ui_container_str8(key, UI_FLAG_DRAW_BACKGROUND)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_CHILDREN},
.layout.axis = UI_AXIS_X},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_AXIS);
ui_container("header", 0)
{
ui_style_next(&(ui_style){.color = levelColors[entry->level],
.font = overlay->fontBold},
UI_STYLE_COLOR
|UI_STYLE_FONT);
ui_label(levelNames[entry->level]);
str8 loc = str8_pushf(mem_scratch(),
"%.*s() in %.*s:%i:",
str8_ip(entry->file),
str8_ip(entry->function),
entry->line);
ui_label_str8(loc);
}
ui_label_str8(entry->msg);
}
}
char m3_type_to_tag(M3ValueType type)
{
switch(type)
@ -173,13 +310,17 @@ void orca_runtime_init(orca_runtime* runtime)
runtime->wasmMemory.ptr = mem_base_reserve(allocator, runtime->wasmMemory.reserved);
}
orca_app __orcaApp;
orca_runtime* orca_runtime_get()
{
return(&__orcaApp.runtime);
}
#include"bindgen_core_api.c"
#include"canvas_api_bind.c"
#include"bindgen_gles_api.c"
#include"manual_gles_api.c"
void* orca_runloop(void* user)
{
orca_app* app = &__orcaApp;
@ -368,6 +509,8 @@ void* orca_runloop(void* user)
mp_rect frame = {0, 0, event->frame.rect.w, event->frame.rect.h};
mg_surface_set_frame(app->surface, frame);
mg_surface_set_frame(app->debugOverlay.surface, frame);
if(eventHandlers[G_EVENT_FRAME_RESIZE])
{
u32 width = (u32)event->frame.rect.w;
@ -414,7 +557,7 @@ void* orca_runloop(void* user)
{
if(event->key.code == MP_KEY_D && (event->key.mods & (MP_KEYMOD_SHIFT | MP_KEYMOD_CMD)))
{
debug_overlay_toogle(&app->debugOverlay);
debug_overlay_toggle(&app->debugOverlay);
}
if(eventHandlers[G_EVENT_KEY_DOWN])
@ -451,7 +594,7 @@ void* orca_runloop(void* user)
{
ui_style debugUIDefaultStyle = {.bgColor = {0},
.color = {1, 1, 1, 1},
.font = app->debugOverlay.font,
.font = app->debugOverlay.fontReg,
.fontSize = 16,
.borderColor = {1, 0, 0, 1},
.borderSize = 2};
@ -476,26 +619,101 @@ void* orca_runloop(void* user)
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 0.4},
.layout.axis = UI_AXIS_Y,
.bgColor = {0, 0, 0, 0.5}},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_AXIS
|UI_STYLE_BG_COLOR);
ui_container("log console", UI_FLAG_DRAW_BACKGROUND)
{
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 1}},
.size.height = {UI_SIZE_CHILDREN},
.layout.axis = UI_AXIS_X,
.layout.spacing = 10,
.layout.margin.x = 10,
.layout.margin.y = 10},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT);
ui_container("log toolbar", 0)
{
ui_style buttonStyle = {.layout.margin.x = 4,
.layout.margin.y = 4,
.roundness = 2,
.bgColor = {0, 0, 0, 0.5},
.color = {1, 1, 1, 1}};
ui_style_mask buttonStyleMask = UI_STYLE_LAYOUT_MARGINS
| UI_STYLE_ROUNDNESS
| UI_STYLE_BG_COLOR
| UI_STYLE_COLOR;
ui_style_match_after(ui_pattern_all(), &buttonStyle, buttonStyleMask);
if(ui_button("Clear").clicked)
{
for_list_safe(&app->debugOverlay.logEntries, entry, log_entry, listElt)
{
list_remove(&app->debugOverlay.logEntries, &entry->listElt);
list_push(&app->debugOverlay.logFreeList, &entry->listElt);
app->debugOverlay.entryCount--;
}
}
}
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PARENT, 1, 1}},
UI_STYLE_SIZE);
ui_panel("log console", UI_FLAG_CLICKABLE)
//TODO: this is annoying to have to do that. Basically there's another 'contents' box inside ui_panel,
// and we need to change that to size according to its parent (whereas the default is sizing according
// to its children)
ui_pattern pattern = {0};
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_OWNER});
ui_pattern_push(mem_scratch(), &pattern, (ui_selector){.kind = UI_SEL_TEXT, .text = STR8("contents")});
ui_style_match_after(pattern, &(ui_style){.size.width = {UI_SIZE_PARENT, 1}}, UI_STYLE_SIZE_WIDTH);
ui_box* panel = ui_box_lookup("log view");
f32 scrollY = 0;
if(panel)
{
scrollY = panel->scroll.y;
}
ui_panel("log view", UI_FLAG_SCROLL_WHEEL_Y)
{
panel = ui_box_top();
ui_style_next(&(ui_style){.size.width = {UI_SIZE_PARENT, 1},
.size.height = {UI_SIZE_PIXELS, 800}},
UI_STYLE_SIZE);
.size.height = {UI_SIZE_CHILDREN},
.layout.axis = UI_AXIS_Y,
.layout.margin.y = 5},
UI_STYLE_SIZE
|UI_STYLE_LAYOUT_AXIS);
ui_container("contents", 0)
{
for_list(&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 = ClampLowBound(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;
}
}
}
@ -512,7 +730,6 @@ void* orca_runloop(void* user)
*/
mg_present();
}
mem_scratch_clear();
}
@ -538,7 +755,10 @@ int main(int argc, char** argv)
orca->debugOverlay.show = false;
orca->debugOverlay.surface = mg_surface_create_for_window(orca->window, MG_BACKEND_DEFAULT);
orca->debugOverlay.canvas = mg_canvas_create(orca->debugOverlay.surface);
orca->debugOverlay.font = orca_font_create("../resources/Andale Mono.ttf");
orca->debugOverlay.fontReg = orca_font_create("../resources/Menlo.ttf");
orca->debugOverlay.fontBold = orca_font_create("../resources/Menlo Bold.ttf");
orca->debugOverlay.maxEntries = 30;
mem_arena_init(&orca->debugOverlay.logArena);
mg_surface_set_hidden(orca->debugOverlay.surface, true);