From 7c8a0c99a4e830564d53ee41e2cd8b27a57afb1d Mon Sep 17 00:00:00 2001 From: Riyyi Date: Sat, 21 Dec 2019 14:54:59 +0100 Subject: [PATCH] Add Shader class --- assets/glsl/simple.frag | 10 ++ assets/glsl/simple.vert | 11 ++ inferno/src/inferno/render/shader.cpp | 140 ++++++++++++++++++++++++++ inferno/src/inferno/render/shader.h | 41 ++++++++ 4 files changed, 202 insertions(+) create mode 100644 assets/glsl/simple.frag create mode 100644 assets/glsl/simple.vert create mode 100644 inferno/src/inferno/render/shader.cpp create mode 100644 inferno/src/inferno/render/shader.h diff --git a/assets/glsl/simple.frag b/assets/glsl/simple.frag new file mode 100644 index 0000000..9c82fcc --- /dev/null +++ b/assets/glsl/simple.frag @@ -0,0 +1,10 @@ +#version 450 core + +layout(location = 0) out vec4 color; + +in vec3 position; + +void main() +{ + color = vec4(position * 0.5f + 0.5f, 1.0f); +} diff --git a/assets/glsl/simple.vert b/assets/glsl/simple.vert new file mode 100644 index 0000000..da47089 --- /dev/null +++ b/assets/glsl/simple.vert @@ -0,0 +1,11 @@ +#version 450 core + +layout(location = 0) in vec3 a_position; + +out vec3 position; + +void main() +{ + position = a_position; + gl_Position = vec4(a_position, 1.0f); +} diff --git a/inferno/src/inferno/render/shader.cpp b/inferno/src/inferno/render/shader.cpp new file mode 100644 index 0000000..a2d5054 --- /dev/null +++ b/inferno/src/inferno/render/shader.cpp @@ -0,0 +1,140 @@ +#include // std::vector + +#include + +#include "inferno/core.h" +#include "inferno/file.h" +#include "inferno/log.h" +#include "inferno/render/shader.h" + +namespace Inferno { + + Shader::Shader(const std::string &vertexSource, const std::string &fragmentSource) : + m_program(0) + { + // Get file contents + std::string vertexSrc = File::read(vertexSource); + std::string fragmentSrc = File::read(fragmentSource); + + // Compile shaders + uint32_t vertexID = compileShader(GL_VERTEX_SHADER, vertexSrc.c_str()); + uint32_t fragmentID = compileShader(GL_FRAGMENT_SHADER, fragmentSrc.c_str()); + + // Link shaders + if (vertexID > 0 && fragmentID > 0) { + m_program = linkShader(vertexID, fragmentID); + } + // Clear resources + else if (vertexID > 0) glDeleteShader(vertexID); + else if (fragmentID > 0) glDeleteShader(fragmentID); + } + + Shader::~Shader() + { + if (m_program > 0) { + glDeleteProgram(m_program); + m_program = 0; + } + } + +// ----------------------------------------- + + void Shader::bind() const + { + glUseProgram(m_program); + } + + void Shader::unbind() const + { + glUseProgram(0); + } + +// ----------------------------------------- + + uint32_t Shader::getProgram() const + { + return m_program; + } + +// ----------------------------------------- + + uint32_t Shader::compileShader(int32_t type, const char* source) const + { + // Create new shader + uint32_t shader = 0; + shader = glCreateShader(type); + // Attach shader source to shader object + glShaderSource(shader, 1, &source, nullptr); + // Compile shader + glCompileShader(shader); + + // Check compilation status + if (checkStatus(shader) == GL_TRUE) { + return shader; + } + + // On fail + glDeleteShader(shader); + return 0; + } + + uint32_t Shader::linkShader(uint32_t vertex, uint32_t fragment) const + { + // Create new shader program + uint32_t shaderProgram = 0; + shaderProgram = glCreateProgram(); + // Attach both shaders to the shader program + glAttachShader(shaderProgram, vertex); + glAttachShader(shaderProgram, fragment); + // Setup vertex attributes + glBindAttribLocation(shaderProgram, 0, "a_position"); + // Link the shaders + glLinkProgram(shaderProgram); + // Clear resources + glDeleteShader(vertex); + glDeleteShader(fragment); + + // Check linking status + if (checkStatus(shaderProgram, true) == GL_TRUE) { + return shaderProgram; + } + + // On fail + glDeleteProgram(shaderProgram); + return 0; + } + + int32_t Shader::checkStatus(uint32_t check, bool isProgram) const + { + int32_t success; + int32_t maxLength = 0; + std::vector infoLog; + + // Get the compilation/linking status + !isProgram + ? glGetShaderiv(check, GL_COMPILE_STATUS, &success) + : glGetProgramiv(check, GL_LINK_STATUS, &success); + + if (success != GL_TRUE) { + // Get max length of the log including \0 terminator + !isProgram + ? glGetShaderiv(check, GL_INFO_LOG_LENGTH, &maxLength) + : glGetProgramiv(check, GL_INFO_LOG_LENGTH, &maxLength); + + // Reserve data for the log + infoLog.reserve(maxLength); + + // Retrieve the error message + !isProgram + ? glGetShaderInfoLog(check, maxLength, nullptr, &infoLog[0]) + : glGetProgramInfoLog(check, maxLength, nullptr, &infoLog[0]); + + NF_CORE_WARN("Shader %s", infoLog.data()); + } + + NF_CORE_ASSERT(success == GL_TRUE, "Shader program creation failed!") + + return success; + } + +} diff --git a/inferno/src/inferno/render/shader.h b/inferno/src/inferno/render/shader.h new file mode 100644 index 0000000..351031c --- /dev/null +++ b/inferno/src/inferno/render/shader.h @@ -0,0 +1,41 @@ +#ifndef SHADER_H +#define SHADER_H + +#define INFO_LOG_SIZE 512 + +#include // std::int32_t, std::uint32_t +#include // std::string + +#include + +namespace Inferno { + + class Shader { + public: + Shader(const std::string &vertexSource, const std::string &fragmentSource); + ~Shader(); + +// ----------------------------------------- + + void bind() const; + void unbind() const; + +// ----------------------------------------- + + uint32_t getProgram() const; + +// ----------------------------------------- + + protected: + uint32_t compileShader(int32_t type, const char* shaderSource) const; + uint32_t linkShader(uint32_t vertex, uint32_t fragment) const; + int32_t checkStatus(uint32_t check, bool isProgram = false) const; + + private: + uint32_t m_program; + }; + +} + + +#endif // SHADER_H