Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/PlugIns/BSPSceneManager/src/OgreBspLevel.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

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 "OgreBspLevel.h"
30#include "OgreBspResourceManager.h"
31#include "OgreException.h"
32#include "OgreMaterial.h"
33#include "OgreMaterialManager.h"
34#include "OgreMovableObject.h"
35#include "OgreSceneManager.h"
36#include "OgrePatchSurface.h"
37#include "OgreQuake3ShaderManager.h"
38#include "OgreQuake3Shader.h"
39#include "OgreMath.h"
40#include "OgreStringVector.h"
41#include "OgreStringConverter.h"
42#include "OgreLogManager.h"
43#include "OgreSceneManagerEnumerator.h"
44#include "OgreTechnique.h"
45#include "OgrePass.h"
46#include "OgreTextureUnitState.h"
47#include "OgreResourceGroupManager.h"
48
49namespace Ogre {
50
51    #define NUM_FACES_PER_PROGRESS_REPORT 100
52    #define NUM_NODES_PER_PROGRESS_REPORT 50
53    #define NUM_LEAVES_PER_PROGRESS_REPORT 50
54    #define NUM_BRUSHES_PER_PROGRESS_REPORT 50
55
56    //-----------------------------------------------------------------------
57    BspLevel::BspLevel(ResourceManager* creator, const String& name, 
58        ResourceHandle handle, const String& group, bool isManual, 
59        ManualResourceLoader* loader)
60      : Resource(creator, name, handle, group, isManual, loader), 
61        mRootNode(0), 
62        mVertexData(0), 
63        mLeafFaceGroups(0),
64        mFaceGroups(0), 
65        mBrushes(0),
66                mSkyEnabled(false)
67    {
68        mVisData.tableData = 0;
69
70        if (createParamDictionary("BspLevel"))
71        {
72            // nothing
73        }
74    }
75
76    //-----------------------------------------------------------------------
77    BspLevel::~BspLevel()
78    {
79        // have to call this here reather than in Resource destructor
80        // since calling virtual methods in base destructors causes crash
81        unload(); 
82
83    }
84
85    //-----------------------------------------------------------------------
86    void BspLevel::loadImpl()
87    {
88                mSkyEnabled = false;
89
90        // Use Quake3 file loader
91        Quake3Level q3;
92        DataStreamPtr stream = 
93                        ResourceGroupManager::getSingleton().openResource(mName, 
94                                ResourceGroupManager::getSingleton().getWorldResourceGroupName());
95
96        q3.loadFromStream(stream);
97
98        loadQuake3Level(q3);
99
100    }
101        //-----------------------------------------------------------------------
102        bool BspLevel::isSkyEnabled(void) const
103        {
104                return mSkyEnabled;
105        }
106        //-----------------------------------------------------------------------
107        const String& BspLevel::getSkyMaterialName(void) const
108        {
109                return mSkyMaterial;
110        }
111        //-----------------------------------------------------------------------
112        Real BspLevel::getSkyCurvature(void) const
113        {
114                return mSkyCurvature;
115        }
116    //-----------------------------------------------------------------------
117    void BspLevel::load(DataStreamPtr& stream)
118    {
119        // Use Quake3 file loader
120        Quake3Level q3;
121        q3.loadFromStream(stream);
122
123        loadQuake3Level(q3);
124
125    }
126    //-----------------------------------------------------------------------
127    void BspLevel::unloadImpl()
128    {
129        if (mVertexData)
130            delete mVertexData;
131        mIndexes.setNull();
132        if (mFaceGroups)
133            delete [] mFaceGroups;
134        if (mLeafFaceGroups)
135            delete [] mLeafFaceGroups;
136        if (mRootNode)
137            delete [] mRootNode;
138        if (mVisData.tableData)
139            delete [] mVisData.tableData;
140        if (mBrushes)
141            delete [] mBrushes;
142
143        mVertexData = 0;
144        mRootNode = 0;
145        mFaceGroups = 0;
146        mLeafFaceGroups = 0;
147        mBrushes = 0;
148        mVisData.tableData = 0;
149        for (PatchMap::iterator pi = mPatches.begin(); pi != mPatches.end(); ++pi)
150        {
151            delete pi->second;
152        }
153        mPatches.clear();
154    }
155    //-----------------------------------------------------------------------
156    size_t BspLevel::calculateLoadingStages(const String& levelName)
157    {
158        DataStreamPtr stream = 
159            ResourceGroupManager::getSingleton().openResource(levelName, 
160            ResourceGroupManager::getSingleton().getWorldResourceGroupName());
161                return calculateLoadingStages(stream);
162        }
163    //-----------------------------------------------------------------------
164    size_t BspLevel::calculateLoadingStages(DataStreamPtr& stream)
165    {
166        Quake3Level q3;
167
168        // Load header only
169        q3.loadHeaderFromStream(stream);
170
171        // Ok, count up the things that we will report
172        size_t stages = 0;
173
174        // loadEntities (1 stage)
175        ++stages;
176        // extractLightmaps (external, 1 stage)
177        ++stages;
178        // initQuake3Patches
179        ++stages;
180        // vertex setup
181        ++stages;
182        // face setup
183        ++stages;
184        // patch building
185        ++stages;
186        // material setup
187        // this is not strictly based on load, since we only know the number
188        // of faces, not the number of materials
189        // raise one event for every 50 faces, plus one at the end
190        stages += (q3.mNumFaces / NUM_FACES_PER_PROGRESS_REPORT) + 1;
191        // node setup
192        stages += (q3.mNumNodes / NUM_NODES_PER_PROGRESS_REPORT) + 1;
193        // brush setup
194        stages += (q3.mNumBrushes / NUM_BRUSHES_PER_PROGRESS_REPORT) + 1;
195        // leaf setup
196        stages += (q3.mNumLeaves / NUM_LEAVES_PER_PROGRESS_REPORT) + 1;
197        // vis
198        ++stages;
199
200        return stages;
201
202    }
203    //-----------------------------------------------------------------------
204    void BspLevel::loadQuake3Level(const Quake3Level& q3lvl)
205    {
206        MaterialManager& mm = MaterialManager::getSingleton();
207        ResourceGroupManager& rgm = ResourceGroupManager::getSingleton();
208
209        rgm._notifyWorldGeometryStageStarted("Parsing entities");
210        loadEntities(q3lvl);
211        rgm._notifyWorldGeometryStageEnded();
212
213        // Extract lightmaps into textures
214        rgm._notifyWorldGeometryStageStarted("Extracting lightmaps");
215        q3lvl.extractLightmaps();
216        rgm._notifyWorldGeometryStageEnded();
217
218        //-----------------------------------------------------------------------
219        // Vertices
220        //-----------------------------------------------------------------------
221        // Allocate memory for vertices & copy
222        mVertexData = new VertexData();
223
224        /// Create vertex declaration
225        VertexDeclaration* decl = mVertexData->vertexDeclaration;
226        size_t offset = 0;
227        decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
228        offset += VertexElement::getTypeSize(VET_FLOAT3);
229        decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
230        offset += VertexElement::getTypeSize(VET_FLOAT3);
231        decl->addElement(0, offset, VET_COLOUR, VES_DIFFUSE);
232        offset += VertexElement::getTypeSize(VET_COLOUR);
233        decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
234        offset += VertexElement::getTypeSize(VET_FLOAT2);
235        decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
236
237        // Build initial patches - we need to know how big the vertex buffer needs to be
238        // to accommodate the subdivision
239        rgm._notifyWorldGeometryStageStarted("Initialising patches");
240        initQuake3Patches(q3lvl, decl);
241        rgm._notifyWorldGeometryStageEnded();
242
243        /// Create the vertex buffer, allow space for patches
244        rgm._notifyWorldGeometryStageStarted("Setting up vertex data");
245        HardwareVertexBufferSharedPtr vbuf = HardwareBufferManager::getSingleton()
246            .createVertexBuffer(
247                sizeof(BspVertex), 
248                q3lvl.mNumVertices + mPatchVertexCount, 
249                HardwareBuffer::HBU_STATIC_WRITE_ONLY);
250        //COPY static vertex data - Note that we can't just block-copy the vertex data because we have to reorder
251        //    our vertex elements; this is to ensure compatibility with older cards when using
252        //    hardware vertex buffers - Direct3D requires that the buffer format maps onto a
253        //    FVF in those older drivers.
254        // Lock just the non-patch area for now
255        BspVertex* pVert = static_cast<BspVertex*>(
256            vbuf->lock(0, q3lvl.mNumVertices * sizeof(BspVertex), HardwareBuffer::HBL_DISCARD) );
257        // Keep another base pointer for use later in patch building
258        for (int v = 0; v < q3lvl.mNumVertices; ++v)
259        {
260            quakeVertexToBspVertex(&q3lvl.mVertices[v], pVert++);
261        }
262        vbuf->unlock();
263        // Setup binding
264        mVertexData->vertexBufferBinding->setBinding(0, vbuf);
265        // Set other data
266        mVertexData->vertexStart = 0;
267        mVertexData->vertexCount = q3lvl.mNumVertices + mPatchVertexCount;
268        rgm._notifyWorldGeometryStageEnded();
269
270        //-----------------------------------------------------------------------
271        // Faces
272        // --------
273        rgm._notifyWorldGeometryStageStarted("Setting up face data");
274        mNumLeafFaceGroups = q3lvl.mNumLeafFaces;
275        mLeafFaceGroups = new int[mNumLeafFaceGroups];
276        memcpy(mLeafFaceGroups, q3lvl.mLeafFaces, sizeof(int)*mNumLeafFaceGroups);
277        mNumFaceGroups = q3lvl.mNumFaces;
278        mFaceGroups = new StaticFaceGroup[mNumFaceGroups];
279        // Set up index buffer
280        // NB Quake3 indexes are 32-bit
281        // Copy the indexes into a software area for staging
282        mNumIndexes = q3lvl.mNumElements + mPatchIndexCount;
283        // Create an index buffer manually in system memory, allow space for patches
284        mIndexes.bind(new DefaultHardwareIndexBuffer(
285            HardwareIndexBuffer::IT_32BIT, 
286            mNumIndexes, 
287            HardwareBuffer::HBU_DYNAMIC));
288        // Write main indexes
289        mIndexes->writeData(0, sizeof(unsigned int) * q3lvl.mNumElements, q3lvl.mElements, true);
290        rgm._notifyWorldGeometryStageEnded();
291
292        // now build patch information
293        rgm._notifyWorldGeometryStageStarted("Building patches");
294        buildQuake3Patches(q3lvl.mNumVertices, q3lvl.mNumElements);
295        rgm._notifyWorldGeometryStageEnded();
296
297        //-----------------------------------------------------------------------
298        // Create materials for shaders
299        //-----------------------------------------------------------------------
300        // NB this only works for the 'default' shaders for now
301        //  i.e. those that don't have a .shader script and thus default
302        //  to just texture + lightmap
303        // TODO: pre-parse all .shader files and create lookup for next stage (use ROGL shader_file_t)
304
305        // Material names are shadername#lightmapnumber
306        // This is because I like to define materials up front completely
307        //  rather than combine lightmap and shader dynamically (it's
308        //  more generic). It results in more materials, but they're small
309        //  beer anyway. Texture duplication is prevented by infrastructure.
310        // To do this I actually need to parse the faces since they have the
311        //  shader/lightmap combo (lightmap number is not in the shader since
312        //  it can be used with multiple lightmaps)
313        String shaderName;
314        int face;
315        face = q3lvl.mNumFaces;
316        int matHandle;
317        String meshName;
318
319        String resourceGroup = ResourceGroupManager::getSingleton().getWorldResourceGroupName();
320        size_t progressCountdown = NUM_FACES_PER_PROGRESS_REPORT;
321        size_t progressCount = 0;
322
323        while(face--)
324        {
325            // Progress reporting
326            if (progressCountdown == NUM_FACES_PER_PROGRESS_REPORT)
327            {
328                ++progressCount;
329                StringUtil::StrStreamType str;
330                str << "Loading materials (phase " << progressCount << ")"; 
331                rgm._notifyWorldGeometryStageStarted(str.str());
332            }
333            else if (progressCountdown == 0)
334            {
335                // stage report
336                rgm._notifyWorldGeometryStageEnded();
337                progressCountdown = NUM_FACES_PER_PROGRESS_REPORT + 1; 
338
339            }
340
341            // Check to see if existing material
342            // Format shader#lightmap
343            int shadIdx = q3lvl.mFaces[face].shader;
344                        StringUtil::StrStreamType tmp;
345                        tmp << q3lvl.mShaders[shadIdx].name << "#" << q3lvl.mFaces[face].lm_texture;
346                        shaderName = tmp.str();
347
348            MaterialPtr shadMat = MaterialManager::getSingleton().getByName(shaderName);
349            if (shadMat.isNull())
350            {
351                // Build new material
352
353                // Colour layer
354                // NB no extension in Q3A(doh), have to try shader, .jpg, .tga
355                String tryName = q3lvl.mShaders[shadIdx].name;
356                // Try shader first
357                Quake3Shader* pShad = Quake3ShaderManager::getSingleton().getByName(tryName);
358                if (pShad)
359                {
360                    shadMat = pShad->createAsMaterial(q3lvl.mFaces[face].lm_texture);
361                                        // Do skydome (use this material)
362                                        if (pShad->skyDome)
363                                        {
364                                                mSkyEnabled = true;
365                                                mSkyMaterial = shadMat->getName();
366                                                mSkyCurvature = 20 - (pShad->cloudHeight / 256 * 18);
367                                        }
368                }
369                else
370                {
371                    // No shader script, try default type texture
372                    shadMat = mm.create(shaderName, resourceGroup);
373                    Pass *shadPass = shadMat->getTechnique(0)->getPass(0);
374                    // Try jpg
375                    TextureUnitState* tex = 0;
376                    if (ResourceGroupManager::getSingleton().resourceExists(resourceGroup, tryName + ".jpg"))
377                    {
378                        tex = shadPass->createTextureUnitState(tryName + ".jpg");
379                    }
380                    else if (ResourceGroupManager::getSingleton().resourceExists(resourceGroup, tryName + ".tga"))
381                    {
382                        tex = shadPass->createTextureUnitState(tryName + ".tga");
383                    }
384
385                    if (tex)
386                    {
387                        // Set replace on all first layer textures for now
388                        tex->setColourOperation(LBO_REPLACE);
389                        tex->setTextureAddressingMode(TextureUnitState::TAM_WRAP);
390                    }
391
392                    if (q3lvl.mFaces[face].lm_texture >= 0)
393                    {
394                        // Add lightmap, additive blending
395                                                StringUtil::StrStreamType lightmapName;
396                        lightmapName << "@lightmap" << q3lvl.mFaces[face].lm_texture;
397                        tex = shadPass->createTextureUnitState(lightmapName.str());
398                        // Blend
399                        tex->setColourOperation(LBO_MODULATE);
400                        // Use 2nd texture co-ordinate set
401                        tex->setTextureCoordSet(1);
402                        // Clamp
403                        tex->setTextureAddressingMode(TextureUnitState::TAM_CLAMP);
404
405                    }
406                    // Set culling mode to none
407                    shadMat->setCullingMode(CULL_NONE);
408                    // No dynamic lighting
409                    shadMat->setLightingEnabled(false);
410
411                }
412            }
413            matHandle = shadMat->getHandle();
414            shadMat->load();
415
416            // Copy face data
417            StaticFaceGroup* dest = &mFaceGroups[face];
418            bsp_face_t* src = &q3lvl.mFaces[face];
419
420            if (q3lvl.mShaders[src->shader].surface_flags & SURF_SKY)
421            {
422                dest->isSky = true;
423            }
424            else
425            {
426                dest->isSky = false;
427            }
428
429
430            dest->materialHandle = matHandle;
431            dest->elementStart = src->elem_start;
432            dest->numElements = src->elem_count;
433            dest->numVertices = src->vert_count;
434            dest->vertexStart = src->vert_start;
435            if (src->type == BSP_FACETYPE_NORMAL)
436            {
437                dest->fType = FGT_FACE_LIST;
438                // Assign plane
439                dest->plane.normal = Vector3(src->normal[0], src->normal[1], src->normal[2]);
440                dest->plane.d = -dest->plane.normal.dotProduct(
441                                        Vector3(src->org[0], src->org[1], src->org[2]));
442
443                // Don't rebase indexes here - Quake3 re-uses some indexes for multiple vertex
444                // groups eg repeating small details have the same relative vertex data but
445                // use the same index data.
446
447            }
448            else if (src->type == BSP_FACETYPE_PATCH)
449            {
450                // Seems to be some crap in the Q3 level where vertex count = 0 or num control points = 0?
451                if (dest->numVertices == 0 || src->mesh_cp[0] == 0)
452                {
453                    dest->fType = FGT_UNKNOWN;
454                }
455                else
456                {
457
458                    // Set up patch surface
459                    dest->fType = FGT_PATCH;
460                   
461                    // Locate the patch we already built
462                    PatchMap::iterator p = mPatches.find(face);
463                    if (p == mPatches.end())
464                    {
465                        OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Patch not found from previous built state",
466                        "BspLevel::loadQuake3Level");
467                    }
468
469                    dest->patchSurf = p->second;
470                   
471                }
472
473
474            }
475                        else if (src->type == BSP_FACETYPE_MESH)
476                        {
477                                dest->fType = FGT_FACE_LIST;
478                                // Assign plane
479                                dest->plane.normal = Vector3(src->normal[0], src->normal[1], src->normal[2]);
480                                dest->plane.d = -dest->plane.normal.dotProduct(
481                                        Vector3(src->org[0], src->org[1], src->org[2]));               
482                        }
483                        else
484                        {
485                                LogManager::getSingleton().logMessage("!!! Unknown Face Type !!!", LML_CRITICAL);
486                        }
487
488            // progress reporting
489            --progressCountdown;
490
491        }
492        // final stage report
493        rgm._notifyWorldGeometryStageEnded();
494
495        //-----------------------------------------------------------------------
496        // Nodes
497        //-----------------------------------------------------------------------
498        // Allocate memory for all nodes (leaves and splitters)
499        mNumNodes = q3lvl.mNumNodes + q3lvl.mNumLeaves;
500        mNumLeaves = q3lvl.mNumLeaves;
501        mLeafStart = q3lvl.mNumNodes;
502        mRootNode = new BspNode[mNumNodes];
503        int i;
504        // Convert nodes
505        // In our array, first q3lvl.mNumNodes are non-leaf, others are leaves
506        progressCountdown = NUM_NODES_PER_PROGRESS_REPORT;
507        progressCount = 0;
508
509        for (i = 0; i < q3lvl.mNumNodes; ++i)
510        {
511            // Progress reporting
512            if (progressCountdown == NUM_NODES_PER_PROGRESS_REPORT)
513            {
514                ++progressCount;
515                StringUtil::StrStreamType str;
516                str << "Loading nodes (phase " << progressCount << ")"; 
517                    rgm._notifyWorldGeometryStageStarted(str.str());
518            }
519            else if (progressCountdown == 0)
520            {
521                // stage report
522                rgm._notifyWorldGeometryStageEnded();
523                progressCountdown = NUM_NODES_PER_PROGRESS_REPORT + 1; 
524
525            }
526
527            BspNode* node = &mRootNode[i];
528            bsp_node_t* q3node = &q3lvl.mNodes[i];
529
530            // Set non-leaf
531            node->mIsLeaf = false;
532            // Set owner
533            node->mOwner = this;
534            // Set plane
535            node->mSplitPlane.normal.x = q3lvl.mPlanes[q3node->plane].normal[0];
536            node->mSplitPlane.normal.y = q3lvl.mPlanes[q3node->plane].normal[1];
537            node->mSplitPlane.normal.z = q3lvl.mPlanes[q3node->plane].normal[2];
538            node->mSplitPlane.d = -q3lvl.mPlanes[q3node->plane].dist;
539            // Set bounding box
540            node->mBounds.setMinimum(Vector3(&q3node->bbox[0]));
541            node->mBounds.setMaximum(Vector3(&q3node->bbox[3]));
542            // Set back pointer
543            // Negative indexes in Quake3 mean leaves
544            if (q3node->back < 0)
545            {
546                // Points to leaf, offset to leaf start and negate index
547                node->mBack = &mRootNode[mLeafStart + (~(q3node->back))];
548
549            }
550            else
551            {
552                // Points to node
553                node->mBack = &mRootNode[q3node->back];
554            }
555            // Set front pointer
556            // Negative indexes in Quake3 mean leaves
557            if (q3node->front < 0)
558            {
559                // Points to leaf, offset to leaf start and negate index
560                node->mFront = &mRootNode[mLeafStart + (~(q3node->front))];
561
562            }
563            else
564            {
565                // Points to node
566                node->mFront = &mRootNode[q3node->front];
567            }
568
569            --progressCountdown;
570
571
572        }
573        // final stage report
574        rgm._notifyWorldGeometryStageEnded();
575
576        //-----------------------------------------------------------------------
577        // Brushes
578        //-----------------------------------------------------------------------
579        // Reserve enough memory for all brushes, solid or not (need to maintain indexes)
580        mBrushes = new BspNode::Brush[q3lvl.mNumBrushes];
581        progressCountdown = NUM_BRUSHES_PER_PROGRESS_REPORT;
582        progressCount = 0;
583
584        for (i = 0; i < q3lvl.mNumBrushes; ++i)
585        {
586            // Progress reporting
587            if (progressCountdown == NUM_BRUSHES_PER_PROGRESS_REPORT)
588            {
589                ++progressCount;
590                StringUtil::StrStreamType str;
591                str << "Loading brushes (phase " << progressCount << ")"; 
592                    rgm._notifyWorldGeometryStageStarted(str.str());
593            }
594            else if (progressCountdown == 0)
595            {
596                // stage report
597                rgm._notifyWorldGeometryStageEnded();
598                progressCountdown = NUM_BRUSHES_PER_PROGRESS_REPORT + 1; 
599
600            }
601            bsp_brush_t* q3brush = &q3lvl.mBrushes[i];
602
603            // Create a new OGRE brush
604            BspNode::Brush *pBrush = &(mBrushes[i]);
605            int brushSideIdx, numBrushSides;
606            numBrushSides = q3brush->numsides;
607            brushSideIdx = q3brush->firstside;
608            // Iterate over the sides and create plane for each
609            while (numBrushSides--)
610            {
611                bsp_brushside_t* q3brushside = &q3lvl.mBrushSides[brushSideIdx];
612                bsp_plane_t* q3brushplane = &q3lvl.mPlanes[q3brushside->planenum];
613                // Notice how we normally invert Q3A plane distances, but here we do not
614                // Because we want plane normals pointing out of solid brushes, not in
615                Plane brushSide(
616                                        Vector3(
617                                                q3brushplane->normal[0], 
618                                                q3brushplane->normal[1], 
619                                                q3brushplane->normal[2]), 
620                                        q3brushplane->dist);
621                pBrush->planes.push_back(brushSide);
622                ++brushSideIdx;
623            }
624            // Build world fragment
625            pBrush->fragment.fragmentType = SceneQuery::WFT_PLANE_BOUNDED_REGION;
626            pBrush->fragment.planes = &(pBrush->planes);
627
628            --progressCountdown;
629
630        }
631        // final stage report
632        rgm._notifyWorldGeometryStageEnded();
633
634
635
636        //-----------------------------------------------------------------------
637        // Leaves
638        //-----------------------------------------------------------------------
639        progressCountdown = NUM_LEAVES_PER_PROGRESS_REPORT;
640        progressCount = 0;
641        for (i = 0; i < q3lvl.mNumLeaves; ++i)
642        {
643            // Progress reporting
644            if (progressCountdown == NUM_LEAVES_PER_PROGRESS_REPORT)
645            {
646                ++progressCount;
647                StringUtil::StrStreamType str;
648                str << "Loading leaves (phase " << progressCount << ")"; 
649                    rgm._notifyWorldGeometryStageStarted(str.str());
650            }
651            else if (progressCountdown == 0)
652            {
653                // stage report
654                rgm._notifyWorldGeometryStageEnded();
655                progressCountdown = NUM_LEAVES_PER_PROGRESS_REPORT + 1; 
656
657            }
658            BspNode* node = &mRootNode[i + mLeafStart];
659            bsp_leaf_t* q3leaf = &q3lvl.mLeaves[i];
660
661            // Set leaf
662            node->mIsLeaf = true;
663            // Set owner
664            node->mOwner = this;
665            // Set bounding box
666            node->mBounds.setMinimum(Vector3(&q3leaf->bbox[0]));
667            node->mBounds.setMaximum(Vector3(&q3leaf->bbox[3]));
668            // Set faces
669            node->mFaceGroupStart = q3leaf->face_start;
670            node->mNumFaceGroups = q3leaf->face_count;
671
672            node->mVisCluster = q3leaf->cluster;
673
674            // Load Brushes for this leaf
675            int brushIdx, brushCount, realBrushIdx;
676            brushCount = q3leaf->brush_count;
677            brushIdx = q3leaf->brush_start;
678
679            while(brushCount--)
680            {
681                realBrushIdx = q3lvl.mLeafBrushes[brushIdx];
682                bsp_brush_t* q3brush = &q3lvl.mBrushes[realBrushIdx];
683                // Only load solid ones, we don't care about any other types
684                // Shader determines this
685                bsp_shader_t* brushShader = &q3lvl.mShaders[q3brush->shaderIndex];
686                if (brushShader->content_flags & CONTENTS_SOLID)
687                {
688                    // Get brush
689                    BspNode::Brush *pBrush = &(mBrushes[realBrushIdx]);
690                    assert(pBrush->fragment.fragmentType == SceneQuery::WFT_PLANE_BOUNDED_REGION);
691                    // Assign node pointer
692                    node->mSolidBrushes.push_back(pBrush);
693                }
694                ++brushIdx;
695            }
696
697            --progressCountdown;
698
699        }
700        // final stage report
701        rgm._notifyWorldGeometryStageEnded();
702
703
704
705        // Vis - just copy
706        // final stage report
707        rgm._notifyWorldGeometryStageStarted("Copying Vis data");
708        mVisData.numClusters = q3lvl.mVis->cluster_count;
709        mVisData.rowLength = q3lvl.mVis->row_size;
710        mVisData.tableData = new unsigned char[q3lvl.mVis->row_size * q3lvl.mVis->cluster_count];
711        memcpy(mVisData.tableData, q3lvl.mVis->data, q3lvl.mVis->row_size * q3lvl.mVis->cluster_count);
712        rgm._notifyWorldGeometryStageEnded();
713
714
715
716    }
717
718    //-----------------------------------------------------------------------
719    void BspLevel::initQuake3Patches(const Quake3Level & q3lvl, VertexDeclaration* decl)
720    {
721        int face;
722
723        mPatchVertexCount = 0;
724        mPatchIndexCount = 0;
725
726        // We're just building the patch here to get a hold on the size of the mesh
727        // although we'll reuse this information later
728        face = q3lvl.mNumFaces;
729        while (face--)
730        {
731
732            bsp_face_t* src = &q3lvl.mFaces[face];
733
734            if (src->type == BSP_FACETYPE_PATCH)
735            {
736                // Seems to be some crap in the Q3 level where vertex count = 0 or num control points = 0?
737                if (src->vert_count == 0 || src->mesh_cp[0] == 0)
738                {
739                    continue;
740                }
741                PatchSurface* ps = new PatchSurface();
742                // Set up control points & format
743                // Reuse the vertex declaration
744                // Copy control points into a buffer so we can convert their format
745                BspVertex* pControlPoints = new BspVertex[src->vert_count];
746                bsp_vertex_t* pSrc = q3lvl.mVertices + src->vert_start;
747                for (int v = 0; v < src->vert_count; ++v)
748                {
749                    quakeVertexToBspVertex(pSrc++, &pControlPoints[v]);
750                }
751                // Define the surface, but don't build it yet (no vertex / index buffer)
752                ps->defineSurface(
753                    pControlPoints,
754                    decl, 
755                    src->mesh_cp[0],
756                    src->mesh_cp[1],
757                    PatchSurface::PST_BEZIER);
758                // Get stats
759                mPatchVertexCount += ps->getRequiredVertexCount();
760                mPatchIndexCount += ps->getRequiredIndexCount();
761
762                // Save the surface for later
763                mPatches[face] = ps;
764            }
765
766
767        }
768
769    }
770    //-----------------------------------------------------------------------
771    void BspLevel::buildQuake3Patches(size_t vertOffset, size_t indexOffset)
772    {
773        // Loop through the patches
774        PatchMap::iterator i, iend;
775        iend = mPatches.end();
776
777        size_t currVertOffset = vertOffset;
778        size_t currIndexOffset = indexOffset;
779
780        HardwareVertexBufferSharedPtr vbuf = mVertexData->vertexBufferBinding->getBuffer(0);
781
782        for (i = mPatches.begin(); i != iend; ++i)
783        {
784            PatchSurface* ps = i->second;
785           
786            ps->build(vbuf, currVertOffset, mIndexes, currIndexOffset);
787
788            // No need for control points anymore
789            BspVertex* pCP = static_cast<BspVertex*>(ps->getControlPointBuffer());
790            delete [] pCP;
791            ps->notifyControlPointBufferDeallocated();
792
793            currVertOffset += ps->getRequiredVertexCount();
794            currIndexOffset += ps->getRequiredIndexCount();
795       
796        }
797    }
798    //-----------------------------------------------------------------------
799    bool BspLevel::isLeafVisible(const BspNode* from, const BspNode* to) const
800    {
801        if (to->mVisCluster == -1)
802            return false;
803        if (from->mVisCluster == -1)
804            // Camera outside world?
805            return true;
806
807
808        if (!from->isLeaf() || !to->isLeaf())
809            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
810                "Both nodes must be leaf nodes for visibility testing.",
811                "BspLevel::isLeafVisible");
812
813        // Use PVS to determine visibility
814
815        /*
816        // In wordier terms, the fairly cryptic (but fast) version is doing this:
817        //   Could make it a macro for even more speed?
818
819        // Row offset = from cluster number * row size
820        int offset = from->mVisCluster*mVisData.rowLength;
821
822        // Column offset (in bytes) = to cluster number divided by 8 (since 8 bits per bytes)
823        offset += to->mVisCluster >> 3;
824
825        // Get the right bit within the byte, i.e. bitwise 'and' with bit at remainder position
826        int result = *(mVisData.tableData + offset) & (1 << (to->mVisCluster & 7));
827
828        return (result != 0);
829        */
830
831        //return ((*(mVisData.tableData + from->mVisCluster * mVisData.rowLength +
832        //           ((to->mVisCluster)>>3)) & (1 << ((to->mVisCluster) & 7))) != 0);
833
834        return (*(mVisData.tableData + from->mVisCluster*mVisData.rowLength +
835                   ((to->mVisCluster)>>3)) & (1 << ((to->mVisCluster) & 7))) != 0;
836
837    }
838    //-----------------------------------------------------------------------
839    const BspNode* BspLevel::getRootNode(void)
840    {
841        return mRootNode;
842    }
843    //-----------------------------------------------------------------------
844    BspNode* BspLevel::findLeaf(const Vector3& point) const
845    {
846        BspNode* node = mRootNode;
847
848        while (!node->isLeaf())
849        {
850            node = node->getNextNode(point);
851        }
852
853        return node;
854
855    }
856    //-----------------------------------------------------------------------
857    void BspLevel::loadEntities(const Quake3Level& q3lvl)
858    {
859        char* strEnt;
860        String line;
861        StringVector vecparams;
862        Vector3 origin;
863        Radian angle ( 0 );
864        size_t pos;
865        char* lineend;
866        bool isPlayerStart;
867
868        isPlayerStart = false;
869        strEnt = (char*)q3lvl.mEntities;
870
871        lineend = strchr(strEnt, '\n');
872        while (lineend != 0)
873        {
874            *lineend = '\0';
875            line = strEnt;
876            strEnt = lineend+1;
877            StringUtil::trim(line);
878            if (line.length() > 0)
879            {
880                StringUtil::toLowerCase(line);
881                // Remove quotes
882                                while( ( pos = line.find("\"",0) ) != String::npos )
883                {
884                    line = line.substr(0,pos) + line.substr(pos+1,line.length()-(pos+1));
885                }
886                vecparams = StringUtil::split(line);
887                StringVector::iterator params = vecparams.begin();
888
889                if (params[0] == "origin")
890                {
891                    origin.x = atof(params[1].c_str());
892                    origin.y = atof(params[2].c_str());
893                    origin.z = atof(params[3].c_str());
894                }
895                if (params[0] == "angle")
896                {
897                    angle = Degree(atof(params[1].c_str()));
898                }
899                if (params[0] == "classname" && params[1] == "info_player_deathmatch")
900                {
901                    isPlayerStart = true;
902                }
903                if (params[0] == "}")
904                {
905                    if (isPlayerStart)
906                    {
907                        // Save player start
908                        ViewPoint vp;
909                        vp.position = origin;
910                        vp.orientation.FromAngleAxis(angle, Vector3::UNIT_Z);
911                        mPlayerStarts.push_back(vp);
912                    }
913                    isPlayerStart = false;
914                }
915            }
916
917            lineend = strchr(strEnt, '\n');
918        }
919
920
921    }
922    //-----------------------------------------------------------------------
923    void BspLevel::_notifyObjectMoved(const MovableObject* mov, 
924            const Vector3& pos)
925    {
926
927        // Locate any current nodes the object is supposed to be attached to
928        MovableToNodeMap::iterator i = mMovableToNodeMap.find(mov);
929        if (i != mMovableToNodeMap.end())
930        {
931            std::list<BspNode*>::iterator nodeit, nodeitend;
932            nodeitend = i->second.end();
933            for (nodeit = i->second.begin(); nodeit != nodeitend; ++nodeit)
934            {
935                // Tell each node
936                (*nodeit)->_removeMovable(mov);
937            }
938            // Clear the existing list of nodes because we'll reevaluate it
939            i->second.clear();
940        }
941
942        tagNodesWithMovable(mRootNode, mov, pos);
943    }
944    //-----------------------------------------------------------------------
945    void BspLevel::tagNodesWithMovable(BspNode* node, const MovableObject* mov,
946        const Vector3& pos)
947    {
948        if (node->isLeaf())
949        {
950            // Add to movable->node map
951            // Insert all the time, will get current if already there
952            std::pair<MovableToNodeMap::iterator, bool> p = 
953                mMovableToNodeMap.insert(
954                MovableToNodeMap::value_type(mov, std::list<BspNode*>()));
955
956            p.first->second.push_back(node);
957
958            // Add movable to node
959            node->_addMovable(mov);
960
961        }
962        else
963        {
964            // Find distance to dividing plane
965            Real dist = node->getDistance(pos);
966            if (Math::Abs(dist) < mov->getBoundingRadius())
967            {
968                // Bounding sphere crosses the plane, do both
969                tagNodesWithMovable(node->getBack(), mov, pos);
970                tagNodesWithMovable(node->getFront(), mov, pos);
971            }
972            else if (dist < 0)
973            {    //-----------------------------------------------------------------------
974
975                // Do back
976                tagNodesWithMovable(node->getBack(), mov, pos);
977            }
978            else
979            {
980                // Do front
981                tagNodesWithMovable(node->getFront(), mov, pos);
982            }
983        }
984    }
985    //-----------------------------------------------------------------------
986        void BspLevel::_notifyObjectDetached(const MovableObject* mov) 
987        {
988        // Locate any current nodes the object is supposed to be attached to
989        MovableToNodeMap::iterator i = mMovableToNodeMap.find(mov);
990        if (i != mMovableToNodeMap.end())
991        {
992            std::list<BspNode*>::iterator nodeit, nodeitend;
993            nodeitend = i->second.end();
994            for (nodeit = i->second.begin(); nodeit != nodeitend; ++nodeit)
995            {
996                // Tell each node
997                (*nodeit)->_removeMovable(mov);
998            }
999            // delete the entry for this MovableObject
1000            mMovableToNodeMap.erase(i);
1001        }
1002        }
1003    //-----------------------------------------------------------------------
1004    void BspLevel::quakeVertexToBspVertex(const bsp_vertex_t* src, BspVertex* dest)
1005    {
1006        memcpy(dest->position, src->point, sizeof(float) * 3);
1007        memcpy(dest->normal, src->normal,  sizeof(float) * 3);
1008        dest->colour = src->color;
1009        dest->texcoords[0]  = src->texture[0];
1010        dest->texcoords[1]  = src->texture[1];
1011        dest->lightmap[0]  = src->lightmap[0];
1012        dest->lightmap[1]  = src->lightmap[1];
1013    }
1014    //-----------------------------------------------------------------------
1015    size_t BspLevel::calculateSize(void) const
1016    {
1017        return 0; // TODO
1018    }
1019}
Note: See TracBrowser for help on using the repository browser.