diff --git a/game/res/scripts/u_debug.scm b/game/res/scripts/u_debug.scm index 7289978..373db5b 100644 --- a/game/res/scripts/u_debug.scm +++ b/game/res/scripts/u_debug.scm @@ -1,23 +1,25 @@ ;; The function is evaulated and returns a pointer, the game eats it ;; and adds it to the UI root. Boom. (widget-new - 'window - #:style style-window - #:text "Debug window" - #:w 350 - #:layout-padding 8 - #:vertical #f - #:horizontal #t - ;; The rest is children. + 'plain (widget-new - 'flowbox - #:style style-container + 'window + #:style style-window + #:text "Debug window" + #:w 350 #:layout-padding 8 - #:layout-spacing 8 + #:vertical #f #: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 "~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))) + ;; The rest is children. + (widget-new + 'flowbox + #:style style-container + #: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 "~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/u_main_menu.scm b/game/res/scripts/u_main_menu.scm index 7d35722..e520a7e 100644 --- a/game/res/scripts/u_main_menu.scm +++ b/game/res/scripts/u_main_menu.scm @@ -1,11 +1,14 @@ (widget-new - 'flowbox - #:style style-container - #:layout-padding 8 - #:layout-spacing 8 - #:horizontal #t - (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "New game" - #:on-click (lambda (w e) (switch-stage "game"))) - (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "Options") - (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "Quit game")) + 'plain + (widget-new + 'flowbox + #:style style-container + #:w 300 + #:layout-padding 8 + #:layout-spacing 8 + #:horizontal #t + (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "New game" + #:on-click (lambda (w e) (switch-stage "ingame"))) + (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "Options") + (widget-new 'label #:style style-button #:layout-weight 1 #:h 20 #:text-alignment 'center #:text "Quit game"))) diff --git a/game/src/chunk/chunkman.c b/game/src/chunk/chunkman.c index 8fee647..5d736a2 100644 --- a/game/src/chunk/chunkman.c +++ b/game/src/chunk/chunkman.c @@ -5,6 +5,9 @@ static GHashTable *chunk_meshes; static gboolean bound = false; +static Profiler profiler; +static const int frame_budget_us = 500; + guint chunkman_ivec2_hash (gconstpointer key) { @@ -105,9 +108,7 @@ chunkman_tick (vec3 position) int cx, cz; chunkman_world_to_chunk (position[0], position[2], &cx, &cz); - uint64_t start = SDL_GetPerformanceCounter (); - uint64_t freq = SDL_GetPerformanceFrequency (); - double elapsed_us = 0; + Profiler_begin (&profiler); int render_distance = gvar_get ("render_distance"); @@ -115,10 +116,9 @@ chunkman_tick (vec3 position) { for (int x = cx - render_distance - 1; x <= cx + render_distance + 1; ++x) { - uint64_t now = SDL_GetPerformanceCounter (); - elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + double elapsed = Profiler_sample (&profiler); - if (elapsed_us > CHUNK_FRAME_BUDGET_US) + if (elapsed > frame_budget_us) { return; } @@ -134,10 +134,9 @@ chunkman_tick (vec3 position) { for (int x = cx - render_distance; x <= cx + render_distance; ++x) { - uint64_t now = SDL_GetPerformanceCounter (); - elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + double elapsed = Profiler_sample (&profiler); - if (elapsed_us > CHUNK_FRAME_BUDGET_US) + if (elapsed > frame_budget_us) { return; } diff --git a/game/src/chunk/chunkman.h b/game/src/chunk/chunkman.h index 9f5b8e9..a3e2dec 100644 --- a/game/src/chunk/chunkman.h +++ b/game/src/chunk/chunkman.h @@ -10,6 +10,7 @@ #include "../graphics.h" #include "../gvar.h" #include "../pakman.h" +#include "../profiler.h" #define TERRAIN_HEIGHT 8.0 diff --git a/game/src/entity/entman.c b/game/src/entity/entman.c index 35443bb..28372c4 100644 --- a/game/src/entity/entman.c +++ b/game/src/entity/entman.c @@ -19,10 +19,14 @@ static unsigned int last_type = 0; static unsigned int last_texture = 0; /* These are defined as statics so we don't get those values from gvar - every frame.. */ + for every entity... */ static int render_distance = 2; static gboolean wireframe_enabled = FALSE; +static Profiler profiler = { 0 }; + +static const int frame_budget_us = 500; + void character_on_tick (Entity *entity) { @@ -63,7 +67,9 @@ void spawn_queue_process_one () { if (g_queue_is_empty(spawn_requests)) - return; + { + return; + } SpawnRequest *req = g_queue_pop_head (spawn_requests); @@ -80,16 +86,13 @@ spawn_queue_process_one () void entman_tick () { - uint64_t start = SDL_GetPerformanceCounter (); - uint64_t freq = SDL_GetPerformanceFrequency (); - double elapsed_us = 0; + Profiler_begin (&profiler); while (!g_queue_is_empty (spawn_requests)) { - uint64_t now = SDL_GetPerformanceCounter(); - elapsed_us = (double) (now - start) * 1000000.0 / (double) freq; + double elapsed = Profiler_sample (&profiler); - if (elapsed_us > ENTITY_FRAME_BUDGET_US) + if (elapsed > frame_budget_us) { break; } diff --git a/game/src/entity/entman.h b/game/src/entity/entman.h index e3a53ae..8c4a818 100644 --- a/game/src/entity/entman.h +++ b/game/src/entity/entman.h @@ -14,6 +14,7 @@ #include "../graphics.h" #include "../gvar.h" #include "../pakman.h" +#include "../profiler.h" #define ENTADD(entity) (entman_add_entity (entity)) diff --git a/game/src/graphics.h b/game/src/graphics.h index 948a70f..e5cbf77 100644 --- a/game/src/graphics.h +++ b/game/src/graphics.h @@ -2,24 +2,14 @@ #include #include -#include -#include "chunk/chunkman.h" -#include "entity/entman.h" +#include + #include "util.h" #include "gvar.h" -#include "pakman.h" #define FRUSTUM_CULL 1 -#define CHUNK_FRAME_BUDGET_US 500 -#define ENTITY_FRAME_BUDGET_US 500 - -#define RENDER_FRAME_BUDGET_US 16666 /* 60 FPS */ -#define RENDER_AVG_FREQ_S 10 -#define RENDER_DISTANCE_MIN 2 -#define RENDER_DISTANCE_MAX 12 - void graphics_init (); void graphics_prerender (); void graphics_postrender (); diff --git a/game/src/profiler.c b/game/src/profiler.c new file mode 100644 index 0000000..8c931cc --- /dev/null +++ b/game/src/profiler.c @@ -0,0 +1,47 @@ +#include "profiler.h" + +void +Profiler_begin (Profiler *p) +{ + p->start_time = SDL_GetPerformanceCounter (); +} + +double +Profiler_sample (Profiler *p) +{ + uint64_t now = SDL_GetPerformanceCounter (); + uint64_t freq = SDL_GetPerformanceFrequency (); + double elapsed_us = (double) (now - p->start_time) * 1000000.0 / (double) freq; + + p->total_us += elapsed_us; + p->sample_count += 1; + + return elapsed_us; +} + +void +Profiler_reset (Profiler *p) +{ + p->total_us = 0.0; + p->sample_count = 0; + p->last_check_time = SDL_GetPerformanceCounter(); +} + +double +Profiler_average (Profiler *p) +{ + if (p->sample_count == 0) + { + return 0; + } + + return p->total_us / (double) p->sample_count; +} + +gboolean +Profiler_should_check (Profiler *p, int seconds) +{ + uint64_t now = SDL_GetPerformanceCounter (); + uint64_t freq = SDL_GetPerformanceFrequency (); + return (now - p->last_check_time) >= (uint64_t) (freq * seconds); +} diff --git a/game/src/profiler.h b/game/src/profiler.h new file mode 100644 index 0000000..aa2888a --- /dev/null +++ b/game/src/profiler.h @@ -0,0 +1,18 @@ +#pragma once + +#include +#include + +typedef struct Profiler +{ + uint64_t start_time, last_check_time; + double total_us; + int sample_count; +} Profiler; + +void Profiler_begin (Profiler *p); +double Profiler_sample (Profiler *p); +void Profiler_reset (Profiler *p); + +double Profiler_average (Profiler *p); +gboolean Profiler_should_check (Profiler *p, int seconds); diff --git a/game/src/stage/stage_game.h b/game/src/stage/stage_game.h deleted file mode 100644 index c500582..0000000 --- a/game/src/stage/stage_game.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "stage_common.h" - -#include "../graphics.h" -#include "../gvar.h" -#include "../camera.h" - -GameStage *stage_game_new (); diff --git a/game/src/stage/stage_global.c b/game/src/stage/stage_global.c index 92bce6c..4ffe361 100644 --- a/game/src/stage/stage_global.c +++ b/game/src/stage/stage_global.c @@ -1,16 +1,11 @@ #include "stage_global.h" -/* The required callbacks. */ - static void _on_enter () { gvar_set ("last_time", SDL_GetTicks ()); - g_print ("Successfuly initialized global stage\n"); } -static void _on_exit () { return; } - static void _on_update () { @@ -31,7 +26,6 @@ stage_global_new () #undef GAEH self->on_enter = _on_enter; - self->on_exit = _on_exit; self->on_update = _on_update; return self; diff --git a/game/src/stage/stage_game.c b/game/src/stage/stage_ingame.c similarity index 89% rename from game/src/stage/stage_game.c rename to game/src/stage/stage_ingame.c index 56e4230..74d1f75 100644 --- a/game/src/stage/stage_game.c +++ b/game/src/stage/stage_ingame.c @@ -1,9 +1,15 @@ -#include "stage_game.h" +#include "stage_ingame.h" extern SDL_Window *sdl_window; - extern Entity *player_entity, *sky_entity; +static Profiler profiler = { 0 }; +static const int profiler_check_freq_s = 10; + +static const int render_frame_budget_us = 16666; +static const int render_distance_min = 2; +static const int render_distance_max = 12; + static void _on_enter () { @@ -92,6 +98,8 @@ _on_update (GameStage *self) static void _on_render (GameStage *self) { + Profiler_begin (&profiler); + mat4 projection, view; Camera_get_projection (self->camera, gvar_get ("window_width") / gvar_get ("window_height"), projection); Camera_get_view (self->camera, view); @@ -109,6 +117,19 @@ _on_render (GameStage *self) chunkman_render (self->camera->position, planes); entman_render (self->camera->position, view, planes); + + Profiler_sample (&profiler); + + if (Profiler_should_check (&profiler, profiler_check_freq_s)) + { + int render_distance = gvar_get ("render_distance"); + + render_distance += Profiler_average (&profiler) < render_frame_budget_us ? 1 : -1; + render_distance = glm_clamp (render_distance, render_distance_min, render_distance_max); + gvar_set ("render_distance", render_distance); + + Profiler_reset (&profiler); + } } /* Some helper callbacks for the game gamestage. */ @@ -141,7 +162,7 @@ _freelook_camera (SDL_Event *event, void *userdata) } GameStage * -stage_game_new () +stage_ingame_new () { GameStage *self = GameStage_new (); diff --git a/game/src/stage/stage_ingame.h b/game/src/stage/stage_ingame.h new file mode 100644 index 0000000..bcf7547 --- /dev/null +++ b/game/src/stage/stage_ingame.h @@ -0,0 +1,13 @@ +#pragma once + +#include "stage_common.h" + +#include "../gvar.h" +#include "../camera.h" +#include "../profiler.h" +#include "../graphics.h" + +#include "../entity/entman.h" +#include "../chunk/chunkman.h" + +GameStage *stage_ingame_new (); diff --git a/game/src/stage/stageman.c b/game/src/stage/stageman.c index d6dbffc..a26b20d 100644 --- a/game/src/stage/stageman.c +++ b/game/src/stage/stageman.c @@ -11,7 +11,7 @@ stageman_init () game_stages = g_hash_table_new (g_str_hash, g_str_equal); stageman_add_stage ("main_menu", stage_main_menu_new ()); - stageman_add_stage ("game", stage_game_new ()); + stageman_add_stage ("ingame", stage_ingame_new ()); global_stage = stage_global_new (); global_stage->on_enter (global_stage); diff --git a/game/src/stage/stageman.h b/game/src/stage/stageman.h index 5906b24..8e6b8ad 100644 --- a/game/src/stage/stageman.h +++ b/game/src/stage/stageman.h @@ -6,7 +6,7 @@ #include "stage_global.h" #include "stage_main_menu.h" -#include "stage_game.h" +#include "stage_ingame.h" void stageman_init (); void stageman_guile_register ();