Game state implementation
This commit is contained in:
@@ -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
|
||||
global=res/scripts/global/ui_styles.scm;res/scripts/global/ui_composites.scm
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
@@ -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))
|
||||
|
||||
@@ -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)))
|
||||
|
||||
@@ -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)
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <glib-2.0/glib.h>
|
||||
#include <cglm/cglm.h>
|
||||
|
||||
#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);
|
||||
@@ -1,12 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <glib-2.0/glib.h>
|
||||
|
||||
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;
|
||||
+6
-63
@@ -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
|
||||
|
||||
+2
-3
@@ -4,10 +4,8 @@
|
||||
#include <SDL3/SDL_opengles2.h>
|
||||
#include <SDL3_image/SDL_image.h>
|
||||
|
||||
#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 ();
|
||||
|
||||
@@ -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))
|
||||
|
||||
+30
-19
@@ -2,18 +2,14 @@
|
||||
#include <SDL3/SDL_main.h>
|
||||
#include <libguile.h>
|
||||
|
||||
#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 ();
|
||||
}
|
||||
|
||||
+43
-1
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <glib-2.0/glib.h>
|
||||
|
||||
#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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "state_common.h"
|
||||
|
||||
#include "../graphics.h"
|
||||
#include "../gvar.h"
|
||||
|
||||
GameState *state_global_new ();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "state_common.h"
|
||||
|
||||
#include "../graphics.h"
|
||||
#include "../gvar.h"
|
||||
|
||||
GameState *state_main_menu_new ();
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <glib-2.0/glib.h>
|
||||
|
||||
#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 ();
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <libguile.h>
|
||||
|
||||
#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);
|
||||
Reference in New Issue
Block a user