#include "../../../include/RenderBackend/OpenGL/PixelShader.hpp" #include "../../../include/RenderBackend/OpenGL/CommonShader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" #include using namespace std; namespace amalgine { PixelShaderTooManyAttributes::PixelShaderTooManyAttributes(i32 maxPixelAttributes) : runtime_error(string("Attempting to define more than ") + to_string(maxPixelAttributes) + " pixel attributes") { } PixelShaderAttributeAlreadyDefined::PixelShaderAttributeAlreadyDefined(const std::string &attributeName) : runtime_error(string("A pixel attribute with the name ") + attributeName + " has already been defined") { } PixelShaderInvalidAttributeName::PixelShaderInvalidAttributeName(const std::string &attributeName) : runtime_error(string("Pixel attribute name ") + attributeName + " is invalid") { } PixelShaderFunctionAlreadyDefined::PixelShaderFunctionAlreadyDefined(const std::string &funcName) : runtime_error(string("Pixel shader function already defined: ") + funcName) { } PixelShader::PixelShader() : locationCounter(0), mainFuncDefined(false) { glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxPixelAttribs); writeHeader("#version 330 core\n\n"); } const string& PixelShader::getOutputAttributeName(i32 attributeIndex) { assert(attributeIndex < pixelAttributeNames.size()); return pixelAttributeNames[attributeIndex]; } ShaderOutputVec4 PixelShader::defineOutputVec4(const std::string &name) { i32 attributeIndex = defineOutputVariable(name, "vec4"); return ShaderOutputVec4(this, attributeIndex); } void PixelShader::defineMain(PixelShaderMainFunc mainFunc) { if(mainFuncDefined) throw PixelShaderFunctionAlreadyDefined("main"); writeBody("void main() {\n"); mainFunc(); mainFuncDefined = true; writeBody("}\n\n"); } void PixelShader::assign(const ShaderOutputVec4 &lhsVariable, const ShaderVec4 &rhsVariable) { writeBody(lhsVariable.getName()); writeBody(" = "); writeBody(rhsVariable.getOutput()); writeBody(";\n"); } i32 PixelShader::defineOutputVariable(const string &variableName, const char *typeName) { if(!isShaderVariableNameValid(variableName.c_str())) throw PixelShaderInvalidAttributeName(variableName); if(locationCounter + 1 > maxPixelAttribs) throw PixelShaderTooManyAttributes(maxPixelAttribs); if(pixelAttributes.find(variableName) != pixelAttributes.end()) throw PixelShaderAttributeAlreadyDefined(variableName); i32 attributeIndex = locationCounter; pixelAttributes[variableName] = locationCounter; pixelAttributeNames.push_back(variableName); ++locationCounter; writeHeader("out "); writeHeader(typeName); writeHeader(" "); writeHeader(variableName); writeHeader(";\n"); return attributeIndex; } string PixelShader::build() { std::string result; result.reserve(header.size() + 2 + body.size()); result += header; result += "\n"; result += body; return result; } void PixelShader::writeHeader(const string &code) { header += code; } void PixelShader::writeBody(const string &code) { body += code; } }