diff options
Diffstat (limited to 'source/Irrlicht/CShadowVolumeSceneNode.cpp')
-rw-r--r-- | source/Irrlicht/CShadowVolumeSceneNode.cpp | 531 |
1 files changed, 0 insertions, 531 deletions
diff --git a/source/Irrlicht/CShadowVolumeSceneNode.cpp b/source/Irrlicht/CShadowVolumeSceneNode.cpp deleted file mode 100644 index 9c7b3ab..0000000 --- a/source/Irrlicht/CShadowVolumeSceneNode.cpp +++ /dev/null @@ -1,531 +0,0 @@ -// 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 "IrrCompileConfig.h"
-
-#ifdef _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
-
-#include "CShadowVolumeSceneNode.h"
-#include "ISceneManager.h"
-#include "IMesh.h"
-#include "IVideoDriver.h"
-#include "ICameraSceneNode.h"
-#include "SViewFrustum.h"
-#include "SLight.h"
-#include "os.h"
-
-namespace irr
-{
-namespace scene
-{
-
-
-//! constructor
-CShadowVolumeSceneNode::CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent,
- ISceneManager* mgr, s32 id, bool zfailmethod, f32 infinity)
-: IShadowVolumeSceneNode(parent, mgr, id),
- AdjacencyDirtyFlag(true),
- ShadowMesh(0), IndexCount(0), VertexCount(0), ShadowVolumesUsed(0),
- Infinity(infinity), UseZFailMethod(zfailmethod), Optimization(ESV_SILHOUETTE_BY_POS)
-{
- #ifdef _DEBUG
- setDebugName("CShadowVolumeSceneNode");
- #endif
- setShadowMesh(shadowMesh);
- setAutomaticCulling(scene::EAC_OFF);
-}
-
-
-//! destructor
-CShadowVolumeSceneNode::~CShadowVolumeSceneNode()
-{
- if (ShadowMesh)
- ShadowMesh->drop();
-}
-
-
-void CShadowVolumeSceneNode::createShadowVolume(const core::vector3df& light, bool isDirectional)
-{
- SShadowVolume* svp = 0;
- core::aabbox3d<f32>* bb = 0;
-
- // builds the shadow volume and adds it to the shadow volume list.
-
- if (ShadowVolumes.size() > ShadowVolumesUsed)
- {
- // get the next unused buffer
-
- svp = &ShadowVolumes[ShadowVolumesUsed];
- svp->set_used(0);
-
- bb = &ShadowBBox[ShadowVolumesUsed];
- }
- else
- {
- ShadowVolumes.push_back(SShadowVolume());
- svp = &ShadowVolumes.getLast();
-
- ShadowBBox.push_back(core::aabbox3d<f32>());
- bb = &ShadowBBox.getLast();
- }
- svp->reallocate(IndexCount*5);
- ++ShadowVolumesUsed;
-
- // We use triangle lists
- Edges.set_used(IndexCount*2);
- u32 numEdges = 0;
-
- numEdges=createEdgesAndCaps(light, isDirectional, svp, bb);
-
- // for all edges add the near->far quads
- core::vector3df lightDir1(light*Infinity);
- core::vector3df lightDir2(light*Infinity);
- for (u32 i=0; i<numEdges; ++i)
- {
- const core::vector3df &v1 = Vertices[Edges[2*i+0]];
- const core::vector3df &v2 = Vertices[Edges[2*i+1]];
- if ( !isDirectional )
- {
- lightDir1 = (v1 - light).normalize()*Infinity;
- lightDir2 = (v2 - light).normalize()*Infinity;
- }
- const core::vector3df v3(v1+lightDir1);
- const core::vector3df v4(v2+lightDir2);
-
- // Add a quad (two triangles) to the vertex list
-#ifdef _DEBUG
- if (svp->size() >= svp->allocated_size()-5)
- os::Printer::log("Allocation too small.", ELL_DEBUG);
-#endif
- svp->push_back(v1);
- svp->push_back(v2);
- svp->push_back(v3);
-
- svp->push_back(v2);
- svp->push_back(v4);
- svp->push_back(v3);
- }
-}
-
-// TODO.
-// Not sure what's going on. Either FaceData should mean the opposite and true should mean facing away from light
-// or I'm missing something else. Anyway - when not setting this then Shadows will look wrong on Burnings driver
-// while they seem to look OK on first view either way on other drivers. Only tested with z-fail so far.
-// Maybe errors only show up close to near/far plane on other drivers as otherwise the stencil-buffer-count
-// is probably ending up with same value anyway
-#define IRR_USE_REVERSE_EXTRUDED
-
-u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, bool isDirectional,
- SShadowVolume* svp, core::aabbox3d<f32>* bb)
-{
- u32 numEdges=0;
- const u32 faceCount = IndexCount / 3;
-
- if(faceCount >= 1)
- bb->reset(Vertices[Indices[0]]);
- else
- bb->reset(0,0,0);
-
- // Check every face if it is front or back facing the light.
- core::vector3df lightDir0(light);
- core::vector3df lightDir1(light);
- core::vector3df lightDir2(light);
- for (u32 i=0; i<faceCount; ++i)
- {
- const core::vector3df v0 = Vertices[Indices[3*i+0]];
- const core::vector3df v1 = Vertices[Indices[3*i+1]];
- const core::vector3df v2 = Vertices[Indices[3*i+2]];
-
- if ( !isDirectional )
- {
- lightDir0 = (v0-light).normalize();
- }
-#ifdef IRR_USE_REVERSE_EXTRUDED
- FaceData[i]=core::triangle3df(v2,v1,v0).isFrontFacing(lightDir0); // actually the back-facing polygons
-#else
- FaceData[i]=core::triangle3df(v0,v1,v2).isFrontFacing(lightDir0);
-#endif
-
-#if 0 // Useful for internal debugging & testing. Show all the faces in the light.
- if ( FaceData[i] )
- {
- video::SMaterial m;
- m.Lighting = false;
- SceneManager->getVideoDriver()->setMaterial(m);
-#ifdef IRR_USE_REVERSE_EXTRUDED
- SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0+lightDir0,v1+lightDir0,v2+lightDir0), irr::video::SColor(255,255, 0, 0));
-#else
- SceneManager->getVideoDriver()->draw3DTriangle(core::triangle3df(v0-lightDir0,v1-lightDir0,v2-lightDir0), irr::video::SColor(255,255, 0, 0));
-#endif
- }
-#endif
-
- if (UseZFailMethod && FaceData[i])
- {
-#ifdef _DEBUG
- if (svp->size() >= svp->allocated_size()-5)
- os::Printer::log("Allocation too small.", ELL_DEBUG);
-#endif
- // add front cap from light-facing faces
- svp->push_back(v2);
- svp->push_back(v1);
- svp->push_back(v0);
-
- // add back cap
- if ( !isDirectional )
- {
- lightDir1 = (v1-light).normalize();
- lightDir2 = (v2-light).normalize();
- }
- const core::vector3df i0 = v0+lightDir0*Infinity;
- const core::vector3df i1 = v1+lightDir1*Infinity;
- const core::vector3df i2 = v2+lightDir2*Infinity;
-
- svp->push_back(i0);
- svp->push_back(i1);
- svp->push_back(i2);
-
- bb->addInternalPoint(i0);
- bb->addInternalPoint(i1);
- bb->addInternalPoint(i2);
- }
- }
-
- // Create edges
- for (u32 i=0; i<faceCount; ++i)
- {
- // check all front facing faces
- if (FaceData[i] == true)
- {
- const u16 wFace0 = Indices[3*i+0];
- const u16 wFace1 = Indices[3*i+1];
- const u16 wFace2 = Indices[3*i+2];
-
- if ( Optimization == ESV_NONE )
- {
- // add edge v0-v1
- Edges[2*numEdges+0] = wFace0;
- Edges[2*numEdges+1] = wFace1;
- ++numEdges;
-
- // add edge v1-v2
- Edges[2*numEdges+0] = wFace1;
- Edges[2*numEdges+1] = wFace2;
- ++numEdges;
-
- // add edge v2-v0
- Edges[2*numEdges+0] = wFace2;
- Edges[2*numEdges+1] = wFace0;
- ++numEdges;
- }
- else
- {
- const u16 adj0 = Adjacency[3*i+0];
- const u16 adj1 = Adjacency[3*i+1];
- const u16 adj2 = Adjacency[3*i+2];
-
- // add edges if face is adjacent to back-facing face
- // or if no adjacent face was found
- if (adj0 == i || FaceData[adj0] == false)
- {
- // add edge v0-v1
- Edges[2*numEdges+0] = wFace0;
- Edges[2*numEdges+1] = wFace1;
- ++numEdges;
- }
-
- if (adj1 == i || FaceData[adj1] == false)
- {
- // add edge v1-v2
- Edges[2*numEdges+0] = wFace1;
- Edges[2*numEdges+1] = wFace2;
- ++numEdges;
- }
-
- if (adj2 == i || FaceData[adj2] == false)
- {
- // add edge v2-v0
- Edges[2*numEdges+0] = wFace2;
- Edges[2*numEdges+1] = wFace0;
- ++numEdges;
- }
- }
- }
- }
- return numEdges;
-}
-
-
-void CShadowVolumeSceneNode::setShadowMesh(const IMesh* mesh)
-{
- if (ShadowMesh == mesh)
- return;
- if (ShadowMesh)
- ShadowMesh->drop();
- ShadowMesh = mesh;
- if (ShadowMesh)
- {
- ShadowMesh->grab();
- Box = ShadowMesh->getBoundingBox();
- }
-}
-
-
-void CShadowVolumeSceneNode::updateShadowVolumes()
-{
- const u32 oldIndexCount = IndexCount;
- const u32 oldVertexCount = VertexCount;
-
- VertexCount = 0;
- IndexCount = 0;
- ShadowVolumesUsed = 0;
-
- const IMesh* const mesh = ShadowMesh;
- if (!mesh)
- return;
-
- // create as much shadow volumes as there are lights but
- // do not ignore the max light settings.
- const u32 lightCount = SceneManager->getVideoDriver()->getDynamicLightCount();
- if (!lightCount)
- return;
-
- // calculate total amount of vertices and indices
-
- u32 i;
- u32 totalVertices = 0;
- u32 totalIndices = 0;
- const u32 bufcnt = mesh->getMeshBufferCount();
-
- for (i=0; i<bufcnt; ++i)
- {
- const IMeshBuffer* buf = mesh->getMeshBuffer(i);
- if ( buf->getIndexType() == video::EIT_16BIT
- && buf->getPrimitiveType() == scene::EPT_TRIANGLES )
- {
- totalIndices += buf->getIndexCount();
- totalVertices += buf->getVertexCount();
- }
- else
- {
- os::Printer::log("ShadowVolumeSceneNode only supports meshbuffers with 16 bit indices and triangles", ELL_WARNING);
- return;
- }
- }
- if ( totalIndices != (u32)(u16)totalIndices)
- {
- // We could switch to 32-bit indices, not much work and just bit of extra memory (< 192k) per shadow volume.
- // If anyone ever complains and really needs that just switch it. But huge shadows are usually a bad idea as they will be slow.
- os::Printer::log("ShadowVolumeSceneNode does not yet support shadowvolumes which need more than 16 bit indices", ELL_WARNING);
- return;
- }
-
- // allocate memory if necessary
-
- Vertices.set_used(totalVertices);
- Indices.set_used(totalIndices);
- FaceData.set_used(totalIndices / 3);
-
- // copy mesh
- // (could speed this up for static meshes by adding some user flag to prevents copying)
- for (i=0; i<bufcnt; ++i)
- {
- const IMeshBuffer* buf = mesh->getMeshBuffer(i);
-
- const u16* idxp = buf->getIndices();
- const u16* idxpend = idxp + buf->getIndexCount();
- for (; idxp!=idxpend; ++idxp)
- Indices[IndexCount++] = *idxp + VertexCount;
-
- const u32 vtxcnt = buf->getVertexCount();
- for (u32 j=0; j<vtxcnt; ++j)
- Vertices[VertexCount++] = buf->getPosition(j);
- }
-
- // recalculate adjacency if necessary
- if (oldVertexCount != VertexCount || oldIndexCount != IndexCount || AdjacencyDirtyFlag)
- calculateAdjacency();
-
- core::matrix4 matInv(Parent->getAbsoluteTransformation());
- matInv.makeInverse();
- core::matrix4 matTransp(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_TRANSPOSED);
- const core::vector3df parentpos = Parent->getAbsolutePosition();
-
- for (i=0; i<lightCount; ++i)
- {
- const video::SLight& dl = SceneManager->getVideoDriver()->getDynamicLight(i);
-
- if ( dl.Type == video::ELT_DIRECTIONAL )
- {
- core::vector3df ldir(dl.Direction);
- matTransp.transformVect(ldir);
- createShadowVolume(ldir, true);
- }
- else
- {
- core::vector3df lpos(dl.Position);
- if (dl.CastShadows &&
- fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f))
- {
- matInv.transformVect(lpos);
- createShadowVolume(lpos, false);
- }
- }
- }
-}
-
-void CShadowVolumeSceneNode::setOptimization(ESHADOWVOLUME_OPTIMIZATION optimization)
-{
- if ( Optimization != optimization )
- {
- Optimization = optimization;
- AdjacencyDirtyFlag = true;
- }
-}
-
-//! pre render method
-void CShadowVolumeSceneNode::OnRegisterSceneNode()
-{
- if (IsVisible)
- {
- SceneManager->registerNodeForRendering(this, scene::ESNRP_SHADOW);
- ISceneNode::OnRegisterSceneNode();
- }
-}
-
-//! renders the node.
-void CShadowVolumeSceneNode::render()
-{
- video::IVideoDriver* driver = SceneManager->getVideoDriver();
-
- if (!ShadowVolumesUsed || !driver)
- return;
-
- driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation());
-
- bool checkFarPlaneClipping = UseZFailMethod && !driver->queryFeature(video::EVDF_DEPTH_CLAMP);
-
- // get camera frustum converted to local coordinates when we have to check for far plane clipping
- SViewFrustum frust;
- if ( checkFarPlaneClipping )
- {
- const irr::scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
- if ( camera )
- {
- frust = *camera->getViewFrustum();
- core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE);
- frust.transform(invTrans);
- }
- else
- checkFarPlaneClipping = false;
- }
-
- for (u32 i=0; i<ShadowVolumesUsed; ++i)
- {
- bool drawShadow = true;
-
- if (checkFarPlaneClipping)
- {
- // Disable shadows drawing, when back cap is behind of ZFar plane.
- // TODO: Using infinite projection matrices instead is said to work better
- // as then we wouldn't fail when the shadow clip the far plane.
- // I couldn't get it working (and neither anyone before me it seems).
- // Anyone who can figure it out is welcome to provide a patch.
-
- core::vector3df edges[8];
- ShadowBBox[i].getEdges(edges);
-
- for(int j = 0; j < 8; ++j)
- {
- if (frust.planes[scene::SViewFrustum::VF_FAR_PLANE].classifyPointRelation(edges[j]) == core::ISREL3D_FRONT)
- {
- drawShadow = false;
- break;
- }
- }
- }
-
- if(drawShadow)
- driver->drawStencilShadowVolume(ShadowVolumes[i], UseZFailMethod, DebugDataVisible);
- else
- {
- // TODO: For some reason (not yet further investigated), Direct3D needs a call to drawStencilShadowVolume
- // even if we have nothing to draw here to set the renderstate into a StencilShadowMode.
- // If that's not done it has effect on further render calls.
- core::array<core::vector3df> triangles;
- driver->drawStencilShadowVolume(triangles, UseZFailMethod, DebugDataVisible);
- }
- }
-}
-
-
-//! returns the axis aligned bounding box of this node
-const core::aabbox3d<f32>& CShadowVolumeSceneNode::getBoundingBox() const
-{
- return Box;
-}
-
-
-//! Generates adjacency information based on mesh indices.
-void CShadowVolumeSceneNode::calculateAdjacency()
-{
- AdjacencyDirtyFlag = false;
-
- if ( Optimization == ESV_NONE )
- {
- Adjacency.clear();
- }
- else if ( Optimization == ESV_SILHOUETTE_BY_POS )
- {
- Adjacency.set_used(IndexCount);
-
- // go through all faces and fetch their three neighbours
- for (u32 f=0; f<IndexCount; f+=3)
- {
- for (u32 edge = 0; edge<3; ++edge)
- {
- const core::vector3df& v1 = Vertices[Indices[f+edge]];
- const core::vector3df& v2 = Vertices[Indices[f+((edge+1)%3)]];
-
- // now we search an_O_ther _F_ace with these two
- // vertices, which is not the current face.
- u32 of;
-
- for (of=0; of<IndexCount; of+=3)
- {
- // only other faces
- if (of != f)
- {
- bool cnt1 = false;
- bool cnt2 = false;
-
- for (s32 e=0; e<3; ++e)
- {
- if (v1.equals(Vertices[Indices[of+e]]))
- cnt1=true;
-
- if (v2.equals(Vertices[Indices[of+e]]))
- cnt2=true;
- }
- // one match for each vertex, i.e. edge is the same
- if (cnt1 && cnt2)
- break;
- }
- }
-
- // no adjacent edges -> store face number, else store adjacent face
- if (of >= IndexCount)
- Adjacency[f + edge] = f/3;
- else
- Adjacency[f + edge] = of/3;
- }
- }
- }
-}
-
-
-} // end namespace scene
-} // end namespace irr
-
-#endif // _IRR_COMPILE_WITH_SHADOW_VOLUME_SCENENODE_
|