goat3dgfx

view src/shader.cc @ 2:7bd5ebec3b6f

fixed visual studio project files, removed the dll crap
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 16 Nov 2013 13:26:53 +0200
parents
children 98f87a1dbb2f
line source
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"
11 #ifdef _MSC_VER
12 #include <malloc.h>
13 #else
14 #include <alloca.h>
15 #endif
17 #ifdef __GLEW_H__
18 #define HAVE_GEOMETRY_SHADER
19 #define HAVE_TESSELATION_SHADER
20 #endif
22 static void bind_standard_attr(const ShaderProg *prog);
23 static const char *strtype(unsigned int type);
25 ShaderProg *ShaderProg::current;
27 Shader::Shader()
28 {
29 sdr = type = 0;
30 name = 0;
31 }
33 Shader::~Shader()
34 {
35 destroy();
36 }
38 unsigned int Shader::get_id() const
39 {
40 return sdr;
41 }
43 void Shader::set_name(const char *name)
44 {
45 delete [] this->name;
46 this->name = new char[strlen(name) + 1];
47 strcpy(this->name, name);
48 }
50 const char *Shader::get_name() const
51 {
52 return name;
53 }
55 bool Shader::create(const char *src, unsigned int type)
56 {
57 #if !GL_ES_VERSION_2_0
58 const char *src_arr[] = {src};
59 #else
60 const char *src_arr[] = { "precision mediump float; ", src };
61 #endif
63 if(!sdr) {
64 sdr = glCreateShader(type);
65 }
67 info_log("compiling shader: %s... ", name ? name : "");
69 glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0);
70 glCompileShader(sdr);
72 int status;
73 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
75 info_log(status ? "success\n" : "failed\n");
77 int info_len;
78 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
79 if(info_len > 1) {
80 char *buf = (char*)alloca(info_len);
81 glGetShaderInfoLog(sdr, info_len, 0, buf);
82 buf[info_len - 1] = 0;
84 if(status) {
85 info_log("%s\n", buf);
86 } else {
87 error_log("%s\n", buf);
88 }
89 }
91 return status == GL_TRUE;
92 }
94 void Shader::destroy()
95 {
96 if(sdr) {
97 glDeleteShader(sdr);
98 }
99 sdr = type = 0;
101 delete [] name;
102 name = 0;
103 }
105 bool Shader::load(const char *fname, unsigned int type)
106 {
107 FILE *fp;
109 if(!(fp = fopen(fname, "rb"))) {
110 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
111 return false;
112 }
114 fseek(fp, 0, SEEK_END);
115 long sz = ftell(fp);
116 rewind(fp);
118 char *src = (char*)alloca(sz + 1);
119 if(fread(src, 1, sz, fp) < (size_t)sz) {
120 error_log("failed to load %s shader: %s: %s\n", strtype(type), fname, strerror(errno));
121 fclose(fp);
122 return false;
123 }
124 src[sz] = 0;
125 fclose(fp);
127 set_name(fname);
128 return create(src, type);
129 }
131 // ---- shader program ----
132 ShaderProg::ShaderProg()
133 {
134 prog = 0;
135 must_link = true;
136 }
138 ShaderProg::~ShaderProg()
139 {
140 destroy();
141 }
143 unsigned int ShaderProg::get_id() const
144 {
145 return prog;
146 }
148 bool ShaderProg::create(const char *src, unsigned int type, ...)
149 {
150 va_list ap;
152 va_start(ap, type);
153 bool res = create(src, type, ap);
154 va_end(ap);
156 return res;
157 }
159 bool ShaderProg::create(const char *src, unsigned int type, va_list ap)
160 {
161 destroy();
162 prog = glCreateProgram();
164 while(src) {
165 Shader *sdr = new Shader;
166 if(!sdr->create(src, type)) {
167 va_end(ap);
168 return false;
169 }
170 add_shader(sdr);
171 src = va_arg(ap, const char*);
172 type = va_arg(ap, unsigned int);
173 }
174 return link();
175 }
177 bool ShaderProg::create(const char *vsrc, const char *psrc)
178 {
179 return create(VSDR(vsrc), PSDR(psrc), 0);
180 }
182 bool ShaderProg::create(Shader *sdr, ...)
183 {
184 va_list ap;
186 va_start(ap, sdr);
187 bool res = create(sdr, ap);
188 va_end(ap);
190 return res;
191 }
193 bool ShaderProg::create(Shader *sdr, va_list ap)
194 {
195 destroy();
196 prog = glCreateProgram();
198 while(sdr) {
199 add_shader(sdr);
200 sdr = va_arg(ap, Shader*);
201 }
202 return link();
203 }
205 bool ShaderProg::create(Shader *vsdr, Shader *psdr)
206 {
207 return create(vsdr, psdr, 0);
208 }
210 void ShaderProg::destroy()
211 {
212 if(prog) {
213 glDeleteProgram(prog);
214 }
215 prog = 0;
217 shaders.clear();
218 // don't actually destroy the shaders, let the ShaderSet own them
219 }
221 bool ShaderProg::load(const char *fname, unsigned int type, ...)
222 {
223 va_list ap;
224 va_start(ap, type);
225 bool res = load(fname, type, ap);
226 va_end(ap);
228 return res;
229 }
231 bool ShaderProg::load(const char *fname, unsigned int type, va_list ap)
232 {
233 destroy();
234 prog = glCreateProgram();
236 while(fname) {
237 Shader *sdr = new Shader;
238 if(!sdr->load(fname, type)) {
239 delete sdr;
240 return false;
241 }
242 add_shader(sdr);
244 if((fname = va_arg(ap, const char*))) {
245 type = va_arg(ap, unsigned int);
246 }
247 }
249 return link();
250 }
252 bool ShaderProg::load(const char *vfname, const char *pfname)
253 {
254 return load(VSDR(vfname), PSDR(pfname), 0);
255 }
257 void ShaderProg::add_shader(Shader *sdr)
258 {
259 glAttachShader(prog, sdr->get_id());
260 }
262 bool ShaderProg::link() const
263 {
264 bind_standard_attr(this);
266 CHECKGLERR;
267 info_log("linking program ... ");
268 glLinkProgram(prog);
270 int status;
271 glGetProgramiv(prog, GL_LINK_STATUS, &status);
273 info_log(status ? "success\n" : "failed\n");
275 int info_len;
276 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
277 if(info_len > 1) {
278 char *buf = (char*)alloca(info_len);
279 glGetProgramInfoLog(prog, info_len, 0, buf);
280 buf[info_len - 1] = 0;
282 if(status) {
283 info_log("%s\n", buf);
284 } else {
285 error_log("%s\n", buf);
286 }
287 }
289 if(status) {
290 must_link = false;
291 cache_state_uniforms();
293 return true;
294 }
295 return false;
296 }
298 void ShaderProg::bind() const
299 {
300 CHECKGLERR;
301 if(must_link) {
302 if(!link()) {
303 return;
304 }
305 }
306 CHECKGLERR;
307 glUseProgram(prog);
308 ShaderProg::current = (ShaderProg*)this;
310 setup_state_uniforms();
311 }
314 int ShaderProg::get_attrib_location(const char *name) const
315 {
316 glUseProgram(prog);
317 return glGetAttribLocation(prog, name);
318 }
320 void ShaderProg::set_attrib_location(const char *name, int loc) const
321 {
322 glBindAttribLocation(prog, loc, name);
323 must_link = true;
324 }
326 int ShaderProg::get_uniform_location(const char *name) const
327 {
328 glUseProgram(prog);
329 return glGetUniformLocation(prog, name);
330 }
332 bool ShaderProg::set_uniform(int loc, int val) const
333 {
334 glUseProgram(prog);
335 if(loc >= 0) {
336 glUniform1i(loc, val);
337 return true;
338 }
339 return false;
340 }
342 bool ShaderProg::set_uniform(int loc, float val) const
343 {
344 glUseProgram(prog);
345 if(loc >= 0) {
346 glUniform1f(loc, val);
347 return true;
348 }
349 return false;
350 }
352 bool ShaderProg::set_uniform(int loc, const Vector2 &v) const
353 {
354 glUseProgram(prog);
355 if(loc >= 0) {
356 glUniform2f(loc, v.x, v.y);
357 return true;
358 }
359 return false;
360 }
362 bool ShaderProg::set_uniform(int loc, const Vector3 &v) const
363 {
364 glUseProgram(prog);
365 if(loc >= 0) {
366 glUniform3f(loc, v.x, v.y, v.z);
367 return true;
368 }
369 return false;
370 }
372 bool ShaderProg::set_uniform(int loc, const Vector4 &v) const
373 {
374 glUseProgram(prog);
375 if(loc >= 0) {
376 glUniform4f(loc, v.x, v.y, v.z, v.w);
377 return true;
378 }
379 return false;
380 }
382 bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const
383 {
384 glUseProgram(prog);
385 if(loc >= 0) {
386 glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]);
387 return true;
388 }
389 return false;
390 }
392 bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const
393 {
394 glUseProgram(prog);
395 if(loc >= 0) {
396 glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]);
397 return true;
398 }
399 return false;
400 }
403 bool ShaderProg::set_uniform(const char *name, int val) const
404 {
405 return set_uniform(get_uniform_location(name), val);
406 }
408 bool ShaderProg::set_uniform(const char *name, float val) const
409 {
410 return set_uniform(get_uniform_location(name), val);
411 }
413 bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const
414 {
415 return set_uniform(get_uniform_location(name), v);
416 }
418 bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const
419 {
420 return set_uniform(get_uniform_location(name), v);
421 }
423 bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const
424 {
425 return set_uniform(get_uniform_location(name), v);
426 }
428 bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const
429 {
430 return set_uniform(get_uniform_location(name), m);
431 }
433 bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const
434 {
435 return set_uniform(get_uniform_location(name), m);
436 }
438 static StType unist_type(GLenum type)
439 {
440 switch(type) {
441 case GL_FLOAT:
442 return ST_FLOAT;
443 case GL_FLOAT_VEC2:
444 return ST_FLOAT2;
445 case GL_FLOAT_VEC3:
446 return ST_FLOAT3;
447 case GL_FLOAT_VEC4:
448 return ST_FLOAT4;
449 case GL_INT:
450 case GL_SAMPLER_2D:
451 case GL_SAMPLER_CUBE:
452 #if !GL_ES_VERSION_2_0
453 case GL_SAMPLER_1D:
454 case GL_SAMPLER_3D:
455 case GL_SAMPLER_1D_SHADOW:
456 case GL_SAMPLER_2D_SHADOW:
457 #endif
458 return ST_INT;
459 case GL_INT_VEC2:
460 return ST_INT2;
461 case GL_INT_VEC3:
462 return ST_INT3;
463 case GL_INT_VEC4:
464 return ST_INT4;
465 case GL_FLOAT_MAT3:
466 return ST_MATRIX3;
467 case GL_FLOAT_MAT4:
468 return ST_MATRIX4;
469 default:
470 break;
471 }
472 return ST_UNKNOWN;
473 }
475 void ShaderProg::cache_state_uniforms() const
476 {
477 if(!glIsProgram(prog)) {
478 return;
479 }
481 int num_uni;
482 glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni);
484 char name[256];
485 for(int i=0; i<num_uni; i++) {
486 GLint sz;
487 GLenum type;
488 glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name);
490 if(strstr(name, "st_") == name) {
491 StateLocCache s;
492 s.sidx = add_unistate(name, unist_type(type));
493 s.loc = glGetUniformLocation(prog, name);
494 stloc_cache.push_back(s);
495 }
496 }
497 }
499 void ShaderProg::setup_state_uniforms() const
500 {
501 for(size_t i=0; i<stloc_cache.size(); i++) {
502 setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc);
503 CHECKGLERR;
504 }
505 }
507 // ---- ShaderSet ----
508 static Shader *load_shader(const char *fname, unsigned int type)
509 {
510 Shader *sdr = new Shader;
511 if(!sdr->load(fname, type)) {
512 delete sdr;
513 return 0;
514 }
515 return sdr;
516 }
518 static Shader *load_vertex_shader(const char *fname)
519 {
520 return load_shader(fname, GL_VERTEX_SHADER);
521 }
523 static Shader *load_pixel_shader(const char *fname)
524 {
525 return load_shader(fname, GL_FRAGMENT_SHADER);
526 }
528 #ifdef HAVE_GEOMETRY_SHADER
529 static Shader *load_geom_shader(const char *fname)
530 {
531 return load_shader(fname, GL_GEOMETRY_SHADER);
532 }
533 #endif
535 #ifdef HAVE_TESSELATION_SHADER
536 static Shader *load_tc_shader(const char *fname)
537 {
538 return load_shader(fname, GL_TESS_CONTROL_SHADER);
539 }
541 static Shader *load_te_shader(const char *fname)
542 {
543 return load_shader(fname, GL_TESS_EVALUATION_SHADER);
544 }
545 #endif
547 static void destroy_shader(Shader *sdr)
548 {
549 delete sdr;
550 }
552 ShaderSet::ShaderSet(unsigned int type)
553 : DataSet<Shader*>(0, destroy_shader)
554 {
555 this->type = type;
557 switch(type) {
558 case GL_VERTEX_SHADER:
559 load = load_vertex_shader;
560 break;
562 case GL_FRAGMENT_SHADER:
563 load = load_pixel_shader;
564 break;
566 #ifdef HAVE_GEOMETRY_SHADER
567 case GL_GEOMETRY_SHADER:
568 load = load_geom_shader;
569 break;
570 #endif
572 #ifdef HAVE_TESSELATION_SHADER
573 case GL_TESS_CONTROL_SHADER:
574 load = load_tc_shader;
575 break;
577 case GL_TESS_EVALUATION_SHADER:
578 load = load_te_shader;
579 break;
580 #endif
582 default:
583 error_log("ShaderSet constructed with invalid shader type!\n");
584 }
585 }
587 static struct { const char *name; int loc; } attr_loc[] = {
588 {"attr_vertex", MESH_ATTR_VERTEX},
589 {"attr_normal", MESH_ATTR_NORMAL},
590 {"attr_tangent", MESH_ATTR_TANGENT},
591 {"attr_texcoord", MESH_ATTR_TEXCOORD},
592 {"attr_color", MESH_ATTR_COLOR},
593 {"attr_boneweights", MESH_ATTR_BONEWEIGHTS},
594 {"attr_boneidx", MESH_ATTR_BONEIDX}
595 };
597 static void bind_standard_attr(const ShaderProg *prog)
598 {
599 // we must link once to find out which are the active attributes
600 glLinkProgram(prog->get_id());
602 int num_attr;
603 glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr);
605 char name[256];
606 for(int i=0; i<num_attr; i++) {
607 GLint sz;
608 GLenum type;
609 glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name);
611 for(int j=0; j<sizeof attr_loc / sizeof *attr_loc; j++) {
612 if(strcmp(name, attr_loc[j].name) == 0) {
613 prog->set_attrib_location(name, attr_loc[j].loc);
614 }
615 }
616 }
617 }
620 static const char *strtype(unsigned int type)
621 {
622 switch(type) {
623 case GL_VERTEX_SHADER:
624 return "vertex";
625 case GL_FRAGMENT_SHADER:
626 return "fragment";
627 #ifdef HAVE_GEOMETRY_SHADER
628 case GL_GEOMETRY_SHADER:
629 return "geometry";
630 #endif
631 #ifdef HAVE_TESSELATION_SHADER
632 case GL_TESS_CONTROL_SHADER:
633 return "tesselation control";
634 case GL_TESS_EVALUATION_SHADER:
635 return "tesselation evaluation";
636 #endif
637 default:
638 break;
639 }
640 return "<unknown>";
641 }