/**************************************************************************** * MeshLab o o * * An extendible mesh processor o o * * _ O _ * * Copyright(C) 2005, 2009 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __SHADERS_H__ #define __SHADERS_H__ #include #include #include #include "gl_object.h" #include "../../vcg/space/point2.h" #include "../../vcg/space/point3.h" #include "../../vcg/space/point4.h" class Shader : public GLObject, public Bindable { public: typedef enum { VERTEX, FRAGMENT, GEOMETRY } ShaderType; Shader(void) : GLObject(), Bindable() { this->flags = 0; this->flags |= SOURCE_DIRTY; this->compiled = false; } void Gen(void) { this->Del(); GLenum t; switch (this->Type()) { case Shader::VERTEX : t = GL_VERTEX_SHADER; break; case Shader::FRAGMENT : t = GL_FRAGMENT_SHADER; break; case Shader::GEOMETRY : t = GL_GEOMETRY_SHADER_EXT; break; default: return; }; this->objectID = glCreateShader(t); } void Del(void) { if (this->objectID == 0) return; glDeleteShader(this->objectID); this->objectID = 0; } virtual ShaderType Type(void) const = 0; void SetSource(const char * src) { if (this->objectID==0) Gen(); this->flags |= SOURCE_DIRTY; this->compiled = false; this->source = src; const char * pSrc = this->source.c_str(); glShaderSource(this->objectID, 1, &pSrc, 0); } bool LoadSource(const char * fileName) { if (this->objectID==0) Gen(); this->flags |= SOURCE_DIRTY; this->compiled = false; FILE * f = fopen(fileName, "rb"); if (f == 0) { this->source = ""; return false; } fseek(f, 0, SEEK_END); const size_t sz = (size_t)ftell(f); rewind(f); char * buff = new char[sz + 1]; fread(buff, sizeof(char), sz, f); fclose(f); buff[sz] = '\0'; this->source = buff; delete [] buff; const char * pSrc = this->source.c_str(); glShaderSource(this->objectID, 1, &pSrc, 0); return true; } bool Compile(void) { glCompileShader(this->objectID); GLint cm = 0; glGetShaderiv(this->objectID, GL_COMPILE_STATUS, &cm); this->compiled = (cm != GL_FALSE); this->flags = 0; return this->compiled; } bool IsCompiled(void) { return this->compiled; } std::string InfoLog(void) { GLint len = 0; glGetShaderiv(this->objectID, GL_INFO_LOG_LENGTH, &len); char * ch = new char[len + 1]; glGetShaderInfoLog(this->objectID, len, &len, ch); std::string infoLog = ch; delete [] ch; return infoLog; } protected: enum { SOURCE_DIRTY }; std::string source; unsigned int flags; bool compiled; void DoBind(void) { } void DoUnbind(void) { } }; class VertexShader : public Shader { public: VertexShader(void) : Shader() { } ShaderType Type(void) const { return Shader::VERTEX; } }; class FragmentShader : public Shader { public: FragmentShader(void) : Shader() { } ShaderType Type(void) const { return Shader::FRAGMENT; } }; class GeometryShader : public Shader { public: GeometryShader(void) : Shader() { } ShaderType Type(void) const { return Shader::GEOMETRY; } }; #if 0 class Program; class Uniform { friend class Program; public: /* typedef enum { U_BOOL, U_BVEC2, U_BVEC3, U_BVEC4, U_BMAT2, U_BMAT3, U_BMAT4, U_INT, U_IVEC2, U_IVEC3, U_IVEC4, U_IMAT2, U_IMAT3, U_IMAT4, U_FLOAT, U_FVEC2, U_FVEC3, U_FVEC4, U_FMAT2, U_FMAT3, U_FMAT4, U_SAMPLER1D, U_SAMPLER2D, U_SAMPLER3D, U_SAMPLERCUBE, U_SAMPLER1DSHADOW, U_SAMPLER2DSHADOW } UniformType; */ const std::string & Name(void) const { return this->name; } virtual GLenum Type(void) const = 0; protected: Program * prog; GLint location; std::string name; Uniform(Program * prog, GLint location, const std::string & name) { this->prog = prog; this->location = location; this->name = name; } virtual void Apply(void) = 0; }; class Uniform1b : public Uniform; { public: void SetValue(GLboolean x) { this->value[0] = x; } GLboolean GetValue(void) const { return this->value[0]; } protected: Program * prog; GLboolean value[1]; Uniform(Program * prog, GLint location, const std::string & name) : Uniform(prog, location, name) { this->value = GL_FALSE; } }; class Uniform2b : public Uniform; { public: void SetValue(GLboolean x, GLboolean y) { this->value[0] = x; this->value[1] = y; } GLboolean GetValueX(void) const { return this->value[0]; } GLboolean GetValueY(void) const { return this->value[1]; } protected: Program * prog; GLboolean value[2]; Uniform(Program * prog, GLint location, const std::string & name) : Uniform(prog, location, name) { this->value[0] = GL_FALSE; this->value[1] = GL_FALSE; } }; class Uniform3b : public Uniform; { public: void SetValue(GLboolean x, GLboolean y, GLboolean z) { this->value[0] = x; this->value[1] = y; this->value[2] = z; } GLboolean GetValueX(void) const { return this->value[0]; } GLboolean GetValueY(void) const { return this->value[1]; } GLboolean GetValueZ(void) const { return this->value[2]; } protected: Program * prog; GLboolean value[2]; Uniform(Program * prog, GLint location, const std::string & name) : Uniform(prog, location, name) { this->value[0] = GL_FALSE; this->value[1] = GL_FALSE; } }; class Uniform1i : public Uniform; { public: void SetValue(GLint v) { this->value = v; } GLint GetValue(void) const { return this->value; } protected: Program * prog; GLint value; Uniform(Program * prog, GLint location, const std::string & name) : Uniform(prog, location, name) { this->value = 0; } }; #endif class Program : public GLObject, public Bindable { public: Program(void) { this->linked = false; } void Gen(void) { this->Del(); this->objectID = glCreateProgram(); } void Del(void) { if (this->objectID == 0) return; glDeleteProgram(this->objectID); this->objectID = 0; } void Attach(Shader * shd) { if (this->objectID==0) Gen(); this->shaders.insert(shd); this->linked = false; glAttachShader(this->objectID, shd->ObjectID()); } void Detach(Shader * shd) { this->shaders.erase(shd); this->linked = false; glDetachShader(this->objectID, shd->ObjectID()); } GLsizei AttachedShaders(void) const { return ((GLsizei)(this->shaders.size())); } Shader * AttachedShader(int i) { Shader * shd = 0; int cnt = 0; for (std::set::iterator it=this->shaders.begin(); (cnt < i) && (it!=this->shaders.end()); ++it) { shd = (*it); } return shd; } bool Link(void) { bool ok = true; for (std::set::iterator it=this->shaders.begin(); it!=this->shaders.end(); ++it) { Shader * shd = (*it); if (!shd->IsCompiled()) { ok = shd->Compile() && ok; } } if (!ok) return false; glLinkProgram(this->objectID); GLint cm = 0; glGetProgramiv(this->objectID, GL_LINK_STATUS, &cm); this->linked = (cm != GL_FALSE); return this->linked; } bool IsLinked(void) const { return this->linked; } std::string InfoLog(void) { GLint len = 0; glGetProgramiv(this->objectID, GL_INFO_LOG_LENGTH, &len); char * ch = new char[len + 1]; glGetProgramInfoLog(this->objectID, len, &len, ch); std::string infoLog = ch; delete [] ch; return infoLog; } void Uniform(const char * name, GLint x) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform1i(loc, x); } void Uniform(const char * name, GLint x, GLint y) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform2i(loc, x, y); } void Uniform(const char * name, GLint x, GLint y, GLint z) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform3i(loc, x, y, z); } void Uniform(const char * name, GLint x, GLint y, GLint z, GLint w) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform4i(loc, x, y, z, w); } void Uniform(const char * name, GLfloat x) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform1f(loc, x); } void Uniform(const char * name, GLfloat x, GLfloat y) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform2f(loc, x, y); } void Uniform(const char * name, GLfloat x, GLfloat y, GLfloat z) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform3f(loc, x, y, z); } void Uniform(const char * name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform4f(loc, x, y, z, w); } void Uniform(const char * name, const vcg::Point2f& p) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform2fv(loc, 1, p.V()); } void Uniform(const char * name, const vcg::Point3f& p) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform3fv(loc, 1, p.V()); } void Uniform(const char * name, const vcg::Point4f& p) { const GLint loc = glGetUniformLocation(this->objectID, name); glUniform4fv(loc, 1, p.V()); } void Parameter(GLenum pname, int value) { glProgramParameteriEXT(this->objectID, pname, value); } void Attribute(int index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) { glVertexAttrib4f(index, x, y, z, w); } void BindAttribute(int index, const char * name) { glBindAttribLocation(this->objectID, index, name); } protected: std::set shaders; bool linked; void DoBind(void) { if (!this->IsLinked()) { this->Link(); } glUseProgram(this->objectID); } void DoUnbind(void) { glUseProgram(0); } }; class ProgramVF : public Bindable { public: Program prog; VertexShader vshd; FragmentShader fshd; ProgramVF(void) : Bindable() { } void SetSources(const char * vsrc, const char * fsrc) { if (vsrc) { this->vshd.SetSource(vsrc); this->prog.Attach(&(this->vshd)); } if (fsrc) { this->fshd.SetSource(fsrc); this->prog.Attach(&(this->fshd)); } } void LoadSources(const char * vfile, const char * ffile) { if (vfile) { this->vshd.LoadSource(vfile); this->prog.Attach(&(this->vshd)); } if (ffile) { this->fshd.LoadSource(ffile); this->prog.Attach(&(this->fshd)); } } protected: void DoBind(void) { this->prog.Bind(); } void DoUnbind(void) { this->prog.Unbind(); } }; #endif // __SHADERS_H__