power_play/src/app.c
2025-07-14 17:04:39 -05:00

330 lines
10 KiB
C

#include "app.h"
#include "arena.h"
#include "string.h"
#include "sys.h"
#include "user.h"
#include "sim.h"
#include "playback.h"
#include "log.h"
#include "resource.h"
#include "asset_cache.h"
#include "font.h"
#include "sprite.h"
#include "ttf.h"
#include "mixer.h"
#include "sound.h"
#include "util.h"
#include "settings.h"
#include "draw.h"
#include "math.h"
#include "gp.h"
#include "phys.h"
#include "host.h"
#include "bitbuff.h"
GLOBAL struct {
struct arena *arena;
struct string write_path;
} G = ZI, DEBUG_ALIAS(G, G_app);
/* ========================== *
* Write directory
* ========================== */
INTERNAL struct string initialize_write_directory(struct arena *arena, struct string write_dir)
{
struct arena_temp scratch = scratch_begin(arena);
/* Create write path */
struct string base_write_dir = sys_get_write_path(scratch.arena);
struct string write_path_fmt = base_write_dir.len > 0 ? LIT("%F/%F/") : LIT("%F%F/");
struct string write_path = string_format(
arena,
write_path_fmt,
FMT_STR(base_write_dir),
FMT_STR(write_dir)
);
/* Create write dir if not present */
if (!sys_is_dir(write_path)) {
sys_mkdir(write_path);
/* TODO: handle failure */
}
scratch_end(scratch);
return write_path;
}
struct string app_write_path_cat(struct arena *arena, struct string filename)
{
return string_cat(arena, G.write_path, filename);
}
/* ========================== *
* Default settings
* ========================== */
INTERNAL struct sys_window_settings default_window_settings(struct sys_window *window)
{
__prof;
struct v2 monitor_size = sys_window_get_monitor_size(window);
i32 width = 1280;
i32 height = math_round_to_int(width / (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT));
i32 x = math_round_to_int(monitor_size.x / 2.f - width / 2);
i32 y = math_round_to_int(monitor_size.y / 2.f - height / 2);
return (struct sys_window_settings) {
.title = WINDOW_TITLE,
.floating_x = x,
.floating_y = y,
.floating_width = width,
.floating_height = height
};
}
/* ========================== *
* Args
* ========================== */
struct app_arg {
struct string key;
struct string value;
struct app_arg *next;
};
struct app_arg_list {
struct app_arg *first;
struct app_arg *last;
u64 count;
};
/* TODO: Remove this and do real argument parsing */
INTERNAL struct app_arg_list parse_args(struct arena *arena, struct string args_str)
{
struct app_arg_list res = ZI;
i64 mode = 0;
i64 i = 0;
i64 key_start = -1;
i64 key_end = -1;
i64 value_start = -1;
i64 value_end = -1;
while (i < (i64)args_str.len) {
u8 c = args_str.text[i];
switch (mode) {
case 0:
{
if (c == '-') {
mode = 1;
key_start = i + 1;
}
++i;
} break;
case 1:
{
if (c == '=') {
key_end = i;
value_start = i + 1;
mode = 2;
}
++i;
} break;
case 2:
{
if (c == '-' || i == (i64)args_str.len - 1) {
if (c == '-') {
value_end = i;
} else {
value_end = i + 1;
}
if (key_start >= 0 && key_end > key_start && key_end <= (i64)args_str.len && value_start >= 0 && value_end > value_start && value_end <= (i64)args_str.len) {
struct string key = string_copy(arena, STRING(key_end - key_start, args_str.text + key_start));
struct string value = string_copy(arena, STRING(value_end - value_start, args_str.text + value_start));
struct app_arg *arg = arena_push(arena, struct app_arg);
arg->key = key;
arg->value = value;
if (res.last) {
res.last->next = arg;
} else {
res.first = arg;
}
res.last = arg;
++res.count;
}
key_start = i + 1;
mode = 1;
}
++i;
} break;
default: break;
}
}
return res;
}
/* ========================== *
* Entry point
* ========================== */
void sys_app_startup(struct string args_str)
{
__prof;
struct arena_temp scratch = scratch_begin_no_conflict();
struct app_arg_list args = parse_args(scratch.arena, args_str);
struct string logfile_name = LIT("log.log");
struct string settings_file_name = LIT("settings.txt");
struct string connect_address = ZI;
for (struct app_arg *arg = args.first; arg; arg = arg->next) {
struct string key = arg->key;
struct string value = arg->value;
if (string_eq(key, LIT("log"))) {
logfile_name = value;
} else if (string_eq(key, LIT("settings"))) {
settings_file_name = value;
} else if (string_eq(key, LIT("connect"))) {
connect_address = value;
}
}
(UNUSED)args;
(UNUSED)logfile_name;
(UNUSED)settings_file_name;
(UNUSED)connect_address;
(UNUSED)default_window_settings;
#if !RTC
/* Verify test modes aren't left on by accident in release mode */
STATIC_ASSERT(BITBUFF_DEBUG == 0);
STATIC_ASSERT(BITBUFF_TEST == 0);
#endif
#if BITBUFF_TEST
bitbuff_test();
#endif
G.arena = arena_alloc(GIBI(64));
G.write_path = initialize_write_directory(G.arena, LIT(WRITE_DIR));
/* Startup logging */
{
struct arena_temp temp = arena_temp_begin(scratch.arena);
struct string logfile_dir = string_cat(temp.arena, G.write_path, LIT("logs/"));
struct string logfile_path = string_cat(temp.arena, logfile_dir, logfile_name);
sys_mkdir(logfile_dir);
log_startup(logfile_path);
logf_info("Start of logs");
arena_temp_end(temp);
}
logf_info("App started with args \"%F\" (%F parsed)", FMT_STR(args_str), FMT_UINT(args.count));
for (struct app_arg *arg = args.first; arg; arg = arg->next) {
logf_info("Parsed arg: key = \"%F\", value = \"%F\"", FMT_STR(arg->key), FMT_STR(arg->value));
}
#if 0
/* Read window settings from file */
{
struct arena_temp temp = arena_temp_begin(scratch.arena);
struct sys_window_settings window_settings = ZI;
struct string settings_path = app_write_path_cat(temp.arena, settings_file_name);
logf_info("Looking for settings file \"%F\"", FMT_STR(settings_path));
if (sys_is_file(settings_path)) {
logf_info("Settings file found");
struct sys_file settings_file = sys_file_open_read(settings_path);
struct string file_data = sys_file_read_all(temp.arena, settings_file);
sys_file_close(settings_file);
logf_info("Deserializing settings file data: %F", FMT_STR(file_data));
struct string error = ZI;
struct sys_window_settings *res = settings_deserialize(temp.arena, file_data, &error);
if (error.len > 0) {
logf_info("Failed to load settings file with error - %F", FMT_STR(error));
struct string msg = string_format(temp.arena,
LIT(
"Failed to loading settings file \"%F\":\n"
"------------\n"
"%F\n"
"------------\n"
"To stop this error from appearing, either fix the issue above or delete the file from the system."
),
FMT_STR(settings_path),
FMT_STR(error));
sys_panic(msg);
}
logf_info("Settings file loaded successfully");
window_settings = *res;
} else {
logf_info("Settings file not found, loading default");
window_settings = default_window_settings(window);
}
string_copy_to_string(STRING_FROM_ARRAY(window_settings.title), LIT(WINDOW_TITLE));
sys_window_update_settings(window, &window_settings);
arena_temp_end(temp);
}
#endif
/* Global systems */
resource_startup();
gp_startup();
/* Subsystems */
struct host_startup_receipt host_sr = host_startup();
struct asset_cache_startup_receipt asset_cache_sr = asset_cache_startup();
struct ttf_startup_receipt ttf_sr = ttf_startup();
struct font_startup_receipt font_sr = font_startup(&asset_cache_sr, &ttf_sr);
struct sprite_startup_receipt sprite_sr = sprite_startup();
struct mixer_startup_receipt mixer_sr = mixer_startup();
struct sound_startup_receipt sound_sr = sound_startup(&asset_cache_sr);
struct draw_startup_receipt draw_sr = draw_startup(&font_sr);
struct sim_startup_receipt sim_sr = sim_startup();
/* Interface systems */
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
struct user_startup_receipt user_sr = user_startup(&font_sr, &sprite_sr, &draw_sr, &asset_cache_sr, &sound_sr, &mixer_sr, &host_sr, &sim_sr, connect_address);
(UNUSED)user_sr;
(UNUSED)playback_sr;
#if 0
/* Write window settings to file */
{
__profn("Write settings file");
struct arena_temp temp = arena_temp_begin(scratch.arena);
struct string window_settings_path = app_write_path_cat(temp.arena, settings_file_name);
struct sys_window_settings settings = sys_window_get_settings(window);
struct string str = settings_serialize(temp.arena, &settings);
logf_info("Serialized window settings: %F", FMT_STR(str));
logf_info("Writing settings file to path \"%F\"", FMT_STR(window_settings_path));
struct sys_file settings_file = sys_file_open_write(window_settings_path);
sys_file_write(settings_file, str);
sys_file_close(settings_file);
logf_info("Finished writing settings file");
arena_temp_end(temp);
}
#endif
#if 0
sys_window_release(window);
#endif
//logf_info("Program exited normally");
scratch_end(scratch);
}