1 module unecht.gl.program;
2 
3 import gl3n.linalg;
4 
5 import derelict.opengl3.gl3;
6 
7 import unecht.meta.misc;
8 import unecht.gl.shader;
9 
10 ///
11 enum GLAtrribTypes
12 {
13     position,
14     normal,
15     color,
16     texcoord
17 }
18 
19 ///
20 alias GLProgramAttribLocations = GLuint[EnumMemberCount!GLAtrribTypes];
21 
22 ///
23 final class GLProgram
24 {
25     GLuint program;
26     //TODO: use sorted array here:
27     GLint[string] uniforms;
28     private string _name;
29     
30     GLProgramAttribLocations attribLocations;
31     
32     void create(GLShader _vshader, GLShader _fshader, string _name="<unknown>")
33     {
34         this._name = _name;
35         
36         program = glCreateProgram();
37         
38         glAttachShader(program, _vshader.shader);
39         glAttachShader(program, _fshader.shader);
40         
41         glLinkProgram(program);
42         
43         int success;
44         glGetProgramiv(program, GL_LINK_STATUS, &success);
45         if (success == 0) {
46             static GLchar[1024] logBuff;
47             static GLsizei logLen;
48             glGetProgramInfoLog(program, logBuff.sizeof, &logLen, logBuff.ptr);
49             import unecht.core.logger;
50             import std.conv;
51             log.errorf("Error: linking program: '%s': %s", _name, to!string(logBuff[0..logLen-1]));
52             return;
53         }
54         
55         foreach(i, att; __traits(allMembers, GLAtrribTypes))
56         {
57             import std.string:toStringz;
58             auto attrName = att.stringof[1..$-1];
59             attribLocations[i] = glGetAttribLocation(program, toStringz(attrName));
60         }
61     }
62     
63     //TODO:
64     void destroy()
65     {
66         
67     }
68     
69     private GLint addUniform(string _name)
70     {
71         import unecht.core.logger:log;
72         import unecht.gl.vertexBufferObject:checkGLError;
73         import std.string:toStringz;
74         
75         auto loc = glGetUniformLocation(program, toStringz(_name));
76         
77         checkGLError();
78         
79         if(loc != -1)
80         {
81             uniforms[_name] = loc;
82             log.infof("Program uniform location found: '%s' at %s", _name, loc);
83             return loc;
84         }
85         else
86         {
87             //TODO: implement a logging scheme
88             //writefln("Error: could not locate uniform: '%s' in '%s'", _name, this._name);
89             return -1;
90         }
91     }
92     
93     ///
94     void setUniformVec3(string _name, in vec3 _val)
95     {
96         auto locPtr = _name in uniforms;
97         GLint loc;
98         
99         if(!locPtr)
100             loc = addUniform(_name);
101         else
102             loc = *locPtr;
103 
104         if(loc != -1)
105             glUniform3fv(loc, 1, _val.vector.ptr);
106     }
107 
108     ///
109     void setUniformVec4(string _name, in vec4 _val)
110     {
111         auto locPtr = _name in uniforms;
112         GLint loc;
113         
114         if(!locPtr)
115             loc = addUniform(_name);
116         else
117             loc = *locPtr;
118         
119         if(loc != -1)
120             glUniform4fv(loc, 1, _val.vector.ptr);
121     }
122     
123     ///
124     void setUniformMatrix(string _name, const ref mat4 _mat)
125     {
126         auto locPtr = _name in uniforms;
127         GLint loc;
128         
129         if(!locPtr)
130             loc = addUniform(_name);
131         else
132             loc = *locPtr;
133 
134         if(loc != -1)
135             glUniformMatrix4fv(loc, 1, GL_TRUE, _mat[0].ptr);
136     }
137     
138     void bind()
139     {
140         glUseProgram(program);
141     }
142     
143     void validate()
144     {
145         glValidateProgram(program);
146         
147         GLint success;
148         glGetProgramiv(program, GL_VALIDATE_STATUS, &success);
149         if (!success) {
150             GLchar[1024] logBuff;
151             GLsizei logLen;
152             glGetProgramInfoLog(program, logBuff.sizeof, &logLen, logBuff.ptr);
153             import unecht.core.logger;
154             import std.conv;
155             log.errorf("Error validating program: '%s'", to!string(logBuff[0..logLen-1]));
156         }
157     }
158     
159     void unbind()
160     {
161         glUseProgram(0);
162     }
163 }