emscripten: Make timers work (if used with emscripten_set_main_loop)

Co-authored-by: aidanhs <aidanhs@cantab.net>
This commit is contained in:
Charlie Birks 2021-11-07 20:40:54 +00:00 committed by GitHub
parent fe2fe29049
commit d950b9e2d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 112 additions and 0 deletions

View File

@ -28,6 +28,8 @@
/* #define DEBUG_TIMERS */
#if !defined(__EMSCRIPTEN__) || !SDL_THREADS_DISABLED
typedef struct _SDL_Timer
{
int timerID;
@ -370,6 +372,116 @@ SDL_RemoveTimer(SDL_TimerID id)
return canceled;
}
#else
#include <emscripten/emscripten.h>
typedef struct _SDL_TimerMap
{
int timerID;
int timeoutID;
struct _SDL_TimerMap *next;
} SDL_TimerMap;
typedef struct {
int nextID;
SDL_TimerMap *timermap;
} SDL_TimerData;
static SDL_TimerData SDL_timer_data;
static void
SDL_Emscripten_TimerHelper(SDL_TimerMap *entry, Uint32 interval, SDL_TimerCallback callback, void *param)
{
Uint32 new_timeout;
new_timeout = callback(interval, param);
if (new_timeout != 0) {
entry->timeoutID = EM_ASM_INT({
return Browser.safeSetTimeout(function() {
dynCall('viiii', $0, [$1, $2, $3, $4]);
}, $2);
}, &SDL_Emscripten_TimerHelper, entry, interval, callback, param);
}
}
int
SDL_TimerInit(void)
{
return 0;
}
void
SDL_TimerQuit(void)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *entry;
while (data->timermap) {
entry = data->timermap;
data->timermap = entry->next;
SDL_free(entry);
}
}
SDL_TimerID
SDL_AddTimer(Uint32 interval, SDL_TimerCallback callback, void *param)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *entry;
entry = (SDL_TimerMap *)SDL_malloc(sizeof(*entry));
if (!entry) {
SDL_OutOfMemory();
return 0;
}
entry->timerID = ++data->nextID;
entry->timeoutID = EM_ASM_INT({
return Browser.safeSetTimeout(function() {
dynCall('viiii', $0, [$1, $2, $3, $4]);
}, $2);
}, &SDL_Emscripten_TimerHelper, entry, interval, callback, param);
entry->next = data->timermap;
data->timermap = entry;
return entry->timerID;
}
SDL_bool
SDL_RemoveTimer(SDL_TimerID id)
{
SDL_TimerData *data = &SDL_timer_data;
SDL_TimerMap *prev, *entry;
/* Find the timer */
prev = NULL;
for (entry = data->timermap; entry; prev = entry, entry = entry->next) {
if (entry->timerID == id) {
if (prev) {
prev->next = entry->next;
} else {
data->timermap = entry->next;
}
break;
}
}
if (entry) {
EM_ASM_({
window.clearTimeout($0);
}, entry->timeoutID);
SDL_free(entry);
return SDL_TRUE;
}
return SDL_FALSE;
}
#endif
/* This is a legacy support function; SDL_GetTicks() returns a Uint32,
which wraps back to zero every ~49 days. The newer SDL_GetTicks64()
doesn't have this problem, so we just wrap that function and clamp to