fixed shader manager, added it
[demo] / src / opengl / shader-gl.cc
1 #include <GL/glew.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include "state_manager.h"
6 #include "opengl/shader-gl.h"
7
8 extern ShaderProgram *current_program;
9
10 ShaderGL::ShaderGL()
11 {
12         sdr = 0;
13 }
14
15 ShaderGL::~ShaderGL()
16 {
17         destroy();
18 }
19
20 bool ShaderGL::create(char *buf, unsigned int bsz, const char *fname)
21 {
22         /* find shader type and create shader */
23         unsigned int stype;
24         switch(type) {
25         case SDR_VERTEX:
26                 stype = GL_VERTEX_SHADER;
27                 break;
28         case SDR_FRAGMENT:
29                 stype = GL_FRAGMENT_SHADER;
30                 break;
31         default:
32                 fprintf(stderr, "Unknown shader type.\n");
33                 return false;
34         }
35         name = std::string(fname);
36         sdr = glCreateShader(stype);
37
38         /* compile */
39         glShaderSource(sdr, 1, (const char **)&buf, 0);
40         glCompileShader(sdr);
41
42         delete [] buf;
43
44         /* check compile status */
45         int status;
46         glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
47         if(status)
48                 printf("Successfully compiled shader: %s\n", fname);
49         else
50                 fprintf(stderr, "Failed to compile %s shader.\n", fname);
51
52         /* print the info log */
53         int loglen;
54         glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &loglen);
55         if(loglen > 0 && (buf = new char[loglen + 1])) {
56                 glGetShaderInfoLog(sdr, loglen, 0, buf);
57                 buf[loglen] = 0;
58                 printf("%s\n", buf);
59
60                 delete [] buf;
61         }
62
63         if(!status) {
64                 destroy();
65                 return false;
66         }
67
68         return true;
69 }
70
71 void ShaderGL::destroy()
72 {
73         if(sdr) {
74                 glDeleteShader(sdr);
75         }
76         sdr = 0;
77         type = SDR_UNKNOWN;
78 }
79
80 /* Shader Program */
81
82 ShaderProgramGL::ShaderProgramGL()
83 {
84         prog = 0;
85         memset(shaders, 0, sizeof shaders / sizeof *shaders);
86
87         current_program = 0;
88         is_linked = false;
89 }
90
91 ShaderProgramGL::~ShaderProgramGL()
92 {
93         destroy();
94 }
95
96 bool ShaderProgramGL::create()
97 {
98         prog = glCreateProgram();
99         if(!prog) {
100                 fprintf(stderr, "Failed to create shader program.\n");
101                 return false;
102         }
103         return true;
104 }
105
106 bool ShaderProgramGL::link()
107 {
108         if(is_linked)
109                 return true;
110
111         glLinkProgram(prog);
112
113         int status;
114         glGetProgramiv(prog, GL_LINK_STATUS, &status);
115         if(status) {
116                 printf("Successfully linked shader program.\n");
117                 is_linked = true;
118         }
119         else
120                 printf("Failed to link shader program.\n");
121
122         int loglen;
123         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &loglen);
124
125         char *buf;
126         if(loglen > 0 && (buf = new char[loglen + 1])) {
127                 glGetProgramInfoLog(prog, loglen, 0, buf);
128                 buf[loglen] = 0;
129                 printf("%s\n", buf);
130                 delete [] buf;
131         }
132
133         return status ? true : false;
134 }
135
136 bool ShaderProgramGL::use()
137 {
138         if(!is_linked && !link()) {
139                 return false;
140         }
141
142         if(!prog) {
143                 glUseProgram(0);
144                 current_program = 0;
145         }
146
147         glUseProgram(prog);
148         current_program = this;
149
150         static void (*const set_uniform[16])(GLint, GLsizei, const GLfloat *) = {
151                 0, glUniform1fv, glUniform2fv, glUniform3fv, glUniform4fv
152         };
153
154         for(size_t i=0; i<uniforms.size(); i++) {
155                 const State *st = state_manager.get_state(uniforms[i].state_idx);
156                 if(st->num < 5) {
157                         set_uniform[st->num](uniforms[i].location, 1, st->data);
158                 }
159                 else if(st->num == 16) {
160                         glUniformMatrix4fv(uniforms[i].location, 1, GL_TRUE, st->data);
161                 }
162                 else {
163                         fprintf(stderr, "Invalid number of floats in state %s: %d\n", st->name, st->num);
164                         continue;
165                 }
166         }
167         return true;
168 }
169
170 void ShaderProgramGL::destroy()
171 {
172         glDeleteProgram(prog);
173         prog = 0;
174         is_linked = false;
175 }
176
177 void ShaderProgramGL::attach_shader(Shader *shader)
178 {
179         glAttachShader(prog, ((ShaderGL *)shader)->sdr);
180         is_linked = false;
181 }
182
183 int ShaderProgramGL::get_uniform_location(const char *name) const
184 {
185         if(!((ShaderProgramGL *)this)->use())
186                 return -1;
187
188         return glGetUniformLocation(prog, name);
189 }
190
191 int ShaderProgramGL::get_attribute_location(const char *name) const
192 {
193         if(!((ShaderProgramGL *)this)->use())
194                 return -1;
195
196         return glGetAttribLocation(prog, name);
197 }
198
199 static int get_floats_num(unsigned int utype)
200 {
201         switch(utype) {
202         case GL_FLOAT:
203                 return 1;
204         case GL_FLOAT_VEC2:
205                 return 2;
206         case GL_FLOAT_VEC3:
207                 return 3;
208         case GL_FLOAT_VEC4:
209                 return 4;
210         case GL_FLOAT_MAT2:
211                 return 4;
212         case GL_FLOAT_MAT3:
213                 return 9;
214         case GL_FLOAT_MAT4:
215                 return 16;
216         default:
217                 break;
218         }
219
220         return -1;
221 }
222
223 void ShaderProgramGL::cache_uniforms()
224 {
225         uniforms.clear();
226
227         int num_uniforms;
228         glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uniforms);
229
230         int max_ulength;
231         glGetProgramiv(prog, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_ulength);
232
233         char *name = new char[max_ulength + 1];
234         name[max_ulength] = 0;
235
236         for(int i=0; i<num_uniforms; i++) {
237                 int usize;
238                 unsigned int utype;
239                 glGetActiveUniform(prog, i, max_ulength, 0, &usize, &utype, name);
240
241                 if(strstr(name, "gl_") == name)
242                         continue;
243
244                 if(strstr(name, "st_") != name)
245                         continue;
246
247                 int num_floats = get_floats_num(utype);
248                 if(num_floats == -1)
249                         continue;
250
251                 int idx = state_manager.add_state_element(name, num_floats);
252                 if(idx == -1)
253                         continue;
254
255                 Uniform uniform;
256                 uniform.name = name;
257                 uniform.location = glGetUniformLocation(prog, name);
258                 uniform.state_idx = idx;
259
260                 uniforms.push_back(uniform);
261         }
262
263         delete [] name;
264 }
265
266 void ShaderProgramGL::set_uniformi(int location, int value)
267 {
268         if(!use() || location == -1) {
269                 return;
270         }
271
272         glUniform1i(location, value);
273 }
274
275 void ShaderProgramGL::set_uniformi(int location, int x, int y)
276 {
277         if(!use() || location == -1) {
278                 return;
279         }
280
281         glUniform2i(location, x, y);
282 }
283
284 void ShaderProgramGL::set_uniformi(int location, int x, int y, int z)
285 {
286         if(!use() || location == -1) {
287                 return;
288         }
289
290         glUniform3i(location, x, y, z);
291 }
292
293 void ShaderProgramGL::set_uniformi(int location, int x, int y, int z, int w)
294 {
295         if(!use() || location == -1) {
296                 return;
297         }
298
299         glUniform4i(location, x, y, z, w);
300 }
301
302 void ShaderProgramGL::set_uniformf(int location, float value)
303 {
304         if(!use() || location == -1) {
305                 return;
306         }
307
308         glUniform1f(location, value);
309 }
310
311 void ShaderProgramGL::set_uniformf(int location, float x, float y)
312 {
313         if(!use() || location == -1) {
314                 return;
315         }
316
317         glUniform2f(location, x, y);
318 }
319
320 void ShaderProgramGL::set_uniformf(int location, float x, float y, float z)
321 {
322         if(!use() || location == -1) {
323                 return;
324         }
325
326         glUniform3f(location, x, y, z);
327 }
328
329 void ShaderProgramGL::set_uniformf(int location, float x, float y, float z, float w)
330 {
331         if(!use() || location == -1) {
332                 return;
333         }
334
335         glUniform4f(location, x, y, z, w);
336 }
337
338 void ShaderProgramGL::set_uniform_matrix(int location, const Mat4 &mat)
339 {
340         if(!use() || location == -1) {
341                 fprintf(stderr, "FOO\n");
342                 return;
343         }
344
345         glUniformMatrix4fv(location, 1, GL_TRUE, (float *)&mat.m[0][0]);
346 }