diff --git a/src/internal.c b/src/internal.c index 1d21282..c43f94b 100644 --- a/src/internal.c +++ b/src/internal.c @@ -21,33 +21,33 @@ #include "3rdparty/valgrind.h" #include -SYMBOL_INTERNAL void SimpleCompositor(struct Game* game, struct Gamestate* gamestates) { +SYMBOL_INTERNAL void SimpleCompositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb) { struct Gamestate* tmp = gamestates; ClearToColor(game, al_map_rgb(0, 0, 0)); while (tmp) { if ((tmp->loaded) && (tmp->started)) { - al_draw_bitmap(tmp->fb, game->_priv.clip_rect.x, game->_priv.clip_rect.y, 0); + al_draw_bitmap(tmp->fb, game->clip_rect.x, game->clip_rect.y, 0); } tmp = tmp->next; } - if (game->_priv.loading.shown) { - al_draw_bitmap(game->loading_fb, game->_priv.clip_rect.x, game->_priv.clip_rect.y, 0); + if (game->loading.shown) { + al_draw_bitmap(loading_fb, game->clip_rect.x, game->clip_rect.y, 0); } } SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { - if (!game->handlers.compositor) { + if (!game->_priv.params.handlers.compositor) { ClearScreen(game); } struct Gamestate* tmp = game->_priv.gamestates; - if (game->handlers.predraw) { - game->handlers.predraw(game); + if (game->_priv.params.handlers.predraw) { + game->_priv.params.handlers.predraw(game); } while (tmp) { if ((tmp->loaded) && (tmp->started)) { game->_priv.current_gamestate = tmp; SetFramebufferAsTarget(game); - if (game->handlers.compositor) { // don't clear when uncomposited + if (game->_priv.params.handlers.compositor) { // don't clear when uncomposited al_reset_clipping_rectangle(); al_clear_to_color(al_map_rgb(0, 0, 0)); // even if everything is going to be redrawn, it optimizes tiled rendering } @@ -57,11 +57,11 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { tmp = tmp->next; } - if (game->_priv.loading.inProgress) { + if (game->_priv.loading.in_progress) { // same as above, but for the loading gamestate game->_priv.current_gamestate = NULL; SetFramebufferAsTarget(game); - if (game->handlers.compositor) { + if (game->_priv.params.handlers.compositor) { al_reset_clipping_rectangle(); al_clear_to_color(al_map_rgb(0, 0, 0)); } @@ -76,19 +76,19 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { al_use_transform(&t); al_reset_clipping_rectangle(); - if (game->handlers.compositor) { - game->handlers.compositor(game, game->_priv.gamestates); + if (game->_priv.params.handlers.compositor) { + game->_priv.params.handlers.compositor(game, game->_priv.gamestates, game->_priv.loading.fb); } - if (game->handlers.postdraw) { - game->handlers.postdraw(game); + if (game->_priv.params.handlers.postdraw) { + game->_priv.params.handlers.postdraw(game); } } SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) { struct Gamestate* tmp = game->_priv.gamestates; - if (game->handlers.prelogic) { - game->handlers.prelogic(game, delta); + if (game->_priv.params.handlers.prelogic) { + game->_priv.params.handlers.prelogic(game, delta); } while (tmp) { if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) { @@ -97,8 +97,8 @@ SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) { } tmp = tmp->next; } - if (game->handlers.postlogic) { - game->handlers.postlogic(game, delta); + if (game->_priv.params.handlers.postlogic) { + game->_priv.params.handlers.postlogic(game, delta); } } @@ -166,18 +166,18 @@ SYMBOL_INTERNAL void ResizeGamestates(struct Game* game) { struct Gamestate* tmp = game->_priv.gamestates; while (tmp) { al_destroy_bitmap(tmp->fb); - if (game->handlers.compositor) { - tmp->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); + if (game->_priv.params.handlers.compositor) { + tmp->fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h); } else { - tmp->fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h); + tmp->fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->clip_rect.x, game->clip_rect.y, game->clip_rect.w, game->clip_rect.h); } tmp = tmp->next; } - al_destroy_bitmap(game->loading_fb); - if (game->handlers.compositor) { - game->loading_fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); + al_destroy_bitmap(game->_priv.loading.fb); + if (game->_priv.params.handlers.compositor) { + game->_priv.loading.fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h); } else { - game->loading_fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h); + game->_priv.loading.fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->clip_rect.x, game->clip_rect.y, game->clip_rect.w, game->clip_rect.h); } } @@ -215,7 +215,7 @@ SYMBOL_INTERNAL void DrawConsole(struct Game* game) { DrawTimelines(game); al_hold_bitmap_drawing(false); - al_use_transform(&game->projection); + al_use_transform(&game->_priv.projection); } if (game_time - game->_priv.fps_count.old_time >= 1.0) { @@ -228,11 +228,11 @@ SYMBOL_INTERNAL void DrawConsole(struct Game* game) { } SYMBOL_INTERNAL void Console_Load(struct Game* game) { - game->_priv.font_console = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), (int)(game->_priv.clip_rect.h * 0.025), 0); - if (game->_priv.clip_rect.h * 0.025 >= 16) { - game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/PerfectDOSVGA437.ttf"), 16 * ((game->_priv.clip_rect.h > 1080) ? 2 : 1), 0); + game->_priv.font_console = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), (int)(game->clip_rect.h * 0.025), 0); + if (game->clip_rect.h * 0.025 >= 16) { + game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/PerfectDOSVGA437.ttf"), 16 * ((game->clip_rect.h > 1080) ? 2 : 1), 0); } else { - game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), (int)(game->_priv.clip_rect.h * 0.025), 0); + game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), (int)(game->clip_rect.h * 0.025), 0); } } @@ -244,7 +244,7 @@ SYMBOL_INTERNAL void Console_Unload(struct Game* game) { SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) { struct GamestateLoadingThreadData* data = arg; - data->game->_priv.loading.inProgress = true; + data->game->_priv.loading.in_progress = true; al_set_new_bitmap_flags(data->bitmap_flags); data->gamestate->data = data->gamestate->api->Gamestate_Load(data->game, &GamestateProgress); if (data->game->_priv.loading.progress != data->gamestate->progressCount) { @@ -256,7 +256,7 @@ SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) { } } data->bitmap_flags = al_get_new_bitmap_flags(); - data->game->_priv.loading.inProgress = false; + data->game->_priv.loading.in_progress = false; return NULL; } @@ -264,7 +264,7 @@ SYMBOL_INTERNAL void* ScreenshotThread(void* arg) { struct ScreenshotThreadData* data = arg; ALLEGRO_PATH* path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); char filename[255]; - snprintf(filename, 255, "%s_%ju_%ju.png", data->game->name, (uintmax_t)time(NULL), (uintmax_t)clock()); + snprintf(filename, 255, "%s_%ju_%ju.png", data->game->_priv.name, (uintmax_t)time(NULL), (uintmax_t)clock()); al_set_path_filename(path, filename); al_save_bitmap(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP), data->bitmap); PrintConsole(data->game, "Screenshot stored in %s", al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP)); @@ -280,7 +280,7 @@ SYMBOL_INTERNAL void CalculateProgress(struct Game* game) { if (game->config.debug) { PrintConsole(game, "[%s] Progress: %d%% (%d/%d)", tmp->name, (int)(progress * 100), game->_priv.loading.progress, tmp->progressCount + 1); } - game->loading_progress = progress; + game->loading.progress = progress; } SYMBOL_INTERNAL void GamestateProgress(struct Game* game) { @@ -310,16 +310,16 @@ SYMBOL_INTERNAL void GamestateProgress(struct Game* game) { SYMBOL_INTERNAL bool OpenGamestate(struct Game* game, struct Gamestate* gamestate) { PrintConsole(game, "Opening gamestate \"%s\"...", gamestate->name); char libname[1024]; - snprintf(libname, 1024, "libsuperderpy-%s-%s" LIBRARY_EXTENSION, game->name, gamestate->name); + snprintf(libname, 1024, "libsuperderpy-%s-%s" LIBRARY_EXTENSION, game->_priv.name, gamestate->name); gamestate->handle = dlopen(AddGarbage(game, GetLibraryPath(game, libname)), RTLD_NOW); if (!gamestate->handle) { FatalError(game, false, "Error while opening gamestate \"%s\": %s", gamestate->name, dlerror()); // TODO: move out return false; } - if (game->handlers.compositor) { - gamestate->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); + if (game->_priv.params.handlers.compositor) { + gamestate->fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h); } else { - gamestate->fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h); + gamestate->fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->clip_rect.x, game->clip_rect.y, game->clip_rect.w, game->clip_rect.h); } gamestate->open = true; return true; @@ -499,10 +499,10 @@ SYMBOL_INTERNAL void ClearScreen(struct Game* game) { al_set_target_backbuffer(game->display); al_reset_clipping_rectangle(); al_clear_to_color(al_map_rgb(0, 0, 0)); - if (game->viewport_config.depth_buffer) { + if (game->_priv.params.depth_buffer) { al_clear_depth_buffer(1.0); } - al_set_clipping_rectangle(game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h); + al_set_clipping_rectangle(game->clip_rect.x, game->clip_rect.y, game->clip_rect.w, game->clip_rect.h); } static void DrawQueue(struct Game* game, struct TM_Action* queue, int clipX, int clipY) { @@ -511,19 +511,19 @@ static void DrawQueue(struct Game* game, struct TM_Action* queue, int clipX, int struct TM_Action* pom = queue; while (pom != NULL) { int width = al_get_text_width(game->_priv.font_console, pom->name); - al_draw_filled_rectangle(pos - (10 / 3200.0) * game->_priv.clip_rect.w, clipY, pos + width + (10 / 3200.0) * game->_priv.clip_rect.w, clipY + (60 / 1800.0) * game->_priv.clip_rect.h, pom->started ? al_map_rgba(255, 255, 255, 192) : al_map_rgba(0, 0, 0, 0)); - al_draw_rectangle(pos - (10 / 3200.0) * game->_priv.clip_rect.w, clipY, pos + width + (10 / 3200.0) * game->_priv.clip_rect.w, clipY + (60 / 1800.0) * game->_priv.clip_rect.h, al_map_rgb(255, 255, 255), 2); + al_draw_filled_rectangle(pos - (10 / 3200.0) * game->clip_rect.w, clipY, pos + width + (10 / 3200.0) * game->clip_rect.w, clipY + (60 / 1800.0) * game->clip_rect.h, pom->started ? al_map_rgba(255, 255, 255, 192) : al_map_rgba(0, 0, 0, 0)); + al_draw_rectangle(pos - (10 / 3200.0) * game->clip_rect.w, clipY, pos + width + (10 / 3200.0) * game->clip_rect.w, clipY + (60 / 1800.0) * game->clip_rect.h, al_map_rgb(255, 255, 255), 2); al_draw_text(game->_priv.font_console, pom->started ? al_map_rgb(0, 0, 0) : al_map_rgb(255, 255, 255), pos, clipY, ALLEGRO_ALIGN_LEFT, pom->name); if (pom->delay) { - al_draw_textf(game->_priv.font_console, al_map_rgb(255, 255, 255), pos, clipY - (50 / 1800.0) * game->_priv.clip_rect.h, ALLEGRO_ALIGN_LEFT, "%d", (int)(pom->delay * 1000)); + al_draw_textf(game->_priv.font_console, al_map_rgb(255, 255, 255), pos, clipY - (50 / 1800.0) * game->clip_rect.h, ALLEGRO_ALIGN_LEFT, "%d", (int)(pom->delay * 1000)); } if (strncmp(pom->name, "TM_RunInBackground", 18) == 0) { // FIXME: this is crappy way to detect queued background actions - al_draw_textf(game->_priv.font_console, al_map_rgb(255, 255, 255), pos, clipY - (50 / 1800.0) * game->_priv.clip_rect.h, ALLEGRO_ALIGN_LEFT, "%s", (char*)pom->arguments->next->next->value); + al_draw_textf(game->_priv.font_console, al_map_rgb(255, 255, 255), pos, clipY - (50 / 1800.0) * game->clip_rect.h, ALLEGRO_ALIGN_LEFT, "%s", (char*)pom->arguments->next->next->value); } - pos += width + (int)((20 / 3200.0) * game->_priv.clip_rect.w); + pos += width + (int)((20 / 3200.0) * game->clip_rect.w); pom = pom->next; } } @@ -618,7 +618,7 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) { SYMBOL_INTERNAL char* GetGameName(struct Game* game, const char* format) { char* result = malloc(sizeof(char) * 255); SUPPRESS_WARNING("-Wformat-nonliteral") - snprintf(result, 255, format, game->name); + snprintf(result, 255, format, game->_priv.name); SUPPRESS_END return AddGarbage(game, result); } diff --git a/src/internal.h b/src/internal.h index 172717c..a5c3266 100644 --- a/src/internal.h +++ b/src/internal.h @@ -72,7 +72,7 @@ struct ScreenshotThreadData { ALLEGRO_BITMAP* bitmap; }; -void SimpleCompositor(struct Game* game, struct Gamestate* gamestates); +void SimpleCompositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb); void DrawGamestates(struct Game* game); void LogicGamestates(struct Game* game, double delta); void TickGamestates(struct Game* game); diff --git a/src/libsuperderpy.c b/src/libsuperderpy.c index 967fb17..ddb5bb0 100644 --- a/src/libsuperderpy.c +++ b/src/libsuperderpy.c @@ -36,7 +36,7 @@ static char* GetDefaultWindowWidth(struct Game* game) { char* buf = malloc(sizeof(char) * 255); - double aspect = game->viewport_config.aspect ? game->viewport_config.aspect : (game->viewport_config.width / (double)game->viewport_config.height); + double aspect = game->_priv.params.aspect ? game->_priv.params.aspect : (game->_priv.params.width / (double)game->_priv.params.height); if (aspect < 1.0) { aspect = 1.0; } @@ -46,7 +46,7 @@ static char* GetDefaultWindowWidth(struct Game* game) { static char* GetDefaultWindowHeight(struct Game* game) { char* buf = malloc(sizeof(char) * 255); - double aspect = game->viewport_config.aspect ? game->viewport_config.aspect : (game->viewport_config.width / (double)game->viewport_config.height); + double aspect = game->_priv.params.aspect ? game->_priv.params.aspect : (game->_priv.params.width / (double)game->_priv.params.height); if (aspect > 1.0) { aspect = 1.0; } @@ -54,11 +54,11 @@ static char* GetDefaultWindowHeight(struct Game* game) { return AddGarbage(game, buf); } -SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* name, struct Viewport viewport) { +SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* name, struct Params params) { struct Game* game = calloc(1, sizeof(struct Game)); - game->name = name; - game->viewport_config = viewport; + game->_priv.name = name; + game->_priv.params = params; #ifdef ALLEGRO_MACOSX getcwd(game->_priv.cwd, MAXPATHLEN); @@ -93,14 +93,6 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* game->_priv.paused = false; - game->handlers.event = NULL; - game->handlers.destroy = NULL; - game->handlers.compositor = NULL; - game->handlers.prelogic = NULL; - game->handlers.postlogic = NULL; - game->handlers.predraw = NULL; - game->handlers.postdraw = NULL; - game->_priv.texture_sync = false; game->_priv.texture_sync_cond = al_create_cond(); game->_priv.texture_sync_mutex = al_create_mutex(); @@ -156,8 +148,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* return NULL; } - game->mouse = al_install_mouse(); - if (!game->mouse) { + game->input.available.mouse = al_install_mouse(); + if (!game->input.available.mouse) { fprintf(stderr, "failed to initialize the mouse!\n"); } @@ -171,10 +163,10 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* return NULL; } - game->touch = false; + game->input.available.touch = false; if (!strtol(GetConfigOptionDefault(game, "SuperDerpy", "disableTouch", "0"), NULL, 10)) { - game->touch = al_install_touch_input(); + game->input.available.touch = al_install_touch_input(); } #ifdef LIBSUPERDERPY_MOUSE_EMULATION @@ -183,10 +175,10 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* } #endif - game->joystick = false; + game->input.available.joystick = false; if (!strtol(GetConfigOptionDefault(game, "SuperDerpy", "disableJoystick", "0"), NULL, 10)) { - game->joystick = al_install_joystick(); + game->input.available.joystick = al_install_joystick(); } #ifdef ALLEGRO_ANDROID @@ -211,7 +203,7 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT, ALLEGRO_SUGGEST); #endif - if (viewport.depth_buffer) { + if (params.depth_buffer) { al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 24, ALLEGRO_SUGGEST); } @@ -219,7 +211,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* al_set_new_window_position(20, 40); // workaround nasty Windows bug with window being created off-screen #endif - al_set_new_window_title(al_get_app_name()); + al_set_new_window_title(game->_priv.params.window_title ? game->_priv.params.window_title : al_get_app_name()); + game->display = al_create_display(game->config.width, game->config.height); if (!game->display) { fprintf(stderr, "Failed to create display!\n"); @@ -269,7 +262,7 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* if (game->config.fullscreen) { al_hide_mouse_cursor(game->display); } al_inhibit_screensaver(true); - SetupViewport(game, viewport); + SetupViewport(game); al_add_new_bitmap_flag(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); @@ -317,17 +310,15 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* game->data = NULL; - game->shutting_down = false; - game->restart = false; + game->_priv.shutting_down = false; + game->_priv.restart = false; - game->show_loading_on_launch = false; + game->loading.progress = 0; - game->loading_progress = 0; - - if (game->handlers.compositor) { - game->loading_fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); + if (game->_priv.params.handlers.compositor) { + game->_priv.loading.fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h); } else { - game->loading_fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h); + game->_priv.loading.fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->clip_rect.x, game->clip_rect.y, game->clip_rect.w, game->clip_rect.h); } return game; @@ -336,13 +327,13 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char* SYMBOL_EXPORT int libsuperderpy_start(struct Game* game) { al_register_event_source(game->_priv.event_queue, al_get_display_event_source(game->display)); al_register_event_source(game->_priv.event_queue, al_get_keyboard_event_source()); - if (game->mouse) { + if (game->input.available.mouse) { al_register_event_source(game->_priv.event_queue, al_get_mouse_event_source()); } - if (game->joystick) { + if (game->input.available.joystick) { al_register_event_source(game->_priv.event_queue, al_get_joystick_event_source()); } - if (game->touch) { + if (game->input.available.touch) { al_register_event_source(game->_priv.event_queue, al_get_touch_input_event_source()); #ifdef LIBSUPERDERPY_MOUSE_EMULATION al_register_event_source(game->_priv.event_queue, al_get_touch_input_mouse_emulation_event_source()); @@ -366,7 +357,7 @@ SYMBOL_EXPORT int libsuperderpy_start(struct Game* game) { struct Gamestate* tmp = game->_priv.gamestates; while (tmp) { // don't show loading screen on init if requested - tmp->showLoading = game->show_loading_on_launch; + tmp->showLoading = game->_priv.params.show_loading_on_launch; tmp = tmp->next; } } @@ -421,7 +412,7 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game* game) { } SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) { - game->shutting_down = true; + game->_priv.shutting_down = true; #ifdef LIBSUPERDERPY_IMGUI ImGui_ImplAllegro5_Shutdown(); @@ -456,8 +447,8 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) { CloseGamestate(game, game->_priv.loading.gamestate); free(game->_priv.loading.gamestate); - if (game->handlers.destroy) { - (*game->handlers.destroy)(game); + if (game->_priv.params.handlers.destroy) { + (*game->_priv.params.handlers.destroy)(game); } DestroyShaders(game); @@ -505,7 +496,7 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) { #ifndef __EMSCRIPTEN__ al_uninstall_system(); char** argv = game->_priv.argv; - bool restart = game->restart; + bool restart = game->_priv.restart; free(game); if (restart) { #ifdef ALLEGRO_MACOSX diff --git a/src/libsuperderpy.h b/src/libsuperderpy.h index 77ea328..e3a69b1 100644 --- a/src/libsuperderpy.h +++ b/src/libsuperderpy.h @@ -86,6 +86,12 @@ struct GamestateResources; #define LIBSUPERDERPY_BITMAP_HASHMAP_BUCKETS 16 +#if !defined(LIBSUPERDERPY_INTERNAL_H) && defined(__GNUC__) +#define LIBSUPERDERPY_DEPRECATED_PRIV __attribute__((deprecated)) +#else +#define LIBSUPERDERPY_DEPRECATED_PRIV +#endif + #if defined(ALLEGRO_WINDOWS) && !defined(LIBSUPERDERPY_NO_MAIN_MANGLING) int _libsuperderpy_main(int argc, char** argv); #define main(a, b) \ @@ -101,21 +107,47 @@ int _libsuperderpy_main(int argc, char** argv); int _libsuperderpy_main(a, b) #endif -struct Viewport { +/*! \brief A list of user callbacks to register. */ +struct Handlers { + bool (*event)(struct Game* game, ALLEGRO_EVENT* ev); + void (*destroy)(struct Game* game); + void (*compositor)(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb); + void (*prelogic)(struct Game* game, double delta); + void (*postlogic)(struct Game* game, double delta); + void (*predraw)(struct Game* game); + void (*postdraw)(struct Game* game); +}; + +/*! \brief Parameters for engine initialization. All values default to 0/false/NULL. */ +struct Params { int width; /*!< Width of the drawing canvas. */ int height; /*!< Height of the drawing canvas. */ float aspect; /*!< When set instead of width/height pair, makes the viewport side fluid; when non-zero, locks its aspect ratio. */ bool integer_scaling; /*!< Ensure that the viewport is zoomed only with integer factors. */ bool depth_buffer; /*!< Request a depth buffer for the framebuffer's render target. */ + bool show_loading_on_launch; /*!< Whether the loading screen should be shown when loading the initial set of gamestates. */ + char* window_title; /*!< A title of the game's window. When NULL, al_get_app_name() is used. */ + struct Handlers handlers; /*!< A list of user callbacks to register. */ }; /*! \brief Main struct of the game. */ struct Game { ALLEGRO_DISPLAY* display; /*!< Main Allegro display. */ + ALLEGRO_EVENT_SOURCE event_source; /*!< Event source for user events. */ + struct { + ALLEGRO_VOICE* v; /*!< Main voice used by the game. */ + ALLEGRO_MIXER* mixer; /*!< Main mixer of the game. */ + ALLEGRO_MIXER* music; /*!< Music mixer. */ + ALLEGRO_MIXER* voice; /*!< Voice mixer. */ + ALLEGRO_MIXER* fx; /*!< Effects mixer. */ + } audio; /*!< Audio resources. */ - ALLEGRO_TRANSFORM projection; /*!< Projection of the game canvas into the actual game window. */ + LIBSUPERDERPY_DATA_TYPE* data; /*!< User defined structure. */ - struct Viewport viewport, viewport_config; + struct { + int width; + int height; + } viewport; /*!< Canvas size. */ double time; /*!< In-game total passed time in seconds. */ @@ -128,17 +160,29 @@ struct Game { bool debug; /*!< Toggles debug mode. */ int width; /*!< Width of window as being set in configuration. */ int height; /*!< Height of window as being set in configuration. */ - } config; + } config; /*!< Configuration values from the config file. */ struct { - ALLEGRO_VOICE* v; /*!< Main voice used by the game. */ - ALLEGRO_MIXER* mixer; /*!< Main mixer of the game. */ - ALLEGRO_MIXER* music; /*!< Music mixer. */ - ALLEGRO_MIXER* voice; /*!< Voice mixer. */ - ALLEGRO_MIXER* fx; /*!< Effects mixer. */ - } audio; /*!< Audio resources. */ + int x, y; + int w, h; + } clip_rect; /*!< Clipping rectangle of the display's backbuffer. */ struct { + float progress; + bool shown; + } loading; /*!< Data about gamestate loading process. */ + + struct { + struct { + bool touch; + bool joystick; + bool mouse; + } available; + } input; + + struct { + struct Params params; + struct Gamestate* gamestates; /*!< List of known gamestates. */ ALLEGRO_FONT* font_console; /*!< Font used in game console. */ ALLEGRO_FONT* font_bsod; /*!< Font used in Blue Screens of Derp. */ @@ -164,9 +208,9 @@ struct Game { struct Gamestate* current; int progress; int loaded, toLoad; - volatile bool inProgress; - bool shown; + volatile bool in_progress; double time; + ALLEGRO_BITMAP* fb; } loading; struct Gamestate* current_gamestate; @@ -175,11 +219,6 @@ struct Game { double timestamp; - struct { - int x, y; - int w, h; - } clip_rect; - bool paused; volatile bool texture_sync; @@ -193,45 +232,25 @@ struct Game { ALLEGRO_MUTEX* mutex; + const char* name; + + bool shutting_down; /*!< If true then shut down of the game is pending. */ + bool restart; /*!< If true then restart of the game is pending. */ + struct { bool verbose, livereload, autopause; } debug; + ALLEGRO_TRANSFORM projection; /*!< Projection of the game canvas into the actual game window. */ + #ifdef ALLEGRO_MACOSX char cwd[MAXPATHLEN]; #endif - } _priv; /*!< Private resources. Do not use in gamestates! */ - - bool shutting_down; /*!< If true then shut down of the game is pending. */ - bool restart; /*!< If true then restart of the game is pending. */ - bool touch; - bool joystick; - bool mouse; - - bool show_loading_on_launch; - - const char* name; - - ALLEGRO_EVENT_SOURCE event_source; - - float loading_progress; - ALLEGRO_BITMAP* loading_fb; - - struct { - bool (*event)(struct Game* game, ALLEGRO_EVENT* ev); - void (*destroy)(struct Game* game); - void (*compositor)(struct Game* game, struct Gamestate* gamestates); - void (*prelogic)(struct Game* game, double delta); - void (*postlogic)(struct Game* game, double delta); - void (*predraw)(struct Game* game); - void (*postdraw)(struct Game* game); - } handlers; - - LIBSUPERDERPY_DATA_TYPE* data; + } _priv LIBSUPERDERPY_DEPRECATED_PRIV; /*!< Private resources. Do not use in gamestates! */ }; -struct Game* libsuperderpy_init(int argc, char** argv, const char* name, struct Viewport viewport); +struct Game* libsuperderpy_init(int argc, char** argv, const char* name, struct Params params); int libsuperderpy_start(struct Game* game); int libsuperderpy_run(struct Game* game); void libsuperderpy_destroy(struct Game* game); diff --git a/src/mainloop.c b/src/mainloop.c index 51d3fb2..aa73419 100644 --- a/src/mainloop.c +++ b/src/mainloop.c @@ -49,7 +49,7 @@ static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) { #ifdef LIBSUPERDERPY_IMGUI ImGui_ImplAllegro5_CreateDeviceObjects(); #endif - SetupViewport(game, game->viewport_config); + SetupViewport(game); break; case ALLEGRO_EVENT_KEY_DOWN: @@ -195,7 +195,7 @@ static inline bool MainloopTick(struct Game* game) { game->_priv.loading.toLoad = 0; game->_priv.loading.loaded = 0; - game->loading_progress = 0; + game->loading.progress = 0; // TODO: support gamestate dependences/ordering while (tmp) { @@ -246,17 +246,17 @@ static inline bool MainloopTick(struct Game* game) { game->_priv.current_gamestate = tmp; struct GamestateLoadingThreadData data = {.game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags()}; - game->_priv.loading.inProgress = true; + game->_priv.loading.in_progress = true; double time = al_get_time(); game->_priv.loading.time = time; CalculateProgress(game); #ifndef LIBSUPERDERPY_SINGLE_THREAD al_run_detached_thread(GamestateLoadingThread, &data); - while (game->_priv.loading.inProgress) { + while (game->_priv.loading.in_progress) { double delta = al_get_time() - game->_priv.loading.time; if (tmp->showLoading) { - game->_priv.loading.shown = true; + game->loading.shown = true; (*game->_priv.loading.gamestate->api->Gamestate_Logic)(game, game->_priv.loading.gamestate->data, delta); DrawGamestates(game); } @@ -307,7 +307,7 @@ static inline bool MainloopTick(struct Game* game) { } if (tmp->showLoading) { (*game->_priv.loading.gamestate->api->Gamestate_Stop)(game, game->_priv.loading.gamestate->data); - game->_priv.loading.shown = false; + game->loading.shown = false; } tmp->showLoading = true; al_resume_timer(game->_priv.timer); @@ -411,8 +411,8 @@ static inline bool MainloopEvents(struct Game* game) { } #endif - if (game->handlers.event) { - if ((*game->handlers.event)(game, &ev)) { + if (game->_priv.params.handlers.event) { + if ((*game->_priv.params.handlers.event)(game, &ev)) { continue; } } diff --git a/src/utils.c b/src/utils.c index 61412d1..f0c6b20 100644 --- a/src/utils.c +++ b/src/utils.c @@ -217,7 +217,7 @@ SYMBOL_EXPORT void FatalErrorWithContext(struct Game* game, int line, const char fprintf(stderr, "%s:%d [%s]\n%s\n", file, line, func, text); #ifndef LIBSUPERDERPY_SINGLE_THREAD - if (game->_priv.loading.inProgress) { + if (game->_priv.loading.in_progress) { al_lock_mutex(game->_priv.bsod_mutex); game->_priv.in_bsod = true; game->_priv.bsod_sync = true; @@ -251,7 +251,7 @@ SYMBOL_EXPORT void FatalErrorWithContext(struct Game* game, int line, const char al_set_target_backbuffer(game->display); al_clear_to_color(al_map_rgb(0, 0, 170)); - const char* header = game->name; + const char* header = game->_priv.name; const int headw = al_get_text_width(game->_priv.font_bsod, header); al_draw_filled_rectangle(offsetx - headw / 2.0 - 4, offsety, 4 + offsetx + headw / 2.0, offsety + fonth, al_map_rgb(170, 170, 170)); @@ -318,9 +318,9 @@ SYMBOL_EXPORT void FatalErrorWithContext(struct Game* game, int line, const char done = true; #endif } - al_use_transform(&game->projection); + al_use_transform(&game->_priv.projection); #ifndef LIBSUPERDERPY_SINGLE_THREAD - if (game->_priv.loading.inProgress) { + if (game->_priv.loading.in_progress) { PrintConsole(game, "Resuming the main thread..."); game->_priv.in_bsod = false; al_signal_cond(game->_priv.bsod_cond); @@ -448,29 +448,29 @@ SYMBOL_EXPORT void PrintConsoleWithContext(struct Game* game, int line, const ch al_unlock_mutex(game->_priv.mutex); } -SYMBOL_EXPORT void SetupViewport(struct Game* game, struct Viewport config) { - game->viewport = config; +SYMBOL_EXPORT void SetupViewport(struct Game* game) { + game->viewport.width = game->_priv.params.width; + game->viewport.height = game->_priv.params.height; if ((game->viewport.width == 0) || (game->viewport.height == 0)) { game->viewport.height = al_get_display_height(game->display); - game->viewport.width = (int)(game->viewport.aspect * game->viewport.height); + game->viewport.width = (int)(game->_priv.params.aspect * game->viewport.height); if (game->viewport.width > al_get_display_width(game->display)) { game->viewport.width = al_get_display_width(game->display); - game->viewport.height = (int)(game->viewport.width / game->viewport.aspect); + game->viewport.height = (int)(game->viewport.width / game->_priv.params.aspect); } } - game->viewport.aspect = game->viewport.width / (float)game->viewport.height; al_set_target_backbuffer(game->display); - al_identity_transform(&game->projection); - al_use_transform(&game->projection); + al_identity_transform(&game->_priv.projection); + al_use_transform(&game->_priv.projection); al_reset_clipping_rectangle(); float resolution = al_get_display_height(game->display) / (float)game->viewport.height; if (al_get_display_width(game->display) / (float)game->viewport.width < resolution) { resolution = al_get_display_width(game->display) / (float)game->viewport.width; } - if (game->viewport.integer_scaling) { + if (game->_priv.params.integer_scaling) { resolution = floorf(resolution); if (floorf(resolution) == 0) { resolution = 1; @@ -488,16 +488,16 @@ SYMBOL_EXPORT void SetupViewport(struct Game* game, struct Viewport config) { if (strtol(GetConfigOptionDefault(game, "SuperDerpy", "letterbox", "1"), NULL, 10)) { int clipX = (al_get_display_width(game->display) - clipWidth) / 2; int clipY = (al_get_display_height(game->display) - clipHeight) / 2; - al_build_transform(&game->projection, clipX, clipY, resolution, resolution, 0.0f); + al_build_transform(&game->_priv.projection, clipX, clipY, resolution, resolution, 0.0f); al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight); - game->_priv.clip_rect.x = clipX; - game->_priv.clip_rect.y = clipY; - game->_priv.clip_rect.w = clipWidth; - game->_priv.clip_rect.h = clipHeight; + game->clip_rect.x = clipX; + game->clip_rect.y = clipY; + game->clip_rect.w = clipWidth; + game->clip_rect.h = clipHeight; } else if (strtol(GetConfigOptionDefault(game, "SuperDerpy", "scaling", "1"), NULL, 10)) { - al_build_transform(&game->projection, 0, 0, al_get_display_width(game->display) / (float)game->viewport.width, al_get_display_height(game->display) / (float)game->viewport.height, 0.0f); + al_build_transform(&game->_priv.projection, 0, 0, al_get_display_width(game->display) / (float)game->viewport.width, al_get_display_height(game->display) / (float)game->viewport.height, 0.0f); } - al_use_transform(&game->projection); + al_use_transform(&game->_priv.projection); Console_Unload(game); Console_Load(game); ResizeGamestates(game); @@ -516,7 +516,7 @@ SYMBOL_EXPORT void WindowCoordsToViewport(struct Game* game, int* x, int* y) { SYMBOL_EXPORT ALLEGRO_BITMAP* GetFramebuffer(struct Game* game) { if (!game->_priv.current_gamestate) { - return game->loading_fb; + return game->_priv.loading.fb; } return game->_priv.current_gamestate->fb; } @@ -544,15 +544,15 @@ SYMBOL_EXPORT ALLEGRO_BITMAP* CreateNotPreservedBitmap(int width, int height) { return bitmap; } -SYMBOL_EXPORT void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates)) { +SYMBOL_EXPORT void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb)) { PrintConsole(game, "Compositor enabled."); - game->handlers.compositor = compositor ? compositor : SimpleCompositor; + game->_priv.params.handlers.compositor = compositor ? compositor : SimpleCompositor; ResizeGamestates(game); } SYMBOL_EXPORT void DisableCompositor(struct Game* game) { PrintConsole(game, "Compositor disabled."); - game->handlers.compositor = NULL; + game->_priv.params.handlers.compositor = NULL; ResizeGamestates(game); } diff --git a/src/utils.h b/src/utils.h index 57fe8ed..c23b869 100644 --- a/src/utils.h +++ b/src/utils.h @@ -35,7 +35,6 @@ #define LIBRARY_EXTENSION ".so" #endif -struct Viewport; struct Gamestate; /*! \brief Draws rectangle filled with vertical gradient. */ @@ -80,7 +79,7 @@ __attribute__((__format__(__printf__, 5, 6))) void PrintConsoleWithContext(struc __attribute__((__format__(__printf__, 6, 7))) void FatalErrorWithContext(struct Game* game, int line, const char* file, const char* func, bool exit, char* format, ...); #define FatalError(game, exit, format, ...) FatalErrorWithContext(game, __LINE__, __FILE__, __func__, exit, format, ##__VA_ARGS__) -void SetupViewport(struct Game* game, struct Viewport config); +void SetupViewport(struct Game* game); void WindowCoordsToViewport(struct Game* game, int* x, int* y); @@ -90,7 +89,7 @@ void SetFramebufferAsTarget(struct Game* game); ALLEGRO_BITMAP* CreateNotPreservedBitmap(int width, int height); -void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates)); +void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates, ALLEGRO_BITMAP* loading_fb)); void DisableCompositor(struct Game* game); char* StrToLower(struct Game* game, char* text);