From b27321336baf553fba66784c6e4c28e5b0221b49 Mon Sep 17 00:00:00 2001 From: Selim Mustafaev Date: Sat, 7 May 2016 20:20:59 +0300 Subject: [PATCH] refactoring loading shaders --- src/OGL.cpp | 6 +++ src/Shaders/Shader.cpp | 61 ++++++++++++++++++++++++++++ src/Shaders/Shader.h | 23 +++++++++++ src/Shaders/ShaderProgram.cpp | 75 ++++++++--------------------------- src/Shaders/ShaderProgram.h | 9 +---- src/utils.cpp | 28 +++++++++++++ src/utils.h | 11 +++++ 7 files changed, 146 insertions(+), 67 deletions(-) create mode 100644 src/Shaders/Shader.cpp create mode 100644 src/Shaders/Shader.h create mode 100644 src/utils.cpp create mode 100644 src/utils.h diff --git a/src/OGL.cpp b/src/OGL.cpp index 92aa970..0d09eaf 100644 --- a/src/OGL.cpp +++ b/src/OGL.cpp @@ -1,5 +1,6 @@ #include "OGL.h" #include "Camera.h" +#include "utils.h" #include #include @@ -122,6 +123,11 @@ void OGL::init() { throw new std::runtime_error(errMsg); } + // even successful call to glewInit() may cause setting global error GL_INVALID_ENUM, + // so we need clear it in order to use glGetError() later + // https://www.opengl.org/wiki/OpenGL_Loading_Library#GLEW_.28OpenGL_Extension_Wrangler.29 + utils::clearGLError(); + glEnable(GL_DEPTH_TEST); glClearDepth(1.0); glDepthFunc(GL_LEQUAL); diff --git a/src/Shaders/Shader.cpp b/src/Shaders/Shader.cpp new file mode 100644 index 0000000..ecaf101 --- /dev/null +++ b/src/Shaders/Shader.cpp @@ -0,0 +1,61 @@ +#include "Shader.h" +#include "../utils.h" +#include +#include +#include +#include +#include + +Shader::Shader(GLenum type, const std::string& path): _path(path), _type(type), _shader(0) { +} + +void Shader::compile() { + std::ifstream is(_path, std::ios::binary); + if(is) { + std::ostringstream ss; + ss << is.rdbuf(); + std::string text = ss.str(); + + _shader = glCreateShader(_type); + utils::throwIfGLError("error creating shader"); + + const GLchar* textBuffer = text.c_str(); + glShaderSource(_shader, 1, &textBuffer, nullptr); + utils::throwIfGLError("error setting shader source"); + + glCompileShader(_shader); + utils::throwIfGLError("error compiling shader"); + + GLint success = GL_TRUE; + glGetShaderiv(_shader, GL_COMPILE_STATUS, &success); + if(success == GL_FALSE) { + logCompileError(); + throw std::runtime_error("error compiling shader: " + _path); + } + } else { + throw std::runtime_error("error opening file: " + _path); + } +} + +Shader::operator GLuint() const { + return _shader; +} + +Shader::~Shader() { + glDeleteShader(_shader); +} + +void Shader::logCompileError() { + std::cout << "shader: " << _shader << std::endl; + GLint logSize = 0; + glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &logSize); + std::cout << "log length: " << logSize << std::endl; + + auto log = std::make_unique(logSize); + memset(log.get(), 0, (size_t)logSize); + + glGetShaderInfoLog(_shader, logSize, &logSize, log.get()); + std::cout << "log: " << log.get() << std::endl; +} + + diff --git a/src/Shaders/Shader.h b/src/Shaders/Shader.h new file mode 100644 index 0000000..dd253b9 --- /dev/null +++ b/src/Shaders/Shader.h @@ -0,0 +1,23 @@ +#ifndef GLTEST_SHADER_H +#define GLTEST_SHADER_H + +#include +#include + +class Shader { +private: + std::string _path; + GLenum _type; + GLuint _shader; + +public: + Shader(GLenum type, const std::string& path); + void compile(); + operator GLuint() const; + ~Shader(); + +private: + void logCompileError(); +}; + +#endif //GLTEST_SHADER_H diff --git a/src/Shaders/ShaderProgram.cpp b/src/Shaders/ShaderProgram.cpp index e9998bb..ccf9cfb 100644 --- a/src/Shaders/ShaderProgram.cpp +++ b/src/Shaders/ShaderProgram.cpp @@ -1,52 +1,27 @@ #include #include #include "ShaderProgram.h" +#include "Shader.h" +#include "../utils.h" -ShaderProgram::ShaderProgram(const char* vertexShaderPath, const char* fragmentShaderPath) { - FILE* f = fopen(vertexShaderPath, "rb"); - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - _vertexShaderText = new char[fsize + 1]; - fread(_vertexShaderText, fsize, 1, f); - fclose(f); - _vertexShaderText[fsize] = 0; - - _vertexShader = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(_vertexShader, 1, (const GLchar**)&_vertexShaderText, nullptr); - glCompileShader(_vertexShader); - - GLint success = GL_TRUE; - glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &success); - if(success == GL_FALSE) { - std::cout << "error compilling vertex shader" << std::endl; - logCompileError(_vertexShader); - } - - f = fopen(fragmentShaderPath, "rb"); - fseek(f, 0, SEEK_END); - fsize = ftell(f); - fseek(f, 0, SEEK_SET); - _fragmentShaderText = new char[fsize + 1]; - fread(_fragmentShaderText, fsize, 1, f); - fclose(f); - _fragmentShaderText[fsize] = 0; - - _fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(_fragmentShader, 1,(const GLchar**)&_fragmentShaderText, nullptr); - glCompileShader(_fragmentShader); - - glGetShaderiv(_fragmentShader, GL_COMPILE_STATUS, &success); - if(success == GL_FALSE) { - std::cout << "error compilling fragment shader" << std::endl; - logCompileError(_fragmentShader); - } +ShaderProgram::ShaderProgram(const std::string& vertexShaderPath, const std::string& fragmentShaderPath) { + Shader vShader(GL_VERTEX_SHADER, vertexShaderPath); + Shader fShader(GL_FRAGMENT_SHADER, fragmentShaderPath); + vShader.compile(); + fShader.compile(); _program = glCreateProgram(); - glAttachShader(_program, _vertexShader); - glAttachShader(_program, _fragmentShader); + if(_program == 0) { + throw std::runtime_error("error creating shader program"); + } + + glAttachShader(_program, vShader); + utils::throwIfGLError("error attaching vertex shader to program"); + glAttachShader(_program, fShader); + utils::throwIfGLError("error attaching fragment shader to program"); glLinkProgram(_program); + utils::throwIfGLError("error linking program"); } void ShaderProgram::use() const { @@ -54,26 +29,8 @@ void ShaderProgram::use() const { } ShaderProgram::~ShaderProgram() { - delete[] _vertexShaderText; - delete[] _fragmentShaderText; - - glDeleteShader(_vertexShader); - glDeleteShader(_fragmentShader); } ShaderProgram::operator GLuint() const { return _program; } - -void ShaderProgram::logCompileError(GLuint shader) { - std::cout << "shader: " << shader << std::endl; - GLint logSize = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logSize); - std::cout << "log length: " << logSize << std::endl; - - GLchar* log = new GLchar[logSize]; - memset(log, 0, (size_t)logSize); - - glGetShaderInfoLog(shader, logSize, &logSize, log); - std::cout << "log: " << log << std::endl; -} diff --git a/src/Shaders/ShaderProgram.h b/src/Shaders/ShaderProgram.h index e16d438..735d390 100644 --- a/src/Shaders/ShaderProgram.h +++ b/src/Shaders/ShaderProgram.h @@ -8,19 +8,12 @@ class ShaderProgram { private: GLuint _program; - GLuint _vertexShader; - GLuint _fragmentShader; - char* _vertexShaderText; - char* _fragmentShaderText; public: - ShaderProgram(const char* vertexShaderPath, const char* fragmentShaderPath); + ShaderProgram(const std::string& vertexShaderPath, const std::string& fragmentShaderPath); void use() const; operator GLuint() const; ~ShaderProgram(); - -private: - void logCompileError(GLuint shader); }; diff --git a/src/utils.cpp b/src/utils.cpp new file mode 100644 index 0000000..0511c29 --- /dev/null +++ b/src/utils.cpp @@ -0,0 +1,28 @@ +#include "utils.h" +#include +#include + +namespace utils { + void throwIfGLError(const std::string& msg) { + std::string err; + while(true) { + GLenum error = glGetError(); + if(error != GL_NO_ERROR) { + const char* errorStr = (const char*)gluErrorString(error); + if(errorStr) { + err += std::string(errorStr) + "\n"; + } + } else { + break; + } + } + + if(!err.empty()) { + throw std::runtime_error(msg + ": " + err); + } + } + + void clearGLError() { + while(glGetError() != GL_NO_ERROR); + } +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..a21565c --- /dev/null +++ b/src/utils.h @@ -0,0 +1,11 @@ +#ifndef GLTEST_UTILS_H +#define GLTEST_UTILS_H + +#include + +namespace utils { + void throwIfGLError(const std::string& msg); + void clearGLError(); +} + +#endif //GLTEST_UTILS_H