Commit 114a3552 authored by Jan Möbius's avatar Jan Möbius

Reorganize and document the shader renderer

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@16073 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 1ce2866d
#include <ACG/GL/gl.hh>
#include <ACG/ShaderUtils/GLSLShader.hh>
#include "Renderer.hh"
#include <ACG/GL/ShaderCache.hh>
#include <ACG/GL/VertexDeclaration.hh>
using namespace ACG;
// =================================================
void Renderer::addRenderObject(RenderObject* _renderObject)
{
// do some more checks for error detection
if (!_renderObject->vertexDecl)
std::cout << "error: missing vertex declaration" << std::endl;
else
{
renderObjects_.push_back(*_renderObject);
RenderObject* p = &renderObjects_.back();
if (!p->shaderDesc.numLights)
p->shaderDesc.numLights = numLights_;
else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
p->shaderDesc.numLights = 0;
p->internalFlags_ = 0;
// precompile shader
ShaderCache::getInstance()->getProgram(&p->shaderDesc);
}
}
void Renderer::collectRenderObjects( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _sceneGraphRoot )
{
// collect light sources
collectLightNodes(_sceneGraphRoot);
// flush render objects
// clear() may actually free memory, resulting in capacity = 0
renderObjects_.resize(0);
// default material needed
ACG::SceneGraph::Material defMat;
defMat.baseColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.ambientColor(Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
defMat.diffuseColor(Vec4f(0.6f, 0.6f, 0.6f, 1.0f));
defMat.specularColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.shininess(1.0f);
// defMat.alphaValue(1.0f);
// collect renderables
traverseRenderableNodes(_glState, _drawMode, _sceneGraphRoot, &defMat);
}
void Renderer::traverseRenderableNodes( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _node, const SceneGraph::Material* _mat )
{
if (_node)
{
SceneGraph::BaseNode::StatusMode status(_node->status());
bool process_children(status != SceneGraph::BaseNode::HideChildren);
SceneGraph::DrawModes::DrawMode nodeDM = _node->drawMode();
if (nodeDM == SceneGraph::DrawModes::DEFAULT)
nodeDM = _drawMode;
// If the subtree is hidden, ignore this node and its children while rendering
if (status != SceneGraph::BaseNode::HideSubtree)
{
if ( _node->status() != SceneGraph::BaseNode::HideNode )
_node->enter(*_glState, _drawMode);
// fetch material (Node itself can be a material node, so we have to
// set that in front of the nodes own rendering
SceneGraph::MaterialNode* matNode = dynamic_cast<SceneGraph::MaterialNode*>(_node);
if (matNode)
_mat = &matNode->material();
if (_node->status() != SceneGraph::BaseNode::HideNode)
_node->getRenderObjects(this, *_glState, nodeDM, _mat);
if (process_children)
{
SceneGraph::BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
// Process all children which are not second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if (~(*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
// Process all children which are second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if ((*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
}
if (_node->status() != SceneGraph::BaseNode::HideNode )
_node->leave(*_glState, nodeDM);
}
}
}
void Renderer::traverseLightNodes( ACG::SceneGraph::BaseNode* _node )
{
if (_node && numLights_ < SG_MAX_SHADER_LIGHTS)
{
BaseNode::StatusMode status(_node->status());
bool process_children(status != BaseNode::HideChildren);
// If the subtree is hidden, ignore this node and its children while rendering
if (status != BaseNode::HideSubtree)
{
if (_node->status() != BaseNode::HideNode)
{
ACG::SceneGraph::LightNode* lnode = dynamic_cast<ACG::SceneGraph::LightNode*>(_node);
if (lnode)
{
ACG::SceneGraph::LightSource light;
// lnode->getLightSource(&light);
lnode->getLightSourceViewSpace(&light);
// --------------------------
// add light to renderer
if (light.directional())
lightTypes_[numLights_] = ACG::SG_LIGHT_DIRECTIONAL;
else if (light.spotCutoff() > 179.5f)
lightTypes_[numLights_] = ACG::SG_LIGHT_POINT;
else
lightTypes_[numLights_] = ACG::SG_LIGHT_SPOT;
lights_[numLights_] = light;
++numLights_;
}
}
if (process_children)
{
BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
// Process all children which are not second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
traverseLightNodes(*cIt);
// Process all children which are second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if ((*cIt)->traverseMode() & BaseNode::SecondPass)
traverseLightNodes(*cIt);
}
}
}
}
void Renderer::collectLightNodes( ACG::SceneGraph::BaseNode* _node )
{
numLights_ = 0;
traverseLightNodes(_node);
}
...@@ -27,126 +27,11 @@ Renderer::Renderer() ...@@ -27,126 +27,11 @@ Renderer::Renderer()
Renderer::~Renderer() Renderer::~Renderer()
{ {
} }
void Renderer::initializePlugin() void Renderer::initializePlugin()
{ {
ACG::ShaderProgGenerator::setShaderDir(OpenFlipper::Options::shaderDirStr()); ACG::ShaderProgGenerator::setShaderDir(OpenFlipper::Options::shaderDirStr());
} }
void Renderer::addRenderObject(RenderObject* _renderObject)
{
// do some more checks for error detection
if (!_renderObject->vertexDecl)
std::cout << "error: missing vertex declaration" << std::endl;
else
{
renderObjects_.push_back(*_renderObject);
RenderObject* p = &renderObjects_.back();
if (!p->shaderDesc.numLights)
p->shaderDesc.numLights = numLights_;
else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
p->shaderDesc.numLights = 0;
p->internalFlags_ = 0;
// precompile shader
ShaderCache::getInstance()->getProgram(&p->shaderDesc);
}
}
void Renderer::collectRenderObjects( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _sceneGraphRoot )
{
// collect light sources
collectLightNodes(_sceneGraphRoot);
// flush render objects
// clear() may actually free memory, resulting in capacity = 0
renderObjects_.resize(0);
// default material needed
ACG::SceneGraph::Material defMat;
defMat.baseColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.ambientColor(Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
defMat.diffuseColor(Vec4f(0.6f, 0.6f, 0.6f, 1.0f));
defMat.specularColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.shininess(1.0f);
// defMat.alphaValue(1.0f);
// collect renderables
traverseRenderableNodes(_glState, _drawMode, _sceneGraphRoot, &defMat);
}
void Renderer::traverseRenderableNodes( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _node, const SceneGraph::Material* _mat )
{
if (_node)
{
SceneGraph::BaseNode::StatusMode status(_node->status());
bool process_children(status != SceneGraph::BaseNode::HideChildren);
SceneGraph::DrawModes::DrawMode nodeDM = _node->drawMode();
if (nodeDM == SceneGraph::DrawModes::DEFAULT)
nodeDM = _drawMode;
// If the subtree is hidden, ignore this node and its children while rendering
if (status != SceneGraph::BaseNode::HideSubtree)
{
if ( _node->status() != SceneGraph::BaseNode::HideNode )
_node->enter(*_glState, _drawMode);
// fetch material (Node itself can be a material node, so we have to
// set that in front of the nodes own rendering
SceneGraph::MaterialNode* matNode = dynamic_cast<SceneGraph::MaterialNode*>(_node);
if (matNode)
_mat = &matNode->material();
if (_node->status() != SceneGraph::BaseNode::HideNode)
_node->getRenderObjects(this, *_glState, nodeDM, _mat);
if (process_children)
{
SceneGraph::BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
// Process all children which are not second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if (~(*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
// Process all children which are second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if ((*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
}
if (_node->status() != SceneGraph::BaseNode::HideNode )
_node->leave(*_glState, nodeDM);
}
}
}
int Renderer::cmpPriority(const void* _a, const void* _b) int Renderer::cmpPriority(const void* _a, const void* _b)
{ {
const RenderObject* a = *(const RenderObject**)_a; const RenderObject* a = *(const RenderObject**)_a;
...@@ -155,47 +40,49 @@ int Renderer::cmpPriority(const void* _a, const void* _b) ...@@ -155,47 +40,49 @@ int Renderer::cmpPriority(const void* _a, const void* _b)
return a->priority - b->priority; return a->priority - b->priority;
} }
void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties) void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
{ {
// First, all render objects get collected.
collectRenderObjects(_glState, _properties.drawMode(), PluginFunctions::getSceneGraphRootNode()); collectRenderObjects(_glState, _properties.drawMode(), PluginFunctions::getSceneGraphRootNode());
// Check if there is anything to render
if (renderObjects_.empty()) if (renderObjects_.empty())
return; return;
const size_t numRenderObjects = getNumRenderObjects(); // ==========================================================
// Sort renderable objects based on their priority
// ==========================================================
const size_t numRenderObjects = renderObjects_.size();
// sort for priority // sort for priority
RenderObject** sortedObjects = new RenderObject*[numRenderObjects]; RenderObject** sortedObjects = new RenderObject*[numRenderObjects];
// init sorted objects // init sorted objects
for (size_t i = 0; i < numRenderObjects; ++i) for (size_t i = 0; i < numRenderObjects; ++i)
{
sortedObjects[i] = &renderObjects_[i]; sortedObjects[i] = &renderObjects_[i];
}
qsort(sortedObjects, numRenderObjects, sizeof(RenderObject*), cmpPriority); qsort(sortedObjects, numRenderObjects, sizeof(RenderObject*), cmpPriority);
// dumpRenderObjectsToText("../../dump_ro.txt", sortedObjects); // dumpRenderObjectsToText("../../dump_ro.txt", sortedObjects);
// ==========================================================
// Now we render them
// ==========================================================
// render // ---------------------------
// Initialize the render state
// ---------------------------
// gl cleanup // gl cleanup
glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_INDEX_ARRAY); glDisableClientState(GL_INDEX_ARRAY);
// size of a rendered point is set in vertex-shader via gl_PointSize // size of a rendered point is set in vertex-shader via gl_PointSize
#ifndef __APPLE__ #ifndef __APPLE__
glEnable(GL_PROGRAM_POINT_SIZE_ARB); glEnable(GL_PROGRAM_POINT_SIZE_ARB);
#endif #endif
glEnable(GL_CULL_FACE); glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
...@@ -207,11 +94,15 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert ...@@ -207,11 +94,15 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert
glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f); glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// ---------------------------
// Render objects one by one
// ---------------------------
for (size_t i = 0; i < numRenderObjects; ++i) for (size_t i = 0; i < numRenderObjects; ++i)
renderObject(sortedObjects[i]); renderObject(sortedObjects[i]);
// ----------------------------------------
// restore common opengl state // Restore common opengl state
// ----------------------------------------
// log window remains hidden otherwise // log window remains hidden otherwise
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
...@@ -225,9 +116,6 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert ...@@ -225,9 +116,6 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
delete [] sortedObjects; delete [] sortedObjects;
} }
...@@ -245,7 +133,6 @@ void Renderer::bindObjectVBO(ACG::RenderObject* _obj, ...@@ -245,7 +133,6 @@ void Renderer::bindObjectVBO(ACG::RenderObject* _obj,
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer); glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer);
// activate vertex declaration // activate vertex declaration
_obj->vertexDecl->activateShaderPipeline(_prog); _obj->vertexDecl->activateShaderPipeline(_prog);
} }
...@@ -409,7 +296,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj, ...@@ -409,7 +296,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj,
// select shader from cache // select shader from cache
GLSL::Program* prog = _prog ? _prog : ShaderCache::getInstance()->getProgram(&_obj->shaderDesc); GLSL::Program* prog = _prog ? _prog : ShaderCache::getInstance()->getProgram(&_obj->shaderDesc);
bindObjectVBO(_obj, prog); bindObjectVBO(_obj, prog);
// --------------------------------------- // ---------------------------------------
...@@ -435,91 +321,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj, ...@@ -435,91 +321,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj,
} }
void Renderer::traverseLightNodes( ACG::SceneGraph::BaseNode* _node )
{
if (_node && numLights_ < SG_MAX_SHADER_LIGHTS)
{
BaseNode::StatusMode status(_node->status());
bool process_children(status != BaseNode::HideChildren);
// If the subtree is hidden, ignore this node and its children while rendering
if (status != BaseNode::HideSubtree)
{
if (_node->status() != BaseNode::HideNode)
{
ACG::SceneGraph::LightNode* lnode = dynamic_cast<ACG::SceneGraph::LightNode*>(_node);
if (lnode)
{
ACG::SceneGraph::LightSource light;
// lnode->getLightSource(&light);
lnode->getLightSourceViewSpace(&light);
// --------------------------
// add light to renderer
if (light.directional())
lightTypes_[numLights_] = ACG::SG_LIGHT_DIRECTIONAL;
else if (light.spotCutoff() > 179.5f)
lightTypes_[numLights_] = ACG::SG_LIGHT_POINT;
else
lightTypes_[numLights_] = ACG::SG_LIGHT_SPOT;
lights_[numLights_] = light;
++numLights_;
}
}
if (process_children)
{
BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
// Process all children which are not second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if (~(*cIt)->traverseMode() & BaseNode::SecondPass)
traverseLightNodes(*cIt);
// Process all children which are second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if ((*cIt)->traverseMode() & BaseNode::SecondPass)
traverseLightNodes(*cIt);
}
}
}
}
void Renderer::collectLightNodes( ACG::SceneGraph::BaseNode* _node )
{
numLights_ = 0;
traverseLightNodes(_node);
}
int Renderer::getNumRenderObjects() const
{
return renderObjects_.size();
}
QString Renderer::checkOpenGL() QString Renderer::checkOpenGL()
{ {
return QString(""); return QString("");
...@@ -531,7 +332,9 @@ void Renderer::dumpRenderObjectsToText(const char* _fileName, RenderObject** _so ...@@ -531,7 +332,9 @@ void Renderer::dumpRenderObjectsToText(const char* _fileName, RenderObject** _so
if (fileOut.open(QFile::WriteOnly | QFile::Truncate)) if (fileOut.open(QFile::WriteOnly | QFile::Truncate))
{ {
QTextStream outStrm(&fileOut); QTextStream outStrm(&fileOut);
for (int i = 0; i < getNumRenderObjects(); ++i) const int numRenderObjects = renderObjects_.size();
for (int i = 0; i < numRenderObjects; ++i)
{ {
if (_sortedList) if (_sortedList)
outStrm << "\n" << _sortedList[i]->toString(); outStrm << "\n" << _sortedList[i]->toString();
......
...@@ -60,6 +60,11 @@ ...@@ -60,6 +60,11 @@
#include <map> #include <map>
/** \brief A simple renderer Example for the shader pipeline
*
* It has to derive from ACG::IRenderer as the nodes will will pass back the generated render objects
* via this objects addRenderObject() function.
*/
class Renderer : public QObject, BaseInterface, RenderInterface, LoggingInterface, ACG::IRenderer class Renderer : public QObject, BaseInterface, RenderInterface, LoggingInterface, ACG::IRenderer
{ {
Q_OBJECT Q_OBJECT
...@@ -94,110 +99,165 @@ private slots: ...@@ -94,110 +99,165 @@ private slots:
void render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties); void render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties);
QString rendererName() {return QString("Alpha_Version_ShaderPipeline");} QString rendererName() {return QString("Alpha_Version_ShaderPipeline");}
void supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode) {_mode = ACG::SceneGraph::DrawModes::DEFAULT;} void supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode) {_mode = ACG::SceneGraph::DrawModes::DEFAULT;}
QString checkOpenGL(); QString checkOpenGL();
//=========================================================================
// Callback for the scenegraph nodes
//=========================================================================
public: public:
/** \brief callback for the nodes, which send new render objects via this function.
*
* AddRenderObject is typically called by a scenegraph nodes during the collection of renderable
* objects.
*
* A renderobject is a collection of opengl states, buffers and parameters, that correspond to exactly one draw call.
*/
virtual void addRenderObject(ACG::RenderObject* _renderObject);
/** //=========================================================================
Traverses the scenegraph and calls the getRenderObject function of each node. // Render object collection
Each node can then add multiple renderobjects via addRenderObject to this renderer. //=========================================================================
Also collects all light sources in the scenegraph. private:
The currently active list of renderobjects is invalidated too. /** \brief Traverse the scenegraph to collect render information
*/ *
* Traverses the scenegraph and calls the getRenderObject function of each node.
* Each node can then add multiple renderobjects via addRenderObject to this renderer.
*
* Also collects all light sources in the scenegraph.
* The currently active list of renderobjects is invalidated too.
*/
void collectRenderObjects(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _sceneGraphRoot); void collectRenderObjects(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _sceneGraphRoot);
/** /** \brief Scene graph traversal for render object collection
addRenderObject is typically called by a scenegraph node. *