shader: auto rebuild and auto destroy shaders

This commit is contained in:
Sebastian Krzyszkowiak 2018-05-31 20:52:16 +02:00
parent 5fe62da08f
commit 71ec8b396e
4 changed files with 110 additions and 28 deletions

View file

@ -94,6 +94,7 @@ SYMBOL_INTERNAL void LogicGamestates(struct Game* game, double delta) {
SYMBOL_INTERNAL void ReloadGamestates(struct Game* game) {
struct Gamestate* tmp = game->_priv.gamestates;
ReloadShaders(game, true);
while (tmp) {
if (tmp->loaded) {
game->_priv.current_gamestate = tmp;
@ -355,7 +356,21 @@ static bool Identity(struct libsuperderpy_list* elem, void* data) {
return elem->data == data;
}
SYMBOL_INTERNAL struct libsuperderpy_list* RemoveFromList(struct libsuperderpy_list** list, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data)) {
SYMBOL_INTERNAL struct libsuperderpy_list* FindInList(struct libsuperderpy_list* list, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data)) {
struct libsuperderpy_list* tmp = list;
if (!identity) {
identity = Identity;
}
while (tmp) {
if (identity(tmp, data)) {
return tmp;
}
tmp = tmp->next;
}
return NULL;
}
SYMBOL_INTERNAL void* RemoveFromList(struct libsuperderpy_list** list, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data)) {
struct libsuperderpy_list *prev = NULL, *tmp = *list, *start;
void* d = NULL;
if (!identity) {
@ -506,6 +521,7 @@ SYMBOL_INTERNAL void PauseExecution(struct Game* game) {
}
SYMBOL_INTERNAL void ResumeExecution(struct Game* game) {
ReloadShaders(game, true);
PrintConsole(game, "DEBUG: reloading the gamestates...");
struct Gamestate* tmp = game->_priv.gamestates;
while (tmp) {

View file

@ -80,7 +80,8 @@ void* AddGarbage(struct Game* game, void* data);
void ClearGarbage(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, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data));
struct libsuperderpy_list* FindInList(struct libsuperderpy_list* list, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data));
void* RemoveFromList(struct libsuperderpy_list** list, void* data, bool (*identity)(struct libsuperderpy_list* elem, void* data));
void AddTimeline(struct Game* game, struct Timeline* timeline);
void RemoveTimeline(struct Game* game, struct Timeline* timeline);
void DrawTimelines(struct Game* game);
@ -91,5 +92,7 @@ struct Gamestate* AllocateGamestate(struct Game* game, const char* name);
char* GetLibraryPath(struct Game* game, char* filename);
void PauseExecution(struct Game* game);
void ResumeExecution(struct Game* game);
void ReloadShaders(struct Game* game, bool force);
void DestroyShaders(struct Game* game);
#endif

View file

@ -420,8 +420,8 @@ SYMBOL_INTERNAL void libsuperderpy_mainloop(void* g) {
#endif
al_set_new_bitmap_flags(data.bitmap_flags);
// TODO: compile shaders
al_convert_memory_bitmaps();
ReloadShaders(game, false);
game->_priv.loading.loaded++;
tmp->loaded = true;
@ -631,6 +631,7 @@ SYMBOL_EXPORT void libsuperderpy_destroy(struct Game* game) {
if (game->handlers.destroy) {
(*game->handlers.destroy)(game);
}
DestroyShaders(game);
ClearScreen(game);
#ifdef __EMSCRIPTEN__

View file

@ -22,39 +22,101 @@
#include <allegro5/allegro.h>
#include <math.h>
ALLEGRO_SHADER* CreateShader(struct Game* game, const char* vertex, const char* fragment) {
const char* log;
static bool AttachToShader(struct Game* game, ALLEGRO_SHADER* shader, ALLEGRO_SHADER_TYPE type, const char* filename) {
bool ret;
if (filename) {
ret = al_attach_shader_source_file(shader, type, filename);
} else {
ret = al_attach_shader_source(shader, type, al_get_default_shader_source(al_get_shader_platform(shader), type));
}
if (!ret) {
const char* log;
log = al_get_shader_log(shader);
if (log) {
FatalError(game, false, "%s", log);
}
}
return ret;
}
struct ShaderListItem {
ALLEGRO_SHADER* shader;
char* vertex;
char* fragment;
bool loaded;
};
SYMBOL_EXPORT ALLEGRO_SHADER* CreateShader(struct Game* game, const char* vertex, const char* fragment) {
PrintConsole(game, "Creating shader V:%s F:%s...", vertex, fragment);
ALLEGRO_SHADER* shader = al_create_shader(ALLEGRO_SHADER_GLSL);
if (!al_attach_shader_source_file(shader, ALLEGRO_VERTEX_SHADER, vertex)) {
log = al_get_shader_log(shader);
if (log) {
PrintConsole(game, "%s", log);
}
}
if (!al_attach_shader_source_file(shader, ALLEGRO_PIXEL_SHADER, fragment)) {
log = al_get_shader_log(shader);
if (log) {
PrintConsole(game, "%s", log);
}
}
if (!al_build_shader(shader)) {
log = al_get_shader_log(shader);
if (log) {
PrintConsole(game, "%s", log);
}
}
game->_priv.shaders = AddToList(game->_priv.shaders, shader);
struct ShaderListItem* item = malloc(sizeof(struct ShaderListItem));
item->shader = shader;
item->vertex = vertex ? strdup(vertex) : NULL;
item->fragment = fragment ? strdup(fragment) : NULL;
item->loaded = false;
PrintConsole(game, "Shader compiled successfully.");
game->_priv.shaders = AddToList(game->_priv.shaders, item);
return shader;
}
void DestroyShader(struct Game* game, ALLEGRO_SHADER* shader) {
RemoveFromList(&game->_priv.shaders, shader, NULL);
al_destroy_shader(shader);
static bool ShaderIdentity(struct libsuperderpy_list* item, void* shader) {
return ((struct ShaderListItem*)item->data)->shader == shader;
}
SYMBOL_EXPORT void DestroyShader(struct Game* game, ALLEGRO_SHADER* shader) {
struct ShaderListItem* item = RemoveFromList(&game->_priv.shaders, shader, ShaderIdentity);
if (!item) {
PrintConsole(game, "Tried to destroy a unregistered shader!");
al_destroy_shader(shader);
return;
}
al_destroy_shader(item->shader);
if (item->vertex) {
free(item->vertex);
}
if (item->fragment) {
free(item->fragment);
}
}
SYMBOL_INTERNAL void ReloadShaders(struct Game* game, bool force) {
struct libsuperderpy_list* list = game->_priv.shaders;
PrintConsole(game, "Reloading shaders...");
while (list) {
struct ShaderListItem* item = list->data;
if (!item->loaded || force) {
PrintConsole(game, "V:%s, F:%s", item->vertex, item->fragment);
AttachToShader(game, item->shader, ALLEGRO_VERTEX_SHADER, item->vertex);
AttachToShader(game, item->shader, ALLEGRO_PIXEL_SHADER, item->fragment);
if (!al_build_shader(item->shader)) {
const char* log = al_get_shader_log(item->shader);
if (log) {
FatalError(game, false, "%s", log);
}
}
}
list = list->next;
}
PrintConsole(game, "Shaders reloaded.");
}
SYMBOL_INTERNAL void DestroyShaders(struct Game* game) {
PrintConsole(game, "Destroying shaders...");
while (game->_priv.shaders) {
struct ShaderListItem* item = game->_priv.shaders->data;
al_destroy_shader(item->shader);
if (item->vertex) {
free(item->vertex);
}
if (item->fragment) {
free(item->fragment);
}
struct libsuperderpy_list* prev = game->_priv.shaders;
game->_priv.shaders = game->_priv.shaders->next;
free(prev);
}
}