// 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& 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 getTransformedBoundingBox() const IRR_OVERRIDE { core::aabbox3d box = getBoundingBox(); getAbsoluteTransformation().transformBoxEx(box); return box; } virtual void getTransformedBoundingBoxEdges(core::array< core::vector3d >& 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