Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/PlugIns/BSPSceneManager/src/OgreBspSceneManager.cpp @ 1

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