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

Revision 692, 36.9 KB checked in by mattausch, 18 years ago (diff)

adding ogre 1.2 and dependencies

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