coeng

view src/shader.cc @ 8:8cce82794f90

seems to work nicely
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 15 Feb 2015 05:14:20 +0200
parents
children
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 "mesh.h"
9 #ifdef _MSC_VER
10 #include <malloc.h>
11 #else
12 #include <alloca.h>
13 #endif
15 #ifdef __GLEW_H__
16 #define HAVE_GEOMETRY_SHADER
17 #define HAVE_TESSELATION_SHADER
18 #endif
20 static std::string read_source(const char *fname);
21 static void bind_standard_attr(const ShaderProg *prog);
23 ShaderProg *ShaderProg::current;
25 void bind_shader(const ShaderProg *sdr)
26 {
27 if(sdr) {
28 sdr->bind();
29 } else {
30 #ifndef GL_ES_VERSION_2_0
31 glUseProgram(0);
32 ShaderProg::current = 0;
33 #endif
34 }
35 }
37 const ShaderProg *get_current_shader()
38 {
39 return ShaderProg::current;
40 }
42 Shader::Shader()
43 {
44 sdr = type = 0;
45 }
47 Shader::~Shader()
48 {
49 destroy();
50 }
52 unsigned int Shader::get_id() const
53 {
54 return sdr;
55 }
57 void Shader::set_name(const char *name)
58 {
59 this->name = std::string(name);
60 }
62 const char *Shader::get_name() const
63 {
64 return name.c_str();
65 }
67 bool Shader::create(const char *src, unsigned int type)
68 {
69 #if !GL_ES_VERSION_2_0
70 const char *src_arr[] = {src};
71 #else
72 const char *src_arr[] = { "precision mediump float; ", src };
73 #endif
75 // keep a copy of the source code
76 this->src = std::string(src);
78 if(!sdr) {
79 sdr = glCreateShader(type);
80 }
82 printf("compiling shader: %s... ", name.c_str());
84 glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0);
85 glCompileShader(sdr);
87 int status;
88 glGetShaderiv(sdr, GL_COMPILE_STATUS, &status);
90 printf(status ? "success\n" : "failed\n");
92 int info_len;
93 glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len);
94 if(info_len > 1) {
95 char *buf = (char*)alloca(info_len);
96 glGetShaderInfoLog(sdr, info_len, 0, buf);
97 buf[info_len - 1] = 0;
99 if(status) {
100 printf("%s\n", buf);
101 } else {
102 fprintf(stderr, "%s\n", buf);
103 }
104 }
106 return status == GL_TRUE;
107 }
109 void Shader::destroy()
110 {
111 if(sdr) {
112 glDeleteShader(sdr);
113 }
114 sdr = type = 0;
116 src.clear();
117 name.clear();
118 }
120 static std::string read_source(const char *fname)
121 {
122 FILE *fp;
124 if(!(fp = fopen(fname, "rb"))) {
125 fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno));
126 return std::string();
127 }
129 fseek(fp, 0, SEEK_END);
130 long sz = ftell(fp);
131 rewind(fp);
133 char *src = (char*)alloca(sz + 1);
134 if(fread(src, 1, sz, fp) < (size_t)sz) {
135 fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno));
136 fclose(fp);
137 delete [] src;
138 return std::string();
139 }
140 src[sz] = 0;
141 fclose(fp);
143 return std::string(src);
144 }
146 bool Shader::load(const char *fname, unsigned int type)
147 {
148 std::string src = read_source(fname);
149 if(src.empty()) {
150 return false;
151 }
152 set_name(fname);
153 return create(src.c_str(), type);
154 }
156 // ---- shader program ----
157 ShaderProg::ShaderProg()
158 {
159 prog = 0;
160 must_link = true;
161 }
163 ShaderProg::~ShaderProg()
164 {
165 destroy();
166 }
168 unsigned int ShaderProg::get_id() const
169 {
170 return prog;
171 }
173 bool ShaderProg::create(const char *src, unsigned int type, ...)
174 {
175 va_list ap;
177 va_start(ap, type);
178 bool res = create(src, type, ap);
179 va_end(ap);
181 return res;
182 }
184 bool ShaderProg::create(const char *src, unsigned int type, va_list ap)
185 {
186 destroy();
187 prog = glCreateProgram();
189 while(src) {
190 Shader *sdr = new Shader;
191 if(!sdr->create(src, type)) {
192 va_end(ap);
193 return false;
194 }
195 add_shader(sdr);
196 src = va_arg(ap, const char*);
197 type = va_arg(ap, unsigned int);
198 }
200 return link();
201 }
203 bool ShaderProg::create(const char *vsrc, const char *psrc)
204 {
205 return create(VSDR(vsrc), PSDR(psrc), 0);
206 }
208 bool ShaderProg::create(Shader *sdr, ...)
209 {
210 va_list ap;
212 va_start(ap, sdr);
213 bool res = create(sdr, ap);
214 va_end(ap);
216 return res;
217 }
219 bool ShaderProg::create(Shader *sdr, va_list ap)
220 {
221 destroy();
222 prog = glCreateProgram();
224 while(sdr) {
225 add_shader(sdr);
226 sdr = va_arg(ap, Shader*);
227 }
228 return link();
229 }
231 bool ShaderProg::create(Shader *vsdr, Shader *psdr)
232 {
233 return create(vsdr, psdr, 0);
234 }
236 void ShaderProg::destroy()
237 {
238 if(prog) {
239 glDeleteProgram(prog);
240 }
241 prog = 0;
243 shaders.clear();
244 // don't actually destroy the shaders, let the ShaderSet own them
245 }
247 bool ShaderProg::load(const char *fname, unsigned int type, ...)
248 {
249 va_list ap;
250 va_start(ap, type);
251 bool res = load(fname, type, ap);
252 va_end(ap);
254 return res;
255 }
257 bool ShaderProg::load(const char *fname, unsigned int type, va_list ap)
258 {
259 destroy();
260 prog = glCreateProgram();
262 while(fname) {
263 Shader *sdr = new Shader;
264 if(!sdr->load(fname, type)) {
265 delete sdr;
266 return false;
267 }
268 add_shader(sdr);
270 if((fname = va_arg(ap, const char*))) {
271 type = va_arg(ap, unsigned int);
272 }
273 }
275 return link();
276 }
278 bool ShaderProg::load(const char *vfname, const char *pfname)
279 {
280 return load(VSDR(vfname), PSDR(pfname), 0);
281 }
283 void ShaderProg::add_shader(Shader *sdr)
284 {
285 glAttachShader(prog, sdr->get_id());
286 }
288 bool ShaderProg::link() const
289 {
290 bind_standard_attr(this);
292 printf("linking program ... ");
293 glLinkProgram(prog);
295 int status;
296 glGetProgramiv(prog, GL_LINK_STATUS, &status);
298 printf(status ? "success\n" : "failed\n");
300 int info_len;
301 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len);
302 if(info_len > 1) {
303 char *buf = (char*)alloca(info_len);
304 glGetProgramInfoLog(prog, info_len, 0, buf);
305 buf[info_len - 1] = 0;
307 if(status) {
308 printf("%s\n", buf);
309 } else {
310 fprintf(stderr, "%s\n", buf);
311 }
312 }
314 if(status) {
315 must_link = false;
316 //cache_state_uniforms();
317 return true;
318 }
319 return false;
320 }
322 void ShaderProg::bind() const
323 {
324 if(must_link) {
325 if(!link()) {
326 return;
327 }
328 }
329 glUseProgram(prog);
330 ShaderProg::current = (ShaderProg*)this;
332 //setup_state_uniforms();
333 }
336 int ShaderProg::get_attrib_location(const char *name) const
337 {
338 glUseProgram(prog);
339 return glGetAttribLocation(prog, name);
340 }
342 void ShaderProg::set_attrib_location(const char *name, int loc) const
343 {
344 glBindAttribLocation(prog, loc, name);
345 must_link = true;
346 }
348 int ShaderProg::get_uniform_location(const char *name) const
349 {
350 glUseProgram(prog);
351 return glGetUniformLocation(prog, name);
352 }
354 bool ShaderProg::set_uniform(int loc, int val) const
355 {
356 glUseProgram(prog);
357 if(loc >= 0) {
358 glUniform1i(loc, val);
359 return true;
360 }
361 return false;
362 }
364 bool ShaderProg::set_uniform(int loc, float val) const
365 {
366 glUseProgram(prog);
367 if(loc >= 0) {
368 glUniform1f(loc, val);
369 return true;
370 }
371 return false;
372 }
374 bool ShaderProg::set_uniform(int loc, const Vector2 &v) const
375 {
376 glUseProgram(prog);
377 if(loc >= 0) {
378 glUniform2f(loc, v.x, v.y);
379 return true;
380 }
381 return false;
382 }
384 bool ShaderProg::set_uniform(int loc, const Vector3 &v) const
385 {
386 glUseProgram(prog);
387 if(loc >= 0) {
388 glUniform3f(loc, v.x, v.y, v.z);
389 return true;
390 }
391 return false;
392 }
394 bool ShaderProg::set_uniform(int loc, const Vector4 &v) const
395 {
396 glUseProgram(prog);
397 if(loc >= 0) {
398 glUniform4f(loc, v.x, v.y, v.z, v.w);
399 return true;
400 }
401 return false;
402 }
404 bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const
405 {
406 glUseProgram(prog);
407 if(loc >= 0) {
408 glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]);
409 return true;
410 }
411 return false;
412 }
414 bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const
415 {
416 glUseProgram(prog);
417 if(loc >= 0) {
418 glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]);
419 return true;
420 }
421 return false;
422 }
425 bool ShaderProg::set_uniform(const char *name, int val) const
426 {
427 return set_uniform(get_uniform_location(name), val);
428 }
430 bool ShaderProg::set_uniform(const char *name, float val) const
431 {
432 return set_uniform(get_uniform_location(name), val);
433 }
435 bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const
436 {
437 return set_uniform(get_uniform_location(name), v);
438 }
440 bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const
441 {
442 return set_uniform(get_uniform_location(name), v);
443 }
445 bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const
446 {
447 return set_uniform(get_uniform_location(name), v);
448 }
450 bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const
451 {
452 return set_uniform(get_uniform_location(name), m);
453 }
455 bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const
456 {
457 return set_uniform(get_uniform_location(name), m);
458 }
460 /*
461 static StType unist_type(GLenum type)
462 {
463 switch(type) {
464 case GL_FLOAT:
465 return ST_FLOAT;
466 case GL_FLOAT_VEC2:
467 return ST_FLOAT2;
468 case GL_FLOAT_VEC3:
469 return ST_FLOAT3;
470 case GL_FLOAT_VEC4:
471 return ST_FLOAT4;
472 case GL_INT:
473 case GL_SAMPLER_2D:
474 case GL_SAMPLER_CUBE:
475 #if !GL_ES_VERSION_2_0
476 case GL_SAMPLER_1D:
477 case GL_SAMPLER_3D:
478 case GL_SAMPLER_1D_SHADOW:
479 case GL_SAMPLER_2D_SHADOW:
480 #endif
481 return ST_INT;
482 case GL_INT_VEC2:
483 return ST_INT2;
484 case GL_INT_VEC3:
485 return ST_INT3;
486 case GL_INT_VEC4:
487 return ST_INT4;
488 case GL_FLOAT_MAT3:
489 return ST_MATRIX3;
490 case GL_FLOAT_MAT4:
491 return ST_MATRIX4;
492 default:
493 break;
494 }
495 return ST_UNKNOWN;
496 }
498 void ShaderProg::cache_state_uniforms() const
499 {
500 if(!glIsProgram(prog)) {
501 return;
502 }
504 int num_uni;
505 glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni);
507 char name[256];
508 for(int i=0; i<num_uni; i++) {
509 GLint sz;
510 GLenum type;
511 glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name);
513 if(strstr(name, "st_") == name) {
514 StateLocCache s;
515 s.sidx = add_unistate(name, unist_type(type));
516 s.loc = glGetUniformLocation(prog, name);
517 stloc_cache.push_back(s);
518 }
519 }
520 }
522 void ShaderProg::setup_state_uniforms() const
523 {
524 for(size_t i=0; i<stloc_cache.size(); i++) {
525 setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc);
526 }
527 }
528 */
530 // Static functions to use with ShaderSet
531 Shader *Shader::create_shader()
532 {
533 return new Shader;
534 }
536 bool Shader::load_shader(Shader *sdr, const char *fname)
537 {
538 std::string src = read_source(fname);
539 if(src.empty()) {
540 return false;
541 }
543 sdr->src = src;
544 return true;
545 }
547 bool Shader::done_shader(Shader *sdr, unsigned int type)
548 {
549 return sdr->create(sdr->src.c_str(), type);
550 }
552 /*
553 static bool done_vertex_shader(Shader *sdr)
554 {
555 return Shader::done_shader(sdr, GL_VERTEX_SHADER);
556 }
558 static bool done_pixel_shader(Shader *sdr)
559 {
560 return Shader::done_shader(sdr, GL_FRAGMENT_SHADER);
561 }
563 #ifdef HAVE_GEOMETRY_SHADER
564 static bool done_geom_shader(Shader *sdr)
565 {
566 return Shader::done_shader(sdr, GL_GEOMETRY_SHADER);
567 }
568 #endif
570 #ifdef HAVE_TESSELATION_SHADER
571 static bool done_tc_shader(Shader *sdr)
572 {
573 return Shader::done_shader(sdr, GL_TESS_CONTROL_SHADER);
574 }
576 static bool done_te_shader(Shader *sdr)
577 {
578 return Shader::done_shader(sdr, GL_TESS_EVALUATION_SHADER);
579 }
580 #endif
582 void Shader::destroy_shader(Shader *sdr)
583 {
584 delete sdr;
585 }
587 // ---- ShaderSet ----
589 ShaderSet::ShaderSet(unsigned int type)
590 : DataSet<Shader*>(Shader::create_shader, Shader::load_shader, 0, Shader::destroy_shader)
591 {
592 switch(type) {
593 case GL_VERTEX_SHADER:
594 done = done_vertex_shader;
595 break;
597 case GL_FRAGMENT_SHADER:
598 done = done_pixel_shader;
599 break;
601 #ifdef HAVE_GEOMETRY_SHADER
602 case GL_GEOMETRY_SHADER:
603 done = done_geom_shader;
604 break;
605 #endif
607 #ifdef HAVE_TESSELATION_SHADER
608 case GL_TESS_CONTROL_SHADER:
609 done = done_tc_shader;
610 break;
612 case GL_TESS_EVALUATION_SHADER:
613 done = done_te_shader;
614 break;
615 #endif
617 default:
618 fprintf(stderr, "ShaderSet constructed with invalid shader type!\n");
619 }
620 }
621 */
623 static struct { const char *name; int loc; } attr_loc[] = {
624 {"attr_vertex", MESH_ATTR_VERTEX},
625 {"attr_normal", MESH_ATTR_NORMAL},
626 {"attr_tangent", MESH_ATTR_TANGENT},
627 {"attr_texcoord", MESH_ATTR_TEXCOORD},
628 {"attr_color", MESH_ATTR_COLOR},
629 {"attr_boneweights", MESH_ATTR_BONEWEIGHTS},
630 {"attr_boneidx", MESH_ATTR_BONEIDX}
631 };
633 static void bind_standard_attr(const ShaderProg *prog)
634 {
635 // we must link once to find out which are the active attributes
636 glLinkProgram(prog->get_id());
638 int num_attr;
639 glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr);
641 char name[256];
642 for(int i=0; i<num_attr; i++) {
643 GLint sz;
644 GLenum type;
645 glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name);
647 for(int j=0; j<(int)(sizeof attr_loc / sizeof *attr_loc); j++) {
648 if(strcmp(name, attr_loc[j].name) == 0) {
649 prog->set_attrib_location(name, attr_loc[j].loc);
650 }
651 }
652 }
653 }
656 /*
657 static const char *strtype(unsigned int type)
658 {
659 switch(type) {
660 case GL_VERTEX_SHADER:
661 return "vertex";
662 case GL_FRAGMENT_SHADER:
663 return "fragment";
664 #ifdef HAVE_GEOMETRY_SHADER
665 case GL_GEOMETRY_SHADER:
666 return "geometry";
667 #endif
668 #ifdef HAVE_TESSELATION_SHADER
669 case GL_TESS_CONTROL_SHADER:
670 return "tesselation control";
671 case GL_TESS_EVALUATION_SHADER:
672 return "tesselation evaluation";
673 #endif
674 default:
675 break;
676 }
677 return "<unknown>";
678 }
679 */