mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-15 04:03:48 +01:00
186 lines
6.9 KiB
C
186 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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//! Renders the node.
|
||
|
virtual void render() IRR_OVERRIDE
|
||
|
{
|
||
|
video::IVideoDriver* driver = SceneManager->getVideoDriver();
|
||
|
driver->setTransform(video::ETS_WORLD, MeshNodeParent.getAbsoluteTransformation());
|
||
|
renderBuffer(driver);
|
||
|
|
||
|
// resetting each time so direct calls to render() for parent node continue to work
|
||
|
RenderPass = ESNRP_NONE;
|
||
|
ParentDoesRender = true;
|
||
|
}
|
||
|
|
||
|
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
|