#include "../../../include/RenderBackend/OpenGL/VertexShader.hpp" #include "../../../include/RenderBackend/OpenGL/CommonShader.hpp" #include "../../../include/RenderBackend/OpenGL/opengl.hpp" #include "../../../include/RenderBackend/OpenGL/CompiledShader.hpp" using namespace std; namespace amalgine { VertexShaderTooManyAttributes::VertexShaderTooManyAttributes(i32 maxVertexAttributes) : runtime_error(string("Attempting to define more than ") + to_string(maxVertexAttributes) + " vertex attributes") { } VertexShaderAttributeAlreadyDefined::VertexShaderAttributeAlreadyDefined(const std::string &attributeName) : runtime_error(string("A vertex attribute with the name ") + attributeName + " has already been defined") { } VertexShaderInvalidAttributeName::VertexShaderInvalidAttributeName(const std::string &attributeName) : runtime_error(string("Vertex attribute name ") + attributeName + " is invalid") { } VertexShaderFunctionAlreadyDefined::VertexShaderFunctionAlreadyDefined(const std::string &funcName) : runtime_error(string("Vertex shader function already defined: ") + funcName) { } VertexShader::VertexShader() : locationCounter(0), mainFuncDefined(false) { glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs); writeHeader("#version 330 core\n\n"); } const string& VertexShader::getInputAttributeName(i32 attributeIndex) { assert(attributeIndex < vertexAttributeNames.size()); return vertexAttributeNames[attributeIndex]; } ShaderInputVec2 VertexShader::defineInputVec2(const std::string &name) { i32 attributeIndex = defineInputVariable(name, "vec2"); return ShaderInputVec2(this, attributeIndex); } void VertexShader::defineMain(VertexShaderMainFunc mainFunc) { if(mainFuncDefined) throw VertexShaderFunctionAlreadyDefined("main"); writeBody("void main() {\n"); ShaderVec4 glPosition = mainFunc(); mainFuncDefined = true; writeBody("gl_Position = "); writeBody(glPosition.getOutput()); writeBody(";\n}\n\n"); } i32 VertexShader::defineInputVariable(const string &variableName, const char *typeName) { if(!isShaderVariableNameValid(variableName.c_str())) throw VertexShaderInvalidAttributeName(variableName); if(locationCounter + 1 > maxVertexAttribs) throw VertexShaderTooManyAttributes(maxVertexAttribs); if(vertexAttributes.find(variableName) != vertexAttributes.end()) throw VertexShaderAttributeAlreadyDefined(variableName); i32 attributeIndex = locationCounter; vertexAttributes[variableName] = locationCounter; vertexAttributeNames.push_back(variableName); writeHeader("layout(location = "); writeHeader(to_string(locationCounter)); ++locationCounter; writeHeader(") in "); writeHeader(typeName); writeHeader(" "); writeHeader(variableName); writeHeader(";\n"); return attributeIndex; } string VertexShader::build() const { std::string result; result.reserve(header.size() + 2 + body.size()); result += header; result += "\n"; result += body; return result; } void VertexShader::writeHeader(const string &code) { header += code; } void VertexShader::writeBody(const string &code) { body += code; } Result VertexShader::compile() { GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER); 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); string compileLog = getShaderCompileLog((u32)vertexShaderId); if(status == GL_TRUE) { if(!compileLog.empty()) printf("Vertex shader compile log:\n%s", compileLog.c_str()); return Result::Ok(new CompiledVertexShader(vertexShaderId)); } else return Result::Err(compileLog); } }