mirror of
https://gitlab.com/dosowisko.net/libsuperderpy.git
synced 2025-03-04 09:11:27 +01:00
rumina hacks
This commit is contained in:
parent
686dab729a
commit
ae70770f77
9 changed files with 134 additions and 17 deletions
|
@ -115,6 +115,7 @@ SYMBOL_EXPORT void RegisterSpritesheet(struct Game* game, struct Character* char
|
|||
s->rows = strtol(al_get_config_value(config, "", "rows"), NULL, 10);
|
||||
s->blanks = strtol(al_get_config_value(config, "", "blanks"), NULL, 10);
|
||||
s->delay = strtod(al_get_config_value(config, "", "delay"), NULL);
|
||||
s->flip = false;
|
||||
const char* val = al_get_config_value(config, "", "repeat");
|
||||
if (val) {
|
||||
s->repeat = strtod(val, NULL);
|
||||
|
@ -258,6 +259,9 @@ SYMBOL_EXPORT void DrawScaledCharacter(struct Game* game, struct Character* char
|
|||
}
|
||||
|
||||
SYMBOL_EXPORT void DrawCharacter(struct Game* game, struct Character* character, ALLEGRO_COLOR tint, int flags) {
|
||||
if (character->spritesheet->flip) {
|
||||
flags = flags | ALLEGRO_FLIP_HORIZONTAL | ALLEGRO_FLIP_VERTICAL;
|
||||
}
|
||||
DrawScaledCharacter(game, character, tint, 1, 1, flags);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ struct Spritesheet {
|
|||
int delay;
|
||||
bool kill;
|
||||
int repeat;
|
||||
bool flip;
|
||||
float scale; /*!< Scale modifier of the frame. */
|
||||
char* successor; /*!< Name of animation successor. If it's not blank, then animation will be played only once. */
|
||||
struct Spritesheet* next; /*!< Next spritesheet in the queue. */
|
||||
|
|
|
@ -49,8 +49,9 @@ struct Gamestate {
|
|||
bool showLoading;
|
||||
bool paused;
|
||||
struct Gamestate* next;
|
||||
void* data;
|
||||
struct Gamestate_API* api;
|
||||
ALLEGRO_BITMAP* fb;
|
||||
void* data;
|
||||
};
|
||||
|
||||
void LoadGamestate(struct Game* game, const char* name);
|
||||
|
|
|
@ -22,11 +22,24 @@
|
|||
#include "libsuperderpy.h"
|
||||
#include <allegro5/allegro_ttf.h>
|
||||
#include <dlfcn.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
SYMBOL_INTERNAL void SimpleCompositor(struct Game* game, struct Gamestate* gamestates) {
|
||||
struct Gamestate* tmp = gamestates;
|
||||
al_clear_to_color(al_map_rgb(0, 0, 0));
|
||||
while (tmp) {
|
||||
if ((tmp->loaded) && (tmp->started)) {
|
||||
al_draw_bitmap(tmp->fb, 0, 0, 0);
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
|
||||
if (!game->handlers.compositor) {
|
||||
ClearScreen(game);
|
||||
al_set_target_backbuffer(game->display);
|
||||
}
|
||||
struct Gamestate* tmp = game->_priv.gamestates;
|
||||
if (game->handlers.predraw) {
|
||||
(*game->handlers.predraw)(game);
|
||||
|
@ -34,10 +47,29 @@ SYMBOL_INTERNAL void DrawGamestates(struct Game* game) {
|
|||
while (tmp) {
|
||||
if ((tmp->loaded) && (tmp->started)) {
|
||||
game->_priv.current_gamestate = tmp;
|
||||
SetFramebufferAsTarget(game);
|
||||
if (game->handlers.compositor) { // don't clear when uncomposited
|
||||
al_clear_to_color(al_map_rgb(0, 0, 0)); // even if everything is going to be redrawn, it optimizes tiled rendering
|
||||
}
|
||||
(*tmp->api->Gamestate_Draw)(game, tmp->data);
|
||||
// TODO: save and restore more state for careless gamestating
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
|
||||
if (game->handlers.compositor) {
|
||||
ALLEGRO_TRANSFORM t;
|
||||
al_set_target_backbuffer(game->display);
|
||||
ClearScreen(game);
|
||||
al_identity_transform(&t);
|
||||
/* double factor = (sin(al_get_time()) / 2.0 + 1.0) * 2;
|
||||
al_translate_transform(&t, -game->_priv.clip_rect.w / factor, -game->_priv.clip_rect.h / factor);
|
||||
al_scale_transform(&t, factor, factor);
|
||||
al_translate_transform(&t, game->_priv.clip_rect.w / factor, game->_priv.clip_rect.h / factor);*/
|
||||
al_translate_transform(&t, game->_priv.clip_rect.x, game->_priv.clip_rect.y);
|
||||
al_use_transform(&t);
|
||||
game->handlers.compositor(game, game->_priv.gamestates);
|
||||
}
|
||||
if (game->handlers.postdraw) {
|
||||
(*game->handlers.postdraw)(game);
|
||||
}
|
||||
|
@ -104,6 +136,19 @@ SYMBOL_INTERNAL void UnfreezeGamestates(struct Game* game) {
|
|||
}
|
||||
}
|
||||
|
||||
SYMBOL_INTERNAL void ResizeGamestates(struct Game* game) {
|
||||
struct Gamestate* tmp = game->_priv.gamestates;
|
||||
while (tmp) {
|
||||
al_destroy_bitmap(tmp->fb);
|
||||
if (game->handlers.compositor) {
|
||||
tmp->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h);
|
||||
} 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 = tmp->next;
|
||||
}
|
||||
}
|
||||
|
||||
SYMBOL_INTERNAL void DrawConsole(struct Game* game) {
|
||||
if (game->_priv.showconsole) {
|
||||
al_set_target_backbuffer(game->display);
|
||||
|
@ -264,6 +309,11 @@ SYMBOL_INTERNAL struct Gamestate* AllocateGamestate(struct Game* game, const cha
|
|||
tmp->pending_unload = false;
|
||||
tmp->next = NULL;
|
||||
tmp->api = NULL;
|
||||
if (game->handlers.compositor) {
|
||||
tmp->fb = CreateNotPreservedBitmap(game->_priv.clip_rect.w, game->_priv.clip_rect.h);
|
||||
} else {
|
||||
tmp->fb = al_create_sub_bitmap(al_get_backbuffer(game->display), game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
@ -278,6 +328,7 @@ SYMBOL_INTERNAL void CloseGamestate(struct Game* game, struct Gamestate* gamesta
|
|||
if (gamestate->api) {
|
||||
free(gamestate->api);
|
||||
}
|
||||
al_destroy_bitmap(gamestate->fb);
|
||||
}
|
||||
|
||||
SYMBOL_INTERNAL struct libsuperderpy_list* AddToList(struct libsuperderpy_list* list, void* data) {
|
||||
|
@ -356,16 +407,10 @@ SYMBOL_INTERNAL void RemoveTimeline(struct Game* game, struct Timeline* timeline
|
|||
}
|
||||
|
||||
SYMBOL_INTERNAL void ClearScreen(struct Game* game) {
|
||||
ALLEGRO_TRANSFORM identity;
|
||||
int clipX, clipY, clipWidth, clipHeight;
|
||||
al_set_target_backbuffer(game->display);
|
||||
al_get_clipping_rectangle(&clipX, &clipY, &clipWidth, &clipHeight);
|
||||
al_set_clipping_rectangle(0, 0, al_get_display_width(game->display), al_get_display_height(game->display));
|
||||
al_identity_transform(&identity);
|
||||
al_use_transform(&identity);
|
||||
al_clear_to_color(al_map_rgb(0, 0, 0));
|
||||
al_use_transform(&game->projection);
|
||||
al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight);
|
||||
al_set_clipping_rectangle(game->_priv.clip_rect.x, game->_priv.clip_rect.y, game->_priv.clip_rect.w, game->_priv.clip_rect.h);
|
||||
}
|
||||
|
||||
static void DrawQueue(struct Game* game, struct TM_Action* queue, int clipX, int clipY) {
|
||||
|
|
|
@ -62,12 +62,14 @@ struct ScreenshotThreadData {
|
|||
ALLEGRO_BITMAP* bitmap;
|
||||
};
|
||||
|
||||
void SimpleCompositor(struct Game* game, struct Gamestate* gamestates);
|
||||
void DrawGamestates(struct Game* game);
|
||||
void LogicGamestates(struct Game* game, double delta);
|
||||
void EventGamestates(struct Game* game, ALLEGRO_EVENT* ev);
|
||||
void ReloadGamestates(struct Game* game);
|
||||
void FreezeGamestates(struct Game* game);
|
||||
void UnfreezeGamestates(struct Game* game);
|
||||
void ResizeGamestates(struct Game* game);
|
||||
void DrawConsole(struct Game* game);
|
||||
void Console_Load(struct Game* game);
|
||||
void Console_Unload(struct Game* game);
|
||||
|
|
|
@ -76,6 +76,7 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
|||
|
||||
game->handlers.event = NULL;
|
||||
game->handlers.destroy = NULL;
|
||||
game->handlers.compositor = NULL;
|
||||
game->handlers.prelogic = NULL;
|
||||
game->handlers.postlogic = NULL;
|
||||
game->handlers.predraw = NULL;
|
||||
|
@ -159,6 +160,8 @@ SYMBOL_EXPORT struct Game* libsuperderpy_init(int argc, char** argv, const char*
|
|||
al_set_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, ALLEGRO_DISPLAY_ORIENTATION_PORTRAIT, ALLEGRO_SUGGEST);
|
||||
#endif
|
||||
|
||||
al_set_new_display_option(ALLEGRO_DEPTH_SIZE, 24, ALLEGRO_SUGGEST);
|
||||
|
||||
#ifdef ALLEGRO_WINDOWS
|
||||
al_set_new_window_position(20, 40); // workaround nasty Windows bug with window being created off-screen
|
||||
#endif
|
||||
|
@ -321,6 +324,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop_exit(struct Game* game) {
|
|||
|
||||
SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
||||
struct Game* game = (struct Game*)g;
|
||||
redraw = true;
|
||||
while (!al_is_event_queue_empty(game->_priv.event_queue) || redraw) {
|
||||
#else
|
||||
bool redraw = false;
|
||||
|
@ -330,7 +334,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
|||
|
||||
// TODO: split mainloop to functions to make it readable
|
||||
ALLEGRO_EVENT ev;
|
||||
if (game->_priv.draw && ((redraw && al_is_event_queue_empty(game->_priv.event_queue)) || (game->_priv.gamestate_scheduled))) {
|
||||
if (game->_priv.draw && (((redraw || true) && al_is_event_queue_empty(game->_priv.event_queue)) || (game->_priv.gamestate_scheduled))) {
|
||||
game->_priv.gamestate_scheduled = false;
|
||||
struct Gamestate* tmp = game->_priv.gamestates;
|
||||
|
||||
|
@ -392,6 +396,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
|||
al_run_detached_thread(GamestateLoadingThread, &data);
|
||||
while (game->_priv.loading.inProgress) {
|
||||
DrawGamestates(game);
|
||||
al_set_target_backbuffer(game->display);
|
||||
if (tmp->showLoading) {
|
||||
(*game->_priv.loading.gamestate->api->Gamestate_Draw)(game, game->_priv.loading.gamestate->data);
|
||||
}
|
||||
|
@ -450,8 +455,15 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
|||
|
||||
al_convert_memory_bitmaps();
|
||||
|
||||
double delta = al_get_time() - game->_priv.timestamp;
|
||||
game->_priv.timestamp += delta;
|
||||
delta /= ALLEGRO_BPS_TO_SECS(al_get_timer_speed(game->_priv.timer) / (1 / 60.f));
|
||||
LogicGamestates(game, delta);
|
||||
redraw = true;
|
||||
|
||||
DrawGamestates(game);
|
||||
DrawConsole(game);
|
||||
//al_wait_for_vsync();
|
||||
al_flip_display();
|
||||
redraw = false;
|
||||
|
||||
|
@ -471,10 +483,10 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
|||
}
|
||||
|
||||
if ((ev.type == ALLEGRO_EVENT_TIMER) && (ev.timer.source == game->_priv.timer)) {
|
||||
double delta = al_get_time() - game->_priv.timestamp;
|
||||
/*double delta = al_get_time() - game->_priv.timestamp;
|
||||
game->_priv.timestamp += delta;
|
||||
LogicGamestates(game, delta);
|
||||
redraw = true;
|
||||
redraw = true;*/
|
||||
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
|
||||
#ifdef __EMSCRIPTEN__
|
||||
libsuperderpy_mainloop_exit(game);
|
||||
|
@ -498,6 +510,7 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
|
|||
} else if (ev.type == ALLEGRO_EVENT_DISPLAY_RESIZE) {
|
||||
al_acknowledge_resize(game->display);
|
||||
SetupViewport(game, game->viewport_config);
|
||||
ResizeGamestates(game);
|
||||
}
|
||||
#ifdef ALLEGRO_ANDROID
|
||||
else if ((ev.type == ALLEGRO_EVENT_KEY_CHAR) && ((ev.keyboard.keycode == ALLEGRO_KEY_MENU) || (ev.keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev.keyboard.keycode == ALLEGRO_KEY_BACKQUOTE))) {
|
||||
|
|
|
@ -53,10 +53,11 @@ struct Game;
|
|||
struct Gamestate;
|
||||
|
||||
struct Viewport {
|
||||
int width; /*!< Actual available width of the drawing canvas. */
|
||||
int height; /*!< Actual available height of the drawing canvas. */
|
||||
float aspect;
|
||||
bool integer_scaling;
|
||||
int width; /*!< Width of the drawing canvas. */
|
||||
int height; /*!< Height of the drawing canvas. */
|
||||
float aspect; /*!< When set instead of width/height pair, makes the viewport side fluid; when non-zero, locks its aspect ratio. */
|
||||
bool integer_scaling; /*!< Ensure that the viewport is zoomed only with integer factors. */
|
||||
bool pixel_perfect; /*!< Ensure that the resulting image is really viewport-sized and (potentially) rescaled afterwards, as opposed to default transformation-based scaling. */
|
||||
};
|
||||
|
||||
/*! \brief Main struct of the game. */
|
||||
|
@ -97,6 +98,8 @@ struct Game {
|
|||
bool showconsole; /*!< If true, game console is rendered on screen. */
|
||||
bool showtimeline;
|
||||
|
||||
ALLEGRO_BITMAP* fb; /*!< Default framebuffer. */
|
||||
|
||||
struct {
|
||||
double old_time, fps;
|
||||
int frames_done;
|
||||
|
@ -123,6 +126,11 @@ struct Game {
|
|||
|
||||
double timestamp;
|
||||
|
||||
struct {
|
||||
int x, y;
|
||||
int w, h;
|
||||
} clip_rect;
|
||||
|
||||
#ifdef ALLEGRO_MACOSX
|
||||
char cwd[MAXPATHLEN];
|
||||
#endif
|
||||
|
@ -144,6 +152,7 @@ struct Game {
|
|||
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);
|
||||
|
|
33
src/utils.c
33
src/utils.c
|
@ -46,6 +46,7 @@ SYMBOL_EXPORT void DrawHorizontalGradientRect(float x, float y, float w, float h
|
|||
}
|
||||
|
||||
SYMBOL_EXPORT void DrawTextWithShadow(ALLEGRO_FONT* font, ALLEGRO_COLOR color, float x, float y, int flags, char const* text) {
|
||||
// TODO: consider using a set of shaders
|
||||
al_draw_text(font, al_map_rgba(0, 0, 0, 128), x + 1, y + 1, flags, text);
|
||||
al_draw_text(font, color, x, y, flags, text);
|
||||
}
|
||||
|
@ -454,6 +455,10 @@ SYMBOL_EXPORT void SetupViewport(struct Game* game, struct Viewport config) {
|
|||
int clipY = (al_get_display_height(game->display) - clipHeight) / 2;
|
||||
al_build_transform(&game->projection, clipX, clipY, resolution, resolution, 0.0f);
|
||||
al_set_clipping_rectangle(clipX, clipY, clipWidth, clipHeight);
|
||||
game->_priv.clip_rect.x = clipX;
|
||||
game->_priv.clip_rect.y = clipY;
|
||||
game->_priv.clip_rect.w = clipWidth;
|
||||
game->_priv.clip_rect.h = clipHeight;
|
||||
} 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);
|
||||
}
|
||||
|
@ -471,10 +476,38 @@ SYMBOL_EXPORT void WindowCoordsToViewport(struct Game* game, int* x, int* y) {
|
|||
*y /= clipHeight / (float)game->viewport.height;
|
||||
}
|
||||
|
||||
SYMBOL_EXPORT ALLEGRO_BITMAP* GetFramebuffer(struct Game* game) {
|
||||
return game->_priv.current_gamestate->fb;
|
||||
}
|
||||
|
||||
SYMBOL_EXPORT void SetFramebufferAsTarget(struct Game* game) {
|
||||
al_set_target_bitmap(GetFramebuffer(game));
|
||||
double x = al_get_bitmap_width(GetFramebuffer(game)) / (double)game->viewport.width;
|
||||
double y = al_get_bitmap_height(GetFramebuffer(game)) / (double)game->viewport.height;
|
||||
ALLEGRO_TRANSFORM t;
|
||||
al_identity_transform(&t);
|
||||
al_scale_transform(&t, x, y);
|
||||
al_use_transform(&t);
|
||||
}
|
||||
|
||||
SYMBOL_EXPORT ALLEGRO_BITMAP* CreateNotPreservedBitmap(int width, int height) {
|
||||
int flags = al_get_new_bitmap_flags();
|
||||
//al_set_new_bitmap_depth(24);
|
||||
al_add_new_bitmap_flag(ALLEGRO_NO_PRESERVE_TEXTURE);
|
||||
ALLEGRO_BITMAP* bitmap = al_create_bitmap(width, height);
|
||||
al_set_new_bitmap_flags(flags);
|
||||
//al_set_new_bitmap_depth(0);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
SYMBOL_EXPORT void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates)) {
|
||||
PrintConsole(game, "Compositor enabled.");
|
||||
game->handlers.compositor = compositor ? compositor : SimpleCompositor;
|
||||
ResizeGamestates(game);
|
||||
}
|
||||
|
||||
SYMBOL_EXPORT void DisableCompositor(struct Game* game) {
|
||||
PrintConsole(game, "Compositor disabled.");
|
||||
game->handlers.compositor = NULL;
|
||||
ResizeGamestates(game);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#endif
|
||||
|
||||
struct Viewport;
|
||||
struct Gamestate;
|
||||
|
||||
/*! \brief Draws rectangle filled with vertical gradient. */
|
||||
void DrawVerticalGradientRect(float x, float y, float w, float h, ALLEGRO_COLOR top, ALLEGRO_COLOR bottom);
|
||||
|
@ -76,5 +77,13 @@ void SetupViewport(struct Game* game, struct Viewport config);
|
|||
|
||||
void WindowCoordsToViewport(struct Game* game, int* x, int* y);
|
||||
|
||||
ALLEGRO_BITMAP* GetFramebuffer(struct Game* game);
|
||||
|
||||
void SetFramebufferAsTarget(struct Game* game);
|
||||
|
||||
ALLEGRO_BITMAP* CreateNotPreservedBitmap(int width, int height);
|
||||
|
||||
void EnableCompositor(struct Game* game, void compositor(struct Game* game, struct Gamestate* gamestates));
|
||||
void DisableCompositor(struct Game* game);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue