#ifndef GLW_PROGRAM_H #define GLW_PROGRAM_H #include #include #include #include #include "./vertexshader.h" #include "./geometryshader.h" #include "./fragmentshader.h" namespace glw { typedef std::vector ShaderHandleVector; class VertexAttributeBinding { public: typedef void BaseType; typedef VertexAttributeBinding ThisType; typedef std::map Map; typedef Map::const_iterator ConstIterator; typedef Map::iterator Iterator; typedef Map::value_type Value; Map bindings; VertexAttributeBinding(void) { this->clear(); } void clear(void) { this->bindings.clear(); } GLuint operator [] (const std::string & attributeName) const { return this->bindings.find(attributeName)->second; } GLuint & operator [] (const std::string & attributeName) { return this->bindings[attributeName]; } }; class GeometryStage { public: typedef void BaseType; typedef GeometryStage ThisType; /* GLenum inputPrimitiveType; GLenum outputPrimitiveType; GLint maxOutputVertices; */ GeometryStage(void) { this->clear(); } void clear(void) { /* this->inputPrimitiveType = GLW_DONT_CARE; this->outputPrimitiveType = GLW_DONT_CARE; this->maxOutputVertices = GLW_DONT_CARE; */ } }; class TransformFeedbackStream { public: typedef void BaseType; typedef TransformFeedbackStream ThisType; typedef std::vector VaryingVector; VaryingVector varyings; GLenum bufferMode; TransformFeedbackStream(void) { this->clear(); } void clear(void) { this->varyings.clear(); this->bufferMode = GL_INTERLEAVED_ATTRIBS; } }; class RasterizerSettings { public: typedef void BaseType; typedef RasterizerSettings ThisType; enum RasterizerExecution { DontCare = 0, Autodetect, ForceEnabled, ForceDisabled }; // TODO //RasterizerExecution execution; RasterizerSettings(void) { this->clear(); } void clear(void) { //this->execution = ThisType::Autodetect; } }; class FragmentOutputBinding { public: typedef void BaseType; typedef FragmentOutputBinding ThisType; typedef std::map Map; typedef Map::const_iterator ConstIterator; typedef Map::iterator Iterator; typedef Map::value_type Value; Map bindings; FragmentOutputBinding(void) { this->clear(); } void clear(void) { this->bindings.clear(); } GLuint operator [] (const std::string & outName) const { return this->bindings.find(outName)->second; } GLuint & operator [] (const std::string & outName) { return this->bindings[outName]; } }; class ProgramArguments : public ObjectArguments { public: typedef ObjectArguments BaseType; typedef ProgramArguments ThisType; ShaderHandleVector shaders; VertexAttributeBinding vertexInputs; GeometryStage geometryStage; TransformFeedbackStream feedbackStream; RasterizerSettings rasterSettings; FragmentOutputBinding fragmentOutputs; ProgramArguments(void) : BaseType() { ; } void clear(void) { BaseType::clear(); this->shaders .clear(); this->vertexInputs .clear(); this->geometryStage .clear(); this->feedbackStream .clear(); this->rasterSettings .clear(); this->fragmentOutputs .clear(); } }; class Program : public Object { friend class Context; public: typedef Object BaseType; typedef Program ThisType; virtual ~Program(void) { this->destroy(); } virtual Type type(void) const { return ProgramType; } const ProgramArguments & arguments(void) const { return this->m_arguments; } const std::string & log(void) const { return this->m_log; } const std::string & fullLog(void) const { return this->m_fullLog; } bool isLinked(void) const { return this->m_linked; } GLint getUniformLocation(const std::string & name) const { #if GLW_ASSERT_UNIFORM_LOCATION GLW_ASSERT(this->m_uniforms.count(name) > 0); #endif UniformMapConstIterator it = this->m_uniforms.find(name); if (it == this->m_uniforms.end()) return -1; return it->second.location; } #define _GLW_IMPLEMENT_SCALAR_UNIFORM_(TYPE, FUNCION_SUFFIX) \ void setUniform (const std::string & name, TYPE x ) { glUniform1 ## FUNCION_SUFFIX (this->getUniformLocation(name), x ); } \ void setUniform (const std::string & name, TYPE x, TYPE y ) { glUniform2 ## FUNCION_SUFFIX (this->getUniformLocation(name), x, y ); } \ void setUniform (const std::string & name, TYPE x, TYPE y, TYPE z ) { glUniform3 ## FUNCION_SUFFIX (this->getUniformLocation(name), x, y, z ); } \ void setUniform (const std::string & name, TYPE x, TYPE y, TYPE z, TYPE w ) { glUniform4 ## FUNCION_SUFFIX (this->getUniformLocation(name), x, y, z, w); } #define _GLW_IMPLEMENT_VECTOR_UNIFORM_(TYPE, FUNCION_SUFFIX) \ void setUniform1 (const std::string & name, const TYPE * v, int count = 1) { glUniform1 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), v ); } \ void setUniform2 (const std::string & name, const TYPE * v, int count = 1) { glUniform2 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), v ); } \ void setUniform3 (const std::string & name, const TYPE * v, int count = 1) { glUniform3 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), v ); } \ void setUniform4 (const std::string & name, const TYPE * v, int count = 1) { glUniform4 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), v ); } #define _GLW_IMPLEMENT_MATRIX_UNIFORM_(TYPE, FUNCION_SUFFIX) \ void setUniform2x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix2 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform2x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix2x3 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform2x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix2x4 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform3x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix3x2 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform3x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix3 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform3x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix3x4 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform4x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix4x2 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform4x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix4x3 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } \ void setUniform4x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { glUniformMatrix4 ## FUNCION_SUFFIX ## v (this->getUniformLocation(name), GLsizei(count), GLboolean(transpose), m ); } _GLW_IMPLEMENT_SCALAR_UNIFORM_(int, i ) _GLW_IMPLEMENT_SCALAR_UNIFORM_(unsigned int, ui) _GLW_IMPLEMENT_SCALAR_UNIFORM_(float, f ) _GLW_IMPLEMENT_VECTOR_UNIFORM_(int, i ) _GLW_IMPLEMENT_VECTOR_UNIFORM_(unsigned int, ui) _GLW_IMPLEMENT_VECTOR_UNIFORM_(float, f ) _GLW_IMPLEMENT_MATRIX_UNIFORM_(float, f ) GLW_IMPLEMENT_CUSTOM_UNIFORMS; #undef _GLW_IMPLEMENT_SCALAR_UNIFORM_ #undef _GLW_IMPLEMENT_VECTOR_UNIFORM_ #undef _GLW_IMPLEMENT_MATRIX_UNIFORM_ protected: Program(Context * ctx) : BaseType (ctx) , m_linked (false) { ; } bool create(const ProgramArguments & args) { this->destroy(); this->m_arguments = args; GLint boundName = 0; glGetIntegerv(GL_CURRENT_PROGRAM, &boundName); this->m_name = glCreateProgram(); this->m_fullLog = ""; // shaders { for (size_t i=0; im_arguments.shaders.size(); ++i) { const ShaderHandle & shader = this->m_arguments.shaders[i]; if (!shader) continue; this->m_fullLog += shader->log(); if (!shader->isCompiled()) continue; glAttachShader(this->m_name, shader->name()); } } // vertex { for (VertexAttributeBinding::ConstIterator it=this->m_arguments.vertexInputs.bindings.begin(); it!=this->m_arguments.vertexInputs.bindings.end(); ++it) { glBindAttribLocation(this->m_name, it->second, it->first.c_str()); } } // geometry { ; } // transform feedback { const size_t count = this->m_arguments.feedbackStream.varyings.size(); if (count > 0) { const char ** varyings = new const char * [count]; for (size_t i=0; im_arguments.feedbackStream.varyings[i].c_str(); } glTransformFeedbackVaryings(this->m_name, GLsizei(count), varyings, this->m_arguments.feedbackStream.bufferMode); delete [] varyings; } } // TODO // rasterizer { ; } // fragment { for (FragmentOutputBinding::ConstIterator it=this->m_arguments.fragmentOutputs.bindings.begin(); it!=this->m_arguments.fragmentOutputs.bindings.end(); ++it) { glBindFragDataLocation(this->m_name, it->second, it->first.c_str()); } } glLinkProgram(this->m_name); GLint linkStatus = 0; glGetProgramiv(this->m_name, GL_LINK_STATUS, &linkStatus); this->m_log = ThisType::getInfoLog(this->m_name); this->m_fullLog += this->m_log; this->m_linked = (linkStatus != GL_FALSE); #if GLW_PRINT_LOG_TO_STDERR std::cerr << "---------------------------" << std::endl; std::cerr << "[Program Link Log]: " << ((this->m_linked) ? ("OK") : ("FAILED")) << std::endl; std::cerr << this->m_log << std::endl; std::cerr << "---------------------------" << std::endl; #endif if (this->m_linked) { this->postLink(); } glUseProgram(boundName); return this->m_linked; } virtual void doDestroy() { glDeleteProgram(this->m_name); this->m_arguments.clear(); this->m_log.clear(); this->m_fullLog.clear(); this->m_linked = false; } virtual bool doIsValid(void) const { return this->m_linked; } private: class UniformInfo { public: typedef void BaseType; typedef UniformInfo ThisType; std::string name; GLint location; GLenum type; GLint size; UniformInfo(void) : location (-1) , type (GL_NONE) , size (0) { ; } }; typedef std::map UniformMap; typedef UniformMap::const_iterator UniformMapConstIterator; typedef UniformMap::iterator UniformMapIterator; typedef UniformMap::value_type UniformMapValue; ProgramArguments m_arguments; UniformMap m_uniforms; std::string m_log; std::string m_fullLog; bool m_linked; static std::string getInfoLog(GLuint Program) { std::string log; GLint logLen = 0; glGetProgramiv(Program, GL_INFO_LOG_LENGTH, &logLen); if (logLen > 0) { char * sLog = new char[logLen + 1]; glGetProgramInfoLog(Program, logLen, &logLen, sLog); if (logLen > 0) { if (sLog[0] != '\0') { sLog[logLen - 1] = '\0'; log = sLog; } } delete [] sLog; } return log; } void setupUniforms(void) { this->m_uniforms.clear(); GLint ucount = 0; glGetProgramiv(this->m_name, GL_ACTIVE_UNIFORMS, &ucount); if (ucount <= 0) return; GLint ulen = 0; glGetProgramiv(this->m_name, GL_ACTIVE_UNIFORM_MAX_LENGTH, &ulen); ulen++; // according to specs, +1 (for null) is already accounted, but some implementations are broken. if (ulen <= 0) return; UniformInfo info; GLchar * uname = new GLchar [ulen + 1]; for (int i=0; im_name, GLuint(i), GLsizei(ulen), &length, &(info.size), &(info.type), uname); info.name = uname; info.location = glGetUniformLocation(this->m_name, uname); this->m_uniforms.insert(UniformMapValue(info.name, info)); } delete [] uname; } void postLink(void) { this->setupUniforms(); } }; namespace detail { template <> struct BaseOf { typedef Object Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type ProgramPtr; class SafeProgram : public SafeObject { friend class Context; friend class BoundProgram; public: typedef SafeObject BaseType; typedef SafeProgram ThisType; const ProgramArguments & arguments(void) const { return this->object()->arguments(); } const std::string & log(void) const { return this->object()->log(); } const std::string & fullLog(void) const { return this->object()->fullLog(); } bool isLinked(void) const { return this->object()->isLinked(); } protected: SafeProgram(const ProgramPtr & program) : BaseType(program) { ; } const ProgramPtr & object(void) const { return static_cast(BaseType::object()); } ProgramPtr & object(void) { return static_cast(BaseType::object()); } }; namespace detail { template <> struct BaseOf { typedef SafeObject Type; }; }; namespace detail { template <> struct ObjectBase { typedef Program Type; }; }; namespace detail { template <> struct ObjectSafe { typedef SafeProgram Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type ProgramHandle; class ProgramBindingParams : public ObjectBindingParams { public: typedef ObjectBindingParams BaseType; typedef ProgramBindingParams ThisType; ProgramBindingParams(void) : BaseType(GL_CURRENT_PROGRAM, 0) { ; } }; class BoundProgram : public BoundObject { friend class Context; public: typedef BoundObject BaseType; typedef BoundProgram ThisType; BoundProgram(void) : BaseType() { ; } const ProgramHandle & handle(void) const { return static_cast(BaseType::handle()); } ProgramHandle & handle(void) { return static_cast(BaseType::handle()); } #define _GLW_FORWARD_SCALAR_UNIFORM_(TYPE) \ void setUniform (const std::string & name, TYPE x ) { this->object()->setUniform(name, x ); } \ void setUniform (const std::string & name, TYPE x, TYPE y ) { this->object()->setUniform(name, x, y ); } \ void setUniform (const std::string & name, TYPE x, TYPE y, TYPE z ) { this->object()->setUniform(name, x, y, z ); } \ void setUniform (const std::string & name, TYPE x, TYPE y, TYPE z, TYPE w ) { this->object()->setUniform(name, x, y, z, w); } #define _GLW_FORWARD_VECTOR_UNIFORM_(TYPE) \ void setUniform1 (const std::string & name, const TYPE * v, int count = 1) { this->object()->setUniform1(name, v, count); } \ void setUniform2 (const std::string & name, const TYPE * v, int count = 1) { this->object()->setUniform2(name, v, count); } \ void setUniform3 (const std::string & name, const TYPE * v, int count = 1) { this->object()->setUniform3(name, v, count); } \ void setUniform4 (const std::string & name, const TYPE * v, int count = 1) { this->object()->setUniform4(name, v, count); } #define _GLW_FORWARD_MATRIX_UNIFORM_(TYPE) \ void setUniform2x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform2x2(name, m, transpose, count); } \ void setUniform2x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform2x3(name, m, transpose, count); } \ void setUniform2x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform2x4(name, m, transpose, count); } \ void setUniform3x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform3x2(name, m, transpose, count); } \ void setUniform3x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform3x3(name, m, transpose, count); } \ void setUniform3x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform3x4(name, m, transpose, count); } \ void setUniform4x2 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform4x2(name, m, transpose, count); } \ void setUniform4x3 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform4x3(name, m, transpose, count); } \ void setUniform4x4 (const std::string & name, const TYPE * m, bool transpose, int count = 1) { this->object()->setUniform4x4(name, m, transpose, count); } _GLW_FORWARD_SCALAR_UNIFORM_(int) _GLW_FORWARD_SCALAR_UNIFORM_(unsigned int) _GLW_FORWARD_SCALAR_UNIFORM_(float) _GLW_FORWARD_VECTOR_UNIFORM_(int) _GLW_FORWARD_VECTOR_UNIFORM_(unsigned int) _GLW_FORWARD_VECTOR_UNIFORM_(float) _GLW_FORWARD_MATRIX_UNIFORM_(float) #undef _GLW_FORWARD_SCALAR_UNIFORM_ #undef _GLW_FORWARD_VECTOR_UNIFORM_ #undef _GLW_FORWARD_MATRIX_UNIFORM_ protected: BoundProgram(const ProgramHandle & handle, const ProgramBindingParams & params) : BaseType(handle, params) { ; } const ProgramPtr & object(void) const { return this->handle()->object(); } ProgramPtr & object(void) { return this->handle()->object(); } virtual void bind(void) { glUseProgram(this->object()->name()); } virtual void unbind(void) { glUseProgram(0); } }; namespace detail { template <> struct ParamsOf { typedef ProgramBindingParams Type; }; }; namespace detail { template <> struct BaseOf { typedef BoundObject Type; }; }; namespace detail { template <> struct ObjectBase { typedef Program Type; }; }; namespace detail { template <> struct ObjectBound { typedef BoundProgram Type; }; }; typedef detail::ObjectSharedPointerTraits ::Type BoundProgramHandle; }; #endif // GLW_PROGRAM_H