source: OGRE/trunk/ogrenew/PlugIns/BSPSceneManager/src/OgreBspSceneManager.cpp @ 657

Revision 657, 33.6 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://ogre.sourceforge.net/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreBspSceneManager.h"
26#include "OgreBspResourceManager.h"
27#include "OgreBspNode.h"
28#include "OgreException.h"
29#include "OgreRenderSystem.h"
30#include "OgreCamera.h"
31#include "OgreMaterial.h"
32#include "OgrePatchSurface.h"
33#include "OgreMesh.h"
34#include "OgreSubMesh.h"
35#include "OgreMath.h"
36#include "OgreControllerManager.h"
37#include "OgreLogManager.h"
38#include "OgreBspSceneNode.h"
39#include "OgreStringConverter.h"
40#include "OgreLogManager.h"
41#include "OgreTechnique.h"
42#include "OgrePass.h"
43
44
45#include <fstream>
46
47namespace Ogre {
48
49    //-----------------------------------------------------------------------
50    BspSceneManager::BspSceneManager()
51    {
52        // Set features for debugging render
53        mShowNodeAABs = false;
54
55        // Instantiate BspResourceManager
56        // Will be managed by singleton
57        mBspResMgr = new BspResourceManager();
58
59        // No sky by default
60        mSkyPlaneEnabled = false;
61        mSkyBoxEnabled = false;
62        mSkyDomeEnabled = false;
63
64        mLevel.setNull();
65
66    }
67
68    //-----------------------------------------------------------------------
69    BspSceneManager::~BspSceneManager()
70    {
71        freeMemory();
72        mLevel.setNull();
73        delete mBspResMgr;
74    }
75    //-----------------------------------------------------------------------
76    size_t BspSceneManager::estimateWorldGeometry(const String& filename)
77    {
78        return BspLevel::calculateLoadingStages(filename);
79       
80    }
81    //-----------------------------------------------------------------------
82    void BspSceneManager::setWorldGeometry(const String& filename)
83    {
84        mLevel.setNull();
85        // Check extension is .bsp
86        char extension[6];
87        size_t pos = filename.find_last_of(".");
88                if( pos == String::npos )
89            OGRE_EXCEPT(
90                                Exception::ERR_INVALIDPARAMS,
91                "Unable to load world geometry. Invalid extension (must be .bsp).",
92                "BspSceneManager::setWorldGeometry");
93
94        strcpy(extension, filename.substr(pos + 1, filename.length() - pos).c_str());
95
96        if (stricmp(extension, "bsp"))
97            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
98                        "Unable to load world geometry. Invalid extension (must be .bsp).",
99            "BspSceneManager::setWorldGeometry");
100
101        // Load using resource manager
102        mLevel = BspResourceManager::getSingleton().load(filename,
103            ResourceGroupManager::getSingleton().getWorldResourceGroupName());
104
105        // Init static render operation
106        mRenderOp.vertexData = mLevel->mVertexData;
107        // index data is per-frame
108        mRenderOp.indexData = new IndexData();
109        mRenderOp.indexData->indexStart = 0;
110        mRenderOp.indexData->indexCount = 0;
111        // Create enough index space to render whole level
112        mRenderOp.indexData->indexBuffer = HardwareBufferManager::getSingleton()
113            .createIndexBuffer(
114                HardwareIndexBuffer::IT_32BIT, // always 32-bit
115                mLevel->mNumIndexes,
116                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, false);
117
118        mRenderOp.operationType = RenderOperation::OT_TRIANGLE_LIST;
119        mRenderOp.useIndexes = true;
120
121
122    }
123    //-----------------------------------------------------------------------
124    void BspSceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
125    {
126        // Clear unique list of movables for this frame
127        mMovablesForRendering.clear();
128        // Walk the tree, tag static geometry, return camera's node (for info only)
129        // Movables are now added to the render queue in processVisibleLeaf
130        BspNode* cameraNode = walkTree(cam, onlyShadowCasters);
131
132
133    }
134    //-----------------------------------------------------------------------
135    void BspSceneManager::renderStaticGeometry(void)
136    {
137                // Check we should be rendering
138                if (!isRenderQueueToBeProcessed(mWorldGeometryRenderQueue))
139                        return;
140
141        // Cache vertex/face data first
142        std::vector<StaticFaceGroup*>::const_iterator faceGrpi;
143        static RenderOperation patchOp;
144       
145        // no world transform required
146        mDestRenderSystem->_setWorldMatrix(Matrix4::IDENTITY);
147        // Set view / proj
148        mDestRenderSystem->_setViewMatrix(mCameraInProgress->getViewMatrix());
149        mDestRenderSystem->_setProjectionMatrix(mCameraInProgress->getProjectionMatrix());
150
151        // For each material in turn, cache rendering data & render
152        MaterialFaceGroupMap::const_iterator mati;
153
154        for (mati = mMatFaceGroupMap.begin(); mati != mMatFaceGroupMap.end(); ++mati)
155        {
156            // Get Material
157            Material* thisMaterial = mati->first;
158
159            // Empty existing cache
160            mRenderOp.indexData->indexCount = 0;
161            // lock index buffer ready to receive data
162            unsigned int* pIdx = static_cast<unsigned int*>(
163                mRenderOp.indexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
164
165            for (faceGrpi = mati->second.begin(); faceGrpi != mati->second.end(); ++faceGrpi)
166            {
167                // Cache each
168                unsigned int numelems = cacheGeometry(pIdx, *faceGrpi);
169                mRenderOp.indexData->indexCount += numelems;
170                pIdx += numelems;
171            }
172            // Unlock the buffer
173            mRenderOp.indexData->indexBuffer->unlock();
174
175            // Skip if no faces to process (we're not doing flare types yet)
176            if (mRenderOp.indexData->indexCount == 0)
177                continue;
178
179            Technique::PassIterator pit = thisMaterial->getTechnique(0)->getPassIterator();
180
181            while (pit.hasMoreElements())
182            {
183                setPass(pit.getNext());
184
185                mDestRenderSystem->_render(mRenderOp);
186
187
188            }
189
190
191        } // for each material
192
193        /*
194        if (mShowNodeAABs)
195        {
196            mDestRenderSystem->_render(mAABGeometry);
197        }
198        */
199    }
200    //-----------------------------------------------------------------------
201    void BspSceneManager::_renderVisibleObjects(void)
202    {
203        // Render static level geometry first
204        renderStaticGeometry();
205
206        // Call superclass to render the rest
207        SceneManager::_renderVisibleObjects();
208
209    }
210
211    //-----------------------------------------------------------------------
212    // REMOVE THIS CRAP
213    //-----------------------------------------------------------------------
214    // Temp debug lines
215    bool firstTime = true;
216    std::ofstream of;
217    //-----------------------------------------------------------------------
218    //-----------------------------------------------------------------------
219    //-----------------------------------------------------------------------
220    BspNode* BspSceneManager::walkTree(Camera* camera, bool onlyShadowCasters)
221    {
222                if (mLevel.isNull()) return 0;
223
224        // Locate the leaf node where the camera is located
225        BspNode* cameraNode = mLevel->findLeaf(camera->getDerivedPosition());
226
227        mMatFaceGroupMap.clear();
228        mFaceGroupSet.clear();
229
230        // Scan through all the other leaf nodes looking for visibles
231        int i = mLevel->mNumNodes - mLevel->mLeafStart;
232        BspNode* nd = mLevel->mRootNode + mLevel->mLeafStart;
233
234        /*
235        if (firstTime)
236        {
237            camera->getViewMatrix(); // Force update view before report
238            of.open("BspSceneManager.log");
239            of << *camera << std::endl;
240            of << "Camera Node: " << *cameraNode << std::endl;
241            of << "Vertex Data: " << std::endl;
242            for (int testi = 0; testi < mLevel->mNumVertices; ++testi)
243            {
244                of << " " << testi << ": pos(" <<
245                  mLevel->mVertices[testi].position[0] << ", " <<
246                    mLevel->mVertices[testi].position[1] << ", " << mLevel->mVertices[testi].position[2] << ")" <<
247                    " uv(" << mLevel->mVertices[testi].texcoords[0] << ", " << mLevel->mVertices[testi].texcoords[1] << ")" <<
248                    " lm(" << mLevel->mVertices[testi].lightmap[0] << ", " << mLevel->mVertices[testi].lightmap[1] << ")" << std::endl;
249            }
250            of << "Element data:" << std::endl;
251            for (testi = 0; testi < mLevel->mNumElements; ++testi)
252            {
253                of << " " << testi << ": " << mLevel->mElements[testi] << std::endl;
254
255            }
256        }
257        */
258
259        while (i--)
260        {
261            if (mLevel->isLeafVisible(cameraNode, nd))
262            {
263
264                // Visible according to PVS, check bounding box against frustum
265                FrustumPlane plane;
266                if (camera->isVisible(nd->getBoundingBox(), &plane))
267                {
268                    //if (firstTime)
269                    //{
270                    //    of << "Visible Node: " << *nd << std::endl;
271                    //}
272                    processVisibleLeaf(nd, camera, onlyShadowCasters);
273                    if (mShowNodeAABs)
274                        addBoundingBox(nd->getBoundingBox(), true);
275                }
276            }
277            nd++;
278        }
279
280
281        // TEST
282        //if (firstTime)
283        //{
284        //    of.close();
285        //    firstTime = false;
286        //}
287        return cameraNode;
288
289    }
290    //-----------------------------------------------------------------------
291    void BspSceneManager::processVisibleLeaf(BspNode* leaf, Camera* cam, bool onlyShadowCasters)
292    {
293        MaterialPtr pMat;
294        // Skip world geometry if we're only supposed to process shadow casters
295        // World is pre-lit
296        if (!onlyShadowCasters)
297        {
298            // Parse the leaf node's faces, add face groups to material map
299            int numGroups = leaf->getNumFaceGroups();
300            int idx = leaf->getFaceGroupStart();
301
302            while (numGroups--)
303            {
304                int realIndex = mLevel->mLeafFaceGroups[idx++];
305                // Check not already included
306                if (mFaceGroupSet.find(realIndex) != mFaceGroupSet.end())
307                    continue;
308                StaticFaceGroup* faceGroup = mLevel->mFaceGroups + realIndex;
309                // Get Material pointer by handle
310                pMat = MaterialManager::getSingleton().getByHandle(faceGroup->materialHandle);
311                assert (!pMat.isNull());
312                // Check normal (manual culling)
313                ManualCullingMode cullMode = pMat->getTechnique(0)->getPass(0)->getManualCullingMode();
314                if (cullMode != MANUAL_CULL_NONE)
315                {
316                    Real dist = faceGroup->plane.getDistance(cam->getDerivedPosition());
317                    if ( (dist < 0 && cullMode == MANUAL_CULL_BACK) ||
318                        (dist > 0 && cullMode == MANUAL_CULL_FRONT) )
319                        continue; // skip
320                }
321                mFaceGroupSet.insert(realIndex);
322                // Try to insert, will find existing if already there
323                std::pair<MaterialFaceGroupMap::iterator, bool> matgrpi;
324                matgrpi = mMatFaceGroupMap.insert(
325                    MaterialFaceGroupMap::value_type(pMat.getPointer(), std::vector<StaticFaceGroup*>())
326                    );
327                // Whatever happened, matgrpi.first is map iterator
328                // Need to get second part of that to get vector
329                matgrpi.first->second.push_back(faceGroup);
330
331                //if (firstTime)
332                //{
333                //    of << "  Emitting faceGroup: index=" << realIndex << ", " << *faceGroup << std::endl;
334                //}
335            }
336        }
337
338        // Add movables to render queue, provided it hasn't been seen already
339        const BspNode::IntersectingObjectSet& objects = leaf->getObjects();
340        BspNode::IntersectingObjectSet::const_iterator oi, oiend;
341        oiend = objects.end();
342        for (oi = objects.begin(); oi != oiend; ++oi)
343        {
344            if (mMovablesForRendering.find(*oi) == mMovablesForRendering.end())
345            {
346                // It hasn't been seen yet
347                MovableObject *mov = const_cast<MovableObject*>(*oi); // hacky
348                if (mov->isVisible() &&
349                    (!onlyShadowCasters || mov->getCastShadows()) &&
350                                        cam->isVisible(mov->getWorldBoundingBox()))
351                {
352                    mov->_notifyCurrentCamera(cam);
353                    mov->_updateRenderQueue(getRenderQueue());
354                    // Check if the bounding box should be shown.
355                    SceneNode* sn = static_cast<SceneNode*>(mov->getParentNode());
356                    if (sn->getShowBoundingBox() || mShowBoundingBoxes)
357                    {
358                        sn->_addBoundingBoxToQueue(getRenderQueue());
359                    }
360                    mMovablesForRendering.insert(*oi);
361                }
362
363            }
364        }
365
366
367    }
368    //-----------------------------------------------------------------------
369    unsigned int BspSceneManager::cacheGeometry(unsigned int* pIndexes,
370        const StaticFaceGroup* faceGroup)
371    {
372        // Skip sky always
373        if (faceGroup->isSky)
374            return 0;
375
376        size_t idxStart, numIdx, vertexStart;
377
378        if (faceGroup->fType == FGT_FACE_LIST)
379        {
380            idxStart = faceGroup->elementStart;
381            numIdx = faceGroup->numElements;
382            vertexStart = faceGroup->vertexStart;
383        }
384        else if (faceGroup->fType == FGT_PATCH)
385        {
386
387            idxStart = faceGroup->patchSurf->getIndexOffset();
388            numIdx = faceGroup->patchSurf->getCurrentIndexCount();
389            vertexStart = faceGroup->patchSurf->getVertexOffset();
390        }
391                else
392                {
393                        // Unsupported face type
394                        return 0;
395                }
396
397
398        // Copy index data
399        unsigned int* pSrc = static_cast<unsigned int*>(
400            mLevel->mIndexes->lock(
401                idxStart * sizeof(unsigned int),
402                numIdx * sizeof(unsigned int),
403                HardwareBuffer::HBL_READ_ONLY));
404        // Offset the indexes here
405        // we have to do this now rather than up-front because the
406        // indexes are sometimes reused to address different vertex chunks
407        for (size_t elem = 0; elem < numIdx; ++elem)
408        {
409            *pIndexes++ = *pSrc++ + vertexStart;
410        }
411        mLevel->mIndexes->unlock();
412
413        // return number of elements
414        return static_cast<unsigned int>(numIdx);
415
416
417    }
418
419    //-----------------------------------------------------------------------
420    void BspSceneManager::freeMemory(void)
421    {
422        // no need to delete index buffer, will be handled by shared pointer
423        delete mRenderOp.indexData;
424                mRenderOp.indexData = 0;
425    }
426    //-----------------------------------------------------------------------
427    void BspSceneManager::showNodeBoxes(bool show)
428    {
429        mShowNodeAABs = show;
430    }
431    //-----------------------------------------------------------------------
432    void BspSceneManager::addBoundingBox(const AxisAlignedBox& aab, bool visible)
433    {
434        /*
435        unsigned long visibleColour;
436        unsigned long nonVisibleColour;
437        Root& r = Root::getSingleton();
438
439        r.convertColourValue(ColourValue::White, &visibleColour);
440        r.convertColourValue(ColourValue::Blue, &nonVisibleColour);
441        if (mShowNodeAABs)
442        {
443            // Add set of lines
444            float* pVertices = (float*)mAABGeometry.pVertices + (mAABGeometry.numVertices*3);
445            unsigned short* pIndexes = mAABGeometry.pIndexes + mAABGeometry.numIndexes;
446            unsigned long* pColours = (unsigned long*)mAABGeometry.pDiffuseColour + mAABGeometry.numVertices;
447
448            const Vector3* pCorner = aab.getAllCorners();
449
450            int i;
451            for (i = 0; i < 8; ++i)
452            {
453                *pVertices++ = pCorner->x;
454                *pVertices++ = pCorner->y;
455                *pVertices++ = pCorner->z;
456                pCorner++;
457
458                if (visible)
459                {
460                    *pColours++ = visibleColour;
461                }
462                else
463                {
464                    *pColours++ = nonVisibleColour;
465                }
466
467            }
468
469            *pIndexes++ = 0 + mAABGeometry.numVertices;
470            *pIndexes++ = 1 + mAABGeometry.numVertices;
471            *pIndexes++ = 1 + mAABGeometry.numVertices;
472            *pIndexes++ = 2 + mAABGeometry.numVertices;
473            *pIndexes++ = 2 + mAABGeometry.numVertices;
474            *pIndexes++ = 3 + mAABGeometry.numVertices;
475            *pIndexes++ = 3 + mAABGeometry.numVertices;
476            *pIndexes++ = 1 + mAABGeometry.numVertices;
477            *pIndexes++ = 4 + mAABGeometry.numVertices;
478            *pIndexes++ = 5 + mAABGeometry.numVertices;
479            *pIndexes++ = 5 + mAABGeometry.numVertices;
480            *pIndexes++ = 6 + mAABGeometry.numVertices;
481            *pIndexes++ = 6 + mAABGeometry.numVertices;
482            *pIndexes++ = 7 + mAABGeometry.numVertices;
483            *pIndexes++ = 7 + mAABGeometry.numVertices;
484            *pIndexes++ = 4 + mAABGeometry.numVertices;
485            *pIndexes++ = 1 + mAABGeometry.numVertices;
486            *pIndexes++ = 5 + mAABGeometry.numVertices;
487            *pIndexes++ = 2 + mAABGeometry.numVertices;
488            *pIndexes++ = 4 + mAABGeometry.numVertices;
489            *pIndexes++ = 0 + mAABGeometry.numVertices;
490            *pIndexes++ = 6 + mAABGeometry.numVertices;
491            *pIndexes++ = 3 + mAABGeometry.numVertices;
492            *pIndexes++ = 7 + mAABGeometry.numVertices;
493
494
495            mAABGeometry.numVertices += 8;
496            mAABGeometry.numIndexes += 24;
497
498
499        }
500        */
501
502    }
503    //-----------------------------------------------------------------------
504    ViewPoint BspSceneManager::getSuggestedViewpoint(bool random)
505    {
506        if (mLevel.isNull() || mLevel->mPlayerStarts.size() == 0)
507        {
508            // No level, use default
509            return SceneManager::getSuggestedViewpoint(random);
510        }
511        else
512        {
513            if (random)
514            {
515                size_t idx = (size_t)( Math::UnitRandom() * mLevel->mPlayerStarts.size() );
516                return mLevel->mPlayerStarts[idx];
517            }
518            else
519            {
520                return mLevel->mPlayerStarts[0];
521            }
522
523
524        }
525
526    }
527    //-----------------------------------------------------------------------
528    SceneNode * BspSceneManager::createSceneNode( void )
529    {
530        BspSceneNode * sn = new BspSceneNode( this );
531        mSceneNodes[ sn->getName() ] = sn;
532        return sn;
533    }
534    //-----------------------------------------------------------------------
535    SceneNode * BspSceneManager::createSceneNode( const String &name )
536    {
537        BspSceneNode * sn = new BspSceneNode( this, name );
538        mSceneNodes[ sn->getName() ] = sn;
539        return sn;
540    }
541    //-----------------------------------------------------------------------
542    void BspSceneManager::_notifyObjectMoved(const MovableObject* mov,
543        const Vector3& pos)
544    {
545                if (!mLevel.isNull())
546                {
547                        mLevel->_notifyObjectMoved(mov, pos);
548                }
549    }
550    //-----------------------------------------------------------------------
551        void BspSceneManager::_notifyObjectDetached(const MovableObject* mov)
552        {
553                if (!mLevel.isNull())
554                {
555                        mLevel->_notifyObjectDetached(mov);
556                }
557        }
558        //-----------------------------------------------------------------------
559        void BspSceneManager::clearScene(void)
560        {
561                SceneManager::clearScene();
562                freeMemory();
563                // Clear level
564                mLevel.setNull();
565        }
566    //-----------------------------------------------------------------------
567    /*
568    AxisAlignedBoxSceneQuery* BspSceneManager::
569    createAABBQuery(const AxisAlignedBox& box, unsigned long mask)
570    {
571        // TODO
572        return NULL;
573    }
574    //-----------------------------------------------------------------------
575    SphereSceneQuery* BspSceneManager::
576    createSphereQuery(const Sphere& sphere, unsigned long mask)
577    {
578        // TODO
579        return NULL;
580    }
581    */
582    //-----------------------------------------------------------------------
583    RaySceneQuery* BspSceneManager::
584    createRayQuery(const Ray& ray, unsigned long mask)
585    {
586        BspRaySceneQuery* q = new BspRaySceneQuery(this);
587        q->setRay(ray);
588        q->setQueryMask(mask);
589        return q;
590    }
591    //-----------------------------------------------------------------------
592    IntersectionSceneQuery* BspSceneManager::
593    createIntersectionQuery(unsigned long mask)
594    {
595        BspIntersectionSceneQuery* q = new BspIntersectionSceneQuery(this);
596        q->setQueryMask(mask);
597        return q;
598    }
599    //-----------------------------------------------------------------------
600    //-----------------------------------------------------------------------
601    BspIntersectionSceneQuery::BspIntersectionSceneQuery(SceneManager* creator)
602        : DefaultIntersectionSceneQuery(creator)
603    {
604        // Add bounds fragment type
605        mSupportedWorldFragments.insert(SceneQuery::WFT_PLANE_BOUNDED_REGION);
606       
607    }
608    void BspIntersectionSceneQuery::execute(IntersectionSceneQueryListener* listener)
609    {
610        /*
611        Go through each leaf node in BspLevel and check movables against each other and world
612        Issue: some movable-movable intersections could be reported twice if 2 movables
613        overlap 2 leaves?
614        */
615        const BspLevelPtr& lvl = ((BspSceneManager*)mParentSceneMgr)->getLevel();
616                if (lvl.isNull()) return;
617
618        BspNode* leaf = lvl->getLeafStart();
619        int numLeaves = lvl->getNumLeaves();
620       
621        while (numLeaves--)
622        {
623            const BspNode::IntersectingObjectSet& objects = leaf->getObjects();
624            int numObjects = (int)objects.size();
625
626            BspNode::IntersectingObjectSet::const_iterator a, b, theEnd;
627            theEnd = objects.end();
628            a = objects.begin();
629            for (int oi = 0; oi < numObjects; ++oi, ++a)
630            {
631                const MovableObject* aObj = *a;
632                // Skip this object if collision not enabled
633                if (!(aObj->getQueryFlags() & mQueryMask) ||
634                                        !aObj->isInScene())
635                    continue;
636
637                if (oi < (numObjects-1))
638                {
639                    // Check object against others in this node
640                    b = a;
641                    for (++b; b != theEnd; ++b)
642                    {
643                        const MovableObject* bObj = *b;
644                        // Apply mask to b (both must pass)
645                        if ((bObj->getQueryFlags() & mQueryMask) &&
646                                                        bObj->isInScene())
647                        {
648                            const AxisAlignedBox& box1 = aObj->getWorldBoundingBox();
649                            const AxisAlignedBox& box2 = bObj->getWorldBoundingBox();
650
651                            if (box1.intersects(box2))
652                            {
653                                if (!listener->queryResult(const_cast<MovableObject*>(aObj),
654                                    const_cast<MovableObject*>(bObj)))
655                                                                        return;
656                            }
657                        }
658                    }
659                }
660                // Check object against brushes
661                if (mQueryMask & SceneManager::WORLD_GEOMETRY_QUERY_MASK)
662                {
663                    const BspNode::NodeBrushList& brushes = leaf->getSolidBrushes();
664                    BspNode::NodeBrushList::const_iterator bi, biend;
665                    biend = brushes.end();
666                    Real radius = aObj->getBoundingRadius();
667                    const Vector3& pos = aObj->getParentNode()->_getDerivedPosition();
668
669                    for (bi = brushes.begin(); bi != biend; ++bi)
670                    {
671                        std::list<Plane>::const_iterator planeit, planeitend;
672                        planeitend = (*bi)->planes.end();
673                        bool brushIntersect = true; // Assume intersecting for now
674
675                        for (planeit = (*bi)->planes.begin(); planeit != planeitend; ++planeit)
676                        {
677                            Real dist = planeit->getDistance(pos);
678                            if (dist > radius)
679                            {
680                                // Definitely excluded
681                                brushIntersect = false;
682                                break;
683                            }
684                        }
685                        if (brushIntersect)
686                        {
687                            // report this brush as it's WorldFragment
688                            assert((*bi)->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION);
689                            if (!listener->queryResult(const_cast<MovableObject*>(aObj),
690                                    const_cast<WorldFragment*>(&((*bi)->fragment))))
691                                                                return;
692                        }
693
694                    }
695                }
696
697
698            }
699
700            ++leaf;
701        }
702
703
704
705    }
706    //-----------------------------------------------------------------------
707    //-----------------------------------------------------------------------
708    BspRaySceneQuery::BspRaySceneQuery(SceneManager* creator)
709        :DefaultRaySceneQuery(creator)
710    {
711        // Add supported fragment types
712        mSupportedWorldFragments.insert(SceneQuery::WFT_SINGLE_INTERSECTION);
713        mSupportedWorldFragments.insert(SceneQuery::WFT_PLANE_BOUNDED_REGION);
714    }
715    //-----------------------------------------------------------------------
716    void BspRaySceneQuery::execute(RaySceneQueryListener* listener)
717    {
718        clearTemporaries();
719                BspLevelPtr lvl = static_cast<BspSceneManager*>(mParentSceneMgr)->getLevel();
720                if (!lvl.isNull())
721                {
722                        processNode(
723                                lvl->getRootNode(),
724                                mRay, listener);
725                }
726    }
727    //-----------------------------------------------------------------------
728    BspRaySceneQuery::~BspRaySceneQuery()
729    {
730        clearTemporaries();
731    }
732    //-----------------------------------------------------------------------
733    void BspRaySceneQuery::clearTemporaries(void)
734    {
735        mObjsThisQuery.clear();
736        std::vector<WorldFragment*>::iterator i;
737        for (i = mSingleIntersections.begin(); i != mSingleIntersections.end(); ++i)
738        {
739            delete *i;
740        }
741        mSingleIntersections.clear();
742    }
743    //-----------------------------------------------------------------------
744    bool BspRaySceneQuery::processNode(const BspNode* node, const Ray& tracingRay,
745        RaySceneQueryListener* listener, Real maxDistance, Real traceDistance)
746    {
747        if (node->isLeaf())
748        {
749            return processLeaf(node, tracingRay, listener, maxDistance, traceDistance);
750        }
751
752        bool res = true;
753        std::pair<bool, Real> result = tracingRay.intersects(node->getSplitPlane());
754        if (result.first && result.second < maxDistance)
755        {
756            // Crosses the split plane, need to perform 2 queries
757            // Calculate split point ray
758            Vector3 splitPoint = tracingRay.getOrigin()
759                + tracingRay.getDirection() * result.second;
760            Ray splitRay(splitPoint, tracingRay.getDirection());
761
762            if (node->getSide(tracingRay.getOrigin()) == Plane::NEGATIVE_SIDE)
763            {
764                // Intersects from -ve side, so do back then front
765                res = processNode(
766                    node->getBack(), tracingRay, listener, result.second, traceDistance);
767                if (!res) return res;
768               
769                res = processNode(
770                    node->getFront(), splitRay, listener,
771                    maxDistance - result.second,
772                    traceDistance + result.second);
773            }
774            else
775            {
776                // Intersects from +ve side, so do front then back
777                res = processNode(node->getFront(), tracingRay, listener,
778                    result.second, traceDistance);
779                if (!res) return res;
780                res = processNode(node->getBack(), splitRay, listener,
781                    maxDistance - result.second,
782                    traceDistance + result.second);
783            }
784        }
785        else
786        {
787            // Does not cross the splitting plane, just cascade down one side
788            res = processNode(node->getNextNode(tracingRay.getOrigin()),
789                tracingRay, listener, maxDistance, traceDistance);
790        }
791
792        return res;
793    }
794    //-----------------------------------------------------------------------
795    bool BspRaySceneQuery::processLeaf(const BspNode* leaf, const Ray& tracingRay,
796        RaySceneQueryListener* listener, Real maxDistance, Real traceDistance)
797    {
798        const BspNode::IntersectingObjectSet& objects = leaf->getObjects();
799
800        BspNode::IntersectingObjectSet::const_iterator i, iend;
801        iend = objects.end();
802        //Check ray against objects
803        for(i = objects.begin(); i != iend; ++i)
804        {
805            // cast away constness, constness of node is nothing to do with objects
806            MovableObject* obj = const_cast<MovableObject*>(*i);
807            // Skip this object if not enabled
808            if((obj->getQueryFlags() & mQueryMask) == 0)
809                continue;
810
811            // check we haven't reported this one already
812            // (objects can be intersecting more than one node)
813            if (mObjsThisQuery.find(obj) != mObjsThisQuery.end())
814                continue;
815
816            //Test object as bounding box
817            std::pair<bool, Real> result =
818                tracingRay.intersects(obj->getWorldBoundingBox());
819            // if the result came back positive and intersection point is inside
820            // the node, fire the event handler
821            if(result.first && result.second <= maxDistance)
822            {
823                if (!listener->queryResult(obj, result.second + traceDistance))
824                                        return false;
825            }
826        }
827
828
829        // Check ray against brushes
830        if (mQueryMask & SceneManager::WORLD_GEOMETRY_QUERY_MASK)
831        {
832            const BspNode::NodeBrushList& brushList = leaf->getSolidBrushes();
833            BspNode::NodeBrushList::const_iterator bi, biend;
834            biend = brushList.end();
835            bool intersectedBrush = false;
836            for (bi = brushList.begin(); bi != biend; ++bi)
837            {
838                BspNode::Brush* brush = *bi;
839               
840
841                std::pair<bool, Real> result = Math::intersects(tracingRay, brush->planes, true);
842                // if the result came back positive and intersection point is inside
843                // the node, check if this brush is closer
844                if(result.first && result.second <= maxDistance)
845                {
846                    intersectedBrush = true;
847                    if(mWorldFragmentType == SceneQuery::WFT_SINGLE_INTERSECTION)
848                    {
849                        // We're interested in a single intersection
850                        // Have to create these
851                        SceneQuery::WorldFragment* wf = new SceneQuery::WorldFragment();
852                        wf->fragmentType = SceneQuery::WFT_SINGLE_INTERSECTION;
853                        wf->singleIntersection = tracingRay.getPoint(result.second);
854                        // save this so we can clean up later
855                        mSingleIntersections.push_back(wf);
856                        if (!listener->queryResult(wf, result.second + traceDistance))
857                                                        return false;
858                    }
859                    else if (mWorldFragmentType ==  SceneQuery::WFT_PLANE_BOUNDED_REGION)
860                    {
861                        // We want the whole bounded volume
862                        assert((*bi)->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION);
863                        if (!listener->queryResult(const_cast<WorldFragment*>(&(brush->fragment)),
864                            result.second + traceDistance))
865                                                        return false;
866
867                    }
868                }
869            }
870            if (intersectedBrush)
871            {
872                return false; // stop here
873            }
874        }
875
876        return true;
877
878    }
879    //-----------------------------------------------------------------------
880}
881
Note: See TracBrowser for help on using the repository browser.