diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-11-04 00:50:45 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-11-18 15:21:48 +0100 |
commit | 23a37b2cdd8ffde8bb85a4159888bf3a7ec35966 (patch) | |
tree | 83db7b81936621b6a2435e9b5db0de18496cd12f | |
parent | fbd2e5d9a802db4fb5e056705ec599ac423e09be (diff) |
Use external shaders instead of generating shader code from c++ code...
24 files changed, 217 insertions, 901 deletions
diff --git a/include/RenderBackend/OpenGL/CommonShader.hpp b/include/RenderBackend/OpenGL/CommonShader.hpp deleted file mode 100644 index 80e63a9..0000000 --- a/include/RenderBackend/OpenGL/CommonShader.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "../../types.hpp" -#include <string> - -namespace amalgine -{ - struct ShaderAttribute - { - std::string name; - const char *typeName; - }; - - static bool isAlpha(char c) - { - return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); - } - - static bool isDigit(char c) - { - return c >= '0' && c <= '9'; - } - - static bool isShaderVariableNameValid(const char *variableName) - { - const char *p = &variableName[0]; - if(isAlpha(*p) || *p == '_') - { - ++p; - while(true) - { - char c = *p; - if(c == '\0') - return true; - else if(isAlpha(c) || isDigit(c) || c == '_') - ++p; - } - } - - return false; - } - - std::string getShaderCompileLog(u32 shaderId); -} diff --git a/include/RenderBackend/OpenGL/CompiledShader.hpp b/include/RenderBackend/OpenGL/CompiledShader.hpp deleted file mode 100644 index 8d2ee84..0000000 --- a/include/RenderBackend/OpenGL/CompiledShader.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "../../types.hpp" -#include <unordered_map> -#include <string> - -namespace amalgine -{ - class CompiledVertexShader - { - friend class VertexShader; - public: - ~CompiledVertexShader(); - u32 getShaderId() const; - private: - CompiledVertexShader(u32 _shaderId); - private: - u32 shaderId; - }; - - class CompiledPixelShader - { - friend class PixelShader; - public: - ~CompiledPixelShader(); - u32 getShaderId() const; - const auto& getPixelAttributes() const - { - return pixelAttributes; - } - private: - CompiledPixelShader(u32 _shaderId, std::unordered_map<std::string, i32> &&_pixelAttributes); - private: - u32 shaderId; - std::unordered_map<std::string, i32> pixelAttributes; - }; -} diff --git a/include/RenderBackend/OpenGL/DeviceFrame.hpp b/include/RenderBackend/OpenGL/DeviceFrame.hpp index 12e578a..f10af4c 100644 --- a/include/RenderBackend/OpenGL/DeviceFrame.hpp +++ b/include/RenderBackend/OpenGL/DeviceFrame.hpp @@ -7,6 +7,7 @@ namespace amalgine { class DeviceMemory; + class ShaderProgram; class DeviceFrame { @@ -16,7 +17,7 @@ namespace amalgine ~DeviceFrame(); DeviceMemory* alloc(); - void draw(); + void draw(ShaderProgram *shader); private: u32 vertexArrayObjectId; std::vector<DeviceMemory*> buffers; diff --git a/include/RenderBackend/OpenGL/DeviceMemory.hpp b/include/RenderBackend/OpenGL/DeviceMemory.hpp index c37acfb..c9c8b23 100644 --- a/include/RenderBackend/OpenGL/DeviceMemory.hpp +++ b/include/RenderBackend/OpenGL/DeviceMemory.hpp @@ -3,21 +3,19 @@ #include "../../DataView.hpp" #include "../../utils.hpp" #include "../../Triangle2D.hpp" -#include <stdexcept> -namespace amalgine -{ - class DeviceMemoryEmpty : public std::runtime_error - { - public: - DeviceMemoryEmpty(const std::string &errMsg) : std::runtime_error(errMsg) {} +namespace amalgine { + enum class DeviceMemoryType { + NONE, + VEC2, + VEC3 }; - + class DeviceMemory { DISABLE_COPY(DeviceMemory) friend class DeviceFrame; - friend class ShaderInputVec2; + friend class ShaderProgram; public: enum class StorageType { @@ -40,13 +38,15 @@ namespace amalgine //void copy(const DataView<f32> &data, StorageType storageType, PrimitiveType primitiveType = PrimitiveType::TRIANGLE); void copy(const DataView<Triangle2D> &triangles, StorageType storageType); void draw(); + + DeviceMemoryType get_type() const { return type; } private: DeviceMemory(); - void operator delete(void *data); void use() const; private: u32 vertexBufferObjectId; u32 primitiveType; u32 numVertices; + DeviceMemoryType type; }; } diff --git a/include/RenderBackend/OpenGL/PixelShader.hpp b/include/RenderBackend/OpenGL/PixelShader.hpp deleted file mode 100644 index ebe5a12..0000000 --- a/include/RenderBackend/OpenGL/PixelShader.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "Shader.hpp" - -namespace amalgine { - class CompiledPixelShader; - - using PixelShaderMainFunc = std::function<void()>; - - class PixelShader : public Shader - { - DISABLE_COPY(PixelShader) - friend class ShaderProgram; - public: - PixelShader(); - - void defineMain(PixelShaderMainFunc mainFunc); - Result<CompiledPixelShader*> compile(); - }; -} diff --git a/include/RenderBackend/OpenGL/Shader.hpp b/include/RenderBackend/OpenGL/Shader.hpp index 7aecc4e..0f802ec 100644 --- a/include/RenderBackend/OpenGL/Shader.hpp +++ b/include/RenderBackend/OpenGL/Shader.hpp @@ -1,79 +1,26 @@ #pragma once -#include "../../DataView.hpp" -#include "../../utils.hpp" #include "../../Result.hpp" -#include "CommonShader.hpp" -#include "ShaderVec.hpp" -#include <string> -#include <unordered_map> -#include <vector> -#include <stdexcept> -#include <functional> +#include "../../utils.hpp" +#include "../../types.hpp" +#include <memory> namespace amalgine { - class ShaderTooManyAttributes : public std::runtime_error - { - public: - ShaderTooManyAttributes(i32 maxAttributes); - }; - - class ShaderAttributeAlreadyDefined : public std::runtime_error - { - public: - ShaderAttributeAlreadyDefined(const std::string &attributeName); - }; - - class ShaderInvalidAttributeName : public std::runtime_error - { - public: - ShaderInvalidAttributeName(const std::string &attributeName); - }; - - class ShaderFunctionAlreadyDefined : public std::runtime_error - { - public: - ShaderFunctionAlreadyDefined(const std::string &funcName); - }; - class Shader { DISABLE_COPY(Shader) friend class ShaderProgram; public: - Shader(); - - const std::string& getOutputAttributeName(i32 attributeIndex); - const std::string& getInputAttributeName(i32 attributeIndex) const; - AttributeType getInputAttributeType(i32 attributeIndex) const; - ShaderOutputVec4 defineOutputVec4(const std::string &name); - ShaderGlobalVec3 defineGlobalVec3(const std::string &name); - ShaderInputVec2 defineInputVec2(const std::string &name); - i32 defineInputVariable(const std::string &variableName, const char *typeName); - - void assign(const ShaderOutputVec4 &lhsVariable, const ShaderVec4 &rhsVariable); - protected: - void writeHeader(const std::string &code); - void writeBody(const std::string &code); - std::string build() const; - - /* - * Throws ShaderTooManyAttributes if too many attributes are defined for the platform. - * Throws ShaderAttributeAlreadyDefined if a attribute with the same name has already been defined. - */ - i32 defineOutputVariable(const std::string &variableName, const char *typeName); - protected: - std::string header; - std::string body; - int inputLocationCounter; - int outputLocationCounter; - // TOOD: Verify if this is correct. This same variable is used for both output and input variables - i32 maxAttribs; // Could make this static - std::unordered_map<std::string, i32> inputAttributes; - std::vector<ShaderAttribute> inputAttributeNames; - std::unordered_map<std::string, i32> outputAttributes; - std::vector<ShaderAttribute> outputAttributeNames; - std::unordered_map<std::string, ShaderGlobalVec> uniforms; - bool mainFuncDefined; + enum class Type { + VERTEX, + PIXEL + }; + + ~Shader(); + + static Result<std::unique_ptr<Shader>> compile(Type type, const char *str, int size); + const u32 id; + private: + Shader(u32 shader_id); }; } diff --git a/include/RenderBackend/OpenGL/ShaderProgram.hpp b/include/RenderBackend/OpenGL/ShaderProgram.hpp index c8740f8..ca96d0c 100644 --- a/include/RenderBackend/OpenGL/ShaderProgram.hpp +++ b/include/RenderBackend/OpenGL/ShaderProgram.hpp @@ -3,44 +3,27 @@ #include "../../Result.hpp" #include "../../types.hpp" #include "../../utils.hpp" -#include "ShaderVec.hpp" +#include "../../Vec.hpp" +#include "DeviceMemory.hpp" #include <vector> -#include <stdexcept> +#include <memory> + +namespace amalgine { + class Shader; -namespace amalgine -{ - class CompiledVertexShader; - class CompiledPixelShader; - - class ShaderProgramUsedBeforeBuilt : public std::runtime_error - { - public: - // TODO: Add name to ShaderProgram so we know which shader has issue when - // an exception is thrown? - ShaderProgramUsedBeforeBuilt(); - }; - - class ShaderProgramNonExistingGlobalVariable : public std::runtime_error - { - public: - ShaderProgramNonExistingGlobalVariable(const char *variableName); - }; - class ShaderProgram { DISABLE_COPY(ShaderProgram) public: - ShaderProgram(); ~ShaderProgram(); - - bool setVertexShader(CompiledVertexShader *vertexShader); - bool setPixelShader(CompiledPixelShader *pixelShader); - - Result<bool> build(); + static Result<std::unique_ptr<ShaderProgram>> build(const std::vector<Shader*> &shaders); + int set_uniform(const char *name, const vec3f &value); + int set_vertex_input(const char *name, const DeviceMemory &data); + void use(); - ShaderProgramGlobalVec3 getGlobalVec3(const char *name); private: - u32 shaderProgramId; - bool built; + ShaderProgram(u32 shader_program_id); + private: + u32 program_id; }; } diff --git a/include/RenderBackend/OpenGL/ShaderVec.hpp b/include/RenderBackend/OpenGL/ShaderVec.hpp deleted file mode 100644 index 4353dd7..0000000 --- a/include/RenderBackend/OpenGL/ShaderVec.hpp +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include "../../types.hpp" -#include "../../RenderBackend/OpenGL/DeviceMemory.hpp" -#include <string> - -namespace amalgine -{ - class Shader; - class ShaderProgram; - - enum class AttributeType - { - NONE, - VEC2, - VEC3, - VEC4 - }; - - AttributeType getAttributeTypeByName(const char *attributeName); - - class ShaderGlobalVec - { - friend class Shader; - 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 Shader; - 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 Shader; - public: - const std::string& getName() const; - void setData(const DeviceMemory &data); - private: - ShaderInputVec2(Shader *_shader, i32 _attributeIndex) : - shader(_shader), - attributeIndex(_attributeIndex) - { - - } - private: - Shader *shader; - i32 attributeIndex; - }; - - class ShaderVec4 - { - public: - ShaderVec4(f32 x = 0.0f, f32 y = 0.0f, f32 z = 0.0f, f32 w = 0.0f) - { - result = "vec4("; - result += std::to_string(x); - result += ", "; - result += std::to_string(y); - result += ", "; - result += std::to_string(z); - result += ", "; - result += std::to_string(w); - result += ")"; - } - - ShaderVec4(const ShaderInputVec2 &vec2, f32 z = 0.0f, f32 w = 0.0f) - { - result = "vec4("; - result += vec2.getName(); - result += ", "; - result += std::to_string(z); - result += ", "; - result += std::to_string(w); - 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; - } - private: - std::string result; - }; - - class ShaderOutputVec4 - { - friend class Shader; - public: - const std::string& getName() const; - - void operator=(const ShaderVec4 &shaderVec4); - private: - ShaderOutputVec4(Shader *_shader, i32 _attributeIndex) : - shader(_shader), - attributeIndex(_attributeIndex) - { - - } - private: - Shader *shader; - i32 attributeIndex; - }; -} diff --git a/include/RenderBackend/OpenGL/VertexShader.hpp b/include/RenderBackend/OpenGL/VertexShader.hpp deleted file mode 100644 index 6fdd6a4..0000000 --- a/include/RenderBackend/OpenGL/VertexShader.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -#include "Shader.hpp" - -namespace amalgine { - class CompiledVertexShader; - - using VertexShaderMainFunc = std::function<ShaderVec4()>; - - class VertexShader : public Shader - { - DISABLE_COPY(VertexShader) - friend class ShaderProgram; - public: - VertexShader(); - - void defineMain(VertexShaderMainFunc mainFunc); - Result<CompiledVertexShader*> compile(); - }; -} diff --git a/include/Result.hpp b/include/Result.hpp index 749d381..50a0d0c 100644 --- a/include/Result.hpp +++ b/include/Result.hpp @@ -9,10 +9,10 @@ namespace amalgine class Result { public: - static Result<T> Ok(const T &data) + static Result<T> Ok(T data) { Result<T> result; - result.data = data; + result.data = std::move(data); result.errorCode = 0; return result; } diff --git a/include/Vec.hpp b/include/Vec.hpp new file mode 100644 index 0000000..339a98b --- /dev/null +++ b/include/Vec.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "types.hpp" + +namespace amalgine { + struct vec3f { + f32 x; + f32 y; + f32 z; + + vec3f() : x(0.0f), y(0.0f) {} + vec3f(f32 x, f32 y, f32 z) : x(x), y(y), z(z) {} + }; +}
\ No newline at end of file diff --git a/include/types.hpp b/include/types.hpp index 4f95730..924dd67 100644 --- a/include/types.hpp +++ b/include/types.hpp @@ -1,9 +1,8 @@ #pragma once -#include <cstdint> +#include <stdint.h> -namespace amalgine -{ +namespace amalgine { typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; diff --git a/shaders/fragment.frag b/shaders/fragment.frag new file mode 100644 index 0000000..ea1ca7d --- /dev/null +++ b/shaders/fragment.frag @@ -0,0 +1,8 @@ +#version 330 core + +uniform vec3 triangle_color; +out vec4 out_color; + +void main() { + out_color = vec4(triangle_color, 1.0); +}
\ No newline at end of file diff --git a/shaders/vertex.vert b/shaders/vertex.vert new file mode 100644 index 0000000..d1cc433 --- /dev/null +++ b/shaders/vertex.vert @@ -0,0 +1,7 @@ +#version 330 core + +in vec2 position; + +void main() { + gl_Position = vec4(position, 0.0, 1.0); +}
\ No newline at end of file diff --git a/src/RenderBackend/OpenGL/CommonShader.cpp b/src/RenderBackend/OpenGL/CommonShader.cpp deleted file mode 100644 index ea88f62..0000000 --- a/src/RenderBackend/OpenGL/CommonShader.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/CommonShader.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" - -using namespace std; - -namespace amalgine -{ - string getShaderCompileLog(u32 shaderId) - { - string result; - GLint shaderLogLength; - glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &shaderLogLength); - if(shaderLogLength > 0) - { - result.resize(shaderLogLength); - glGetShaderInfoLog(shaderId, shaderLogLength, NULL, &result[0]); - } - return result; - } -} diff --git a/src/RenderBackend/OpenGL/CompiledShader.cpp b/src/RenderBackend/OpenGL/CompiledShader.cpp deleted file mode 100644 index f4a1fec..0000000 --- a/src/RenderBackend/OpenGL/CompiledShader.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" - -using namespace std; - -namespace amalgine -{ - CompiledVertexShader::CompiledVertexShader(u32 _shaderId) : - shaderId(_shaderId) - { - - } - - CompiledVertexShader::~CompiledVertexShader() - { - glDeleteShader(shaderId); - } - - u32 CompiledVertexShader::getShaderId() const - { - return shaderId; - } - - CompiledPixelShader::CompiledPixelShader(u32 _shaderId, unordered_map<string, i32> &&_pixelAttributes) : - shaderId(_shaderId), - pixelAttributes(_pixelAttributes) - { - - } - - CompiledPixelShader::~CompiledPixelShader() - { - glDeleteShader(shaderId); - } - - u32 CompiledPixelShader::getShaderId() const - { - return shaderId; - } -} diff --git a/src/RenderBackend/OpenGL/DeviceFrame.cpp b/src/RenderBackend/OpenGL/DeviceFrame.cpp index e79dfa1..2132f83 100644 --- a/src/RenderBackend/OpenGL/DeviceFrame.cpp +++ b/src/RenderBackend/OpenGL/DeviceFrame.cpp @@ -1,6 +1,7 @@ #include "../../../include/RenderBackend/OpenGL/DeviceFrame.hpp" #include "../../../include/RenderBackend/OpenGL/DeviceMemory.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" +#include "../../../include/RenderBackend/OpenGL/ShaderProgram.hpp" namespace amalgine { @@ -26,13 +27,13 @@ namespace amalgine return deviceMemory; } - void DeviceFrame::draw() - { - glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + void DeviceFrame::draw(ShaderProgram *shader) { + shader->use(); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); for(DeviceMemory *deviceMemory : buffers) { deviceMemory->draw(); } - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } } diff --git a/src/RenderBackend/OpenGL/DeviceMemory.cpp b/src/RenderBackend/OpenGL/DeviceMemory.cpp index 0dd3e89..2d40569 100644 --- a/src/RenderBackend/OpenGL/DeviceMemory.cpp +++ b/src/RenderBackend/OpenGL/DeviceMemory.cpp @@ -33,7 +33,7 @@ namespace amalgine } } - DeviceMemory::DeviceMemory() : primitiveType(0), numVertices(0) + DeviceMemory::DeviceMemory() : primitiveType(0), numVertices(0), type(DeviceMemoryType::NONE) { glGenBuffers(1, &vertexBufferObjectId); } @@ -43,11 +43,6 @@ namespace amalgine glDeleteBuffers(1, &vertexBufferObjectId); } - void DeviceMemory::operator delete(void *data) - { - free(data); - } - void DeviceMemory::use() const { // TODO: Bind vao here? @@ -68,12 +63,11 @@ namespace amalgine glBufferData(GL_ARRAY_BUFFER, triangles.getByteSize(), triangles.data, getOpenglStorageType(storageType)); primitiveType = GL_TRIANGLES; numVertices = triangles.size * 3; + type = DeviceMemoryType::VEC2; } void DeviceMemory::draw() { - if(primitiveType == 0) - throw DeviceMemoryEmpty("Unable to draw buffer as no data has been copied to device memory"); glDrawArrays(primitiveType, 0, numVertices); } } diff --git a/src/RenderBackend/OpenGL/PixelShader.cpp b/src/RenderBackend/OpenGL/PixelShader.cpp deleted file mode 100644 index e6006f2..0000000 --- a/src/RenderBackend/OpenGL/PixelShader.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/PixelShader.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" - -namespace amalgine -{ - PixelShader::PixelShader() - { - glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxAttribs); - } - - void PixelShader::defineMain(PixelShaderMainFunc mainFunc) - { - if(mainFuncDefined) - throw ShaderFunctionAlreadyDefined("main"); - - writeBody("void main() {\n"); - mainFunc(); - mainFuncDefined = true; - writeBody("}\n\n"); - } - - Result<CompiledPixelShader*> PixelShader::compile() - { - if(!mainFuncDefined) - return Result<CompiledPixelShader*>::Err("main function not defined (defineMain not called)"); - - GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER); - std::string verterShaderSource = build(); - const char *verterShaderSourcePtr = verterShaderSource.c_str(); - printf("Vertex shader:\n%s\n", verterShaderSourcePtr); - glShaderSource(fragmentShaderId, 1, &verterShaderSourcePtr, NULL); - glCompileShader(fragmentShaderId); - - GLint status; - glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &status); - std::string compileLog = getShaderCompileLog((u32)fragmentShaderId); - if(status == GL_TRUE) - { - if(!compileLog.empty()) - printf("Pixel shader compile log:\n%s", compileLog.c_str()); - return Result<CompiledPixelShader*>::Ok(new CompiledPixelShader(fragmentShaderId, move(inputAttributes))); - } - else - return Result<CompiledPixelShader*>::Err(compileLog); - } -} diff --git a/src/RenderBackend/OpenGL/Shader.cpp b/src/RenderBackend/OpenGL/Shader.cpp index fad1702..3b6563f 100644 --- a/src/RenderBackend/OpenGL/Shader.cpp +++ b/src/RenderBackend/OpenGL/Shader.cpp @@ -1,169 +1,55 @@ #include "../../../include/RenderBackend/OpenGL/Shader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" -#include <cassert> - -using namespace std; namespace amalgine { - ShaderTooManyAttributes::ShaderTooManyAttributes(i32 maxAttributes) : - runtime_error(string("Attempting to define more than ") + to_string(maxAttributes) + " attributes") - { - - } - - ShaderAttributeAlreadyDefined::ShaderAttributeAlreadyDefined(const std::string &attributeName) : - runtime_error(string("An attribute with the name ") + attributeName + " has already been defined") - { - - } - - ShaderInvalidAttributeName::ShaderInvalidAttributeName(const std::string &attributeName) : - runtime_error(string("Attribute name ") + attributeName + " is invalid") - { - - } - - ShaderFunctionAlreadyDefined::ShaderFunctionAlreadyDefined(const std::string &funcName) : - runtime_error(string("Shader function already defined: ") + funcName) - { - - } - - Shader::Shader() : inputLocationCounter(0), outputLocationCounter(0), mainFuncDefined(false) - { - writeHeader("#version 330 core\n\n"); - } - - const string& Shader::getOutputAttributeName(i32 attributeIndex) - { - assert(attributeIndex < (i32)outputAttributeNames.size()); - return outputAttributeNames[attributeIndex].name; + static GLuint to_opengl_shader_type(Shader::Type type) { + switch(type) { + case Shader::Type::VERTEX: + return GL_VERTEX_SHADER; + case Shader::Type::PIXEL: + return GL_FRAGMENT_SHADER; + } + assert(false); } - const string& Shader::getInputAttributeName(i32 attributeIndex) const - { - assert(attributeIndex < (i32)inputAttributeNames.size()); - return inputAttributeNames[attributeIndex].name; - } - - AttributeType Shader::getInputAttributeType(i32 attributeIndex) const - { - assert(attributeIndex < (i32)inputAttributeNames.size()); - return getAttributeTypeByName(inputAttributeNames[attributeIndex].typeName); - } - - ShaderOutputVec4 Shader::defineOutputVec4(const std::string &name) - { - i32 attributeIndex = defineOutputVariable(name, "vec4"); - return ShaderOutputVec4(this, attributeIndex); - } - - // TODO: Generate warning if global variable is defined but not assigned to? - ShaderGlobalVec3 Shader::defineGlobalVec3(const std::string &name) - { - if(!isShaderVariableNameValid(name.c_str())) - throw ShaderInvalidAttributeName(name); - - if(uniforms.find(name) != uniforms.end()) - throw ShaderAttributeAlreadyDefined(name); - - writeHeader("uniform vec3 "); - writeHeader(name); - writeHeader(";\n"); - - ShaderGlobalVec3 globalVec(name); - uniforms[name] = globalVec.getVecObject(); - return ShaderGlobalVec3(globalVec); - } - - i32 Shader::defineOutputVariable(const string &variableName, const char *typeName) - { - if(!isShaderVariableNameValid(variableName.c_str())) - throw ShaderInvalidAttributeName(variableName); - - if(outputLocationCounter + 1 > maxAttribs) - throw ShaderTooManyAttributes(maxAttribs); - - if(outputAttributes.find(variableName) != outputAttributes.end()) - throw ShaderAttributeAlreadyDefined(variableName); - - i32 attributeIndex = outputLocationCounter; - outputAttributes[variableName] = outputLocationCounter; - writeHeader("out "); - writeHeader(typeName); - writeHeader(" "); - writeHeader(variableName); - writeHeader(";\n"); - - ShaderAttribute shaderAttribute; - shaderAttribute.name = variableName; - shaderAttribute.typeName = typeName; - outputAttributeNames.push_back(shaderAttribute); - ++outputLocationCounter; - return attributeIndex; - } - - ShaderInputVec2 Shader::defineInputVec2(const std::string &name) - { - i32 attributeIndex = defineInputVariable(name, "vec2"); - return ShaderInputVec2(this, attributeIndex); - } - - i32 Shader::defineInputVariable(const string &variableName, const char *typeName) - { - if(!isShaderVariableNameValid(variableName.c_str())) - throw ShaderInvalidAttributeName(variableName); - - if(inputLocationCounter + 1 > maxAttribs) - throw ShaderTooManyAttributes(maxAttribs); - - if(inputAttributes.find(variableName) != inputAttributes.end()) - throw ShaderAttributeAlreadyDefined(variableName); - - i32 attributeIndex = inputLocationCounter; - inputAttributes[variableName] = inputLocationCounter; - ShaderAttribute shaderAttribute; - shaderAttribute.name = variableName; - shaderAttribute.typeName = typeName; - inputAttributeNames.push_back(shaderAttribute); - - writeHeader("layout(location = "); - writeHeader(to_string(inputLocationCounter)); - ++inputLocationCounter; - writeHeader(") in "); - writeHeader(typeName); - writeHeader(" "); - writeHeader(variableName); - writeHeader(";\n"); - return attributeIndex; - } - - void Shader::assign(const ShaderOutputVec4 &lhsVariable, const ShaderVec4 &rhsVariable) - { - writeBody(lhsVariable.getName()); - writeBody(" = "); - writeBody(rhsVariable.getOutput()); - writeBody(";\n"); - } - - string Shader::build() const + static std::string get_shader_compile_log(GLuint shaderId) { std::string result; - result.reserve(header.size() + 2 + body.size()); - result += header; - result += "\n"; - result += body; + GLint shaderLogLength; + glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &shaderLogLength); + if(shaderLogLength > 0) { + result.resize(shaderLogLength); + glGetShaderInfoLog(shaderId, shaderLogLength, NULL, &result[0]); + } return result; } - - void Shader::writeHeader(const string &code) - { - header += code; + + Shader::Shader(u32 shader_id) : id(shader_id) { + } - - void Shader::writeBody(const string &code) - { - body += code; + + Shader::~Shader() { + glDeleteShader(id); + } + + // static + Result<std::unique_ptr<Shader>> Shader::compile(Type type, const char *str, int size) { + GLuint shader_id = glCreateShader(to_opengl_shader_type(type)); + GLint shader_lengths[1] = { size }; + glShaderSource(shader_id, 1, &str, shader_lengths); + glCompileShader(shader_id); + + GLint status; + glGetShaderiv(shader_id, GL_COMPILE_STATUS, &status); + std::string compileLog = get_shader_compile_log(shader_id); + if(status == GL_TRUE) { + if(!compileLog.empty()) + fprintf(stderr, "Shader compile log:\n%s", compileLog.c_str()); + std::unique_ptr<Shader> shader; + shader.reset(new Shader(shader_id)); + return Result<std::unique_ptr<Shader>>::Ok(std::move(shader)); + } + else + return Result<std::unique_ptr<Shader>>::Err(compileLog); } } diff --git a/src/RenderBackend/OpenGL/ShaderProgram.cpp b/src/RenderBackend/OpenGL/ShaderProgram.cpp index aceda3b..e613668 100644 --- a/src/RenderBackend/OpenGL/ShaderProgram.cpp +++ b/src/RenderBackend/OpenGL/ShaderProgram.cpp @@ -1,56 +1,34 @@ #include "../../../include/RenderBackend/OpenGL/ShaderProgram.hpp" + +#include "../../../include/RenderBackend/OpenGL/Shader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" using namespace std; -namespace amalgine -{ - ShaderProgramUsedBeforeBuilt::ShaderProgramUsedBeforeBuilt() : - runtime_error("Shader program was used before it was built") - { +namespace amalgine { + ShaderProgram::ShaderProgram(u32 shader_program_id) : program_id(shader_program_id) { } - ShaderProgramNonExistingGlobalVariable::ShaderProgramNonExistingGlobalVariable(const char *variableName) : - runtime_error(string("There is no shader global variable with the name '") + variableName + "'") - { - - } - - ShaderProgram::ShaderProgram() : built(false) - { - shaderProgramId = glCreateProgram(); - } - ShaderProgram::~ShaderProgram() { GLint numAttachedShaders; - glGetProgramiv(shaderProgramId, GL_ATTACHED_SHADERS, &numAttachedShaders); + glGetProgramiv(program_id, GL_ATTACHED_SHADERS, &numAttachedShaders); GLuint *attachedShaders = new GLuint[numAttachedShaders]; - glGetAttachedShaders(shaderProgramId, numAttachedShaders, nullptr, attachedShaders); + glGetAttachedShaders(program_id, numAttachedShaders, nullptr, attachedShaders); for(int i = 0; i < numAttachedShaders; ++i) { GLuint attachedShaderId = attachedShaders[i]; - glDetachShader(shaderProgramId, attachedShaderId); + glDetachShader(program_id, attachedShaderId); } - glDeleteProgram(shaderProgramId); - } - - // TODO: Before adding shader to program, check if it has already been added - - bool ShaderProgram::setVertexShader(CompiledVertexShader *vertexShader) - { - if(!vertexShader) return false; - - // TODO: Do not allow adding shader if the program has already been built - glAttachShader(shaderProgramId, vertexShader->getShaderId()); - return true; + glDeleteProgram(program_id); + delete []attachedShaders; } + #if 0 bool ShaderProgram::setPixelShader(CompiledPixelShader *pixelShader) { if(!pixelShader) return false; @@ -68,41 +46,55 @@ namespace amalgine return true; } + #endif - Result<bool> ShaderProgram::build() - { - if(built) - return Result<bool>::Err("Shader program already built"); + // static + Result<std::unique_ptr<ShaderProgram>> ShaderProgram::build(const std::vector<Shader*> &shaders) { + u32 shader_program_id = glCreateProgram(); + if(shader_program_id == 0) + return Result<std::unique_ptr<ShaderProgram>>::Err("Failed to create shader program"); - glLinkProgram(shaderProgramId); - built = true; - return Result<bool>::Ok(true); - } - - void ShaderProgram::use() - { - if(built) - { - glUseProgram(shaderProgramId); - } - else - { - throw ShaderProgramUsedBeforeBuilt(); + for(Shader *shader : shaders) { + glAttachShader(shader_program_id, shader->id); } + + glLinkProgram(shader_program_id); + std::unique_ptr<ShaderProgram> shader_program; + shader_program.reset(new ShaderProgram(shader_program_id)); + return Result<std::unique_ptr<ShaderProgram>>::Ok(std::move(shader_program)); } - - ShaderProgramGlobalVec3 ShaderProgram::getGlobalVec3(const char *name) - { - if(built) - { - GLint uniformId = glGetUniformLocation(shaderProgramId, name); - if(uniformId == -1) - throw ShaderProgramNonExistingGlobalVariable(name); - return ShaderProgramGlobalVec3(this, uniformId); + + int ShaderProgram::set_uniform(const char *name, const vec3f &value) { + GLint uniformId = glGetUniformLocation(program_id, name); + if(uniformId == -1) + return -1; + use(); + glUniform3f(uniformId, value.x, value.y, value.z); + return 0; + } + + int ShaderProgram::set_vertex_input(const char *name, const DeviceMemory &data) { + GLint attrib_location = glGetAttribLocation(program_id, name); + if(attrib_location == -1) { + fprintf(stderr, "No such attribute in shader: %s\n", name); + return -1; } - else - { - throw ShaderProgramUsedBeforeBuilt(); + + data.use(); + switch(data.get_type()) { + case DeviceMemoryType::NONE: + return -1; + case DeviceMemoryType::VEC2: { + glVertexAttribPointer(attrib_location, 2, GL_FLOAT, GL_FALSE, 0, 0); + break; + } + case DeviceMemoryType::VEC3: assert(false); return -1; } + glEnableVertexAttribArray(attrib_location); + return 0; + } + + void ShaderProgram::use() { + glUseProgram(program_id); } } diff --git a/src/RenderBackend/OpenGL/ShaderVec.cpp b/src/RenderBackend/OpenGL/ShaderVec.cpp deleted file mode 100644 index 8897b84..0000000 --- a/src/RenderBackend/OpenGL/ShaderVec.cpp +++ /dev/null @@ -1,69 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/ShaderVec.hpp" -#include "../../../include/RenderBackend/OpenGL/Shader.hpp" -#include "../../../include/RenderBackend/OpenGL/ShaderProgram.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include <cstring> -#include <cassert> - -using namespace std; - -namespace amalgine -{ - AttributeType getAttributeTypeByName(const char *attributeName) - { - if(strncmp(attributeName, "vec2", 4) == 0) - { - return AttributeType::VEC2; - } - else if(strncmp(attributeName, "vec3", 4) == 0) - { - return AttributeType::VEC3; - } - else if(strncmp(attributeName, "vec4", 4) == 0) - { - return AttributeType::VEC4; - } - - assert(false); - 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 shader->getInputAttributeName(attributeIndex); - } - - void ShaderInputVec2::setData(const DeviceMemory &data) - { - data.use(); - AttributeType attributeType = shader->getInputAttributeType(attributeIndex); - switch(attributeType) - { - case AttributeType::VEC2: - { - glVertexAttribPointer(attributeIndex, 2, GL_FLOAT, GL_FALSE, 0, 0); - break; - } - default: - assert(false); - break; - } - glEnableVertexAttribArray(attributeIndex); - } - - const string& ShaderOutputVec4::getName() const - { - return shader->getOutputAttributeName(attributeIndex); - } - - void ShaderOutputVec4::operator=(const ShaderVec4 &shaderVec4) - { - shader->assign(*this, shaderVec4); - } -} diff --git a/src/RenderBackend/OpenGL/VertexShader.cpp b/src/RenderBackend/OpenGL/VertexShader.cpp deleted file mode 100644 index 19705b6..0000000 --- a/src/RenderBackend/OpenGL/VertexShader.cpp +++ /dev/null @@ -1,45 +0,0 @@ -#include "../../../include/RenderBackend/OpenGL/VertexShader.hpp" -#include "../../../include/RenderBackend/OpenGL/opengl.hpp" -#include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" - -namespace amalgine { - VertexShader::VertexShader() - { - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); - } - - void VertexShader::defineMain(VertexShaderMainFunc mainFunc) - { - if(mainFuncDefined) - throw ShaderFunctionAlreadyDefined("main"); - - writeBody("void main() {\n"); - ShaderVec4 glPosition = mainFunc(); - mainFuncDefined = true; - writeBody("gl_Position = "); - writeBody(glPosition.getOutput()); - writeBody(";\n}\n\n"); - } - - Result<CompiledVertexShader*> VertexShader::compile() - { - GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER); - std::string verterShaderSource = build(); - const char *verterShaderSourcePtr = verterShaderSource.c_str(); - printf("Vertex shader:\n%s\n", verterShaderSourcePtr); - glShaderSource(vertexShaderId, 1, &verterShaderSourcePtr, NULL); - glCompileShader(vertexShaderId); - - GLint status; - glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &status); - std::string compileLog = getShaderCompileLog((u32)vertexShaderId); - if(status == GL_TRUE) - { - if(!compileLog.empty()) - printf("Vertex shader compile log:\n%s", compileLog.c_str()); - return Result<CompiledVertexShader*>::Ok(new CompiledVertexShader(vertexShaderId)); - } - else - return Result<CompiledVertexShader*>::Err(compileLog); - } -} diff --git a/src/main.cpp b/src/main.cpp index 24ef4f8..f6f827f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #include <cstdio> #include "../include/RenderBackend/OpenGL/opengl.hpp" -#include "../include/RenderBackend/OpenGL/VertexShader.hpp" -#include "../include/RenderBackend/OpenGL/PixelShader.hpp" +#include "../include/RenderBackend/OpenGL/Shader.hpp" #include "../include/RenderBackend/OpenGL/ShaderProgram.hpp" #include "../include/RenderBackend/OpenGL/DeviceMemory.hpp" #include "../include/RenderBackend/OpenGL/DeviceFrame.hpp" @@ -16,13 +15,11 @@ using namespace amalgine; using namespace std; -void glfwErrorHandler(int errorCode, const char *errorDescription); -void initGlfw(); -void initGlew(); -GLFWwindow *createWindow(); - -CompiledVertexShader* createVertexShader(const DeviceMemory &inputData); -CompiledPixelShader* createPixelShader(); +static void glfwErrorHandler(int errorCode, const char *errorDescription); +static void initGlfw(); +static void initGlew(); +static GLFWwindow *createWindow(); +static std::unique_ptr<Shader> load_shader_from_file(const char *filepath, Shader::Type shader_type); int main() { @@ -40,25 +37,19 @@ int main() DataView<Triangle2D> cpuTriangles(&cpuTriangle, 1); DeviceMemory *gpuTriangle = frame.alloc(); gpuTriangle->copy(cpuTriangles, DeviceMemory::StorageType::STATIC); + + std::unique_ptr<Shader> vertex_shader = load_shader_from_file("shaders/vertex.vert", Shader::Type::VERTEX); + std::unique_ptr<Shader> pixel_shader = load_shader_from_file("shaders/fragment.frag", Shader::Type::PIXEL); - CompiledVertexShader *vertexShader = createVertexShader(*gpuTriangle); - CompiledPixelShader *pixelShader = createPixelShader(); - - 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<bool> 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()); - exit(20); + Result<std::unique_ptr<ShaderProgram>> shader_program_result = ShaderProgram::build({ vertex_shader.get(), pixel_shader.get() }); + if(!shader_program_result) { + fprintf(stderr, "Failed to link shaders, error: %s\n", shader_program_result.getErrorMsg().c_str()); + exit(13); } + std::unique_ptr<ShaderProgram> shader_program = std::move(shader_program_result.unwrap()); + + shader_program->set_vertex_input("position", *gpuTriangle); + shader_program->set_uniform("triangle_color", vec3f{ 1.0f, 0.0f, 0.0f }); while(!glfwWindowShouldClose(window)) { @@ -70,8 +61,7 @@ int main() 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(); + frame.draw(shader_program.get()); glfwSwapBuffers(window); } @@ -128,53 +118,31 @@ GLFWwindow* createWindow() return window; } -CompiledVertexShader* createVertexShader(const DeviceMemory &inputData) -{ - VertexShader vertexShader; - ShaderInputVec2 inputPosition = vertexShader.defineInputVec2("position"); - inputPosition.setData(inputData); - #if 0 - ShaderGlobalMat4x4 model = vertexShader.defineGlobalMat4x4("model"); - ShaderGlobalMat4x4 view = vertexShader.defineGlobalMat4x4("view"); - ShaderGlobalMat4x4 proj = vertexShader.defineGlobalMat4x4("proj"); - - vertexShader.defineMain([&inputPosition, &model, &view, &proj]() - { - return proj * view * model * ShaderVec4(inputPosition, 0.0f, 1.0f); - }); - #endif - vertexShader.defineMain([&inputPosition]() - { - return ShaderVec4(inputPosition, 0.0f, 1.0f); - }); - - Result<CompiledVertexShader*> compiledVertexShader = vertexShader.compile(); - if(!compiledVertexShader) - { - fprintf(stderr, "Failed to compile vertex shader:\n%s", compiledVertexShader.getErrorMsg().c_str()); - exit(2); +static int file_read_all(const char *filepath, std::string &result) { + FILE *file = fopen(filepath, "rb"); + if(!file) { + perror("file_read_all"); + return errno; } - - return compiledVertexShader.unwrap(); + + fseek(file, 0, SEEK_END); + size_t file_size = ftell(file); + fseek(file, 0, SEEK_SET); + result.resize(file_size); + fread(&result[0], 1, result.size(), file); + fclose(file); + return 0; } -CompiledPixelShader* createPixelShader() -{ - PixelShader pixelShader; - ShaderGlobalVec3 triangleColor = pixelShader.defineGlobalVec3("triangleColor"); - ShaderOutputVec4 outColor = pixelShader.defineOutputVec4("outColor"); - - pixelShader.defineMain([&triangleColor, &outColor]() - { - outColor = ShaderVec4(triangleColor, 1.0f); - }); - - Result<CompiledPixelShader*> compiledPixelShader = pixelShader.compile(); - if(!compiledPixelShader) - { - fprintf(stderr, "Failed to compile pixel shader:\n%s", compiledPixelShader.getErrorMsg().c_str()); - exit(2); +std::unique_ptr<Shader> load_shader_from_file(const char *filepath, Shader::Type shader_type) { + std::string file_content; + if(file_read_all(filepath, file_content) != 0) + exit(13); + + Result<std::unique_ptr<Shader>> vertex_shader_result = Shader::compile(shader_type, file_content.data(), file_content.size()); + if(!vertex_shader_result) { + fprintf(stderr, "Failed to compile shader, error: %s\n", vertex_shader_result.getErrorMsg().c_str()); + exit(12); } - - return compiledPixelShader.unwrap(); -} + return std::move(vertex_shader_result.unwrap()); +}
\ No newline at end of file |