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