reorganize Game structure, deprecate access to _priv fields

This commit is contained in:
Sebastian Krzyszkowiak 2018-12-15 00:59:34 +01:00
parent 23b11b1a5b
commit ce66ba8060
No known key found for this signature in database
GPG key ID: E8F235CF3BDBC3FF
7 changed files with 174 additions and 165 deletions

View file

@ -21,33 +21,33 @@
#include "3rdparty/valgrind.h"
#include <dlfcn.h>
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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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