SceneNode bounds calculation
[laserbrain_demo] / src / shader.cc
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdarg.h>
4 #include <errno.h>
5 #include "opengl.h"
6 #include "shader.h"
7 #include "logger.h"
8 #include "unistate.h"
9 #include "mesh.h"
10
11 #ifdef _WIN32
12 #include <malloc.h>
13 #else
14 #include <alloca.h>
15 #endif
16
17 #ifdef __GLEW_H__
18 #define HAVE_GEOMETRY_SHADER
19 #define HAVE_TESSELATION_SHADER
20 #endif
21
22 static void bind_standard_attr(const ShaderProg *prog);
23 static const char *strtype(unsigned int type);
24
25 ShaderProg *ShaderProg::current;
26
27 void bind_shader(const ShaderProg *sdr)
28 {
29         if(sdr) {
30                 sdr->bind();
31         } else {
32 #ifndef GL_ES_VERSION_2_0
33                 glUseProgram(0);
34                 ShaderProg::current = 0;
35 #endif
36         }
37 }
38
39 const ShaderProg *get_current_shader()
40 {
41         return ShaderProg::current;
42 }
43
44
45 Shader::Shader()
46 {
47         sdr = type = 0;
48         name = src = 0;
49 }
50
51 Shader::~Shader()
52 {
53         destroy();
54 }
55
56 unsigned int Shader::get_id() const
57 {
58         return sdr;
59 }
60
61 unsigned int Shader::get_type() const
62 {
63         return type;
64 }
65
66 void Shader::set_name(const char *name)
67 {
68         delete [] this->name;
69         this->name = new char[strlen(name) + 1];
70         strcpy(this->name, name);
71 }
72
73 const char *Shader::get_name() const
74 {
75         return name;
76 }
77
78 void Shader::set_source(const char *src)
79 {
80         delete [] this->src;
81         this->src = new char[strlen(src) + 1];
82         strcpy(this->src, src);
83 }
84
85 const char *Shader::get_source() const
86 {
87         return src;
88 }
89
90 bool Shader::create(const char *src, unsigned int type)
91 {
92 #if !GL_ES_VERSION_2_0
93         const char *src_arr[] = {src};
94 #else
95         const char *src_arr[] = { "precision mediump float; ", src };
96 #endif
97         this->type = type;
98
99         if(src != this->src) {
100                 delete [] this->src;
101                 int len = strlen(src);
102                 this->src = new char[len + 1];
103                 memcpy(this->src, src, len + 1);
104         }
105
106         if(!sdr) {
107                 sdr = glCreateShader(type);
108         }
109
110         info_log("compiling shader: %s... ", name ? name : "");
111
112         glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0);
113
114         glCompileShader(sdr);
115
116         int status;
117         glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
118
119         info_log(status ? "success\n" : "failed\n");
120
121         int info_len;
122         glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
123         if(info_len > 1) {
124                 char *buf = (char*)alloca(info_len);
125                 glGetShaderInfoLog(sdr, info_len, 0, buf);
126                 buf[info_len - 1] = 0;
127
128                 if(status) {
129                         info_log("%s\n", buf);
130                 } else {
131                         error_log("%s\n", buf);
132                 }
133         }
134
135         return status == GL_TRUE;
136 }
137
138 void Shader::destroy()
139 {
140         if(sdr) {
141                 glDeleteShader(sdr);
142         }
143         sdr = type = 0;
144         delete [] src;
145         src = 0;
146         delete [] name;
147         name = 0;
148 }
149
150 bool Shader::load(const char *fname, unsigned int type)
151 {
152         FILE *fp;
153
154         if(!(fp = fopen(fname, "rb"))) {
155                 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
156                 return false;
157         }
158
159         fseek(fp, 0, SEEK_END);
160         long sz = ftell(fp);
161         fseek(fp, 0, SEEK_SET);
162
163         char *src = (char*)alloca(sz + 1);
164         if(fread(src, 1, sz, fp) < (size_t)sz) {
165                 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
166                 fclose(fp);
167                 return false;
168         }
169         src[sz] = 0;
170         fclose(fp);
171
172         set_name(fname);
173         return create(src, type);
174 }
175
176 // ---- shader program ----
177 ShaderProg::ShaderProg()
178 {
179         prog = 0;
180         must_link = true;
181 }
182
183 ShaderProg::~ShaderProg()
184 {
185         destroy();
186 }
187
188 unsigned int ShaderProg::get_id() const
189 {
190         return prog;
191 }
192
193 bool ShaderProg::create(const char *src, unsigned int type, ...)
194 {
195         va_list ap;
196
197         va_start(ap, type);
198         bool res = create(src, type, ap);
199         va_end(ap);
200
201         return res;
202 }
203
204 bool ShaderProg::create(const char *src, unsigned int type, va_list ap)
205 {
206         destroy();
207         prog = glCreateProgram();
208
209         while(src) {
210                 Shader *sdr = new Shader;
211                 if(!sdr->create(src, type)) {
212                         delete sdr;
213                         return false;
214                 }
215                 add_shader(sdr);
216                 src = va_arg(ap, const char*);
217                 type = va_arg(ap, unsigned int);
218         }
219         return link();
220 }
221
222 bool ShaderProg::create(const char *vsrc, const char *psrc)
223 {
224         return create(VSDR(vsrc), PSDR(psrc), 0);
225 }
226
227 bool ShaderProg::create(Shader *sdr, ...)
228 {
229         va_list ap;
230
231         va_start(ap, sdr);
232         bool res = create(sdr, ap);
233         va_end(ap);
234
235         return res;
236 }
237
238 bool ShaderProg::create(Shader *sdr, va_list ap)
239 {
240         destroy();
241         prog = glCreateProgram();
242
243         while(sdr) {
244                 add_shader(sdr);
245                 sdr = va_arg(ap, Shader*);
246         }
247         return link();
248 }
249
250 bool ShaderProg::create(Shader *vsdr, Shader *psdr)
251 {
252         return create(vsdr, psdr, 0);
253 }
254
255 void ShaderProg::destroy()
256 {
257         if(prog) {
258                 glDeleteProgram(prog);
259         }
260         prog = 0;
261
262         shaders.clear();
263         // don't actually destroy the shaders, let the ShaderSet own them
264 }
265
266 bool ShaderProg::load(const char *fname, unsigned int type, ...)
267 {
268         va_list ap;
269         va_start(ap, type);
270         bool res = load(fname, type, ap);
271         va_end(ap);
272
273         return res;
274 }
275
276 bool ShaderProg::load(const char *fname, unsigned int type, va_list ap)
277 {
278         destroy();
279         prog = glCreateProgram();
280
281         while(fname) {
282                 Shader *sdr = new Shader;
283                 if(!sdr->load(fname, type)) {
284                         delete sdr;
285                         return false;
286                 }
287                 add_shader(sdr);
288
289                 if((fname = va_arg(ap, const char*))) {
290                         type = va_arg(ap, unsigned int);
291                 }
292         }
293
294         return link();
295 }
296
297 bool ShaderProg::load(const char *vfname, const char *pfname)
298 {
299         return load(VSDR(vfname), PSDR(pfname), 0);
300 }
301
302 void ShaderProg::add_shader(Shader *sdr)
303 {
304         glAttachShader(prog, sdr->get_id());
305 }
306
307 bool ShaderProg::link() const
308 {
309         bind_standard_attr(this);
310
311         info_log("linking program ... ");
312         glLinkProgram(prog);
313
314         int status;
315         glGetProgramiv(prog, GL_LINK_STATUS, &status);
316
317         info_log(status ? "success\n" : "failed\n");
318
319         int info_len;
320         glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
321         if(info_len > 1) {
322                 char *buf = (char*)alloca(info_len);
323                 glGetProgramInfoLog(prog, info_len, 0, buf);
324                 buf[info_len - 1] = 0;
325
326                 if(status) {
327                         info_log("%s\n", buf);
328                 } else {
329                         error_log("%s\n", buf);
330                 }
331         }
332
333         if(status) {
334                 must_link = false;
335                 cache_state_uniforms();
336
337                 return true;
338         }
339         return false;
340 }
341
342 void ShaderProg::bind() const
343 {
344         if(must_link) {
345                 if(!link()) {
346                         return;
347                 }
348         }
349         glUseProgram(prog);
350         ShaderProg::current = (ShaderProg*)this;
351
352         setup_state_uniforms();
353 }
354
355
356 int ShaderProg::get_attrib_location(const char *name) const
357 {
358         bind();
359         return glGetAttribLocation(prog, name);
360 }
361
362 void ShaderProg::set_attrib_location(const char *name, int loc) const
363 {
364         glBindAttribLocation(prog, loc, name);
365         must_link = true;
366 }
367
368 int ShaderProg::get_uniform_location(const char *name) const
369 {
370         bind();
371         return glGetUniformLocation(prog, name);
372 }
373
374 bool ShaderProg::set_uniform(int loc, int val) const
375 {
376         bind();
377         if(loc >= 0) {
378                 glUniform1i(loc, val);
379                 return true;
380         }
381         return false;
382 }
383
384 bool ShaderProg::set_uniform(int loc, float val) const
385 {
386         bind();
387         if(loc >= 0) {
388                 glUniform1f(loc, val);
389                 return true;
390         }
391         return false;
392 }
393
394 bool ShaderProg::set_uniform(int loc, const Vec2 &v) const
395 {
396         bind();
397         if(loc >= 0) {
398                 glUniform2f(loc, v.x, v.y);
399                 return true;
400         }
401         return false;
402 }
403
404 bool ShaderProg::set_uniform(int loc, const Vec3 &v) const
405 {
406         bind();
407         if(loc >= 0) {
408                 glUniform3f(loc, v.x, v.y, v.z);
409                 return true;
410         }
411         return false;
412 }
413
414 bool ShaderProg::set_uniform(int loc, const Vec4 &v) const
415 {
416         bind();
417         if(loc >= 0) {
418                 glUniform4f(loc, v.x, v.y, v.z, v.w);
419                 return true;
420         }
421         return false;
422 }
423
424 bool ShaderProg::set_uniform(int loc, const Mat3 &m) const
425 {
426         bind();
427         if(loc >= 0) {
428                 glUniformMatrix3fv(loc, 1, GL_FALSE, m[0]);
429                 return true;
430         }
431         return false;
432 }
433
434 bool ShaderProg::set_uniform(int loc, const Mat4 &m) const
435 {
436         bind();
437         if(loc >= 0) {
438                 glUniformMatrix4fv(loc, 1, GL_FALSE, m[0]);
439                 return true;
440         }
441         return false;
442 }
443
444
445 bool ShaderProg::set_uniform(const char *name, int val) const
446 {
447         return set_uniform(get_uniform_location(name), val);
448 }
449
450 bool ShaderProg::set_uniform(const char *name, float val) const
451 {
452         return set_uniform(get_uniform_location(name), val);
453 }
454
455 bool ShaderProg::set_uniform(const char *name, const Vec2 &v) const
456 {
457         return set_uniform(get_uniform_location(name), v);
458 }
459
460 bool ShaderProg::set_uniform(const char *name, const Vec3 &v) const
461 {
462         return set_uniform(get_uniform_location(name), v);
463 }
464
465 bool ShaderProg::set_uniform(const char *name, const Vec4 &v) const
466 {
467         return set_uniform(get_uniform_location(name), v);
468 }
469
470 bool ShaderProg::set_uniform(const char *name, const Mat3 &m) const
471 {
472         return set_uniform(get_uniform_location(name), m);
473 }
474
475 bool ShaderProg::set_uniform(const char *name, const Mat4 &m) const
476 {
477         return set_uniform(get_uniform_location(name), m);
478 }
479
480 static StType unist_type(GLenum type)
481 {
482         switch(type) {
483         case GL_FLOAT:
484                 return ST_FLOAT;
485         case GL_FLOAT_VEC2:
486                 return ST_FLOAT2;
487         case GL_FLOAT_VEC3:
488                 return ST_FLOAT3;
489         case GL_FLOAT_VEC4:
490                 return ST_FLOAT4;
491         case GL_INT:
492         case GL_SAMPLER_2D:
493         case GL_SAMPLER_CUBE:
494 #if !GL_ES_VERSION_2_0
495         case GL_SAMPLER_1D:
496         case GL_SAMPLER_3D:
497         case GL_SAMPLER_1D_SHADOW:
498         case GL_SAMPLER_2D_SHADOW:
499 #endif
500                 return ST_INT;
501         case GL_INT_VEC2:
502                 return ST_INT2;
503         case GL_INT_VEC3:
504                 return ST_INT3;
505         case GL_INT_VEC4:
506                 return ST_INT4;
507         case GL_FLOAT_MAT3:
508                 return ST_MATRIX3;
509         case GL_FLOAT_MAT4:
510                 return ST_MATRIX4;
511         default:
512                 break;
513         }
514         return ST_UNKNOWN;
515 }
516
517 void ShaderProg::cache_state_uniforms() const
518 {
519         if(!glIsProgram(prog)) {
520                 return;
521         }
522
523         int num_uni;
524         glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni);
525
526         char name[256];
527         for(int i=0; i<num_uni; i++) {
528                 GLint sz;
529                 GLenum type;
530                 glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name);
531
532                 if(strstr(name, "st_") == name) {
533                         StateLocCache s;
534                         s.sidx = add_unistate(name, unist_type(type));
535                         s.loc = glGetUniformLocation(prog, name);
536                         stloc_cache.push_back(s);
537                 }
538         }
539 }
540
541 void ShaderProg::setup_state_uniforms() const
542 {
543 #ifdef USE_OLDGL
544         setup_gl_matrices();
545 #endif
546
547         for(size_t i=0; i<stloc_cache.size(); i++) {
548                 setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc);
549         }
550 }
551
552 // ---- ShaderSet ----
553 static Shader *create_shader()
554 {
555         return new Shader;
556 }
557
558 bool load_shader(Shader *sdr, const char *fname, unsigned int type)
559 {
560         FILE *fp;
561
562         if(!(fp = fopen(fname, "rb"))) {
563                 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
564                 return false;
565         }
566
567         fseek(fp, 0, SEEK_END);
568         long sz = ftell(fp);
569         fseek(fp, 0, SEEK_SET);
570
571         sdr->src = new char[sz + 1];
572         if(fread(sdr->src, 1, sz, fp) < (size_t)sz) {
573                 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
574                 fclose(fp);
575                 delete [] sdr->src;
576                 return false;
577         }
578         sdr->src[sz] = 0;
579         fclose(fp);
580
581         sdr->set_name(fname);
582         return true;
583 }
584
585 static bool load_vertex_shader(Shader *sdr, const char *fname)
586 {
587         return load_shader(sdr, fname, GL_VERTEX_SHADER);
588 }
589
590 static bool load_pixel_shader(Shader *sdr, const char *fname)
591 {
592         return load_shader(sdr, fname, GL_FRAGMENT_SHADER);
593 }
594
595 #ifdef HAVE_GEOMETRY_SHADER
596 static bool load_geom_shader(Shader *sdr, const char *fname)
597 {
598         return load_shader(sdr, fname, GL_GEOMETRY_SHADER);
599 }
600 #endif
601
602 #ifdef HAVE_TESSELATION_SHADER
603 static bool load_tc_shader(Shader *sdr, const char *fname)
604 {
605         return load_shader(sdr, fname, GL_TESS_CONTROL_SHADER);
606 }
607
608 static bool load_te_shader(Shader *sdr, const char *fname)
609 {
610         return load_shader(sdr, fname, GL_TESS_EVALUATION_SHADER);
611 }
612 #endif
613
614 static bool done_shader(Shader *sdr)
615 {
616         return sdr->create(sdr->get_source(), sdr->get_type());
617 }
618
619 static void destroy_shader(Shader *sdr)
620 {
621         delete sdr;
622 }
623
624 ShaderSet::ShaderSet(unsigned int type)
625         : DataSet<Shader*>(create_shader, 0, done_shader, destroy_shader)
626 {
627         this->type = type;
628
629         switch(type) {
630         case GL_VERTEX_SHADER:
631                 load = load_vertex_shader;
632                 break;
633
634         case GL_FRAGMENT_SHADER:
635                 load = load_pixel_shader;
636                 break;
637
638 #ifdef HAVE_GEOMETRY_SHADER
639         case GL_GEOMETRY_SHADER:
640                 load = load_geom_shader;
641                 break;
642 #endif
643
644 #ifdef HAVE_TESSELATION_SHADER
645         case GL_TESS_CONTROL_SHADER:
646                 load = load_tc_shader;
647                 break;
648
649         case GL_TESS_EVALUATION_SHADER:
650                 load = load_te_shader;
651                 break;
652 #endif
653
654         default:
655                 error_log("ShaderSet constructed with invalid shader type!\n");
656         }
657 }
658
659 static struct {
660         const char *name;
661         int loc;
662 } attr_loc[] = {
663         {"attr_vertex", MESH_ATTR_VERTEX},
664         {"attr_normal", MESH_ATTR_NORMAL},
665         {"attr_tangent", MESH_ATTR_TANGENT},
666         {"attr_texcoord", MESH_ATTR_TEXCOORD},
667         {"attr_color", MESH_ATTR_COLOR},
668         {"attr_boneweights", MESH_ATTR_BONEWEIGHTS},
669         {"attr_boneidx", MESH_ATTR_BONEIDX}
670 };
671
672 static void bind_standard_attr(const ShaderProg *prog)
673 {
674         // we must link once to find out which are the active attributes
675         glLinkProgram(prog->get_id());
676
677         int num_attr;
678         glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr);
679
680         char name[256];
681         for(int i=0; i<num_attr; i++) {
682                 GLint sz;
683                 GLenum type;
684                 glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name);
685
686                 for(int j=0; j<(int)(sizeof attr_loc / sizeof *attr_loc); j++) {
687                         if(strcmp(name, attr_loc[j].name) == 0) {
688                                 prog->set_attrib_location(name, attr_loc[j].loc);
689                         }
690                 }
691         }
692 }
693
694
695 static const char *strtype(unsigned int type)
696 {
697         switch(type) {
698         case GL_VERTEX_SHADER:
699                 return "vertex";
700         case GL_FRAGMENT_SHADER:
701                 return "fragment";
702 #ifdef HAVE_GEOMETRY_SHADER
703         case GL_GEOMETRY_SHADER:
704                 return "geometry";
705 #endif
706 #ifdef HAVE_TESSELATION_SHADER
707         case GL_TESS_CONTROL_SHADER:
708                 return "tesselation control";
709         case GL_TESS_EVALUATION_SHADER:
710                 return "tesselation evaluation";
711 #endif
712         default:
713                 break;
714         }
715         return "<unknown>";
716 }