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

Revision 690, 37.2 KB checked in by mattausch, 18 years ago (diff)

added ogre 1.07 main

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