summaryrefslogtreecommitdiff
path: root/src/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/state.c')
-rw-r--r--src/state.c251
1 files changed, 251 insertions, 0 deletions
diff --git a/src/state.c b/src/state.c
new file mode 100644
index 0000000..08d9f37
--- /dev/null
+++ b/src/state.c
@@ -0,0 +1,251 @@
+#include <string.h>
+
+#include <daw/dltools.h>
+#include <daw/logging.h>
+#include <daw/state.h>
+#include <daw/input.h>
+
+//typedef void state_init_t(void*,void*);
+//typedef void* (state_free_t(void*));
+typedef StateType state_update_t(f64, void*);
+
+const char* StateTypeStr[] = {
+ "null",
+#define State(name) #name,
+#include <states/list_of_states.h>
+#undef State
+ "quit",
+};
+
+// Setup API for states
+#define State(name) \
+ typedef struct name##_state name##_state; \
+ typedef void(state_##name##_init_t)(name##_state*,void*); \
+ typedef void*(state_##name##_free_t)(name##_state*); \
+ typedef StateType(state_##name##_update_t)(name##_state*);
+#include <states/list_of_states.h>
+#undef State
+
+#ifdef DAW_BUILD_HOTRELOAD
+
+// When hotreloading is enabled, we want to assign state function pointers
+// dynamically.
+#define State(name) \
+ state_##name##_init_t* name##_init = NULL; \
+ state_##name##_free_t* name##_free = NULL; \
+ state_##name##_update_t* name##_update = NULL; \
+ \
+ void* libstate_##name = NULL; \
+ const char* libstate_##name##_str = "lib" #name ".so";
+#else
+
+// Otherwise we just declare them.
+#define State(name) \
+ extern state_##name##_init_t name##_init; \
+ extern state_##name##_free_t name##_free; \
+ extern state_##name##_update_t name##_update;
+#endif
+
+#include <states/list_of_states.h>
+#undef State
+
+#include <states/all_states.h>
+
+void State_init(StateType type, memory* mem, void* arg) {
+ switch (type) {
+#define State(name) \
+ case (STATE_##name): { \
+ name##_init(memory_allocate(mem, sizeof(name##_state)), arg); \
+ break; \
+ }
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ DEBUG("Got %s state.\n", StateTypeStr[type]);
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+}
+
+void* State_free(StateType type, memory* mem) {
+ void* state_retval = NULL;
+ switch (type) {
+#define State(name) \
+ case (STATE_##name): { \
+ state_retval = name##_free(mem->data); \
+ break; \
+ }
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ DEBUG("Got %s state.\n", StateTypeStr[type]);
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ memory_clear(mem);
+ return state_retval;
+}
+
+/* Returns the update function of a given state type */
+StateType (*State_updateFunc(StateType type))(f64, void*) {
+ switch (type) {
+#ifdef DAW_BUILD_HOTRELOAD
+#define State(name) \
+ case (STATE_##name): { \
+ return (state_update_t*)name##_update; \
+ break; \
+ }
+#else
+#define State(name) \
+ case (STATE_##name): { \
+ return (state_update_t*)&name##_update; \
+ break; \
+ }
+#endif
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ return NULL; // DEBUG("Got %s state.\n", StateTypeStr[type]);
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ return NULL;
+}
+
+StateType State_update(StateType type, f64 dt, memory* mem) {
+ StateType next_state = STATE_null;
+ switch (type) {
+#define State(name) \
+ case (STATE_##name): { \
+ next_state = name##_update(mem->data); \
+ break; \
+ }
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ DEBUG("Got %s state.\n", StateTypeStr[type]);
+ break;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ return next_state;
+}
+
+#ifdef DAW_BUILD_HOTRELOAD
+bool State_reload(StateType type, i_ctx** ctx, usize ctx_len) {
+ void* libptr = NULL;
+
+ switch (type) {
+#define State(name) \
+ case (STATE_##name): { \
+ if (libstate_##name == NULL) { \
+ libstate_##name = dynamic_library_open(libstate_##name##_str); \
+ } else { \
+ libstate_##name = \
+ dynamic_library_reload(libstate_##name, libstate_##name##_str); \
+ } \
+ if (libstate_##name == NULL) { \
+ ERROR("Failed loading shared object: %s (%s)", libstate_##name##_str, \
+ dynamic_library_get_error()); \
+ return false; \
+ } \
+ \
+ name##_init = (state_##name##_init_t*)dynamic_library_get_symbol( \
+ libstate_##name, STR(name##_init)); \
+ name##_free = (state_##name##_free_t*)dynamic_library_get_symbol( \
+ libstate_##name, STR(name##_free)); \
+ name##_update = (state_##name##_update_t*)dynamic_library_get_symbol( \
+ libstate_##name, STR(name##_update)); \
+ libptr = libstate_##name; \
+ break; \
+ }
+#include <states/list_of_states.h>
+#undef State
+ case STATE_null:
+ case STATE_quit:
+ ERROR("Invalid state");
+ DEBUG("Got %s state.\n", StateTypeStr[type]);
+ return false;
+ default:
+ exit(EXIT_FAILURE);
+ }
+ return state_refresh_input_ctx(libptr, ctx, ctx_len);
+}
+
+
+bool state_refresh_input_ctx(void* lib, i_ctx** ctx, usize ctx_len) {
+ if (ctx == NULL) return true;
+ if (ctx_len > 0 && ctx[0] == NULL) return false;
+ if (lib == NULL) return false;
+
+ for (usize c = 0; c < ctx_len; c++) {
+ LOG("ctx[%d]->len = %d", c, ctx[c]->len);
+ for (isize b = 0; b < ctx[c]->len; b++) {
+ switch (ctx[c]->bindings[b].action.type) {
+ case InputType_error:
+ break;
+ case InputType_action:
+ if (strcmp("NULL", ctx[c]->bindings[b].action.action.callback_str) !=
+ 0) {
+
+ ctx[c]->bindings[b].action.action.callback =
+ (input_callback_t*)dynamic_library_get_symbol(
+ lib, ctx[c]->bindings[b].action.action.callback_str);
+
+ if (ctx[c]->bindings[b].action.action.callback == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.action.callback_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+ break;
+ case InputType_state:
+ if (strcmp("NULL", ctx[c]->bindings[b].action.state.activate_str) !=
+ 0) {
+
+ ctx[c]->bindings[b].action.state.activate =
+ (input_callback_t*)dynamic_library_get_symbol(
+ lib, ctx[c]->bindings[b].action.state.activate_str);
+
+ if (ctx[c]->bindings[b].action.state.activate == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.state.activate_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+
+ if (strcmp("NULL", ctx[c]->bindings[b].action.state.deactivate_str) !=
+ 0) {
+
+ ctx[c]->bindings[b].action.state.deactivate =
+ (input_callback_t*)dynamic_library_get_symbol(
+ lib, ctx[c]->bindings[b].action.state.deactivate_str);
+
+ if (ctx[c]->bindings[b].action.state.deactivate == NULL) {
+ ERROR("Failed to get binding for %s: %s",
+ ctx[c]->bindings[b].action.state.deactivate_str,
+ dynamic_library_get_error());
+ return false;
+ }
+ }
+ break;
+ case InputType_range:
+ default:
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+#endif