Refactor of the shader class into a cleaner more functional graphics namespace and a procedural builder-style shader

This commit is contained in:
Ben Kyd
2023-04-23 14:10:02 +01:00
parent 5fd66cfdfa
commit b4e7a51400
7 changed files with 133 additions and 145 deletions

View File

@@ -23,9 +23,9 @@
#include <chrono> #include <chrono>
#include <numeric> #include <numeric>
namespace inferno::core { using namespace inferno;
InfernoApp* create_inferno() InfernoApp* inferno_create()
{ {
// MOTD // MOTD
yolo::info("INFERNO HART v" INFERNO_VERSION); yolo::info("INFERNO HART v" INFERNO_VERSION);
@@ -38,11 +38,11 @@ InfernoApp* create_inferno()
return app; 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("(?)"); ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayShort)) 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"); ImGuiID dockspace_id = ImGui::GetID("main");
@@ -72,7 +72,7 @@ void preset_gui(InfernoApp *app)
yolo::info("LAYOUT SET TO DEFAULT"); yolo::info("LAYOUT SET TO DEFAULT");
} }
void move_input(InfernoApp *app) void inferno_move_input(InfernoApp *app)
{ {
static GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR); static GLFWcursor* cursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
glfwSetCursor(app->Win->getGLFWWindow(), cursor); glfwSetCursor(app->Win->getGLFWWindow(), cursor);
@@ -114,16 +114,14 @@ void move_input(InfernoApp *app)
app->Input->MovementDelta |= 0b00000100; app->Input->MovementDelta |= 0b00000100;
} }
void stop_move_input(InfernoApp *app) void inferno_stop_move_input(InfernoApp *app)
{ {
app->Input->MovementDelta = 0x0; app->Input->MovementDelta = 0x0;
app->Input->MouseDelta = { 0.0f, 0.0f }; app->Input->MouseDelta = { 0.0f, 0.0f };
} }
int run(InfernoApp *app) int inferno_run(InfernoApp *app)
{ {
return 1; return 1;
} }
}

View File

@@ -2,9 +2,9 @@
#include "graphics.hpp" #include "graphics.hpp"
#include <singleton.hpp> #include <memory>
namespace inferno::core { namespace inferno {
class Window; class Window;
class HHM; class HHM;
@@ -19,12 +19,12 @@ typedef struct InfernoApp {
InfernoInput* Input; InfernoInput* Input;
} InfernoApp; } InfernoApp;
InfernoApp* create_inferno(); InfernoApp* inferno_create();
void cleanup_inferno(InfernoApp* app); void inferno_cleanup(InfernoApp* app);
void preset_gui(InfernoApp* app); void inferno_preset_gui(InfernoApp* app);
void move_input(InfernoApp* app); void inferno_move_input(InfernoApp* app);
void stop_move_input(InfernoApp* app); void inferno_stop_move_input(InfernoApp* app);
int run(InfernoApp* app); int inferno_run(InfernoApp* app);
} }

View File

@@ -5,7 +5,7 @@
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
auto* inferno = inferno::core::create_inferno(); auto* inferno = inferno::inferno_create();
return inferno::core::run(inferno); return inferno::inferno_run(inferno);
} }

View File

