rewrite json parser to be dumber
This commit is contained in:
parent
fec692b434
commit
900e841228
@ -145,6 +145,7 @@ target_precompile_headers(powerplay_exe PRIVATE src/common.h)
|
|||||||
set(COMPILER_FLAGS "
|
set(COMPILER_FLAGS "
|
||||||
-fno-strict-aliasing \
|
-fno-strict-aliasing \
|
||||||
-fno-finite-loops \
|
-fno-finite-loops \
|
||||||
|
-fwrapv \
|
||||||
-msse4.2 \
|
-msse4.2 \
|
||||||
")
|
")
|
||||||
|
|
||||||
@ -175,9 +176,10 @@ if (RTC)
|
|||||||
message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)")
|
message(FATAL_ERROR "CRTLIB (C runtime library) Must be enabled when compiling with RTC (runtime checks)")
|
||||||
endif()
|
endif()
|
||||||
# NOTE: Adress sanitizer is disabled for now because for some reason it's screwing up viewing local variables while debugging.
|
# NOTE: Adress sanitizer is disabled for now because for some reason it's screwing up viewing local variables while debugging.
|
||||||
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -DRTC=1")
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -DRTC=1")
|
||||||
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -fno-sanitize=alignment -DRTC=1")
|
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -fsanitize-trap=undefined -DRTC=1")
|
||||||
set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -fsanitize-trap=undefined -fno-sanitize=alignment -DRTC=1")
|
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=undefined -DRTC=1")
|
||||||
|
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=address -fsanitize=undefined -DRTC=1")
|
||||||
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=address -fsanitize=undefined -fno-sanitize=alignment -DRTC=1")
|
# set(COMPILER_FLAGS "${COMPILER_FLAGS} -fsanitize=address -fsanitize=undefined -fno-sanitize=alignment -DRTC=1")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|||||||
100
src/app.c
100
src/app.c
@ -20,8 +20,24 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
|
#include "math.h"
|
||||||
|
|
||||||
#define WRITE_DIR "power_play"
|
#define WRITE_DIR "power_play"
|
||||||
|
#define SETTINGS_FILENAME "settings.json"
|
||||||
|
|
||||||
|
#if RTC
|
||||||
|
# if DEVELOPER
|
||||||
|
# define WINDOW_TITLE "Debug (Developer Build)"
|
||||||
|
# else
|
||||||
|
# define WINDOW_TITLE "Debug"
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if DEVELOPER
|
||||||
|
# define WINDOW_TITLE "Power Play (Developer Build)"
|
||||||
|
# else
|
||||||
|
# define WINDOW_TITLE "Power Play"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
GLOBAL struct {
|
GLOBAL struct {
|
||||||
struct arena arena;
|
struct arena arena;
|
||||||
@ -63,6 +79,30 @@ struct string app_write_path_cat(struct arena *arena, struct string filename)
|
|||||||
return string_cat(arena, L.write_path, filename);
|
return string_cat(arena, L.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(width / (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT));
|
||||||
|
i32 x = math_round(monitor_size.x / 2.f - width / 2);
|
||||||
|
i32 y = math_round(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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Entry point
|
* Entry point
|
||||||
* ========================== */
|
* ========================== */
|
||||||
@ -91,9 +131,8 @@ void app_entry_point(void)
|
|||||||
L.arena = arena_alloc(GIGABYTE(64));
|
L.arena = arena_alloc(GIGABYTE(64));
|
||||||
L.write_path = initialize_write_directory(&L.arena, STR(WRITE_DIR));
|
L.write_path = initialize_write_directory(&L.arena, STR(WRITE_DIR));
|
||||||
|
|
||||||
{
|
|
||||||
/* Startup base systems */
|
/* Startup base systems */
|
||||||
|
{
|
||||||
/* Startup logging */
|
/* Startup logging */
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
@ -111,11 +150,44 @@ void app_entry_point(void)
|
|||||||
|
|
||||||
/* Create window */
|
/* Create window */
|
||||||
struct sys_window window = sys_window_alloc();
|
struct sys_window window = sys_window_alloc();
|
||||||
{
|
|
||||||
/* Read window settings from file */
|
/* Read window settings from file */
|
||||||
struct sys_window_settings window_settings = settings_default_window_settings(&window);
|
{
|
||||||
settings_read_from_file(&window_settings);
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
struct sys_window_settings window_settings = default_window_settings(&window);
|
||||||
|
struct string settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
|
||||||
|
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 buffer file_data = sys_file_read_all(scratch.arena, settings_file);
|
||||||
|
sys_file_close(settings_file);
|
||||||
|
logf_info("Deserializing settings file data: %F", FMT_STR(STRING_FROM_BUFFER(file_data)));
|
||||||
|
struct string error = { 0 };
|
||||||
|
struct sys_window_settings *res = settings_deserialize(scratch.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(scratch.arena,
|
||||||
|
STR(
|
||||||
|
"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);
|
||||||
|
} else {
|
||||||
|
logf_info("Settings file loaded successfully");
|
||||||
|
window_settings = *res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
string_copy_buff(BUFFER_FROM_ARRAY(window_settings.title), STR(WINDOW_TITLE));
|
||||||
sys_window_update_settings(&window, &window_settings);
|
sys_window_update_settings(&window, &window_settings);
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Startup systems */
|
/* Startup systems */
|
||||||
@ -153,8 +225,24 @@ void app_entry_point(void)
|
|||||||
work_shutdown();
|
work_shutdown();
|
||||||
|
|
||||||
/* Write window settings to file */
|
/* Write window settings to file */
|
||||||
|
{
|
||||||
|
struct temp_arena scratch = scratch_begin_no_conflict();
|
||||||
|
|
||||||
|
struct string window_settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
|
||||||
|
|
||||||
struct sys_window_settings settings = sys_window_get_settings(&window);
|
struct sys_window_settings settings = sys_window_get_settings(&window);
|
||||||
settings_write_to_file(&settings);
|
struct buffer buff = settings_serialize(scratch.arena, &settings);
|
||||||
|
logf_info("Serialized window settings: %F", FMT_STR(STRING_FROM_BUFFER(buff)));
|
||||||
|
|
||||||
|
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, buff);
|
||||||
|
sys_file_close(settings_file);
|
||||||
|
logf_info("Finished writing settings file");
|
||||||
|
|
||||||
|
scratch_end(scratch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
logf_info("Program exited normally");
|
logf_info("Program exited normally");
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/arena.h
17
src/arena.h
@ -9,8 +9,8 @@
|
|||||||
#define arena_push_array(a, type, n) ((type *)_arena_push_bytes((a), (sizeof(type) * (n)), ALIGNOF(type)))
|
#define arena_push_array(a, type, n) ((type *)_arena_push_bytes((a), (sizeof(type) * (n)), ALIGNOF(type)))
|
||||||
#define arena_push_array_zero(a, type, n) ((type *)_arena_push_bytes_zero((a), (sizeof(type) * (n)), ALIGNOF(type)))
|
#define arena_push_array_zero(a, type, n) ((type *)_arena_push_bytes_zero((a), (sizeof(type) * (n)), ALIGNOF(type)))
|
||||||
|
|
||||||
#define arena_pop(a, type) ((type *)_arena_pop((a), sizeof(type)))
|
#define arena_pop(a, type, dest) _arena_pop_struct((a), sizeof(type), dest)
|
||||||
#define arena_pop_array(a, type, n) ((type *)_arena_pop((a), sizeof(type) * (n)))
|
#define arena_pop_array(a, type, n, dest) _arena_pop_struct((a), sizeof(type) * (n), dest)
|
||||||
|
|
||||||
/* Returns a pointer to where the next allocation would be (at alignment of type).
|
/* Returns a pointer to where the next allocation would be (at alignment of type).
|
||||||
* Equivalent arena_push but without actually allocating anything. */
|
* Equivalent arena_push but without actually allocating anything. */
|
||||||
@ -40,18 +40,23 @@ INLINE void *_arena_push_bytes_zero(struct arena *arena, u64 size, u64 align)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void *_arena_pop_to(struct arena *arena, u64 pos)
|
INLINE void _arena_pop_to(struct arena *arena, u64 pos)
|
||||||
{
|
{
|
||||||
ASSERT(arena->pos >= pos);
|
ASSERT(arena->pos >= pos);
|
||||||
ASAN_POISON(arena->base + pos, arena->pos - pos);
|
ASAN_POISON(arena->base + pos, arena->pos - pos);
|
||||||
arena->pos = pos;
|
arena->pos = pos;
|
||||||
return (void *)(arena->base + arena->pos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE void *_arena_pop(struct arena *arena, u64 size)
|
INLINE void _arena_pop_struct(struct arena *arena, u64 size, void *copy_dest)
|
||||||
{
|
{
|
||||||
ASSERT(arena->pos >= size);
|
ASSERT(arena->pos >= size);
|
||||||
return _arena_pop_to(arena, arena->pos - size);
|
|
||||||
|
u64 new_pos = arena->pos - size;
|
||||||
|
void *src = (void *)(arena->base + new_pos);
|
||||||
|
MEMCPY(copy_dest, src, size);
|
||||||
|
|
||||||
|
ASAN_POISON(arena->base + new_pos, arena->pos - new_pos);
|
||||||
|
arena->pos = new_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
INLINE struct temp_arena arena_temp_begin(struct arena *arena)
|
INLINE struct temp_arena arena_temp_begin(struct arena *arena)
|
||||||
|
|||||||
@ -86,7 +86,8 @@ INTERNAL void recalculate_world_xform_recurse(struct entity *parent)
|
|||||||
u64 stack_count = 1;
|
u64 stack_count = 1;
|
||||||
while (stack_count > 0) {
|
while (stack_count > 0) {
|
||||||
/* Pull from top of stack */
|
/* Pull from top of stack */
|
||||||
struct stack_node node = *arena_pop(scratch.arena, struct stack_node);
|
struct stack_node node;
|
||||||
|
arena_pop(scratch.arena, struct stack_node, &node);
|
||||||
--stack_count;
|
--stack_count;
|
||||||
|
|
||||||
/* Calculate child world xform */
|
/* Calculate child world xform */
|
||||||
|
|||||||
1799
src/json.c
1799
src/json.c
File diff suppressed because it is too large
Load Diff
146
src/json.h
146
src/json.h
@ -2,142 +2,48 @@
|
|||||||
#define JSON_H
|
#define JSON_H
|
||||||
|
|
||||||
enum json_type {
|
enum json_type {
|
||||||
JSON_TYPE_INVALID,
|
|
||||||
|
|
||||||
JSON_TYPE_STRING,
|
|
||||||
JSON_TYPE_NULL,
|
JSON_TYPE_NULL,
|
||||||
JSON_TYPE_BOOL,
|
JSON_TYPE_BOOL,
|
||||||
|
JSON_TYPE_NUMBER,
|
||||||
|
JSON_TYPE_STRING,
|
||||||
JSON_TYPE_ARRAY,
|
JSON_TYPE_ARRAY,
|
||||||
JSON_TYPE_OBJECT,
|
JSON_TYPE_OBJECT
|
||||||
JSON_TYPE_NUMBER
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct json_object_entry;
|
struct json {
|
||||||
|
|
||||||
struct json_ir_parent_data {
|
|
||||||
u32 child_count;
|
|
||||||
struct json_ir *child_first;
|
|
||||||
struct json_ir *child_last;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Intermediate representation of JSON hierarchy tree in memory. Used for mutating
|
|
||||||
* JSON in parsing stage or for creating new objects. Should be manipulated via the
|
|
||||||
* API. */
|
|
||||||
struct json_ir {
|
|
||||||
enum json_type type;
|
enum json_type type;
|
||||||
struct json_ir *next_child;
|
|
||||||
struct string key;
|
struct string key;
|
||||||
|
|
||||||
|
struct json *parent;
|
||||||
|
struct json *next;
|
||||||
|
struct json *child_first;
|
||||||
|
struct json *child_last;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct json_ir_parent_data children;
|
|
||||||
b32 boolean;
|
|
||||||
struct string string;
|
struct string string;
|
||||||
f64 number;
|
f64 number;
|
||||||
} val;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Final representation of JSON hierarchy. Should be manipulated via the API. */
|
|
||||||
struct json_val {
|
|
||||||
enum json_type type;
|
|
||||||
u32 child_count;
|
|
||||||
union {
|
|
||||||
void *object_table;
|
|
||||||
struct json_val *array_children;
|
|
||||||
b32 boolean;
|
b32 boolean;
|
||||||
struct string *string;
|
} value;
|
||||||
f64 number;
|
|
||||||
} val;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct json_object_entry {
|
struct json_error {
|
||||||
struct string key;
|
struct string msg;
|
||||||
struct json_val value;
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
struct json_error *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Parse */
|
struct json_error_list {
|
||||||
const struct json_ir *json_parse(struct arena *arena, struct buffer bytes, struct string **error);
|
u64 count;
|
||||||
|
struct json_error *first;
|
||||||
|
struct json_error *last;
|
||||||
|
};
|
||||||
|
|
||||||
/* Format */
|
struct json_parse_result {
|
||||||
const struct json_val *json_format(struct arena *arena, const struct json_ir *ir);
|
struct json *root;
|
||||||
const struct json_val *json_parse_and_format(struct arena *arena, struct buffer bytes, struct string **error);
|
struct json_error_list errors;
|
||||||
|
};
|
||||||
|
|
||||||
/* Index */
|
struct json_parse_result json_from_string(struct arena *arena, struct string src);
|
||||||
const struct json_val *json_array_get(const struct json_val *a, u32 index);
|
|
||||||
const struct json_val *json_object_get(const struct json_val *obj, struct string key);
|
|
||||||
const struct json_object_entry *json_object_get_index(const struct json_val *obj, u32 index);
|
|
||||||
|
|
||||||
/* Dump */
|
|
||||||
struct string json_dump_to_string(struct arena *arena, const struct json_val *val, u32 indent);
|
|
||||||
|
|
||||||
/* Write */
|
|
||||||
struct json_ir *json_ir_object(struct arena *arena);
|
|
||||||
struct json_ir *json_ir_number(struct arena *arena, f64 n);
|
|
||||||
struct json_ir *json_ir_bool(struct arena *arena, b32 b);
|
|
||||||
struct json_ir *json_ir_object_set(struct json_ir *obj, struct string key, struct json_ir *value);
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Type util
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INLINE b32 json_is_object(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_OBJECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_is_string(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_is_number(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_NUMBER;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_is_array(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_ARRAY;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_is_bool(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_BOOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_is_null(const struct json_val *v)
|
|
||||||
{
|
|
||||||
return v && v->type == JSON_TYPE_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Val util
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INLINE struct string json_string(const struct json_val *v)
|
|
||||||
{
|
|
||||||
ASSERT(json_is_string(v));
|
|
||||||
return *v->val.string;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE f64 json_number(const struct json_val *v)
|
|
||||||
{
|
|
||||||
ASSERT(json_is_number(v));
|
|
||||||
return v->val.number;
|
|
||||||
}
|
|
||||||
|
|
||||||
INLINE b32 json_bool(const struct json_val *v)
|
|
||||||
{
|
|
||||||
ASSERT(json_is_bool(v));
|
|
||||||
return v->val.boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ========================== *
|
|
||||||
* Parent util
|
|
||||||
* ========================== */
|
|
||||||
|
|
||||||
INLINE u32 json_child_count(const struct json_val *v)
|
|
||||||
{
|
|
||||||
ASSERT(json_is_object(v) || json_is_array(v));
|
|
||||||
return v->child_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
262
src/settings.c
262
src/settings.c
@ -1,158 +1,156 @@
|
|||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "sys.h"
|
|
||||||
#include "json.h"
|
#include "json.h"
|
||||||
#include "scratch.h"
|
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "app.h"
|
#include "arena.h"
|
||||||
|
#include "scratch.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
|
|
||||||
/* TODO:
|
struct buffer settings_serialize(struct arena *arena, const struct sys_window_settings *settings)
|
||||||
* Rework the whole settings system to be not so rigid.
|
{
|
||||||
* - Multi-threaded
|
__prof;
|
||||||
* - Current settings state is readable & modifiable at any time
|
|
||||||
* - Can be done w/ a settings_open / settings_close block
|
|
||||||
* - Allow for dot notation in settings queries (should probably be implemented in the json layer).
|
|
||||||
* - "." denotes subindexing, IE: settings_get("window.width") (numbers can also be implemented for arrays).
|
|
||||||
* - "\." escapable
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define SETTINGS_FILENAME "settings.json"
|
struct string minimized = settings->flags & SYS_WINDOW_SETTINGS_FLAG_MINIMIZED ? STR("true") : STR("false");
|
||||||
|
struct string maximized = settings->flags & SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED ? STR("true") : STR("false");
|
||||||
|
struct string fullscreen = settings->flags & SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN ? STR("true") : STR("false");
|
||||||
|
i32 x = settings->floating_x;
|
||||||
|
i32 y = settings->floating_y;
|
||||||
|
i32 width = settings->floating_width;
|
||||||
|
i32 height = settings->floating_height;
|
||||||
|
|
||||||
INTERNAL struct buffer serialize_window_settings(struct arena *arena, const struct sys_window_settings *settings)
|
struct string fmt = STR(
|
||||||
|
"{\n"
|
||||||
|
" \"window\": {\n"
|
||||||
|
" \"minimized\": %F,\n"
|
||||||
|
" \"maximized\": %F,\n"
|
||||||
|
" \"fullscreen\": %F,\n"
|
||||||
|
" \"x\": %F,\n"
|
||||||
|
" \"y\": %F,\n"
|
||||||
|
" \"width\": %F,\n"
|
||||||
|
" \"height\": %F\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
);
|
||||||
|
|
||||||
|
struct string formatted = string_format(arena,
|
||||||
|
fmt,
|
||||||
|
FMT_STR(minimized),
|
||||||
|
FMT_STR(maximized),
|
||||||
|
FMT_STR(fullscreen),
|
||||||
|
FMT_SINT(x),
|
||||||
|
FMT_SINT(y),
|
||||||
|
FMT_SINT(width),
|
||||||
|
FMT_SINT(height));
|
||||||
|
|
||||||
|
return BUFFER_FROM_STRING(formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sys_window_settings *settings_deserialize(struct arena *arena, struct buffer src, struct string *error_out)
|
||||||
{
|
{
|
||||||
__prof;
|
__prof;
|
||||||
struct temp_arena scratch = scratch_begin(arena);
|
struct temp_arena scratch = scratch_begin(arena);
|
||||||
struct json_ir *root_obj = json_ir_object(scratch.arena);
|
|
||||||
struct json_ir *window_settings_obj = json_ir_object_set(root_obj, STR("window"), json_ir_object(scratch.arena));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("minimized"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_MINIMIZED));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("maximized"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("fullscreen"), json_ir_bool(scratch.arena, settings->flags & SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("x"), json_ir_number(scratch.arena, settings->floating_x));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("y"), json_ir_number(scratch.arena, settings->floating_y));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("width"), json_ir_number(scratch.arena, settings->floating_width));
|
|
||||||
json_ir_object_set(window_settings_obj, STR("height"), json_ir_number(scratch.arena, settings->floating_height));
|
|
||||||
|
|
||||||
const struct json_val *formatted = json_format(scratch.arena, root_obj);
|
|
||||||
struct buffer buff = BUFFER_FROM_STRING(json_dump_to_string(arena, formatted, 2));
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
return buff;
|
|
||||||
}
|
|
||||||
|
|
||||||
INTERNAL void deserialize_window_settings(struct buffer json_bytes, struct sys_window_settings *settings)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
||||||
struct string error = { 0 };
|
struct string error = { 0 };
|
||||||
|
struct json_error json_error = { 0 };
|
||||||
|
|
||||||
if (json_bytes.size <= 0) {
|
struct sys_window_settings *settings = arena_push_zero(arena, struct sys_window_settings);
|
||||||
goto end;
|
struct json_parse_result parse_res = json_from_string(scratch.arena, STRING_FROM_BUFFER(src));
|
||||||
|
|
||||||
|
if (parse_res.errors.count > 0) {
|
||||||
|
json_error = *parse_res.errors.first;
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct string *parse_error = NULL;
|
struct json *root = parse_res.root;
|
||||||
const struct json_val *root_json = json_parse_and_format(scratch.arena, json_bytes, &parse_error);
|
if (!root) {
|
||||||
if (parse_error) {
|
error = STR("Root object not found.");
|
||||||
error = *parse_error;
|
goto abort;
|
||||||
goto end;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct json_val *window_settings_json = json_object_get(root_json, STR("window"));
|
struct json *window = root->child_first;
|
||||||
if (!window_settings_json || !json_is_object(window_settings_json)) {
|
if (!window || window->type != JSON_TYPE_OBJECT || !string_eq(window->key, STR("window"))) {
|
||||||
goto end;
|
error = STR("\"window\" object not found");
|
||||||
|
goto abort;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct json_val *maximized = json_object_get(window_settings_json, STR("maximized"));
|
b32 found_maximized = false;
|
||||||
const struct json_val *fullscreen = json_object_get(window_settings_json, STR("fullscreen"));
|
b32 found_fullscreen = false;
|
||||||
const struct json_val *width = json_object_get(window_settings_json, STR("width"));
|
b32 found_x = false;
|
||||||
const struct json_val *height = json_object_get(window_settings_json, STR("height"));
|
b32 found_y = false;
|
||||||
const struct json_val *x = json_object_get(window_settings_json, STR("x"));
|
b32 found_width = false;
|
||||||
const struct json_val *y = json_object_get(window_settings_json, STR("y"));
|
b32 found_height = false;
|
||||||
|
for (struct json *child = window->child_first; child; child = child->next) {
|
||||||
|
struct string key = child->key;
|
||||||
|
|
||||||
settings->floating_x = json_is_number(x) ? (i32)clamp_f64(json_number(x), I32_MIN, I32_MAX) : settings->floating_x;
|
if (string_eq(key, STR("maximized"))) {
|
||||||
settings->floating_y = json_is_number(y) ? (i32)clamp_f64(json_number(y), I32_MIN, I32_MAX) : settings->floating_y;
|
if (child->type != JSON_TYPE_BOOL) {
|
||||||
settings->floating_width = json_is_number(width) ? (i32)clamp_f64(json_number(width), I32_MIN, I32_MAX) : settings->floating_width;
|
error = STR("Expected boolean for \"maximized\"");
|
||||||
settings->floating_height = json_is_number(height) ? (i32)clamp_f64(json_number(height), I32_MIN, I32_MAX) : settings->floating_height;
|
goto abort;
|
||||||
settings->flags = json_is_bool(maximized) ? (json_bool(maximized) ? (settings->flags | SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED) : (settings->flags & ~SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED)) : settings->flags;
|
}
|
||||||
settings->flags = json_is_bool(fullscreen) ? (json_bool(fullscreen) ? (settings->flags | SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN) : (settings->flags & ~SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN)) : settings->flags;
|
if (child->value.boolean) {
|
||||||
|
settings->flags |= SYS_WINDOW_SETTINGS_FLAG_MAXIMIZED;
|
||||||
|
}
|
||||||
|
found_maximized = true;
|
||||||
|
} else if (string_eq(key, STR("fullscreen"))) {
|
||||||
|
if (child->type != JSON_TYPE_BOOL) {
|
||||||
|
error = STR("Expected boolean for \"fulscreen\"");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
if (child->value.boolean) {
|
||||||
|
settings->flags |= SYS_WINDOW_SETTINGS_FLAG_FULLSCREEN;
|
||||||
|
}
|
||||||
|
found_fullscreen = true;
|
||||||
|
} else if (string_eq(key, STR("x"))) {
|
||||||
|
if (child->type != JSON_TYPE_NUMBER) {
|
||||||
|
error = STR("Expected number for \"x\"");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
settings->floating_x = math_round(child->value.number);
|
||||||
|
found_x = true;
|
||||||
|
} else if (string_eq(key, STR("y"))) {
|
||||||
|
if (child->type != JSON_TYPE_NUMBER) {
|
||||||
|
error = STR("Expected number for \"y\"");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
settings->floating_y = math_round(child->value.number);
|
||||||
|
found_y = true;
|
||||||
|
} else if (string_eq(key, STR("width"))) {
|
||||||
|
if (child->type != JSON_TYPE_NUMBER) {
|
||||||
|
error = STR("Expected number for \"width\"");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
settings->floating_width = math_round(child->value.number);
|
||||||
|
found_width = true;
|
||||||
|
} else if (string_eq(key, STR("height"))) {
|
||||||
|
if (child->type != JSON_TYPE_NUMBER) {
|
||||||
|
error = STR("Expected number for \"height\"");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
settings->floating_height = math_round(child->value.number);
|
||||||
|
found_height = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_maximized) { error = STR("Missing \"maximized\""); goto abort; }
|
||||||
|
if (!found_fullscreen) { error = STR("Missing \"fullscreen\""); goto abort; }
|
||||||
|
if (!found_x) { error = STR("Missing \"x\""); goto abort; }
|
||||||
|
if (!found_y) { error = STR("Missing \"y\""); goto abort; }
|
||||||
|
if (!found_width) { error = STR("Missing \"width\""); goto abort; }
|
||||||
|
if (!found_height) { error = STR("Missing \"height\""); goto abort; }
|
||||||
|
|
||||||
end:
|
abort:
|
||||||
if (error.len > 0) {
|
if (error_out && (error.len > 0 || json_error.msg.len > 0)) {
|
||||||
sys_message_box(
|
if (json_error.msg.len > 0) {
|
||||||
SYS_MESSAGE_BOX_KIND_WARNING,
|
*error_out = string_format(arena,
|
||||||
string_format(
|
STR("%F\n(%F:%F)"),
|
||||||
scratch.arena,
|
FMT_STR(json_error.msg),
|
||||||
STR("Error loading settings file:\n%F"),
|
FMT_UINT(json_error.start),
|
||||||
FMT_STR(error)
|
FMT_UINT(json_error.end));
|
||||||
)
|
} else {
|
||||||
);
|
*error_out = string_copy(arena, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sys_window_settings 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(width / (f32)(DEFAULT_CAMERA_WIDTH / DEFAULT_CAMERA_HEIGHT));
|
|
||||||
i32 x = math_round(monitor_size.x / 2.f - width / 2);
|
|
||||||
i32 y = math_round(monitor_size.y / 2.f - height / 2);
|
|
||||||
|
|
||||||
return (struct sys_window_settings) {
|
|
||||||
#if RTC
|
|
||||||
# if DEVELOPER
|
|
||||||
.title = "Debug (Developer Build)",
|
|
||||||
# else
|
|
||||||
.title = "Debug",
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# if DEVELOPER
|
|
||||||
.title = "Power Play (Developer Build)",
|
|
||||||
# else
|
|
||||||
.title = "Power Play",
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
.floating_x = x,
|
|
||||||
.floating_y = y,
|
|
||||||
.floating_width = width,
|
|
||||||
.floating_height = height
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void settings_read_from_file(struct sys_window_settings *default_settings)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
||||||
|
|
||||||
/* Read window settings file if it exists */
|
|
||||||
struct string window_settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
|
|
||||||
if (sys_is_file(window_settings_path)) {
|
|
||||||
struct sys_file settings_file = sys_file_open_read(window_settings_path);
|
|
||||||
struct buffer file_data = sys_file_read_all(scratch.arena, settings_file);
|
|
||||||
sys_file_close(settings_file);
|
|
||||||
deserialize_window_settings(file_data, default_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void settings_write_to_file(const struct sys_window_settings *settings)
|
|
||||||
{
|
|
||||||
__prof;
|
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
|
||||||
|
|
||||||
/* Write window settings to file */
|
|
||||||
struct buffer settings_file_data = serialize_window_settings(scratch.arena, settings);
|
|
||||||
if (settings_file_data.size > 0) {
|
|
||||||
struct string window_settings_path = app_write_path_cat(scratch.arena, STR(SETTINGS_FILENAME));
|
|
||||||
struct sys_file settings_file = sys_file_open_write(window_settings_path);
|
|
||||||
sys_file_write(settings_file, settings_file_data);
|
|
||||||
sys_file_close(settings_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scratch_end(scratch);
|
scratch_end(scratch);
|
||||||
|
|
||||||
|
return settings;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
#ifndef SETTINGS_H
|
#ifndef SETTINGS_H
|
||||||
#define SETTINGS_H
|
#define SETTINGS_H
|
||||||
|
|
||||||
struct sys_window;
|
struct sys_window_settings;
|
||||||
|
|
||||||
struct sys_window_settings settings_default_window_settings(struct sys_window *window);
|
struct buffer settings_serialize(struct arena *arena, const struct sys_window_settings *settings);
|
||||||
void settings_read_from_file(struct sys_window_settings *default_settings);
|
struct sys_window_settings *settings_deserialize(struct arena *arena, struct buffer src, struct string *error_out);
|
||||||
void settings_write_to_file(const struct sys_window_settings *settings);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user