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