Refactor of the shader class into a cleaner more functional graphics namespace and a procedural builder-style shader
This commit is contained in:
@@ -23,9 +23,9 @@
|
||||
#include <chrono>
|
||||
#include <numeric>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include "graphics.hpp"
|
||||
|
||||
#include <singleton.hpp>
|
||||
#include <memory>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
#include <iostream>
|
||||
#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)
|
||||
{
|
||||
str.erase(str.find_last_not_of(' ')+1); //suffixing spaces
|
||||
@@ -10,126 +18,19 @@ inline std::string trim(std::string& 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::ifstream input(path);
|
||||
return std::string((std::istreambuf_iterator<char>(input)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
}
|
||||
|
||||
Shader::Shader()
|
||||
: mShaders({ GL_NONE, GL_NONE, GL_NONE})
|
||||
, mProgram(0) {
|
||||
std::vector<const ShaderPreprocessorDefinition*> getKeys(std::unique_ptr<Shader>& shader, std::string key) {
|
||||
std::vector<const ShaderPreprocessorDefinition*> ret;
|
||||
for (const auto& p : shader->PreprocessorDefinitions) if (p.key == key) ret.push_back(&p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Shader::~Shader() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (mShaders[i] == GL_NONE) continue;
|
||||
glDeleteShader(mShaders[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Shader* Shader::load(std::filesystem::path path) {
|
||||
|
||||
assert(std::filesystem::exists(path));
|
||||
|
||||
std::string loadedShaderSource = textFromFile(path);
|
||||
|
||||
for (int i = 0; i < loadedShaderSource.length(); i++) {
|
||||
const char& c = loadedShaderSource[i];
|
||||
if (c == '#') {
|
||||
mPreprocessorDefinition def = { .start = i };
|
||||
int j;
|
||||
for (j = ++i; loadedShaderSource[j] != ' '; j++) {
|
||||
def.key += loadedShaderSource[j];
|
||||
}
|
||||
for (j++; loadedShaderSource[j] != '\n'; j++) {
|
||||
def.def += loadedShaderSource[j];
|
||||
}
|
||||
def.end = j; i = j; // advance i
|
||||
def.def = trim(def.def);
|
||||
def.key = trim(def.key);
|
||||
mDefinitions.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");
|
||||
int i = 0;
|
||||
for (const mPreprocessorDefinition* type : types) {
|
||||
GLuint glType = GL_NONE;
|
||||
if (type->def == "vertex") glType = GL_VERTEX_SHADER;
|
||||
if (type->def == "geometry") glType = GL_GEOMETRY_SHADER;
|
||||
if (type->def == "fragment") glType = GL_FRAGMENT_SHADER;
|
||||
|
||||
assert(glType != GL_NONE);
|
||||
|
||||
mShaders[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);
|
||||
i++;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
Shader* Shader::link() {
|
||||
|
||||
mProgram = glCreateProgram();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (mShaders[i] == GL_NONE) continue;
|
||||
|
||||
glCompileShader(mShaders[i]);
|
||||
if (!mCheckShader(mShaders[i])) continue;
|
||||
|
||||
glAttachShader(mProgram, mShaders[i]);
|
||||
}
|
||||
|
||||
glLinkProgram(mProgram);
|
||||
return this;
|
||||
}
|
||||
|
||||
Shader* Shader::use() {
|
||||
glUseProgram(mProgram);
|
||||
return this;
|
||||
}
|
||||
|
||||
Shader* Shader::unUse() {
|
||||
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) {
|
||||
bool checkShader(GLuint uid) {
|
||||
GLint isCompiled = 0;
|
||||
glGetShaderiv(uid, GL_COMPILE_STATUS, &isCompiled);
|
||||
if(isCompiled == GL_FALSE)
|
||||
@@ -151,8 +52,112 @@ bool Shader::mCheckShader(GLuint uid) {
|
||||
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;
|
||||
|
||||
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++) {
|
||||
if (shader->Shaders[i] == GL_NONE) continue;
|
||||
glDeleteShader(shader->Shaders[i]);
|
||||
}
|
||||
|
||||
glDeleteProgram(shader->Program);
|
||||
}
|
||||
|
||||
void shader_load(std::unique_ptr<Shader>& shader, std::filesystem::path path) {
|
||||
|
||||
assert(std::filesystem::exists(path));
|
||||
|
||||
std::string loadedShaderSource = textFromFile(path);
|
||||
|
||||
for (int i = 0; i < loadedShaderSource.length(); i++) {
|
||||
const char& c = loadedShaderSource[i];
|
||||
if (c == '#') {
|
||||
ShaderPreprocessorDefinition def = { .start = i };
|
||||
int j;
|
||||
for (j = ++i; loadedShaderSource[j] != ' '; j++) {
|
||||
def.key += loadedShaderSource[j];
|
||||
}
|
||||
for (j++; loadedShaderSource[j] != '\n'; j++) {
|
||||
def.def += loadedShaderSource[j];
|
||||
}
|
||||
def.end = j; i = j; // advance i
|
||||
def.def = trim(def.def);
|
||||
def.key = trim(def.key);
|
||||
shader->PreprocessorDefinitions.push_back(def);
|
||||
}
|
||||
}
|
||||
|
||||
// now we have all of the key/value definitions
|
||||
// we can extract the relavent ones, for example
|
||||
// "type"
|
||||
std::vector<const ShaderPreprocessorDefinition*> types = getKeys(shader, "type");
|
||||
int i = 0;
|
||||
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;
|
||||
if (type->def == "fragment") glType = GL_FRAGMENT_SHADER;
|
||||
|
||||
assert(glType != GL_NONE);
|
||||
|
||||
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(shader->Shaders[shader2Index[glType]], 1, &source, &length);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void shader_link(std::unique_ptr<Shader> &shader) {
|
||||
shader->Program = glCreateProgram();
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (shader->Shaders[i] == GL_NONE) continue;
|
||||
|
||||
glCompileShader(shader->Shaders[i]);
|
||||
if (!checkShader(shader->Shaders[i])) continue;
|
||||
|
||||
glAttachShader(shader->Program, shader->Shaders[i]);
|
||||
}
|
||||
|
||||
glLinkProgram(shader->Program);
|
||||
}
|
||||
|
||||
|
||||
void shader_add_attribute(std::unique_ptr<Shader> &shader, const std::string &attribute) {
|
||||
shader->Attributes[attribute] = glGetAttribLocation(shader->Program, attribute.c_str());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,52 +8,37 @@
|
||||
#include <filesystem>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace inferno {
|
||||
namespace inferno::graphics {
|
||||
|
||||
class Shader {
|
||||
public:
|
||||
Shader();
|
||||
~Shader();
|
||||
|
||||
Shader* preprocessorDefine(std::string statement);
|
||||
|
||||
Shader* load(std::filesystem::path path);
|
||||
Shader* link();
|
||||
|
||||
Shader* use();
|
||||
Shader* unUse();
|
||||
|
||||
GLuint getProgram();
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
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 {
|
||||
typedef struct ShaderPreprocessorDefinition {
|
||||
int start, end;
|
||||
std::string key;
|
||||
std::string def;
|
||||
};
|
||||
std::vector<mPreprocessorDefinition> mDefinitions;
|
||||
std::vector<const Shader::mPreprocessorDefinition*> mGetKeys(std::string key);
|
||||
};
|
||||
} shaderpreprocessordefinition;
|
||||
|
||||
|
||||
typedef struct Shader {
|
||||
GLuint Shaders[3];
|
||||
GLuint Program;
|
||||
std::unordered_map<std::string, GLuint> Attributes;
|
||||
std::unordered_map<std::string, GLuint> Uniforms;
|
||||
std::vector<ShaderPreprocessorDefinition> PreprocessorDefinitions;
|
||||
} Shader;
|
||||
|
||||
std::unique_ptr<Shader> shader_create();
|
||||
void shader_cleanup(std::unique_ptr<Shader>& shader);
|
||||
|
||||
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 shader_use(std::unique_ptr<Shader>& shader);
|
||||
void shader_unuse(std::unique_ptr<Shader>& shader);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "yolo/yolo.hpp"
|
||||
|
||||
using namespace inferno::core;
|
||||
using namespace inferno;
|
||||
|
||||
Window::Window() {}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user