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

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