rumina hacks

This commit is contained in:
Sebastian Krzyszkowiak 2018-02-03 03:46:33 +01:00
parent 686dab729a
commit ae70770f77
9 changed files with 134 additions and 17 deletions

View file

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

View file

@ -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. */

View file

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

View file

@ -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) {
ClearScreen(game);
al_set_target_backbuffer(game->display);
if (!game->handlers.compositor) {
ClearScreen(game);
}
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) {

View file

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

View file

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

View file

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

View file

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

View file

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