#include "../../../include/RenderBackend/OpenGL/Shader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" #include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" #include 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; } }