From 34cb0fb1c67bf413a290bb631a74a2f8bc81decc Mon Sep 17 00:00:00 2001 From: Ben Date: Sun, 13 Jan 2019 16:27:45 +0000 Subject: [PATCH] Shader abstractions --- OpenGL/cube/cube.a | Bin 83784 -> 56104 bytes OpenGL/cube/src/main.cpp | 81 +++--------------------- OpenGL/cube/src/shader.cpp | 125 +++++++++++++++++++++++++++++++++++++ OpenGL/cube/src/shader.hpp | 38 +++++++++++ 4 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 OpenGL/cube/src/shader.cpp create mode 100644 OpenGL/cube/src/shader.hpp diff --git a/OpenGL/cube/cube.a b/OpenGL/cube/cube.a index 0f82cd6220d1ddc1c9a5d6d1697c4f99f6afe020..fd7ad2fc240194e7ff52f113582ad9a8bd3d060c 100755 GIT binary patch literal 56104 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

4W8UxF28W8GR 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 literal 83784 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 diff --git a/OpenGL/cube/src/main.cpp b/OpenGL/cube/src/main.cpp index 176c372..2fded2a 100644 --- a/OpenGL/cube/src/main.cpp +++ b/OpenGL/cube/src/main.cpp @@ -7,6 +7,8 @@ #include #include +#include "shader.hpp" + void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, @@ -27,71 +29,6 @@ public: bool isWindowClosed = true; }; -std::map VertexShaders; -std::map FragmentShaders; -std::map ShaderPrograms; - -std::string readShader(std::string source) { - std::ifstream t(source); - std::string shaderCode((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - // std::cout << shaderCode << std::endl; - return shaderCode; -} - -bool loadShader(std::string shaderSource, GLenum type, std::string shader) { - const char* source = shaderSource.c_str(); - - if (type == GL_VERTEX_SHADER) { - GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertexShader, 1, &source, NULL); - glCompileShader(vertexShader); - - GLint status; - glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - char buf[512]; - glGetShaderInfoLog(vertexShader, 512, NULL, buf); - std::cerr << buf << std::endl; - return false; - } - - VertexShaders[shader] = vertexShader; - std::cout << "Vertex shader at '" << shader << "' compiled..." << std::endl; - } else if (type == GL_FRAGMENT_SHADER) { - GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragmentShader, 1, &source, NULL); - glCompileShader(fragmentShader); - - GLint status; - glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - char buf[512]; - glGetShaderInfoLog(fragmentShader, 512, NULL, buf); - std::cerr << buf << std::endl; - return false; - } - - FragmentShaders[shader] = fragmentShader; - std::cout << "Fragment shader at '" << shader << "' compiled..." << std::endl; - } - return true; -} - -void makeShaderProgram(std::string vert, std::string frag, std::string program) { - GLuint shaderProgram = glCreateProgram(); - glAttachShader(shaderProgram, VertexShaders[vert]); - glAttachShader(shaderProgram, FragmentShaders[frag]); - ShaderPrograms[program] = shaderProgram; - std::cout << "Shader program '" << program << "' created" << std::endl; -} - -void applyShader(std::string shader) { - glLinkProgram(ShaderPrograms[shader]); - glUseProgram(ShaderPrograms[shader]); - std::cout << "Shader program '" << shader << "' applied" << std::endl; -} - int main(int argc, char** argv) { Game* game = new Game(); SDL_Init(SDL_INIT_EVERYTHING); @@ -152,24 +89,20 @@ int main(int argc, char** argv) { glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * numOfVerticies, vertices, GL_STATIC_DRAW); // Load, compile, apply and link shader programs - if (!loadShader(readShader("shaders/simple.vert"), GL_VERTEX_SHADER , "simpleVert") || - !loadShader(readShader("shaders/simple.frag"), GL_FRAGMENT_SHADER, "simpleFrag")) { - return 0; - } - makeShaderProgram("simpleVert", "simpleFrag", "simpleProc"); - applyShader("simpleProc"); + Shader simpleShader; + simpleShader.load("./shaders/simple").attatch().link().use(); - GLint posAttrib = glGetAttribLocation(ShaderPrograms["simpleProc"], "position"); + GLint posAttrib = glGetAttribLocation(simpleShader.getProgram(), "position"); glEnableVertexAttribArray(posAttrib); glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 5*sizeof(float), 0); - GLint colAttrib = glGetAttribLocation(ShaderPrograms["simpleProc"], "colour"); + GLint colAttrib = glGetAttribLocation(simpleShader.getProgram(), "colour"); glEnableVertexAttribArray(colAttrib); glVertexAttribPointer(colAttrib, 3, GL_FLOAT, GL_FALSE, 5*sizeof(float), (void*)(2*sizeof(float))); - GLint triangleUniColour = glGetUniformLocation(ShaderPrograms["simpleProc"], "triangleColour"); + GLint triangleUniColour = glGetUniformLocation(simpleShader.getProgram(), "triangleColour"); glUniform3f(triangleUniColour, 0.2f, 0.8f, 0.3f); SDL_Event event; diff --git a/OpenGL/cube/src/shader.cpp b/OpenGL/cube/src/shader.cpp new file mode 100644 index 0000000..7b06a61 --- /dev/null +++ b/OpenGL/cube/src/shader.cpp @@ -0,0 +1,125 @@ +#include "shader.hpp" + +#include +#include + +Shader::Shader() { + m_program = glCreateProgram(); +} + +Shader& Shader::use() { + glUseProgram(m_program); + return *this; +} + +Shader& Shader::link() { + glLinkProgram(m_program); + return *this; +} + +Shader& Shader::attatch() { + glAttachShader(m_program, m_vert); + glAttachShader(m_program, m_frag); + return *this; +} + +std::string readShader(std::string source) { + std::ifstream t(source); + std::string shaderCode((std::istreambuf_iterator(t)), + std::istreambuf_iterator()); + return shaderCode; +} + +Shader& Shader::load(GLenum type, std::string sourceLoc) { + const char* source = readShader(sourceLoc).c_str(); + + if (type == GL_VERTEX_SHADER) { + GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(vertexShader, 1, &source, NULL); + glCompileShader(vertexShader); + + glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &m_status); + if (m_status == GL_FALSE) { + char buf[512]; + glGetShaderInfoLog(vertexShader, 512, NULL, buf); + std::cerr << buf << std::endl; + } + + m_vert = vertexShader; + m_vertLoc = sourceLoc; + m_vertSource = (std::string)source; + std::cout << "Vertex shader at '" << sourceLoc << "' compiled..." << std::endl; + } else if (type == GL_FRAGMENT_SHADER) { + GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(fragmentShader, 1, &source, NULL); + glCompileShader(fragmentShader); + + glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &m_status); + if (m_status == GL_FALSE) { + char buf[512]; + glGetShaderInfoLog(fragmentShader, 512, NULL, buf); + std::cerr << buf << std::endl; + } + + m_frag = fragmentShader; + m_fragLoc = sourceLoc; + m_fragSource = (std::string)source; + std::cout << "Fragment shader at '" << sourceLoc << "' compiled..." << std::endl; + } + return *this; +} + +Shader& Shader::load(std::string sourceLoc) { + m_vertLoc = sourceLoc + ".vert"; + m_fragLoc = sourceLoc + ".frag"; + + m_vertSource = readShader(m_vertLoc); + m_fragSource = readShader(m_fragLoc); + + m_vert = glCreateShader(GL_VERTEX_SHADER); + m_frag = glCreateShader(GL_FRAGMENT_SHADER); + + const char* vertSource = m_vertSource.c_str(); + glShaderSource(m_vert, 1, &vertSource, NULL); + glCompileShader(m_vert); + + const char* fragSource = m_fragSource.c_str(); + glShaderSource(m_frag, 1, &fragSource, NULL); + glCompileShader(m_frag); + + glGetShaderiv(m_vert, GL_COMPILE_STATUS, &m_status); + if (m_status == GL_FALSE) { + char buf[512]; + glGetShaderInfoLog(m_vert, 512, NULL, buf); + std::cerr << buf << std::endl; + } + + glGetShaderiv(m_frag, GL_COMPILE_STATUS, &m_status); + if (m_status == GL_FALSE) { + char buf[512]; + glGetShaderInfoLog(m_frag, 512, NULL, buf); + std::cerr << buf << std::endl; + } + + std::cout << "Vertex shader at '" << m_vertLoc << "' compiled..." << std::endl; + std::cout << "Fragment shader at '" << m_fragLoc << "' compiled..." << std::endl; + return *this; +} + +GLuint Shader::getProgram() { + return m_program; +} + +GLuint Shader::getVertex() { + return m_vert; +} + +GLuint Shader::getFragment() { + return m_frag; +} + +Shader::~Shader() { + glDeleteProgram(m_program); + glDeleteShader(m_vert); + glDeleteShader(m_frag); +} diff --git a/OpenGL/cube/src/shader.hpp b/OpenGL/cube/src/shader.hpp new file mode 100644 index 0000000..5db2c51 --- /dev/null +++ b/OpenGL/cube/src/shader.hpp @@ -0,0 +1,38 @@ +#ifndef _SHADER_H_ +#define _SHADER_H_ + +#include +#include + +class Shader { +public: + Shader(); + + Shader& use(); + Shader& link(); + Shader& attatch(); + Shader& load(GLenum type, std::string sourceLoc); + Shader& load(std::string sourceLoc); + + GLuint getProgram(); + GLuint getVertex(); + GLuint getFragment(); + + virtual ~Shader(); +private: + Shader(Shader const &) = delete; + Shader & operator=(Shader const &) = delete; + + GLuint m_program; + GLuint m_vert; + GLuint m_frag; + + std::string m_vertSource; + std::string m_fragSource; + std::string m_vertLoc; + std::string m_fragLoc; + + GLint m_status; +}; + +#endif