From 7028cbe09c688437910a25623098762bf0fa592d Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Mon, 28 Mar 2016 22:28:34 +1000 Subject: Move Irrlicht to src/others. --- .../source/Irrlicht/COctreeSceneNode.cpp | 636 +++++++++++++++++++++ 1 file changed, 636 insertions(+) create mode 100644 src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp') diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp new file mode 100644 index 0000000..226f6f6 --- /dev/null +++ b/src/others/irrlicht-1.8.1/source/Irrlicht/COctreeSceneNode.cpp @@ -0,0 +1,636 @@ +// 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 "COctreeSceneNode.h" +#include "Octree.h" +#include "ISceneManager.h" +#include "IVideoDriver.h" +#include "ICameraSceneNode.h" +#include "IMeshCache.h" +#include "IAnimatedMesh.h" +#include "IMaterialRenderer.h" +#include "os.h" +#include "CShadowVolumeSceneNode.h" + +namespace irr +{ +namespace scene +{ + + +//! constructor +COctreeSceneNode::COctreeSceneNode(ISceneNode* parent, ISceneManager* mgr, + s32 id, s32 minimalPolysPerNode) + : IMeshSceneNode(parent, mgr, id), StdOctree(0), LightMapOctree(0), + TangentsOctree(0), VertexType((video::E_VERTEX_TYPE)-1), + MinimalPolysPerNode(minimalPolysPerNode), Mesh(0), Shadow(0), + UseVBOs(OCTREE_USE_HARDWARE), UseVisibilityAndVBOs(OCTREE_USE_VISIBILITY), + BoxBased(OCTREE_BOX_BASED) +{ +#ifdef _DEBUG + setDebugName("COctreeSceneNode"); +#endif +} + + +//! destructor +COctreeSceneNode::~COctreeSceneNode() +{ + if (Shadow) + Shadow->drop(); + deleteTree(); +} + + +void COctreeSceneNode::OnRegisterSceneNode() +{ + if (IsVisible) + { + // because this node supports rendering of mixed mode meshes consisting of + // transparent and solid material at the same time, we need to go through all + // materials, check of what type they are and register this node for the right + // render pass according to that. + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + PassCount = 0; + u32 transparentCount = 0; + u32 solidCount = 0; + + // count transparent and solid materials in this scene node + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + + if (rnd && rnd->isTransparent()) + ++transparentCount; + else + ++solidCount; + + if (solidCount && transparentCount) + break; + } + + // register according to material types counted + + if (solidCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID); + + if (transparentCount) + SceneManager->registerNodeForRendering(this, scene::ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); + } +} + + +//! renders the node. +void COctreeSceneNode::render() +{ + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + + if (VertexType == -1 || !driver) + return; + + ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if (!camera) + return; + + bool isTransparentPass = + SceneManager->getSceneNodeRenderPass() == scene::ESNRP_TRANSPARENT; + ++PassCount; + + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + if (Shadow) + Shadow->updateShadowVolumes(); + + SViewFrustum frust = *camera->getViewFrustum(); + + //transform the frustum to the current absolute transformation + if ( !AbsoluteTransformation.isIdentity() ) + { + core::matrix4 invTrans(AbsoluteTransformation, core::matrix4::EM4CONST_INVERSE); + frust.transform(invTrans); + } + + const core::aabbox3d &box = frust.getBoundingBox(); + + switch (VertexType) + { + case video::EVT_STANDARD: + { + if (BoxBased) + StdOctree->calculatePolys(box); + else + StdOctree->calculatePolys(frust); + + const Octree::SIndexData* d = StdOctree->getIndexData(); + + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + driver->drawIndexedTriangleList( + &StdMeshes[i].Vertices[0], StdMeshes[i].Vertices.size(), + d[i].Indices, d[i].CurrentSize / 3); + } + } + + // for debug purposes only + if (DebugDataVisible && !Materials.empty() && PassCount==1) + { + const core::aabbox3df& box = frust.getBoundingBox(); + core::array< const core::aabbox3d* > boxes; + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) + { + StdOctree->getBoundingBoxes(box, boxes); + for (u32 b=0; b!=boxes.size(); ++b) + driver->draw3DBox(*boxes[b]); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + driver->draw3DBox(Box,video::SColor(0,255,0,0)); + } + } + break; + case video::EVT_2TCOORDS: + { + if (BoxBased) + LightMapOctree->calculatePolys(box); + else + LightMapOctree->calculatePolys(frust); + + const Octree::SIndexData* d = LightMapOctree->getIndexData(); + + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + if (UseVBOs) + { + if (UseVisibilityAndVBOs) + { + u16* oldPointer = LightMapMeshes[i].Indices.pointer(); + const u32 oldSize = LightMapMeshes[i].Indices.size(); + LightMapMeshes[i].Indices.set_free_when_destroyed(false); + LightMapMeshes[i].Indices.set_pointer(d[i].Indices, d[i].CurrentSize, false, false); + LightMapMeshes[i].setDirty(scene::EBT_INDEX); + driver->drawMeshBuffer ( &LightMapMeshes[i] ); + LightMapMeshes[i].Indices.set_pointer(oldPointer, oldSize); + LightMapMeshes[i].setDirty(scene::EBT_INDEX); + } + else + driver->drawMeshBuffer ( &LightMapMeshes[i] ); + } + else + driver->drawIndexedTriangleList( + &LightMapMeshes[i].Vertices[0], + LightMapMeshes[i].Vertices.size(), + d[i].Indices, d[i].CurrentSize / 3); + } + } + + // for debug purposes only + if (DebugDataVisible && !Materials.empty() && PassCount==1) + { + const core::aabbox3d &box = frust.getBoundingBox(); + core::array< const core::aabbox3d* > boxes; + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) + { + LightMapOctree->getBoundingBoxes(box, boxes); + for (u32 b=0; bdraw3DBox(*boxes[b]); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + driver->draw3DBox(Box,video::SColor(0,255,0,0)); + } + } + break; + case video::EVT_TANGENTS: + { + if (BoxBased) + TangentsOctree->calculatePolys(box); + else + TangentsOctree->calculatePolys(frust); + + const Octree::SIndexData* d = TangentsOctree->getIndexData(); + + for (u32 i=0; igetMaterialRenderer(Materials[i].MaterialType); + const bool transparent = (rnd && rnd->isTransparent()); + + // only render transparent buffer if this is the transparent render pass + // and solid only in solid pass + if (transparent == isTransparentPass) + { + driver->setMaterial(Materials[i]); + driver->drawIndexedTriangleList( + &TangentsMeshes[i].Vertices[0], TangentsMeshes[i].Vertices.size(), + d[i].Indices, d[i].CurrentSize / 3); + } + } + + // for debug purposes only + if (DebugDataVisible && !Materials.empty() && PassCount==1) + { + const core::aabbox3d &box = frust.getBoundingBox(); + core::array< const core::aabbox3d* > boxes; + video::SMaterial m; + m.Lighting = false; + driver->setMaterial(m); + if ( DebugDataVisible & scene::EDS_BBOX_BUFFERS ) + { + TangentsOctree->getBoundingBoxes(box, boxes); + for (u32 b=0; bdraw3DBox(*boxes[b]); + } + + if ( DebugDataVisible & scene::EDS_BBOX ) + driver->draw3DBox(Box,video::SColor(0,255,0,0)); + } + } + break; + } +} + + +//! Removes a child from this scene node. +//! Implemented here, to be able to remove the shadow properly, if there is one, +//! or to remove attached childs. +bool COctreeSceneNode::removeChild(ISceneNode* child) +{ + if (child && Shadow == child) + { + Shadow->drop(); + Shadow = 0; + } + + return ISceneNode::removeChild(child); +} + + +//! Creates shadow volume scene node as child of this node +//! and returns a pointer to it. +IShadowVolumeSceneNode* COctreeSceneNode::addShadowVolumeSceneNode( + const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) +{ + if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) + return 0; + + if (!shadowMesh) + shadowMesh = Mesh; // if null is given, use the mesh of node + + if (Shadow) + Shadow->drop(); + + Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); + return Shadow; +} + + +//! returns the axis aligned bounding box of this node +const core::aabbox3d& COctreeSceneNode::getBoundingBox() const +{ + return Box; +} + + +//! creates the tree +/* This method has a lot of duplication and overhead. Moreover, the tangents mesh conversion does not really work. I think we need a a proper mesh implementation for octrees, which handle all vertex types internally. Converting all structures to just one vertex type is always problematic. +Thanks to Auria for fixing major parts of this method. */ +bool COctreeSceneNode::createTree(IMesh* mesh) +{ + if (!mesh) + return false; + + MeshName = SceneManager->getMeshCache()->getMeshName(mesh); + + mesh->grab(); + deleteTree(); + + Mesh = mesh; + + const u32 beginTime = os::Timer::getRealTime(); + + u32 nodeCount = 0; + u32 polyCount = 0; + u32 i; + + Box = mesh->getBoundingBox(); + + if (mesh->getMeshBufferCount()) + { + // check for "larger" buffer types + VertexType = video::EVT_STANDARD; + u32 meshReserve = 0; + for (i=0; igetMeshBufferCount(); ++i) + { + const IMeshBuffer* b = mesh->getMeshBuffer(i); + if (b->getVertexCount() && b->getIndexCount()) + { + ++meshReserve; + if (b->getVertexType() == video::EVT_2TCOORDS) + VertexType = video::EVT_2TCOORDS; + else if (b->getVertexType() == video::EVT_TANGENTS) + VertexType = video::EVT_TANGENTS; + } + } + Materials.reallocate(Materials.size()+meshReserve); + + switch(VertexType) + { + case video::EVT_STANDARD: + { + StdMeshes.reallocate(StdMeshes.size() + meshReserve); + for (i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + + StdMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk &nchunk = StdMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]); + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]); + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + StdOctree = new Octree(StdMeshes, MinimalPolysPerNode); + nodeCount = StdOctree->getNodeCount(); + } + break; + case video::EVT_2TCOORDS: + { + LightMapMeshes.reallocate(LightMapMeshes.size() + meshReserve); + + for ( i=0; i < mesh->getMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + LightMapMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk& nchunk = LightMapMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + if (UseVisibilityAndVBOs) + { + nchunk.setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); + nchunk.setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); + } + else + nchunk.setHardwareMappingHint(scene::EHM_STATIC); + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex*)b->getVertices())[v]); + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertex2TCoords*)b->getVertices())[v]); + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + LightMapOctree = new Octree(LightMapMeshes, MinimalPolysPerNode); + nodeCount = LightMapOctree->getNodeCount(); + } + break; + case video::EVT_TANGENTS: + { + TangentsMeshes.reallocate(TangentsMeshes.size() + meshReserve); + + for (u32 i=0; igetMeshBufferCount(); ++i) + { + IMeshBuffer* b = mesh->getMeshBuffer(i); + + if (b->getVertexCount() && b->getIndexCount()) + { + Materials.push_back(b->getMaterial()); + TangentsMeshes.push_back(Octree::SMeshChunk()); + Octree::SMeshChunk& nchunk = TangentsMeshes.getLast(); + nchunk.MaterialId = Materials.size() - 1; + + u32 v; + nchunk.Vertices.reallocate(b->getVertexCount()); + switch (b->getVertexType()) + { + case video::EVT_STANDARD: + for (v=0; vgetVertexCount(); ++v) + { + const video::S3DVertex& tmpV = ((video::S3DVertex*)b->getVertices())[v]; + nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords)); + } + break; + case video::EVT_2TCOORDS: + for (v=0; vgetVertexCount(); ++v) + { + const video::S3DVertex2TCoords& tmpV = ((video::S3DVertex2TCoords*)b->getVertices())[v]; + nchunk.Vertices.push_back(video::S3DVertexTangents(tmpV.Pos, tmpV.Color, tmpV.TCoords)); + } + break; + case video::EVT_TANGENTS: + for (v=0; vgetVertexCount(); ++v) + nchunk.Vertices.push_back(((video::S3DVertexTangents*)b->getVertices())[v]); + break; + } + + polyCount += b->getIndexCount(); + nchunk.Indices.reallocate(b->getIndexCount()); + for (v=0; vgetIndexCount(); ++v) + nchunk.Indices.push_back(b->getIndices()[v]); + } + } + + TangentsOctree = new Octree(TangentsMeshes, MinimalPolysPerNode); + nodeCount = TangentsOctree->getNodeCount(); + } + break; + } + } + + const u32 endTime = os::Timer::getRealTime(); + c8 tmp[255]; + sprintf(tmp, "Needed %ums to create Octree SceneNode.(%u nodes, %u polys)", + endTime - beginTime, nodeCount, polyCount/3); + os::Printer::log(tmp, ELL_INFORMATION); + + return true; +} + + +//! returns the material based on the zero based index i. To get the amount +//! of materials used by this scene node, use getMaterialCount(). +//! This function is needed for inserting the node into the scene hirachy on a +//! optimal position for minimizing renderstate changes, but can also be used +//! to directly modify the material of a scene node. +video::SMaterial& COctreeSceneNode::getMaterial(u32 i) +{ + if ( i >= Materials.size() ) + return ISceneNode::getMaterial(i); + + return Materials[i]; +} + + +//! returns amount of materials used by this scene node. +u32 COctreeSceneNode::getMaterialCount() const +{ + return Materials.size(); +} + + +//! Writes attributes of the scene node. +void COctreeSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + ISceneNode::serializeAttributes(out, options); + + out->addInt("MinimalPolysPerNode", MinimalPolysPerNode); + out->addString("Mesh", MeshName.c_str()); +} + + +//! Reads attributes of the scene node. +void COctreeSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + const s32 oldMinimal = MinimalPolysPerNode; + + MinimalPolysPerNode = in->getAttributeAsInt("MinimalPolysPerNode"); + io::path newMeshStr = in->getAttributeAsString("Mesh"); + + IMesh* newMesh = 0; + + if (newMeshStr == "") + newMeshStr = MeshName; + + IAnimatedMesh* newAnimatedMesh = SceneManager->getMesh(newMeshStr.c_str()); + + if (newAnimatedMesh) + newMesh = newAnimatedMesh->getMesh(0); + + if (newMesh && ((MeshName != newMeshStr) || (MinimalPolysPerNode != oldMinimal))) + { + // recalculate tree + createTree(newMesh); + } + + ISceneNode::deserializeAttributes(in, options); +} + + +void COctreeSceneNode::deleteTree() +{ + delete StdOctree; + StdOctree = 0; + StdMeshes.clear(); + + delete LightMapOctree; + LightMapOctree = 0; + LightMapMeshes.clear(); + + delete TangentsOctree; + TangentsOctree = 0; + TangentsMeshes.clear(); + + Materials.clear(); + + if(Mesh) + Mesh->drop(); +} + +void COctreeSceneNode::setMesh(IMesh* mesh) +{ + createTree(mesh); +} + +IMesh* COctreeSceneNode::getMesh(void) +{ + return Mesh; +} + +void COctreeSceneNode::setReadOnlyMaterials(bool readonly) +{ + // Do nothing +} + +bool COctreeSceneNode::isReadOnlyMaterials() const +{ + return false; +} + + +} // end namespace scene +} // end namespace irr + -- cgit v1.1