From b4e7a5140033cc9f49444e0f6ff6e766923ef86e Mon Sep 17 00:00:00 2001 From: Ben Kyd Date: Sun, 23 Apr 2023 14:10:02 +0100 Subject: [PATCH] Refactor of the shader class into a cleaner more functional graphics namespace and a procedural builder-style shader --- src/inferno.cpp | 18 ++-- src/inferno.hpp | 16 +-- src/main.cpp | 4 +- src/preview_renderer/shader.cpp | 171 ++++++++++++++++---------------- src/preview_renderer/shader.hpp | 65 +++++------- src/window.cpp | 2 +- src/window.hpp | 2 +- 7 files changed, 133 insertions(+), 145 deletions(-) diff --git a/src/inferno.cpp b/src/inferno.cpp index d0eaa3e..3d9c24b 100644 --- a/src/inferno.cpp +++ b/src/inferno.cpp @@ -23,9 +23,9 @@ #include #include -namespace inferno::core { +using namespace inferno; -InfernoApp* create_inferno() +InfernoApp* inferno_create() { // MOTD yolo::info("INFERNO HART v" INFERNO_VERSION); @@ -38,11 +38,11 @@ InfernoApp* create_inferno() return app; } -void cleanup_inferno(InfernoApp* app) +void inferno_cleanup(InfernoApp* app) { } -static void gui_help_marker(const char* desc) +static void inferno_gui_help_marker(const char* desc) { ImGui::TextDisabled("(?)"); if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) @@ -55,7 +55,7 @@ static void gui_help_marker(const char* desc) } } -void preset_gui(InfernoApp *app) +void inferno_preset_gui(InfernoApp *app) { ImGuiID dockspace_id = ImGui::GetID("main"); @@ -72,7 +72,7 @@ void preset_gui(InfernoApp *app) yolo::info("LAYOUT SET TO DEFAULT"); } -void move_input(InfernoApp *app) +void inferno_move_input(InfernoApp *app) { static GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); glfwSetCursor(app->Win->getGLFWWindow(), cursor); @@ -114,16 +114,14 @@ void move_input(InfernoApp *app) app->Input->MovementDelta |= 0b00000100; } -void stop_move_input(InfernoApp *app) +void inferno_stop_move_input(InfernoApp *app) { app->Input->MovementDelta = 0x0; app->Input->MouseDelta = { 0.0f, 0.0f }; } -int run(InfernoApp *app) +int inferno_run(InfernoApp *app) { return 1; } -} - diff --git a/src/inferno.hpp b/src/inferno.hpp index 31f1e74..a9192fa 100644 --- a/src/inferno.hpp +++ b/src/inferno.hpp @@ -2,9 +2,9 @@ #include "graphics.hpp" -#include +#include -namespace inferno::core { +namespace inferno { class Window; class HHM; @@ -19,12 +19,12 @@ typedef struct InfernoApp { InfernoInput* Input; } InfernoApp; -InfernoApp* create_inferno(); -void cleanup_inferno(InfernoApp* app); -void preset_gui(InfernoApp* app); -void move_input(InfernoApp* app); -void stop_move_input(InfernoApp* app); -int run(InfernoApp* app); +InfernoApp* inferno_create(); +void inferno_cleanup(InfernoApp* app); +void inferno_preset_gui(InfernoApp* app); +void inferno_move_input(InfernoApp* app); +void inferno_stop_move_input(InfernoApp* app); +int inferno_run(InfernoApp* app); } diff --git a/src/main.cpp b/src/main.cpp index d76ce3b..9ee8811 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,7 @@ int main(int argc, char** argv) { - auto* inferno = inferno::core::create_inferno(); - return inferno::core::run(inferno); + auto* inferno = inferno::inferno_create(); + return inferno::inferno_run(inferno); } diff --git a/src/preview_renderer/shader.cpp b/src/preview_renderer/shader.cpp index 34f005f..c19160b 100644 --- a/src/preview_renderer/shader.cpp +++ b/src/preview_renderer/shader.cpp @@ -3,6 +3,14 @@ #include #include +using namespace inferno::graphics; + +static std::unordered_map shader2Index = { + {GL_VERTEX_SHADER, 0}, + {GL_GEOMETRY_SHADER, 1}, + {GL_FRAGMENT_SHADER, 2} +}; + inline std::string trim(std::string& str) { str.erase(str.find_last_not_of(' ')+1); //suffixing spaces @@ -10,35 +18,62 @@ inline std::string trim(std::string& str) return str; } -static std::unordered_map Shader2Index = { - {GL_VERTEX_SHADER, 0}, - {GL_GEOMETRY_SHADER, 1}, - {GL_FRAGMENT_SHADER, 2} -}; - -using namespace inferno; - std::string textFromFile(const std::filesystem::path& path) { std::ifstream input(path); - return std::string((std::istreambuf_iterator(input)), - std::istreambuf_iterator()); - + return std::string((std::istreambuf_iterator(input)), + std::istreambuf_iterator()); } -Shader::Shader() - : mShaders({ GL_NONE, GL_NONE, GL_NONE}) - , mProgram(0) { +std::vector getKeys(std::unique_ptr& shader, std::string key) { + std::vector ret; + for (const auto& p : shader->PreprocessorDefinitions) if (p.key == key) ret.push_back(&p); + return ret; +} + +bool checkShader(GLuint uid) { + GLint isCompiled = 0; + glGetShaderiv(uid, GL_COMPILE_STATUS, &isCompiled); + if(isCompiled == GL_FALSE) + { + GLint maxLength = 0; + glGetShaderiv(uid, GL_INFO_LOG_LENGTH, &maxLength); + + std::vector errorLog(maxLength); + glGetShaderInfoLog(uid, maxLength, &maxLength, &errorLog[0]); + + for (int i = 0; i < errorLog.size(); i++) { + std::cout << errorLog[i]; + } + + glDeleteShader(uid); + return false; + } + + return true; } -Shader::~Shader() { +std::unique_ptr shader_create() { + std::unique_ptr shader = std::make_unique(); + + shader->Program = 0; + shader->Shaders[0] = GL_NONE; + shader->Shaders[1] = GL_NONE; + shader->Shaders[2] = GL_NONE; + + return shader; +} + +void shader_cleanup(std::unique_ptr& shader) { for (int i = 0; i < 3; i++) { - if (mShaders[i] == GL_NONE) continue; - glDeleteShader(mShaders[i]); + if (shader->Shaders[i] == GL_NONE) continue; + glDeleteShader(shader->Shaders[i]); } + + glDeleteProgram(shader->Program); } -Shader* Shader::load(std::filesystem::path path) { +void shader_load(std::unique_ptr& shader, std::filesystem::path path) { assert(std::filesystem::exists(path)); @@ -47,7 +82,7 @@ Shader* Shader::load(std::filesystem::path path) { for (int i = 0; i < loadedShaderSource.length(); i++) { const char& c = loadedShaderSource[i]; if (c == '#') { - mPreprocessorDefinition def = { .start = i }; + ShaderPreprocessorDefinition def = { .start = i }; int j; for (j = ++i; loadedShaderSource[j] != ' '; j++) { def.key += loadedShaderSource[j]; @@ -58,16 +93,16 @@ Shader* Shader::load(std::filesystem::path path) { def.end = j; i = j; // advance i def.def = trim(def.def); def.key = trim(def.key); - mDefinitions.push_back(def); + shader->PreprocessorDefinitions.push_back(def); } } // now we have all of the key/value definitions // we can extract the relavent ones, for example // "type" - auto types = mGetKeys("type"); + std::vector types = getKeys(shader, "type"); int i = 0; - for (const mPreprocessorDefinition* type : types) { + for (const ShaderPreprocessorDefinition* type : types) { GLuint glType = GL_NONE; if (type->def == "vertex") glType = GL_VERTEX_SHADER; if (type->def == "geometry") glType = GL_GEOMETRY_SHADER; @@ -75,84 +110,54 @@ Shader* Shader::load(std::filesystem::path path) { assert(glType != GL_NONE); - mShaders[Shader2Index[glType]] = glCreateShader(glType); - + shader->Shaders[shader2Index[glType]] = glCreateShader(glType); + const char* source = loadedShaderSource.c_str() + type->end; int end = types.size() - 1 == i ? types.size(): types[i + 1]->start; int length = end - type->end; - - glShaderSource(mShaders[Shader2Index[glType]], 1, &source, &length); + + glShaderSource(shader->Shaders[shader2Index[glType]], 1, &source, &length); i++; } - - return this; } -Shader* Shader::link() { +void shader_link(std::unique_ptr &shader) { + shader->Program = glCreateProgram(); - mProgram = glCreateProgram(); - for (int i = 0; i < 3; i++) { - if (mShaders[i] == GL_NONE) continue; + if (shader->Shaders[i] == GL_NONE) continue; - glCompileShader(mShaders[i]); - if (!mCheckShader(mShaders[i])) continue; + glCompileShader(shader->Shaders[i]); + if (!checkShader(shader->Shaders[i])) continue; - glAttachShader(mProgram, mShaders[i]); + glAttachShader(shader->Program, shader->Shaders[i]); } - glLinkProgram(mProgram); - return this; + glLinkProgram(shader->Program); } -Shader* Shader::use() { - glUseProgram(mProgram); - return this; + +void shader_add_attribute(std::unique_ptr &shader, const std::string &attribute) { + shader->Attributes[attribute] = glGetAttribLocation(shader->Program, attribute.c_str()); } -Shader* Shader::unUse() { +void shader_add_uniform(std::unique_ptr &shader, const std::string &uniform) { + shader->Uniforms[uniform] = glGetUniformLocation(shader->Program, uniform.c_str()); +} + +GLuint shader_get_attribute(std::unique_ptr &shader, const std::string &attribute) { + return shader->Attributes[attribute]; +} + +GLuint shader_get_uniform(std::unique_ptr &shader, const std::string &uniform) { + return shader->Uniforms[uniform]; +} + +void shader_use(std::unique_ptr& shader) { + glUseProgram(shader->Program); +} + +void shader_unuse(std::unique_ptr& shader) { glUseProgram(0); - return this; } -GLuint Shader::getProgram() -{ - return mProgram; -} - - -void Shader::addAttribute(const std::string& attribute) { - mAttributes[attribute] = glGetAttribLocation(mProgram, attribute.c_str()); -} - -void Shader::addUniform(const std::string& uniform) { - mUniformLocations[uniform] = glGetUniformLocation(mProgram, uniform.c_str()); -} - -bool Shader::mCheckShader(GLuint uid) { - GLint isCompiled = 0; - glGetShaderiv(uid, GL_COMPILE_STATUS, &isCompiled); - if(isCompiled == GL_FALSE) - { - GLint maxLength = 0; - glGetShaderiv(uid, GL_INFO_LOG_LENGTH, &maxLength); - - std::vector errorLog(maxLength); - glGetShaderInfoLog(uid, maxLength, &maxLength, &errorLog[0]); - - for (int i = 0; i < errorLog.size(); i++) { - std::cout << errorLog[i]; - } - - glDeleteShader(uid); - return false; - } - - return true; -} - -std::vector Shader::mGetKeys(std::string key) { - std::vector ret; - for (const auto& p : mDefinitions) if (p.key == key) ret.push_back(&p); - return ret; -} diff --git a/src/preview_renderer/shader.hpp b/src/preview_renderer/shader.hpp index f2661e3..c43bd7f 100644 --- a/src/preview_renderer/shader.hpp +++ b/src/preview_renderer/shader.hpp @@ -8,52 +8,37 @@ #include #include -namespace inferno { +namespace inferno::graphics { -class Shader { -public: - Shader(); - ~Shader(); +typedef struct ShaderPreprocessorDefinition { + int start, end; + std::string key; + std::string def; +} shaderpreprocessordefinition; - Shader* preprocessorDefine(std::string statement); - Shader* load(std::filesystem::path path); - Shader* link(); +typedef struct Shader { + GLuint Shaders[3]; + GLuint Program; + std::unordered_map Attributes; + std::unordered_map Uniforms; + std::vector PreprocessorDefinitions; +} Shader; - Shader* use(); - Shader* unUse(); +std::unique_ptr shader_create(); +void shader_cleanup(std::unique_ptr& shader); - GLuint getProgram(); +void shader_load(std::unique_ptr& shader, std::filesystem::path path); +void shader_link(std::unique_ptr& shader); +// TODO: Implement shader_reload +void shader_add_attribute(std::unique_ptr& shader, const std::string& attribute); +void shader_add_uniform(std::unique_ptr& shader, const std::string& uniform); +GLuint shader_get_attribute(std::unique_ptr& shader, const std::string& attribute); +GLuint shader_get_uniform(std::unique_ptr& shader, const std::string& uniform); - void addAttribute(const std::string& attribute); - void addUniform(const std::string& uniform); - GLuint operator[](const std::string& attribute) { - return mAttributes[attribute]; - } - GLuint operator()(const std::string& uniform) { - return mUniformLocations[uniform]; - } +void shader_use(std::unique_ptr& shader); +void shader_unuse(std::unique_ptr& shader); -private: - GLuint mShaders[3]; - GLuint mProgram; - - std::unordered_map mAttributes; - std::unordered_map mUniformLocations; - bool mCheckShader(GLuint uid); - -private: - // preprocessor definitions can be defined by their - // start/end index, this is so that text can either be inserted - // in their place or for the "type" definition, the program - // can count until the next "type" definition per shader - struct mPreprocessorDefinition { - int start, end; - std::string key; - std::string def; - }; - std::vector mDefinitions; - std::vector mGetKeys(std::string key); -}; } + diff --git a/src/window.cpp b/src/window.cpp index 87d6151..121a470 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -4,7 +4,7 @@ #include "yolo/yolo.hpp" -using namespace inferno::core; +using namespace inferno; Window::Window() {} diff --git a/src/window.hpp b/src/window.hpp index 7bb1324..6063da9 100644 --- a/src/window.hpp +++ b/src/window.hpp @@ -7,7 +7,7 @@ #define WINDOW_FLAGS ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoCollapse -namespace inferno::core { +namespace inferno { typedef void (*KeyCallback)(int key, int scan, int action, int mod); typedef void (*MouseCallback)(double x, double y);