From ffadc23cab725828a3a38646d3efa10bd551f7b2 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Thu, 9 Feb 2023 14:48:39 +0100 Subject: Expose elapsed time API (#670) --- FL/Fl.H | 7 +++ FL/platform_types.h | 21 +++++++++ src/Fl_Timeout.cxx | 129 +++++++++++++++++++++++++++++++++++++++------------- 3 files changed, 126 insertions(+), 31 deletions(-) diff --git a/FL/Fl.H b/FL/Fl.H index d33ff393c..925daa591 100644 --- a/FL/Fl.H +++ b/FL/Fl.H @@ -470,6 +470,13 @@ public: static void add_check(Fl_Timeout_Handler, void* = 0); static int has_check(Fl_Timeout_Handler, void* = 0); static void remove_check(Fl_Timeout_Handler, void* = 0); + + static Fl_Timestamp now(); + static double seconds_since(Fl_Timestamp& then); + static double seconds_between(Fl_Timestamp& back, Fl_Timestamp& further_back); + static long ticks_since(Fl_Timestamp& then); + static long ticks_between(Fl_Timestamp& back, Fl_Timestamp& further_back); + // private static void run_idle(); static void run_checks(); diff --git a/FL/platform_types.h b/FL/platform_types.h index b55544d4c..421a0b7c6 100644 --- a/FL/platform_types.h +++ b/FL/platform_types.h @@ -12,6 +12,9 @@ * https://www.fltk.org/bugs.php */ +#ifndef Fl_Platform_Types_H +#define Fl_Platform_Types_H + /** \file Definitions of platform-dependent types. The exact nature of these types varies with the platform. @@ -62,6 +65,13 @@ typedef opaque FL_SOCKET; /**< socket or file descriptor */ */ typedef struct opaque *GLContext; +/** + Platform-specific point in time, used for delta time calculation. + \note This type may be a struct. sizeof(Fl_Timestamp) may be different on + different platforms. Fl_Timestamp may change with future ABI changes. + */ +typedef opaque Fl_Timestamp; + # define FL_COMMAND opaque /**< An alias for FL_CTRL on Windows and X11, or FL_META on MacOS X */ # define FL_CONTROL opaque /**< An alias for FL_META on Windows and X11, or FL_CTRL on MacOS X */ @@ -127,4 +137,15 @@ extern FL_EXPORT int fl_control_modifier(); #endif /* FL_PLATFORM_TYPES_H */ +// This is currently the same for all platforms, but may change in the future +struct Fl_Timestamp_t { + long sec; + long usec; +}; + +typedef struct Fl_Timestamp_t Fl_Timestamp; + #endif /* FL_DOXYGEN */ + +#endif /* Fl_Platform_Types_H */ + diff --git a/src/Fl_Timeout.cxx b/src/Fl_Timeout.cxx index f8ae8df94..e52573ff0 100644 --- a/src/Fl_Timeout.cxx +++ b/src/Fl_Timeout.cxx @@ -2,7 +2,7 @@ // Timeout support functions for the Fast Light Tool Kit (FLTK). // // Author: Albrecht Schlosser -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2023 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -34,40 +34,108 @@ Fl_Timeout *Fl_Timeout::current_timeout = 0; static int num_timers = 0; // DEBUG #endif -// Internal timestamp, used for delta time calculation. -// Note: FLTK naming convention is not used here to avoid potential conflicts -// in the future. +/** + Set a time stamp at this point in time. + + The time stamp is an opaque type and does not represent the time of day or + some time and date in the calendar. It is used with Fl::seconds_between() and + Fl::seconds_since() to measure elapsed time. + + \code + Fl_Timestamp start = Fl::now(); + // do something + double s = Fl::seconds_since(start); + printf("That operation took %g seconds\n", s); + \endcode + + Depending on the system the resolution may be milliseconds or microseconds. + Under certain conditions (particularly on Windows) the value in member `sec` + may wrap around and does not represent a real time (maybe runtime of the system). + Function seconds_since() below uses this to subtract two timestamps which is + always a correct delta time with milliseconds or microseconds resolution. + + \todo Fl::system_driver()->gettime() was implemented for the Forms library and + has a limited resolution (on Windows: milliseconds). On POSIX platforms it uses + gettimeofday() with microsecond resolution. + A new function could use a better resolution on Windows with its multimedia + timers which requires a new dependency: winmm.lib (dll). This could be a future + improvement, maybe set as a build option or generally (requires Win95 or 98?). + + \return this moment in time as an opaque time stamp + + \see Fl::seconds_since(Fl_Timestamp& then) + Fl::seconds_between(Fl_Timestamp& back, Fl_Timestamp& further_back) + Fl::ticks_since(Fl_Timestamp& then) + Fl::ticks_between(Fl_Timestamp& back, Fl_Timestamp& further_back) + */ +Fl_Timestamp Fl::now() { + Fl_Timestamp ts; + time_t sec; + int usec; + Fl::system_driver()->gettime(&sec, &usec); + ts.sec = (long)sec; + ts.usec = usec; + return ts; // C++ will copy the result into the lvalue for us +} -struct FlTimeStamp { - long sec; - long usec; -}; +/** + Return the time in seconds between now and a previously taken time stamp. -typedef struct FlTimeStamp FlTimeStamp_t; + \param[in] then a previously taken time stamp + \return elapsed seconds and fractions of a second -// Get a timestamp of type FlTimeStamp. + \see Fl::seconds_between(Fl_Timestamp& back, Fl_Timestamp& further_back) + Fl::now() + */ +double Fl::seconds_since(Fl_Timestamp& then) { + Fl_Timestamp ts_now = Fl::now(); + return Fl::seconds_between(ts_now, then); +} -// Depending on the system the resolution may be milliseconds or microseconds. -// Under certain conditions (particularly on Windows) the value in member `sec' -// may wrap around and does not represent a real time (maybe runtime of the system). -// Function elapsed_time() below uses this to subtract two timestamps which is always -// a correct delta time with milliseconds or microseconds resolution. +/** + Return the time in seconds between two time stamps. -// To do: Fl::system_driver()->gettime() was implemented for the Forms library and -// has a limited resolution (on Windows: milliseconds). On POSIX platforms it uses -// gettimeofday() with microsecond resolution. -// A new function could use a better resolution on Windows with its multimedia -// timers which requires a new dependency: winmm.lib (dll). This could be a future -// improvement, maybe set as a build option or generally (requires Win95 or 98?). + \param[in] back a previously taken time stamp + \param[in] further_back an even earlier time stamp + \return elapsed seconds and fractions of a second -static void get_timestamp(FlTimeStamp_t *ts) { - time_t sec; - int usec; - Fl::system_driver()->gettime(&sec, &usec); - ts->sec = (long)sec; - ts->usec = usec; + \see Fl::seconds_since(Fl_Timestamp& then), Fl::now() + */ +double Fl::seconds_between(Fl_Timestamp& back, Fl_Timestamp& further_back) { + return double((back.sec - further_back.sec) + (back.usec - further_back.usec) / 1000000.); } +/** + Return the time in ticks (60Hz) between now and a previously taken time stamp. + + Ticks are a convenient way to time animations 'per frame'. Even though + modern computers use all kinds of screen refresh rates, 60Hz is a very good + base for animation that is typically shown in user interface graphics. + + \param[in] then a previously taken time stamp + \return elapsed ticks in 60th of a second + + \see Fl::ticks_between(Fl_Timestamp& back, Fl_Timestamp& further_back), Fl::now() + */ +long Fl::ticks_since(Fl_Timestamp& then) { + Fl_Timestamp ts_now = Fl::now(); + return Fl::ticks_between(ts_now, then); +} + +/** + Return the time in ticks (60Hz) between two time stamps. + + \param[in] back a previously taken time stamp + \param[in] further_back an even earlier time stamp + \return elapsed ticks in 60th of a second + + \see Fl::ticks_since(Fl_Timestamp& then), Fl::now() + */ +long Fl::ticks_between(Fl_Timestamp& back, Fl_Timestamp& further_back) { + return (back.sec-further_back.sec)*60 + (back.usec-further_back.usec)/16666; +} + + // Returns 0 and initializes the "previous" timestamp when called for the first time. /* @@ -83,14 +151,13 @@ static void get_timestamp(FlTimeStamp_t *ts) { */ static double elapsed_time() { static int first = 1; // initialization - static FlTimeStamp_t prev; // previous timestamp - FlTimeStamp_t now; // current timestamp + static Fl_Timestamp prev; // previous timestamp + Fl_Timestamp now = Fl::now(); // current timestamp double elapsed = 0.0; - get_timestamp(&now); if (first) { first = 0; } else { - elapsed = double((now.sec - prev.sec) + (now.usec - prev.usec) / 1000000.); + elapsed = Fl::seconds_between(now, prev); } prev = now; return elapsed; -- cgit v1.2.3