mirror of
https://gitlab.com/dosowisko.net/libsuperderpy.git
synced 2025-02-08 06:06:43 +01:00
emscripten: use emterpreter for displaying loading screen
This commit is contained in:
parent
7d9adc8d14
commit
f357d75591
4 changed files with 93 additions and 75 deletions
|
@ -194,7 +194,7 @@ if (NOT LIBSUPERDERPY_CONFIG_INCLUDED)
|
||||||
set(CMAKE_EXECUTABLE_SUFFIX ".bc")
|
set(CMAKE_EXECUTABLE_SUFFIX ".bc")
|
||||||
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
set(CMAKE_SHARED_LIBRARY_SUFFIX ".so")
|
||||||
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -s SIDE_MODULE=1 -s EXPORT_ALL=1")
|
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(LIBSUPERDERPY_EMSCRIPTEN_MODE "asm.js" CACHE STRING "Emscripten compilation mode (JavaScript or WebAssembly)")
|
||||||
set_property(CACHE LIBSUPERDERPY_EMSCRIPTEN_MODE PROPERTY STRINGS "asm.js;wasm")
|
set_property(CACHE LIBSUPERDERPY_EMSCRIPTEN_MODE PROPERTY STRINGS "asm.js;wasm")
|
||||||
|
|
|
@ -57,7 +57,7 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
|
||||||
tmp = tmp->next;
|
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
|
// same as above, but for the loading gamestate
|
||||||
game->_priv.current_gamestate = NULL;
|
game->_priv.current_gamestate = NULL;
|
||||||
SetFramebufferAsTarget(game);
|
SetFramebufferAsTarget(game);
|
||||||
|
@ -249,11 +249,13 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) {
|
||||||
data->gamestate->data = data->gamestate->api->load(data->game, &GamestateProgress);
|
data->gamestate->data = data->gamestate->api->load(data->game, &GamestateProgress);
|
||||||
if (data->game->_priv.loading.progress != data->gamestate->progress_count) {
|
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);
|
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) {
|
if (data->game->config.debug.enabled) {
|
||||||
PrintConsole(data->game, "(sleeping for 3 seconds...)");
|
PrintConsole(data->game, "(sleeping for 3 seconds...)");
|
||||||
data->game->_priv.showconsole = true;
|
data->game->_priv.showconsole = true;
|
||||||
al_rest(3.0);
|
al_rest(3.0);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
data->bitmap_flags = al_get_new_bitmap_flags();
|
data->bitmap_flags = al_get_new_bitmap_flags();
|
||||||
data->game->_priv.loading.in_progress = false;
|
data->game->_priv.loading.in_progress = false;
|
||||||
|
@ -297,11 +299,12 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game* game) {
|
||||||
#else
|
#else
|
||||||
al_convert_memory_bitmaps();
|
al_convert_memory_bitmaps();
|
||||||
double delta = al_get_time() - game->_priv.loading.time;
|
double delta = al_get_time() - game->_priv.loading.time;
|
||||||
if (game->_priv.loading.current->show_loading) {
|
game->time += delta; // TODO: ability to disable passing time during loading
|
||||||
game->_priv.loading.gamestate->api->logic(game, game->_priv.loading.gamestate->data, delta);
|
|
||||||
DrawGamestates(game);
|
|
||||||
}
|
|
||||||
game->_priv.loading.time += delta;
|
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);
|
DrawConsole(game);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -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);
|
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);
|
game->audio.v = al_create_voice(samplerate, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2);
|
||||||
if (!game->audio.v) {
|
if (!game->audio.v) {
|
||||||
// fallback
|
// fallback
|
||||||
game->audio.v = al_create_voice(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
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.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.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);
|
game->audio.music = al_create_mixer(samplerate, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
||||||
|
|
149
src/mainloop.c
149
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) {
|
static inline bool MainloopTick(struct Game* game) {
|
||||||
if (game->_priv.paused) {
|
if (game->_priv.paused) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -248,27 +308,31 @@ static inline bool MainloopTick(struct Game* game) {
|
||||||
game->_priv.loading.time = time;
|
game->_priv.loading.time = time;
|
||||||
|
|
||||||
CalculateProgress(game);
|
CalculateProgress(game);
|
||||||
|
if (tmp->show_loading) {
|
||||||
|
game->loading.shown = true;
|
||||||
|
DrawGamestates(game);
|
||||||
|
DrawConsole(game);
|
||||||
|
al_flip_display();
|
||||||
|
}
|
||||||
#ifndef LIBSUPERDERPY_SINGLE_THREAD
|
#ifndef LIBSUPERDERPY_SINGLE_THREAD
|
||||||
al_run_detached_thread(GamestateLoadingThread, &data);
|
al_run_detached_thread(GamestateLoadingThread, &data);
|
||||||
while (game->_priv.loading.in_progress) {
|
while (game->_priv.loading.in_progress) {
|
||||||
double delta = al_get_time() - game->_priv.loading.time;
|
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->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) {
|
if (game->_priv.texture_sync) {
|
||||||
al_convert_memory_bitmaps();
|
al_convert_memory_bitmaps();
|
||||||
game->_priv.texture_sync = false;
|
game->_priv.texture_sync = false;
|
||||||
al_signal_cond(game->_priv.texture_sync_cond);
|
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);
|
DrawConsole(game);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
|
|
||||||
#ifndef LIBSUPERDERPY_SINGLE_THREAD
|
|
||||||
if (game->_priv.bsod_sync) {
|
if (game->_priv.bsod_sync) {
|
||||||
al_set_target_bitmap(NULL);
|
al_set_target_bitmap(NULL);
|
||||||
game->_priv.bsod_sync = false;
|
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_wait_cond(game->_priv.bsod_cond, game->_priv.bsod_mutex);
|
||||||
}
|
}
|
||||||
al_unlock_mutex(game->_priv.bsod_mutex);
|
al_unlock_mutex(game->_priv.bsod_mutex);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
GamestateLoadingThread(&data);
|
GamestateLoadingThread(&data);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_sleep(0);
|
||||||
|
#endif
|
||||||
al_convert_memory_bitmaps();
|
al_convert_memory_bitmaps();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -316,6 +382,10 @@ static inline bool MainloopTick(struct Game* game) {
|
||||||
|
|
||||||
if (game->_priv.loading.loaded) {
|
if (game->_priv.loading.loaded) {
|
||||||
ReloadShaders(game, false);
|
ReloadShaders(game, false);
|
||||||
|
MainloopEvents(game); // consume queued events
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_sleep(0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gameActive = false;
|
bool gameActive = false;
|
||||||
|
@ -328,6 +398,7 @@ static inline bool MainloopTick(struct Game* game) {
|
||||||
game->_priv.current_gamestate = tmp;
|
game->_priv.current_gamestate = tmp;
|
||||||
tmp->started = true;
|
tmp->started = true;
|
||||||
tmp->pending_start = false;
|
tmp->pending_start = false;
|
||||||
|
|
||||||
(*tmp->api->start)(game, tmp->data);
|
(*tmp->api->start)(game, tmp->data);
|
||||||
al_resume_timer(game->_priv.timer);
|
al_resume_timer(game->_priv.timer);
|
||||||
game->_priv.timestamp = al_get_time();
|
game->_priv.timestamp = al_get_time();
|
||||||
|
@ -371,66 +442,6 @@ static inline bool MainloopTick(struct Game* game) {
|
||||||
return true;
|
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) {
|
SYMBOL_EXPORT bool libsuperderpy_mainloop(struct Game* game) {
|
||||||
ClearGarbage(game);
|
ClearGarbage(game);
|
||||||
return MainloopEvents(game) && MainloopTick(game);
|
return MainloopEvents(game) && MainloopTick(game);
|
||||||
|
|
Loading…
Reference in a new issue