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 <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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#include "yolo/yolo.hpp"
|
#include "yolo/yolo.hpp"
|
||||||
|
|
||||||
using namespace inferno::core;
|
using namespace inferno;
|
||||||
|
|
||||||
Window::Window() {}
|
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
|
#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);
|
||||||
|
|||||||
Reference in New Issue
Block a user