From f357d75591f6dc96bd36c546f5a58ccff89e3b02 Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Thu, 3 Jan 2019 23:22:26 +0100 Subject: [PATCH] emscripten: use emterpreter for displaying loading screen --- cmake/libsuperderpy.cmake | 2 +- src/internal.c | 13 ++-- src/libsuperderpy.c | 4 + src/mainloop.c | 149 ++++++++++++++++++++------------------ 4 files changed, 93 insertions(+), 75 deletions(-) diff --git a/cmake/libsuperderpy.cmake b/cmake/libsuperderpy.cmake index 0cc05c1..d23c96a 100644 --- a/cmake/libsuperderpy.cmake +++ b/cmake/libsuperderpy.cmake @@ -194,7 +194,7 @@ if (NOT LIBSUPERDERPY_CONFIG_INCLUDED) set(CMAKE_EXECUTABLE_SUFFIX ".bc") set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s SIDE_MODULE=1 -s EXPORT_ALL=1") - set(EMSCRIPTEN_FLAGS -s FULL_ES2=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s NO_EXIT_RUNTIME=0 -s PRECISE_F32=1 -s EXPORT_ALL=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=[\"Pointer_stringify\"]) + set(EMSCRIPTEN_FLAGS -s FULL_ES2=1 -s ERROR_ON_UNDEFINED_SYMBOLS=1 -s EMTERPRETIFY=1 -s EMTERPRETIFY_ASYNC=1 -s EMTERPRETIFY_WHITELIST=[\"_libsuperderpy_emscripten_mainloop\",\"_libsuperderpy_mainloop\",\"_MainloopTick\",\"_GamestateLoadingThread\"] -s PRECISE_F32=1 -s EXPORT_ALL=1 -s EXTRA_EXPORTED_RUNTIME_METHODS=[\"Pointer_stringify\"]) set(LIBSUPERDERPY_EMSCRIPTEN_MODE "asm.js" CACHE STRING "Emscripten compilation mode (JavaScript or WebAssembly)") set_property(CACHE LIBSUPERDERPY_EMSCRIPTEN_MODE PROPERTY STRINGS "asm.js;wasm") diff --git a/src/internal.c b/src/internal.c index 58526a4..06b35fc 100644 --- a/src/internal.c +++ b/src/internal.c @@ -57,7 +57,7 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { tmp = tmp->next; } - if (game->_priv.loading.in_progress) { + if (game->_priv.loading.in_progress && game->loading.shown) { // same as above, but for the loading gamestate game->_priv.current_gamestate = NULL; SetFramebufferAsTarget(game); @@ -249,11 +249,13 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) { data->gamestate->data = data->gamestate->api->load(data->game, &GamestateProgress); if (data->game->_priv.loading.progress != data->gamestate->progress_count) { PrintConsole(data->game, "[%s] WARNING: Gamestate_ProgressCount does not match the number of progress invokations (%d)!", data->gamestate->name, data->game->_priv.loading.progress); +#ifndef LIBSUPERDERPY_SINGLE_THREAD if (data->game->config.debug.enabled) { PrintConsole(data->game, "(sleeping for 3 seconds...)"); data->game->_priv.showconsole = true; al_rest(3.0); } +#endif } data->bitmap_flags = al_get_new_bitmap_flags(); data->game->_priv.loading.in_progress = false; @@ -297,11 +299,12 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game* game) { #else al_convert_memory_bitmaps(); double delta = al_get_time() - game->_priv.loading.time; - if (game->_priv.loading.current->show_loading) { - game->_priv.loading.gamestate->api->logic(game, game->_priv.loading.gamestate->data, delta); - DrawGamestates(game); - } + game->time += delta; // TODO: ability to disable passing time during loading game->_priv.loading.time += delta; + if (game->loading.shown) { + game->_priv.loading.gamestate->api->logic(game, game->_priv.loading.gamestate->data, delta); + } + DrawGamestates(game); DrawConsole(game); al_flip_display(); #endif diff --git a/src/libsuperderpy.c b/src/libsuperderpy.c index 44513ea..72654f6 100644 --- a/src/libsuperderpy.c +++ b/src/libsuperderpy.c @@ -277,11 +277,15 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* } int samplerate = strtol(GetConfigOptionDefault(game, "SuperDerpy", "samplerate", "44100"), NULL, 10); +#ifdef __EMSCRIPTEN__ + game->audio.v = al_create_voice(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); +#else game->audio.v = al_create_voice(samplerate, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2); if (!game->audio.v) { // fallback game->audio.v = al_create_voice(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); } +#endif game->audio.mixer = al_create_mixer(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); game->audio.fx = al_create_mixer(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); game->audio.music = al_create_mixer(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2); diff --git a/src/mainloop.c b/src/mainloop.c index b56ee0b..60a1077 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -183,6 +183,66 @@ static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) { } } +static inline bool MainloopEvents(struct Game* game) { + do { + ALLEGRO_EVENT ev; + + if (game->_priv.paused) { + // there's no frame flipping when paused, so avoid pointless busylooping + al_wait_for_event(game->_priv.event_queue, &ev); + } else if (!al_get_next_event(game->_priv.event_queue, &ev)) { + break; + } + +#ifdef LIBSUPERDERPY_IMGUI + ImGui_ImplAllegro5_ProcessEvent(&ev); + switch (ev.type) { + case ALLEGRO_EVENT_KEY_CHAR: + case ALLEGRO_EVENT_KEY_DOWN: + case ALLEGRO_EVENT_KEY_UP: + if (igGetIO()->WantCaptureKeyboard) { + continue; + } + break; + case ALLEGRO_EVENT_MOUSE_AXES: + case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: + case ALLEGRO_EVENT_MOUSE_BUTTON_UP: + case ALLEGRO_EVENT_TOUCH_BEGIN: + case ALLEGRO_EVENT_TOUCH_CANCEL: + case ALLEGRO_EVENT_TOUCH_END: + case ALLEGRO_EVENT_TOUCH_MOVE: + if (igGetIO()->WantCaptureMouse) { + continue; + } + break; + default: + break; + } +#endif + + if (game->_priv.params.handlers.event) { + if ((*game->_priv.params.handlers.event)(game, &ev)) { + continue; + } + } + + if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { + EventGamestates(game, &ev); + return false; + } + + HandleEvent(game, &ev); + + if (game->config.debug.enabled) { + HandleDebugEvent(game, &ev); + } + + EventGamestates(game, &ev); + + } while (!al_is_event_queue_empty(game->_priv.event_queue)); + return true; +} + static inline bool MainloopTick(struct Game* game) { if (game->_priv.paused) { return true; @@ -248,27 +308,31 @@ static inline bool MainloopTick(struct Game* game) { game->_priv.loading.time = time; CalculateProgress(game); + if (tmp->show_loading) { + game->loading.shown = true; + DrawGamestates(game); + DrawConsole(game); + al_flip_display(); + } #ifndef LIBSUPERDERPY_SINGLE_THREAD al_run_detached_thread(GamestateLoadingThread, &data); while (game->_priv.loading.in_progress) { double delta = al_get_time() - game->_priv.loading.time; - if (tmp->show_loading) { - game->loading.shown = true; - (*game->_priv.loading.gamestate->api->logic)(game, game->_priv.loading.gamestate->data, delta); - DrawGamestates(game); - } - game->_priv.loading.time += delta; game->time += delta; // TODO: ability to disable passing time during loading + game->_priv.loading.time += delta; + if (game->loading.shown) { + (*game->_priv.loading.gamestate->api->logic)(game, game->_priv.loading.gamestate->data, delta); + } + DrawGamestates(game); if (game->_priv.texture_sync) { al_convert_memory_bitmaps(); game->_priv.texture_sync = false; al_signal_cond(game->_priv.texture_sync_cond); - game->_priv.loading.time = al_get_time(); + game->_priv.loading.time = al_get_time(); // TODO: rethink time management during loading } DrawConsole(game); al_flip_display(); -#ifndef LIBSUPERDERPY_SINGLE_THREAD if (game->_priv.bsod_sync) { al_set_target_bitmap(NULL); game->_priv.bsod_sync = false; @@ -280,10 +344,12 @@ static inline bool MainloopTick(struct Game* game) { al_wait_cond(game->_priv.bsod_cond, game->_priv.bsod_mutex); } al_unlock_mutex(game->_priv.bsod_mutex); -#endif } #else GamestateLoadingThread(&data); +#ifdef __EMSCRIPTEN__ + emscripten_sleep(0); +#endif al_convert_memory_bitmaps(); #endif @@ -316,6 +382,10 @@ static inline bool MainloopTick(struct Game* game) { if (game->_priv.loading.loaded) { ReloadShaders(game, false); + MainloopEvents(game); // consume queued events +#ifdef __EMSCRIPTEN__ + emscripten_sleep(0); +#endif } bool gameActive = false; @@ -328,6 +398,7 @@ static inline bool MainloopTick(struct Game* game) { game->_priv.current_gamestate = tmp; tmp->started = true; tmp->pending_start = false; + (*tmp->api->start)(game, tmp->data); al_resume_timer(game->_priv.timer); game->_priv.timestamp = al_get_time(); @@ -371,66 +442,6 @@ static inline bool MainloopTick(struct Game* game) { return true; } -static inline bool MainloopEvents(struct Game* game) { - do { - ALLEGRO_EVENT ev; - - if (game->_priv.paused) { - // there's no frame flipping when paused, so avoid pointless busylooping - al_wait_for_event(game->_priv.event_queue, &ev); - } else if (!al_get_next_event(game->_priv.event_queue, &ev)) { - break; - } - -#ifdef LIBSUPERDERPY_IMGUI - ImGui_ImplAllegro5_ProcessEvent(&ev); - switch (ev.type) { - case ALLEGRO_EVENT_KEY_CHAR: - case ALLEGRO_EVENT_KEY_DOWN: - case ALLEGRO_EVENT_KEY_UP: - if (igGetIO()->WantCaptureKeyboard) { - continue; - } - break; - case ALLEGRO_EVENT_MOUSE_AXES: - case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN: - case ALLEGRO_EVENT_MOUSE_BUTTON_UP: - case ALLEGRO_EVENT_TOUCH_BEGIN: - case ALLEGRO_EVENT_TOUCH_CANCEL: - case ALLEGRO_EVENT_TOUCH_END: - case ALLEGRO_EVENT_TOUCH_MOVE: - if (igGetIO()->WantCaptureMouse) { - continue; - } - break; - default: - break; - } -#endif - - if (game->_priv.params.handlers.event) { - if ((*game->_priv.params.handlers.event)(game, &ev)) { - continue; - } - } - - if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) { - EventGamestates(game, &ev); - return false; - } - - HandleEvent(game, &ev); - - if (game->config.debug.enabled) { - HandleDebugEvent(game, &ev); - } - - EventGamestates(game, &ev); - - } while (!al_is_event_queue_empty(game->_priv.event_queue)); - return true; -} - SYMBOL_EXPORT bool libsuperderpy_mainloop(struct Game* game) { ClearGarbage(game); return MainloopEvents(game) && MainloopTick(game);