irrlicht/source/Irrlicht/CBufferRenderNode.h
cutealien 31931b0455 Fix problems in rendering nodes outside SceneManager caused by new render-per-buffer code
Did no longer render nodes which were rendered in SceneManager + outside SceneManager if they didn't have the per-buffer-rendering enabled.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6491 dfc29bdd-3216-0410-991c-e03cc46cb475
2023-05-09 10:11:49 +00:00

187 lines
6.9 KiB
C++

// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "IMeshSceneNode.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "ISceneNode.h"
namespace irr
{
namespace scene
{
// A node which helps rendering a single buffer of an IMeshSceneNode
// It solves several problems:
// - Allowing the scene manager to sort meshbuffers. Currently it only sorts nodes, so we have to put each meshbuffer in an extra node to allow that
// The reason we want that is
// a) Better sorting when a node has several transparent buffers (without it they will be just drawn in original order)
// b) It can allow to avoid texture changes in the render-pipeline which can make quite a bit of a performance difference
// - It buffers the RenderPass. Bit of an abuse of this interface maybe?
// Strangely the check for finding out the correct render pass constantly shows up in profilers.
// Not exactly sure why as the check looks pretty cheap. My best guess is that there are some cache misses going on due to several virtual
// function pointers being involved in the transparency check.
//
// For now (added pre Irrlicht 1.9) this interface is still a bit experimental. Maybe could go into public headers later, not sure yet.
// Or maybe the SceneManager shouldn't work with nodes at all but a simplified interface to render buffers from which Nodes can derive?
// CBufferRenderNode isn't really a node - it has to work around nearly all the ISceneNode functions, it only has to be one because
// the SceneManager can't sort anything else but nodes.
class CBufferRenderNode : public ISceneNode
{
public:
CBufferRenderNode(irr::scene::IMeshSceneNode& parent, irr::scene::ISceneManager* mgr, irr::u32 bufferIdx)
: ISceneNode(0, mgr) // we don't want it in the scenegraph
, MeshNodeParent(parent)
, BufferIdx(bufferIdx)
, RenderPass(ESNRP_NONE)
, ParentDoesRender(true)
{
// While it's not the parent in the SceneGraph, we still want to allow accessing it
// That can be useful p.E. in a light manager
// Arguably if it's a good idea as it's a bit going against the ISceneNode interface - having a parent which doesn't have this node as child.
// But the alternative is adding another member to the ISceneNode or having SceneManager not use the ISceneNode for rendering
// So for now it should be fine, but if that interface ever get's public... we might have to reconsider
Parent = &MeshNodeParent;
}
u32 prepareRendering(E_SCENE_NODE_RENDER_PASS pass, bool parentDoesRender)
{
RenderPass = pass;
ParentDoesRender = parentDoesRender;
if ( !ParentDoesRender )
return SceneManager->registerNodeForRendering(this, pass);
return 0;
}
E_SCENE_NODE_RENDER_PASS getRenderPass() const
{
return RenderPass;
}
// When true render() this node hasn't registered itself for rendering, but expects it's owner to do the rendering
bool getDoesParentRender() const
{
return ParentDoesRender;
}
// Render meshbuffer, but don't set transformation
// It's assumed that this function is only called from within the correct render stage
void renderBuffer(video::IVideoDriver* driver)
{
const IMeshBuffer* mb = MeshNodeParent.getMesh()->getMeshBuffer(BufferIdx);
if (mb)
{
const video::SMaterial& material = MeshNodeParent.getMaterial(BufferIdx);
driver->setMaterial(material);
driver->drawMeshBuffer(mb);
}
// Resetting after each rendering so direct calls to render() for parent node continue to work
// Assuming each pass only runs once
RenderPass = ESNRP_NONE;
ParentDoesRender = true;
}
//! Renders the node.
virtual void render() IRR_OVERRIDE
{
video::IVideoDriver* driver = SceneManager->getVideoDriver();
driver->setTransform(video::ETS_WORLD, MeshNodeParent.getAbsoluteTransformation());
renderBuffer(driver);
}
virtual const core::aabbox3d<f32>& getBoundingBox() const IRR_OVERRIDE
{
return MeshNodeParent.getMesh()->getMeshBuffer(BufferIdx)->getBoundingBox();
}
virtual video::SMaterial& getMaterial(u32 num) IRR_OVERRIDE
{
return MeshNodeParent.getMaterial(BufferIdx);
}
virtual u32 getMaterialCount() const IRR_OVERRIDE
{
return 1;
}
virtual const core::matrix4& getAbsoluteTransformation() const IRR_OVERRIDE
{
return MeshNodeParent.getAbsoluteTransformation();
}
virtual const core::aabbox3d<f32> getTransformedBoundingBox() const IRR_OVERRIDE
{
core::aabbox3d<f32> box = getBoundingBox();
getAbsoluteTransformation().transformBoxEx(box);
return box;
}
virtual void getTransformedBoundingBoxEdges(core::array< core::vector3d<f32> >& edges) const IRR_OVERRIDE
{
edges.set_used(8);
getBoundingBox().getEdges( edges.pointer() );
for ( u32 i=0; i<8; ++i )
getAbsoluteTransformation().transformVect( edges[i] );
}
virtual core::matrix4 getRelativeTransformation() const IRR_OVERRIDE
{
return MeshNodeParent.getRelativeTransformation();
}
virtual s32 getID() const IRR_OVERRIDE
{
return MeshNodeParent.getID();
}
virtual const core::vector3df& getScale() const IRR_OVERRIDE
{
return MeshNodeParent.getScale();
}
virtual const core::vector3df& getRotation() const IRR_OVERRIDE
{
return MeshNodeParent.getRotation();
}
virtual const core::vector3df& getPosition() const IRR_OVERRIDE
{
return MeshNodeParent.getPosition();
}
virtual core::vector3df getAbsolutePosition() const IRR_OVERRIDE
{
return MeshNodeParent.getAbsolutePosition();
}
virtual ITriangleSelector* getTriangleSelector() const IRR_OVERRIDE
{
return MeshNodeParent.getTriangleSelector();
}
// Not allowing any of that stuff
virtual void OnRegisterSceneNode()IRR_OVERRIDE {}
virtual void OnAnimate(u32 timeMs) IRR_OVERRIDE {}
virtual void addChild(ISceneNode* child) IRR_OVERRIDE {}
virtual void addAnimator(ISceneNodeAnimator* animator) IRR_OVERRIDE {}
virtual void setScale(const core::vector3df& scale) IRR_OVERRIDE {}
virtual void setRotation(const core::vector3df& rotation) IRR_OVERRIDE {}
virtual void setPosition(const core::vector3df& newpos) IRR_OVERRIDE {}
virtual void setParent(ISceneNode* newParent) IRR_OVERRIDE {}
virtual void setTriangleSelector(ITriangleSelector* selector) IRR_OVERRIDE {}
virtual void updateAbsolutePosition() IRR_OVERRIDE {}
virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const IRR_OVERRIDE {}
virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) IRR_OVERRIDE {}
private:
irr::scene::IMeshSceneNode& MeshNodeParent;
irr::u32 BufferIdx; // Note: Not saving the meshbuffer pointer as meshes can add/remove buffers and we don't want to keep track of that
E_SCENE_NODE_RENDER_PASS RenderPass;
bool ParentDoesRender;
};
} // end namespace scene
} // end namespace irr