From ff4daae11db0ab811cac66e262d289a4107bba4a Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 27 Dec 2017 23:48:41 +0100 Subject: Add uniform (shader global variable) --- include/RenderBackend/OpenGL/PixelShader.hpp | 2 + include/RenderBackend/OpenGL/ShaderProgram.hpp | 8 ++++ include/RenderBackend/OpenGL/ShaderVec.hpp | 56 +++++++++++++++++++++++++- src/RenderBackend/OpenGL/PixelShader.cpp | 18 +++++++++ src/RenderBackend/OpenGL/ShaderProgram.cpp | 21 ++++++++++ src/RenderBackend/OpenGL/ShaderVec.cpp | 6 +++ src/main.cpp | 28 ++++++++++--- 7 files changed, 133 insertions(+), 6 deletions(-) diff --git a/include/RenderBackend/OpenGL/PixelShader.hpp b/include/RenderBackend/OpenGL/PixelShader.hpp index e025c6f..6794fb1 100644 --- a/include/RenderBackend/OpenGL/PixelShader.hpp +++ b/include/RenderBackend/OpenGL/PixelShader.hpp @@ -54,6 +54,7 @@ namespace amalgine const std::string& getOutputAttributeName(i32 attributeIndex); ShaderOutputVec4 defineOutputVec4(const std::string &name); + ShaderGlobalVec3 defineGlobalVec3(const std::string &name); void defineMain(PixelShaderMainFunc mainFunc); void assign(const ShaderOutputVec4 &lhsVariable, const ShaderVec4 &rhsVariable); @@ -75,6 +76,7 @@ namespace amalgine i32 maxPixelAttribs; // Could make this static std::unordered_map pixelAttributes; std::vector pixelAttributeNames; + std::unordered_map globalAttributes; bool mainFuncDefined; }; } diff --git a/include/RenderBackend/OpenGL/ShaderProgram.hpp b/include/RenderBackend/OpenGL/ShaderProgram.hpp index 2b1c5b4..c8740f8 100644 --- a/include/RenderBackend/OpenGL/ShaderProgram.hpp +++ b/include/RenderBackend/OpenGL/ShaderProgram.hpp @@ -3,6 +3,7 @@ #include "../../Result.hpp" #include "../../types.hpp" #include "../../utils.hpp" +#include "ShaderVec.hpp" #include #include @@ -19,6 +20,12 @@ namespace amalgine ShaderProgramUsedBeforeBuilt(); }; + class ShaderProgramNonExistingGlobalVariable : public std::runtime_error + { + public: + ShaderProgramNonExistingGlobalVariable(const char *variableName); + }; + class ShaderProgram { DISABLE_COPY(ShaderProgram) @@ -31,6 +38,7 @@ namespace amalgine Result build(); void use(); + ShaderProgramGlobalVec3 getGlobalVec3(const char *name); private: u32 shaderProgramId; bool built; diff --git a/include/RenderBackend/OpenGL/ShaderVec.hpp b/include/RenderBackend/OpenGL/ShaderVec.hpp index a5163ba..7c14af1 100644 --- a/include/RenderBackend/OpenGL/ShaderVec.hpp +++ b/include/RenderBackend/OpenGL/ShaderVec.hpp @@ -8,15 +8,60 @@ namespace amalgine { class VertexShader; class PixelShader; + class ShaderProgram; enum class AttributeType { NONE, - VEC2 + VEC2, + VEC3, + VEC4 }; AttributeType getAttributeTypeByName(const char *attributeName); + class ShaderGlobalVec + { + friend class VertexShader; + friend class PixelShader; + friend class ShaderGlobalVec3; + public: + ShaderGlobalVec() : attributeType(AttributeType::NONE) {} + const std::string& getName() const { return name; } + AttributeType getAttributeType() const { return attributeType; } + protected: + ShaderGlobalVec(const std::string &_name, AttributeType _attributeType) : name(_name), attributeType(_attributeType) {} + private: + std::string name; + AttributeType attributeType; + }; + + class ShaderGlobalVec3 + { + friend class VertexShader; + friend class PixelShader; + public: + const std::string& getName() const { return globalVec.getName(); } + AttributeType getAttributeType() const { return globalVec.getAttributeType(); } + ShaderGlobalVec getVecObject() const { return globalVec; } + private: + ShaderGlobalVec3(const std::string &_name) : globalVec(_name, AttributeType::VEC3) {} + private: + ShaderGlobalVec globalVec; + }; + + class ShaderProgramGlobalVec3 + { + friend class ShaderProgram; + public: + void set(f32 x = 0.0f, f32 y = 0.0f, f32 z = 0.0f); + private: + ShaderProgramGlobalVec3(ShaderProgram *_shaderProgram, i32 _uniformId) : shaderProgram(_shaderProgram), uniformId(_uniformId){} + private: + ShaderProgram *shaderProgram; + i32 uniformId; + }; + class ShaderInputVec2 { friend class VertexShader; @@ -62,6 +107,15 @@ namespace amalgine result += ")"; } + ShaderVec4(const ShaderGlobalVec3 &vec3, f32 w = 0.0f) + { + result = "vec4("; + result += vec3.getName(); + result += ", "; + result += std::to_string(w); + result += ")"; + } + const std::string& getOutput() const { return result; diff --git a/src/RenderBackend/OpenGL/PixelShader.cpp b/src/RenderBackend/OpenGL/PixelShader.cpp index 8aa4d9a..f263513 100644 --- a/src/RenderBackend/OpenGL/PixelShader.cpp +++ b/src/RenderBackend/OpenGL/PixelShader.cpp @@ -49,6 +49,24 @@ namespace amalgine return ShaderOutputVec4(this, attributeIndex); } + // TODO: Generate warning if global variable is defined but not assigned to? + ShaderGlobalVec3 PixelShader::defineGlobalVec3(const std::string &name) + { + if(!isShaderVariableNameValid(name.c_str())) + throw PixelShaderInvalidAttributeName(name); + + if(globalAttributes.find(name) != globalAttributes.end()) + throw PixelShaderAttributeAlreadyDefined(name); + + writeHeader("uniform vec3 "); + writeHeader(name); + writeHeader(";\n"); + + ShaderGlobalVec3 globalVec(name); + globalAttributes[name] = globalVec.getVecObject(); + return ShaderGlobalVec3(globalVec); + } + i32 PixelShader::defineOutputVariable(const string &variableName, const char *typeName) { if(!isShaderVariableNameValid(variableName.c_str())) diff --git a/src/RenderBackend/OpenGL/ShaderProgram.cpp b/src/RenderBackend/OpenGL/ShaderProgram.cpp index 40f5b6c..aceda3b 100644 --- a/src/RenderBackend/OpenGL/ShaderProgram.cpp +++ b/src/RenderBackend/OpenGL/ShaderProgram.cpp @@ -12,6 +12,12 @@ namespace amalgine } + ShaderProgramNonExistingGlobalVariable::ShaderProgramNonExistingGlobalVariable(const char *variableName) : + runtime_error(string("There is no shader global variable with the name '") + variableName + "'") + { + + } + ShaderProgram::ShaderProgram() : built(false) { shaderProgramId = glCreateProgram(); @@ -84,4 +90,19 @@ namespace amalgine throw ShaderProgramUsedBeforeBuilt(); } } + + ShaderProgramGlobalVec3 ShaderProgram::getGlobalVec3(const char *name) + { + if(built) + { + GLint uniformId = glGetUniformLocation(shaderProgramId, name); + if(uniformId == -1) + throw ShaderProgramNonExistingGlobalVariable(name); + return ShaderProgramGlobalVec3(this, uniformId); + } + else + { + throw ShaderProgramUsedBeforeBuilt(); + } + } } diff --git a/src/RenderBackend/OpenGL/ShaderVec.cpp b/src/RenderBackend/OpenGL/ShaderVec.cpp index 3bbe0be..dd3bbe5 100644 --- a/src/RenderBackend/OpenGL/ShaderVec.cpp +++ b/src/RenderBackend/OpenGL/ShaderVec.cpp @@ -20,6 +20,12 @@ namespace amalgine return AttributeType::NONE; } + void ShaderProgramGlobalVec3::set(f32 x, f32 y, f32 z) + { + shaderProgram->use(); + glUniform3f(uniformId, x, y, z); + } + const string& ShaderInputVec2::getName() const { return vertexShader->getInputAttributeName(attributeIndex); diff --git a/src/main.cpp b/src/main.cpp index a04fb99..ada75e2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ using namespace amalgine; using namespace std; +void glfwErrorHandler(int errorCode, const char *errorDescription); void initGlfw(); void initGlew(); GLFWwindow *createWindow(); @@ -26,6 +27,7 @@ CompiledPixelShader* createPixelShader(); int main() { initGlfw(); + glfwSetErrorCallback(glfwErrorHandler); GLFWwindow *window = createWindow(); DeviceFrame frame; @@ -35,10 +37,9 @@ int main() Vertex2D(0.5f, -0.5f), Vertex2D(-0.5f, -0.5f) ); - + DataView cpuTriangles(&cpuTriangle, 1); DeviceMemory *gpuTriangle = frame.alloc(); - DataView triangles(&cpuTriangle, 1); - gpuTriangle->copy(triangles, DeviceMemory::StorageType::STATIC); + gpuTriangle->copy(cpuTriangles, DeviceMemory::StorageType::STATIC); CompiledVertexShader *vertexShader = createVertexShader(*gpuTriangle); CompiledPixelShader *pixelShader = createPixelShader(); @@ -46,7 +47,13 @@ int main() ShaderProgram shaderProgram; shaderProgram.setVertexShader(vertexShader); shaderProgram.setPixelShader(pixelShader); + // Make ShaderProgram.build return an object which we can do things on? since some operations + // require the shader to be built to be used Result shaderBuildResult = shaderProgram.build(); + + ShaderProgramGlobalVec3 triangleColor = shaderProgram.getGlobalVec3("triangleColor"); + triangleColor.set(1.0f, 0.0f, 0.0f); + if(!shaderBuildResult) { fprintf(stderr, "Failed to build shader program: %s\n", shaderBuildResult.getErrorMsg().c_str()); @@ -59,6 +66,10 @@ int main() if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, GL_TRUE); + // Set color for clearing + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + // Do the actual screen clearing, using the color set using glClearColor + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shaderProgram.use(); frame.draw(); glfwSwapBuffers(window); @@ -68,6 +79,11 @@ int main() return 0; } +void glfwErrorHandler(int errorCode, const char *errorDescription) +{ + printf("GLFW error code: %d, description: %s\n", errorCode, errorDescription); +} + void initGlfw() { if(!glfwInit()) @@ -107,6 +123,7 @@ GLFWwindow* createWindow() glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); glfwMakeContextCurrent(window); + glfwSwapInterval(0); initGlew(); return window; } @@ -135,11 +152,12 @@ CompiledVertexShader* createVertexShader(const DeviceMemory &inputData) CompiledPixelShader* createPixelShader() { PixelShader pixelShader; + ShaderGlobalVec3 triangleColor = pixelShader.defineGlobalVec3("triangleColor"); ShaderOutputVec4 outColor = pixelShader.defineOutputVec4("outColor"); - pixelShader.defineMain([&outColor]() + pixelShader.defineMain([&triangleColor, &outColor]() { - outColor = ShaderVec4(1.0f, 1.0f, 1.0f, 1.0f); + outColor = ShaderVec4(triangleColor, 1.0f); }); Result compiledPixelShader = pixelShader.compile(); -- cgit v1.2.3