coeng
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/shader.cc Sun Feb 15 05:14:20 2015 +0200 1.3 @@ -0,0 +1,679 @@ 1.4 +#include <stdio.h> 1.5 +#include <string.h> 1.6 +#include <stdarg.h> 1.7 +#include <errno.h> 1.8 +#include "opengl.h" 1.9 +#include "shader.h" 1.10 +#include "mesh.h" 1.11 + 1.12 +#ifdef _MSC_VER 1.13 +#include <malloc.h> 1.14 +#else 1.15 +#include <alloca.h> 1.16 +#endif 1.17 + 1.18 +#ifdef __GLEW_H__ 1.19 +#define HAVE_GEOMETRY_SHADER 1.20 +#define HAVE_TESSELATION_SHADER 1.21 +#endif 1.22 + 1.23 +static std::string read_source(const char *fname); 1.24 +static void bind_standard_attr(const ShaderProg *prog); 1.25 + 1.26 +ShaderProg *ShaderProg::current; 1.27 + 1.28 +void bind_shader(const ShaderProg *sdr) 1.29 +{ 1.30 + if(sdr) { 1.31 + sdr->bind(); 1.32 + } else { 1.33 +#ifndef GL_ES_VERSION_2_0 1.34 + glUseProgram(0); 1.35 + ShaderProg::current = 0; 1.36 +#endif 1.37 + } 1.38 +} 1.39 + 1.40 +const ShaderProg *get_current_shader() 1.41 +{ 1.42 + return ShaderProg::current; 1.43 +} 1.44 + 1.45 +Shader::Shader() 1.46 +{ 1.47 + sdr = type = 0; 1.48 +} 1.49 + 1.50 +Shader::~Shader() 1.51 +{ 1.52 + destroy(); 1.53 +} 1.54 + 1.55 +unsigned int Shader::get_id() const 1.56 +{ 1.57 + return sdr; 1.58 +} 1.59 + 1.60 +void Shader::set_name(const char *name) 1.61 +{ 1.62 + this->name = std::string(name); 1.63 +} 1.64 + 1.65 +const char *Shader::get_name() const 1.66 +{ 1.67 + return name.c_str(); 1.68 +} 1.69 + 1.70 +bool Shader::create(const char *src, unsigned int type) 1.71 +{ 1.72 +#if !GL_ES_VERSION_2_0 1.73 + const char *src_arr[] = {src}; 1.74 +#else 1.75 + const char *src_arr[] = { "precision mediump float; ", src }; 1.76 +#endif 1.77 + 1.78 + // keep a copy of the source code 1.79 + this->src = std::string(src); 1.80 + 1.81 + if(!sdr) { 1.82 + sdr = glCreateShader(type); 1.83 + } 1.84 + 1.85 + printf("compiling shader: %s... ", name.c_str()); 1.86 + 1.87 + glShaderSource(sdr, sizeof src_arr / sizeof *src_arr, src_arr, 0); 1.88 + glCompileShader(sdr); 1.89 + 1.90 + int status; 1.91 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); 1.92 + 1.93 + printf(status ? "success\n" : "failed\n"); 1.94 + 1.95 + int info_len; 1.96 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &info_len); 1.97 + if(info_len > 1) { 1.98 + char *buf = (char*)alloca(info_len); 1.99 + glGetShaderInfoLog(sdr, info_len, 0, buf); 1.100 + buf[info_len - 1] = 0; 1.101 + 1.102 + if(status) { 1.103 + printf("%s\n", buf); 1.104 + } else { 1.105 + fprintf(stderr, "%s\n", buf); 1.106 + } 1.107 + } 1.108 + 1.109 + return status == GL_TRUE; 1.110 +} 1.111 + 1.112 +void Shader::destroy() 1.113 +{ 1.114 + if(sdr) { 1.115 + glDeleteShader(sdr); 1.116 + } 1.117 + sdr = type = 0; 1.118 + 1.119 + src.clear(); 1.120 + name.clear(); 1.121 +} 1.122 + 1.123 +static std::string read_source(const char *fname) 1.124 +{ 1.125 + FILE *fp; 1.126 + 1.127 + if(!(fp = fopen(fname, "rb"))) { 1.128 + fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno)); 1.129 + return std::string(); 1.130 + } 1.131 + 1.132 + fseek(fp, 0, SEEK_END); 1.133 + long sz = ftell(fp); 1.134 + rewind(fp); 1.135 + 1.136 + char *src = (char*)alloca(sz + 1); 1.137 + if(fread(src, 1, sz, fp) < (size_t)sz) { 1.138 + fprintf(stderr, "failed to load shader: %s: %s\n", fname, strerror(errno)); 1.139 + fclose(fp); 1.140 + delete [] src; 1.141 + return std::string(); 1.142 + } 1.143 + src[sz] = 0; 1.144 + fclose(fp); 1.145 + 1.146 + return std::string(src); 1.147 +} 1.148 + 1.149 +bool Shader::load(const char *fname, unsigned int type) 1.150 +{ 1.151 + std::string src = read_source(fname); 1.152 + if(src.empty()) { 1.153 + return false; 1.154 + } 1.155 + set_name(fname); 1.156 + return create(src.c_str(), type); 1.157 +} 1.158 + 1.159 +// ---- shader program ---- 1.160 +ShaderProg::ShaderProg() 1.161 +{ 1.162 + prog = 0; 1.163 + must_link = true; 1.164 +} 1.165 + 1.166 +ShaderProg::~ShaderProg() 1.167 +{ 1.168 + destroy(); 1.169 +} 1.170 + 1.171 +unsigned int ShaderProg::get_id() const 1.172 +{ 1.173 + return prog; 1.174 +} 1.175 + 1.176 +bool ShaderProg::create(const char *src, unsigned int type, ...) 1.177 +{ 1.178 + va_list ap; 1.179 + 1.180 + va_start(ap, type); 1.181 + bool res = create(src, type, ap); 1.182 + va_end(ap); 1.183 + 1.184 + return res; 1.185 +} 1.186 + 1.187 +bool ShaderProg::create(const char *src, unsigned int type, va_list ap) 1.188 +{ 1.189 + destroy(); 1.190 + prog = glCreateProgram(); 1.191 + 1.192 + while(src) { 1.193 + Shader *sdr = new Shader; 1.194 + if(!sdr->create(src, type)) { 1.195 + va_end(ap); 1.196 + return false; 1.197 + } 1.198 + add_shader(sdr); 1.199 + src = va_arg(ap, const char*); 1.200 + type = va_arg(ap, unsigned int); 1.201 + } 1.202 + 1.203 + return link(); 1.204 +} 1.205 + 1.206 +bool ShaderProg::create(const char *vsrc, const char *psrc) 1.207 +{ 1.208 + return create(VSDR(vsrc), PSDR(psrc), 0); 1.209 +} 1.210 + 1.211 +bool ShaderProg::create(Shader *sdr, ...) 1.212 +{ 1.213 + va_list ap; 1.214 + 1.215 + va_start(ap, sdr); 1.216 + bool res = create(sdr, ap); 1.217 + va_end(ap); 1.218 + 1.219 + return res; 1.220 +} 1.221 + 1.222 +bool ShaderProg::create(Shader *sdr, va_list ap) 1.223 +{ 1.224 + destroy(); 1.225 + prog = glCreateProgram(); 1.226 + 1.227 + while(sdr) { 1.228 + add_shader(sdr); 1.229 + sdr = va_arg(ap, Shader*); 1.230 + } 1.231 + return link(); 1.232 +} 1.233 + 1.234 +bool ShaderProg::create(Shader *vsdr, Shader *psdr) 1.235 +{ 1.236 + return create(vsdr, psdr, 0); 1.237 +} 1.238 + 1.239 +void ShaderProg::destroy() 1.240 +{ 1.241 + if(prog) { 1.242 + glDeleteProgram(prog); 1.243 + } 1.244 + prog = 0; 1.245 + 1.246 + shaders.clear(); 1.247 + // don't actually destroy the shaders, let the ShaderSet own them 1.248 +} 1.249 + 1.250 +bool ShaderProg::load(const char *fname, unsigned int type, ...) 1.251 +{ 1.252 + va_list ap; 1.253 + va_start(ap, type); 1.254 + bool res = load(fname, type, ap); 1.255 + va_end(ap); 1.256 + 1.257 + return res; 1.258 +} 1.259 + 1.260 +bool ShaderProg::load(const char *fname, unsigned int type, va_list ap) 1.261 +{ 1.262 + destroy(); 1.263 + prog = glCreateProgram(); 1.264 + 1.265 + while(fname) { 1.266 + Shader *sdr = new Shader; 1.267 + if(!sdr->load(fname, type)) { 1.268 + delete sdr; 1.269 + return false; 1.270 + } 1.271 + add_shader(sdr); 1.272 + 1.273 + if((fname = va_arg(ap, const char*))) { 1.274 + type = va_arg(ap, unsigned int); 1.275 + } 1.276 + } 1.277 + 1.278 + return link(); 1.279 +} 1.280 + 1.281 +bool ShaderProg::load(const char *vfname, const char *pfname) 1.282 +{ 1.283 + return load(VSDR(vfname), PSDR(pfname), 0); 1.284 +} 1.285 + 1.286 +void ShaderProg::add_shader(Shader *sdr) 1.287 +{ 1.288 + glAttachShader(prog, sdr->get_id()); 1.289 +} 1.290 + 1.291 +bool ShaderProg::link() const 1.292 +{ 1.293 + bind_standard_attr(this); 1.294 + 1.295 + printf("linking program ... "); 1.296 + glLinkProgram(prog); 1.297 + 1.298 + int status; 1.299 + glGetProgramiv(prog, GL_LINK_STATUS, &status); 1.300 + 1.301 + printf(status ? "success\n" : "failed\n"); 1.302 + 1.303 + int info_len; 1.304 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &info_len); 1.305 + if(info_len > 1) { 1.306 + char *buf = (char*)alloca(info_len); 1.307 + glGetProgramInfoLog(prog, info_len, 0, buf); 1.308 + buf[info_len - 1] = 0; 1.309 + 1.310 + if(status) { 1.311 + printf("%s\n", buf); 1.312 + } else { 1.313 + fprintf(stderr, "%s\n", buf); 1.314 + } 1.315 + } 1.316 + 1.317 + if(status) { 1.318 + must_link = false; 1.319 + //cache_state_uniforms(); 1.320 + return true; 1.321 + } 1.322 + return false; 1.323 +} 1.324 + 1.325 +void ShaderProg::bind() const 1.326 +{ 1.327 + if(must_link) { 1.328 + if(!link()) { 1.329 + return; 1.330 + } 1.331 + } 1.332 + glUseProgram(prog); 1.333 + ShaderProg::current = (ShaderProg*)this; 1.334 + 1.335 + //setup_state_uniforms(); 1.336 +} 1.337 + 1.338 + 1.339 +int ShaderProg::get_attrib_location(const char *name) const 1.340 +{ 1.341 + glUseProgram(prog); 1.342 + return glGetAttribLocation(prog, name); 1.343 +} 1.344 + 1.345 +void ShaderProg::set_attrib_location(const char *name, int loc) const 1.346 +{ 1.347 + glBindAttribLocation(prog, loc, name); 1.348 + must_link = true; 1.349 +} 1.350 + 1.351 +int ShaderProg::get_uniform_location(const char *name) const 1.352 +{ 1.353 + glUseProgram(prog); 1.354 + return glGetUniformLocation(prog, name); 1.355 +} 1.356 + 1.357 +bool ShaderProg::set_uniform(int loc, int val) const 1.358 +{ 1.359 + glUseProgram(prog); 1.360 + if(loc >= 0) { 1.361 + glUniform1i(loc, val); 1.362 + return true; 1.363 + } 1.364 + return false; 1.365 +} 1.366 + 1.367 +bool ShaderProg::set_uniform(int loc, float val) const 1.368 +{ 1.369 + glUseProgram(prog); 1.370 + if(loc >= 0) { 1.371 + glUniform1f(loc, val); 1.372 + return true; 1.373 + } 1.374 + return false; 1.375 +} 1.376 + 1.377 +bool ShaderProg::set_uniform(int loc, const Vector2 &v) const 1.378 +{ 1.379 + glUseProgram(prog); 1.380 + if(loc >= 0) { 1.381 + glUniform2f(loc, v.x, v.y); 1.382 + return true; 1.383 + } 1.384 + return false; 1.385 +} 1.386 + 1.387 +bool ShaderProg::set_uniform(int loc, const Vector3 &v) const 1.388 +{ 1.389 + glUseProgram(prog); 1.390 + if(loc >= 0) { 1.391 + glUniform3f(loc, v.x, v.y, v.z); 1.392 + return true; 1.393 + } 1.394 + return false; 1.395 +} 1.396 + 1.397 +bool ShaderProg::set_uniform(int loc, const Vector4 &v) const 1.398 +{ 1.399 + glUseProgram(prog); 1.400 + if(loc >= 0) { 1.401 + glUniform4f(loc, v.x, v.y, v.z, v.w); 1.402 + return true; 1.403 + } 1.404 + return false; 1.405 +} 1.406 + 1.407 +bool ShaderProg::set_uniform(int loc, const Matrix3x3 &m) const 1.408 +{ 1.409 + glUseProgram(prog); 1.410 + if(loc >= 0) { 1.411 + glUniformMatrix3fv(loc, 1, GL_TRUE, m[0]); 1.412 + return true; 1.413 + } 1.414 + return false; 1.415 +} 1.416 + 1.417 +bool ShaderProg::set_uniform(int loc, const Matrix4x4 &m) const 1.418 +{ 1.419 + glUseProgram(prog); 1.420 + if(loc >= 0) { 1.421 + glUniformMatrix4fv(loc, 1, GL_TRUE, m[0]); 1.422 + return true; 1.423 + } 1.424 + return false; 1.425 +} 1.426 + 1.427 + 1.428 +bool ShaderProg::set_uniform(const char *name, int val) const 1.429 +{ 1.430 + return set_uniform(get_uniform_location(name), val); 1.431 +} 1.432 + 1.433 +bool ShaderProg::set_uniform(const char *name, float val) const 1.434 +{ 1.435 + return set_uniform(get_uniform_location(name), val); 1.436 +} 1.437 + 1.438 +bool ShaderProg::set_uniform(const char *name, const Vector2 &v) const 1.439 +{ 1.440 + return set_uniform(get_uniform_location(name), v); 1.441 +} 1.442 + 1.443 +bool ShaderProg::set_uniform(const char *name, const Vector3 &v) const 1.444 +{ 1.445 + return set_uniform(get_uniform_location(name), v); 1.446 +} 1.447 + 1.448 +bool ShaderProg::set_uniform(const char *name, const Vector4 &v) const 1.449 +{ 1.450 + return set_uniform(get_uniform_location(name), v); 1.451 +} 1.452 + 1.453 +bool ShaderProg::set_uniform(const char *name, const Matrix3x3 &m) const 1.454 +{ 1.455 + return set_uniform(get_uniform_location(name), m); 1.456 +} 1.457 + 1.458 +bool ShaderProg::set_uniform(const char *name, const Matrix4x4 &m) const 1.459 +{ 1.460 + return set_uniform(get_uniform_location(name), m); 1.461 +} 1.462 + 1.463 +/* 1.464 +static StType unist_type(GLenum type) 1.465 +{ 1.466 + switch(type) { 1.467 + case GL_FLOAT: 1.468 + return ST_FLOAT; 1.469 + case GL_FLOAT_VEC2: 1.470 + return ST_FLOAT2; 1.471 + case GL_FLOAT_VEC3: 1.472 + return ST_FLOAT3; 1.473 + case GL_FLOAT_VEC4: 1.474 + return ST_FLOAT4; 1.475 + case GL_INT: 1.476 + case GL_SAMPLER_2D: 1.477 + case GL_SAMPLER_CUBE: 1.478 +#if !GL_ES_VERSION_2_0 1.479 + case GL_SAMPLER_1D: 1.480 + case GL_SAMPLER_3D: 1.481 + case GL_SAMPLER_1D_SHADOW: 1.482 + case GL_SAMPLER_2D_SHADOW: 1.483 +#endif 1.484 + return ST_INT; 1.485 + case GL_INT_VEC2: 1.486 + return ST_INT2; 1.487 + case GL_INT_VEC3: 1.488 + return ST_INT3; 1.489 + case GL_INT_VEC4: 1.490 + return ST_INT4; 1.491 + case GL_FLOAT_MAT3: 1.492 + return ST_MATRIX3; 1.493 + case GL_FLOAT_MAT4: 1.494 + return ST_MATRIX4; 1.495 + default: 1.496 + break; 1.497 + } 1.498 + return ST_UNKNOWN; 1.499 +} 1.500 + 1.501 +void ShaderProg::cache_state_uniforms() const 1.502 +{ 1.503 + if(!glIsProgram(prog)) { 1.504 + return; 1.505 + } 1.506 + 1.507 + int num_uni; 1.508 + glGetProgramiv(prog, GL_ACTIVE_UNIFORMS, &num_uni); 1.509 + 1.510 + char name[256]; 1.511 + for(int i=0; i<num_uni; i++) { 1.512 + GLint sz; 1.513 + GLenum type; 1.514 + glGetActiveUniform(prog, i, sizeof name - 1, 0, &sz, &type, name); 1.515 + 1.516 + if(strstr(name, "st_") == name) { 1.517 + StateLocCache s; 1.518 + s.sidx = add_unistate(name, unist_type(type)); 1.519 + s.loc = glGetUniformLocation(prog, name); 1.520 + stloc_cache.push_back(s); 1.521 + } 1.522 + } 1.523 +} 1.524 + 1.525 +void ShaderProg::setup_state_uniforms() const 1.526 +{ 1.527 + for(size_t i=0; i<stloc_cache.size(); i++) { 1.528 + setup_unistate(stloc_cache[i].sidx, this, stloc_cache[i].loc); 1.529 + } 1.530 +} 1.531 +*/ 1.532 + 1.533 +// Static functions to use with ShaderSet 1.534 +Shader *Shader::create_shader() 1.535 +{ 1.536 + return new Shader; 1.537 +} 1.538 + 1.539 +bool Shader::load_shader(Shader *sdr, const char *fname) 1.540 +{ 1.541 + std::string src = read_source(fname); 1.542 + if(src.empty()) { 1.543 + return false; 1.544 + } 1.545 + 1.546 + sdr->src = src; 1.547 + return true; 1.548 +} 1.549 + 1.550 +bool Shader::done_shader(Shader *sdr, unsigned int type) 1.551 +{ 1.552 + return sdr->create(sdr->src.c_str(), type); 1.553 +} 1.554 + 1.555 +/* 1.556 +static bool done_vertex_shader(Shader *sdr) 1.557 +{ 1.558 + return Shader::done_shader(sdr, GL_VERTEX_SHADER); 1.559 +} 1.560 + 1.561 +static bool done_pixel_shader(Shader *sdr) 1.562 +{ 1.563 + return Shader::done_shader(sdr, GL_FRAGMENT_SHADER); 1.564 +} 1.565 + 1.566 +#ifdef HAVE_GEOMETRY_SHADER 1.567 +static bool done_geom_shader(Shader *sdr) 1.568 +{ 1.569 + return Shader::done_shader(sdr, GL_GEOMETRY_SHADER); 1.570 +} 1.571 +#endif 1.572 + 1.573 +#ifdef HAVE_TESSELATION_SHADER 1.574 +static bool done_tc_shader(Shader *sdr) 1.575 +{ 1.576 + return Shader::done_shader(sdr, GL_TESS_CONTROL_SHADER); 1.577 +} 1.578 + 1.579 +static bool done_te_shader(Shader *sdr) 1.580 +{ 1.581 + return Shader::done_shader(sdr, GL_TESS_EVALUATION_SHADER); 1.582 +} 1.583 +#endif 1.584 + 1.585 +void Shader::destroy_shader(Shader *sdr) 1.586 +{ 1.587 + delete sdr; 1.588 +} 1.589 + 1.590 +// ---- ShaderSet ---- 1.591 + 1.592 +ShaderSet::ShaderSet(unsigned int type) 1.593 + : DataSet<Shader*>(Shader::create_shader, Shader::load_shader, 0, Shader::destroy_shader) 1.594 +{ 1.595 + switch(type) { 1.596 + case GL_VERTEX_SHADER: 1.597 + done = done_vertex_shader; 1.598 + break; 1.599 + 1.600 + case GL_FRAGMENT_SHADER: 1.601 + done = done_pixel_shader; 1.602 + break; 1.603 + 1.604 +#ifdef HAVE_GEOMETRY_SHADER 1.605 + case GL_GEOMETRY_SHADER: 1.606 + done = done_geom_shader; 1.607 + break; 1.608 +#endif 1.609 + 1.610 +#ifdef HAVE_TESSELATION_SHADER 1.611 + case GL_TESS_CONTROL_SHADER: 1.612 + done = done_tc_shader; 1.613 + break; 1.614 + 1.615 + case GL_TESS_EVALUATION_SHADER: 1.616 + done = done_te_shader; 1.617 + break; 1.618 +#endif 1.619 + 1.620 + default: 1.621 + fprintf(stderr, "ShaderSet constructed with invalid shader type!\n"); 1.622 + } 1.623 +} 1.624 +*/ 1.625 + 1.626 +static struct { const char *name; int loc; } attr_loc[] = { 1.627 + {"attr_vertex", MESH_ATTR_VERTEX}, 1.628 + {"attr_normal", MESH_ATTR_NORMAL}, 1.629 + {"attr_tangent", MESH_ATTR_TANGENT}, 1.630 + {"attr_texcoord", MESH_ATTR_TEXCOORD}, 1.631 + {"attr_color", MESH_ATTR_COLOR}, 1.632 + {"attr_boneweights", MESH_ATTR_BONEWEIGHTS}, 1.633 + {"attr_boneidx", MESH_ATTR_BONEIDX} 1.634 +}; 1.635 + 1.636 +static void bind_standard_attr(const ShaderProg *prog) 1.637 +{ 1.638 + // we must link once to find out which are the active attributes 1.639 + glLinkProgram(prog->get_id()); 1.640 + 1.641 + int num_attr; 1.642 + glGetProgramiv(prog->get_id(), GL_ACTIVE_ATTRIBUTES, &num_attr); 1.643 + 1.644 + char name[256]; 1.645 + for(int i=0; i<num_attr; i++) { 1.646 + GLint sz; 1.647 + GLenum type; 1.648 + glGetActiveAttrib(prog->get_id(), i, sizeof name - 1, 0, &sz, &type, name); 1.649 + 1.650 + for(int j=0; j<(int)(sizeof attr_loc / sizeof *attr_loc); j++) { 1.651 + if(strcmp(name, attr_loc[j].name) == 0) { 1.652 + prog->set_attrib_location(name, attr_loc[j].loc); 1.653 + } 1.654 + } 1.655 + } 1.656 +} 1.657 + 1.658 + 1.659 +/* 1.660 +static const char *strtype(unsigned int type) 1.661 +{ 1.662 + switch(type) { 1.663 + case GL_VERTEX_SHADER: 1.664 + return "vertex"; 1.665 + case GL_FRAGMENT_SHADER: 1.666 + return "fragment"; 1.667 +#ifdef HAVE_GEOMETRY_SHADER 1.668 + case GL_GEOMETRY_SHADER: 1.669 + return "geometry"; 1.670 +#endif 1.671 +#ifdef HAVE_TESSELATION_SHADER 1.672 + case GL_TESS_CONTROL_SHADER: 1.673 + return "tesselation control"; 1.674 + case GL_TESS_EVALUATION_SHADER: 1.675 + return "tesselation evaluation"; 1.676 +#endif 1.677 + default: 1.678 + break; 1.679 + } 1.680 + return "<unknown>"; 1.681 +} 1.682 +*/