mirror of
https://gitlab.com/dosowisko.net/libsuperderpy.git
synced 2025-02-07 21:56:44 +01:00
support of loading in separate thread; thread-safe console; various fixes from clang code model warnings
This commit is contained in:
parent
4a2e2a3d25
commit
450e33b2e3
9 changed files with 285 additions and 212 deletions
|
@ -71,6 +71,10 @@ if(EMSCRIPTEN)
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(ANDROID OR EMSCRIPTEN)
|
||||||
|
add_definitions(-DLIBSUPERDERPY_SINGLE_THREAD=1)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(Allegro5 REQUIRED)
|
find_package(Allegro5 REQUIRED)
|
||||||
find_package(Allegro5Font REQUIRED)
|
find_package(Allegro5Font REQUIRED)
|
||||||
find_package(Allegro5TTF REQUIRED)
|
find_package(Allegro5TTF REQUIRED)
|
||||||
|
|
|
@ -22,34 +22,22 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "gamestate.h"
|
#include "gamestate.h"
|
||||||
|
|
||||||
SYMBOL_INTERNAL struct Gamestate* AddNewGamestate(struct Game *game, const char* name) {
|
static struct Gamestate* AddNewGamestate(struct Game *game, const char* name) {
|
||||||
struct Gamestate *tmp = game->_priv.gamestates;
|
struct Gamestate *tmp = game->_priv.gamestates;
|
||||||
if (!tmp) {
|
if (!tmp) {
|
||||||
game->_priv.gamestates = malloc(sizeof(struct Gamestate));
|
game->_priv.gamestates = AllocateGamestate(game, name);
|
||||||
tmp = game->_priv.gamestates;
|
tmp = game->_priv.gamestates;
|
||||||
} else {
|
} else {
|
||||||
while (tmp->next) {
|
while (tmp->next) {
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
tmp->next = malloc(sizeof(struct Gamestate));
|
tmp->next = AllocateGamestate(game, name);
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
tmp->name = strdup(name);
|
|
||||||
tmp->handle = NULL;
|
|
||||||
tmp->loaded = false;
|
|
||||||
tmp->paused = false;
|
|
||||||
tmp->frozen = false;
|
|
||||||
tmp->started = false;
|
|
||||||
tmp->pending_load = false;
|
|
||||||
tmp->pending_start = false;
|
|
||||||
tmp->pending_stop = false;
|
|
||||||
tmp->pending_unload = false;
|
|
||||||
tmp->next = NULL;
|
|
||||||
tmp->api = NULL;
|
|
||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL struct Gamestate* FindGamestate(struct Game *game, const char* name) {
|
static struct Gamestate* FindGamestate(struct Game *game, const char* name) {
|
||||||
struct Gamestate *tmp = game->_priv.gamestates;
|
struct Gamestate *tmp = game->_priv.gamestates;
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
if (!strcmp(name, tmp->name)) {
|
if (!strcmp(name, tmp->name)) {
|
||||||
|
|
153
src/internal.c
153
src/internal.c
|
@ -18,9 +18,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <allegro5/allegro_ttf.h>
|
#include <allegro5/allegro_ttf.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "libsuperderpy.h"
|
#include "libsuperderpy.h"
|
||||||
|
#include "3rdparty/valgrind.h"
|
||||||
|
|
||||||
SYMBOL_INTERNAL void DrawGamestates(struct Game *game) {
|
SYMBOL_INTERNAL void DrawGamestates(struct Game *game) {
|
||||||
ClearScreen(game);
|
ClearScreen(game);
|
||||||
|
@ -99,22 +101,40 @@ SYMBOL_INTERNAL void DrawConsole(struct Game *game) {
|
||||||
al_get_clipping_rectangle(&clipX, &clipY, &clipWidth, &clipHeight);
|
al_get_clipping_rectangle(&clipX, &clipY, &clipWidth, &clipHeight);
|
||||||
al_use_transform(&trans);
|
al_use_transform(&trans);
|
||||||
|
|
||||||
al_draw_bitmap(game->_priv.console, clipX, clipY, 0);
|
int width = (al_get_display_width(game->display) / game->viewport.width) * game->viewport.width;
|
||||||
double game_time = al_get_time();
|
if (!game->viewport.integer_scaling) {
|
||||||
if(game_time - game->_priv.fps_count.old_time >= 1.0) {
|
width = (al_get_display_width(game->display) / (float)game->viewport.width) * game->viewport.width;
|
||||||
game->_priv.fps_count.fps = game->_priv.fps_count.frames_done / (game_time - game->_priv.fps_count.old_time);
|
|
||||||
game->_priv.fps_count.frames_done = 0;
|
|
||||||
game->_priv.fps_count.old_time = game_time;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int size = sizeof(game->_priv.console) / sizeof(game->_priv.console[0]);
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
al_draw_filled_rectangle(clipX, clipY, clipX + width, clipY + al_get_font_line_height(game->_priv.font_console)*(size-i), al_map_rgba(0,0,0,80));
|
||||||
|
}
|
||||||
|
int cur = game->_priv.console_pos + size;
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
if (cur >= size) {
|
||||||
|
cur -= size;
|
||||||
|
}
|
||||||
|
al_draw_text(game->_priv.font_console, al_map_rgb(255,255,255), clipX + (int)(game->viewport.width*0.005), clipY + al_get_font_line_height(game->_priv.font_console)*i, ALLEGRO_ALIGN_LEFT, game->_priv.console[cur]);
|
||||||
|
cur++;
|
||||||
|
}
|
||||||
|
|
||||||
char sfps[6] = { };
|
char sfps[6] = { };
|
||||||
snprintf(sfps, 6, "%.0f", game->_priv.fps_count.fps);
|
snprintf(sfps, 6, "%.0f", game->_priv.fps_count.fps);
|
||||||
DrawTextWithShadow(game->_priv.font_console, al_map_rgb(255,255,255), clipX + clipWidth, clipY, ALLEGRO_ALIGN_RIGHT, sfps);
|
DrawTextWithShadow(game->_priv.font_console, al_map_rgb(255,255,255), clipX + clipWidth, clipY, ALLEGRO_ALIGN_RIGHT, sfps);
|
||||||
|
|
||||||
al_use_transform(&game->projection);
|
al_use_transform(&game->projection);
|
||||||
|
|
||||||
|
DrawTimelines(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
double game_time = al_get_time();
|
||||||
|
if (game_time - game->_priv.fps_count.old_time >= 1.0) {
|
||||||
|
game->_priv.fps_count.fps = game->_priv.fps_count.frames_done / (game_time - game->_priv.fps_count.old_time);
|
||||||
|
game->_priv.fps_count.frames_done = 0;
|
||||||
|
game->_priv.fps_count.old_time = game_time;
|
||||||
}
|
}
|
||||||
game->_priv.fps_count.frames_done++;
|
game->_priv.fps_count.frames_done++;
|
||||||
DrawTimelines(game);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void Console_Load(struct Game *game) {
|
SYMBOL_INTERNAL void Console_Load(struct Game *game) {
|
||||||
|
@ -124,35 +144,106 @@ SYMBOL_INTERNAL void Console_Load(struct Game *game) {
|
||||||
} else {
|
} else {
|
||||||
game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), al_get_display_height(game->display)*0.025,0 );
|
game->_priv.font_bsod = al_load_ttf_font(GetDataFilePath(game, "fonts/DejaVuSansMono.ttf"), al_get_display_height(game->display)*0.025,0 );
|
||||||
}
|
}
|
||||||
int width = (al_get_display_width(game->display) / game->viewport.width) * game->viewport.width;
|
|
||||||
if (!game->viewport.integer_scaling) {
|
|
||||||
width = (al_get_display_width(game->display) / (float)game->viewport.width) * game->viewport.width;
|
|
||||||
}
|
|
||||||
game->_priv.console = CreateNotPreservedBitmap(width, al_get_font_line_height(game->_priv.font_console)*5);
|
|
||||||
game->_priv.console_tmp = CreateNotPreservedBitmap(width, al_get_font_line_height(game->_priv.font_console)*5);
|
|
||||||
al_set_target_bitmap(game->_priv.console);
|
|
||||||
al_clear_to_color(al_map_rgba(0,0,0,80));
|
|
||||||
al_set_target_bitmap(al_get_backbuffer(game->display));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void Console_Unload(struct Game *game) {
|
SYMBOL_INTERNAL void Console_Unload(struct Game *game) {
|
||||||
al_destroy_font(game->_priv.font_console);
|
if (game->_priv.font_console) {
|
||||||
al_destroy_bitmap(game->_priv.console);
|
al_destroy_font(game->_priv.font_console);
|
||||||
al_destroy_bitmap(game->_priv.console_tmp);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL void* GamestateLoadingThread(void *arg) {
|
||||||
|
struct GamestateLoadingThreadData *data = arg;
|
||||||
|
data->game->_priv.loading.inProgress = true;
|
||||||
|
al_set_new_bitmap_flags(data->bitmap_flags);
|
||||||
|
GamestateProgress(data->game);
|
||||||
|
data->gamestate->data = (*data->gamestate->api->Gamestate_Load)(data->game, &GamestateProgress);
|
||||||
|
data->bitmap_flags = al_get_new_bitmap_flags();
|
||||||
|
data->game->_priv.loading.inProgress = false;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void GamestateProgress(struct Game *game) {
|
SYMBOL_INTERNAL void GamestateProgress(struct Game *game) {
|
||||||
struct Gamestate *tmp = game->_priv.tmp_gamestate.tmp;
|
struct Gamestate *tmp = game->_priv.loading.current;
|
||||||
game->_priv.tmp_gamestate.p++;
|
game->_priv.loading.progress++;
|
||||||
DrawGamestates(game);
|
|
||||||
float progressCount = *(tmp->api->Gamestate_ProgressCount) ? (float)*(tmp->api->Gamestate_ProgressCount) : 1;
|
float progressCount = *(tmp->api->Gamestate_ProgressCount) ? (float)*(tmp->api->Gamestate_ProgressCount) : 1;
|
||||||
float progress = ((game->_priv.tmp_gamestate.p / progressCount) / (float)game->_priv.tmp_gamestate.toLoad) + (game->_priv.tmp_gamestate.loaded/(float)game->_priv.tmp_gamestate.toLoad);
|
float progress = ((game->_priv.loading.progress / progressCount) / (float)game->_priv.loading.toLoad) + (game->_priv.loading.loaded/(float)game->_priv.loading.toLoad);
|
||||||
if (game->config.debug) PrintConsole(game, "[%s] Progress: %d% (%d/%d)", tmp->name, (int)(progress*100), game->_priv.tmp_gamestate.p, *(tmp->api->Gamestate_ProgressCount));
|
game->loading_progress = progress;
|
||||||
if (tmp->showLoading) (*game->_priv.loading.Draw)(game, game->_priv.loading.data, progress);
|
if (game->config.debug) PrintConsole(game, "[%s] Progress: %d% (%d/%d)", tmp->name, (int)(progress*100), game->_priv.loading.progress, *(tmp->api->Gamestate_ProgressCount));
|
||||||
|
#ifdef LIBSUPERDERPY_SINGLE_THREAD
|
||||||
|
DrawGamestates(game);
|
||||||
|
if (tmp->showLoading) (*game->_priv.loading.gamestate->api->Gamestate_Draw)(game, game->_priv.loading.gamestate->data);
|
||||||
DrawConsole(game);
|
DrawConsole(game);
|
||||||
if (al_get_time() - game->_priv.tmp_gamestate.t >= 1/60.0) {
|
al_flip_display();
|
||||||
al_flip_display();
|
#endif
|
||||||
game->_priv.tmp_gamestate.t = al_get_time();
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
gamestate->handle = dlopen(libname, RTLD_NOW);
|
||||||
|
if (!gamestate->handle) {
|
||||||
|
FatalError(game, false, "Error while opening gamestate \"%s\": %s", gamestate->name, dlerror()); // TODO: move out
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL bool LinkGamestate(struct Game *game, struct Gamestate *gamestate) {
|
||||||
|
gamestate->api = malloc(sizeof(struct Gamestate_API));
|
||||||
|
|
||||||
|
#define GS_ERROR FatalError(game, false, "Error on resolving gamestate's %s symbol: %s", gamestate->name, dlerror()); /* TODO: move out */ \
|
||||||
|
free(gamestate->api); \
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!(gamestate->api->Gamestate_Draw = dlsym(gamestate->handle, "Gamestate_Draw"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Logic = dlsym(gamestate->handle, "Gamestate_Logic"))) { GS_ERROR; }
|
||||||
|
|
||||||
|
if (!(gamestate->api->Gamestate_Load = dlsym(gamestate->handle, "Gamestate_Load"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Start = dlsym(gamestate->handle, "Gamestate_Start"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Pause = dlsym(gamestate->handle, "Gamestate_Pause"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Resume = dlsym(gamestate->handle, "Gamestate_Resume"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Stop = dlsym(gamestate->handle, "Gamestate_Stop"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Unload = dlsym(gamestate->handle, "Gamestate_Unload"))) { GS_ERROR; }
|
||||||
|
|
||||||
|
if (!(gamestate->api->Gamestate_ProcessEvent = dlsym(gamestate->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
|
||||||
|
if (!(gamestate->api->Gamestate_Reload = dlsym(gamestate->handle, "Gamestate_Reload"))) { GS_ERROR; }
|
||||||
|
|
||||||
|
if (!(gamestate->api->Gamestate_ProgressCount = dlsym(gamestate->handle, "Gamestate_ProgressCount"))) { GS_ERROR; }
|
||||||
|
|
||||||
|
#undef GS_ERROR
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL struct Gamestate* AllocateGamestate(struct Game *game, const char* name) {
|
||||||
|
struct Gamestate *tmp = malloc(sizeof(struct Gamestate));
|
||||||
|
tmp->name = strdup(name);
|
||||||
|
tmp->handle = NULL;
|
||||||
|
tmp->loaded = false;
|
||||||
|
tmp->paused = false;
|
||||||
|
tmp->frozen = false;
|
||||||
|
tmp->started = false;
|
||||||
|
tmp->pending_load = false;
|
||||||
|
tmp->pending_start = false;
|
||||||
|
tmp->pending_stop = false;
|
||||||
|
tmp->pending_unload = false;
|
||||||
|
tmp->next = NULL;
|
||||||
|
tmp->api = NULL;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SYMBOL_INTERNAL void CloseGamestate(struct Game *game, struct Gamestate *gamestate) {
|
||||||
|
if (gamestate->handle && !RUNNING_ON_VALGRIND) {
|
||||||
|
#ifndef LEAK_SANITIZER
|
||||||
|
PrintConsole(game, "Closing gamestate \"%s\"...", gamestate->name);
|
||||||
|
dlclose(gamestate->handle);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
free(gamestate->name);
|
||||||
|
if (gamestate->api) {
|
||||||
|
free(gamestate->api);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,7 +336,7 @@ SYMBOL_INTERNAL void ClearScreen(struct Game *game) {
|
||||||
al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight);
|
al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL 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) {
|
||||||
|
|
||||||
int pos = clipX;
|
int pos = clipX;
|
||||||
|
|
||||||
|
@ -270,7 +361,7 @@ SYMBOL_INTERNAL void DrawQueue(struct Game *game, struct TM_Action* queue, int c
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void DrawTimeline(struct Game *game, struct Timeline* timeline, int pos) {
|
static void DrawTimeline(struct Game *game, struct Timeline* timeline, int pos) {
|
||||||
al_set_target_backbuffer(game->display);
|
al_set_target_backbuffer(game->display);
|
||||||
ALLEGRO_TRANSFORM trans;
|
ALLEGRO_TRANSFORM trans;
|
||||||
al_identity_transform(&trans);
|
al_identity_transform(&trans);
|
||||||
|
@ -289,7 +380,7 @@ SYMBOL_INTERNAL void DrawTimeline(struct Game *game, struct Timeline* timeline,
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void DrawTimelines(struct Game *game) {
|
SYMBOL_INTERNAL void DrawTimelines(struct Game *game) {
|
||||||
if ((!game->_priv.showconsole) || (!game->_priv.showtimeline)) {
|
if (!game->_priv.showtimeline) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct libsuperderpy_list *tmp = game->_priv.timelines;
|
struct libsuperderpy_list *tmp = game->_priv.timelines;
|
||||||
|
|
|
@ -42,6 +42,12 @@ struct libsuperderpy_list {
|
||||||
struct libsuperderpy_list *next;
|
struct libsuperderpy_list *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GamestateLoadingThreadData {
|
||||||
|
struct Game *game;
|
||||||
|
struct Gamestate *gamestate;
|
||||||
|
int bitmap_flags;
|
||||||
|
};
|
||||||
|
|
||||||
void DrawGamestates(struct Game *game);
|
void DrawGamestates(struct Game *game);
|
||||||
void LogicGamestates(struct Game *game);
|
void LogicGamestates(struct Game *game);
|
||||||
void EventGamestates(struct Game *game, ALLEGRO_EVENT *ev);
|
void EventGamestates(struct Game *game, ALLEGRO_EVENT *ev);
|
||||||
|
@ -51,12 +57,19 @@ void UnfreezeGamestates(struct Game *game);
|
||||||
void DrawConsole(struct Game *game);
|
void DrawConsole(struct Game *game);
|
||||||
void Console_Load(struct Game *game);
|
void Console_Load(struct Game *game);
|
||||||
void Console_Unload(struct Game *game);
|
void Console_Unload(struct Game *game);
|
||||||
|
void* GamestateLoadingThread(void *arg);
|
||||||
void GamestateProgress(struct Game *game);
|
void GamestateProgress(struct Game *game);
|
||||||
void* AddGarbage(struct Game *game, void* data);
|
void* AddGarbage(struct Game *game, void* data);
|
||||||
void ClearGarbage(struct Game *game);
|
void ClearGarbage(struct Game *game);
|
||||||
void ClearScreen(struct Game *game);
|
void ClearScreen(struct Game *game);
|
||||||
|
struct libsuperderpy_list* AddToList(struct libsuperderpy_list *list, void* data);
|
||||||
|
struct libsuperderpy_list* RemoveFromList(struct libsuperderpy_list **list, bool (*identity)(struct libsuperderpy_list* elem, void* data), void* data);
|
||||||
void AddTimeline(struct Game *game, struct Timeline *timeline);
|
void AddTimeline(struct Game *game, struct Timeline *timeline);
|
||||||
void RemoveTimeline(struct Game *game, struct Timeline *timeline);
|
void RemoveTimeline(struct Game *game, struct Timeline *timeline);
|
||||||
void DrawTimelines(struct Game *game);
|
void DrawTimelines(struct Game *game);
|
||||||
|
bool OpenGamestate(struct Game *game, struct Gamestate *gamestate);
|
||||||
|
bool LinkGamestate(struct Game *game, struct Gamestate *gamestate);
|
||||||
|
void CloseGamestate(struct Game *game, struct Gamestate *gamestate);
|
||||||
|
struct Gamestate* AllocateGamestate(struct Game *game, const char* name);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -34,7 +34,6 @@
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "libsuperderpy.h"
|
#include "libsuperderpy.h"
|
||||||
#include "3rdparty/valgrind.h"
|
|
||||||
#ifdef ALLEGRO_MACOSX
|
#ifdef ALLEGRO_MACOSX
|
||||||
#include <mach-o/dyld.h>
|
#include <mach-o/dyld.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -67,15 +66,18 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
game->_priv.fps_count.fps = 0;
|
game->_priv.fps_count.fps = 0;
|
||||||
game->_priv.fps_count.old_time = 0;
|
game->_priv.fps_count.old_time = 0;
|
||||||
|
|
||||||
|
game->_priv.font_console = NULL;
|
||||||
game->_priv.font_bsod = NULL;
|
game->_priv.font_bsod = NULL;
|
||||||
game->_priv.console = NULL;
|
game->_priv.console_pos = 0;
|
||||||
game->_priv.console_tmp = NULL;
|
for (unsigned int i=0; i<(sizeof(game->_priv.console)/sizeof(game->_priv.console[0])); i++) {
|
||||||
|
game->_priv.console[i][0] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
game->_priv.garbage = NULL;
|
game->_priv.garbage = NULL;
|
||||||
game->_priv.timelines = NULL;
|
game->_priv.timelines = NULL;
|
||||||
|
|
||||||
game->eventHandler = NULL;
|
game->handlers.event = NULL;
|
||||||
game->destroyHandler = NULL;
|
game->handlers.destroy = NULL;
|
||||||
|
|
||||||
game->config.fullscreen = atoi(GetConfigOptionDefault(game, "SuperDerpy", "fullscreen", "1"));
|
game->config.fullscreen = atoi(GetConfigOptionDefault(game, "SuperDerpy", "fullscreen", "1"));
|
||||||
game->config.music = atoi(GetConfigOptionDefault(game, "SuperDerpy", "music", "10"));
|
game->config.music = atoi(GetConfigOptionDefault(game, "SuperDerpy", "music", "10"));
|
||||||
|
@ -143,7 +145,7 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
|
|
||||||
al_install_joystick();
|
al_install_joystick();
|
||||||
|
|
||||||
al_set_new_display_flags(ALLEGRO_PROGRAMMABLE_PIPELINE | (game->config.fullscreen ? ALLEGRO_FULLSCREEN_WINDOW : ALLEGRO_WINDOWED) | ALLEGRO_RESIZABLE | ALLEGRO_OPENGL ); // TODO: make ALLEGRO_PROGRAMMABLE_PIPELINE game-optional
|
al_set_new_display_flags(ALLEGRO_OPENGL_ES_PROFILE | ALLEGRO_PROGRAMMABLE_PIPELINE | (game->config.fullscreen ? ALLEGRO_FULLSCREEN_WINDOW : ALLEGRO_WINDOWED) | ALLEGRO_RESIZABLE | ALLEGRO_OPENGL);
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
al_set_new_display_flags((al_get_new_display_flags() | ALLEGRO_WINDOWED) ^ ALLEGRO_FULLSCREEN_WINDOW);
|
al_set_new_display_flags((al_get_new_display_flags() | ALLEGRO_WINDOWED) ^ ALLEGRO_FULLSCREEN_WINDOW);
|
||||||
#endif
|
#endif
|
||||||
|
@ -183,7 +185,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);
|
||||||
|
|
||||||
al_set_new_bitmap_flags(ALLEGRO_MIN_LINEAR);
|
al_add_new_bitmap_flag(ALLEGRO_MIN_LINEAR | ALLEGRO_MAG_LINEAR);
|
||||||
|
|
||||||
game->_priv.gamestates = NULL;
|
game->_priv.gamestates = NULL;
|
||||||
game->_priv.gamestate_scheduled = false;
|
game->_priv.gamestate_scheduled = false;
|
||||||
|
@ -197,9 +199,15 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
game->audio.v = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
ALLEGRO_AUDIO_DEPTH depth = ALLEGRO_AUDIO_DEPTH_FLOAT32;
|
||||||
|
#ifdef ALLEGRO_ANDROID
|
||||||
|
depth = ALLEGRO_AUDIO_DEPTH_INT16;
|
||||||
|
#endif
|
||||||
|
game->audio.v = al_create_voice(44100, depth, ALLEGRO_CHANNEL_CONF_2);
|
||||||
if (!game->audio.v) {
|
if (!game->audio.v) {
|
||||||
game->audio.v = al_create_voice(44100, ALLEGRO_AUDIO_DEPTH_INT16, ALLEGRO_CHANNEL_CONF_2);
|
// fallback
|
||||||
|
depth = (depth == ALLEGRO_AUDIO_DEPTH_FLOAT32) ? ALLEGRO_AUDIO_DEPTH_INT16 : ALLEGRO_AUDIO_DEPTH_FLOAT32;
|
||||||
|
game->audio.v = al_create_voice(44100, depth, ALLEGRO_CHANNEL_CONF_2);
|
||||||
}
|
}
|
||||||
game->audio.mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
game->audio.mixer = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
||||||
game->audio.fx = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
game->audio.fx = al_create_mixer(44100, ALLEGRO_AUDIO_DEPTH_FLOAT32, ALLEGRO_CHANNEL_CONF_2);
|
||||||
|
@ -220,11 +228,13 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
||||||
|
|
||||||
game->data = NULL;
|
game->data = NULL;
|
||||||
|
|
||||||
game->shuttingdown = false;
|
game->shutting_down = false;
|
||||||
game->restart = false;
|
game->restart = false;
|
||||||
|
|
||||||
game->show_loading_on_launch = false;
|
game->show_loading_on_launch = false;
|
||||||
|
|
||||||
|
game->loading_progress = 0;
|
||||||
|
|
||||||
return game;
|
return game;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,24 +269,13 @@ SYMBOL_EXPORT int libsuperderpy_run(struct Game *game) {
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
char libname[1024] = {};
|
game->_priv.loading.gamestate = AllocateGamestate(game, "loading");
|
||||||
snprintf(libname, 1024, "libsuperderpy-%s-loading" LIBRARY_EXTENSION, game->name);
|
if (!OpenGamestate(game, game->_priv.loading.gamestate) || !LinkGamestate(game, game->_priv.loading.gamestate)) {
|
||||||
void *handle = dlopen(libname, RTLD_NOW);
|
// TODO: support loading-less scenario
|
||||||
if (!handle) {
|
|
||||||
FatalError(game, true, "Error while initializing loading screen: %s", dlerror());
|
|
||||||
return 2;
|
return 2;
|
||||||
} else {
|
|
||||||
|
|
||||||
#define GS_LOADINGERROR FatalError(game, true, "Error on resolving loading symbol: %s", dlerror()); return 3;
|
|
||||||
|
|
||||||
if (!(game->_priv.loading.Draw = dlsym(handle, "Draw"))) { GS_LOADINGERROR; }
|
|
||||||
if (!(game->_priv.loading.Load = dlsym(handle, "Load"))) { GS_LOADINGERROR; }
|
|
||||||
if (!(game->_priv.loading.Start = dlsym(handle, "Start"))) { GS_LOADINGERROR; }
|
|
||||||
if (!(game->_priv.loading.Stop = dlsym(handle, "Stop"))) { GS_LOADINGERROR; }
|
|
||||||
if (!(game->_priv.loading.Unload = dlsym(handle, "Unload"))) { GS_LOADINGERROR; }
|
|
||||||
}
|
}
|
||||||
|
game->_priv.loading.gamestate->data = (*game->_priv.loading.gamestate->api->Gamestate_Load)(game, NULL);
|
||||||
game->_priv.loading.data = (*game->_priv.loading.Load)(game);
|
PrintConsole(game, "Loading screen registered.");
|
||||||
|
|
||||||
game->_priv.draw = true;
|
game->_priv.draw = true;
|
||||||
|
|
||||||
|
@ -311,10 +310,11 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
game->_priv.gamestate_scheduled = false;
|
game->_priv.gamestate_scheduled = false;
|
||||||
struct Gamestate *tmp = game->_priv.gamestates;
|
struct Gamestate *tmp = game->_priv.gamestates;
|
||||||
|
|
||||||
game->_priv.tmp_gamestate.toLoad = 0;
|
game->_priv.loading.toLoad = 0;
|
||||||
game->_priv.tmp_gamestate.loaded = 0;
|
game->_priv.loading.loaded = 0;
|
||||||
|
game->loading_progress = 0;
|
||||||
|
|
||||||
// TODO: support gamestate dependences
|
// TODO: support gamestate dependences/ordering
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
if (tmp->pending_stop) {
|
if (tmp->pending_stop) {
|
||||||
PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
|
PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
|
||||||
|
@ -324,14 +324,12 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
tmp->pending_stop = false;
|
tmp->pending_stop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp->pending_load) game->_priv.tmp_gamestate.toLoad++;
|
if (tmp->pending_load) game->_priv.loading.toLoad++;
|
||||||
tmp=tmp->next;
|
tmp=tmp->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = game->_priv.gamestates;
|
tmp = game->_priv.gamestates;
|
||||||
|
|
||||||
game->_priv.tmp_gamestate.t = -1;
|
|
||||||
|
|
||||||
while (tmp) {
|
while (tmp) {
|
||||||
if (tmp->pending_unload) {
|
if (tmp->pending_unload) {
|
||||||
PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
|
PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
|
||||||
|
@ -344,60 +342,48 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
}
|
}
|
||||||
if (tmp->pending_load) {
|
if (tmp->pending_load) {
|
||||||
al_stop_timer(game->_priv.timer);
|
al_stop_timer(game->_priv.timer);
|
||||||
|
if (tmp->showLoading) (*game->_priv.loading.gamestate->api->Gamestate_Start)(game, game->_priv.loading.gamestate->data);
|
||||||
|
|
||||||
if (!tmp->api) {
|
if (!tmp->api) {
|
||||||
PrintConsole(game, "Opening gamestate \"%s\"...", tmp->name);
|
if (!OpenGamestate(game, tmp) || !LinkGamestate(game, tmp)) {
|
||||||
char libname[1024];
|
|
||||||
snprintf(libname, 1024, "libsuperderpy-%s-%s" LIBRARY_EXTENSION, game->name, tmp->name);
|
|
||||||
tmp->handle = dlopen(libname,RTLD_NOW);
|
|
||||||
if (!tmp->handle) {
|
|
||||||
FatalError(game, false, "Error while opening gamestate \"%s\": %s", tmp->name, dlerror());
|
|
||||||
|
|
||||||
tmp->pending_load = false;
|
tmp->pending_load = false;
|
||||||
tmp->pending_start = false;
|
tmp->pending_start = false;
|
||||||
} else {
|
tmp->next = tmp;
|
||||||
|
continue;
|
||||||
tmp->api = malloc(sizeof(struct Gamestate_API));
|
|
||||||
|
|
||||||
#define GS_ERROR FatalError(game, false, "Error on resolving gamestate symbol: %s", dlerror()); tmp->pending_load = false; tmp->pending_start = false; tmp=tmp->next; continue;
|
|
||||||
|
|
||||||
if (!(tmp->api->Gamestate_Draw = dlsym(tmp->handle, "Gamestate_Draw"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Logic = dlsym(tmp->handle, "Gamestate_Logic"))) { GS_ERROR; }
|
|
||||||
|
|
||||||
if (!(tmp->api->Gamestate_Load = dlsym(tmp->handle, "Gamestate_Load"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Start = dlsym(tmp->handle, "Gamestate_Start"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Pause = dlsym(tmp->handle, "Gamestate_Pause"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Resume = dlsym(tmp->handle, "Gamestate_Resume"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Stop = dlsym(tmp->handle, "Gamestate_Stop"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Unload = dlsym(tmp->handle, "Gamestate_Unload"))) { GS_ERROR; }
|
|
||||||
|
|
||||||
if (!(tmp->api->Gamestate_ProcessEvent = dlsym(tmp->handle, "Gamestate_ProcessEvent"))) { GS_ERROR; }
|
|
||||||
if (!(tmp->api->Gamestate_Reload = dlsym(tmp->handle, "Gamestate_Reload"))) { GS_ERROR; }
|
|
||||||
|
|
||||||
if (!(tmp->api->Gamestate_ProgressCount = dlsym(tmp->handle, "Gamestate_ProgressCount"))) { GS_ERROR; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tmp->api) {
|
if (tmp->api) {
|
||||||
PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
|
PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
|
||||||
game->_priv.tmp_gamestate.p = 0;
|
game->_priv.loading.progress = -1;
|
||||||
|
|
||||||
DrawGamestates(game);
|
game->_priv.loading.current = tmp;
|
||||||
if (tmp->showLoading) {
|
|
||||||
(*game->_priv.loading.Draw)(game, game->_priv.loading.data, game->_priv.tmp_gamestate.loaded/(float)game->_priv.tmp_gamestate.toLoad);
|
|
||||||
}
|
|
||||||
DrawConsole(game);
|
|
||||||
if (al_get_time() - game->_priv.tmp_gamestate.t >= 1/60.0) {
|
|
||||||
al_flip_display();
|
|
||||||
game->_priv.tmp_gamestate.t = al_get_time();
|
|
||||||
}
|
|
||||||
game->_priv.tmp_gamestate.tmp = tmp;
|
|
||||||
game->_priv.current_gamestate = tmp;
|
game->_priv.current_gamestate = tmp;
|
||||||
tmp->data = (*tmp->api->Gamestate_Load)(game, &GamestateProgress);
|
|
||||||
game->_priv.tmp_gamestate.loaded++;
|
struct GamestateLoadingThreadData data = { .game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags() };
|
||||||
|
game->_priv.loading.inProgress = true;
|
||||||
|
|
||||||
|
#ifndef LIBSUPERDERPY_SINGLE_THREAD
|
||||||
|
al_run_detached_thread(GamestateLoadingThread, &data);
|
||||||
|
while (game->_priv.loading.inProgress) {
|
||||||
|
DrawGamestates(game);
|
||||||
|
if (tmp->showLoading) (*game->_priv.loading.gamestate->api->Gamestate_Draw)(game, game->_priv.loading.gamestate->data);
|
||||||
|
DrawConsole(game);
|
||||||
|
al_flip_display();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
GamestateLoadingThread(&data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
al_set_new_bitmap_flags(data.bitmap_flags);
|
||||||
|
// TODO: compile shaders
|
||||||
|
al_convert_memory_bitmaps();
|
||||||
|
game->_priv.loading.loaded++;
|
||||||
|
|
||||||
tmp->loaded = true;
|
tmp->loaded = true;
|
||||||
tmp->pending_load = false;
|
tmp->pending_load = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
if (tmp->showLoading) (*game->_priv.loading.gamestate->api->Gamestate_Stop)(game, game->_priv.loading.gamestate->data);
|
||||||
al_resume_timer(game->_priv.timer);
|
al_resume_timer(game->_priv.timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,6 +416,8 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
al_convert_memory_bitmaps();
|
||||||
|
|
||||||
DrawGamestates(game);
|
DrawGamestates(game);
|
||||||
DrawConsole(game);
|
DrawConsole(game);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
|
@ -445,8 +433,8 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
|
|
||||||
al_wait_for_event(game->_priv.event_queue, &ev);
|
al_wait_for_event(game->_priv.event_queue, &ev);
|
||||||
|
|
||||||
if (game->eventHandler) {
|
if (game->handlers.event) {
|
||||||
if ((*game->eventHandler)(game, &ev)) {
|
if ((*game->handlers.event)(game, &ev)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -467,13 +455,11 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
al_stop_timer(game->_priv.timer);
|
al_stop_timer(game->_priv.timer);
|
||||||
al_detach_voice(game->audio.v);
|
al_detach_voice(game->audio.v);
|
||||||
FreezeGamestates(game);
|
FreezeGamestates(game);
|
||||||
if (game->_priv.console) Console_Unload(game);
|
|
||||||
al_acknowledge_drawing_halt(game->display);
|
al_acknowledge_drawing_halt(game->display);
|
||||||
}
|
}
|
||||||
else if(ev.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) {
|
else if(ev.type == ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING) {
|
||||||
game->_priv.draw = true;
|
game->_priv.draw = true;
|
||||||
al_acknowledge_drawing_resume(game->display);
|
al_acknowledge_drawing_resume(game->display);
|
||||||
Console_Load(game);
|
|
||||||
PrintConsole(game, "Engine resumed.");
|
PrintConsole(game, "Engine resumed.");
|
||||||
ReloadGamestates(game);
|
ReloadGamestates(game);
|
||||||
UnfreezeGamestates(game);
|
UnfreezeGamestates(game);
|
||||||
|
@ -529,7 +515,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
if (game->destroyHandler) {
|
if (game->handlers.destroy) {
|
||||||
libsuperderpy_destroy(game);
|
libsuperderpy_destroy(game);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -537,7 +523,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void *g) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
game->shuttingdown = true;
|
game->shutting_down = true;
|
||||||
|
|
||||||
ClearGarbage(game);
|
ClearGarbage(game);
|
||||||
|
|
||||||
|
@ -555,41 +541,37 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
(*tmp->api->Gamestate_Unload)(game, tmp->data);
|
(*tmp->api->Gamestate_Unload)(game, tmp->data);
|
||||||
tmp->loaded = false;
|
tmp->loaded = false;
|
||||||
}
|
}
|
||||||
if (tmp->handle && !RUNNING_ON_VALGRIND) {
|
CloseGamestate(game, tmp);
|
||||||
#ifndef LEAK_SANITIZER
|
|
||||||
PrintConsole(game, "Closing gamestate \"%s\"...", tmp->name);
|
|
||||||
dlclose(tmp->handle);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
free(tmp->name);
|
|
||||||
if (tmp->api) {
|
|
||||||
free(tmp->api);
|
|
||||||
}
|
|
||||||
pom = tmp->next;
|
pom = tmp->next;
|
||||||
free(tmp);
|
free(tmp);
|
||||||
tmp=pom;
|
tmp=pom;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (game->destroyHandler) {
|
(*game->_priv.loading.gamestate->api->Gamestate_Unload)(game, game->_priv.loading.gamestate->data);
|
||||||
(*game->destroyHandler)(game);
|
CloseGamestate(game, game->_priv.loading.gamestate);
|
||||||
|
free(game->_priv.loading.gamestate);
|
||||||
|
|
||||||
|
if (game->handlers.destroy) {
|
||||||
|
(*game->handlers.destroy)(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearScreen(game);
|
ClearScreen(game);
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
{
|
{
|
||||||
ALLEGRO_BITMAP *bmp = al_create_bitmap(320, 180);
|
ALLEGRO_BITMAP *bmp = al_create_bitmap(320, 180);
|
||||||
al_set_target_bitmap(bmp);
|
al_set_target_bitmap(bmp);
|
||||||
al_clear_to_color(al_map_rgb(0,0,0));
|
al_clear_to_color(al_map_rgb(0,0,0));
|
||||||
ALLEGRO_FONT *font = al_create_builtin_font();
|
ALLEGRO_FONT *font = al_create_builtin_font();
|
||||||
al_draw_text(font, al_map_rgb(228,127,59), 320/2, 180/2 - 8 - 6, ALLEGRO_ALIGN_CENTER, "It's now safe to turn off");
|
al_draw_text(font, al_map_rgb(228,127,59), 320/2, 180/2 - 8 - 6, ALLEGRO_ALIGN_CENTER, "It's now safe to turn off");
|
||||||
al_draw_text(font, al_map_rgb(228,127,59), 320/2, 180/2 - 8 + 6, ALLEGRO_ALIGN_CENTER, "your browser.");
|
al_draw_text(font, al_map_rgb(228,127,59), 320/2, 180/2 - 8 + 6, ALLEGRO_ALIGN_CENTER, "your browser.");
|
||||||
al_set_target_backbuffer(game->display);
|
al_set_target_backbuffer(game->display);
|
||||||
al_draw_scaled_bitmap(bmp, 0, 0, 320, 180, 0, -game->viewport.height*0.2, game->viewport.width, game->viewport.height*1.4, 0);
|
al_draw_scaled_bitmap(bmp, 0, 0, 320, 180, 0, -game->viewport.height*0.2, game->viewport.width, game->viewport.height*1.4, 0);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
al_destroy_bitmap(bmp);
|
al_destroy_bitmap(bmp);
|
||||||
al_destroy_font(font);
|
al_destroy_font(font);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PrintConsole(game, "Shutting down...");
|
PrintConsole(game, "Shutting down...");
|
||||||
DrawConsole(game);
|
DrawConsole(game);
|
||||||
al_flip_display();
|
al_flip_display();
|
||||||
|
@ -597,7 +579,6 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game *game) {
|
||||||
free(game->_priv.garbage->data);
|
free(game->_priv.garbage->data);
|
||||||
game->_priv.garbage = game->_priv.garbage->next;
|
game->_priv.garbage = game->_priv.garbage->next;
|
||||||
}
|
}
|
||||||
(*game->_priv.loading.Unload)(game, game->_priv.loading.data);
|
|
||||||
al_destroy_timer(game->_priv.timer);
|
al_destroy_timer(game->_priv.timer);
|
||||||
Console_Unload(game);
|
Console_Unload(game);
|
||||||
al_destroy_display(game->display);
|
al_destroy_display(game->display);
|
||||||
|
|
|
@ -87,8 +87,8 @@ struct Game {
|
||||||
bool gamestate_scheduled; /*!< Whether there's some gamestate lifecycle management work to do. */
|
bool gamestate_scheduled; /*!< Whether there's some gamestate lifecycle management work to do. */
|
||||||
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. */
|
||||||
ALLEGRO_BITMAP *console; /*!< Bitmap with game console. */
|
char console[5][1024];
|
||||||
ALLEGRO_BITMAP *console_tmp; /*!< Bitmap used for drawing game console. */
|
unsigned int console_pos;
|
||||||
ALLEGRO_EVENT_QUEUE *event_queue; /*!< Main event queue. */
|
ALLEGRO_EVENT_QUEUE *event_queue; /*!< Main event queue. */
|
||||||
ALLEGRO_TIMER *timer; /*!< Main LPS (logic) timer. */
|
ALLEGRO_TIMER *timer; /*!< Main LPS (logic) timer. */
|
||||||
bool showconsole; /*!< If true, game console is rendered on screen. */
|
bool showconsole; /*!< If true, game console is rendered on screen. */
|
||||||
|
@ -101,25 +101,16 @@ struct Game {
|
||||||
|
|
||||||
ALLEGRO_CONFIG *config; /*!< Configuration file interface. */
|
ALLEGRO_CONFIG *config; /*!< Configuration file interface. */
|
||||||
|
|
||||||
struct {
|
|
||||||
void (*Draw)(struct Game *game, void* data, float p);
|
|
||||||
void* (*Load)(struct Game *game);
|
|
||||||
void (*Start)(struct Game *game, void* data);
|
|
||||||
void (*Stop)(struct Game *game, void* data);
|
|
||||||
void (*Unload)(struct Game *game, void* data);
|
|
||||||
|
|
||||||
void* data;
|
|
||||||
} loading; /*!< Interface for accessing loading screen functions. */
|
|
||||||
|
|
||||||
int argc;
|
int argc;
|
||||||
char** argv;
|
char** argv;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int p;
|
struct Gamestate *gamestate;
|
||||||
struct Gamestate *tmp;
|
struct Gamestate *current;
|
||||||
double t;
|
int progress;
|
||||||
int loaded, toLoad;
|
int loaded, toLoad;
|
||||||
} tmp_gamestate;
|
bool inProgress;
|
||||||
|
} loading;
|
||||||
|
|
||||||
struct Gamestate *current_gamestate;
|
struct Gamestate *current_gamestate;
|
||||||
|
|
||||||
|
@ -133,7 +124,7 @@ struct Game {
|
||||||
|
|
||||||
} _priv; /*!< Private resources. Do not use in gamestates! */
|
} _priv; /*!< Private resources. Do not use in gamestates! */
|
||||||
|
|
||||||
bool shuttingdown; /*!< If true then shut down of the game is pending. */
|
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 restart; /*!< If true then restart of the game is pending. */
|
||||||
bool touch;
|
bool touch;
|
||||||
|
|
||||||
|
@ -143,8 +134,12 @@ struct Game {
|
||||||
|
|
||||||
ALLEGRO_EVENT_SOURCE event_source;
|
ALLEGRO_EVENT_SOURCE event_source;
|
||||||
|
|
||||||
bool (*eventHandler)(struct Game *game, ALLEGRO_EVENT *ev);
|
float loading_progress;
|
||||||
void (*destroyHandler)(struct Game *game);
|
|
||||||
|
struct {
|
||||||
|
bool (*event)(struct Game *game, ALLEGRO_EVENT *ev);
|
||||||
|
void (*destroy)(struct Game *game);
|
||||||
|
} handlers;
|
||||||
|
|
||||||
LIBSUPERDERPY_DATA_TYPE *data;
|
LIBSUPERDERPY_DATA_TYPE *data;
|
||||||
|
|
||||||
|
@ -154,4 +149,17 @@ struct Game* libsuperderpy_init(int argc, char **argv, const char* name, struct
|
||||||
int libsuperderpy_run(struct Game* game);
|
int libsuperderpy_run(struct Game* game);
|
||||||
void libsuperderpy_destroy(struct Game* game);
|
void libsuperderpy_destroy(struct Game* game);
|
||||||
|
|
||||||
|
struct GamestateResources;
|
||||||
|
extern int Gamestate_ProgressCount;
|
||||||
|
void Gamestate_ProcessEvent(struct Game *game, struct GamestateResources *data, ALLEGRO_EVENT *ev);
|
||||||
|
void Gamestate_Logic(struct Game *game, struct GamestateResources *data);
|
||||||
|
void Gamestate_Draw(struct Game *game, struct GamestateResources *data);
|
||||||
|
void* Gamestate_Load(struct Game *game, void (*progress)(struct Game*));
|
||||||
|
void Gamestate_Unload(struct Game *game, struct GamestateResources *data);
|
||||||
|
void Gamestate_Start(struct Game *game, struct GamestateResources *data);
|
||||||
|
void Gamestate_Stop(struct Game *game, struct GamestateResources *data);
|
||||||
|
void Gamestate_Reload(struct Game *game, struct GamestateResources* data);
|
||||||
|
void Gamestate_Pause(struct Game *game, struct GamestateResources* data);
|
||||||
|
void Gamestate_Resume(struct Game *game, struct GamestateResources* data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -128,7 +128,7 @@ SYMBOL_EXPORT void TM_Process(struct Timeline* timeline) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void PauseTimers(struct Timeline* timeline, bool pause) {
|
static void PauseTimers(struct Timeline* timeline, bool pause) {
|
||||||
if (timeline->queue) {
|
if (timeline->queue) {
|
||||||
if (timeline->queue->timer) {
|
if (timeline->queue->timer) {
|
||||||
if (pause) {
|
if (pause) {
|
||||||
|
@ -147,7 +147,7 @@ SYMBOL_INTERNAL void PauseTimers(struct Timeline* timeline, bool pause) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT void TM_Propagate(struct Timeline* timeline, enum TM_ActionState action) {
|
static void TM_Propagate(struct Timeline* timeline, enum TM_ActionState action) {
|
||||||
if (timeline->queue) {
|
if (timeline->queue) {
|
||||||
if ((*timeline->queue->function) && (timeline->queue->active)) {
|
if ((*timeline->queue->function) && (timeline->queue->active)) {
|
||||||
(*timeline->queue->function)(timeline->game, timeline->queue, action);
|
(*timeline->queue->function)(timeline->game, timeline->queue, action);
|
||||||
|
@ -273,7 +273,7 @@ SYMBOL_EXPORT struct TM_Action* TM_AddBackgroundAction(struct Timeline* timeline
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Predefined action used by TM_AddQueuedBackgroundAction */
|
/*! \brief Predefined action used by TM_AddQueuedBackgroundAction */
|
||||||
SYMBOL_INTERNAL bool runinbackground(struct Game* game, struct TM_Action* action, enum TM_ActionState state) {
|
static bool runinbackground(struct Game* game, struct TM_Action* action, enum TM_ActionState state) {
|
||||||
int* delay = (int*) TM_GetArg(action->arguments, 1);
|
int* delay = (int*) TM_GetArg(action->arguments, 1);
|
||||||
char* name = (char*) TM_GetArg(action->arguments, 2);
|
char* name = (char*) TM_GetArg(action->arguments, 2);
|
||||||
struct Timeline *timeline = (struct Timeline*) TM_GetArg(action->arguments, 3);
|
struct Timeline *timeline = (struct Timeline*) TM_GetArg(action->arguments, 3);
|
||||||
|
|
63
src/utils.c
63
src/utils.c
|
@ -187,20 +187,12 @@ SYMBOL_EXPORT ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename
|
||||||
|
|
||||||
SYMBOL_EXPORT void FatalError(struct Game *game, bool fatal, char* format, ...) {
|
SYMBOL_EXPORT void FatalError(struct Game *game, bool fatal, char* format, ...) {
|
||||||
char text[1024] = {};
|
char text[1024] = {};
|
||||||
if (!game->_priv.console) {
|
PrintConsole(game, "Fatal Error, displaying Blue Screen of Derp...");
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
vsnprintf(text, 1024, format, vl);
|
vsnprintf(text, 1024, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
printf("%s\n", text);
|
PrintConsole(game, text);
|
||||||
} else {
|
|
||||||
PrintConsole(game, "Fatal Error, displaying Blue Screen of Derp...");
|
|
||||||
va_list vl;
|
|
||||||
va_start(vl, format);
|
|
||||||
vsnprintf(text, 1024, format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
PrintConsole(game, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
ALLEGRO_TRANSFORM trans;
|
ALLEGRO_TRANSFORM trans;
|
||||||
al_identity_transform(&trans);
|
al_identity_transform(&trans);
|
||||||
|
@ -270,7 +262,7 @@ SYMBOL_EXPORT void FatalError(struct Game *game, bool fatal, char* format, ...)
|
||||||
al_use_transform(&game->projection);
|
al_use_transform(&game->projection);
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_INTERNAL void TestPath(char* filename, char* subpath, char** result) {
|
static void TestPath(char* filename, char* subpath, char** result) {
|
||||||
if (*result) return; //already found
|
if (*result) return; //already found
|
||||||
ALLEGRO_PATH *tail = al_create_path(filename);
|
ALLEGRO_PATH *tail = al_create_path(filename);
|
||||||
ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
|
ALLEGRO_PATH *path = al_get_standard_path(ALLEGRO_RESOURCES_PATH);
|
||||||
|
@ -293,7 +285,7 @@ SYMBOL_EXPORT char* GetGameName(struct Game *game, char* format) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
SYMBOL_INTERNAL char* TestDataFilePath(struct Game *game, char* filename) {
|
static char* TestDataFilePath(struct Game *game, char* filename) {
|
||||||
char *result = NULL;
|
char *result = NULL;
|
||||||
|
|
||||||
if (al_filename_exists(filename)) {
|
if (al_filename_exists(filename)) {
|
||||||
|
@ -339,11 +331,11 @@ SYMBOL_EXPORT char* GetDataFilePath(struct Game *game, char* filename) {
|
||||||
char* file = AddGarbage(game, strdup(filename));
|
char* file = AddGarbage(game, strdup(filename));
|
||||||
char* sub = strstr(file, ".flac");
|
char* sub = strstr(file, ".flac");
|
||||||
if (sub) {
|
if (sub) {
|
||||||
sub[0] = '.';
|
sub[0] = '.';
|
||||||
sub[1] = 'o';
|
sub[1] = 'o';
|
||||||
sub[2] = 'g';
|
sub[2] = 'g';
|
||||||
sub[3] = 'g';
|
sub[3] = 'g';
|
||||||
sub[4] = 0;
|
sub[4] = 0;
|
||||||
}
|
}
|
||||||
result = TestDataFilePath(game, file);
|
result = TestDataFilePath(game, file);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -368,8 +360,8 @@ ALLEGRO_DEBUG_CHANNEL("libsuperderpy")
|
||||||
SYMBOL_EXPORT void PrintConsole(struct Game *game, char* format, ...) {
|
SYMBOL_EXPORT void PrintConsole(struct Game *game, char* format, ...) {
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
char text[1024] = {};
|
char* text = game->_priv.console[game->_priv.console_pos];
|
||||||
vsnprintf(text, 1024, format, vl);
|
vsnprintf(text, (sizeof(game->_priv.console[0])/sizeof(game->_priv.console[0][0])), format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
ALLEGRO_DEBUG("%s", text);
|
ALLEGRO_DEBUG("%s", text);
|
||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
|
@ -379,18 +371,11 @@ SYMBOL_EXPORT void PrintConsole(struct Game *game, char* format, ...) {
|
||||||
printf("%s\n", text);
|
printf("%s\n", text);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
if (!game->_priv.draw) return;
|
game->_priv.console_pos++;
|
||||||
if (!game->_priv.console) return;
|
if (game->_priv.console_pos >= (sizeof(game->_priv.console)/sizeof(game->_priv.console[0]))) {
|
||||||
if ((!game->config.debug) && (!game->_priv.showconsole)) return;
|
game->_priv.console_pos = 0;
|
||||||
ALLEGRO_BITMAP *target = al_get_target_bitmap();
|
}
|
||||||
al_set_target_bitmap(game->_priv.console_tmp);
|
return;
|
||||||
al_clear_to_color(al_map_rgba(0,0,0,80));
|
|
||||||
al_draw_bitmap_region(game->_priv.console, 0, (int)(al_get_bitmap_height(game->_priv.console)*0.2), al_get_bitmap_width(game->_priv.console), (int)(al_get_bitmap_height(game->_priv.console)*0.8), 0, 0, 0);
|
|
||||||
al_draw_text(game->_priv.font_console, al_map_rgb(255,255,255), (int)(game->viewport.width*0.005), (int)(al_get_bitmap_height(game->_priv.console)*0.81), ALLEGRO_ALIGN_LEFT, text);
|
|
||||||
al_set_target_bitmap(game->_priv.console);
|
|
||||||
al_clear_to_color(al_map_rgba(0,0,0,0));
|
|
||||||
al_draw_bitmap(game->_priv.console_tmp, 0, 0, 0);
|
|
||||||
al_set_target_bitmap(target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SYMBOL_EXPORT void SetupViewport(struct Game *game, struct Viewport config) {
|
SYMBOL_EXPORT void SetupViewport(struct Game *game, struct Viewport config) {
|
||||||
|
@ -418,6 +403,9 @@ SYMBOL_EXPORT void SetupViewport(struct Game *game, struct Viewport config) {
|
||||||
}
|
}
|
||||||
if (game->viewport.integer_scaling) {
|
if (game->viewport.integer_scaling) {
|
||||||
resolution = floor(resolution);
|
resolution = floor(resolution);
|
||||||
|
if (floor(resolution) == 0) {
|
||||||
|
resolution = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if ((!atoi(GetConfigOptionDefault(game, "SuperDerpy", "downscale", "1"))) && (resolution < 1)) {
|
if ((!atoi(GetConfigOptionDefault(game, "SuperDerpy", "downscale", "1"))) && (resolution < 1)) {
|
||||||
resolution = 1;
|
resolution = 1;
|
||||||
|
@ -425,9 +413,6 @@ SYMBOL_EXPORT void SetupViewport(struct Game *game, struct Viewport config) {
|
||||||
if (!atoi(GetConfigOptionDefault(game, "SuperDerpy", "scaling", "1"))) {
|
if (!atoi(GetConfigOptionDefault(game, "SuperDerpy", "scaling", "1"))) {
|
||||||
resolution = 1;
|
resolution = 1;
|
||||||
}
|
}
|
||||||
if (resolution == 0) {
|
|
||||||
resolution = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int clipWidth = game->viewport.width * resolution;
|
int clipWidth = game->viewport.width * resolution;
|
||||||
int clipHeight = game->viewport.height * resolution;
|
int clipHeight = game->viewport.height * resolution;
|
||||||
|
@ -440,7 +425,7 @@ SYMBOL_EXPORT void SetupViewport(struct Game *game, struct Viewport config) {
|
||||||
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->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->projection);
|
||||||
if (game->_priv.console) Console_Unload(game);
|
Console_Unload(game);
|
||||||
Console_Load(game);
|
Console_Load(game);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ void DrawTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float
|
||||||
int DrawWrappedText(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int width, int flags, char const *text);
|
int DrawWrappedText(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int width, int flags, char const *text);
|
||||||
int DrawWrappedTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int width, int flags, char const *text);
|
int DrawWrappedTextWithShadow(ALLEGRO_FONT *font, ALLEGRO_COLOR color, float x, float y, int width, int flags, char const *text);
|
||||||
|
|
||||||
|
ALLEGRO_COLOR InterpolateColor(ALLEGRO_COLOR c1, ALLEGRO_COLOR c2, float frac);
|
||||||
|
void ScaleBitmap(ALLEGRO_BITMAP* source, int width, int height);
|
||||||
|
|
||||||
/*! \brief Loads bitmap into memory and scales it with software linear filtering. */
|
/*! \brief Loads bitmap into memory and scales it with software linear filtering. */
|
||||||
ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, int height);
|
ALLEGRO_BITMAP* LoadScaledBitmap(struct Game *game, char* filename, int width, int height);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue