diff --git a/game/res/manifest.cfg b/game/res/manifest.cfg index 036543b..90d97a2 100644 --- a/game/res/manifest.cfg +++ b/game/res/manifest.cfg @@ -21,6 +21,7 @@ uidummy=res/shaders/uidummy.vert;res/shaders/uidummy.frag [Textures] font0=res/textures/font_9x20.png icons=res/textures/icons.png +logo=res/textures/logo.png terrain0=res/textures/dirt.png terrain1=res/textures/drygrass.png @@ -40,12 +41,16 @@ clouds=res/textures/clouds.png # heightmap bitmap is multiplied by `heightmult`, and that's how many # metres 1 is. [Map] -heightmult=16 +height_multiplier=16 heightmap=res/map/heightmap.png texturemap=res/map/texturemap.png entitymap=res/map/entitymap.png +[UIDefs] +tooltip=res/scripts/ui/tooltip.scm +main_menu=res/scripts/ui/debug_window.scm + # The scripts are loaded and executed after everything above has been # loaded, so that Guile has some stuff to work with. [Scripts] -global=res/scripts/ui_styles.scm;res/scripts/ui_composites.scm \ No newline at end of file +global=res/scripts/global/ui_styles.scm;res/scripts/global/ui_composites.scm diff --git a/game/res/map/heightmap.png b/game/res/map/heightmap.png new file mode 100644 index 0000000..6c4e075 Binary files /dev/null and b/game/res/map/heightmap.png differ diff --git a/game/res/scripts/global/ui_styles.scm b/game/res/scripts/global/ui_styles.scm index 3d3b263..bb814cf 100644 --- a/game/res/scripts/global/ui_styles.scm +++ b/game/res/scripts/global/ui_styles.scm @@ -42,4 +42,7 @@ (define style-tooltip (style-new + #:text-color COLOR_WHITE + #:text-color-hovered COLOR_WHITE + #:text-color-clicked COLOR_WHITE #:background-color COLOR_BLACK)) diff --git a/game/res/scripts/ui/debug_window.scm b/game/res/scripts/ui/debug_window.scm index 97f8e0c..7289978 100644 --- a/game/res/scripts/ui/debug_window.scm +++ b/game/res/scripts/ui/debug_window.scm @@ -1,4 +1,3 @@ -(use-modules (ice-9 format)) ;; The function is evaulated and returns a pointer, the game eats it ;; and adds it to the UI root. Boom. (widget-new @@ -17,8 +16,8 @@ #:layout-spacing 8 #:horizontal #t (widget-label-gvar 'float "Delta time: ~,2f" "delta_time" #:style style-default #:layout-weight 1 #:h 20 #:text-alignment 'center) - (widget-label-gvar 'int "Chunks: ~d" "frame_chunks" #:style style-default #:layout-weight 0.5 #:h 20) - (widget-label-gvar 'int "Entities: ~d" "frame_entities" #:style style-default #:layout-weight 0.5 #:h 20) + (widget-label-gvar 'int "~d chunks" "frame_chunks" #:style style-default #:layout-weight 0.5 #:h 20) + (widget-label-gvar 'int "~d entities" "frame_entities" #:style style-default #:layout-weight 0.5 #:h 20) (widget-checkbox "Flight" "flight_enabled" #:layout-weight 0.5 #:h 20) (widget-checkbox "Wireframe" "wireframe_enabled" #:layout-weight 0.5 #:h 20) (widget-spinner 'int "Render distance: ~d" "render_distance" #:layout-weight 1 #:h 20))) diff --git a/game/res/scripts/ui/tooltip.scm b/game/res/scripts/ui/tooltip.scm index dd79cd0..63e7ec6 100644 --- a/game/res/scripts/ui/tooltip.scm +++ b/game/res/scripts/ui/tooltip.scm @@ -1,9 +1,6 @@ -(widget-new - 'flowbox - #:style style-tooltip - #:w 200 - #:visible #f - #:horizontal #t - #:layout-padding 4 - #:layout-spacing 8 - (widget-new 'multiline #:line-height 20 #:layout-weight 1 #:style style-default)) +(widget-new 'multiline + #:w 200 + #:visible #f + #:layout-padding 4 + #:line-height 20 + #:style style-tooltip) diff --git a/game/res/textures/logo.png b/game/res/textures/logo.png new file mode 100644 index 0000000..9d07bea Binary files /dev/null and b/game/res/textures/logo.png differ diff --git a/game/src/entity/entman.h b/game/src/entity/entman.h index 35d537c..d5efe54 100644 --- a/game/src/entity/entman.h +++ b/game/src/entity/entman.h @@ -10,7 +10,6 @@ #include "templates.h" #include "../gl/mesh.h" #include "../util.h" -#include "../state.h" #include "../chunk/chunkman.h" #include "../graphics.h" #include "../gvar.h" diff --git a/game/src/event/evtman.c b/game/src/event/evtman.c deleted file mode 100644 index edfea1a..0000000 --- a/game/src/event/evtman.c +++ /dev/null @@ -1,146 +0,0 @@ -#include "evtman.h" - -extern vec3 camera_rotation; - -static GList *handlers = NULL; - -gboolean -evt_pred_key (SDL_Event *event, void *data) -{ - unsigned int expected_key = GPOINTER_TO_INT (data); - return event->key.key == expected_key; -} - -gboolean -evt_pred_mouse (SDL_Event *event, void *data) -{ - unsigned int expected_button = GPOINTER_TO_INT (data); - return event->button.button == expected_button; -} - -gboolean -evt_pred_flag (SDL_Event *event, void *data) -{ - UNUSED (event); - char *flag = data; - return FLAG_GET (flag); -} - -gboolean -evt_cb_rotate_camera (SDL_Event *event, void *userdata) -{ - UNUSED (userdata); - camera_rotation[0] -= event->motion.xrel / 100.f; - camera_rotation[1] -= event->motion.yrel / 100.f; - camera_rotation[1] = - glm_clamp (camera_rotation[1], -M_PI / 2 + 0.025, M_PI / 2 - 0.025); - return true; -} - -gboolean -evt_cb_flag_off (SDL_Event *event, void *data) -{ - UNUSED (event); - char *flag = data; - FLAG_SET (flag, FALSE); - return true; -} - -gboolean -evt_cb_flag_on (SDL_Event *event, void *data) -{ - UNUSED (event); - char *flag = data; - FLAG_SET (flag, TRUE); - return true; -} - -gboolean -evt_cb_flag_switch (SDL_Event *event, void *data) -{ - UNUSED (event); - char *flag = data; - FLAG_SWITCH (flag); - return true; -} - -void -evtman_init () -{ -#define KEY(k) GINT_TO_POINTER(k) - - evtman_add_handler (2, SDL_EVENT_WINDOW_RESIZED, NULL, NULL, graphics_cb_window_resize, NULL); - evtman_add_handler (2, SDL_EVENT_WINDOW_RESIZED, NULL, NULL, uiman_cb_window_resize, NULL); - /* The UI effectively eats most SDL events, as it needs it for it's - own calculations. */ - evtman_add_handler (2, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_TAB), uiman_cb_switch_focus, NULL); - evtman_add_handler (1, SDL_EVENT_KEY_DOWN, evt_pred_flag, "ui_has_focus", uiman_cb_key_down, NULL); - evtman_add_handler (1, SDL_EVENT_KEY_UP, evt_pred_flag, "ui_has_focus", uiman_cb_key_up, NULL); - evtman_add_handler (1, SDL_EVENT_MOUSE_MOTION, evt_pred_flag, "ui_has_focus", uiman_cb_mouse_motion, NULL); - evtman_add_handler (1, SDL_EVENT_MOUSE_BUTTON_DOWN, evt_pred_flag, "ui_has_focus", uiman_cb_button_down, NULL); - evtman_add_handler (1, SDL_EVENT_MOUSE_BUTTON_UP, evt_pred_flag, "ui_has_focus", uiman_cb_button_up, NULL); - evtman_add_handler (1, SDL_EVENT_MOUSE_WHEEL, evt_pred_flag, "ui_has_focus", uiman_cb_mouse_wheel, NULL); - evtman_add_handler (1, SDL_EVENT_TEXT_INPUT, evt_pred_flag, "ui_has_focus", uiman_cb_text_input, NULL); - - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_W), evt_cb_flag_on, "moving_forward"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_W), evt_cb_flag_off, "moving_forward"); - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_S), evt_cb_flag_on, "moving_backward"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_S), evt_cb_flag_off, "moving_backward"); - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_A), evt_cb_flag_on, "moving_left"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_A), evt_cb_flag_off, "moving_left"); - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_D), evt_cb_flag_on, "moving_right"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_D), evt_cb_flag_off, "moving_right"); - - evtman_add_handler (0, SDL_EVENT_MOUSE_MOTION, NULL, NULL, evt_cb_rotate_camera, NULL); - - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_SPACE), evt_cb_flag_on, "flying_up"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_SPACE), evt_cb_flag_off, "flying_up"); - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_LCTRL), evt_cb_flag_on, "flying_down"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_LCTRL), evt_cb_flag_off, "flying_down"); - evtman_add_handler (0, SDL_EVENT_KEY_DOWN, evt_pred_key, KEY (SDLK_LSHIFT), evt_cb_flag_on, "flying_fast"); - evtman_add_handler (0, SDL_EVENT_KEY_UP, evt_pred_key, KEY (SDLK_LSHIFT), evt_cb_flag_off, "flying_fast"); - -#undef KEY -} - -void -evtman_add_handler (int priority, unsigned int filter, - gboolean (*predicate) (SDL_Event *sdl_event, void *userdata), - void *predicate_data, - gboolean (*callback) (SDL_Event *sdl_event, void *userdata), - void *callback_data) -{ - EventHandler *h = g_new (EventHandler, 1); - h->filter = filter; - h->priority = priority; - h->predicate_data = predicate_data; - h->callback_data = callback_data; - h->predicate = predicate; - h->callback = callback; - - GList *iter = handlers; - while (iter && ((EventHandler *) iter->data)->priority >= priority) - { - iter = iter->next; - } - - handlers = g_list_insert_before (handlers, iter, h); -} - -void -evtman_handle_SDL_Event (SDL_Event *event) -{ - for (GList *l = handlers; l != NULL; l = l->next) - { - EventHandler *h = (EventHandler *) l->data; - - if ((h->filter == 0 || h->filter == event->type) - && (!h->predicate || h->predicate (event, h->predicate_data))) - { - if (h->callback && h->callback (event, h->callback_data)) - { - break; - } - } - } -} diff --git a/game/src/event/evtman.h b/game/src/event/evtman.h deleted file mode 100644 index 3e52677..0000000 --- a/game/src/event/evtman.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "handler.h" -#include "../util.h" -#include "../gvar.h" -#include "../graphics.h" -#include "../ui/uiman.h" - -void evtman_init (); -void evtman_add_handler (int priority, unsigned int filter, - gboolean (*predicate) (SDL_Event *sdl_event, void *userdata), - void *predicate_data, - gboolean (*callback) (SDL_Event *sdl_event, void *userdata), - void *callback_data); -void evtman_handle_SDL_Event (SDL_Event *event); diff --git a/game/src/event/handler.h b/game/src/event/handler.h deleted file mode 100644 index 43e5984..0000000 --- a/game/src/event/handler.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include -#include - -typedef struct { - unsigned int filter; - int priority; - void *predicate_data, *callback_data; - gboolean (*predicate) (SDL_Event *sdl_event, void *userdata); - gboolean (*callback) (SDL_Event *sdl_event, void *userdata); -} EventHandler; diff --git a/game/src/graphics.c b/game/src/graphics.c index 8f2c2b7..2a97226 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -5,9 +5,6 @@ extern vec3 camera_position; SDL_Window *sdl_window; static SDL_GLContext gl_context; -static uint64_t last_check_perf = 0; -static int avg_counter = 0; -static double avg_elapsed = 0; void graphics_init () @@ -40,7 +37,6 @@ graphics_init () } SDL_GL_MakeCurrent (sdl_window, gl_context); - SDL_SetWindowRelativeMouseMode (sdl_window, true); g_info ("Renderer: %s", glGetString (GL_RENDERER)); g_info ("OpenGL version: %s", glGetString (GL_VERSION)); @@ -57,68 +53,15 @@ graphics_init () } void -graphics_render () +graphics_prerender () { glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} - uint64_t start = SDL_GetPerformanceCounter (); - uint64_t freq = SDL_GetPerformanceFrequency (); - - mat4 projection, view; - camera_get_projection (gvar_get ("window_width") / gvar_get ("window_height"), projection); - camera_get_view (view); - - pakman_all_paks_set_mat4 ("projection", projection); - pakman_all_paks_set_mat4 ("view", view); - pakman_all_paks_set_float ("time", gvar_get ("last_time")); - - vec4 planes[6]; -#if FRUSTUM_CULL - mat4 view_proj; - glm_mat4_mul (projection, view, view_proj); - glm_frustum_planes (view_proj, planes); -#endif - - chunkman_render (camera_position, planes); - entman_render (view, planes); - - /* We don't care about blending elsewhere for now. */ - glEnable (GL_SCISSOR_TEST); - glEnable (GL_BLEND); - glDisable (GL_DEPTH_TEST); - uiman_render (); - glEnable (GL_DEPTH_TEST); - glDisable (GL_BLEND); - glDisable (GL_SCISSOR_TEST); - - SDL_GL_SwapWindow (sdl_window); - - uint64_t now = SDL_GetPerformanceCounter(); - double elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; - - avg_elapsed += elapsed_us; - avg_counter++; - - int render_distance = gvar_get ("render_distance"); - - if ((now - last_check_perf) >= freq * RENDER_AVG_FREQ_S) - { - double avg = avg_elapsed / avg_counter; - - if (avg < RENDER_FRAME_BUDGET_US && render_distance < RENDER_DISTANCE_MAX) - { - gvar_set ("render_distance", ++render_distance); - } - else if (avg > RENDER_FRAME_BUDGET_US && render_distance > RENDER_DISTANCE_MIN) - { - gvar_set ("render_distance", --render_distance); - } - - avg_elapsed = 0; - avg_counter = 0; - last_check_perf = now; - g_debug ("Dynamic render distance check: render distance %d, average ms: %.2f", render_distance, avg / 10000.0); - } +void +graphics_postrender () +{ + SDL_GL_SwapWindow (sdl_window); } void diff --git a/game/src/graphics.h b/game/src/graphics.h index 20890f7..948a70f 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -4,10 +4,8 @@ #include #include -#include "ui/uiman.h" #include "chunk/chunkman.h" #include "entity/entman.h" -#include "state.h" #include "util.h" #include "gvar.h" #include "pakman.h" @@ -23,6 +21,7 @@ #define RENDER_DISTANCE_MAX 12 void graphics_init (); -void graphics_render (); +void graphics_prerender (); +void graphics_postrender (); void graphics_free (); gboolean graphics_cb_window_resize (); diff --git a/game/src/gvar.h b/game/src/gvar.h index e7ccf79..38fbe74 100644 --- a/game/src/gvar.h +++ b/game/src/gvar.h @@ -8,6 +8,22 @@ gvars store arbitrary variables as floats. This can be used for flags as well as configuration options and whatnot. + Here's a list of game flags that are used regardless of whether a + .pak defines some or not: + + in_main_menu + ui_has_focus + + moving_forward + moving_left + moving_right + moving_back + + flight_enabled + flying_up + flying_down + flying_fast + */ #define FLAG_GET(key) ((gboolean) gvar_get (key)) diff --git a/game/src/main.c b/game/src/main.c index df3cb94..2f309e6 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -2,18 +2,14 @@ #include #include -#include "event/evtman.h" #include "chunk/chunkman.h" #include "entity/templates.h" #include "entity/entity_guile.h" -#include "ui/uiman.h" #include "ui/widget_guile.h" -#include "state.h" #include "graphics.h" #include "gvar.h" #include "pakman.h" - -extern vec3 camera_position; +#include "states/stateman.h" SDL_AppResult SDL_AppInit (void **appstate, int argc, char **argv) @@ -21,24 +17,38 @@ SDL_AppInit (void **appstate, int argc, char **argv) UNUSED (appstate, argc, argv); SDL_SetAppMetadata (GAME_NAME, GAME_VERSION, "eur.chopininteractive.wschod-game"); + /* Initialize GNU Guile and register all kinds of functions and cool + things. */ scm_init_guile (); gvar_guile_register (); widget_guile_register (); entity_guile_register (); pakman_guile_register (); + + /* TODO: move this somewhere. */ + scm_c_primitive_load ("res/scripts/global/ui_styles.scm"); + scm_c_primitive_load ("res/scripts/global/ui_composites.scm"); + /* The basics; game variables, graphics, the state manager, and the + pak manager. */ gvar_init (); graphics_init (); pakman_init (); + /* The base pack is always required, as it contains all the data + needed for the functioning of the UI and graphics. */ pakman_load_pak ("res/"); - - evtman_init (); - uiman_init (); - chunkman_init (); - entman_init (); - ent_templates_init (); - game_state_init (SDL_GetTicks ()); + stateman_init (); + + /* I don't know. This probably needs to be moved somewhere. */ + ui_widget_mesh_init (); + + /* The UI, entity and chunk subsystems. */ + entman_init (); + chunkman_init (); + + stateman_switch_state ("main_menu"); + return SDL_APP_CONTINUE; } @@ -52,7 +62,8 @@ SDL_AppEvent (void *appstate, SDL_Event *event) return SDL_APP_SUCCESS; } - evtman_handle_SDL_Event (event); + stateman_on_SDL_Event (event); + return SDL_APP_CONTINUE; } @@ -61,11 +72,11 @@ SDL_AppIterate (void *appstate) { UNUSED (appstate); - game_state_tick (SDL_GetTicks ()); - chunkman_tick (camera_position); - entman_tick (); - uiman_tick (); - graphics_render (); + stateman_update (); + + graphics_prerender (); + stateman_render (); + graphics_postrender (); return SDL_APP_CONTINUE; } @@ -75,5 +86,5 @@ SDL_AppQuit (void *appstate, SDL_AppResult result) { UNUSED (appstate, result); graphics_free (); - uiman_free (); + stateman_free (); } diff --git a/game/src/pakman.c b/game/src/pakman.c index af7c36d..66e9a16 100644 --- a/game/src/pakman.c +++ b/game/src/pakman.c @@ -24,11 +24,20 @@ _scm_get_texture (SCM pak_scm, SCM key_scm) return scm_from_int (pakman_pak_texture (pak, key)); } +static SCM +_scm_get_uidef (SCM pak_scm, SCM key_scm) +{ + const char *pak = scm_to_utf8_string (pak_scm); + const char *key = scm_to_utf8_string (key_scm); + return scm_from_pointer (pakman_pak_uidef (pak, key), NULL); +} + void pakman_guile_register () { scm_c_define_gsubr ("pak-program", 2, 0, 0, _scm_get_program); scm_c_define_gsubr ("pak-texture", 2, 0, 0, _scm_get_texture); + scm_c_define_gsubr ("pak-uidef", 2, 0, 0, _scm_get_uidef); } unsigned int @@ -87,7 +96,8 @@ pakman_load_pak (const char *path) PakFile *pak = g_new0 (PakFile, 1); pak->programs = g_hash_table_new (g_str_hash, g_str_equal); - pak->textures = g_hash_table_new (g_str_hash, g_str_equal); + pak->textures = g_hash_table_new (g_str_hash, g_str_equal); + pak->uidefs = g_hash_table_new (g_str_hash, g_str_equal); char **programs = g_key_file_get_keys (key_file, "Programs", NULL, &err); @@ -114,6 +124,16 @@ pakman_load_pak (const char *path) g_hash_table_insert (pak->textures, g_strdup (*t), GUINT_TO_POINTER (_pm_load_texture (texture))); } + char **uidefs = g_key_file_get_keys (key_file, "UIDefs", NULL, &err); + + for (char **u = uidefs; *u != NULL; u++) + { + char *uidef_path = g_key_file_get_string (key_file, "UIDefs", *u, &err); + SCM uidef_scm = scm_c_primitive_load (uidef_path); + Widget *uidef = (Widget *) scm_to_pointer (uidef_scm); + g_hash_table_insert (pak->uidefs, g_strdup (*u), uidef); + } + char *id = g_key_file_get_string (key_file, "Metadata", "id", &err); g_hash_table_insert (paks, g_strdup (id), pak); @@ -171,6 +191,28 @@ pakman_pak_texture (const char *pak, const char *texture) return GPOINTER_TO_UINT (value); } +Widget * +pakman_pak_uidef (const char *pak, const char *uidef) +{ + PakFile *p = g_hash_table_lookup (paks, pak); + + if (!p) + { + g_warning ("Pak `%s' not found.", pak); + return NULL; + } + + Widget *value = g_hash_table_lookup (p->uidefs, uidef); + + if (!value) + { + g_warning ("Uidef `%s' not found in pak `%s'.", uidef, pak); + return NULL; + } + + return value; +} + void pakman_all_paks_set_mat4 (const char *uniform, mat4 value) { diff --git a/game/src/pakman.h b/game/src/pakman.h index 8d4b8cb..363d27b 100644 --- a/game/src/pakman.h +++ b/game/src/pakman.h @@ -8,11 +8,13 @@ #include "gl/program.h" #include "gl/texture.h" #include "util.h" +#include "ui/widget_core.h" typedef struct PakFile { GHashTable *programs; GHashTable *textures; + GHashTable *uidefs; } PakFile; void pakman_init (); @@ -21,9 +23,11 @@ void pakman_load_pak (const char *path); unsigned int pakman_pak_program (const char *pak, const char *program); unsigned int pakman_pak_texture (const char *pak, const char *texture); +Widget *pakman_pak_uidef (const char *pak, const char *texture); void pakman_all_paks_set_mat4 (const char *uniform, mat4 value); void pakman_all_paks_set_float (const char *uniform, float value); #define PMPRG(program) pakman_pak_program ("base", program) #define PMTEX(texture) pakman_pak_texture ("base", texture) +#define PMUID(uidef) pakman_pak_uidef ("base", uidef) diff --git a/game/src/state.c b/game/src/state.c deleted file mode 100644 index c98f4bf..0000000 --- a/game/src/state.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "state.h" - -extern vec3 camera_position; -extern vec3 camera_rotation; -extern Entity *player_entity, *sky_entity; - -void -game_state_init (int ticks) -{ - gvar_set ("last_time", ticks); -} - -void -game_state_tick (int ticks) -{ - /* Caluclate stuff per frame. */ - gvar_set ("delta_time", (ticks - gvar_get ("last_time")) / 1000.0); - gvar_set ("last_time", ticks); - - float delta_time = gvar_get ("delta_time"); - - /* We pin the camera to the player position, with eye level 20 - centimeters below the height. */ - glm_vec3_copy (player_entity->position, camera_position); - camera_position[1] += player_entity->scale[1] - 0.2; - player_entity->rotation[1] = camera_rotation[1]; - /* The sky needs to be in the center of the world all the time, - otherwise, as we explore the world, we might reach the end of the - sky. */ - sky_entity->position[0] = camera_position[0]; - sky_entity->position[2] = camera_position[2]; - - int speed = 5; - - if (FLAG_GET ("flight_enabled") && FLAG_GET ("flying_fast")) - { - speed = 15; - } - - if (FLAG_GET ("moving_forward")) - { - vec3 dir, change, new_pos; - camera_get_direction (dir); - glm_vec3_scale (dir, delta_time * speed, change); - glm_vec3_add (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } - - if (FLAG_GET ("moving_backward")) - { - vec3 dir, change, new_pos; - camera_get_direction (dir); - glm_vec3_scale (dir, delta_time * speed, change); - glm_vec3_sub (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } - - if (FLAG_GET ("moving_right")) - { - vec3 right, change, new_pos; - camera_get_right (right); - glm_vec3_scale (right, delta_time * speed, change); - glm_vec3_add (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } - - if (FLAG_GET ("moving_left")) - { - vec3 right, change, new_pos; - camera_get_right (right); - glm_vec3_scale (right, delta_time * speed, change); - glm_vec3_sub (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } - - if (FLAG_GET ("flying_up") && FLAG_GET ("flight_enabled")) - { - vec3 change, new_pos; - glm_vec3_scale (GLM_YUP, delta_time * speed, change); - glm_vec3_add (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } - - if (FLAG_GET ("flying_down") && FLAG_GET ("flight_enabled")) - { - vec3 change, new_pos; - glm_vec3_scale (GLM_YUP, delta_time * speed, change); - glm_vec3_sub (player_entity->position, change, new_pos); - glm_vec3_copy (new_pos, player_entity->position); - } -} diff --git a/game/src/state.h b/game/src/state.h deleted file mode 100644 index 8bdcad5..0000000 --- a/game/src/state.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "camera.h" -#include "gvar.h" -#include "chunk/chunkman.h" -#include "entity/entman.h" - -void game_state_init (int ticks); -void game_state_tick (int ticks); diff --git a/game/src/states/state_common.c b/game/src/states/state_common.c new file mode 100644 index 0000000..1553d0e --- /dev/null +++ b/game/src/states/state_common.c @@ -0,0 +1,125 @@ +#include "state_common.h" + +GameState * +GameState_new () +{ + GameState *g = g_new0 (GameState, 1); + g->ui_context = UIContext_new (); + g->ui_context->tooltip = PMUID ("tooltip"); + return g; +} + +void +GameState_register_UIContext_handlers (GameState *self) +{ + /* UGH... I fucking hate this whole structure of the game I did + here. It should be really extensible and whatnot, but jesus + christ, it's so complex... */ +#define GAEH GameState_add_event_handler + + GAEH (self, 1, SDL_EVENT_WINDOW_RESIZED, NULL, NULL, UIContext_window_resize,self->ui_context); + GAEH (self, 1, SDL_EVENT_KEY_DOWN, evt_pred_flag, "ui_has_focus", UIContext_key_down, self->ui_context); + GAEH (self, 1, SDL_EVENT_KEY_UP, evt_pred_flag, "ui_has_focus", UIContext_key_up, self->ui_context); + GAEH (self, 1, SDL_EVENT_MOUSE_MOTION, evt_pred_flag, "ui_has_focus", UIContext_mouse_motion, self->ui_context); + GAEH (self, 1, SDL_EVENT_MOUSE_BUTTON_DOWN, evt_pred_flag, "ui_has_focus", UIContext_button_down, self->ui_context); + GAEH (self, 1, SDL_EVENT_MOUSE_BUTTON_UP, evt_pred_flag, "ui_has_focus", UIContext_button_up, self->ui_context); + GAEH (self, 1, SDL_EVENT_MOUSE_WHEEL, evt_pred_flag, "ui_has_focus", UIContext_mouse_wheel, self->ui_context); + GAEH (self, 1, SDL_EVENT_TEXT_INPUT, evt_pred_flag, "ui_has_focus", UIContext_text_input, self->ui_context); + +#undef GAEH +} + +void +GameState_add_event_handler (GameState *self, int priority, unsigned int on_event, + gboolean (*predicate) (SDL_Event *sdl_event, void *userdata), + void *predicate_data, + gboolean (*callback) (SDL_Event *sdl_event, void *userdata), + void *callback_data) +{ + EventHandler *h = g_new (EventHandler, 1); + h->on_event = on_event; + h->priority = priority; + h->predicate_data = predicate_data; + h->callback_data = callback_data; + h->predicate = predicate; + h->callback = callback; + + GList *iter = self->event_handlers; + while (iter && ((EventHandler *) iter->data)->priority >= priority) + { + iter = iter->next; + } + + self->event_handlers = g_list_insert_before (self->event_handlers, iter, h); +} + +void +GameState_handle_SDL_Event (GameState *self, SDL_Event *event) +{ + for (GList *l = self->event_handlers; l != NULL; l = l->next) + { + EventHandler *h = (EventHandler *) l->data; + + if ((h->on_event == 0 || h->on_event == event->type) + && (!h->predicate || h->predicate (event, h->predicate_data))) + { + if (h->callback && h->callback (event, h->callback_data)) + { + break; + } + } + } +} + +/* Event predicates, for convenience's sake. */ + +gboolean +evt_pred_key (SDL_Event *event, void *data) +{ + unsigned int expected_key = GPOINTER_TO_INT (data); + return event->key.key == expected_key; +} + +gboolean +evt_pred_flag (SDL_Event *event, void *data) +{ + UNUSED (event); + char *flag = data; + return FLAG_GET (flag); +} + +/* Event callbacks. */ + +gboolean +evt_cb_flag_off (SDL_Event *event, void *data) +{ + UNUSED (event); + char *flag = data; + FLAG_SET (flag, FALSE); + return TRUE; +} + +gboolean +evt_cb_flag_on (SDL_Event *event, void *data) +{ + UNUSED (event); + char *flag = data; + FLAG_SET (flag, TRUE); + return TRUE; +} + +gboolean +evt_cb_flag_switch (SDL_Event *event, void *data) +{ + UNUSED (event); + char *flag = data; + FLAG_SWITCH (flag); + return TRUE; +} + +gboolean +evt_cb_eat (SDL_Event *event, void *data) +{ + UNUSED (event, data); + return TRUE; +} diff --git a/game/src/states/state_common.h b/game/src/states/state_common.h new file mode 100644 index 0000000..a3a90c7 --- /dev/null +++ b/game/src/states/state_common.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include "../ui/ui_context.h" + +#include "../util.h" +#include "../gvar.h" + +typedef struct { + unsigned int on_event; + int priority; + void *predicate_data, *callback_data; + gboolean (*predicate) (SDL_Event *sdl_event, void *userdata); + gboolean (*callback) (SDL_Event *sdl_event, void *userdata); +} EventHandler; + +typedef struct GameState +{ + UIContext *ui_context; + GList *event_handlers; + + void (*on_enter) (struct GameState *); + void (*on_exit) (struct GameState *); + void (*on_update) (struct GameState *); + void (*on_render) (struct GameState *); +} GameState; + +GameState *GameState_new (); + +void GameState_register_UIContext_handlers (GameState *self); + +void GameState_add_event_handler (GameState *self, int priority, unsigned int on_event, + gboolean (*predicate) (SDL_Event *sdl_event, void *userdata), + void *predicate_data, + gboolean (*callback) (SDL_Event *sdl_event, void *userdata), + void *callback_data); + +void GameState_handle_SDL_Event (GameState *self, SDL_Event *event); + +gboolean evt_pred_key (SDL_Event *event, void *data); +gboolean evt_pred_flag (SDL_Event *event, void *data); + +gboolean evt_cb_flag_off (SDL_Event *event, void *data); +gboolean evt_cb_flag_on (SDL_Event *event, void *data); +gboolean evt_cb_flag_switch (SDL_Event *event, void *data); +gboolean evt_cb_eat (SDL_Event *event, void *data); diff --git a/game/src/states/state_global.c b/game/src/states/state_global.c new file mode 100644 index 0000000..6fbdc4b --- /dev/null +++ b/game/src/states/state_global.c @@ -0,0 +1,41 @@ +#include "state_global.h" + +/* The required callbacks. */ + +static void +_on_enter () +{ + gvar_set ("last_time", SDL_GetTicks ()); + g_print ("Successfuly initialized global state\n"); +} + +static void _on_exit () { return; } + +static void +_on_update () +{ + unsigned int now = SDL_GetTicks (); + gvar_set ("delta_time", (now - gvar_get ("last_time")) / 1000.0); + gvar_set ("last_time", now); +} + +static void _on_render () { return; } + +GameState * +state_global_new () +{ + GameState *self = GameState_new (); + +#define GAEH GameState_add_event_handler + + GAEH (self, 0, SDL_EVENT_WINDOW_RESIZED, NULL, NULL, graphics_cb_window_resize, NULL); + +#undef GAEH + + self->on_enter = _on_enter; + self->on_exit = _on_exit; + self->on_update = _on_update; + self->on_render = _on_render; + + return self; +} diff --git a/game/src/states/state_global.h b/game/src/states/state_global.h new file mode 100644 index 0000000..71ce682 --- /dev/null +++ b/game/src/states/state_global.h @@ -0,0 +1,8 @@ +#pragma once + +#include "state_common.h" + +#include "../graphics.h" +#include "../gvar.h" + +GameState *state_global_new (); diff --git a/game/src/states/state_main_menu.c b/game/src/states/state_main_menu.c new file mode 100644 index 0000000..3f38147 --- /dev/null +++ b/game/src/states/state_main_menu.c @@ -0,0 +1,43 @@ +#include "state_main_menu.h" + +static void +_on_enter () +{ + gvar_set ("ui_has_focus", TRUE); +} + +static void +_on_exit () +{ + +} + +static void +_on_update () +{ + +} + +static void +_on_render () +{ + +} + +GameState * +state_main_menu_new () +{ + GameState *g = GameState_new (); + + g->on_enter = _on_enter; + g->on_exit = _on_exit; + g->on_update = _on_update; + g->on_render = _on_render; + + /* If your GameState uses the UI, always call this. */ + GameState_register_UIContext_handlers (g); + + g->ui_context->root = PMUID ("main_menu"); + + return g; +} diff --git a/game/src/states/state_main_menu.h b/game/src/states/state_main_menu.h new file mode 100644 index 0000000..a59d8fe --- /dev/null +++ b/game/src/states/state_main_menu.h @@ -0,0 +1,8 @@ +#pragma once + +#include "state_common.h" + +#include "../graphics.h" +#include "../gvar.h" + +GameState *state_main_menu_new (); diff --git a/game/src/states/stateman.c b/game/src/states/stateman.c new file mode 100644 index 0000000..b533235 --- /dev/null +++ b/game/src/states/stateman.c @@ -0,0 +1,87 @@ +#include "stateman.h" + +static GHashTable *game_states; + +static GameState *current_state; +static GameState *global_state; + +void +stateman_init () +{ + game_states = g_hash_table_new (g_str_hash, g_str_equal); + + stateman_add_state ("main_menu", state_main_menu_new ()); + + global_state = state_global_new (); + global_state->on_enter (global_state); +} + +void +stateman_add_state (const char *name, GameState *state) +{ + g_hash_table_replace (game_states, g_strdup (name), state); +} + +void +stateman_switch_state (const char *name) +{ + GameState *next_state = g_hash_table_lookup (game_states, name); + + if (current_state && current_state->on_exit) + { + current_state->on_exit (current_state); + } + + if (next_state && next_state->on_enter) + { + /* When we enter, we also set the UI root to be the current + window size. After that, if callbacks for a given state are + set up correctly (using + GameState_register_UIContext_handlers), then it will update + the root size automatically.*/ + next_state->ui_context->root->size[0] = gvar_get ("window_width"); + next_state->ui_context->root->size[1] = gvar_get ("window_height"); + next_state->on_enter (next_state); + current_state = next_state; + } +} + +void stateman_update () +{ + global_state->on_update (global_state); + + if (current_state && current_state->on_update) + { + current_state->on_update (current_state); + } + + if (current_state && current_state->ui_context) + { + UIContext_update (current_state->ui_context); + } +} + +void +stateman_on_SDL_Event (SDL_Event *event) +{ + GameState_handle_SDL_Event (global_state, event); + + if (current_state && current_state->event_handlers) + { + GameState_handle_SDL_Event (current_state, event); + } +} + +void +stateman_render () +{ + if (current_state && current_state->on_render) + { + current_state->on_render (current_state); + } + + if (current_state && current_state->ui_context) + { + UIContext_render (current_state->ui_context); + } +} diff --git a/game/src/states/stateman.h b/game/src/states/stateman.h new file mode 100644 index 0000000..d1e3ac3 --- /dev/null +++ b/game/src/states/stateman.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#include "state_common.h" +#include "state_global.h" + +#include "state_main_menu.h" + +void stateman_init (); +static inline void stateman_free () { } /* TODO: implement */ +void stateman_add_state (const char *name, GameState *state); +void stateman_switch_state (const char *name); + +void stateman_update (); +void stateman_on_SDL_Event (SDL_Event *event); +void stateman_render (); diff --git a/game/src/ui/ui_context.c b/game/src/ui/ui_context.c new file mode 100644 index 0000000..3013db2 --- /dev/null +++ b/game/src/ui/ui_context.c @@ -0,0 +1,230 @@ +#include "ui_context.h" + +extern SDL_Window *sdl_window; + +UIContext * +UIContext_new () +{ + UIContext *u = g_new0 (UIContext, 1); + u->root = Widget_new (); + u->tooltip = Widget_new (); + return u; +} + +void +UIContext_update (UIContext *self) +{ + Widget_tick (self->root); +} + +void +UIContext_render (UIContext *self) +{ + glEnable (GL_SCISSOR_TEST); + glEnable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + + /* Probably good enough, LOL. No need to store that shiet + anywhere. */ + mat4 projection; + glm_ortho (0.0, gvar_get ("window_width"), gvar_get ("window_height"), 0.0, -1.0, 1.0, projection); + + Widget_render (self->root, projection, gvar_get ("window_height")); + Widget_render (self->tooltip, projection, gvar_get ("window_height")); + + glEnable (GL_DEPTH_TEST); + glDisable (GL_BLEND); + glDisable (GL_SCISSOR_TEST); +} + +/* UIContext callback helpers */ + +static inline gboolean +_call_on_event (Widget *widget, SDL_Event *sdl_event, WidgetEvent event) +{ + if (widget && widget->on_event[event]) + { + widget->on_event[event] (widget, sdl_event, widget->event_data[event]); + return TRUE; + } + + return FALSE; +} + +static inline void +_set_clicked (Widget *widget, gboolean state) +{ + if (widget) + { + widget->clicked = state; + } +} + +static inline void +_set_hovered (Widget *widget, gboolean state) +{ + if (widget) + { + widget->hovered = state; + } +} + +static inline void +_set_focused (Widget *widget, gboolean state) +{ + if (widget) + { + widget->focused = state; + } +} + +/* UIContext callbacks */ + +gboolean +UIContext_window_resize (SDL_Event *event, void *data) +{ + UNUSED (event); + UIContext *self = data; + self->root->size[0] = gvar_get ("window_width"); + self->root->size[1] = gvar_get ("window_height"); + return TRUE; +} + +gboolean +UIContext_key_down (SDL_Event *event, void *data) +{ + UIContext *self = data; + Widget *focused = self->focused_widget; + + SDL_Scancode sc = event->key.scancode; + + if (focused && focused->on_key[sc]) + { + focused->on_key[sc] (focused, event, focused->key_data[sc]); + return TRUE; + } + + if (focused && SDL_TextInputActive (sdl_window)) + { + return TRUE; + } + + return FALSE; +} + +gboolean +UIContext_key_up (SDL_Event *event, void *data) +{ + UNUSED (event, data); + return FALSE; +} + +gboolean +UIContext_mouse_motion (SDL_Event *event, void *data) +{ + UIContext *self = data; + + ivec2 pos = { event->motion.x, event->motion.y }; + Widget *new_hover = Widget_find_xy_cond (self->root, pos, wcond_any, NULL); + + if (new_hover != self->hovered_widget) + { + _call_on_event (self->hovered_widget, event, EVENT_MOUSE_LEAVE); + _set_hovered (self->hovered_widget, FALSE); + _call_on_event (new_hover, event, EVENT_MOUSE_ENTER); + _set_hovered (new_hover, TRUE); + self->hovered_widget = new_hover; + } + + _call_on_event (self->hovered_widget, event, EVENT_MOUSE_MOVE); + /* Even if it isn't the hovered widget, this is useful for stuff + like scrollbars. */ + _call_on_event (self->clicked_widget, event, EVENT_MOUSE_MOVE); + + /* TODO: Later... */ + + Widget *tooltip_source = Widget_find_xy_cond (self->root, pos, wcond_tooltip, NULL); + + if (tooltip_source && tooltip_source->tooltip && tooltip_source->tooltip->len > 0) + { + g_string_overwrite (self->tooltip->multiline_text.text, 0, tooltip_source->tooltip->str); + self->tooltip->visible = TRUE; + self->tooltip->position[0] = pos[0] + 12; + self->tooltip->position[1] = pos[1] + 12; + } + else + { + self->tooltip->visible = FALSE; + } + + /* This callback always eats the event, because why would the game + need mouse motion if the UI has stolen the focus? */ + return TRUE; + +} + +gboolean +UIContext_button_down (SDL_Event *event, void *data) +{ + UIContext *self = data; + Widget *focused_widget = self->focused_widget; + + ivec2 pos = { event->button.x, event->button.y }; + WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_DOWN : EVENT_RIGHT_DOWN; + Widget *widget = Widget_find_xy_cond (self->root, pos, wcond_any, NULL); + + _set_clicked (widget, TRUE); + self->clicked_widget = widget; + + if (widget != focused_widget) + { + _set_focused (focused_widget, FALSE); + _call_on_event (focused_widget, event, EVENT_FOCUS_LOST); + _set_focused (widget, TRUE); + _call_on_event (widget, event, EVENT_FOCUS_GAINED); + focused_widget = widget; + } + + return _call_on_event (widget, event, e); +} + +gboolean +UIContext_button_up (SDL_Event *event, void *data) +{ + UIContext *self = data; + WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_UP : EVENT_RIGHT_UP; + gboolean val = _call_on_event (self->clicked_widget, event, e); + + _set_clicked (self->clicked_widget, FALSE); + self->clicked_widget = NULL; + return val; + +} + +gboolean +UIContext_mouse_wheel (SDL_Event *event, void *data) +{ + UNUSED (event); + UIContext *self = data; + ivec2 pos = { event->button.x, event->button.y }; + + WidgetEvent e = event->wheel.y > 0 ? EVENT_SCROLL_UP : EVENT_SCROLL_DOWN; + Widget *widget = Widget_find_xy_cond (self->root, pos, wcond_event, GINT_TO_POINTER (e)); + return _call_on_event (widget, event, e); + +} + +gboolean +UIContext_text_input (SDL_Event *event, void *data) +{ + UNUSED (event); + UIContext *self = data; + + if (self->focused_widget) + { + _call_on_event (self->focused_widget, event, EVENT_TEXT_INPUT); + return TRUE; + } + + return FALSE; +} diff --git a/game/src/ui/ui_context.h b/game/src/ui/ui_context.h new file mode 100644 index 0000000..036cfa9 --- /dev/null +++ b/game/src/ui/ui_context.h @@ -0,0 +1,24 @@ +#pragma once + +#include "widget_core.h" +#include "../gvar.h" +#include "../graphics.h" + +typedef struct UIContext +{ + Widget *root, *hovered_widget, *clicked_widget, *focused_widget; + Widget *tooltip; +} UIContext; + +UIContext *UIContext_new (); +void UIContext_update (UIContext *self); +void UIContext_render (UIContext *self); + +gboolean UIContext_window_resize (SDL_Event *event, void *data); +gboolean UIContext_key_down (SDL_Event *event, void *data); +gboolean UIContext_key_up (SDL_Event *event, void *data); +gboolean UIContext_mouse_motion (SDL_Event *event, void *data); +gboolean UIContext_button_down (SDL_Event *event, void *data); +gboolean UIContext_button_up (SDL_Event *event, void *data); +gboolean UIContext_mouse_wheel (SDL_Event *event, void *data); +gboolean UIContext_text_input (SDL_Event *event, void *data); diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c deleted file mode 100644 index 74d8eae..0000000 --- a/game/src/ui/uiman.c +++ /dev/null @@ -1,256 +0,0 @@ -#include "uiman.h" - -extern SDL_Window *sdl_window; - -/* UI global state variables. */ - -static Widget *ui_root; -static mat4 projection; - -static Widget *hovered_widget = NULL; -static Widget *clicked_widget = NULL; -static Widget *focused_widget = NULL; - -static Widget *tooltip_widget = NULL; -static Widget *tooltip_text = NULL; - -void -uiman_init () -{ - ui_widget_mesh_init (); - glm_ortho (0.0, gvar_get ("window_width"), gvar_get ("window_height"), 0.0, -1.0, 1.0, projection); - - ui_root = Widget_new (); - ui_root->size[0] = gvar_get ("window_width"); - ui_root->size[1] = gvar_get ("window_height"); - - scm_c_primitive_load ("res/scripts/global/ui_styles.scm"); - scm_c_primitive_load ("res/scripts/global/ui_composites.scm"); - - SCM scm_debug = scm_c_primitive_load ("res/scripts/ui/debug_window.scm"); - Widget *debug_window = (Widget *) scm_to_pointer (scm_debug); - Widget_add_child (ui_root, debug_window); - - SCM scm_tooltip = scm_c_primitive_load ("res/scripts/ui/tooltip.scm"); - tooltip_widget = (Widget *) scm_to_pointer (scm_tooltip); - tooltip_text = g_array_index (tooltip_widget->children, Widget *, 0); -} - -void -uiman_tick () -{ - Widget_tick (ui_root); -} - -void -uiman_render () -{ - Widget_render (ui_root, projection, gvar_get ("window_height")); - Widget_render (tooltip_widget, projection, gvar_get ("window_height")); -} - -void -uiman_free () -{ - Widget_free (ui_root); -} - -static inline gboolean -_uiman_call_on_event (Widget *widget, SDL_Event *sdl_event, WidgetEvent event) -{ - if (widget && widget->on_event[event]) - { - widget->on_event[event] (widget, sdl_event, widget->event_data[event]); - return TRUE; - } - - return FALSE; -} - -static inline void -_uiman_set_clicked (Widget *widget, gboolean state) -{ - if (widget) - { - widget->clicked = state; - } -} - -static inline void -_uiman_set_hovered (Widget *widget, gboolean state) -{ - if (widget) - { - widget->hovered = state; - } -} - -static inline void -_uiman_set_focused (Widget *widget, gboolean state) -{ - if (widget) - { - widget->focused = state; - } -} - -gboolean -uiman_cb_switch_focus (SDL_Event *event, void *data) -{ - UNUSED (event, data); - FLAG_SWITCH ("ui_has_focus"); - SDL_SetWindowRelativeMouseMode (sdl_window, !FLAG_GET ("ui_has_focus")); - - /* We reset the global states of the UI. TODO: also launch the - callbacks on mouse leave? */ - SDL_StopTextInput (sdl_window); - _uiman_set_hovered (hovered_widget, FALSE); - hovered_widget = NULL; - _uiman_set_focused (focused_widget, FALSE); - focused_widget = NULL; - _uiman_set_clicked (clicked_widget, FALSE); - clicked_widget = NULL; - - tooltip_widget->visible = FALSE; - - return TRUE; -} - -gboolean -uiman_cb_window_resize (SDL_Event *event, void *data) -{ - UNUSED (event, data); - glm_ortho (0.0, gvar_get ("window_width"), gvar_get ("window_height"), 0.0, -1.0, 1.0, projection); - ui_root->size[0] = gvar_get ("window_width"); - ui_root->size[1] = gvar_get ("window_height"); - return FALSE; -} - -gboolean -uiman_cb_key_down (SDL_Event *event, void *data) -{ - UNUSED (data); - - SDL_Scancode sc = event->key.scancode; - if (focused_widget && focused_widget->on_key[sc]) - { - focused_widget->on_key[sc] (focused_widget, event, focused_widget->key_data[sc]); - return TRUE; - } - - if (focused_widget && SDL_TextInputActive (sdl_window)) - { - return TRUE; - } - - return FALSE; -} - -gboolean -uiman_cb_key_up (SDL_Event *event, void *data) -{ - UNUSED (event, data); - return FALSE; -} - -gboolean -uiman_cb_mouse_motion (SDL_Event *event, void *data) -{ - UNUSED (data); - ivec2 pos = { event->motion.x, event->motion.y }; - - Widget *new_hover = Widget_find_xy_cond (ui_root, pos, wcond_any, NULL); - - if (new_hover != hovered_widget) - { - _uiman_call_on_event (hovered_widget, event, EVENT_MOUSE_LEAVE); - _uiman_set_hovered (hovered_widget, FALSE); - _uiman_call_on_event (new_hover, event, EVENT_MOUSE_ENTER); - _uiman_set_hovered (new_hover, TRUE); - hovered_widget = new_hover; - } - - _uiman_call_on_event (hovered_widget, event, EVENT_MOUSE_MOVE); - /* Even if it isn't the hovered widget, this is useful for stuff - like scrollbars. */ - _uiman_call_on_event (clicked_widget, event, EVENT_MOUSE_MOVE); - - Widget *tooltip_source = Widget_find_xy_cond (ui_root, pos, wcond_tooltip, NULL); - - if (tooltip_source && tooltip_source->tooltip && tooltip_source->tooltip->len > 0) - { - g_string_overwrite (tooltip_text->multiline_text.text, 0, tooltip_source->tooltip->str); - tooltip_widget->visible = TRUE; - tooltip_widget->position[0] = pos[0] + 12; - tooltip_widget->position[1] = pos[1] + 12; - } - else - { - tooltip_widget->visible = FALSE; - } - - /* This callback always eats the event, because why would the game - need mouse motion if the UI has stolen the focus? */ - return TRUE; -} - -gboolean -uiman_cb_button_down (SDL_Event *event, void *data) -{ - UNUSED (data); - ivec2 pos = { event->button.x, event->button.y }; - - WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_DOWN : EVENT_RIGHT_DOWN; - Widget *widget = Widget_find_xy_cond (ui_root, pos, wcond_any, NULL); - - _uiman_set_clicked (widget, TRUE); - clicked_widget = widget; - - if (widget != focused_widget) - { - _uiman_set_focused (focused_widget, FALSE); - _uiman_call_on_event (focused_widget, event, EVENT_FOCUS_LOST); - _uiman_set_focused (widget, TRUE); - _uiman_call_on_event (widget, event, EVENT_FOCUS_GAINED); - focused_widget = widget; - } - - return _uiman_call_on_event (widget, event, e); -} - -gboolean -uiman_cb_button_up (SDL_Event *event, void *data) -{ - UNUSED (data); - - WidgetEvent e = event->button.button == SDL_BUTTON_LEFT ? EVENT_LEFT_UP : EVENT_RIGHT_UP; - gboolean val = _uiman_call_on_event (clicked_widget, event, e); - _uiman_set_clicked (clicked_widget, FALSE); - clicked_widget = NULL; - return val; -} - -gboolean -uiman_cb_mouse_wheel (SDL_Event *event, void *data) -{ - UNUSED (event, data); - ivec2 pos = { event->button.x, event->button.y }; - - WidgetEvent e = event->wheel.y > 0 ? EVENT_SCROLL_UP : EVENT_SCROLL_DOWN; - Widget *widget = Widget_find_xy_cond (ui_root, pos, wcond_event, GINT_TO_POINTER (e)); - return _uiman_call_on_event (widget, event, e); -} - -gboolean -uiman_cb_text_input (SDL_Event *event, void *data) -{ - UNUSED (event, data); - - if (focused_widget) - { - _uiman_call_on_event (focused_widget, event, EVENT_TEXT_INPUT); - return TRUE; - } - - return FALSE; -} diff --git a/game/src/ui/uiman.h b/game/src/ui/uiman.h deleted file mode 100644 index 78df2d2..0000000 --- a/game/src/ui/uiman.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -#include - -#include "widget_core.h" -#include "../gvar.h" -#include "../state.h" -#include "../camera.h" -#include "../graphics.h" - -void uiman_init (); -void uiman_tick (); -void uiman_render (); -void uiman_free (); - -gboolean uiman_cb_switch_focus (SDL_Event *event, void *data); - -gboolean uiman_cb_window_resize (SDL_Event *event, void *data); -gboolean uiman_cb_key_down (SDL_Event *event, void *data); -gboolean uiman_cb_key_up (SDL_Event *event, void *data); -gboolean uiman_cb_mouse_motion (SDL_Event *event, void *data); -gboolean uiman_cb_button_down (SDL_Event *event, void *data); -gboolean uiman_cb_button_up (SDL_Event *event, void *data); -gboolean uiman_cb_mouse_wheel (SDL_Event *event, void *data); -gboolean uiman_cb_text_input (SDL_Event *event, void *data);