From: Lukas Krickl Date: Thu, 26 Feb 2026 10:50:55 +0000 (+0100) Subject: timer: Added fps capping and fps calculation. X-Git-Url: https://git.krickl.dev/?a=commitdiff_plain;h=2d730100029ecefa57bf9f14b5352b52b501f57c;p=lrts%2F.git timer: Added fps capping and fps calculation. Added a few platform functions that give hints about the current tickrate of the rendering backend. Added timer struct. Added tickrate constant for simulation updates. --- diff --git a/src/lrts.c b/src/lrts.c index d5de30f..110ed9d 100644 --- a/src/lrts.c +++ b/src/lrts.c @@ -6,6 +6,7 @@ #include "i_input.h" #include "t_camera.h" #include "t_map.h" +#include "u_time.h" struct lrts_config lrts_global_cfg; @@ -65,12 +66,17 @@ struct u_vec2 lrts_get_screen_res(void) { } void lrts_init(void) { + struct lrts_config* cfg = lrts_cfg(); struct u_vec2 res = lrts_get_render_res(); + + cfg->target_fps = LRTS_DEFAULT_TARGET_FPS; + /* init the fallback tile mask */ r_asset_init_fallback_tile(); i_input_init(); - + + u_fps_timer = u_timer_init(); t_main_camera = t_camera_init(res.x, res.y); diff --git a/src/lrts_impl.h b/src/lrts_impl.h index 0e7f219..49f7fd0 100644 --- a/src/lrts_impl.h +++ b/src/lrts_impl.h @@ -49,6 +49,7 @@ #include "r_color.c" #include "r_assets.c" #include "i_input.c" +#include "u_time.c" #endif diff --git a/src/p_platform.h b/src/p_platform.h index 5de02c7..fa02758 100644 --- a/src/p_platform.h +++ b/src/p_platform.h @@ -32,6 +32,32 @@ int p_render_init_framebuffer(void); */ int p_renderer_finish(void); +/* + * Caps the fps at configured target fps. + * This should generally be based on the time it took between + * begin and end of drawing. + * returns current fps. + */ +u32 p_cap_fps(void); + +/* returns an integer representation of + * the current tick rate + * the number itself is abstract and simply represents + * a unit of time + */ +u64 p_get_ticks(void); + +/* returns the ticks contained in a single + * second */ +u64 p_ticks_per_second(void); + +/* delays execution + * the delay time is relative to + * the unit ticks are in + */ +void p_delay(u64 time); + + /** * polls input events * should be called once a frame diff --git a/src/p_r_sdl/p_draw.c b/src/p_r_sdl/p_draw.c index cf5416e..fdb0c03 100644 --- a/src/p_r_sdl/p_draw.c +++ b/src/p_r_sdl/p_draw.c @@ -2,6 +2,19 @@ #include "p_window.h" #include "../u_assert.h" + +u64 p_get_ticks(void) { + return SDL_GetTicksNS(); +} + +void p_delay(u64 time) { + SDL_DelayNS(time); +} + +u64 p_ticks_per_second(void) { + return 1000000000; +} + void p_draw_begin(void) { SDL_LockSurface(r_target); } @@ -22,3 +35,4 @@ void p_draw_present(void) { SDL_BlitSurfaceScaled(r_target, NULL, screen, &dst, SDL_SCALEMODE_PIXELART); SDL_UpdateWindowSurface(p_main_window); } + diff --git a/src/r_render.c b/src/r_render.c index 48dfa6a..837ff10 100644 --- a/src/r_render.c +++ b/src/r_render.c @@ -26,6 +26,7 @@ void r_draw_pixel(struct r_framebuffer *fb, i32 x, i32 y, r_color color) { } void r_render_frame() { + u_timer_start(&u_fps_timer); p_draw_begin(); @@ -33,4 +34,7 @@ void r_render_frame() { p_draw_end(); p_draw_present(); + u_timer_end(&u_fps_timer); + + u_cap_fps(); } diff --git a/src/t_map.c b/src/t_map.c index 26e53c5..46cf298 100644 --- a/src/t_map.c +++ b/src/t_map.c @@ -22,11 +22,21 @@ struct t_map t_map_init(void) { } void t_map_draw(struct t_map *m) { - u32 i, j; + i32 i, j; + struct u_vec2 start; + struct u_vec2 end; + + start.x = 0; + start.y = 0; + + end.x = m->width; + end.y = m->height; - /* TODO: only draw visible tiles */ - for (i = 0; i < m->width; i++) { - for (j = 0; j < m->height; j++) { + /* find start tile that is inside of camera viewport */ + + + for (i = start.x; i < end.x; i++) { + for (j = start.y; j < end.y; j++) { r_draw_tile(&m->tiles[j * m->width + i], i, j); } } diff --git a/src/u_defs.h b/src/u_defs.h index 5207fb4..f9dde6b 100644 --- a/src/u_defs.h +++ b/src/u_defs.h @@ -26,6 +26,8 @@ typedef unsigned short u16; typedef short i16; typedef unsigned int u32; typedef int i32; +typedef long int i64; +typedef unsigned long int u64; typedef unsigned char lrts_bool; #define LRTS_TRUE 1 @@ -33,6 +35,10 @@ typedef unsigned char lrts_bool; #include "u_math.h" +/* in-game tick rate */ +#define LRTS_TPS 20 +#define LRTS_DEFAULT_TARGET_FPS 60 + struct lrts_config { lrts_bool verbose; @@ -42,6 +48,9 @@ struct lrts_config { struct u_vec2 render_res; struct u_vec2 screen_res; + + /* visual fps target */ + int target_fps; char **argv; int argc; diff --git a/src/u_time.c b/src/u_time.c new file mode 100644 index 0000000..544bdac --- /dev/null +++ b/src/u_time.c @@ -0,0 +1,54 @@ +#include "u_time.h" + +u32 u_cap_fps(void) { + u32 fps = 0; + u32 target_fps; + u32 delta; + u32 total_frame_time; + + u64 per_frame, delay; + const u64 in_sec = p_ticks_per_second(); + struct lrts_config* cfg = lrts_cfg(); + + target_fps = cfg->target_fps; + per_frame = in_sec / target_fps; + + delta = u_timer_delta(&u_fps_timer); + delay = per_frame - delta; + + + /* 0 target fps means we do not delay */ + if (target_fps > 0 && delta < per_frame) { + p_delay(delay); + } + + delta = u_timer_end(&u_fps_timer); + total_frame_time = delta; + + /* TODO: take average from pervious few frames for fps */ + fps = in_sec / total_frame_time; + return (u32)fps; +} + +struct u_timer u_timer_init(void) { + struct u_timer t; + t.start = 0; + t.end = 0; + return t; +} + +void u_timer_start(struct u_timer *t) { + t->start = p_get_ticks(); + t->end = 0; +} + +u64 u_timer_end(struct u_timer *t) { + t->end = p_get_ticks(); + return u_timer_delta(t); +} + +u64 u_timer_delta(struct u_timer *t) { + return t->end - t->start; +} + +struct u_timer u_fps_timer; diff --git a/src/u_time.h b/src/u_time.h new file mode 100644 index 0000000..ecfbdbf --- /dev/null +++ b/src/u_time.h @@ -0,0 +1,19 @@ +#ifndef U_TIME_H__ +#define U_TIME_H__ + +struct u_timer { + u64 start; + u64 end; +}; + +struct u_timer u_timer_init(void); + +void u_timer_start(struct u_timer *t); +u64 u_timer_end(struct u_timer *t); +u64 u_timer_delta(struct u_timer *t); + +extern struct u_timer u_fps_timer; + +u32 u_cap_fps(void); + +#endif