diff --git a/thirdparty/sokol_time.h b/thirdparty/sokol_time.h new file mode 100644 index 0000000..cacfb13 --- /dev/null +++ b/thirdparty/sokol_time.h @@ -0,0 +1,228 @@ +#pragma once +/* + sokol_time.h -- simple cross-platform time measurement + + Do this: + #define SOKOL_IMPL + before you include this file in *one* C or C++ file to create the + implementation. + + Optionally provide the following defines with your own implementations: + SOKOL_ASSERT(c) - your own assert macro (default: assert(c)) + SOKOL_API_DECL - public function declaration prefix (default: extern) + SOKOL_API_IMPL - public function implementation prefix (default: -) + + void stm_setup(); + Call once before any other functions to initialize sokol_time + (this calls for instance QueryPerformanceFrequency on Windows) + + uint64_t stm_now(); + Get current point in time in unspecified 'ticks'. The value that + is returned has no relation to the 'wall-clock' time and is + not in a specific time unit, it is only useful to compute + time differences. + + uint64_t stm_diff(uint64_t new, uint64_t old); + Computes the time difference between new and old. This will always + return a positive, non-zero value. + + uint64_t stm_since(uint64_t start); + Takes the current time, and returns the elapsed time since start + (this is a shortcut for "stm_diff(stm_now(), start)") + + uint64_t stm_laptime(uint64_t* last_time); + This is useful for measuring frame time and other recurring + events. It takes the current time, returns the time difference + to the value in last_time, and stores the current time in + last_time for the next call. If the value in last_time is 0, + the return value will be zero (this usually happens on the + very first call). + + Use the following functions to convert a duration in ticks into + useful time units: + + double stm_sec(uint64_t ticks); + double stm_ms(uint64_t ticks); + double stm_us(uint64_t ticks); + double stm_ns(uint64_t ticks); + Converts a tick value into seconds, milliseconds, microseconds + or nanoseconds. Note that not all platforms will have nanosecond + or even microsecond precision. + + Uses the following time measurement functions under the hood: + + Windows: QueryPerformanceFrequency() / QueryPerformanceCounter() + MacOS/iOS: mach_absolute_time() + emscripten: clock_gettime(CLOCK_MONOTONIC) + Linux+others: clock_gettime(CLOCK_MONITONIC) + + zlib/libpng license + + Copyright (c) 2018 Andre Weissflog + + This software is provided 'as-is', without any express or implied warranty. + In no event will the authors be held liable for any damages arising from the + use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software in a + product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. +*/ +#include + +#ifndef SOKOL_API_DECL + #define SOKOL_API_DECL extern +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +SOKOL_API_DECL void stm_setup(void); +SOKOL_API_DECL uint64_t stm_now(void); +SOKOL_API_DECL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks); +SOKOL_API_DECL uint64_t stm_since(uint64_t start_ticks); +SOKOL_API_DECL uint64_t stm_laptime(uint64_t* last_time); +SOKOL_API_DECL double stm_sec(uint64_t ticks); +SOKOL_API_DECL double stm_ms(uint64_t ticks); +SOKOL_API_DECL double stm_us(uint64_t ticks); +SOKOL_API_DECL double stm_ns(uint64_t ticks); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/*-- IMPLEMENTATION ----------------------------------------------------------*/ +#ifdef SOKOL_IMPL + +#ifndef SOKOL_API_IMPL + #define SOKOL_API_IMPL +#endif +#ifndef SOKOL_ASSERT + #include + #define SOKOL_ASSERT(c) assert(c) +#endif +#ifndef _SOKOL_PRIVATE + #if defined(__GNUC__) + #define _SOKOL_PRIVATE __attribute__((unused)) static + #else + #define _SOKOL_PRIVATE static + #endif +#endif + +static int _stm_initialized; +#if defined(_WIN32) +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +static LARGE_INTEGER _stm_win_freq; +static LARGE_INTEGER _stm_win_start; +#elif defined(__APPLE__) && defined(__MACH__) +#include +static mach_timebase_info_data_t _stm_osx_timebase; +static uint64_t _stm_osx_start; +#else /* anything else, this will need more care for non-Linux platforms */ +#include +static uint64_t _stm_posix_start; +#endif + +/* prevent 64-bit overflow when computing relative timestamp + see https://gist.github.com/jspohr/3dc4f00033d79ec5bdaf67bc46c813e3 +*/ +#if defined(_WIN32) || (defined(__APPLE__) && defined(__MACH__)) +_SOKOL_PRIVATE int64_t int64_muldiv(int64_t value, int64_t numer, int64_t denom) { + int64_t q = value / denom; + int64_t r = value % denom; + return q * numer + r * numer / denom; +} +#endif + + +SOKOL_API_IMPL void stm_setup(void) { + SOKOL_ASSERT(0 == _stm_initialized); + _stm_initialized = 1; + #if defined(_WIN32) + QueryPerformanceFrequency(&_stm_win_freq); + QueryPerformanceCounter(&_stm_win_start); + #elif defined(__APPLE__) && defined(__MACH__) + mach_timebase_info(&_stm_osx_timebase); + _stm_osx_start = mach_absolute_time(); + #else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + _stm_posix_start = (uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec; + #endif +} + +SOKOL_API_IMPL uint64_t stm_now(void) { + SOKOL_ASSERT(_stm_initialized); + uint64_t now; + #if defined(_WIN32) + LARGE_INTEGER qpc_t; + QueryPerformanceCounter(&qpc_t); + now = int64_muldiv(qpc_t.QuadPart - _stm_win_start.QuadPart, 1000000000, _stm_win_freq.QuadPart); + #elif defined(__APPLE__) && defined(__MACH__) + const uint64_t mach_now = mach_absolute_time() - _stm_osx_start; + now = int64_muldiv(mach_now, _stm_osx_timebase.numer, _stm_osx_timebase.denom); + #else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + now = ((uint64_t)ts.tv_sec*1000000000 + (uint64_t)ts.tv_nsec) - _stm_posix_start; + #endif + return now; +} + +SOKOL_API_IMPL uint64_t stm_diff(uint64_t new_ticks, uint64_t old_ticks) { + if (new_ticks > old_ticks) { + return new_ticks - old_ticks; + } + else { + /* FIXME: this should be a value that converts to a non-null double */ + return 1; + } +} + +SOKOL_API_IMPL uint64_t stm_since(uint64_t start_ticks) { + return stm_diff(stm_now(), start_ticks); +} + +SOKOL_API_IMPL uint64_t stm_laptime(uint64_t* last_time) { + SOKOL_ASSERT(last_time); + uint64_t dt = 0; + uint64_t now = stm_now(); + if (0 != *last_time) { + dt = stm_diff(now, *last_time); + } + *last_time = now; + return dt; +} + +SOKOL_API_IMPL double stm_sec(uint64_t ticks) { + return (double)ticks / 1000000000.0; +} + +SOKOL_API_IMPL double stm_ms(uint64_t ticks) { + return (double)ticks / 1000000.0; +} + +SOKOL_API_IMPL double stm_us(uint64_t ticks) { + return (double)ticks / 1000.0; +} + +SOKOL_API_IMPL double stm_ns(uint64_t ticks) { + return (double)ticks; +} +#endif /* SOKOL_IMPL */ + diff --git a/tool b/tool index 118da96..a23dc8b 100755 --- a/tool +++ b/tool @@ -231,14 +231,22 @@ build_target() { # if we ever need newer posix stuff # add cc_flags -D_POSIX_C_SOURCE=200809L out_exe=orca - if [[ $os = mac ]]; then - # prefer homebrew version of ncurses if installed. Will give us better - # terminfo, so we can use A_DIM in Terminal.app, etc. - if [[ -d /usr/local/opt/ncurses ]]; then - add libraries -L/usr/local/opt/ncurses/lib - add cc_flags -I/usr/local/opt/ncurses/include - fi - fi + case $os in + mac) + # prefer homebrew version of ncurses if installed. Will give us + # better terminfo, so we can use A_DIM in Terminal.app, etc. + if [[ -d /usr/local/opt/ncurses ]]; then + add libraries -L/usr/local/opt/ncurses/lib + add cc_flags -I/usr/local/opt/ncurses/include + fi + # todo mach time stuff for mac + ;; + *) + # librt and high-res posix timers on Linux + add libraries -lrt + add cc_flags -D_POSIX_C_SOURCE=200809L + ;; + esac add libraries -lncurses # If we wanted wide chars, use -lncursesw on Linux, and still just # -lncurses on Mac. diff --git a/tui_main.c b/tui_main.c index b7ef007..fd8b717 100644 --- a/tui_main.c +++ b/tui_main.c @@ -8,6 +8,10 @@ #include #include +#define SOKOL_IMPL +#include "thirdparty/sokol_time.h" +#undef SOKOL_IMPL + #define AND_CTRL(c) ((c)&037) static void usage() { @@ -497,6 +501,9 @@ int main(int argc, char** argv) { return 1; } + // Set up timer lib + stm_setup(); + Field field; if (input_file) { field_init(&field); @@ -601,6 +608,7 @@ int main(int argc, char** argv) { bool is_playing = false; bool needs_remarking = true; bool draw_event_list = false; + double bpm = 120.0; for (;;) { int term_height = getmaxy(stdscr); int term_width = getmaxx(stdscr);