vcglib/wrap/glw/program.h

660 lines
20 KiB
C++

#ifndef GLW_PROGRAM_H
#define GLW_PROGRAM_H
#include <memory.h>
#include <string>
#include <vector>
#include <map>
#include "./vertexshader.h"
#include "./geometryshader.h"
#include "./fragmentshader.h"
namespace glw
{
typedef std::vector<ShaderHandle> ShaderHandleVector;
class VertexAttributeBinding
{
public:
typedef void BaseType;
typedef VertexAttributeBinding ThisType;
typedef std::map<std::string, GLuint> 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<std::string> 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<std::string, GLuint> 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; i<this->m_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; i<count; ++i)
{
varyings[i] = this->m_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<std::string, UniformInfo> 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; i<int(ucount); ++i)
{
GLsizei length = 0;
glGetActiveUniform(this->m_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 <Program> { typedef Object Type; }; };
typedef detail::ObjectSharedPointerTraits <Program> ::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<const ProgramPtr &>(BaseType::object());
}
ProgramPtr & object(void)
{
return static_cast<ProgramPtr &>(BaseType::object());
}
};
namespace detail { template <> struct BaseOf <SafeProgram> { typedef SafeObject Type; }; };
namespace detail { template <> struct ObjectBase <SafeProgram> { typedef Program Type; }; };
namespace detail { template <> struct ObjectSafe <Program > { typedef SafeProgram Type; }; };
typedef detail::ObjectSharedPointerTraits <SafeProgram> ::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<const ProgramHandle &>(BaseType::handle());
}
ProgramHandle & handle(void)
{
return static_cast<ProgramHandle &>(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 <BoundProgram> { typedef ProgramBindingParams Type; }; };
namespace detail { template <> struct BaseOf <BoundProgram> { typedef BoundObject Type; }; };
namespace detail { template <> struct ObjectBase <BoundProgram> { typedef Program Type; }; };
namespace detail { template <> struct ObjectBound <Program > { typedef BoundProgram Type; }; };
typedef detail::ObjectSharedPointerTraits <BoundProgram> ::Type BoundProgramHandle;
};
#endif // GLW_PROGRAM_H