From 71ec8b396e704813048c49d54245eb2573998bfc Mon Sep 17 00:00:00 2001 From: Sebastian Krzyszkowiak Date: Thu, 31 May 2018 20:52:16 +0200 Subject: [PATCH] shader: auto rebuild and auto destroy shaders --- src/internal.c | 18 ++++++- src/internal.h | 5 +- src/libsuperderpy.c | 3 +- src/shader.c | 112 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 110 insertions(+), 28 deletions(-) diff --git a/src/internal.c b/src/internal.c index c202b8b..8849348 100644 --- a/src/internal.c +++ b/src/internal.c @@ -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) { diff --git a/src/internal.h b/src/internal.h index c6959b3..09e982e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -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 diff --git a/src/libsuperderpy.c b/src/libsuperderpy.c index 53cd1d5..74d14b3 100644 --- a/src/libsuperderpy.c +++ b/src/libsuperderpy.c @@ -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__ diff --git a/src/shader.c b/src/shader.c index db4eb04..c837e80 100644 --- a/src/shader.c +++ b/src/shader.c @@ -22,39 +22,101 @@ #include #include -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); + } }