timer: Added fps capping and fps calculation.
authorLukas Krickl <lukas@krickl.dev>
Thu, 26 Feb 2026 10:50:55 +0000 (11:50 +0100)
committerLukas Krickl <lukas@krickl.dev>
Thu, 26 Feb 2026 10:50:55 +0000 (11:50 +0100)
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.

src/lrts.c
src/lrts_impl.h
src/p_platform.h
src/p_r_sdl/p_draw.c
src/r_render.c
src/t_map.c
src/u_defs.h
src/u_time.c [new file with mode: 0644]
src/u_time.h [new file with mode: 0644]

index d5de30f5b10553cb60a299d73cce0965dead2966..110ed9dc85abcfa63fe89edfb08fee7b97349b78 100644 (file)
@@ -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);
index 0e7f21981ae9a2fea4b53efb74c520469d3365ee..49f7fd08e4f8f78b20b38db4f7d3a77a40a7cdab 100644 (file)
@@ -49,6 +49,7 @@
 #include "r_color.c"
 #include "r_assets.c"
 #include "i_input.c"
+#include "u_time.c"
 
 #endif
 
index 5de02c7d81a80ea3683dec89defe4813d043f819..fa02758e55f64c1692eb069e037334ad7a3c4ad1 100644 (file)
@@ -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
index cf5416e22dbf4c57fd1d25d63afe04ede7f7c6b1..fdb0c0320d00b399d7423c3b527d2b72e8a7defc 100644 (file)
@@ -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);
 }
+
index 48dfa6ab530747859c3e567201ebd2c0d176da4a..837ff103a3f7c92e263b2c1e8d1fa170559b6650 100644 (file)
@@ -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();
 }
index 26e53c536a04aa492602c4d41d029606a78b2549..46cf2988611a7599dedc2a60634dff15f059a6d0 100644 (file)
@@ -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);
                }
        }
index 5207fb40ca386a17d9f558b6b761235b60d240e3..f9dde6bb5b19abbab95be3eb51df31c810dd05f8 100644 (file)
@@ -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 (file)
index 0000000..544bdac
--- /dev/null
@@ -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 (file)
index 0000000..ecfbdbf
--- /dev/null
@@ -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