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

Revision 692, 56.2 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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