diff --git a/src/app.c b/src/app.c index 6b2286ab..1f1848fb 100644 --- a/src/app.c +++ b/src/app.c @@ -268,8 +268,7 @@ void app_entry_point(struct string args_str) struct string logfile_path = string_cat(temp.arena, logfile_dir, logfile_name); sys_mkdir(logfile_dir); - struct log_startup_receipt log_sr = log_startup(logfile_path); - (UNUSED)log_sr; + log_startup(logfile_path); logf_info("Start of logs"); arena_temp_end(temp); } diff --git a/src/draw.c b/src/draw.c index f84b00c3..843f8f95 100644 --- a/src/draw.c +++ b/src/draw.c @@ -372,14 +372,12 @@ struct rect draw_text(struct gpu_cmd_buffer *cmdbuff, struct draw_text_params pa u64 num_line_glyphs = 0; struct drawable_glyph *line_glyphs = arena_dry_push(scratch.arena, struct drawable_glyph); - b32 submit_line = false; b32 line_done = false; while (!line_done) { string_done = !string_codepoint_iter_next(&iter); if (string_done) { line_done = true; } else { - submit_line = true; u32 codepoint = iter.codepoint; if (codepoint == '\n') { line_done = true; @@ -411,23 +409,21 @@ struct rect draw_text(struct gpu_cmd_buffer *cmdbuff, struct draw_text_params pa } /* Line ended */ - if (submit_line) { - /* TODO: Only create nodes for non-empty lines. Embed line number in the node. */ - struct drawable_line *node = arena_push(scratch.arena, struct drawable_line); - node->line_width = line_width; - node->num_glyphs = num_line_glyphs; - node->glyphs = line_glyphs; - if (last_line) { - last_line->next = node; - } else { - first_line = node; - first_line_top_offset = top_offset; - } - last_line = node; - last_line_bottom_offset = bottom_offset; - widest_line = max_f32(widest_line, line_width); - ++num_lines; + /* TODO: Only create nodes for non-empty lines. Embed line number in the node. */ + struct drawable_line *node = arena_push(scratch.arena, struct drawable_line); + node->line_width = line_width; + node->num_glyphs = num_line_glyphs; + node->glyphs = line_glyphs; + if (last_line) { + last_line->next = node; + } else { + first_line = node; + first_line_top_offset = top_offset; } + last_line = node; + last_line_bottom_offset = bottom_offset; + widest_line = max_f32(widest_line, line_width); + ++num_lines; } string_codepoint_iter_end(&iter); } @@ -453,12 +449,7 @@ struct rect draw_text(struct gpu_cmd_buffer *cmdbuff, struct draw_text_params pa /* Offset bounds Y */ switch (params.offset_y) { - case DRAW_TEXT_OFFSET_Y_TOP: - { - if (first_line) { - bounds.y -= first_line_top_offset; - } - } break; + case DRAW_TEXT_OFFSET_Y_TOP: break; case DRAW_TEXT_OFFSET_Y_CENTER: { bounds.y -= bounds.height / 2.f; @@ -466,7 +457,7 @@ struct rect draw_text(struct gpu_cmd_buffer *cmdbuff, struct draw_text_params pa case DRAW_TEXT_OFFSET_Y_BOTTOM: { if (last_line) { - bounds.y -= bounds.height - first_line_top_offset - last_line_bottom_offset; + bounds.y -= bounds.height + last_line_bottom_offset; } } break; } @@ -475,7 +466,7 @@ struct rect draw_text(struct gpu_cmd_buffer *cmdbuff, struct draw_text_params pa u64 line_number = 0; for (struct drawable_line *line = first_line; line; line = line->next) { struct v2 draw_pos = bounds.pos; - draw_pos.y += line_number * line_spacing; + draw_pos.y += line_number * line_spacing - first_line_top_offset; /* Alignment */ switch (params.alignment) { diff --git a/src/font.c b/src/font.c index 224c1519..bd1aeca4 100644 --- a/src/font.c +++ b/src/font.c @@ -156,8 +156,7 @@ INTERNAL WORK_TASK_FUNC_DEF(font_load_asset_task, vparams) font_task_params_release(params); - f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); - logf_info("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(elapsed)); + logf_success("Finished loading font \"%F\" (point size %F) in %F seconds", FMT_STR(path), FMT_FLOAT((f64)point_size), FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns))); asset_cache_mark_ready(asset, font); scratch_end(scratch); diff --git a/src/gpu_dx11.c b/src/gpu_dx11.c index 4abf7c6b..41ca891d 100644 --- a/src/gpu_dx11.c +++ b/src/gpu_dx11.c @@ -638,6 +638,7 @@ INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *sha __prof; struct temp_arena scratch = scratch_begin(arena); struct string error_str = ZI; + i64 start_ns = sys_time_ns(); struct string shader_name = string_from_cstr_no_limit(shader_desc->name_cstr); @@ -666,10 +667,12 @@ INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *sha logf_info("Compiling shader \"%F\"", FMT_STR(shader_name)); /* Compile shader */ /* TODO: pre-compile shaders w/ FXC? */ - HRESULT hr = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, (ID3DInclude *)&include_handler, "vs_main", "vs_5_0", flags, 0, &vs_blob, &error_blob); + struct string friendly_name = string_cat(scratch.arena, LIT("res/"), shader_name); + char *friendly_name_cstr = cstr_from_string(scratch.arena, friendly_name); + HRESULT hr = D3DCompile(shader_src.text, shader_src.len, friendly_name_cstr, NULL, (ID3DInclude *)&include_handler, "vs_main", "vs_5_0", flags, 0, &vs_blob, &error_blob); if (SUCCEEDED(hr)) { ID3D11Device_CreateVertexShader(G.dev, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), NULL, &shader->vs); - hr = D3DCompile(shader_src.text, shader_src.len, NULL, NULL, (ID3DInclude *)&include_handler, "ps_main", "ps_5_0", flags, 0, &ps_blob, &error_blob); + hr = D3DCompile(shader_src.text, shader_src.len, friendly_name_cstr, NULL, (ID3DInclude *)&include_handler, "ps_main", "ps_5_0", flags, 0, &ps_blob, &error_blob); if (SUCCEEDED(hr)) { ID3D11Device_CreatePixelShader(G.dev, ID3D10Blob_GetBufferPointer(ps_blob), ID3D10Blob_GetBufferSize(ps_blob), NULL, &shader->ps); success = true; @@ -688,9 +691,19 @@ INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *sha } /* Create device layout */ - ID3D11Device_CreateInputLayout(G.dev, shader_desc->input_layout_desc, elem_count, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), &shader->input_layout); + HRESULT hr = ID3D11Device_CreateInputLayout(G.dev, shader_desc->input_layout_desc, elem_count, ID3D10Blob_GetBufferPointer(vs_blob), ID3D10Blob_GetBufferSize(vs_blob), &shader->input_layout); + if (!SUCCEEDED(hr)) { + success = false; + error_str = LIT("Failed to create input layout"); + } } else { - error_str = LIT("Unknown error"); + success = false; + } + + if (!success || error_blob) { + if (error_str.len <= 0) { + error_str = LIT("Unknown error"); + } if (error_blob) { u64 error_blob_cstr_len = ID3D10Blob_GetBufferSize(error_blob); char *error_blob_cstr = (char *)ID3D10Blob_GetBufferPointer(error_blob); @@ -709,6 +722,10 @@ INTERNAL struct string shader_alloc(struct arena *arena, struct dx11_shader *sha } } + if (success) { + logf_success("Finished compiling shader \"%F\" in %F seconds", FMT_STR(shader_name), FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns))); + } + if (vs_blob) { ID3D10Blob_Release(vs_blob); } @@ -759,7 +776,7 @@ INTERNAL void reload_shader(struct dx11_shader *old_shader, struct dx11_shader_d *old_shader = new_shader; } else { error_msg = string_format(scratch.arena, - LIT("Failed to compile shader \"%F\":\n\n%F"), + LIT("Failed to compile shader \"%F\": %F"), FMT_STR(name), FMT_STR(comp_error)); shader_release(&new_shader); @@ -785,7 +802,7 @@ INTERNAL void reload_shader(struct dx11_shader *old_shader, struct dx11_shader_d INTERNAL RESOURCE_WATCH_CALLBACK_FUNC_DEF(shader_resource_watch_callback, name) { if (shader_set_dirty(name)) { - logf_info("Shader source file \"%F\" has changed", FMT_STR(name)); + logf_debug("Shader source file \"%F\" has changed", FMT_STR(name)); } } #endif diff --git a/src/log.c b/src/log.c index a2349885..32a82387 100644 --- a/src/log.c +++ b/src/log.c @@ -1,12 +1,12 @@ -#include "log.h" #include "scratch.h" +#include "log.h" #include "string.h" #include "atomic.h" struct log_event_callback { log_event_callback_func *func; - i32 level; struct log_event_callback *next; + i32 level; }; /* ========================== * @@ -15,9 +15,12 @@ struct log_event_callback { GLOBAL struct { struct atomic_i32 initialized; - struct sys_mutex mutex; - struct arena arena; - log_event_callback_func *callbacks_head; + + struct sys_mutex callbacks_mutex; + struct arena callbacks_arena; + struct log_event_callback *first_callback; + struct log_event_callback *last_callback; + struct sys_file file; b32 file_valid; } G = ZI, DEBUG_ALIAS(G, G_log); @@ -25,27 +28,32 @@ GLOBAL struct { GLOBAL READONLY struct log_level_settings g_log_level_settings[LOG_LEVEL_COUNT] = { [LOG_LEVEL_CRITICAL] = { LIT_NOCAST("CRITICAL"), - 0xFFFF00FF + COLOR_PURPLE }, [LOG_LEVEL_ERROR] = { LIT_NOCAST("ERROR"), - 0xFFFF0000 + COLOR_RED }, [LOG_LEVEL_WARNING] = { LIT_NOCAST("WARNING"), - 0xFFFFFF00 + COLOR_YELLOW + }, + + [LOG_LEVEL_SUCCESS] = { + LIT_NOCAST("SUCCESS"), + COLOR_GREEN }, [LOG_LEVEL_INFO] = { LIT_NOCAST("INFO"), - 0xFFFFFFFF + COLOR_WHITE }, [LOG_LEVEL_DEBUG] = { LIT_NOCAST("DEBUG"), - 0xFF30D5C8 + COLOR_BLUE } }; @@ -53,10 +61,10 @@ GLOBAL READONLY struct log_level_settings g_log_level_settings[LOG_LEVEL_COUNT] * Startup * ========================== */ -struct log_startup_receipt log_startup(struct string logfile_path) +void log_startup(struct string logfile_path) { - G.mutex = sys_mutex_alloc(); - G.arena = arena_alloc(GIGABYTE(64)); + G.callbacks_arena = arena_alloc(MEGABYTE(8)); + G.callbacks_mutex = sys_mutex_alloc(); if (logfile_path.len > 0) { /* Create / wipe log file */ sys_file_close(sys_file_open_write(logfile_path)); @@ -67,22 +75,28 @@ struct log_startup_receipt log_startup(struct string logfile_path) } } atomic_i32_eval_exchange(&G.initialized, 1); - return (struct log_startup_receipt) { 0 }; } /* ========================== * * Callback * ========================== */ -void log_register_callback(log_event_callback_func *func) +void log_register_callback(log_event_callback_func *func, i32 level) { - /* TODO */ - (UNUSED)func; -#if 0 if (!atomic_i32_eval(&G.initialized)) { return; } - struct sys_lock lock = sys_mutex_lock_e(&G.mutex); + struct sys_lock lock = sys_mutex_lock_e(&G.callbacks_mutex); + { + struct log_event_callback *callback = arena_push(&G.callbacks_arena, struct log_event_callback); + callback->func = func; + callback->level = level; + if (G.last_callback) { + G.last_callback->next = callback; + } else { + G.first_callback = callback; + } + G.last_callback = callback; + } sys_mutex_unlock(&lock); -#endif } /* ========================== * @@ -130,7 +144,9 @@ void _log(i32 level, struct string msg) struct temp_arena scratch = scratch_begin_no_conflict(); - struct sys_datetime lt = sys_local_time(); + struct sys_datetime datetime = sys_local_time(); + i64 time_ns = sys_time_ns(); + u32 tid = sys_thread_id(); struct log_level_settings settings = g_log_level_settings[level]; @@ -142,10 +158,10 @@ void _log(i32 level, struct string msg) LIT("[%F:%F:%F.%F] |%F| [%F] <%F:%F> %F"), /* Time */ - FMT_UINT_Z(lt.hour, 2), - FMT_UINT_Z(lt.minute, 2), - FMT_UINT_Z(lt.second, 2), - FMT_UINT_Z(lt.milliseconds, 3), + FMT_UINT_Z(datetime.hour, 2), + FMT_UINT_Z(datetime.minute, 2), + FMT_UINT_Z(datetime.second, 2), + FMT_UINT_Z(datetime.milliseconds, 3), /* TID */ FMT_UINT_Z(tid, 5), @@ -166,10 +182,10 @@ void _log(i32 level, struct string msg) LIT("[%F:%F:%F.%F] |%F| [%F] %F"), /* Time */ - FMT_UINT_Z(lt.hour, 2), - FMT_UINT_Z(lt.minute, 2), - FMT_UINT_Z(lt.second, 2), - FMT_UINT_Z(lt.milliseconds, 3), + FMT_UINT_Z(datetime.hour, 2), + FMT_UINT_Z(datetime.minute, 2), + FMT_UINT_Z(datetime.second, 2), + FMT_UINT_Z(datetime.milliseconds, 3), /* TID */ FMT_UINT_Z(tid, 5), @@ -185,6 +201,27 @@ void _log(i32 level, struct string msg) __profmsg((char *)msg.text, msg.len, settings.color); append_to_logfile(msg_formatted); + + /* Run callbacks */ + struct log_event event = ZI; + event.level = level; + event.msg = msg; + event.datetime = datetime; + event.time_ns = time_ns; +#if LOG_INCLUDE_SOURCE_LOCATION + event.file = file; + event.line = line; +#endif + { + struct sys_lock lock = sys_mutex_lock_s(&G.callbacks_mutex); + for (struct log_event_callback *callback = G.first_callback; callback; callback = callback->next) { + if (level <= callback->level) { + callback->func(event); + } + } + sys_mutex_unlock(&lock); + } + scratch_end(scratch); } diff --git a/src/log.h b/src/log.h index 24e565ff..055e3a9a 100644 --- a/src/log.h +++ b/src/log.h @@ -2,6 +2,7 @@ #define LOG_H #include "string.h" +#include "sys.h" #define LOG_LEVEL(l) (l <= LOG_LEVEL_COMPTIME) @@ -23,9 +24,10 @@ #define LOG_LEVEL_CRITICAL 0 #define LOG_LEVEL_ERROR 1 #define LOG_LEVEL_WARNING 2 -#define LOG_LEVEL_INFO 3 -#define LOG_LEVEL_DEBUG 4 -#define LOG_LEVEL_COUNT 5 +#define LOG_LEVEL_SUCCESS 3 +#define LOG_LEVEL_INFO 4 +#define LOG_LEVEL_DEBUG 5 +#define LOG_LEVEL_COUNT 6 /* ========================== * * Callback interface @@ -37,18 +39,22 @@ struct log_level_settings { }; struct log_event { + /* Msg lifetime is only as long as callback duration */ + struct string msg; i32 level; - struct string msg; /* Lifetime is only as long as the callback function call receiving the event */ - struct log_level_settings settings; + + struct sys_datetime datetime; + i64 time_ns; /* These will be nulled if LOG_INCLUDE_SOURCE_LOCATION is disabled */ struct string file; i32 line; }; -typedef void (log_event_callback_func)(struct log_event); +#define LOG_EVENT_CALLBACK_FUNC_DEF(name, log_event_arg) void name(struct log_event log_event_arg) +typedef LOG_EVENT_CALLBACK_FUNC_DEF(log_event_callback_func, log_event); -void log_register_callback(log_event_callback_func *func); +void log_register_callback(log_event_callback_func *func, i32 level); /* ========================== * * Logging macros @@ -95,20 +101,19 @@ void log_register_callback(log_event_callback_func *func); # define logf_warning(fmt_lit, ...) #endif -#if LOG_LEVEL(LOG_LEVEL_DEBUG) +#if LOG_LEVEL(LOG_LEVEL_SUCCESS) # if LOG_INCLUDE_SOURCE_LOCATION -# define log_debug(msg) _log(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, msg) -# define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) +# define log_success(msg) _log(LOG_LEVEL_SUCCESS, LIT(__FILE__), __LINE__, msg) +# define logf_success(fmt_lit, ...) _logf(LOG_LEVEL_SUCCESS, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # else -# define log_debug(msg) _log(LOG_LEVEL_DEBUG, msg) -# define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) +# define log_success(msg) _log(LOG_LEVEL_SUCCESS, msg) +# define logf_success(fmt_lit, ...) _logf(LOG_LEVEL_SUCCESS, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) # endif #else -# define log_debug(msg) -# define logf_debug(fmt_lit, ...) +# define log_success(msg) +# define logf_success(fmt_lit, ...) #endif - #if LOG_LEVEL(LOG_LEVEL_INFO) # if LOG_INCLUDE_SOURCE_LOCATION # define log_info(msg) _log(LOG_LEVEL_INFO, LIT(__FILE__), __LINE__, msg) @@ -122,12 +127,24 @@ void log_register_callback(log_event_callback_func *func); # define logf_info(fmt_lit, ...) #endif +#if LOG_LEVEL(LOG_LEVEL_DEBUG) +# if LOG_INCLUDE_SOURCE_LOCATION +# define log_debug(msg) _log(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, msg) +# define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(__FILE__), __LINE__, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) +# else +# define log_debug(msg) _log(LOG_LEVEL_DEBUG, msg) +# define logf_debug(fmt_lit, ...) _logf(LOG_LEVEL_DEBUG, LIT(fmt_lit) , ## __VA_ARGS__, FMT_END) +# endif +#else +# define log_debug(msg) +# define logf_debug(fmt_lit, ...) +#endif + /* ========================== * * Function declarations * ========================== */ -struct log_startup_receipt { i32 _; }; -struct log_startup_receipt log_startup(struct string logfile_path); +void log_startup(struct string logfile_path); void _log_panic(struct string msg); diff --git a/src/sim_step.c b/src/sim_step.c index 1e4584bd..c3830fd8 100644 --- a/src/sim_step.c +++ b/src/sim_step.c @@ -997,7 +997,7 @@ void sim_step(struct sim_step_ctx *ctx) test_clear_level(ctx); } if (flags & SIM_CONTROL_FLAG_SPAWN1_TEST) { - logf_info("Spawn test 1"); + logf_debug("Spawn test 1"); u32 count = 1; f32 spread = 0; for (u32 j = 0; j < count; ++j) { @@ -1007,7 +1007,7 @@ void sim_step(struct sim_step_ctx *ctx) } } if (flags & SIM_CONTROL_FLAG_SPAWN2_TEST) { - logf_info("Spawn test 2"); + logf_debug("Spawn test 2"); u32 count = 1; f32 spread = 0; for (u32 j = 0; j < count; ++j) { @@ -1017,7 +1017,7 @@ void sim_step(struct sim_step_ctx *ctx) } } if (flags & SIM_CONTROL_FLAG_SPAWN3_TEST) { - logf_info("Spawn test 3"); + logf_debug("Spawn test 3"); u32 count = 1; f32 spread = 0; for (u32 j = 0; j < count; ++j) { @@ -1030,7 +1030,7 @@ void sim_step(struct sim_step_ctx *ctx) test_generate_walls(world); } if (flags & SIM_CONTROL_FLAG_EXPLODE_TEST) { - logf_info("Explosion test"); + logf_debug("Explosion test"); test_spawn_explosion(root, player->player_cursor_pos, 100, 2); } } diff --git a/src/sound.c b/src/sound.c index 103c6cd2..f1093803 100644 --- a/src/sound.c +++ b/src/sound.c @@ -134,8 +134,7 @@ INTERNAL WORK_TASK_FUNC_DEF(sound_load_asset_task, vparams) sound->pcm.samples = samples; MEMCPY(sound->pcm.samples, decoded.pcm.samples, decoded.pcm.count * sizeof(*decoded.pcm.samples)); - f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); - logf_info("Finished loading sound \"%F\" in %F seconds", FMT_STR(path), FMT_FLOAT(elapsed)); + logf_success("Finished loading sound \"%F\" in %F seconds", FMT_STR(path), FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns))); asset_cache_mark_ready(asset, sound); } else { logf_error("Error loading sound \"%F\": %F", FMT_STR(path), FMT_STR(error_msg)); diff --git a/src/sprite.c b/src/sprite.c index 5c2ad8ce..6d93b6c7 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -351,6 +351,7 @@ INTERNAL void cache_entry_load_texture(struct cache_ref ref, struct sprite_tag t struct string path = tag.path; logf_info("Loading sprite texture [%F] \"%F\"", FMT_HEX(e->hash.v), FMT_STR(path)); + b32 success = false; i64 start_ns = sys_time_ns(); ASSERT(string_ends_with(path, LIT(".ase"))); @@ -388,18 +389,20 @@ INTERNAL void cache_entry_load_texture(struct cache_ref ref, struct sprite_tag t e->texture->loaded = true; /* TODO: Query gpu for more accurate texture size in VRAM */ memory_size += (decoded.image.width * decoded.image.height) * sizeof(*decoded.image.pixels); + success = true; } } arena_set_readonly(&e->arena); e->memory_usage = e->arena.committed + memory_size; atomic_u64_eval_add_u64(&G.cache.memory_usage, e->memory_usage); - f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); - logf_info("Finished loading sprite texture [%F] \"%F\" in %F seconds (cache size: %F bytes).", - FMT_HEX(e->hash.v), - FMT_STR(path), - FMT_FLOAT(elapsed), - FMT_UINT(e->memory_usage)); + if (success) { + logf_success("Finished loading sprite texture [%F] \"%F\" in %F seconds (cache size: %F bytes).", + FMT_HEX(e->hash.v), + FMT_STR(path), + FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns)), + FMT_UINT(e->memory_usage)); + } atomic_i32_eval_exchange(&e->state, CACHE_ENTRY_STATE_LOADED); @@ -676,6 +679,7 @@ INTERNAL void cache_entry_load_sheet(struct cache_ref ref, struct sprite_tag tag struct string path = tag.path; logf_info("Loading sprite sheet [%F] \"%F\"", FMT_HEX(e->hash.v), FMT_STR(path)); + b32 success = false; i64 start_ns = sys_time_ns(); ASSERT(e->kind == CACHE_ENTRY_KIND_SHEET); @@ -705,19 +709,21 @@ INTERNAL void cache_entry_load_sheet(struct cache_ref ref, struct sprite_tag tag *e->sheet = init_sheet_from_ase_result(&e->arena, decoded); e->sheet->loaded = true; e->sheet->valid = true; + + success = true; } } arena_set_readonly(&e->arena); e->memory_usage = e->arena.committed; atomic_u64_eval_add_u64(&G.cache.memory_usage, e->memory_usage); - f64 elapsed = SECONDS_FROM_NS(sys_time_ns() - start_ns); - logf_info("Finished loading sprite sheet [%F] \"%F\" in %F seconds (cache size: %F bytes).", - FMT_HEX(e->hash.v), - FMT_STR(path), - FMT_FLOAT(elapsed), - FMT_UINT(e->memory_usage)); - + if (success) { + logf_success("Finished loading sprite sheet [%F] \"%F\" in %F seconds (cache size: %F bytes).", + FMT_HEX(e->hash.v), + FMT_STR(path), + FMT_FLOAT(SECONDS_FROM_NS(sys_time_ns() - start_ns)), + FMT_UINT(e->memory_usage)); + } atomic_i32_eval_exchange(&e->state, CACHE_ENTRY_STATE_LOADED); diff --git a/src/sys_win32.c b/src/sys_win32.c index 485ae03d..e58baf21 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -683,9 +683,6 @@ struct win32_watch { HANDLE dir_handle; HANDLE wake_handle; struct win32_watch *next_free; - - u64 dir_path_len; - u8 dir_path_text[1024]; u8 results_buff[KILOBYTE(64)]; }; @@ -708,23 +705,6 @@ struct sys_watch sys_watch_alloc(struct string dir_path) } MEMZERO_STRUCT(w32_watch); - if (dir_path.len > 0 && dir_path.len < (ARRAY_COUNT(w32_watch->dir_path_text) - 1)) { - u64 dir_path_len = dir_path.len; - MEMCPY(w32_watch->dir_path_text, dir_path.text, dir_path_len); - for (u64 i = 0; i < dir_path_len; ++i) { - if (w32_watch->dir_path_text[i] == '\\') { - w32_watch->dir_path_text[i] = '/'; - } - } - if (w32_watch->dir_path_text[dir_path_len - 1] != '/') { - w32_watch->dir_path_text[dir_path_len] = '/'; - ++dir_path_len; - } - w32_watch->dir_path_len = dir_path_len; - } else { - sys_panic(string_format(scratch.arena, LIT("Directory path too \"%F\" has invalid length"), FMT_STR(dir_path))); - } - wchar_t *dir_path_wstr = wstr_from_string(scratch.arena, dir_path); w32_watch->dir_handle = CreateFileW( dir_path_wstr, @@ -812,8 +792,7 @@ struct sys_watch_info_list sys_watch_wait(struct arena *arena, struct sys_watch name16.text = res->FileName; name16.len = res->FileNameLength / sizeof(wchar_t); - info->name = string_copy(arena, STRING(w32_watch->dir_path_len, w32_watch->dir_path_text)); - info->name.len += string_from_string16(arena, name16).len; + info->name = string_from_string16(arena, name16); for (u64 i = 0; i < info->name.len; ++i) { if (info->name.text[i] == '\\') { info->name.text[i] = '/'; diff --git a/src/user.c b/src/user.c index 4550d3ed..c9a73c8d 100644 --- a/src/user.c +++ b/src/user.c @@ -37,6 +37,17 @@ struct second_stat { u64 last_second; }; +struct console_log { + struct string msg; + i32 level; + i32 index; + struct sys_datetime datetime; + i64 time_ns; + struct rect bounds; + struct console_log *prev; + struct console_log *next; +}; + GLOBAL struct { struct atomic_i32 user_thread_shutdown; struct sys_thread user_thread; @@ -74,13 +85,20 @@ GLOBAL struct { struct bind_state bind_states[USER_BIND_KIND_COUNT]; + /* Debug camera */ struct sim_ent_id debug_following; b32 debug_camera; b32 debug_camera_panning; struct v2 debug_camera_pan_start; - b32 debug_draw; + /* Debug console */ + struct sys_mutex console_logs_mutex; + struct arena console_logs_arena; + struct console_log *first_console_log; + struct console_log *last_console_log; + f32 console_logs_height; + /* Window -> user */ struct sys_mutex sys_events_mutex; struct arena sys_events_arena; @@ -178,6 +196,7 @@ GLOBAL READONLY enum user_bind_kind g_binds[SYS_BTN_COUNT] = { * ========================== */ INTERNAL APP_EXIT_CALLBACK_FUNC_DEF(user_shutdown); +INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log); INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_thread_entry_point, arg); INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg); INTERNAL SYS_WINDOW_EVENT_CALLBACK_FUNC_DEF(window_event_callback, event); @@ -239,12 +258,17 @@ struct user_startup_receipt user_startup(struct work_startup_receipt *work_sr, G.final_cmd_buffer = gpu_cmd_buffer_alloc(); G.backbuffer_cmd_buffer = gpu_cmd_buffer_alloc(); + //log_register_callback(debug_console_log_callback, LOG_LEVEL_SUCCESS); + log_register_callback(debug_console_log_callback, LOG_LEVEL_INFO); + G.console_logs_mutex = sys_mutex_alloc(); + G.console_logs_arena = arena_alloc(GIGABYTE(64)); + G.window = window; sys_window_register_event_callback(G.window, &window_event_callback); G.local_sim_thread = sys_thread_alloc(&user_local_sim_thread_entry_point, G.local_sim_ctx, LIT("[P8] Local sim thread")); - G.debug_draw = true; + //G.debug_draw = true; G.user_thread = sys_thread_alloc(&user_thread_entry_point, NULL, LIT("[P9] User thread")); app_register_exit_callback(&user_shutdown); @@ -435,6 +459,106 @@ INTERNAL struct string get_ent_debug_text(struct arena *arena, struct sim_ent *e return res; } +/* ========================== * + * Debug console + * ========================== */ + +INTERNAL LOG_EVENT_CALLBACK_FUNC_DEF(debug_console_log_callback, log) +{ + struct sys_lock lock = sys_mutex_lock_e(&G.console_logs_mutex); + { + struct console_log *clog = arena_push(&G.console_logs_arena, struct console_log); + clog->level = log.level; + clog->msg = string_copy(&G.console_logs_arena, log.msg); + clog->datetime = log.datetime; + clog->time_ns = log.time_ns; + + if (G.last_console_log) { + G.last_console_log->next = clog; + clog->prev = G.last_console_log; + clog->index = G.last_console_log->index + 1; + } else { + G.first_console_log = clog; + } + G.last_console_log = clog; + } + sys_mutex_unlock(&lock); +} + +INTERNAL void draw_debug_console(b32 minimized) +{ + struct temp_arena scratch = scratch_begin_no_conflict(); + + struct v2 desired_start_pos = V2(10, 400); + i64 fade_time_ns = NS_FROM_SECONDS(10); + f32 fade_curve = 0.5; + f32 spacing = 0; + f32 bg_margin = 5; + u32 info_colors[2] = { RGB_F(0.4, 0.4, 0.4), RGB_F(0.5, 0.5, 0.5) }; + u32 success_colors[2] = { RGB_F(0.1, 0.3, 0.1), RGB_F(0.2, 0.4, 0.2) }; + u32 warning_colors[2] = { RGB_F(0.4, 0.4, 0.1), RGB_F(0.5, 0.5, 0.2) }; + u32 error_colors[2] = { RGB_F(0.4, 0.1, 0.1), RGB_F(0.5, 0.2, 0.2) }; + + struct v2 draw_pos = desired_start_pos; + f32 bounds_top = F32_INFINITY; + f32 bounds_bottom = -F32_INFINITY; + + if (G.console_logs_height < desired_start_pos.y) { + draw_pos.y = G.console_logs_height; + } + G.console_logs_height = 0; + + i64 now_ns = sys_time_ns(); + struct font *font = font_load_async(LIT("fonts/fixedsys.ttf"), 12.0f); + if (font) { + struct sys_lock lock = sys_mutex_lock_e(&G.console_logs_mutex); + { + for (struct console_log *log = G.last_console_log; log; log = log->prev) { + f32 opacity = 0.75; + if (minimized) { + f32 lin = 1.0 - clamp_f64((f64)(now_ns - log->time_ns) / (f64)fade_time_ns, 0, 1); + opacity *= math_pow(lin, fade_curve); + } + if (draw_pos.y > -desired_start_pos.y && opacity > 0) { + /* Draw background */ + u32 color_index = log->index & 1; /* Alternate colors for greater distinction between logs */ + u32 color = info_colors[color_index]; + switch (log->level) { + default: break; + case LOG_LEVEL_ERROR: color = error_colors[color_index]; break; + case LOG_LEVEL_WARNING: color = warning_colors[color_index]; break; + case LOG_LEVEL_SUCCESS: color = success_colors[color_index]; break; + } + draw_quad(G.ui_cmd_buffer, quad_from_rect(log->bounds), ALPHA_F(color, opacity)); + + /* Draw text */ + struct string text = log->msg; + struct draw_text_params params = DRAW_TEXT_PARAMS(.font = font, .pos = draw_pos, .offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM, .color = ALPHA_F(COLOR_WHITE, opacity), .str = text); + struct rect bounds = draw_text(G.ui_cmd_buffer, params); + + struct rect draw_bounds = bounds; + draw_bounds.x -= bg_margin; + draw_bounds.y -= bg_margin; + draw_bounds.width += bg_margin * 2.f; + draw_bounds.height += bg_margin * 2.f; + draw_pos.y -= draw_bounds.height + spacing; + log->bounds = draw_bounds; + + bounds_top = min_f32(bounds_top, draw_bounds.y); + bounds_bottom = max_f32(bounds_bottom, draw_bounds.y + draw_bounds.height); + } else { + break; + } + } + } + sys_mutex_unlock(&lock); + } + if (bounds_top < F32_INFINITY && bounds_bottom > -F32_INFINITY) { + G.console_logs_height = bounds_bottom - bounds_top; + } + scratch_end(scratch); +} + /* ========================== * * Sort entities * ========================== */ @@ -1880,9 +2004,16 @@ INTERNAL void user_update(void) draw_text(G.ui_cmd_buffer, DRAW_TEXT_PARAMS(.font = font, .pos = pos, .str = text, .offset_y = DRAW_TEXT_OFFSET_Y_BOTTOM, .color = COLOR_WHITE)); arena_temp_end(temp); } - } +#if DEVELOPER + draw_debug_console(!G.debug_draw); +#else + if (G.debug_draw) { + draw_debug_console(false); + } +#endif + /* ========================== * * Render * ========================== */ @@ -2601,19 +2732,6 @@ INTERNAL SYS_THREAD_ENTRY_POINT_FUNC_DEF(user_local_sim_thread_entry_point, arg) } } - - - - - - - - - - - - - /* Publish snapshot to remote clients */ for (u64 i = 0; i < store->num_clients_reserved; ++i) { struct sim_client *client = &store->clients[i];