nuclear@1: #include nuclear@1: #include nuclear@1: #include nuclear@1: #ifdef _MSC_VER nuclear@1: #include nuclear@1: #else nuclear@1: #include nuclear@1: #endif nuclear@1: #include nuclear@1: #include "shaders.h" nuclear@1: nuclear@1: Shader::Shader(unsigned int type) nuclear@1: { nuclear@1: sdr = glCreateShader(type); nuclear@1: compiled = false; nuclear@1: nuclear@1: assert(glGetError() == GL_NO_ERROR); nuclear@1: } nuclear@1: nuclear@1: Shader::~Shader() nuclear@1: { nuclear@1: glDeleteShader(sdr); nuclear@1: } nuclear@1: nuclear@1: void Shader::set_source(const char *src) nuclear@1: { nuclear@1: glShaderSource(sdr, 1, &src, 0); nuclear@1: compiled = false; nuclear@1: nuclear@1: assert(glGetError() == GL_NO_ERROR); nuclear@1: } nuclear@1: nuclear@1: bool Shader::compile() nuclear@1: { nuclear@1: if(compiled) { nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: glCompileShader(sdr); nuclear@1: nuclear@1: int len; nuclear@1: glGetShaderiv(sdr, GL_INFO_LOG_LENGTH, &len); nuclear@1: if(len) { nuclear@1: char *buf = (char*)alloca(len + 1); nuclear@1: glGetShaderInfoLog(sdr, len, &len, buf); nuclear@1: fprintf(stderr, "compiler: %s\n", buf); nuclear@1: } nuclear@1: nuclear@1: int status; nuclear@1: glGetShaderiv(sdr, GL_COMPILE_STATUS, &status); nuclear@1: if(!status) { nuclear@1: fprintf(stderr, "shader compilation failed\n"); nuclear@1: return false; nuclear@1: } nuclear@1: nuclear@1: compiled = true; nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: bool Shader::is_compiled() const nuclear@1: { nuclear@1: return compiled; nuclear@1: } nuclear@1: nuclear@1: bool Shader::load(const char *fname) nuclear@1: { nuclear@1: FILE *fp; nuclear@1: nuclear@1: if(!(fp = fopen(fname, "rb"))) { nuclear@1: fprintf(stderr, "failed to open shader file: %s\n", fname); nuclear@1: return false; nuclear@1: } nuclear@1: nuclear@1: fseek(fp, 0, SEEK_END); nuclear@1: long sz = ftell(fp); nuclear@1: rewind(fp); nuclear@1: nuclear@1: char *buf = new char[sz + 1]; nuclear@1: if((long)fread(buf, 1, sz, fp) < sz) { nuclear@1: fprintf(stderr, "failed to read shader contents\n"); nuclear@1: fclose(fp); nuclear@1: return false; nuclear@1: } nuclear@1: fclose(fp); nuclear@1: nuclear@1: set_source(buf); nuclear@1: delete [] buf; nuclear@1: nuclear@1: return compile(); nuclear@1: } nuclear@1: nuclear@1: // ---- shader manager ---- nuclear@1: static std::map sdrcache; nuclear@1: nuclear@1: Shader *get_shader(const char *fname, unsigned int type) nuclear@1: { nuclear@1: std::map::const_iterator it; nuclear@1: nuclear@1: if((it = sdrcache.find(std::string(fname))) != sdrcache.end()) { nuclear@1: return it->second; nuclear@1: } nuclear@1: nuclear@1: Shader *sdr = new Shader(type); nuclear@1: if(!sdr->load(fname)) { nuclear@1: delete sdr; nuclear@1: return 0; nuclear@1: } nuclear@1: sdrcache[fname] = sdr; nuclear@1: return sdr; nuclear@1: } nuclear@1: nuclear@1: nuclear@1: // ---- class SdrProg ---- nuclear@1: nuclear@1: SdrProg::SdrProg() nuclear@1: { nuclear@1: prog = glCreateProgram(); nuclear@1: linked = false; nuclear@1: assert(glGetError() == GL_NO_ERROR); nuclear@1: } nuclear@1: nuclear@1: SdrProg::~SdrProg() nuclear@1: { nuclear@1: glDeleteProgram(prog); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::add_shader(Shader *sdr) nuclear@1: { nuclear@1: if(sdr->compile()) { nuclear@1: glAttachShader(prog, sdr->sdr); nuclear@1: assert(glGetError() == GL_NO_ERROR); nuclear@1: nuclear@1: shaders.push_back(sdr); nuclear@1: linked = false; nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: bool SdrProg::link() nuclear@1: { nuclear@1: if(linked) { nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: glLinkProgram(prog); nuclear@1: nuclear@1: int len; nuclear@1: glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &len); nuclear@1: if(len) { nuclear@1: char *buf = (char*)alloca(len + 1); nuclear@1: glGetProgramInfoLog(prog, len, &len, buf); nuclear@1: assert(glGetError() == GL_NO_ERROR); nuclear@1: fprintf(stderr, "linker: %s\n", buf); nuclear@1: } nuclear@1: nuclear@1: int status; nuclear@1: glGetProgramiv(prog, GL_LINK_STATUS, &status); nuclear@1: if(!status) { nuclear@1: fprintf(stderr, "program linking failed\n"); nuclear@1: return false; nuclear@1: } nuclear@1: nuclear@1: linked = true; nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: bool SdrProg::load(const char *vsfname, const char *psfname) nuclear@1: { nuclear@1: Shader *sdr; nuclear@1: nuclear@1: if(vsfname) { nuclear@1: if(!(sdr = get_shader(vsfname, GL_VERTEX_SHADER))) { nuclear@1: return false; nuclear@1: } nuclear@1: add_shader(sdr); nuclear@1: } nuclear@1: nuclear@1: if(psfname) { nuclear@1: if(!(sdr = get_shader(psfname, GL_FRAGMENT_SHADER))) { nuclear@1: return false; nuclear@1: } nuclear@1: add_shader(sdr); nuclear@1: } nuclear@1: return link(); nuclear@1: } nuclear@1: nuclear@1: int SdrProg::get_uniform_location(const char *name) nuclear@1: { nuclear@1: bind_program(this); nuclear@1: return glGetUniformLocation(prog, name); nuclear@1: } nuclear@1: nuclear@1: int SdrProg::get_attribute_location(const char *name) nuclear@1: { nuclear@1: bind_program(this); nuclear@1: return glGetAttribLocation(prog, name); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, int val) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), val); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, float val) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), val); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, const Vector2 &v) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), v); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, const Vector3 &v) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), v); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, const Vector4 &v) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), v); nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(const char *name, const Matrix4x4 &mat) nuclear@1: { nuclear@1: set_uniform(get_uniform_location(name), mat); nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, int val) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: glUniform1i(loc, val); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, float val) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: glUniform1f(loc, val); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, const Vector2 &v) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: glUniform2f(loc, v.x, v.y); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, const Vector3 &v) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: glUniform3f(loc, v.x, v.y, v.z); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, const Vector4 &v) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: glUniform4f(loc, v.x, v.y, v.z, v.w); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: void SdrProg::set_uniform(int loc, const Matrix4x4 &mat) nuclear@1: { nuclear@1: if(loc >= 0) { nuclear@1: bind_program(this); nuclear@1: // loading transpose matrix (3rd arg true) nuclear@1: #ifdef SINGLE_PRECISION_MATH nuclear@1: glUniformMatrix4fv(loc, 1, GL_TRUE, (float*)mat.m); nuclear@1: #else nuclear@1: glUniformMatrix4dv(loc, 1, GL_TRUE, (double*)mat.m); nuclear@1: #endif nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: bool bind_program(const SdrProg *prog) nuclear@1: { nuclear@1: if(!prog) { nuclear@1: glUseProgram(0); nuclear@1: return true; nuclear@1: } nuclear@1: nuclear@1: if(!((SdrProg*)prog)->link()) { nuclear@1: return false; nuclear@1: } nuclear@1: glUseProgram(prog->prog); nuclear@1: if(glGetError()) { nuclear@1: return false; nuclear@1: } nuclear@1: return true; nuclear@1: }