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 "3rdparty/valgrind.h"
#include <dlfcn.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; struct Gamestate* tmp = gamestates;
ClearToColor(game, al_map_rgb(0, 0, 0)); ClearToColor(game, al_map_rgb(0, 0, 0));
while (tmp) { while (tmp) {
if ((tmp->loaded) && (tmp->started)) { 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; tmp = tmp->next;
} }
if (game->_priv.loading.shown) { if (game->loading.shown) {
al_draw_bitmap(game->loading_fb, game->_priv.clip_rect.x, game->_priv.clip_rect.y, 0); al_draw_bitmap(loading_fb, game->clip_rect.x, game->clip_rect.y, 0);
} }
} }
SYMBOL_INTERNAL void DrawGamestates(struct Game* game) { SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
if (!game->handlers.compositor) { if (!game->_priv.params.handlers.compositor) {
ClearScreen(game); ClearScreen(game);
} }
struct Gamestate* tmp = game->_priv.gamestates; struct Gamestate* tmp = game->_priv.gamestates;
if (game->handlers.predraw) { if (game->_priv.params.handlers.predraw) {
game->handlers.predraw(game); game->_priv.params.handlers.predraw(game);
} }
while (tmp) { while (tmp) {
if ((tmp->loaded) && (tmp->started)) { if ((tmp->loaded) && (tmp->started)) {
game->_priv.current_gamestate = tmp; game->_priv.current_gamestate = tmp;
SetFramebufferAsTarget(game); 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_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 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; tmp = tmp->next;
} }
if (game->_priv.loading.inProgress) { if (game->_priv.loading.in_progress) {
// 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);
if (game->handlers.compositor) { if (game->_priv.params.handlers.compositor) {
al_reset_clipping_rectangle(); al_reset_clipping_rectangle();
al_clear_to_color(al_map_rgb(0, 0, 0)); 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_use_transform(&t);
al_reset_clipping_rectangle(); al_reset_clipping_rectangle();
if (game->handlers.compositor) { if (game->_priv.params.handlers.compositor) {
game->handlers.compositor(game, game->_priv.gamestates); game->_priv.params.handlers.compositor(game, game->_priv.gamestates, game->_priv.loading.fb);
} }
if (game->handlers.postdraw) { if (game->_priv.params.handlers.postdraw) {
game->handlers.postdraw(game); game->_priv.params.handlers.postdraw(game);
} }
} }
SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) { SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
struct Gamestate* tmp = game->_priv.gamestates; struct Gamestate* tmp = game->_priv.gamestates;
if (game->handlers.prelogic) { if (game->_priv.params.handlers.prelogic) {
game->handlers.prelogic(game, delta); game->_priv.params.handlers.prelogic(game, delta);
} }
while (tmp) { while (tmp) {
if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) { if ((tmp->loaded) && (tmp->started) && (!tmp->paused)) {
@ -97,8 +97,8 @@ SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
} }
tmp = tmp->next; tmp = tmp->next;
} }
if (game->handlers.postlogic) { if (game->_priv.params.handlers.postlogic) {
game->handlers.postlogic(game, delta); game->_priv.params.handlers.postlogic(game, delta);
} }
} }
@ -166,18 +166,18 @@ SYMBOL_INTERNAL void ResizeGamestates(struct Game* game) {
struct Gamestate* tmp = game->_priv.gamestates; struct Gamestate* tmp = game->_priv.gamestates;
while (tmp) { while (tmp) {
al_destroy_bitmap(tmp->fb); al_destroy_bitmap(tmp->fb);
if (game->handlers.compositor) { if (game->_priv.params.handlers.compositor) {
tmp->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); tmp->fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h);
} else { } 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; tmp = tmp->next;
} }
al_destroy_bitmap(game->loading_fb); al_destroy_bitmap(game->_priv.loading.fb);
if (game->handlers.compositor) { if (game->_priv.params.handlers.compositor) {
game->loading_fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); game->_priv.loading.fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h);
} else { } 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); DrawTimelines(game);
al_hold_bitmap_drawing(false); 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) { 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) { 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); game->_priv.font_console = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), (int)(game->clip_rect.h * 0.025), 0);
if (game->_priv.clip_rect.h * 0.025 >= 16) { if (game->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_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/PerfectDOSVGA437.ttf"), 16 * ((game->clip_rect.h > 1080) ? 2 : 1), 0);
} else { } 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) { SYMBOL_INTERNAL void* GamestateLoadingThread(void* arg) {
struct GamestateLoadingThreadData* data = 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); al_set_new_bitmap_flags(data->bitmap_flags);
data->gamestate->data = data->gamestate->api->Gamestate_Load(data->game, &GamestateProgress); data->gamestate->data = data->gamestate->api->Gamestate_Load(data->game, &GamestateProgress);
if (data->game->_priv.loading.progress != data->gamestate->progressCount) { 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->bitmap_flags = al_get_new_bitmap_flags();
data->game->_priv.loading.inProgress = false; data->game->_priv.loading.in_progress = false;
return NULL; return NULL;
} }
@ -264,7 +264,7 @@ SYMBOL_INTERNAL void* ScreenshotThread(void* arg) {
struct ScreenshotThreadData* data = arg; struct ScreenshotThreadData* data = arg;
ALLEGRO_PATH* path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH); ALLEGRO_PATH* path = al_get_standard_path(ALLEGRO_USER_DOCUMENTS_PATH);
char filename[255]; 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_set_path_filename(path, filename);
al_save_bitmap(al_path_cstr(path, ALLEGRO_NATIVE_PATH_SEP), data->bitmap); 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)); 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) { if (game->config.debug) {
PrintConsole(game, "[%s] Progress: %d%% (%d/%d)", tmp->name, (int)(progress * 100), game->_priv.loading.progress, tmp->progressCount + 1); 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) { 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) { SYMBOL_INTERNAL bool OpenGamestate(struct Game* game, struct Gamestate* gamestate) {
PrintConsole(game, "Opening gamestate \"%s\"...", gamestate->name); PrintConsole(game, "Opening gamestate \"%s\"...", gamestate->name);
char libname[1024]; 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); gamestate->handle = dlopen(AddGarbage(game, GetLibraryPath(game, libname)), RTLD_NOW);
if (!gamestate->handle) { if (!gamestate->handle) {
FatalError(game, false, "Error while opening gamestate \"%s\": %s", gamestate->name, dlerror()); // TODO: move out FatalError(game, false, "Error while opening gamestate \"%s\": %s", gamestate->name, dlerror()); // TODO: move out
return false; return false;
} }
if (game->handlers.compositor) { if (game->_priv.params.handlers.compositor) {
gamestate->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h); gamestate->fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h);
} else { } 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; gamestate->open = true;
return true; return true;
@ -499,10 +499,10 @@ SYMBOL_INTERNAL void ClearScreen(struct Game* game) {
al_set_target_backbuffer(game->display); al_set_target_backbuffer(game->display);
al_reset_clipping_rectangle(); al_reset_clipping_rectangle();
al_clear_to_color(al_map_rgb(0, 0, 0)); 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_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) { 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; struct TM_Action* pom = queue;
while (pom != NULL) { while (pom != NULL) {
int width = al_get_text_width(game->_priv.font_console, pom->name); 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_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->_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_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); 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) { 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 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; pom = pom->next;
} }
} }
@ -618,7 +618,7 @@ SYMBOL_INTERNAL void ResumeExecution(struct Game* game) {
SYMBOL_INTERNAL char* GetGameName(struct Game* game, const char* format) { SYMBOL_INTERNAL char* GetGameName(struct Game* game, const char* format) {
char* result = malloc(sizeof(char) * 255); char* result = malloc(sizeof(char) * 255);
SUPPRESS_WARNING("-Wformat-nonliteral") SUPPRESS_WARNING("-Wformat-nonliteral")
snprintf(result, 255, format, game->name); snprintf(result, 255, format, game->_priv.name);
SUPPRESS_END SUPPRESS_END
return AddGarbage(game, result); return AddGarbage(game, result);
} }

View file

@ -72,7 +72,7 @@ struct ScreenshotThreadData {
ALLEGRO_BITMAP* bitmap; 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 DrawGamestates(struct Game* game);
void LogicGamestates(struct Game* game, double delta); void LogicGamestates(struct Game* game, double delta);
void TickGamestates(struct Game* game); void TickGamestates(struct Game* game);

View file

@ -36,7 +36,7 @@
static char* GetDefaultWindowWidth(struct Game* game) { static char* GetDefaultWindowWidth(struct Game* game) {
char* buf = malloc(sizeof(char) * 255); 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) { if (aspect < 1.0) {
aspect = 1.0; aspect = 1.0;
} }
@ -46,7 +46,7 @@ static char* GetDefaultWindowWidth(struct Game* game) {
static char* GetDefaultWindowHeight(struct Game* game) { static char* GetDefaultWindowHeight(struct Game* game) {
char* buf = malloc(sizeof(char) * 255); 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) { if (aspect > 1.0) {
aspect = 1.0; aspect = 1.0;
} }
@ -54,11 +54,11 @@ static char* GetDefaultWindowHeight(struct Game* game) {
return AddGarbage(game, buf); 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)); struct Game* game = calloc(1, sizeof(struct Game));
game->name = name; game->_priv.name = name;
game->viewport_config = viewport; game->_priv.params = params;
#ifdef ALLEGRO_MACOSX #ifdef ALLEGRO_MACOSX
getcwd(game->_priv.cwd, MAXPATHLEN); 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->_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 = false;
game->_priv.texture_sync_cond = al_create_cond(); game->_priv.texture_sync_cond = al_create_cond();
game->_priv.texture_sync_mutex = al_create_mutex(); 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; return NULL;
} }
game->mouse = al_install_mouse(); game->input.available.mouse = al_install_mouse();
if (!game->mouse) { if (!game->input.available.mouse) {
fprintf(stderr, "failed to initialize the mouse!\n"); 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; return NULL;
} }
game->touch = false; game->input.available.touch = false;
if (!strtol(GetConfigOptionDefault(game, "SuperDerpy", "disableTouch", "0"), NULL, 10)) { 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 #ifdef LIBSUPERDERPY_MOUSE_EMULATION
@ -183,10 +175,10 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
} }
#endif #endif
game->joystick = false; game->input.available.joystick = false;
if (!strtol(GetConfigOptionDefault(game, "SuperDerpy", "disableJoystick", "0"), NULL, 10)) { if (!strtol(GetConfigOptionDefault(game, "SuperDerpy", "disableJoystick", "0"), NULL, 10)) {
game->joystick = al_install_joystick(); game->input.available.joystick = al_install_joystick();
} }
#ifdef ALLEGRO_ANDROID #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); al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT, ALLEGRO_SUGGEST);
#endif #endif
if (viewport.depth_buffer) { if (params.depth_buffer) {
al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 24, ALLEGRO_SUGGEST); 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 al_set_new_window_position(20, 40); // workaround nasty Windows bug with window being created off-screen
#endif #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); game->display = al_create_display(game->config.width, game->config.height);
if (!game->display) { if (!game->display) {
fprintf(stderr, "Failed to create display!\n"); 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); } if (game->config.fullscreen) { al_hide_mouse_cursor(game->display); }
al_inhibit_screensaver(true); al_inhibit_screensaver(true);
SetupViewport(game, viewport); SetupViewport(game);
al_add_new_bitmap_flag(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR); 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->data = NULL;
game->shutting_down = false; game->_priv.shutting_down = false;
game->restart = false; game->_priv.restart = false;
game->show_loading_on_launch = false; game->loading.progress = 0;
game->loading_progress = 0; if (game->_priv.params.handlers.compositor) {
game->_priv.loading.fb = CreateNotPreservedBitmap(game->clip_rect.w, game->clip_rect.h);
if (game->handlers.compositor) {
game->loading_fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h);
} else { } 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; 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) { 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_display_event_source(game->display));
al_register_event_source(game->_priv.event_queue, al_get_keyboard_event_source()); 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()); 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()); 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()); al_register_event_source(game->_priv.event_queue, al_get_touch_input_event_source());
#ifdef LIBSUPERDERPY_MOUSE_EMULATION #ifdef LIBSUPERDERPY_MOUSE_EMULATION
al_register_event_source(game->_priv.event_queue, al_get_touch_input_mouse_emulation_event_source()); 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; struct Gamestate* tmp = game->_priv.gamestates;
while (tmp) { while (tmp) {
// don't show loading screen on init if requested // 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; tmp = tmp->next;
} }
} }
@ -421,7 +412,7 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game* game) {
} }
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) { SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) {
game->shutting_down = true; game->_priv.shutting_down = true;
#ifdef LIBSUPERDERPY_IMGUI #ifdef LIBSUPERDERPY_IMGUI
ImGui_ImplAllegro5_Shutdown(); ImGui_ImplAllegro5_Shutdown();
@ -456,8 +447,8 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) {
CloseGamestate(game, game->_priv.loading.gamestate); CloseGamestate(game, game->_priv.loading.gamestate);
free(game->_priv.loading.gamestate); free(game->_priv.loading.gamestate);
if (game->handlers.destroy) { if (game->_priv.params.handlers.destroy) {
(*game->handlers.destroy)(game); (*game->_priv.params.handlers.destroy)(game);
} }
DestroyShaders(game); DestroyShaders(game);
@ -505,7 +496,7 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) {
#ifndef __EMSCRIPTEN__ #ifndef __EMSCRIPTEN__
al_uninstall_system(); al_uninstall_system();
char** argv = game->_priv.argv; char** argv = game->_priv.argv;
bool restart = game->restart; bool restart = game->_priv.restart;
free(game); free(game);
if (restart) { if (restart) {
#ifdef ALLEGRO_MACOSX #ifdef ALLEGRO_MACOSX

View file

@ -86,6 +86,12 @@ struct GamestateResources;
#define LIBSUPERDERPY_BITMAP_HASHMAP_BUCKETS 16 #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) #if defined(ALLEGRO_WINDOWS) && !defined(LIBSUPERDERPY_NO_MAIN_MANGLING)
int _libsuperderpy_main(int argc, char** argv); int _libsuperderpy_main(int argc, char** argv);
#define main(a, b) \ #define main(a, b) \
@ -101,21 +107,47 @@ int _libsuperderpy_main(int argc, char** argv);
int _libsuperderpy_main(a, b) int _libsuperderpy_main(a, b)
#endif #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 width; /*!< Width of the drawing canvas. */
int height; /*!< Height 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. */ 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 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 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. */ /*! \brief Main struct of the game. */
struct Game { struct Game {
ALLEGRO_DISPLAY* display; /*!< Main Allegro display. */ 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. */ double time; /*!< In-game total passed time in seconds. */
@ -128,17 +160,29 @@ struct Game {
bool debug; /*!< Toggles debug mode. */ bool debug; /*!< Toggles debug mode. */
int width; /*!< Width of window as being set in configuration. */ int width; /*!< Width of window as being set in configuration. */
int height; /*!< Height 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 { struct {
ALLEGRO_VOICE* v; /*!< Main voice used by the game. */ int x, y;
ALLEGRO_MIXER* mixer; /*!< Main mixer of the game. */ int w, h;
ALLEGRO_MIXER* music; /*!< Music mixer. */ } clip_rect; /*!< Clipping rectangle of the display's backbuffer. */
ALLEGRO_MIXER* voice; /*!< Voice mixer. */
ALLEGRO_MIXER* fx; /*!< Effects mixer. */
} audio; /*!< Audio resources. */
struct { 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. */ struct Gamestate* gamestates; /*!< List of known gamestates. */
ALLEGRO_FONT* font_console; /*!< Font used in game console. */ ALLEGRO_FONT* font_console; /*!< Font used in game console. */
ALLEGRO_FONT* font_bsod; /*!< Font used in Blue Screens of Derp. */ ALLEGRO_FONT* font_bsod; /*!< Font used in Blue Screens of Derp. */
@ -164,9 +208,9 @@ struct Game {
struct Gamestate* current; struct Gamestate* current;
int progress; int progress;
int loaded, toLoad; int loaded, toLoad;
volatile bool inProgress; volatile bool in_progress;
bool shown;
double time; double time;
ALLEGRO_BITMAP* fb;
} loading; } loading;
struct Gamestate* current_gamestate; struct Gamestate* current_gamestate;
@ -175,11 +219,6 @@ struct Game {
double timestamp; double timestamp;
struct {
int x, y;
int w, h;
} clip_rect;
bool paused; bool paused;
volatile bool texture_sync; volatile bool texture_sync;
@ -193,45 +232,25 @@ struct Game {
ALLEGRO_MUTEX* mutex; 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 { struct {
bool verbose, livereload, autopause; bool verbose, livereload, autopause;
} debug; } debug;
ALLEGRO_TRANSFORM projection; /*!< Projection of the game canvas into the actual game window. */
#ifdef ALLEGRO_MACOSX #ifdef ALLEGRO_MACOSX
char cwd[MAXPATHLEN]; char cwd[MAXPATHLEN];
#endif #endif
} _priv; /*!< Private resources. Do not use in gamestates! */ } _priv LIBSUPERDERPY_DEPRECATED_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;
}; };
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_start(struct Game* game);
int libsuperderpy_run(struct Game* game); int libsuperderpy_run(struct Game* game);
void libsuperderpy_destroy(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 #ifdef LIBSUPERDERPY_IMGUI
ImGui_ImplAllegro5_CreateDeviceObjects(); ImGui_ImplAllegro5_CreateDeviceObjects();
#endif #endif
SetupViewport(game, game->viewport_config); SetupViewport(game);
break; break;
case ALLEGRO_EVENT_KEY_DOWN: case ALLEGRO_EVENT_KEY_DOWN:
@ -195,7 +195,7 @@ static inline bool MainloopTick(struct Game* game) {
game->_priv.loading.toLoad = 0; game->_priv.loading.toLoad = 0;
game->_priv.loading.loaded = 0; game->_priv.loading.loaded = 0;
game->loading_progress = 0; game->loading.progress = 0;
// TODO: support gamestate dependences/ordering // TODO: support gamestate dependences/ordering
while (tmp) { while (tmp) {
@ -246,17 +246,17 @@ static inline bool MainloopTick(struct Game* game) {
game->_priv.current_gamestate = tmp; game->_priv.current_gamestate = tmp;
struct GamestateLoadingThreadData data = {.game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags()}; 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(); double time = al_get_time();
game->_priv.loading.time = time; game->_priv.loading.time = time;
CalculateProgress(game); CalculateProgress(game);
#ifndef LIBSUPERDERPY_SINGLE_THREAD #ifndef LIBSUPERDERPY_SINGLE_THREAD
al_run_detached_thread(GamestateLoadingThread, &data); 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; double delta = al_get_time() - game->_priv.loading.time;
if (tmp->showLoading) { 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); (*game->_priv.loading.gamestate->api->Gamestate_Logic)(game, game->_priv.loading.gamestate->data, delta);
DrawGamestates(game); DrawGamestates(game);
} }
@ -307,7 +307,7 @@ static inline bool MainloopTick(struct Game* game) {
} }
if (tmp->showLoading) { if (tmp->showLoading) {
(*game->_priv.loading.gamestate->api->Gamestate_Stop)(game, game->_priv.loading.gamestate->data); (*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; tmp->showLoading = true;
al_resume_timer(game->_priv.timer); al_resume_timer(game->_priv.timer);
@ -411,8 +411,8 @@ static inline bool MainloopEvents(struct Game* game) {
} }
#endif #endif
if (game->handlers.event) { if (game->_priv.params.handlers.event) {
if ((*game->handlers.event)(game, &ev)) { if ((*game->_priv.params.handlers.event)(game, &ev)) {
continue; 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); fprintf(stderr, "%s:%d [%s]\n%s\n", file, line, func, text);
#ifndef LIBSUPERDERPY_SINGLE_THREAD #ifndef LIBSUPERDERPY_SINGLE_THREAD
if (game->_priv.loading.inProgress) { if (game->_priv.loading.in_progress) {
al_lock_mutex(game->_priv.bsod_mutex); al_lock_mutex(game->_priv.bsod_mutex);
game->_priv.in_bsod = true; game->_priv.in_bsod = true;
game->_priv.bsod_sync = 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_set_target_backbuffer(game->display);
al_clear_to_color(al_map_rgb(0, 0, 170)); 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); 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)); 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; done = true;
#endif #endif
} }
al_use_transform(&game->projection); al_use_transform(&game->_priv.projection);
#ifndef LIBSUPERDERPY_SINGLE_THREAD #ifndef LIBSUPERDERPY_SINGLE_THREAD
if (game->_priv.loading.inProgress) { if (game->_priv.loading.in_progress) {
PrintConsole(game, "Resuming the main thread..."); PrintConsole(game, "Resuming the main thread...");
game->_priv.in_bsod = false; game->_priv.in_bsod = false;
al_signal_cond(game->_priv.bsod_cond); 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); al_unlock_mutex(game->_priv.mutex);
} }
SYMBOL_EXPORT void SetupViewport(struct Game* game, struct Viewport config) { SYMBOL_EXPORT void SetupViewport(struct Game* game) {
game->viewport = config; game->viewport.width = game->_priv.params.width;
game->viewport.height = game->_priv.params.height;
if ((game->viewport.width == 0) || (game->viewport.height == 0)) { if ((game->viewport.width == 0) || (game->viewport.height == 0)) {
game->viewport.height = al_get_display_height(game->display); 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)) { if (game->viewport.width > al_get_display_width(game->display)) {
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_set_target_backbuffer(game->display);
al_identity_transform(&game->projection); al_identity_transform(&game->_priv.projection);
al_use_transform(&game->projection); al_use_transform(&game->_priv.projection);
al_reset_clipping_rectangle(); al_reset_clipping_rectangle();
float resolution = al_get_display_height(game->display) / (float)game->viewport.height; float resolution = al_get_display_height(game->display) / (float)game->viewport.height;
if (al_get_display_width(game->display) / (float)game->viewport.width < resolution) { if (al_get_display_width(game->display) / (float)game->viewport.width < resolution) {
resolution = al_get_display_width(game->display) / (float)game->viewport.width; 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); resolution = floorf(resolution);
if (floorf(resolution) == 0) { if (floorf(resolution) == 0) {
resolution = 1; 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)) { if (strtol(GetConfigOptionDefault(game, "SuperDerpy", "letterbox", "1"), NULL, 10)) {
int clipX = (al_get_display_width(game->display) - clipWidth) / 2; int clipX = (al_get_display_width(game->display) - clipWidth) / 2;
int clipY = (al_get_display_height(game->display) - clipHeight) / 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); al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight);
game->_priv.clip_rect.x = clipX; game->clip_rect.x = clipX;
game->_priv.clip_rect.y = clipY; game->clip_rect.y = clipY;
game->_priv.clip_rect.w = clipWidth; game->clip_rect.w = clipWidth;
game->_priv.clip_rect.h = clipHeight; game->clip_rect.h = clipHeight;
} else if (strtol(GetConfigOptionDefault(game, "SuperDerpy", "scaling", "1"), NULL, 10)) { } 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_Unload(game);
Console_Load(game); Console_Load(game);
ResizeGamestates(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) { SYMBOL_EXPORT ALLEGRO_BITMAP* GetFramebuffer(struct Game* game) {
if (!game->_priv.current_gamestate) { if (!game->_priv.current_gamestate) {
return game->loading_fb; return game->_priv.loading.fb;
} }
return game->_priv.current_gamestate->fb; return game->_priv.current_gamestate->fb;
} }
@ -544,15 +544,15 @@ SYMBOL_EXPORT ALLEGRO_BITMAP* CreateNotPreservedBitmap(int width, int height) {
return bitmap; 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."); PrintConsole(game, "Compositor enabled.");
game->handlers.compositor = compositor ? compositor : SimpleCompositor; game->_priv.params.handlers.compositor = compositor ? compositor : SimpleCompositor;
ResizeGamestates(game); ResizeGamestates(game);
} }
SYMBOL_EXPORT void DisableCompositor(struct Game* game) { SYMBOL_EXPORT void DisableCompositor(struct Game* game) {
PrintConsole(game, "Compositor disabled."); PrintConsole(game, "Compositor disabled.");
game->handlers.compositor = NULL; game->_priv.params.handlers.compositor = NULL;
ResizeGamestates(game); ResizeGamestates(game);
} }

View file

@ -35,7 +35,6 @@
#define LIBRARY_EXTENSION ".so" #define LIBRARY_EXTENSION ".so"
#endif #endif
struct Viewport;
struct Gamestate; struct Gamestate;
/*! \brief Draws rectangle filled with vertical gradient. */ /*! \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, ...); __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__) #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); 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); 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); void DisableCompositor(struct Game* game);
char* StrToLower(struct Game* game, char* text); char* StrToLower(struct Game* game, char* text);