1#if !defined(BACKEND_WIN)
2#define _POSIX_C_SOURCE 199309L
3#else
4#include <windows.h>
5#endif
6
7#include <stdarg.h>
8#include <stdio.h>
9#include <stdlib.h>
10#include <time.h>
11
12#include "maus.h"
13
14static void vlog(FILE* fd, const char* fmt, va_list ap);
15
16static void vlog(FILE* fd, const char* fmt, va_list ap)
17{
18 fprintf(fd, "maus: ");
19 vfprintf(fd, fmt, ap);
20}
21
22void maus_die(const char* fmt, ...)
23{
24 va_list ap;
25 va_start(ap, fmt);
26 vlog(stderr, fmt, ap);
27 va_end(ap);
28
29 exit(EXIT_FAILURE);
30}
31
32uint64_t maus_get_time_ns(void)
33{
34#if !defined(_WIN32)
35 struct timespec ts;
36 clock_gettime(CLOCK_MONOTONIC, &ts);
37 return ts.tv_sec * 1000000000ULL + ts.tv_nsec;
38#else
39 static LARGE_INTEGER frequency = {0};
40 if (frequency.QuadPart == 0)
41 QueryPerformanceFrequency(&frequency);
42
43 LARGE_INTEGER counter;
44 QueryPerformanceCounter(&counter);
45
46 uint64_t sec = counter.QuadPart / frequency.QuadPart;
47 uint64_t rem = counter.QuadPart % frequency.QuadPart;
48
49 return (sec * 1000000000ULL) + ((rem * 1000000000ULL) / frequency.QuadPart);
50#endif
51}
52
53void maus_log(FILE* fd, const char* fmt, ...)
54{
55 va_list ap;
56 va_start(ap, fmt);
57 vlog(fd, fmt, ap);
58 fputc('\n', fd);
59 va_end(ap);
60}
61
62void maus_target_fps(Maus* mw, uint32_t fps)
63{
64 if (fps == 0)
65 return;
66
67 uint64_t ns_frame = 1000000000ULL / fps; /* max ns a frame can take */
68 uint64_t cur_time = maus_get_time_ns();
69 uint64_t elapsed = cur_time - mw->frame_time_last;
70
71 /* if early finish, sleep for the remaining time balance */
72 if (elapsed < ns_frame) {
73 uint64_t sleep = ns_frame - elapsed;
74 #if !defined(_WIN32)
75 struct timespec ts;
76 ts.tv_sec = sleep / 1000000000ULL;
77 ts.tv_nsec = sleep % 1000000000ULL;
78 nanosleep(&ts, NULL);
79 #else /* unix */
80 Sleep((DWORD)((sleep + 999999ULL) / 1000000ULL));
81 #endif /* platform */
82 }
83
84 mw->frame_time_last = maus_get_time_ns();
85}
86