From c86b8ef7bbe56f8dc3295fcb558b1b30311bebac Mon Sep 17 00:00:00 2001 From: Emil Kosz Date: Sun, 20 Jul 2025 20:23:51 +0200 Subject: [PATCH] more guile features --- game/res/scripts/global/ui_composites.scm | 32 ++++++++++-- game/res/scripts/ui/debug_window.scm | 11 ++--- game/src/chunk/chunkman.c | 24 ++++----- game/src/entity/entman.c | 20 ++++---- game/src/graphics.c | 24 +++++---- game/src/graphics.h | 1 + game/src/main.c | 4 +- game/src/state.c | 11 ++--- game/src/ui/uiman.c | 13 +++-- game/src/ui/widget_guile.c | 59 +++++++++++++++-------- 10 files changed, 125 insertions(+), 74 deletions(-) diff --git a/game/res/scripts/global/ui_composites.scm b/game/res/scripts/global/ui_composites.scm index b14c3b3..edc0307 100644 --- a/game/res/scripts/global/ui_composites.scm +++ b/game/res/scripts/global/ui_composites.scm @@ -1,3 +1,5 @@ +(use-modules (ice-9 format)) + (define (widget-checkbox-icon-switch widget event) (if (= (widget-get-icon widget) 1) (widget-set-icon! widget 2) @@ -14,13 +16,35 @@ #:on-click (lambda (w e) (widget-checkbox-icon-switch w e) (flag-switch flag))) (widget-new 'label #:style style-default #:text text #:layout-weight 1))))) -(define (widget-spinner . args) +(define (coerce type val) + (cond + ((eq? type 'int) (inexact->exact (round val))) + ((eq? type 'bool) (if (> val 0.5) #t #f)) + (else val))) + +(define (widget-spinner type fmt gvar . args) (apply widget-new (append (list 'container #:horizontal #t #:layout-spacing 8) args (list - (widget-new 'plain #:style style-icon-button #:icon 3 #:aspect-ratio 1) - (widget-new 'label #:style style-default #:layout-weight 1) - (widget-new 'plain #:style style-icon-button #:icon 4 #:aspect-ratio 1))))) + (widget-new 'plain #:style style-icon-button #:icon 3 #:aspect-ratio 1 + #:on-click (lambda (w e) + (gvar-set gvar (- (gvar-get gvar) 1)))) + (widget-new 'label #:style style-default #:layout-weight 1 #:text-alignment 'center + #:on-tick (lambda (w e) + (widget-set-text! w (apply format #f fmt (list (coerce type (gvar-get gvar))))))) + (widget-new 'plain #:style style-icon-button #:icon 4 #:aspect-ratio 1 + #:on-click (lambda (w e) + (gvar-set gvar (+ (gvar-get gvar) 1)))))))) + +(define (widget-label-gvar type fmt gvar . args) + (apply + widget-new + (append + (list 'label + #:on-tick + (lambda (w e) + (widget-set-text! w (apply format #f fmt (list (coerce type (gvar-get gvar))))))) + args))) diff --git a/game/res/scripts/ui/debug_window.scm b/game/res/scripts/ui/debug_window.scm index 86f4883..97f8e0c 100644 --- a/game/res/scripts/ui/debug_window.scm +++ b/game/res/scripts/ui/debug_window.scm @@ -1,7 +1,6 @@ +(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. -(gvar-set "Some crap" 100.0) - (widget-new 'window #:style style-window @@ -17,9 +16,9 @@ #:layout-padding 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-checkbox "Flight" "flight_enabled" #:layout-weight 0.5 #:h 20) (widget-checkbox "Wireframe" "wireframe_enabled" #:layout-weight 0.5 #:h 20) - (widget-new 'label #:style style-default #:layout-weight 1 #:h 20 - #:on-tick (lambda (w e) (widget-set-text! w (number->string (gvar-get "Some crap"))))) - (widget-spinner #:layout-weight 1 #:h 20) - (widget-new 'entry #:style style-default #:layout-weight 1 #:h 20 #:text "Enter text..."))) + (widget-spinner 'int "Render distance: ~d" "render_distance" #:layout-weight 1 #:h 20))) diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index ba0a7e2..71b1a1b 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -1,9 +1,5 @@ #include "chunkman.h" -extern int render_distance; - -int n_frame_chunks; - static GHashTable *chunks; static GHashTable *chunk_meshes; @@ -112,6 +108,8 @@ chunkman_tick (vec3 position) uint64_t start = SDL_GetPerformanceCounter (); uint64_t freq = SDL_GetPerformanceFrequency (); double elapsed_us = 0; + + int render_distance = gvar_get ("render_distance"); for (int z = cz - render_distance - 1; z <= cz + render_distance + 1; ++z) { @@ -148,9 +146,9 @@ chunkman_tick (vec3 position) { chunkman_generate_ChunkMesh_at (x, z); } + } } } -} void chunkman_render (vec3 position, vec4 planes[6]) @@ -170,7 +168,8 @@ chunkman_render (vec3 position, vec4 planes[6]) texture_use (RESTEX ("terrain3"), 3); texture_use (RESTEX ("terrain4"), 4); - n_frame_chunks = 0; + int render_distance = gvar_get ("render_distance"); + int frame_chunks = 0; for (int z = cz - render_distance; z <= cz + render_distance; ++z) { @@ -178,9 +177,9 @@ chunkman_render (vec3 position, vec4 planes[6]) { /* Render in a circle instead of a square. */ if ((x - cx) * (x - cx) + (z - cz) * (z - cz) > render_distance*render_distance) - { - continue; - } + { + continue; + } ChunkMesh *mesh = chunkman_get_ChunkMesh_at (x, z); if (mesh != NULL) @@ -205,12 +204,13 @@ chunkman_render (vec3 position, vec4 planes[6]) program_set_vec3_ind (RESPRG ("chunk"), "chunk_position", x * CHUNK_DIM, 0.0, z * CHUNK_DIM); ChunkMesh_render (mesh, FLAG_GET ("wireframe_enabled")); - n_frame_chunks++; + frame_chunks++; } + } } -} -bound = false; + bound = false; + gvar_set ("frame_chunks", frame_chunks); } Chunk * diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index af3095e..8f9d128 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -7,10 +7,8 @@ seperately somehow. */ extern vec3 camera_position; -extern int render_distance; Entity *player_entity, *sky_entity; -int n_frame_ents; /* The GArray is the fastest of all sequence types. Should work fine for a billion entities. */ @@ -108,7 +106,7 @@ entman_tick () } } -void +gboolean entman_render_entity (Entity *entity, void *userdata) { struct { @@ -120,9 +118,10 @@ entman_render_entity (Entity *entity, void *userdata) if (!entity->visible) { - return; + return FALSE; } + int render_distance = gvar_get ("render_distance"); /* Why an int, why int division? It's simply much faster than floating point operations. No need to have super accurate cull distance anyway, and might as well save a lot when rendering entities. */ @@ -136,7 +135,7 @@ entman_render_entity (Entity *entity, void *userdata) if (glm_vec2_distance2 (c_xz, e_xz) > cull_dist*cull_dist && !entity->dont_cull) { - return; + return FALSE; } #if FRUSTUM_CULL @@ -145,7 +144,7 @@ entman_render_entity (Entity *entity, void *userdata) if (!glm_aabb_frustum (aabb, *vp->frustum_planes)) { - return; + return FALSE; } #endif @@ -234,7 +233,7 @@ entman_render_entity (Entity *entity, void *userdata) } SimpleMesh_render (&to_render, FLAG_GET ("wireframe_enabled")); - n_frame_ents++; + return TRUE; } void @@ -247,7 +246,6 @@ entman_render (mat4 *view, vec4 planes[6]) last_program = -1; last_texture = -1; last_type = -1; - n_frame_ents = 0; struct { mat4 *view; @@ -261,11 +259,15 @@ entman_render (mat4 *view, vec4 planes[6]) #endif }; + int frame_entities = 0; + for (guint i = 0; i < entities->len; ++i) { Entity *e = g_array_index (entities, Entity*, i); - entman_render_entity (e, &data); + frame_entities += entman_render_entity (e, &data) ? 1 : 0; } + + gvar_set ("frame_entities", frame_entities); } void diff --git a/game/src/graphics.c b/game/src/graphics.c index 5db5ba0..267f29b 100644 --- a/game/src/graphics.c +++ b/game/src/graphics.c @@ -1,11 +1,8 @@ #include "graphics.h" extern vec3 camera_position; -extern int last_time; SDL_Window *sdl_window; -int sdl_window_w = 800, sdl_window_h = 600; -int render_distance = 2; static SDL_GLContext gl_context; static uint64_t last_check_perf = 0; @@ -15,12 +12,16 @@ static double avg_elapsed = 0; void graphics_init () { + gvar_set ("render_distance", 2); + gvar_set ("window_width", 800); + gvar_set ("window_height", 600); + if (!SDL_Init (SDL_INIT_VIDEO)) { g_error ("Couldn't initialize SDL: %s", SDL_GetError ()); } - sdl_window = SDL_CreateWindow (GAME_NAME, sdl_window_w, sdl_window_h, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); + sdl_window = SDL_CreateWindow (GAME_NAME, gvar_get ("window_width"), gvar_get ("window_height"), SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE); if (!sdl_window) { @@ -50,7 +51,7 @@ graphics_init () g_info ("GLSL version: %s", glGetString (GL_SHADING_LANGUAGE_VERSION)); g_info ("Max vertex attributes: %d", GL_MAX_VERTEX_ATTRIBS); - glViewport (0, 0, sdl_window_w, sdl_window_h); + glViewport (0, 0, gvar_get ("window_width"), gvar_get ("window_height")); glClearColor (0, 0.3, 0.8, 1); glEnable (GL_CULL_FACE); @@ -68,12 +69,12 @@ graphics_render () uint64_t freq = SDL_GetPerformanceFrequency (); mat4 projection, view; - camera_get_projection ((float) sdl_window_w / (float) sdl_window_h, projection); + camera_get_projection (gvar_get ("window_width") / gvar_get ("window_height"), projection); camera_get_view (view); resources_programs_set_mat4 ("projection", &projection); resources_programs_set_mat4 ("view", &view); - resources_programs_set_float ("time", last_time); + resources_programs_set_float ("time", gvar_get ("last_time")); vec4 planes[6]; #if FRUSTUM_CULL @@ -102,17 +103,19 @@ graphics_render () 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) { - render_distance++; + gvar_set ("render_distance", ++render_distance); } else if (avg > RENDER_FRAME_BUDGET_US && render_distance > RENDER_DISTANCE_MIN) { - render_distance--; + gvar_set ("render_distance", --render_distance); } avg_elapsed = 0; @@ -133,8 +136,11 @@ gboolean graphics_cb_window_resize (SDL_Event *event, void *data) { UNUSED (event, data); + int sdl_window_w, sdl_window_h; SDL_GetWindowSizeInPixels (sdl_window, &sdl_window_w, &sdl_window_h); glViewport (0, 0, sdl_window_w, sdl_window_h); + gvar_set ("window_width", sdl_window_w); + gvar_set ("window_height", sdl_window_h); /* Since other subsystems might want to use the event. */ return FALSE; } diff --git a/game/src/graphics.h b/game/src/graphics.h index f8299b7..94f11de 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -10,6 +10,7 @@ #include "state.h" #include "resources.h" #include "util.h" +#include "gvar.h" #define FRUSTUM_CULL 1 diff --git a/game/src/main.c b/game/src/main.c index a124605..b983fa9 100644 --- a/game/src/main.c +++ b/game/src/main.c @@ -23,10 +23,10 @@ SDL_AppInit (void **appstate, int argc, char **argv) scm_init_guile (); gvar_guile_register (); widget_guile_register (); - + + gvar_init (); graphics_init (); resources_init (); - gvar_init (); evtman_init (); uiman_init (); chunkman_init (); diff --git a/game/src/state.c b/game/src/state.c index ceddb68..c98f4bf 100644 --- a/game/src/state.c +++ b/game/src/state.c @@ -4,22 +4,21 @@ extern vec3 camera_position; extern vec3 camera_rotation; extern Entity *player_entity, *sky_entity; -float delta_time; -int last_time; - void game_state_init (int ticks) { - last_time = ticks; + gvar_set ("last_time", ticks); } void game_state_tick (int ticks) { /* Caluclate stuff per frame. */ - delta_time = (ticks - last_time) / 1000.0; - last_time = ticks; + 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); diff --git a/game/src/ui/uiman.c b/game/src/ui/uiman.c index e4a7369..02c6e0f 100644 --- a/game/src/ui/uiman.c +++ b/game/src/ui/uiman.c @@ -1,7 +1,6 @@ #include "uiman.h" extern SDL_Window *sdl_window; -extern int sdl_window_w, sdl_window_h; /* UI global state variables. */ @@ -19,10 +18,10 @@ void uiman_init () { ui_widget_mesh_init (); - glm_ortho (0.0, sdl_window_w, sdl_window_h, 0.0, -1.0, 1.0, projection); + glm_ortho (0.0, gvar_get ("window_width"), gvar_get ("window_height"), 0.0, -1.0, 1.0, projection); ui_root = Widget_new (); - IVEC2_SETI (ui_root->size, sdl_window_w, sdl_window_h); + IVEC2_SETI (ui_root->size, gvar_get ("window_width"), gvar_get ("window_height")); scm_c_primitive_load ("res/scripts/global/ui_styles.scm"); scm_c_primitive_load ("res/scripts/global/ui_composites.scm"); @@ -45,8 +44,8 @@ uiman_tick () void uiman_render () { - Widget_render (ui_root, projection, sdl_window_h); - Widget_render (tooltip_widget, projection, sdl_window_h); + Widget_render (ui_root, projection, gvar_get ("window_height")); + Widget_render (tooltip_widget, projection, gvar_get ("window_height")); } void @@ -120,8 +119,8 @@ gboolean uiman_cb_window_resize (SDL_Event *event, void *data) { UNUSED (event, data); - glm_ortho (0.0, sdl_window_w, sdl_window_h, 0.0, -1.0, 1.0, projection); - IVEC2_SETI (ui_root->size, sdl_window_w, sdl_window_h); + glm_ortho (0.0, gvar_get ("window_width"), gvar_get ("window_height"), 0.0, -1.0, 1.0, projection); + IVEC2_SETI (ui_root->size, gvar_get ("window_width"), gvar_get ("window_height")); return FALSE; } diff --git a/game/src/ui/widget_guile.c b/game/src/ui/widget_guile.c index 8acafb4..3a6fe5b 100644 --- a/game/src/ui/widget_guile.c +++ b/game/src/ui/widget_guile.c @@ -235,6 +235,22 @@ _wgcb_event (Widget *w, SDL_Event *event, void *data) } } +static inline TextAlignment +_str_to_textalignment (const char *str) +{ + if (!g_strcmp0 (str, "center")) + { + return TEXT_ALIGN_CENTER; + } + + if (!g_strcmp0 (str, "right")) + { + return TEXT_ALIGN_RIGHT; + } + + return TEXT_ALIGN_LEFT; +} + static void _wgg_set_property (Widget *w, const char *key, SCM val) { @@ -345,24 +361,39 @@ _wgg_set_property (Widget *w, const char *key, SCM val) switch (w->kind) { case WIDGET_LABEL: - g_string_overwrite (w->label.text, 0, scm_to_utf8_string (val)); + g_string_assign (w->label.text, scm_to_utf8_string (val)); break; case WIDGET_MULTILINE_TEXT: - g_string_overwrite (w->multiline_text.text, 0, scm_to_utf8_string (val)); + g_string_assign (w->multiline_text.text, scm_to_utf8_string (val)); break; case WIDGET_WINDOW: - g_string_overwrite (w->window.title, 0, scm_to_utf8_string (val)); + g_string_assign (w->window.title, scm_to_utf8_string (val)); break; case WIDGET_ENTRY: - g_string_overwrite (w->entry.ghost_text, 0, scm_to_utf8_string (val)); + g_string_assign (w->entry.ghost_text, scm_to_utf8_string (val)); default: break; } } + if (!g_strcmp0 (key, "text-alignment")) + { + const char *s = scm_symbol_to_string (val) ? scm_to_utf8_string (scm_symbol_to_string (val)) : NULL; + + if (s != NULL && w->kind == WIDGET_LABEL) + { + w->label.text_alignment = _str_to_textalignment (s); + } + + if (s != NULL && w->kind == WIDGET_MULTILINE_TEXT) + { + w->multiline_text.text_alignment = _str_to_textalignment (s); + } + } + if (!g_strcmp0 (key, "tooltip")) { - g_string_overwrite (w->tooltip, 0, scm_to_utf8_string (val)); + g_string_assign (w->tooltip, scm_to_utf8_string (val)); } if (!g_strcmp0 (key, "on-tick")) @@ -470,14 +501,6 @@ _wg_set_icon (SCM widget_ptr, SCM icon_val) return SCM_UNSPECIFIED; } -static SCM -_wg_get_child (SCM widget_ptr, SCM index_val) -{ - Widget *w = (Widget *) scm_to_pointer (widget_ptr); - int index = scm_to_int (index_val); - return scm_from_pointer (g_array_index (w->children, Widget *, index), NULL); -} - static SCM _wg_set_text (SCM widget_ptr, SCM val) { @@ -486,16 +509,16 @@ _wg_set_text (SCM widget_ptr, SCM val) switch (w->kind) { case WIDGET_LABEL: - g_string_overwrite (w->label.text, 0, scm_to_utf8_string (val)); + g_string_assign (w->label.text, scm_to_utf8_string (val)); break; case WIDGET_MULTILINE_TEXT: - g_string_overwrite (w->multiline_text.text, 0, scm_to_utf8_string (val)); + g_string_assign (w->multiline_text.text, scm_to_utf8_string (val)); break; case WIDGET_WINDOW: - g_string_overwrite (w->window.title, 0, scm_to_utf8_string (val)); + g_string_assign (w->window.title, scm_to_utf8_string (val)); break; case WIDGET_ENTRY: - g_string_overwrite (w->entry.ghost_text, 0, scm_to_utf8_string (val)); + g_string_assign (w->entry.ghost_text, scm_to_utf8_string (val)); default: break; } @@ -512,7 +535,5 @@ widget_guile_register () scm_c_define_gsubr ("widget-get-icon", 1, 0, 0, _wg_get_icon); scm_c_define_gsubr ("widget-set-icon!", 2, 0, 0, _wg_set_icon); - scm_c_define_gsubr ("widget-get-child", 2, 0, 0, _wg_get_child); - scm_c_define_gsubr ("widget-set-text!", 2, 0, 0, _wg_set_text); }