A class that matches the rendered objects shader and render function(sets shader resources) based on its typeid
hash.
#include <unordered_map>
#include <glm/glm.hpp>
#include "gl_func.h"
#include "gl_buffer.h"
#include "shader.h"
#include "log.h"
class Renderer
{
private:
typedef void (*RenderFunctionPointer)();
typedef std::unordered_map< size_t, Shader* >::iterator ShaderIterator;
typedef std::unordered_map< size_t, RenderFunctionPointer >::iterator
FunctionIterator;
std::unordered_map< size_t, Shader* > Shaders;
std::unordered_map< size_t, RenderFunctionPointer > RenderFunctions;
glm::mat4 ProjectionMatrix;
glm::mat4 ViewMatrix;
public:
// Sets the given matrices for all shaders
void SetProjectionMatrix( glm::mat4 p );
void SetViewMatrix( glm::mat4 v );
/*! \brief Tells the renderer how to render object of type T
* \param shd Shader to use for rendering.
* \param f Pointer to a function that takes a shader and a T& argument. */
template< typename T >
void AddObjectType( Shader* shd, void (*f)(Shader*, T& ) )
{
size_t type = typeid( T ).hash_code();
Shaders[type] = shd;
RenderFunctions[type] = (RenderFunctionPointer)f;
}
/*! \brief Renders the given object.
* The object type has to be registered before this call.
* \param obj Object to Render */
template< typename T >
void Render( T& obj )
{
size_t type = typeid( T ).hash_code();
ShaderIterator i = Shaders.find( type );
if( i == Shaders.end() )
{
LOG_WARNING() << "Couldn't find shader for object: "
<< typeid( T ).name();
return;
}
Shader* shd = i->second;
shd->SetModelMatrix( obj.GetTransform() );
shd->Bind();
FunctionIterator f = RenderFunctions.find( type );
if( f == RenderFunctions.end() )
{
LOG_WARNING() << "Couldn't find renderfunction for object: "
<< typeid( T ).name();
return;
}
RenderFunctionPointer rp = f->second;
reinterpret_cast< void(*)(Shader* shd, T& t) >(rp)( shd, obj );
}
};
Here is some usage to clarify why is a reinterpret_cast
necessary(this is not code to be reviewed, just rough example of usage):
// Init
DeferredRenderer->AddObjectType<Asset>(AssetShader.Get(),
RenderFunctions::Deferred::RenderAsset );
// Somewhere passing a Asset to external C code( lua )
void* genericRenderable = MyAsset;
PassToLua( genericRenderable );
// Lua code calling entity system.
SetComponent( DeferredRenderable, genericRenderable );
// The render system processing entities
static_cast<Renderable*>(genericRenderable)->Render( DeferredRenderer );
// This calls
void Asset::Render( Renderer* r ) // where r is DeferredRenderer
{
r->Render( *this );
}