emscripten: use emterpreter for displaying loading screen

This commit is contained in:
Sebastian Krzyszkowiak 2019-01-03 23:22:26 +01:00
parent 7d9adc8d14
commit f357d75591
No known key found for this signature in database
GPG key ID: E8F235CF3BDBC3FF
4 changed files with 93 additions and 75 deletions

View file

@ -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")

View file

@ -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

View file

@ -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);

View file

@ -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);