bloboland
diff src/shaders.cc @ 1:cfe68befb7cc
some progress
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 15 Dec 2012 23:43:03 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/shaders.cc Sat Dec 15 23:43:03 2012 +0200 1.3 @@ -0,0 +1,297 @@ 1.4 +#include <stdio.h> 1.5 +#include <assert.h> 1.6 +#include <map> 1.7 +#ifdef _MSC_VER 1.8 +#include <memory.h> 1.9 +#else 1.10 +#include <alloca.h> 1.11 +#endif 1.12 +#include <GL/glew.h> 1.13 +#include "shaders.h" 1.14 + 1.15 +Shader::Shader(unsigned int type) 1.16 +{ 1.17 + sdr = glCreateShader(type); 1.18 + compiled = false; 1.19 + 1.20 + assert(glGetError() == GL_NO_ERROR); 1.21 +} 1.22 + 1.23 +Shader::~Shader() 1.24 +{ 1.25 + glDeleteShader(sdr); 1.26 +} 1.27 + 1.28 +void Shader::set_source(const char *src) 1.29 +{ 1.30 + glShaderSource(sdr, 1, &src, 0); 1.31 + compiled = false; 1.32 + 1.33 + assert(glGetError() == GL_NO_ERROR); 1.34 +} 1.35 + 1.36 +bool Shader::compile() 1.37 +{ 1.38 + if(compiled) { 1.39 + return true; 1.40 + } 1.41 + 1.42 + glCompileShader(sdr); 1.43 + 1.44 + int len; 1.45 + glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &len); 1.46 + if(len) { 1.47 + char *buf = (char*)alloca(len + 1); 1.48 + glGetShaderInfoLog(sdr, len, &len, buf); 1.49 + fprintf(stderr, "compiler: %s\n", buf); 1.50 + } 1.51 + 1.52 + int status; 1.53 + glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); 1.54 + if(!status) { 1.55 + fprintf(stderr, "shader compilation failed\n"); 1.56 + return false; 1.57 + } 1.58 + 1.59 + compiled = true; 1.60 + return true; 1.61 +} 1.62 + 1.63 +bool Shader::is_compiled() const 1.64 +{ 1.65 + return compiled; 1.66 +} 1.67 + 1.68 +bool Shader::load(const char *fname) 1.69 +{ 1.70 + FILE *fp; 1.71 + 1.72 + if(!(fp = fopen(fname, "rb"))) { 1.73 + fprintf(stderr, "failed to open shader file: %s\n", fname); 1.74 + return false; 1.75 + } 1.76 + 1.77 + fseek(fp, 0, SEEK_END); 1.78 + long sz = ftell(fp); 1.79 + rewind(fp); 1.80 + 1.81 + char *buf = new char[sz + 1]; 1.82 + if((long)fread(buf, 1, sz, fp) < sz) { 1.83 + fprintf(stderr, "failed to read shader contents\n"); 1.84 + fclose(fp); 1.85 + return false; 1.86 + } 1.87 + fclose(fp); 1.88 + 1.89 + set_source(buf); 1.90 + delete [] buf; 1.91 + 1.92 + return compile(); 1.93 +} 1.94 + 1.95 +// ---- shader manager ---- 1.96 +static std::map<std::string, Shader*> sdrcache; 1.97 + 1.98 +Shader *get_shader(const char *fname, unsigned int type) 1.99 +{ 1.100 + std::map<std::string, Shader*>::const_iterator it; 1.101 + 1.102 + if((it = sdrcache.find(std::string(fname))) != sdrcache.end()) { 1.103 + return it->second; 1.104 + } 1.105 + 1.106 + Shader *sdr = new Shader(type); 1.107 + if(!sdr->load(fname)) { 1.108 + delete sdr; 1.109 + return 0; 1.110 + } 1.111 + sdrcache[fname] = sdr; 1.112 + return sdr; 1.113 +} 1.114 + 1.115 + 1.116 +// ---- class SdrProg ---- 1.117 + 1.118 +SdrProg::SdrProg() 1.119 +{ 1.120 + prog = glCreateProgram(); 1.121 + linked = false; 1.122 + assert(glGetError() == GL_NO_ERROR); 1.123 +} 1.124 + 1.125 +SdrProg::~SdrProg() 1.126 +{ 1.127 + glDeleteProgram(prog); 1.128 +} 1.129 + 1.130 +void SdrProg::add_shader(Shader *sdr) 1.131 +{ 1.132 + if(sdr->compile()) { 1.133 + glAttachShader(prog, sdr->sdr); 1.134 + assert(glGetError() == GL_NO_ERROR); 1.135 + 1.136 + shaders.push_back(sdr); 1.137 + linked = false; 1.138 + } 1.139 +} 1.140 + 1.141 +bool SdrProg::link() 1.142 +{ 1.143 + if(linked) { 1.144 + return true; 1.145 + } 1.146 + 1.147 + glLinkProgram(prog); 1.148 + 1.149 + int len; 1.150 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); 1.151 + if(len) { 1.152 + char *buf = (char*)alloca(len + 1); 1.153 + glGetProgramInfoLog(prog, len, &len, buf); 1.154 + assert(glGetError() == GL_NO_ERROR); 1.155 + fprintf(stderr, "linker: %s\n", buf); 1.156 + } 1.157 + 1.158 + int status; 1.159 + glGetProgramiv(prog, GL_LINK_STATUS, &status); 1.160 + if(!status) { 1.161 + fprintf(stderr, "program linking failed\n"); 1.162 + return false; 1.163 + } 1.164 + 1.165 + linked = true; 1.166 + return true; 1.167 +} 1.168 + 1.169 +bool SdrProg::load(const char *vsfname, const char *psfname) 1.170 +{ 1.171 + Shader *sdr; 1.172 + 1.173 + if(vsfname) { 1.174 + if(!(sdr = get_shader(vsfname, GL_VERTEX_SHADER))) { 1.175 + return false; 1.176 + } 1.177 + add_shader(sdr); 1.178 + } 1.179 + 1.180 + if(psfname) { 1.181 + if(!(sdr = get_shader(psfname, GL_FRAGMENT_SHADER))) { 1.182 + return false; 1.183 + } 1.184 + add_shader(sdr); 1.185 + } 1.186 + return link(); 1.187 +} 1.188 + 1.189 +int SdrProg::get_uniform_location(const char *name) 1.190 +{ 1.191 + bind_program(this); 1.192 + return glGetUniformLocation(prog, name); 1.193 +} 1.194 + 1.195 +int SdrProg::get_attribute_location(const char *name) 1.196 +{ 1.197 + bind_program(this); 1.198 + return glGetAttribLocation(prog, name); 1.199 +} 1.200 + 1.201 +void SdrProg::set_uniform(const char *name, int val) 1.202 +{ 1.203 + set_uniform(get_uniform_location(name), val); 1.204 +} 1.205 + 1.206 +void SdrProg::set_uniform(const char *name, float val) 1.207 +{ 1.208 + set_uniform(get_uniform_location(name), val); 1.209 +} 1.210 + 1.211 +void SdrProg::set_uniform(const char *name, const Vector2 &v) 1.212 +{ 1.213 + set_uniform(get_uniform_location(name), v); 1.214 +} 1.215 + 1.216 +void SdrProg::set_uniform(const char *name, const Vector3 &v) 1.217 +{ 1.218 + set_uniform(get_uniform_location(name), v); 1.219 +} 1.220 + 1.221 +void SdrProg::set_uniform(const char *name, const Vector4 &v) 1.222 +{ 1.223 + set_uniform(get_uniform_location(name), v); 1.224 +} 1.225 + 1.226 +void SdrProg::set_uniform(const char *name, const Matrix4x4 &mat) 1.227 +{ 1.228 + set_uniform(get_uniform_location(name), mat); 1.229 +} 1.230 + 1.231 + 1.232 +void SdrProg::set_uniform(int loc, int val) 1.233 +{ 1.234 + if(loc >= 0) { 1.235 + bind_program(this); 1.236 + glUniform1i(loc, val); 1.237 + } 1.238 +} 1.239 + 1.240 +void SdrProg::set_uniform(int loc, float val) 1.241 +{ 1.242 + if(loc >= 0) { 1.243 + bind_program(this); 1.244 + glUniform1f(loc, val); 1.245 + } 1.246 +} 1.247 + 1.248 +void SdrProg::set_uniform(int loc, const Vector2 &v) 1.249 +{ 1.250 + if(loc >= 0) { 1.251 + bind_program(this); 1.252 + glUniform2f(loc, v.x, v.y); 1.253 + } 1.254 +} 1.255 + 1.256 +void SdrProg::set_uniform(int loc, const Vector3 &v) 1.257 +{ 1.258 + if(loc >= 0) { 1.259 + bind_program(this); 1.260 + glUniform3f(loc, v.x, v.y, v.z); 1.261 + } 1.262 +} 1.263 + 1.264 +void SdrProg::set_uniform(int loc, const Vector4 &v) 1.265 +{ 1.266 + if(loc >= 0) { 1.267 + bind_program(this); 1.268 + glUniform4f(loc, v.x, v.y, v.z, v.w); 1.269 + } 1.270 +} 1.271 + 1.272 +void SdrProg::set_uniform(int loc, const Matrix4x4 &mat) 1.273 +{ 1.274 + if(loc >= 0) { 1.275 + bind_program(this); 1.276 + // loading transpose matrix (3rd arg true) 1.277 +#ifdef SINGLE_PRECISION_MATH 1.278 + glUniformMatrix4fv(loc, 1, GL_TRUE, (float*)mat.m); 1.279 +#else 1.280 + glUniformMatrix4dv(loc, 1, GL_TRUE, (double*)mat.m); 1.281 +#endif 1.282 + } 1.283 +} 1.284 + 1.285 +bool bind_program(const SdrProg *prog) 1.286 +{ 1.287 + if(!prog) { 1.288 + glUseProgram(0); 1.289 + return true; 1.290 + } 1.291 + 1.292 + if(!((SdrProg*)prog)->link()) { 1.293 + return false; 1.294 + } 1.295 + glUseProgram(prog->prog); 1.296 + if(glGetError()) { 1.297 + return false; 1.298 + } 1.299 + return true; 1.300 +}