aboutsummaryrefslogtreecommitdiff
path: root/src/RenderBackend/OpenGL/Shader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/RenderBackend/OpenGL/Shader.cpp')
-rw-r--r--src/RenderBackend/OpenGL/Shader.cpp169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/RenderBackend/OpenGL/Shader.cpp b/src/RenderBackend/OpenGL/Shader.cpp
new file mode 100644
index 0000000..fad1702
--- /dev/null
+++ b/src/RenderBackend/OpenGL/Shader.cpp
@@ -0,0 +1,169 @@
+#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;
+ }
+
+ 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
+ {
+ std::string result;
+ result.reserve(header.size() + 2 + body.size());
+ result += header;
+ result += "\n";
+ result += body;
+ return result;
+ }
+
+ void Shader::writeHeader(const string &code)
+ {
+ header += code;
+ }
+
+ void Shader::writeBody(const string &code)
+ {
+ body += code;
+ }
+}