@@ -3,6 +3,14 @@
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
using namespace inferno::graphics;
static std::unordered_map<GLuint, int> shader2Index = {
{GL_VERTEX_SHADER, 0},
{GL_GEOMETRY_SHADER, 1},
{GL_FRAGMENT_SHADER, 2}
};
inline std::string trim(std::string& str) inline std::string trim(std::string& str)
{ {
str.erase(str.find_last_not_of(' ')+1); //suffixing spaces str.erase(str.find_last_not_of(' ')+1); //suffixing spaces
@@ -10,35 +18,62 @@ inline std::string trim(std::string& str)
return str; return str;
} }
static std::unordered_map<GLuint, int> 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::string textFromFile(const std::filesystem::path& path) {
std::ifstream input(path); std::ifstream input(path);
return std::string((std::istreambuf_iterator<char>(input)), return std::string((std::istreambuf_iterator<char>(input)),
std::istreambuf_iterator<char>()); std::istreambuf_iterator<char>());
} }
Shader::Shader() std::vector<const ShaderPreprocessorDefinition*> getKeys(std::unique_ptr<Shader>& shader, std::string key) {
: mShaders({ GL_NONE, GL_NONE, GL_NONE}) std::vector<const ShaderPreprocessorDefinition*> ret;
, mProgram(0) { 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<GLchar> 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> shader_create() {
std::unique_ptr<Shader> shader = std::make_unique<Shader>();
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>& shader) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (mShaders[i] == GL_NONE) continue; if (shader->Shaders[i] == GL_NONE) continue;
glDeleteShader(mShaders[i]); glDeleteShader(shader->Shaders[i]);
} }
glDeleteProgram(shader->Program);
} }
Shader* Shader::load(std::filesystem::path path) { void shader_load(std::unique_ptr<Shader>& shader, std::filesystem::path path) {
assert(std::filesystem::exists(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++) { for (int i = 0; i < loadedShaderSource.length(); i++) {
const char& c = loadedShaderSource[i]; const char& c = loadedShaderSource[i];
if (c == '#') { if (c == '#') {
mPreprocessorDefinition def = { .start = i }; ShaderPreprocessorDefinition def = { .start = i };
int j; int j;
for (j = ++i; loadedShaderSource[j] != ' '; j++) { for (j = ++i; loadedShaderSource[j] != ' '; j++) {
def.key += loadedShaderSource[j]; def.key += loadedShaderSource[j];
@@ -58,16 +93,16 @@ Shader* Shader::load(std::filesystem::path path) {
def.end = j; i = j; // advance i def.end = j; i = j; // advance i
def.def = trim(def.def); def.def = trim(def.def);
def.key = trim(def.key); def.key = trim(def.key);
mDefinitions.push_back(def); shader->PreprocessorDefinitions.push_back(def);
} }
} }
// now we have all of the key/value definitions // now we have all of the key/value definitions
// we can extract the relavent ones, for example // we can extract the relavent ones, for example
// "type" // "type"
auto types = mGetKeys("type"); std::vector<const ShaderPreprocessorDefinition*> types = getKeys(shader, "type");
int i = 0; int i = 0;
for (const mPreprocessorDefinition* type : types) { for (const ShaderPreprocessorDefinition* type : types) {
GLuint glType = GL_NONE; GLuint glType = GL_NONE;
if (type->def == "vertex") glType = GL_VERTEX_SHADER; if (type->def == "vertex") glType = GL_VERTEX_SHADER;
if (type->def == "geometry") glType = GL_GEOMETRY_SHADER; if (type->def == "geometry") glType = GL_GEOMETRY_SHADER;
@@ -75,84 +110,54 @@ Shader* Shader::load(std::filesystem::path path) {
assert(glType != GL_NONE); assert(glType != GL_NONE);
mShaders[Shader2Index[glType]] = glCreateShader(glType); shader->Shaders[shader2Index[glType]] = glCreateShader(glType);
const char* source = loadedShaderSource.c_str() + type->end; const char* source = loadedShaderSource.c_str() + type->end;
int end = types.size() - 1 == i ? types.size(): types[i + 1]->start; int end = types.size() - 1 == i ? types.size(): types[i + 1]->start;
int length = end - type->end; int length = end - type->end;
glShaderSource(mShaders[Shader2Index[glType]], 1, &source, &length); glShaderSource(shader->Shaders[shader2Index[glType]], 1, &source, &length);
i++; i++;
} }
return this;
} }
Shader* Shader::link() { void shader_link(std::unique_ptr<Shader> &shader) {
shader->Program = glCreateProgram();
mProgram = glCreateProgram();
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
if (mShaders[i] == GL_NONE) continue; if (shader->Shaders[i] == GL_NONE) continue;
glCompileShader(mShaders[i]); glCompileShader(shader->Shaders[i]);
if (!mCheckShader(mShaders[i])) continue; if (!checkShader(shader->Shaders[i])) continue;
glAttachShader(mProgram, mShaders[i]); glAttachShader(shader->Program, shader->Shaders[i]);
} }
glLinkProgram(mProgram); glLinkProgram(shader->Program);
return this;
} }
Shader* Shader::use() {
glUseProgram(mProgram); void shader_add_attribute(std::unique_ptr<Shader> &shader, const std::string &attribute) {
return this; shader->Attributes[attribute] = glGetAttribLocation(shader->Program, attribute.c_str());
} }
Shader* Shader::unUse() { void shader_add_uniform(std::unique_ptr<Shader> &shader, const std::string &uniform) {
shader->Uniforms[uniform] = glGetUniformLocation(shader->Program, uniform.c_str());
}
GLuint shader_get_attribute(std::unique_ptr<Shader> &shader, const std::string &attribute) {
return shader->Attributes[attribute];
}
GLuint shader_get_uniform(std::unique_ptr<Shader> &shader, const std::string &uniform) {
return shader->Uniforms[uniform];
}
void shader_use(std::unique_ptr<Shader>& shader) {
glUseProgram(shader->Program);
}
void shader_unuse(std::unique_ptr<Shader>& shader) {
glUseProgram(0); 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<GLchar> 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<const Shader::mPreprocessorDefinition*> Shader::mGetKeys(std::string key) {
std::vector<const Shader::mPreprocessorDefinition*> ret;
for (const auto& p : mDefinitions) if (p.key == key) ret.push_back(&p);
return ret;
}

View File

@@ -8,52 +8,37 @@
#include <filesystem> #include <filesystem>
#include <unordered_map> #include <unordered_map>
namespace inferno { namespace inferno::graphics {
class Shader { typedef struct ShaderPreprocessorDefinition {
public: int start, end;
Shader(); std::string key;
~Shader(); std::string def;
} shaderpreprocessordefinition;
Shader* preprocessorDefine(std::string statement);
Shader* load(std::filesystem::path path); typedef struct Shader {
Shader* link(); GLuint Shaders[3];
GLuint Program;
std::unordered_map<std::string, GLuint> Attributes;
std::unordered_map<std::string, GLuint> Uniforms;
std::vector<ShaderPreprocessorDefinition> PreprocessorDefinitions;
} Shader;
Shader* use(); std::unique_ptr<Shader> shader_create();
Shader* unUse(); void shader_cleanup(std::unique_ptr<Shader>& shader);
GLuint getProgram(); void shader_load(std::unique_ptr<Shader>& shader, std::filesystem::path path);
void shader_link(std::unique_ptr<Shader>& shader);
// TODO: Implement shader_reload
void shader_add_attribute(std::unique_ptr<Shader>& shader, const std::string& attribute);
void shader_add_uniform(std::unique_ptr<Shader>& shader, const std::string& uniform);
GLuint shader_get_attribute(std::unique_ptr<Shader>& shader, const std::string& attribute);
GLuint shader_get_uniform(std::unique_ptr<Shader>& shader, const std::string& uniform);
void addAttribute(const std::string& attribute); void shader_use(std::unique_ptr<Shader>& shader);
void addUniform(const std::string& uniform); void shader_unuse(std::unique_ptr<Shader>& shader);
GLuint operator[](const std::string& attribute) {
return mAttributes[attribute];
}
GLuint operator()(const std::string& uniform) {
return mUniformLocations[uniform];
}
private:
GLuint mShaders[3];
GLuint mProgram;
std::unordered_map<std::string, GLuint> mAttributes;
std::unordered_map<std::string, GLuint> 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<mPreprocessorDefinition> mDefinitions;
std::vector<const Shader::mPreprocessorDefinition*> mGetKeys(std::string key);
};
} }

View File

@@ -4,7 +4,7 @@
#include "yolo/yolo.hpp" #include "yolo/yolo.hpp"
using namespace inferno::core; using namespace inferno;
Window::Window() {} Window::Window() {}

View File

@@ -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 #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 (*KeyCallback)(int key, int scan, int action, int mod);
typedef void (*MouseCallback)(double x, double y); typedef void (*MouseCallback)(double x, double y);