make the timer have nanoseconds precision

Fri, 29 Mar 2024 00:03:25 +0100

author
Mike Becker <universe@uap-core.de>
date
Fri, 29 Mar 2024 00:03:25 +0100
changeset 46
d3285aed65b3
parent 45
18de2af03531
child 47
44457f6cb0a2

make the timer have nanoseconds precision

src/ascension/context.h file | annotate | diff | comparison | revisions
src/ascension/datatypes.h file | annotate | diff | comparison | revisions
src/context.c file | annotate | diff | comparison | revisions
test/snake.c file | annotate | diff | comparison | revisions
--- a/src/ascension/context.h	Thu Mar 28 23:30:21 2024 +0100
+++ b/src/ascension/context.h	Fri Mar 29 00:03:25 2024 +0100
@@ -55,8 +55,8 @@
     unsigned int fonts_loaded;
     AscFont const *active_font;
     asc_col4i ink;
-    unsigned int elapsed_millis;
-    float elapsed;
+    uint64_t frame_nanos;
+    uint64_t total_nanos;
 } AscContext;
 
 /** Global ascension context. */
--- a/src/ascension/datatypes.h	Thu Mar 28 23:30:21 2024 +0100
+++ b/src/ascension/datatypes.h	Fri Mar 29 00:03:25 2024 +0100
@@ -37,6 +37,14 @@
 #include <SDL2/SDL_pixels.h>
 
 // --------------------------------------------------------------------------
+//    Useful Macros
+// --------------------------------------------------------------------------
+
+#define ASC_NANOS_SECOND 1000000000ull
+#define ASC_NANOS_MILLISECOND 1000000ull
+#define ASC_NANOS_MICROSECOND 1000000ull
+
+// --------------------------------------------------------------------------
 //    Datatype Definitions
 // --------------------------------------------------------------------------
 
--- a/src/context.c	Thu Mar 28 23:30:21 2024 +0100
+++ b/src/context.c	Fri Mar 29 00:03:25 2024 +0100
@@ -33,8 +33,16 @@
 #include <SDL2/SDL.h>
 #include <SDL2/SDL_ttf.h>
 
+#include <time.h>
+
 AscContext asc_context;
 
+static uint64_t asc_nanos(void) {
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return 1000000000ull*(uint64_t)ts.tv_sec + (uint64_t)ts.tv_nsec;
+}
+
 void asc_context_initialize(void) {
     if (asc_test_flag(asc_context.flags, ASC_FLAG_INITILIZED))
         return;
@@ -58,6 +66,7 @@
         }
     }
     SDL_ClearError();
+    asc_context.total_nanos = asc_nanos();
     asc_set_flag(&asc_context.flags, ASC_FLAG_INITILIZED);
     asc_dprintf("Ascension context initialized.");
 }
@@ -128,11 +137,13 @@
     }
 
     // compute frame time
-    static Uint32 ticks;
-    Uint32 ticks_elapsed = SDL_GetTicks() - ticks;
-    ticks = SDL_GetTicks();
-    asc_context.elapsed_millis = ticks_elapsed;
-    asc_context.elapsed = (float) ticks_elapsed / 1000.0f;
+    uint64_t frame_nanos, ns;
+    do {
+        ns = asc_nanos();
+        frame_nanos = ns - asc_context.total_nanos;
+    } while (frame_nanos == 0);
+    asc_context.frame_nanos = frame_nanos;
+    asc_context.total_nanos = ns;
 
     return !asc_test_flag(asc_context.flags, ASC_FLAG_QUIT);
 }
--- a/test/snake.c	Thu Mar 28 23:30:21 2024 +0100
+++ b/test/snake.c	Fri Mar 29 00:03:25 2024 +0100
@@ -29,18 +29,17 @@
 #include <cx/printf.h>
 
 static void update_fps_counter(AscSceneNode *node) {
-    // addition and multiplication is more efficient testing for zero
-    // at an unnoticeable cost of imprecision
-    static unsigned last_fps = 0u;
-    static unsigned debounce = 999u;
-    unsigned fps = 1000u;
-    debounce += asc_context.elapsed_millis;
-    if (debounce >= 1000u) {
+    static uint64_t last_fps = 0;
+    static uint64_t debounce = ASC_NANOS_SECOND - 1;
+    debounce += asc_context.frame_nanos;
+    // only update text every seconds
+    if (debounce >= ASC_NANOS_SECOND) {
         debounce = 0;
-        fps /= asc_context.elapsed_millis;
+        uint64_t fps = ASC_NANOS_SECOND;
+        fps /= asc_context.frame_nanos;
         if (fps != last_fps) {
             last_fps = fps;
-            snprintf(asc_text_data(node)->text, 9, "%u FPS", fps);
+            snprintf(asc_text_data(node)->text, 11, "%"PRIu64" FPS", fps);
             asc_node_update(node);
         }
     }
@@ -49,7 +48,7 @@
 static void create_fps_counter(void) {
     asc_set_font(asc_font(ASC_FONT_REGULAR, 24));
     asc_ink_rgb(255, 0, 0);
-    AscSceneNode* node = asc_text(10, 10, "XXXXX FPS");
+    AscSceneNode* node = asc_text(10, 10, "XXXXXXX FPS");
     asc_scene_add_behavior(node, update_fps_counter);
     asc_scene_add(&asc_window_active->ui, node);
 }

mercurial