aboutsummaryrefslogtreecommitdiff
path: root/src/RenderBackend/OpenGL/VertexShader.cpp
blob: ac9a15924a85088158589562e227d61d23798073 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "../../../include/RenderBackend/OpenGL/VertexShader.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) const
    {
        assert(attributeIndex < vertexAttributeNames.size());
        return vertexAttributeNames[attributeIndex].name;
    }
    
    AttributeType VertexShader::getInputAttributeType(i32 attributeIndex) const
    {
        assert(attributeIndex < vertexAttributeNames.size());
        return getAttributeTypeByName(vertexAttributeNames[attributeIndex].typeName);
    }
    
    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;
        ShaderAttribute shaderAttribute;
        shaderAttribute.name = variableName;
        shaderAttribute.typeName = typeName;
        vertexAttributeNames.push_back(shaderAttribute);
        
        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<CompiledVertexShader*> 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<CompiledVertexShader*>::Ok(new CompiledVertexShader(vertexShaderId));
        }
        else
            return Result<CompiledVertexShader*>::Err(compileLog);
    }
}