source: OGRE/trunk/ogrenew/OgreMain/src/OgreStaticGeometry.cpp @ 690

Revision 690, 56.3 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 "OgreStableHeaders.h"
26#include "OgreStaticGeometry.h"
27#include "OgreEntity.h"
28#include "OgreSubEntity.h"
29#include "OgreSceneNode.h"
30#include "OgreException.h"
31#include "OgreMesh.h"
32#include "OgreSubMesh.h"
33#include "OgreLogManager.h"
34#include "OgreSceneManager.h"
35#include "OgreCamera.h"
36#include "OgreMaterialManager.h"
37#include "OgreRoot.h"
38#include "OgreRenderSystem.h"
39
40namespace Ogre {
41
42        #define REGION_RANGE 1024
43        #define REGION_HALF_RANGE 512
44        #define REGION_MAX_INDEX 511
45        #define REGION_MIN_INDEX -512
46
47        //--------------------------------------------------------------------------
48        StaticGeometry::StaticGeometry(SceneManager* owner, const String& name):
49                mOwner(owner),
50                mName(name),
51                mBuilt(false),
52                mUpperDistance(0.0f),
53                mSquaredUpperDistance(0.0f),
54                mCastShadows(false),
55                mRegionDimensions(Vector3(1000,1000,1000)),
56                mHalfRegionDimensions(Vector3(500,500,500)),
57                mOrigin(Vector3(0,0,0)),
58                mVisible(true),
59        mRenderQueueID(RENDER_QUEUE_MAIN),
60        mRenderQueueIDSet(false)
61        {
62        }
63        //--------------------------------------------------------------------------
64        StaticGeometry::~StaticGeometry()
65        {
66                reset();
67        }
68        //--------------------------------------------------------------------------
69        StaticGeometry::Region* StaticGeometry::getRegion(const AxisAlignedBox& bounds,
70                bool autoCreate)
71        {
72                if (bounds.isNull())
73                        return 0;
74
75                // Get the region which has the largest overlapping volume
76                const Vector3 min = bounds.getMinimum();
77                const Vector3 max = bounds.getMaximum();
78
79                // Get the min and max region indexes
80                ushort minx, miny, minz;
81                ushort maxx, maxy, maxz;
82                getRegionIndexes(min, minx, miny, minz);
83                getRegionIndexes(max, maxx, maxy, maxz);
84                Real maxVolume = 0.0f;
85                ushort finalx, finaly, finalz;
86                for (ushort x = minx; x <= maxx; ++x)
87                {
88                        for (ushort y = miny; y <= maxy; ++y)
89                        {
90                                for (ushort z = minz; z <= maxz; ++z)
91                                {
92                                        Real vol = getVolumeIntersection(bounds, x, y, z);
93                                        if (vol > maxVolume)
94                                        {
95                                                maxVolume = vol;
96                                                finalx = x;
97                                                finaly = y;
98                                                finalz = z;
99                                        }
100
101                                }
102                        }
103                }
104
105                assert(maxVolume > 0.0f &&
106                        "Static geometry: Problem determining closest volume match!");
107
108                return getRegion(finalx, finaly, finalz, autoCreate);
109
110        }
111        //--------------------------------------------------------------------------
112        Real StaticGeometry::getVolumeIntersection(const AxisAlignedBox& box, 
113                ushort x, ushort y, ushort z)
114        {
115                // Get bounds of indexed region
116                AxisAlignedBox regionBounds = getRegionBounds(x, y, z);
117                AxisAlignedBox intersectBox = regionBounds.intersection(box);
118                // return a 'volume' which ignores zero dimensions
119                // since we only use this for relative comparisons of the same bounds
120                // this will still be internally consistent
121                Vector3 boxdiff = box.getMaximum() - box.getMinimum();
122                Vector3 intersectDiff = intersectBox.getMaximum() - intersectBox.getMinimum();
123
124                return (boxdiff.x == 0 ? 1 : intersectDiff.x) *
125                        (boxdiff.y == 0 ? 1 : intersectDiff.y) *
126                        (boxdiff.z == 0 ? 1 : intersectDiff.z);
127
128        }
129        //--------------------------------------------------------------------------
130        AxisAlignedBox StaticGeometry::getRegionBounds(ushort x, ushort y, ushort z)
131        {
132                Vector3 min(
133                        ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x,
134                        ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y,
135                        ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z
136                        );
137                Vector3 max = min + mRegionDimensions;
138                return AxisAlignedBox(min, max);
139        }
140        //--------------------------------------------------------------------------
141        Vector3 StaticGeometry::getRegionCentre(ushort x, ushort y, ushort z)
142        {
143                return Vector3(
144                        ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x
145                                + mHalfRegionDimensions.x,
146                        ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y
147                                + mHalfRegionDimensions.y,
148                        ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z
149                                + mHalfRegionDimensions.z
150                        );
151        }
152        //--------------------------------------------------------------------------
153        StaticGeometry::Region* StaticGeometry::getRegion(
154                        ushort x, ushort y, ushort z, bool autoCreate)
155        {
156                uint32 index = packIndex(x, y, z);
157                Region* ret = getRegion(index);
158                if (!ret && autoCreate)
159                {
160                        // Make a name
161                        StringUtil::StrStreamType str;
162                        str << mName << ":" << index;
163                        // Calculate the region centre
164                        Vector3 centre = getRegionCentre(x, y, z);
165                        ret = new Region(this, str.str(), mOwner, index, centre);
166                        ret->setVisible(mVisible);
167                        ret->setCastShadows(mCastShadows);
168                        if (mRenderQueueIDSet)
169                        {
170                                ret->setRenderQueueGroup(mRenderQueueID);
171                        }
172                        mRegionMap[index] = ret;
173                }
174                return ret;
175        }
176        //--------------------------------------------------------------------------
177        StaticGeometry::Region* StaticGeometry::getRegion(uint32 index)
178        {
179                RegionMap::iterator i = mRegionMap.find(index);
180                if (i != mRegionMap.end())
181                {
182                        return i->second;
183                }
184                else
185                {
186                        return 0;
187                }
188               
189        }
190        //--------------------------------------------------------------------------
191        void StaticGeometry::getRegionIndexes(const Vector3& point,
192                ushort& x, ushort& y, ushort& z)
193        {
194                // Scale the point into multiples of region and adjust for origin
195                Vector3 scaledPoint = (point - mOrigin) / mRegionDimensions;
196
197                // Round down to 'bottom left' point which represents the cell index
198                int ix = Math::IFloor(scaledPoint.x);
199                int iy = Math::IFloor(scaledPoint.y);
200                int iz = Math::IFloor(scaledPoint.z);
201
202                // Check bounds
203                if (ix < REGION_MIN_INDEX || ix > REGION_MAX_INDEX
204                        || iy < REGION_MIN_INDEX || iy > REGION_MAX_INDEX
205                        || iz < REGION_MIN_INDEX || iz > REGION_MAX_INDEX)
206                {
207                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
208                                "Point out of bounds",
209                                "StaticGeometry::getRegionIndexes");
210                }
211                // Adjust for the fact that we use unsigned values for simplicity
212                // (requires less faffing about for negatives give 10-bit packing
213                x = static_cast<ushort>(ix + REGION_HALF_RANGE);
214                y = static_cast<ushort>(iy + REGION_HALF_RANGE);
215                z = static_cast<ushort>(iz + REGION_HALF_RANGE);
216
217
218        }
219        //--------------------------------------------------------------------------
220        uint32 StaticGeometry::packIndex(ushort x, ushort y, ushort z)
221        {
222                return x + (y << 10) + (z << 20);
223        }
224        //--------------------------------------------------------------------------
225        StaticGeometry::Region* StaticGeometry::getRegion(const Vector3& point,
226                bool autoCreate)
227        {
228                ushort x, y, z;
229                getRegionIndexes(point, x, y, z);
230                return getRegion(x, y, z, autoCreate);
231        }
232        //--------------------------------------------------------------------------
233        AxisAlignedBox StaticGeometry::calculateBounds(VertexData* vertexData,
234                const Vector3& position, const Quaternion& orientation,
235                const Vector3& scale)
236        {
237                const VertexElement* posElem =
238                        vertexData->vertexDeclaration->findElementBySemantic(
239                                VES_POSITION);
240                HardwareVertexBufferSharedPtr vbuf =
241                        vertexData->vertexBufferBinding->getBuffer(posElem->getSource());
242                unsigned char* vertex =
243                        static_cast<unsigned char*>(
244                                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
245                float* pFloat;
246
247                Vector3 min, max;
248                bool first = true;
249
250                for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize())
251                {
252                        posElem->baseVertexPointerToElement(vertex, &pFloat);
253
254                        Vector3 pt;
255
256                        pt.x = (*pFloat++);
257                        pt.y = (*pFloat++);
258                        pt.z = (*pFloat++);
259                        // Transform to world (scale, rotate, translate)
260                        pt = (orientation * (pt * scale)) + position;
261                        if (first)
262                        {
263                                min = max = pt;
264                                first = false;
265                        }
266                        else
267                        {
268                                min.makeFloor(pt);
269                                max.makeCeil(pt);
270                        }
271
272                }
273                vbuf->unlock();
274                return AxisAlignedBox(min, max);
275        }
276        //--------------------------------------------------------------------------
277        void StaticGeometry::addEntity(Entity* ent, const Vector3& position,
278                const Quaternion& orientation, const Vector3& scale)
279        {
280                MeshPtr& msh = ent->getMesh();
281                // Validate
282                if (msh->isLodManual())
283                {
284                        LogManager::getSingleton().logMessage(
285                                "WARNING (StaticGeometry): Manual LOD is not supported. "
286                                "Using only highest LOD level for mesh " + msh->getName());
287                }
288                               
289                AxisAlignedBox sharedWorldBounds;
290                // queue this entities submeshes and choice of material
291                // also build the lists of geometry to be used for the source of lods
292                for (uint i = 0; i < ent->getNumSubEntities(); ++i)
293                {
294                        SubEntity* se = ent->getSubEntity(i);
295                        QueuedSubMesh* q = new QueuedSubMesh();
296
297                        // Get the geometry for this SubMesh
298                        q->submesh = se->getSubMesh();
299                        q->geometryLodList = determineGeometry(q->submesh);
300                        q->materialName = se->getMaterialName();
301                        q->orientation = orientation;
302                        q->position = position;
303                        q->scale = scale;
304                        // Determine the bounds based on the highest LOD
305                        q->worldBounds = calculateBounds(
306                                (*q->geometryLodList)[0].vertexData,
307                                        position, orientation, scale);
308                       
309                        mQueuedSubMeshes.push_back(q);
310                }
311        }
312        //--------------------------------------------------------------------------
313        StaticGeometry::SubMeshLodGeometryLinkList*
314        StaticGeometry::determineGeometry(SubMesh* sm)
315        {
316                // First, determine if we've already seen this submesh before
317                SubMeshGeometryLookup::iterator i =
318                        mSubMeshGeometryLookup.find(sm);
319                if (i != mSubMeshGeometryLookup.end())
320                {
321                        return i->second;
322                }
323                // Otherwise, we have to create a new one
324                SubMeshLodGeometryLinkList* lodList = new SubMeshLodGeometryLinkList();
325                mSubMeshGeometryLookup[sm] = lodList;
326                ushort numLods = sm->parent->isLodManual() ? 1 :
327                        sm->parent->getNumLodLevels();
328                lodList->resize(numLods);
329                for (ushort lod = 0; lod < numLods; ++lod)
330                {
331                        SubMeshLodGeometryLink& geomLink = (*lodList)[lod];
332                        IndexData *lodIndexData;
333                        if (lod == 0)
334                        {
335                                lodIndexData = sm->indexData;
336                        }
337                        else
338                        {
339                                lodIndexData = sm->mLodFaceList[lod - 1];
340                        }
341                        // Can use the original mesh geometry?
342                        if (sm->useSharedVertices)
343                        {
344                                if (sm->parent->getNumSubMeshes() == 1)
345                                {
346                                        // Ok, this is actually our own anyway
347                                        geomLink.vertexData = sm->parent->sharedVertexData;
348                                        geomLink.indexData = lodIndexData;
349                                }
350                                else
351                                {
352                                        // We have to split it
353                                        splitGeometry(sm->parent->sharedVertexData,
354                                                lodIndexData, &geomLink);
355                                }
356                        }
357                        else
358                        {
359                                if (lod == 0)
360                                {
361                                        // Ok, we can use the existing geometry; should be in full
362                                        // use by just this SubMesh
363                                        geomLink.vertexData = sm->vertexData;
364                                        geomLink.indexData = sm->indexData;
365                                }
366                                else
367                                {
368                                        // We have to split it
369                                        splitGeometry(sm->vertexData,
370                                                lodIndexData, &geomLink);
371                                }
372                        }
373                        assert (geomLink.vertexData->vertexStart == 0 &&
374                                "Cannot use vertexStart > 0 on indexed geometry due to "
375                                "rendersystem incompatibilities - see the docs!");
376                }
377
378
379                return lodList;
380        }
381        //--------------------------------------------------------------------------
382        void StaticGeometry::splitGeometry(VertexData* vd, IndexData* id,
383                        StaticGeometry::SubMeshLodGeometryLink* targetGeomLink)
384        {
385                // Firstly we need to scan to see how many vertices are being used
386                // and while we're at it, build the remap we can use later
387                bool use32bitIndexes =
388                        id->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT;
389                uint16 *p16;
390                uint32 *p32;
391                IndexRemap indexRemap;
392                if (use32bitIndexes)
393                {
394                        p32 = static_cast<uint32*>(id->indexBuffer->lock(
395                                id->indexStart, id->indexCount, HardwareBuffer::HBL_READ_ONLY));
396                        buildIndexRemap(p32, id->indexCount, indexRemap);
397                        id->indexBuffer->unlock();
398                }
399                else
400                {
401                        p16 = static_cast<uint16*>(id->indexBuffer->lock(
402                                id->indexStart, id->indexCount, HardwareBuffer::HBL_READ_ONLY));
403                        buildIndexRemap(p16, id->indexCount, indexRemap);
404                        id->indexBuffer->unlock();
405                }
406                if (indexRemap.size() == vd->vertexCount)
407                {
408                        // ha, complete usage after all
409                        targetGeomLink->vertexData = vd;
410                        targetGeomLink->indexData = id;
411                        return;
412                }
413               
414               
415                // Create the new vertex data records
416                targetGeomLink->vertexData = vd->clone(false);
417                // Convenience
418                VertexData* newvd = targetGeomLink->vertexData;
419                IndexData* newid = targetGeomLink->indexData;
420                // Update the vertex count
421                newvd->vertexCount = indexRemap.size();
422                       
423                size_t numvbufs = vd->vertexBufferBinding->getBufferCount();
424                // Copy buffers from old to new
425                for (unsigned short b = 0; b < numvbufs; ++b)
426                {
427                        // Lock old buffer
428                        HardwareVertexBufferSharedPtr oldBuf =
429                                vd->vertexBufferBinding->getBuffer(b);
430                        // Create new buffer
431                        HardwareVertexBufferSharedPtr newBuf =
432                                HardwareBufferManager::getSingleton().createVertexBuffer(
433                                        oldBuf->getVertexSize(),
434                                        indexRemap.size(),
435                                        HardwareBuffer::HBU_STATIC);
436                        // rebind
437                        newvd->vertexBufferBinding->setBinding(b, newBuf);
438
439                        // Copy all the elements of the buffer across, by iterating over
440                        // the IndexRemap which describes how to move the old vertices
441                        // to the new ones. By nature of the map the remap is in order of
442                        // indexes in the old buffer, but note that we're not guaranteed to
443                        // address every vertex (which is kinda why we're here)
444                        uchar* pSrcBase = static_cast<uchar*>(
445                                oldBuf->lock(HardwareBuffer::HBL_READ_ONLY));
446                        uchar* pDstBase = static_cast<uchar*>(
447                                newBuf->lock(HardwareBuffer::HBL_DISCARD));
448                        size_t vertexSize = oldBuf->getVertexSize();
449                        // Buffers should be the same size
450                        assert (vertexSize == newBuf->getVertexSize());
451
452                        for (IndexRemap::iterator r = indexRemap.begin();
453                                r != indexRemap.end(); ++r)
454                        {
455                                assert (r->first < oldBuf->getNumVertices());
456                                assert (r->second < newBuf->getNumVertices());
457
458                                uchar* pSrc = pSrcBase + r->first * vertexSize;
459                                uchar* pDst = pDstBase + r->second * vertexSize;
460                                memcpy(pDst, pSrc, vertexSize);
461                        }
462                        // unlock
463                        oldBuf->unlock();
464                        newBuf->unlock();
465
466                }
467
468                // Now create a new index buffer
469                HardwareIndexBufferSharedPtr ibuf =
470                        HardwareBufferManager::getSingleton().createIndexBuffer(
471                                id->indexBuffer->getType(), id->indexCount,
472                                HardwareBuffer::HBU_STATIC);
473               
474                if (use32bitIndexes)
475                {
476                        uint32 *pSrc32, *pDst32;
477                        pSrc32 = static_cast<uint32*>(id->indexBuffer->lock(
478                                id->indexStart, id->indexCount, HardwareBuffer::HBL_READ_ONLY));
479                        pDst32 = static_cast<uint32*>(ibuf->lock(
480                                HardwareBuffer::HBL_DISCARD));
481                        remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount);
482                        id->indexBuffer->unlock();
483                        ibuf->unlock();
484                }
485                else
486                {
487                        uint16 *pSrc16, *pDst16;
488                        pSrc16 = static_cast<uint16*>(id->indexBuffer->lock(
489                                id->indexStart, id->indexCount, HardwareBuffer::HBL_READ_ONLY));
490                        pDst16 = static_cast<uint16*>(ibuf->lock(
491                                HardwareBuffer::HBL_DISCARD));
492                        remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount);
493                        id->indexBuffer->unlock();
494                        ibuf->unlock();
495                }
496               
497                targetGeomLink->indexData = new IndexData();
498                targetGeomLink->indexData->indexStart = 0;
499                targetGeomLink->indexData->indexCount = id->indexCount;
500                targetGeomLink->indexData->indexBuffer = ibuf;
501
502                // Store optimised geometry for deallocation later
503                OptimisedSubMeshGeometry *optGeom = new OptimisedSubMeshGeometry();
504                optGeom->indexData = targetGeomLink->indexData;
505                optGeom->vertexData = targetGeomLink->vertexData;
506                mOptimisedSubMeshGeometryList.push_back(optGeom);
507        }
508        //--------------------------------------------------------------------------
509        void StaticGeometry::addSceneNode(const SceneNode* node)
510        {
511                SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator();
512                while (obji.hasMoreElements())
513                {
514                        MovableObject* mobj = obji.getNext();
515                        if (mobj->getMovableType() == "Entity")
516                        {
517                                addEntity(static_cast<Entity*>(mobj),
518                                        node->_getDerivedPosition(),
519                                        node->_getDerivedOrientation(),
520                                        node->_getDerivedScale());
521                        }
522                }
523                // Iterate through all the child-nodes
524                SceneNode::ConstChildNodeIterator nodei = node->getChildIterator();
525
526                while (nodei.hasMoreElements())
527                {
528                        const SceneNode* node = static_cast<const SceneNode*>(nodei.getNext());
529                        // Add this subnode and its children...
530                        addSceneNode( node );
531                }
532        }
533        //--------------------------------------------------------------------------
534        void StaticGeometry::build(void)
535        {
536                // Make sure there's nothing from previous builds
537                destroy();
538
539                // Firstly allocate meshes to regions
540                for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin();
541                        qi != mQueuedSubMeshes.end(); ++qi)
542                {
543                        QueuedSubMesh* qsm = *qi;
544                        Region* region = getRegion(qsm->worldBounds, true);
545                        region->assign(qsm);
546                }
547                bool stencilShadows = false;
548                if (mCastShadows &&
549                        (mOwner->getShadowTechnique() == SHADOWTYPE_STENCIL_ADDITIVE ||
550                        mOwner->getShadowTechnique() == SHADOWTYPE_STENCIL_MODULATIVE))
551                {
552                        stencilShadows = true;
553                }
554
555                // Now tell each region to build itself
556                for (RegionMap::iterator ri = mRegionMap.begin();
557                        ri != mRegionMap.end(); ++ri)
558                {
559                        ri->second->build(stencilShadows);
560                }
561
562        }
563        //--------------------------------------------------------------------------
564        void StaticGeometry::destroy(void)
565        {
566                // delete the regions
567                for (RegionMap::iterator i = mRegionMap.begin();
568                        i != mRegionMap.end(); ++i)
569                {
570                        delete i->second;
571                }
572                mRegionMap.clear();
573        }
574        //--------------------------------------------------------------------------
575        void StaticGeometry::reset(void)
576        {
577                destroy();
578                for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin();
579                        i != mQueuedSubMeshes.end(); ++i)
580                {
581                        delete *i;
582                }
583                mQueuedSubMeshes.clear();
584                // Delete precached geoemtry lists
585                for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin();
586                        l != mSubMeshGeometryLookup.end(); ++l)
587                {
588                        delete l->second;
589                }
590                mSubMeshGeometryLookup.clear();
591                // Delete optimised geometry
592                for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin();
593                        o != mOptimisedSubMeshGeometryList.end(); ++o)
594                {
595                        delete *o;
596                }
597                mOptimisedSubMeshGeometryList.clear();
598
599        }
600        //--------------------------------------------------------------------------
601        void StaticGeometry::setVisible(bool visible)
602        {
603                mVisible = visible;
604                // tell any existing regions
605                for (RegionMap::iterator ri = mRegionMap.begin();
606                        ri != mRegionMap.end(); ++ri)
607                {
608                        ri->second->setVisible(visible);
609                }
610        }
611        //--------------------------------------------------------------------------
612        void StaticGeometry::setCastShadows(bool castShadows)
613        {
614                mCastShadows = castShadows;
615                // tell any existing regions
616                for (RegionMap::iterator ri = mRegionMap.begin();
617                        ri != mRegionMap.end(); ++ri)
618                {
619                        ri->second->setCastShadows(castShadows);
620                }
621
622        }
623        //--------------------------------------------------------------------------
624    void StaticGeometry::setRenderQueueGroup(RenderQueueGroupID queueID)
625        {
626                mRenderQueueIDSet = true;
627                mRenderQueueID = queueID;
628                // tell any existing regions
629                for (RegionMap::iterator ri = mRegionMap.begin();
630                        ri != mRegionMap.end(); ++ri)
631                {
632                        ri->second->setRenderQueueGroup(queueID);
633                }
634        }
635        //--------------------------------------------------------------------------
636        RenderQueueGroupID StaticGeometry::getRenderQueueGroup(void) const
637        {
638                return mRenderQueueID;
639        }
640        //--------------------------------------------------------------------------
641        void StaticGeometry::dump(const String& filename) const
642        {
643                std::ofstream of(filename.c_str());
644                of << "Static Geometry Report for " << mName << std::endl;
645                of << "-------------------------------------------------" << std::endl;
646                of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl;
647                of << "Number of regions: " << mRegionMap.size() << std::endl;
648                of << "Region dimensions: " << mRegionDimensions << std::endl;
649                of << "Origin: " << mOrigin << std::endl;
650                of << "Max distance: " << mUpperDistance << std::endl;
651                of << "Casts shadows?: " << mCastShadows << std::endl;
652                of << std::endl;
653                for (RegionMap::const_iterator ri = mRegionMap.begin();
654                        ri != mRegionMap.end(); ++ri)
655                {
656                        ri->second->dump(of);
657                }
658                of << "-------------------------------------------------" << std::endl;
659        }
660        //--------------------------------------------------------------------------
661        StaticGeometry::RegionIterator StaticGeometry::getRegionIterator(void)
662        {
663                return RegionIterator(mRegionMap.begin(), mRegionMap.end());
664        }
665        //--------------------------------------------------------------------------
666        //--------------------------------------------------------------------------
667        StaticGeometry::Region::Region(StaticGeometry* parent, const String& name,
668                SceneManager* mgr, uint32 regionID, const Vector3& centre)
669                : mParent(parent), mName(name), mSceneMgr(mgr), mNode(0),
670                mRegionID(regionID), mCentre(centre), mBoundingRadius(0.0f),
671                mCurrentLod(0), mLightListUpdated(0), mBeyondFarDistance(false),
672                mEdgeList(0), mVertexProgramInUse(false)
673        {
674                // First LOD mandatory, and always from 0
675                mLodSquaredDistances.push_back(0.0f);
676        }
677        //--------------------------------------------------------------------------
678        StaticGeometry::Region::~Region()
679        {
680                if (mNode)
681                {
682                        mNode->getParentSceneNode()->removeChild(mNode);
683                        mSceneMgr->destroySceneNode(mNode->getName());
684                        mNode = 0;
685                }
686                // delete
687                for (LODBucketList::iterator i = mLodBucketList.begin();
688                        i != mLodBucketList.end(); ++i)
689                {
690                        delete *i;
691                }
692                mLodBucketList.clear();
693
694                for (ShadowRenderableList::iterator s = mShadowRenderables.begin();
695                        s != mShadowRenderables.end(); ++s)
696                {
697                        delete *s;
698                }
699                mShadowRenderables.clear();
700                delete mEdgeList;
701
702                // no need to delete queued meshes, these are managed in StaticGeometry
703
704        }
705        //--------------------------------------------------------------------------
706        void StaticGeometry::Region::assign(QueuedSubMesh* qmesh)
707        {
708                mQueuedSubMeshes.push_back(qmesh);
709                // update lod distances
710                ushort lodLevels = qmesh->submesh->parent->getNumLodLevels();
711                assert(qmesh->geometryLodList->size() == lodLevels);
712               
713                while(mLodSquaredDistances.size() < lodLevels)
714                {
715                        mLodSquaredDistances.push_back(0.0f);
716                }
717                // Make sure LOD levels are max of all at the requested level
718                for (ushort lod = 1; lod < lodLevels; ++lod)
719                {
720                        const MeshLodUsage& meshLod =
721                                qmesh->submesh->parent->getLodLevel(lod);
722                        mLodSquaredDistances[lod] = std::max(mLodSquaredDistances[lod],
723                                meshLod.fromDepthSquared);
724                }
725
726                // update bounds
727                // Transform world bounds relative to our centre
728                AxisAlignedBox localBounds(
729                        qmesh->worldBounds.getMinimum() - mCentre,
730                        qmesh->worldBounds.getMaximum() - mCentre);
731                mAABB.merge(localBounds);
732                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMinimum().length());
733                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMaximum().length());
734
735        }
736        //--------------------------------------------------------------------------
737        void StaticGeometry::Region::build(bool stencilShadows)
738        {
739                // Create a node
740                mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName,
741                        mCentre);
742                mNode->attachObject(this);
743                // We need to create enough LOD buckets to deal with the highest LOD
744                // we encountered in all the meshes queued
745                for (ushort lod = 0; lod < mLodSquaredDistances.size(); ++lod)
746                {
747                        LODBucket* lodBucket =
748                                new LODBucket(this, lod, mLodSquaredDistances[lod]);
749                        mLodBucketList.push_back(lodBucket);
750                        // Now iterate over the meshes and assign to LODs
751                        // LOD bucket will pick the right LOD to use
752                        QueuedSubMeshList::iterator qi, qiend;
753                        qiend = mQueuedSubMeshes.end();
754                        for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi)
755                        {
756                                lodBucket->assign(*qi, lod);
757                        }
758                        // now build
759                        lodBucket->build(stencilShadows);
760                }
761
762                // Do we need to build an edge list?
763                if (stencilShadows)
764                {
765                        EdgeListBuilder eb;
766                        size_t vertexSet = 0;
767                        LODIterator lodIterator = getLODIterator();
768                        while (lodIterator.hasMoreElements())
769                        {
770                                LODBucket* lod = lodIterator.getNext();
771                                LODBucket::MaterialIterator matIt = lod->getMaterialIterator();
772                                while (matIt.hasMoreElements())
773                                {
774                                        MaterialBucket* mat = matIt.getNext();
775                                        MaterialBucket::GeometryIterator geomIt =
776                                                mat->getGeometryIterator();
777                                        // Check if we have vertex programs here
778                                        Technique* t = mat->getMaterial()->getBestTechnique();
779                                        if (t)
780                                        {
781                                                Pass* p = t->getPass(0);
782                                                if (p)
783                                                {
784                                                        if (p->hasVertexProgram())
785                                                        {
786                                                                mVertexProgramInUse = true;
787                                                        }
788                                                }
789                                        }
790
791                                        while (geomIt.hasMoreElements())
792                                        {
793                                                GeometryBucket* geom = geomIt.getNext();
794
795                                                // Check we're dealing with 16-bit indexes here
796                                                // Since stencil shadows can only deal with 16-bit
797                                                // More than that and stencil is probably too CPU-heavy
798                                                // in any case
799                                                assert(geom->getIndexData()->indexBuffer->getType()
800                                                        == HardwareIndexBuffer::IT_16BIT &&
801                                                        "Only 16-bit indexes allowed when using stencil shadows");
802                                                eb.addVertexData(geom->getVertexData());
803                                                eb.addIndexData(geom->getIndexData(), vertexSet++);
804                                        }
805                                }
806                        }
807                        mEdgeList = eb.build();
808
809                }
810
811
812        }
813        //--------------------------------------------------------------------------
814        const String& StaticGeometry::Region::getName(void) const
815        {
816                return mName;
817        }
818        //--------------------------------------------------------------------------
819        const String& StaticGeometry::Region::getMovableType(void) const
820        {
821                static String sType = "StaticGeometry";
822                return sType;
823        }
824        //--------------------------------------------------------------------------
825        void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam)
826        {
827                // Calculate squared view depth
828                Vector3 diff = cam->getDerivedPosition() - mCentre;
829                Real squaredDepth = diff.squaredLength();
830
831                // Determine whether to still render
832                Real renderingDist = mParent->getRenderingDistance();
833                if (renderingDist > 0)
834                {
835                        // Max distance to still render
836                        Real maxDist = renderingDist + mBoundingRadius;
837                        if (squaredDepth > Math::Sqr(maxDist))
838                        {
839                                mBeyondFarDistance = true;
840                                return;
841                        }
842                }
843
844                mBeyondFarDistance = false;
845
846                // Distance from the edge of the bounding sphere
847                mCamDistanceSquared = squaredDepth - mBoundingRadius * mBoundingRadius;
848                // Clamp to 0
849                mCamDistanceSquared = std::max(static_cast<Real>(0.0), mCamDistanceSquared);
850
851                // Determine active lod
852                mCurrentLod = mLodSquaredDistances.size() - 1;
853                for (ushort i = 0; i < mLodSquaredDistances.size(); ++i)
854                {
855                        if (mLodSquaredDistances[i] > mCamDistanceSquared)
856                        {
857                                mCurrentLod = i - 1;
858                                break;
859                        }
860                }
861               
862        }
863        //--------------------------------------------------------------------------
864        const AxisAlignedBox& StaticGeometry::Region::getBoundingBox(void) const
865        {
866                return mAABB;
867        }
868        //--------------------------------------------------------------------------
869        Real StaticGeometry::Region::getBoundingRadius(void) const
870        {
871                return mBoundingRadius;
872        }
873        //--------------------------------------------------------------------------
874        void StaticGeometry::Region::_updateRenderQueue(RenderQueue* queue)
875        {
876                mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID,
877                        mCamDistanceSquared);
878        }
879        //--------------------------------------------------------------------------
880        bool StaticGeometry::Region::isVisible(void) const
881        {
882                return mVisible && !mBeyondFarDistance;
883        }
884        //--------------------------------------------------------------------------
885        StaticGeometry::Region::LODIterator
886        StaticGeometry::Region::getLODIterator(void)
887        {
888                return LODIterator(mLodBucketList.begin(), mLodBucketList.end());
889        }
890        //--------------------------------------------------------------------------
891        const LightList& StaticGeometry::Region::getLights(void) const
892        {
893                // Make sure we only update this once per frame no matter how many
894                // times we're asked
895                ulong frame = Root::getSingleton().getCurrentFrameNumber();
896                if (frame > mLightListUpdated)
897                {
898                        mLightList = mNode->findLights(mBoundingRadius);
899                        mLightListUpdated = frame;
900                }
901                return mLightList;
902
903        }
904        //--------------------------------------------------------------------------
905        ShadowCaster::ShadowRenderableListIterator
906        StaticGeometry::Region::getShadowVolumeRenderableIterator(
907                ShadowTechnique shadowTechnique, const Light* light,
908                HardwareIndexBufferSharedPtr* indexBuffer,
909                bool extrude, Real extrusionDistance, unsigned long flags)
910        {
911
912                assert(indexBuffer && "Only external index buffers are supported right now");
913                assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
914                        "Only 16-bit indexes supported for now");
915
916                // Calculate the object space light details
917                Vector4 lightPos = light->getAs4DVector();
918                Matrix4 world2Obj = mParentNode->_getFullTransform().inverse();
919                lightPos =  world2Obj * lightPos;
920
921                // We need to search the edge list for silhouette edges
922                if (!mEdgeList)
923                {
924                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
925                                "You enabled stencil shadows after the buid process!",
926                                "StaticGeometry::Region::getShadowVolumeRenderableIterator");
927                }
928
929                // Init shadow renderable list if required
930                bool init = mShadowRenderables.empty();
931
932                EdgeData::EdgeGroupList::iterator egi;
933                ShadowRenderableList::iterator si, siend;
934                RegionShadowRenderable* esr = 0;
935                if (init)
936                        mShadowRenderables.resize(mEdgeList->edgeGroups.size());
937
938                bool updatedSharedGeomNormals = false;
939                siend = mShadowRenderables.end();
940                egi = mEdgeList->edgeGroups.begin();
941                for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
942                {
943                        if (init)
944                        {
945                                // Create a new renderable, create a separate light cap if
946                                // we're using a vertex program (either for this model, or
947                                // for extruding the shadow volume) since otherwise we can
948                                // get depth-fighting on the light cap
949
950                                *si = new RegionShadowRenderable(this, indexBuffer,
951                                        egi->vertexData, mVertexProgramInUse || !extrude);
952                        }
953                        // Get shadow renderable
954                        esr = static_cast<RegionShadowRenderable*>(*si);
955                        HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
956                        // Extrude vertices in software if required
957                        if (extrude)
958                        {
959                                extrudeVertices(esrPositionBuffer,
960                                        egi->vertexData->vertexCount,
961                                        lightPos, extrusionDistance);
962
963                        }
964
965                }
966                // Calc triangle light facing
967                updateEdgeListLightFacing(mEdgeList, lightPos);
968
969                // Generate indexes and update renderables
970                generateShadowVolume(mEdgeList, *indexBuffer, light,
971                        mShadowRenderables, flags);
972
973
974                return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
975
976
977        }
978        //--------------------------------------------------------------------------
979        EdgeData* StaticGeometry::Region::getEdgeList(void)
980        {
981                return mEdgeList;
982        }
983        //--------------------------------------------------------------------------
984        void StaticGeometry::Region::dump(std::ofstream& of) const
985        {
986                of << "Region " << mRegionID << std::endl;
987                of << "--------------------------" << std::endl;
988                of << "Centre: " << mCentre << std::endl;
989                of << "Local AABB: " << mAABB << std::endl;
990                of << "Bounding radius: " << mBoundingRadius << std::endl;
991                of << "Number of LODs: " << mLodBucketList.size() << std::endl;
992
993                for (LODBucketList::const_iterator i = mLodBucketList.begin();
994                        i != mLodBucketList.end(); ++i)
995                {
996                        (*i)->dump(of);
997                }
998                of << "--------------------------" << std::endl;
999        }
1000        //--------------------------------------------------------------------------
1001        //--------------------------------------------------------------------------
1002        StaticGeometry::Region::RegionShadowRenderable::RegionShadowRenderable(
1003                Region* parent, HardwareIndexBufferSharedPtr* indexBuffer,
1004                const VertexData* vertexData, bool createSeparateLightCap,
1005                bool isLightCap)
1006                : mParent(parent)
1007        {
1008                // Initialise render op
1009                mRenderOp.indexData = new IndexData();
1010                mRenderOp.indexData->indexBuffer = *indexBuffer;
1011                mRenderOp.indexData->indexStart = 0;
1012                // index start and count are sorted out later
1013
1014                // Create vertex data which just references position component (and 2 component)
1015                mRenderOp.vertexData = new VertexData();
1016                mRenderOp.vertexData->vertexDeclaration =
1017                        HardwareBufferManager::getSingleton().createVertexDeclaration();
1018                mRenderOp.vertexData->vertexBufferBinding =
1019                        HardwareBufferManager::getSingleton().createVertexBufferBinding();
1020                // Map in position data
1021                mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
1022                ushort origPosBind =
1023                        vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
1024                mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(origPosBind);
1025                mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
1026                // Map in w-coord buffer (if present)
1027                if(!vertexData->hardwareShadowVolWBuffer.isNull())
1028                {
1029                        mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
1030                        mWBuffer = vertexData->hardwareShadowVolWBuffer;
1031                        mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
1032                }
1033                // Use same vertex start as input
1034                mRenderOp.vertexData->vertexStart = vertexData->vertexStart;
1035
1036                if (isLightCap)
1037                {
1038                        // Use original vertex count, no extrusion
1039                        mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
1040                }
1041                else
1042                {
1043                        // Vertex count must take into account the doubling of the buffer,
1044                        // because second half of the buffer is the extruded copy
1045                        mRenderOp.vertexData->vertexCount =
1046                                vertexData->vertexCount * 2;
1047                        if (createSeparateLightCap)
1048                        {
1049                                // Create child light cap
1050                                mLightCap = new RegionShadowRenderable(parent,
1051                                        indexBuffer, vertexData, false, true);
1052                        }
1053                }
1054        }
1055        //--------------------------------------------------------------------------
1056        StaticGeometry::Region::RegionShadowRenderable::~RegionShadowRenderable()
1057        {
1058                delete mRenderOp.indexData;
1059                delete mRenderOp.vertexData;
1060        }
1061        //--------------------------------------------------------------------------
1062        void StaticGeometry::Region::RegionShadowRenderable::getWorldTransforms(
1063                Matrix4* xform) const
1064        {
1065                // pretransformed
1066                *xform = mParent->_getParentNodeFullTransform();
1067        }
1068        //--------------------------------------------------------------------------
1069        const Quaternion&
1070        StaticGeometry::Region::RegionShadowRenderable::getWorldOrientation(void) const
1071        {
1072                return mParent->getParentNode()->_getDerivedOrientation();
1073        }
1074        //--------------------------------------------------------------------------
1075        const Vector3&
1076        StaticGeometry::Region::RegionShadowRenderable::getWorldPosition(void) const
1077        {
1078                return mParent->getCentre();
1079        }
1080        //--------------------------------------------------------------------------
1081        //--------------------------------------------------------------------------
1082        StaticGeometry::LODBucket::LODBucket(Region* parent, unsigned short lod,
1083                Real lodDist)
1084                : mParent(parent), mLod(lod), mSquaredDistance(lodDist)
1085        {
1086        }
1087        //--------------------------------------------------------------------------
1088        StaticGeometry::LODBucket::~LODBucket()
1089        {
1090                // delete
1091                for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1092                        i != mMaterialBucketMap.end(); ++i)
1093                {
1094                        delete i->second;
1095                }
1096                mMaterialBucketMap.clear();
1097                for(QueuedGeometryList::iterator qi = mQueuedGeometryList.begin();
1098                        qi != mQueuedGeometryList.end(); ++qi)
1099                {
1100                        delete *qi;
1101                }
1102                mQueuedGeometryList.clear();
1103
1104                // no need to delete queued meshes, these are managed in StaticGeometry
1105        }
1106        //--------------------------------------------------------------------------
1107        void StaticGeometry::LODBucket::assign(QueuedSubMesh* qmesh, ushort atLod)
1108        {
1109                QueuedGeometry* q = new QueuedGeometry();
1110                mQueuedGeometryList.push_back(q);
1111                q->position = qmesh->position;
1112                q->orientation = qmesh->orientation;
1113                q->scale = qmesh->scale;
1114                if (qmesh->geometryLodList->size() > atLod)
1115                {
1116                        // This submesh has enough lods, use the right one
1117                        q->geometry = &(*qmesh->geometryLodList)[atLod];
1118                }
1119                else
1120                {
1121                        // Not enough lods, use the lowest one we have
1122                        q->geometry =
1123                                &(*qmesh->geometryLodList)[qmesh->geometryLodList->size() - 1];
1124                }
1125                // Locate a material bucket
1126                MaterialBucket* mbucket = 0;
1127                MaterialBucketMap::iterator m =
1128                        mMaterialBucketMap.find(qmesh->materialName);
1129                if (m != mMaterialBucketMap.end())
1130                {
1131                        mbucket = m->second;
1132                }
1133                else
1134                {
1135                        mbucket = new MaterialBucket(this, qmesh->materialName);
1136                        mMaterialBucketMap[qmesh->materialName] = mbucket;
1137                }
1138                mbucket->assign(q);
1139        }
1140        //--------------------------------------------------------------------------
1141        void StaticGeometry::LODBucket::build(bool stencilShadows)
1142        {
1143                // Just pass this on to child buckets
1144                for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1145                        i != mMaterialBucketMap.end(); ++i)
1146                {
1147                        i->second->build(stencilShadows);
1148                }
1149        }
1150        //--------------------------------------------------------------------------
1151        void StaticGeometry::LODBucket::addRenderables(RenderQueue* queue,
1152                RenderQueueGroupID group, Real camDistanceSquared)
1153        {
1154                // Just pass this on to child buckets
1155                MaterialBucketMap::iterator i, iend;
1156                iend =  mMaterialBucketMap.end();
1157                for (i = mMaterialBucketMap.begin(); i != iend; ++i)
1158                {
1159                        i->second->addRenderables(queue, group, camDistanceSquared);
1160                }
1161        }
1162        //--------------------------------------------------------------------------
1163        StaticGeometry::LODBucket::MaterialIterator
1164        StaticGeometry::LODBucket::getMaterialIterator(void)
1165        {
1166                return MaterialIterator(
1167                        mMaterialBucketMap.begin(), mMaterialBucketMap.end());
1168        }
1169        //--------------------------------------------------------------------------
1170        void StaticGeometry::LODBucket::dump(std::ofstream& of) const
1171        {
1172                of << "LOD Bucket " << mLod << std::endl;
1173                of << "------------------" << std::endl;
1174                of << "Distance: " << Math::Sqrt(mSquaredDistance) << std::endl;
1175                of << "Number of Materials: " << mMaterialBucketMap.size() << std::endl;
1176                for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin();
1177                        i != mMaterialBucketMap.end(); ++i)
1178                {
1179                        i->second->dump(of);
1180                }
1181                of << "------------------" << std::endl;
1182               
1183        }
1184        //--------------------------------------------------------------------------
1185        //--------------------------------------------------------------------------
1186        StaticGeometry::MaterialBucket::MaterialBucket(LODBucket* parent,
1187                const String& materialName)
1188                : mParent(parent), mMaterialName(materialName)
1189        {
1190        }
1191        //--------------------------------------------------------------------------
1192        StaticGeometry::MaterialBucket::~MaterialBucket()
1193        {
1194                // delete
1195                for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1196                        i != mGeometryBucketList.end(); ++i)
1197                {
1198                        delete *i;
1199                }
1200                mGeometryBucketList.clear();
1201
1202                // no need to delete queued meshes, these are managed in StaticGeometry
1203        }
1204        //--------------------------------------------------------------------------
1205        void StaticGeometry::MaterialBucket::assign(QueuedGeometry* qgeom)
1206        {
1207                // Look up any current geometry
1208                String formatString = getGeometryFormatString(qgeom->geometry);
1209                CurrentGeometryMap::iterator gi = mCurrentGeometryMap.find(formatString);
1210                bool newBucket = true;
1211                if (gi != mCurrentGeometryMap.end())
1212                {
1213                        // Found existing geometry, try to assign
1214                        newBucket = !gi->second->assign(qgeom);
1215                        // Note that this bucket will be replaced as the 'current'
1216                        // for this format string below since it's out of space
1217                }
1218                // Do we need to create a new one?
1219                if (newBucket)
1220                {
1221                        GeometryBucket* gbucket = new GeometryBucket(this, formatString,
1222                                qgeom->geometry->vertexData, qgeom->geometry->indexData);
1223                        // Add to main list
1224                        mGeometryBucketList.push_back(gbucket);
1225                        // Also index in 'current' list
1226                        mCurrentGeometryMap[formatString] = gbucket;
1227                        if (!gbucket->assign(qgeom))
1228                        {
1229                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1230                                        "Somehow we couldn't fit the requested geometry even in a "
1231                                        "brand new GeometryBucket!! Must be a bug, please report.",
1232                                        "StaticGeometry::MaterialBucket::assign");
1233                        }
1234                }
1235        }
1236        //--------------------------------------------------------------------------
1237        void StaticGeometry::MaterialBucket::build(bool stencilShadows)
1238        {
1239                mMaterial = MaterialManager::getSingleton().getByName(mMaterialName);
1240                if (mMaterial.isNull())
1241                {
1242                        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1243                                "Material '" + mMaterialName + "' not found.",
1244                                "StaticGeometry::MaterialBucket::build");
1245                }
1246                mMaterial->load();
1247                // tell the geometry buckets to build
1248                for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1249                        i != mGeometryBucketList.end(); ++i)
1250                {
1251                        (*i)->build(stencilShadows);
1252                }
1253        }
1254        //--------------------------------------------------------------------------
1255        void StaticGeometry::MaterialBucket::addRenderables(RenderQueue* queue,
1256                RenderQueueGroupID group, Real camDistanceSquared)
1257        {
1258                // Determine the current material technique
1259                mTechnique = mMaterial->getTechnique(
1260                        mMaterial->getLodIndexSquaredDepth(camDistanceSquared));
1261
1262                GeometryBucketList::iterator i, iend;
1263                iend =  mGeometryBucketList.end();
1264                for (i = mGeometryBucketList.begin(); i != iend; ++i)
1265                {
1266                        queue->addRenderable(*i, group);
1267                }
1268
1269        }
1270        //--------------------------------------------------------------------------
1271        String StaticGeometry::MaterialBucket::getGeometryFormatString(
1272                SubMeshLodGeometryLink* geom)
1273        {
1274                // Formulate an identifying string for the geometry format
1275                // Must take into account the vertex declaration and the index type
1276                // Format is (all lines separated by '|'):
1277                // Index type
1278                // Vertex element (repeating)
1279                //   source
1280                //   semantic
1281                //   type
1282                StringUtil::StrStreamType str;
1283
1284                str << geom->indexData->indexBuffer->getType() << "|";
1285                const VertexDeclaration::VertexElementList& elemList =
1286                        geom->vertexData->vertexDeclaration->getElements();
1287                VertexDeclaration::VertexElementList::const_iterator ei, eiend;
1288                eiend = elemList.end();
1289                for (ei = elemList.begin(); ei != eiend; ++ei)
1290                {
1291                        const VertexElement& elem = *ei;
1292                        str << elem.getSource() << "|";
1293                        str << elem.getSource() << "|";
1294                        str << elem.getSemantic() << "|";
1295                        str << elem.getType() << "|";
1296                }
1297               
1298                return str.str();
1299
1300        }
1301        //--------------------------------------------------------------------------
1302        StaticGeometry::MaterialBucket::GeometryIterator
1303        StaticGeometry::MaterialBucket::getGeometryIterator(void)
1304        {
1305                return GeometryIterator(
1306                        mGeometryBucketList.begin(), mGeometryBucketList.end());
1307        }
1308        //--------------------------------------------------------------------------
1309        void StaticGeometry::MaterialBucket::dump(std::ofstream& of) const
1310        {
1311                of << "Material Bucket " << mMaterialName << std::endl;
1312                of << "--------------------------------------------------" << std::endl;
1313                of << "Geometry buckets: " << mGeometryBucketList.size() << std::endl;
1314                for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin();
1315                        i != mGeometryBucketList.end(); ++i)
1316                {
1317                        (*i)->dump(of);
1318                }
1319                of << "--------------------------------------------------" << std::endl;
1320               
1321        }
1322        //--------------------------------------------------------------------------
1323        //--------------------------------------------------------------------------
1324        StaticGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent,
1325                const String& formatString, const VertexData* vData,
1326                const IndexData* iData)
1327                : Renderable(), mParent(parent), mFormatString(formatString)
1328        {
1329                // Clone the structure from the example
1330                mVertexData = vData->clone(false);
1331                mIndexData = iData->clone(false);
1332                mVertexData->vertexCount = 0;
1333                mVertexData->vertexStart = 0;
1334                mIndexData->indexCount = 0;
1335                mIndexData->indexStart = 0;
1336                mIndexType = iData->indexBuffer->getType();
1337                // Derive the max vertices
1338                if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1339                {
1340                        mMaxVertexIndex = 0xFFFFFFFF;
1341                }
1342                else
1343                {
1344                        mMaxVertexIndex = 0xFFFF;
1345                }
1346
1347                // Check to see if we have blend indices / blend weights
1348                // remove them if so, they can try to blend non-existent bones!
1349                const VertexElement* blendIndices =
1350                        mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
1351                const VertexElement* blendWeights =
1352                        mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
1353                if (blendIndices && blendWeights)
1354                {
1355                        assert(blendIndices->getSource() == blendWeights->getSource()
1356                                && "Blend indices and weights should be in the same buffer");
1357                        // Get the source
1358                        ushort source = blendIndices->getSource();
1359                        assert(blendIndices->getSize() + blendWeights->getSize() ==
1360                                mVertexData->vertexBufferBinding->getBuffer(source)->getVertexSize()
1361                                && "Blend indices and blend buffers should have buffer to themselves!");
1362                        // Unset the buffer
1363                        mVertexData->vertexBufferBinding->unsetBinding(source);
1364                        // Remove the elements
1365                        mVertexData->vertexDeclaration->removeElement(VES_BLEND_INDICES);
1366                        mVertexData->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
1367
1368
1369                }
1370
1371
1372        }
1373        //--------------------------------------------------------------------------
1374        StaticGeometry::GeometryBucket::~GeometryBucket()
1375        {
1376                delete mVertexData;
1377                delete mIndexData;
1378        }
1379        //--------------------------------------------------------------------------
1380        const MaterialPtr& StaticGeometry::GeometryBucket::getMaterial(void) const
1381        {
1382                return mParent->getMaterial();
1383        }
1384        //--------------------------------------------------------------------------
1385        Technique* StaticGeometry::GeometryBucket::getTechnique(void) const
1386        {
1387                return mParent->getCurrentTechnique();
1388        }
1389        //--------------------------------------------------------------------------
1390        void StaticGeometry::GeometryBucket::getRenderOperation(RenderOperation& op)
1391        {
1392                op.indexData = mIndexData;
1393                op.operationType = RenderOperation::OT_TRIANGLE_LIST;
1394                op.srcRenderable = this;
1395                op.useIndexes = true;
1396                op.vertexData = mVertexData;
1397        }
1398        //--------------------------------------------------------------------------
1399        void StaticGeometry::GeometryBucket::getWorldTransforms(Matrix4* xform) const
1400        {
1401                // Should be the identity transform, but lets allow transformation of the
1402                // nodes the regions are attached to for kicks
1403                *xform = mParent->getParent()->getParent()->_getParentNodeFullTransform();
1404        }
1405        //--------------------------------------------------------------------------
1406        const Quaternion& StaticGeometry::GeometryBucket::getWorldOrientation(void) const
1407        {
1408                return Quaternion::IDENTITY;
1409        }
1410        //--------------------------------------------------------------------------
1411        const Vector3& StaticGeometry::GeometryBucket::getWorldPosition(void) const
1412        {
1413                return mParent->getParent()->getParent()->getCentre();
1414        }
1415        //--------------------------------------------------------------------------
1416        Real StaticGeometry::GeometryBucket::getSquaredViewDepth(const Camera* cam) const
1417        {
1418                return mParent->getParent()->getSquaredDistance();
1419        }
1420        //--------------------------------------------------------------------------
1421        const LightList& StaticGeometry::GeometryBucket::getLights(void) const
1422        {
1423                return mParent->getParent()->getParent()->getLights();
1424        }
1425        //--------------------------------------------------------------------------
1426        bool StaticGeometry::GeometryBucket::getCastsShadows(void) const
1427        {
1428                return mParent->getParent()->getParent()->getCastShadows();
1429        }
1430        //--------------------------------------------------------------------------
1431        bool StaticGeometry::GeometryBucket::assign(QueuedGeometry* qgeom)
1432        {
1433                // Do we have enough space?
1434                if (mVertexData->vertexCount + qgeom->geometry->vertexData->vertexCount
1435                        > mMaxVertexIndex)
1436                {
1437                        return false;
1438                }
1439
1440                mQueuedGeometry.push_back(qgeom);
1441                mVertexData->vertexCount += qgeom->geometry->vertexData->vertexCount;
1442                mIndexData->indexCount += qgeom->geometry->indexData->indexCount;
1443
1444                return true;
1445        }
1446        //--------------------------------------------------------------------------
1447        void StaticGeometry::GeometryBucket::build(bool stencilShadows)
1448        {
1449                // Ok, here's where we transfer the vertices and indexes to the shared
1450                // buffers
1451                // Shortcuts
1452                VertexDeclaration* dcl = mVertexData->vertexDeclaration;
1453                VertexBufferBinding* binds = mVertexData->vertexBufferBinding;
1454
1455                // create index buffer, and lock
1456                mIndexData->indexBuffer = HardwareBufferManager::getSingleton()
1457                        .createIndexBuffer(mIndexType, mIndexData->indexCount,
1458                                HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1459                uint32* p32Dest = 0;
1460                uint16* p16Dest = 0;
1461                if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1462                {
1463                        p32Dest = static_cast<uint32*>(
1464                                mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1465                }
1466                else
1467                {
1468                        p16Dest = static_cast<uint16*>(
1469                                mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1470                }
1471                // create all vertex buffers, and lock
1472                ushort b;
1473                ushort posBufferIdx = dcl->findElementBySemantic(VES_POSITION)->getSource();
1474
1475                std::vector<uchar*> destBufferLocks;
1476                std::vector<VertexDeclaration::VertexElementList> bufferElements;
1477                for (b = 0; b < binds->getBufferCount(); ++b)
1478                {
1479                        size_t vertexCount = mVertexData->vertexCount;
1480                        // Need to double the vertex count for the position buffer
1481                        // if we're doing stencil shadows
1482                        if (stencilShadows && b == posBufferIdx)
1483                        {
1484                                vertexCount = vertexCount * 2;
1485                                assert(vertexCount <= mMaxVertexIndex &&
1486                                        "Index range exceeded when using stencil shadows, consider "
1487                                        "reducing your region size or reducing poly count");
1488                        }
1489                        HardwareVertexBufferSharedPtr vbuf =
1490                                HardwareBufferManager::getSingleton().createVertexBuffer(
1491                                        dcl->getVertexSize(b),
1492                                        vertexCount,
1493                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1494                        binds->setBinding(b, vbuf);
1495                        uchar* pLock = static_cast<uchar*>(
1496                                vbuf->lock(HardwareBuffer::HBL_DISCARD));
1497                        destBufferLocks.push_back(pLock);
1498                        // Pre-cache vertex elements per buffer
1499                        bufferElements.push_back(dcl->findElementsBySource(b));
1500                }
1501
1502
1503                // Iterate over the geometry items
1504                size_t indexOffset = 0;
1505                QueuedGeometryList::iterator gi, giend;
1506                giend = mQueuedGeometry.end();
1507                Vector3 regionCentre = mParent->getParent()->getParent()->getCentre();
1508                for (gi = mQueuedGeometry.begin(); gi != giend; ++gi)
1509                {
1510                        QueuedGeometry* geom = *gi;
1511                        // Copy indexes across with offset
1512                        IndexData* srcIdxData = geom->geometry->indexData;
1513                        if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1514                        {
1515                                // Lock source indexes
1516                                uint32* pSrc = static_cast<uint32*>(
1517                                        srcIdxData->indexBuffer->lock(
1518                                                srcIdxData->indexStart, srcIdxData->indexCount,
1519                                                HardwareBuffer::HBL_READ_ONLY));
1520
1521                                copyIndexes(pSrc, p32Dest, srcIdxData->indexCount, indexOffset);
1522                                p32Dest += srcIdxData->indexCount;
1523                                srcIdxData->indexBuffer->unlock();
1524                        }
1525                        else
1526                        {
1527                                // Lock source indexes
1528                                uint16* pSrc = static_cast<uint16*>(
1529                                        srcIdxData->indexBuffer->lock(
1530                                        srcIdxData->indexStart, srcIdxData->indexCount,
1531                                        HardwareBuffer::HBL_READ_ONLY));
1532
1533                                copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset);
1534                                p16Dest += srcIdxData->indexCount;
1535                                srcIdxData->indexBuffer->unlock();
1536                        }
1537
1538                        // Now deal with vertex buffers
1539                        // we can rely on buffer counts / formats being the same
1540                        VertexData* srcVData = geom->geometry->vertexData;
1541                        VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding;
1542                        for (b = 0; b < binds->getBufferCount(); ++b)
1543                        {
1544                                // lock source
1545                                HardwareVertexBufferSharedPtr srcBuf =
1546                                        srcBinds->getBuffer(b);
1547                                uchar* pSrcBase = static_cast<uchar*>(
1548                                        srcBuf->lock(HardwareBuffer::HBL_READ_ONLY));
1549                                // Get buffer lock pointer, we'll update this later
1550                                uchar* pDstBase = destBufferLocks[b];
1551                                size_t bufInc = srcBuf->getVertexSize();
1552                               
1553                                // Iterate over vertices
1554                                float *pSrcReal, *pDstReal;
1555                                Vector3 tmp;
1556                                for (size_t v = 0; v < srcVData->vertexCount; ++v)
1557                                {
1558                                        // Iterate over vertex elements
1559                                        VertexDeclaration::VertexElementList& elems =
1560                                                bufferElements[b];
1561                                        VertexDeclaration::VertexElementList::iterator ei;
1562                                        for (ei = elems.begin(); ei != elems.end(); ++ei)
1563                                        {
1564                                                VertexElement& elem = *ei;
1565                                                elem.baseVertexPointerToElement(pSrcBase, &pSrcReal);
1566                                                elem.baseVertexPointerToElement(pDstBase, &pDstReal);
1567                                                switch (elem.getSemantic())
1568                                                {
1569                                                case VES_POSITION:
1570                                                        tmp.x = *pSrcReal++;
1571                                                        tmp.y = *pSrcReal++;
1572                                                        tmp.z = *pSrcReal++;
1573                                                        // transform
1574                                                        tmp = (geom->orientation * (tmp * geom->scale)) +
1575                                                                geom->position;
1576                                                        // Adjust for region centre
1577                                                        tmp -= regionCentre;
1578                                                        *pDstReal++ = tmp.x;
1579                                                        *pDstReal++ = tmp.y;
1580                                                        *pDstReal++ = tmp.z;
1581                                                        break;         
1582                                                case VES_NORMAL:
1583                                                        tmp.x = *pSrcReal++;
1584                                                        tmp.y = *pSrcReal++;
1585                                                        tmp.z = *pSrcReal++;
1586                                                        // rotation only
1587                                                        tmp = geom->orientation * tmp;
1588                                                        *pDstReal++ = tmp.x;
1589                                                        *pDstReal++ = tmp.y;
1590                                                        *pDstReal++ = tmp.z;
1591                                                        break; 
1592                                                default:
1593                                                        // just raw copy
1594                                                        memcpy(pDstReal, pSrcReal,
1595                                                                        VertexElement::getTypeSize(elem.getType()));
1596                                                        break;
1597                                                };
1598                                       
1599                                        }
1600
1601                                        // Increment both pointers
1602                                        pDstBase += bufInc;
1603                                        pSrcBase += bufInc;
1604                                       
1605                                }
1606
1607                                // Update pointer
1608                                destBufferLocks[b] = pDstBase;
1609                                srcBuf->unlock();
1610                        }
1611
1612                        indexOffset += geom->geometry->vertexData->vertexCount;
1613                }
1614
1615                // Unlock everything
1616                mIndexData->indexBuffer->unlock();
1617                for (b = 0; b < binds->getBufferCount(); ++b)
1618                {
1619                        binds->getBuffer(b)->unlock();
1620                }
1621
1622                // If we're dealing with stencil shadows, copy the position data from
1623                // the early half of the buffer to the latter part
1624                if (stencilShadows)
1625                {
1626                        HardwareVertexBufferSharedPtr buf = binds->getBuffer(posBufferIdx);
1627                        void* pSrc = buf->lock(HardwareBuffer::HBL_NORMAL);
1628                        // Point dest at second half (remember vertexcount is original count)
1629                        void* pDest = static_cast<uchar*>(pSrc) +
1630                                buf->getVertexSize() * mVertexData->vertexCount;
1631                        memcpy(pDest, pSrc, buf->getVertexSize() * mVertexData->vertexCount);
1632                        buf->unlock();
1633
1634                        // Also set up hardware W buffer if appropriate
1635                        RenderSystem* rend = Root::getSingleton().getRenderSystem();
1636                        if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
1637                        {
1638                                buf = HardwareBufferManager::getSingleton().createVertexBuffer(
1639                                        sizeof(float), mVertexData->vertexCount * 2,
1640                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
1641                                // Fill the first half with 1.0, second half with 0.0
1642                                float *pW = static_cast<float*>(
1643                                        buf->lock(HardwareBuffer::HBL_DISCARD));
1644                                size_t v;
1645                                for (v = 0; v < mVertexData->vertexCount; ++v)
1646                                {
1647                                        *pW++ = 1.0f;
1648                                }
1649                                for (v = 0; v < mVertexData->vertexCount; ++v)
1650                                {
1651                                        *pW++ = 0.0f;
1652                                }
1653                                buf->unlock();
1654                                mVertexData->hardwareShadowVolWBuffer = buf;
1655                        }
1656                }
1657
1658        }
1659        //--------------------------------------------------------------------------
1660        void StaticGeometry::GeometryBucket::dump(std::ofstream& of) const
1661        {
1662                of << "Geometry Bucket" << std::endl;
1663                of << "---------------" << std::endl;
1664                of << "Format string: " << mFormatString << std::endl;
1665                of << "Geometry items: " << mQueuedGeometry.size() << std::endl;
1666                of << "Vertex count: " << mVertexData->vertexCount << std::endl;
1667                of << "Index count: " << mIndexData->indexCount << std::endl;
1668                of << "---------------" << std::endl;
1669               
1670        }
1671        //--------------------------------------------------------------------------
1672
1673}
1674
Note: See TracBrowser for help on using the repository browser.