Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/OgreMain/src/OgreStaticGeometry.cpp @ 3

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

=update

File size: 54.8 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23
24You may alternatively use this source under the terms of a specific version of
25the OGRE Unrestricted License provided you have obtained such a license from
26Torus Knot Software Ltd.
27-----------------------------------------------------------------------------
28*/
29#include "OgreStableHeaders.h"
30#include "OgreStaticGeometry.h"
31#include "OgreEntity.h"
32#include "OgreSubEntity.h"
33#include "OgreSceneNode.h"
34#include "OgreException.h"
35#include "OgreMesh.h"
36#include "OgreSubMesh.h"
37#include "OgreLogManager.h"
38#include "OgreSceneManager.h"
39#include "OgreCamera.h"
40#include "OgreMaterialManager.h"
41#include "OgreRoot.h"
42#include "OgreRenderSystem.h"
43#include "OgreEdgeListBuilder.h"
44
45namespace Ogre {
46
47        #define REGION_RANGE 1024
48        #define REGION_HALF_RANGE 512
49        #define REGION_MAX_INDEX 511
50        #define REGION_MIN_INDEX -512
51
52        //--------------------------------------------------------------------------
53        StaticGeometry::StaticGeometry(SceneManager* owner, const String& name):
54                mOwner(owner),
55                mName(name),
56                mBuilt(false),
57                mUpperDistance(0.0f),
58                mSquaredUpperDistance(0.0f),
59                mCastShadows(false),
60                mRegionDimensions(Vector3(1000,1000,1000)),
61                mHalfRegionDimensions(Vector3(500,500,500)),
62                mOrigin(Vector3(0,0,0)),
63                mVisible(true),
64        mRenderQueueID(RENDER_QUEUE_MAIN),
65        mRenderQueueIDSet(false)
66        {
67        }
68        //--------------------------------------------------------------------------
69        StaticGeometry::~StaticGeometry()
70        {
71                reset();
72        }
73        //--------------------------------------------------------------------------
74        StaticGeometry::Region* StaticGeometry::getRegion(const AxisAlignedBox& bounds,
75                bool autoCreate)
76        {
77                if (bounds.isNull())
78                        return 0;
79
80                // Get the region which has the largest overlapping volume
81                const Vector3 min = bounds.getMinimum();
82                const Vector3 max = bounds.getMaximum();
83
84                // Get the min and max region indexes
85                ushort minx, miny, minz;
86                ushort maxx, maxy, maxz;
87                getRegionIndexes(min, minx, miny, minz);
88                getRegionIndexes(max, maxx, maxy, maxz);
89                Real maxVolume = 0.0f;
90                ushort finalx, finaly, finalz;
91                for (ushort x = minx; x <= maxx; ++x)
92                {
93                        for (ushort y = miny; y <= maxy; ++y)
94                        {
95                                for (ushort z = minz; z <= maxz; ++z)
96                                {
97                                        Real vol = getVolumeIntersection(bounds, x, y, z);
98                                        if (vol > maxVolume)
99                                        {
100                                                maxVolume = vol;
101                                                finalx = x;
102                                                finaly = y;
103                                                finalz = z;
104                                        }
105
106                                }
107                        }
108                }
109
110                assert(maxVolume > 0.0f &&
111                        "Static geometry: Problem determining closest volume match!");
112
113                return getRegion(finalx, finaly, finalz, autoCreate);
114
115        }
116        //--------------------------------------------------------------------------
117        Real StaticGeometry::getVolumeIntersection(const AxisAlignedBox& box,
118                ushort x, ushort y, ushort z)
119        {
120                // Get bounds of indexed region
121                AxisAlignedBox regionBounds = getRegionBounds(x, y, z);
122                AxisAlignedBox intersectBox = regionBounds.intersection(box);
123                // return a 'volume' which ignores zero dimensions
124                // since we only use this for relative comparisons of the same bounds
125                // this will still be internally consistent
126                Vector3 boxdiff = box.getMaximum() - box.getMinimum();
127                Vector3 intersectDiff = intersectBox.getMaximum() - intersectBox.getMinimum();
128
129                return (boxdiff.x == 0 ? 1 : intersectDiff.x) *
130                        (boxdiff.y == 0 ? 1 : intersectDiff.y) *
131                        (boxdiff.z == 0 ? 1 : intersectDiff.z);
132
133        }
134        //--------------------------------------------------------------------------
135        AxisAlignedBox StaticGeometry::getRegionBounds(ushort x, ushort y, ushort z)
136        {
137                Vector3 min(
138                        ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x,
139                        ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y,
140                        ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z
141                        );
142                Vector3 max = min + mRegionDimensions;
143                return AxisAlignedBox(min, max);
144        }
145        //--------------------------------------------------------------------------
146        Vector3 StaticGeometry::getRegionCentre(ushort x, ushort y, ushort z)
147        {
148                return Vector3(
149                        ((Real)x - REGION_HALF_RANGE) * mRegionDimensions.x + mOrigin.x
150                                + mHalfRegionDimensions.x,
151                        ((Real)y - REGION_HALF_RANGE) * mRegionDimensions.y + mOrigin.y
152                                + mHalfRegionDimensions.y,
153                        ((Real)z - REGION_HALF_RANGE) * mRegionDimensions.z + mOrigin.z
154                                + mHalfRegionDimensions.z
155                        );
156        }
157        //--------------------------------------------------------------------------
158        StaticGeometry::Region* StaticGeometry::getRegion(
159                        ushort x, ushort y, ushort z, bool autoCreate)
160        {
161                uint32 index = packIndex(x, y, z);
162                Region* ret = getRegion(index);
163                if (!ret && autoCreate)
164                {
165                        // Make a name
166                        StringUtil::StrStreamType str;
167                        str << mName << ":" << index;
168                        // Calculate the region centre
169                        Vector3 centre = getRegionCentre(x, y, z);
170                        ret = new Region(this, str.str(), mOwner, index, centre);
171                        mOwner->injectMovableObject(ret);
172                        ret->setVisible(mVisible);
173                        ret->setCastShadows(mCastShadows);
174                        if (mRenderQueueIDSet)
175                        {
176                                ret->setRenderQueueGroup(mRenderQueueID);
177                        }
178                        mRegionMap[index] = ret;
179                }
180                return ret;
181        }
182        //--------------------------------------------------------------------------
183        StaticGeometry::Region* StaticGeometry::getRegion(uint32 index)
184        {
185                RegionMap::iterator i = mRegionMap.find(index);
186                if (i != mRegionMap.end())
187                {
188                        return i->second;
189                }
190                else
191                {
192                        return 0;
193                }
194
195        }
196        //--------------------------------------------------------------------------
197        void StaticGeometry::getRegionIndexes(const Vector3& point,
198                ushort& x, ushort& y, ushort& z)
199        {
200                // Scale the point into multiples of region and adjust for origin
201                Vector3 scaledPoint = (point - mOrigin) / mRegionDimensions;
202
203                // Round down to 'bottom left' point which represents the cell index
204                int ix = Math::IFloor(scaledPoint.x);
205                int iy = Math::IFloor(scaledPoint.y);
206                int iz = Math::IFloor(scaledPoint.z);
207
208                // Check bounds
209                if (ix < REGION_MIN_INDEX || ix > REGION_MAX_INDEX
210                        || iy < REGION_MIN_INDEX || iy > REGION_MAX_INDEX
211                        || iz < REGION_MIN_INDEX || iz > REGION_MAX_INDEX)
212                {
213                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
214                                "Point out of bounds",
215                                "StaticGeometry::getRegionIndexes");
216                }
217                // Adjust for the fact that we use unsigned values for simplicity
218                // (requires less faffing about for negatives give 10-bit packing
219                x = static_cast<ushort>(ix + REGION_HALF_RANGE);
220                y = static_cast<ushort>(iy + REGION_HALF_RANGE);
221                z = static_cast<ushort>(iz + REGION_HALF_RANGE);
222
223
224        }
225        //--------------------------------------------------------------------------
226        uint32 StaticGeometry::packIndex(ushort x, ushort y, ushort z)
227        {
228                return x + (y << 10) + (z << 20);
229        }
230        //--------------------------------------------------------------------------
231        StaticGeometry::Region* StaticGeometry::getRegion(const Vector3& point,
232                bool autoCreate)
233        {
234                ushort x, y, z;
235                getRegionIndexes(point, x, y, z);
236                return getRegion(x, y, z, autoCreate);
237        }
238        //--------------------------------------------------------------------------
239        AxisAlignedBox StaticGeometry::calculateBounds(VertexData* vertexData,
240                const Vector3& position, const Quaternion& orientation,
241                const Vector3& scale)
242        {
243                const VertexElement* posElem =
244                        vertexData->vertexDeclaration->findElementBySemantic(
245                                VES_POSITION);
246                HardwareVertexBufferSharedPtr vbuf =
247                        vertexData->vertexBufferBinding->getBuffer(posElem->getSource());
248                unsigned char* vertex =
249                        static_cast<unsigned char*>(
250                                vbuf->lock(HardwareBuffer::HBL_READ_ONLY));
251                float* pFloat;
252
253                Vector3 min, max;
254                bool first = true;
255
256                for(size_t j = 0; j < vertexData->vertexCount; ++j, vertex += vbuf->getVertexSize())
257                {
258                        posElem->baseVertexPointerToElement(vertex, &pFloat);
259
260                        Vector3 pt;
261
262                        pt.x = (*pFloat++);
263                        pt.y = (*pFloat++);
264                        pt.z = (*pFloat++);
265                        // Transform to world (scale, rotate, translate)
266                        pt = (orientation * (pt * scale)) + position;
267                        if (first)
268                        {
269                                min = max = pt;
270                                first = false;
271                        }
272                        else
273                        {
274                                min.makeFloor(pt);
275                                max.makeCeil(pt);
276                        }
277
278                }
279                vbuf->unlock();
280                return AxisAlignedBox(min, max);
281        }
282        //--------------------------------------------------------------------------
283        void StaticGeometry::addEntity(Entity* ent, const Vector3& position,
284                const Quaternion& orientation, const Vector3& scale)
285        {
286                const MeshPtr& msh = ent->getMesh();
287                // Validate
288                if (msh->isLodManual())
289                {
290                        LogManager::getSingleton().logMessage(
291                                "WARNING (StaticGeometry): Manual LOD is not supported. "
292                                "Using only highest LOD level for mesh " + msh->getName());
293                }
294
295                AxisAlignedBox sharedWorldBounds;
296                // queue this entities submeshes and choice of material
297                // also build the lists of geometry to be used for the source of lods
298                for (uint i = 0; i < ent->getNumSubEntities(); ++i)
299                {
300                        SubEntity* se = ent->getSubEntity(i);
301                        QueuedSubMesh* q = new QueuedSubMesh();
302
303                        // Get the geometry for this SubMesh
304                        q->submesh = se->getSubMesh();
305                        q->geometryLodList = determineGeometry(q->submesh);
306                        q->materialName = se->getMaterialName();
307                        q->orientation = orientation;
308                        q->position = position;
309                        q->scale = scale;
310                        // Determine the bounds based on the highest LOD
311                        q->worldBounds = calculateBounds(
312                                (*q->geometryLodList)[0].vertexData,
313                                        position, orientation, scale);
314
315                        mQueuedSubMeshes.push_back(q);
316                }
317        }
318        //--------------------------------------------------------------------------
319        StaticGeometry::SubMeshLodGeometryLinkList*
320        StaticGeometry::determineGeometry(SubMesh* sm)
321        {
322                // First, determine if we've already seen this submesh before
323                SubMeshGeometryLookup::iterator i =
324                        mSubMeshGeometryLookup.find(sm);
325                if (i != mSubMeshGeometryLookup.end())
326                {
327                        return i->second;
328                }
329                // Otherwise, we have to create a new one
330                SubMeshLodGeometryLinkList* lodList = new SubMeshLodGeometryLinkList();
331                mSubMeshGeometryLookup[sm] = lodList;
332                ushort numLods = sm->parent->isLodManual() ? 1 :
333                        sm->parent->getNumLodLevels();
334                lodList->resize(numLods);
335                for (ushort lod = 0; lod < numLods; ++lod)
336                {
337                        SubMeshLodGeometryLink& geomLink = (*lodList)[lod];
338                        IndexData *lodIndexData;
339                        if (lod == 0)
340                        {
341                                lodIndexData = sm->indexData;
342                        }
343                        else
344                        {
345                                lodIndexData = sm->mLodFaceList[lod - 1];
346                        }
347                        // Can use the original mesh geometry?
348                        if (sm->useSharedVertices)
349                        {
350                                if (sm->parent->getNumSubMeshes() == 1)
351                                {
352                                        // Ok, this is actually our own anyway
353                                        geomLink.vertexData = sm->parent->sharedVertexData;
354                                        geomLink.indexData = lodIndexData;
355                                }
356                                else
357                                {
358                                        // We have to split it
359                                        splitGeometry(sm->parent->sharedVertexData,
360                                                lodIndexData, &geomLink);
361                                }
362                        }
363                        else
364                        {
365                                if (lod == 0)
366                                {
367                                        // Ok, we can use the existing geometry; should be in full
368                                        // use by just this SubMesh
369                                        geomLink.vertexData = sm->vertexData;
370                                        geomLink.indexData = sm->indexData;
371                                }
372                                else
373                                {
374                                        // We have to split it
375                                        splitGeometry(sm->vertexData,
376                                                lodIndexData, &geomLink);
377                                }
378                        }
379                        assert (geomLink.vertexData->vertexStart == 0 &&
380                                "Cannot use vertexStart > 0 on indexed geometry due to "
381                                "rendersystem incompatibilities - see the docs!");
382                }
383
384
385                return lodList;
386        }
387        //--------------------------------------------------------------------------
388        void StaticGeometry::splitGeometry(VertexData* vd, IndexData* id,
389                        StaticGeometry::SubMeshLodGeometryLink* targetGeomLink)
390        {
391                // Firstly we need to scan to see how many vertices are being used
392                // and while we're at it, build the remap we can use later
393                bool use32bitIndexes =
394                        id->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT;
395                uint16 *p16;
396                uint32 *p32;
397                IndexRemap indexRemap;
398                if (use32bitIndexes)
399                {
400                        p32 = static_cast<uint32*>(id->indexBuffer->lock(
401                                id->indexStart, 
402                                id->indexCount * id->indexBuffer->getIndexSize(), 
403                                HardwareBuffer::HBL_READ_ONLY));
404                        buildIndexRemap(p32, id->indexCount, indexRemap);
405                        id->indexBuffer->unlock();
406                }
407                else
408                {
409                        p16 = static_cast<uint16*>(id->indexBuffer->lock(
410                                id->indexStart, 
411                                id->indexCount * id->indexBuffer->getIndexSize(), 
412                                HardwareBuffer::HBL_READ_ONLY));
413                        buildIndexRemap(p16, id->indexCount, indexRemap);
414                        id->indexBuffer->unlock();
415                }
416                if (indexRemap.size() == vd->vertexCount)
417                {
418                        // ha, complete usage after all
419                        targetGeomLink->vertexData = vd;
420                        targetGeomLink->indexData = id;
421                        return;
422                }
423
424
425                // Create the new vertex data records
426                targetGeomLink->vertexData = vd->clone(false);
427                // Convenience
428                VertexData* newvd = targetGeomLink->vertexData;
429                //IndexData* newid = targetGeomLink->indexData;
430                // Update the vertex count
431                newvd->vertexCount = indexRemap.size();
432
433                size_t numvbufs = vd->vertexBufferBinding->getBufferCount();
434                // Copy buffers from old to new
435                for (unsigned short b = 0; b < numvbufs; ++b)
436                {
437                        // Lock old buffer
438                        HardwareVertexBufferSharedPtr oldBuf =
439                                vd->vertexBufferBinding->getBuffer(b);
440                        // Create new buffer
441                        HardwareVertexBufferSharedPtr newBuf =
442                                HardwareBufferManager::getSingleton().createVertexBuffer(
443                                        oldBuf->getVertexSize(),
444                                        indexRemap.size(),
445                                        HardwareBuffer::HBU_STATIC);
446                        // rebind
447                        newvd->vertexBufferBinding->setBinding(b, newBuf);
448
449                        // Copy all the elements of the buffer across, by iterating over
450                        // the IndexRemap which describes how to move the old vertices
451                        // to the new ones. By nature of the map the remap is in order of
452                        // indexes in the old buffer, but note that we're not guaranteed to
453                        // address every vertex (which is kinda why we're here)
454                        uchar* pSrcBase = static_cast<uchar*>(
455                                oldBuf->lock(HardwareBuffer::HBL_READ_ONLY));
456                        uchar* pDstBase = static_cast<uchar*>(
457                                newBuf->lock(HardwareBuffer::HBL_DISCARD));
458                        size_t vertexSize = oldBuf->getVertexSize();
459                        // Buffers should be the same size
460                        assert (vertexSize == newBuf->getVertexSize());
461
462                        for (IndexRemap::iterator r = indexRemap.begin();
463                                r != indexRemap.end(); ++r)
464                        {
465                                assert (r->first < oldBuf->getNumVertices());
466                                assert (r->second < newBuf->getNumVertices());
467
468                                uchar* pSrc = pSrcBase + r->first * vertexSize;
469                                uchar* pDst = pDstBase + r->second * vertexSize;
470                                memcpy(pDst, pSrc, vertexSize);
471                        }
472                        // unlock
473                        oldBuf->unlock();
474                        newBuf->unlock();
475
476                }
477
478                // Now create a new index buffer
479                HardwareIndexBufferSharedPtr ibuf =
480                        HardwareBufferManager::getSingleton().createIndexBuffer(
481                                id->indexBuffer->getType(), id->indexCount,
482                                HardwareBuffer::HBU_STATIC);
483
484                if (use32bitIndexes)
485                {
486                        uint32 *pSrc32, *pDst32;
487                        pSrc32 = static_cast<uint32*>(id->indexBuffer->lock(
488                                id->indexStart, 
489                                id->indexCount * id->indexBuffer->getIndexSize(), 
490                                HardwareBuffer::HBL_READ_ONLY));
491                        pDst32 = static_cast<uint32*>(ibuf->lock(
492                                HardwareBuffer::HBL_DISCARD));
493                        remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount);
494                        id->indexBuffer->unlock();
495                        ibuf->unlock();
496                }
497                else
498                {
499                        uint16 *pSrc16, *pDst16;
500                        pSrc16 = static_cast<uint16*>(id->indexBuffer->lock(
501                                id->indexStart, 
502                                id->indexCount * id->indexBuffer->getIndexSize(), 
503                                HardwareBuffer::HBL_READ_ONLY));
504                        pDst16 = static_cast<uint16*>(ibuf->lock(
505                                HardwareBuffer::HBL_DISCARD));
506                        remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount);
507                        id->indexBuffer->unlock();
508                        ibuf->unlock();
509                }
510
511                targetGeomLink->indexData = new IndexData();
512                targetGeomLink->indexData->indexStart = 0;
513                targetGeomLink->indexData->indexCount = id->indexCount;
514                targetGeomLink->indexData->indexBuffer = ibuf;
515
516                // Store optimised geometry for deallocation later
517                OptimisedSubMeshGeometry *optGeom = new OptimisedSubMeshGeometry();
518                optGeom->indexData = targetGeomLink->indexData;
519                optGeom->vertexData = targetGeomLink->vertexData;
520                mOptimisedSubMeshGeometryList.push_back(optGeom);
521        }
522        //--------------------------------------------------------------------------
523        void StaticGeometry::addSceneNode(const SceneNode* node)
524        {
525                SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator();
526                while (obji.hasMoreElements())
527                {
528                        MovableObject* mobj = obji.getNext();
529                        if (mobj->getMovableType() == "Entity")
530                        {
531                                addEntity(static_cast<Entity*>(mobj),
532                                        node->_getDerivedPosition(),
533                                        node->_getDerivedOrientation(),
534                                        node->_getDerivedScale());
535                        }
536                }
537                // Iterate through all the child-nodes
538                SceneNode::ConstChildNodeIterator nodei = node->getChildIterator();
539
540                while (nodei.hasMoreElements())
541                {
542                        const SceneNode* node = static_cast<const SceneNode*>(nodei.getNext());
543                        // Add this subnode and its children...
544                        addSceneNode( node );
545                }
546        }
547        //--------------------------------------------------------------------------
548        void StaticGeometry::build(void)
549        {
550                // Make sure there's nothing from previous builds
551                destroy();
552
553                // Firstly allocate meshes to regions
554                for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin();
555                        qi != mQueuedSubMeshes.end(); ++qi)
556                {
557                        QueuedSubMesh* qsm = *qi;
558                        Region* region = getRegion(qsm->worldBounds, true);
559                        region->assign(qsm);
560                }
561                bool stencilShadows = false;
562                if (mCastShadows && mOwner->isShadowTechniqueStencilBased())
563                {
564                        stencilShadows = true;
565                }
566
567                // Now tell each region to build itself
568                for (RegionMap::iterator ri = mRegionMap.begin();
569                        ri != mRegionMap.end(); ++ri)
570                {
571                        ri->second->build(stencilShadows);
572                }
573
574        }
575        //--------------------------------------------------------------------------
576        void StaticGeometry::destroy(void)
577        {
578                // delete the regions
579                for (RegionMap::iterator i = mRegionMap.begin();
580                        i != mRegionMap.end(); ++i)
581                {
582                        mOwner->extractMovableObject(i->second);
583                        delete i->second;
584                }
585                mRegionMap.clear();
586        }
587        //--------------------------------------------------------------------------
588        void StaticGeometry::reset(void)
589        {
590                destroy();
591                for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin();
592                        i != mQueuedSubMeshes.end(); ++i)
593                {
594                        delete *i;
595                }
596                mQueuedSubMeshes.clear();
597                // Delete precached geoemtry lists
598                for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin();
599                        l != mSubMeshGeometryLookup.end(); ++l)
600                {
601                        delete l->second;
602                }
603                mSubMeshGeometryLookup.clear();
604                // Delete optimised geometry
605                for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin();
606                        o != mOptimisedSubMeshGeometryList.end(); ++o)
607                {
608                        delete *o;
609                }
610                mOptimisedSubMeshGeometryList.clear();
611
612        }
613        //--------------------------------------------------------------------------
614        void StaticGeometry::setVisible(bool visible)
615        {
616                mVisible = visible;
617                // tell any existing regions
618                for (RegionMap::iterator ri = mRegionMap.begin();
619                        ri != mRegionMap.end(); ++ri)
620                {
621                        ri->second->setVisible(visible);
622                }
623        }
624        //--------------------------------------------------------------------------
625        void StaticGeometry::setCastShadows(bool castShadows)
626        {
627                mCastShadows = castShadows;
628                // tell any existing regions
629                for (RegionMap::iterator ri = mRegionMap.begin();
630                        ri != mRegionMap.end(); ++ri)
631                {
632                        ri->second->setCastShadows(castShadows);
633                }
634
635        }
636        //--------------------------------------------------------------------------
637    void StaticGeometry::setRenderQueueGroup(uint8 queueID)
638        {
639                assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!");
640                mRenderQueueIDSet = true;
641                mRenderQueueID = queueID;
642                // tell any existing regions
643                for (RegionMap::iterator ri = mRegionMap.begin();
644                        ri != mRegionMap.end(); ++ri)
645                {
646                        ri->second->setRenderQueueGroup(queueID);
647                }
648        }
649        //--------------------------------------------------------------------------
650        uint8 StaticGeometry::getRenderQueueGroup(void) const
651        {
652                return mRenderQueueID;
653        }
654        //--------------------------------------------------------------------------
655        void StaticGeometry::dump(const String& filename) const
656        {
657                std::ofstream of(filename.c_str());
658                of << "Static Geometry Report for " << mName << std::endl;
659                of << "-------------------------------------------------" << std::endl;
660                of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl;
661                of << "Number of regions: " << mRegionMap.size() << std::endl;
662                of << "Region dimensions: " << mRegionDimensions << std::endl;
663                of << "Origin: " << mOrigin << std::endl;
664                of << "Max distance: " << mUpperDistance << std::endl;
665                of << "Casts shadows?: " << mCastShadows << std::endl;
666                of << std::endl;
667                for (RegionMap::const_iterator ri = mRegionMap.begin();
668                        ri != mRegionMap.end(); ++ri)
669                {
670                        ri->second->dump(of);
671                }
672                of << "-------------------------------------------------" << std::endl;
673        }
674        //--------------------------------------------------------------------------
675        StaticGeometry::RegionIterator StaticGeometry::getRegionIterator(void)
676        {
677                return RegionIterator(mRegionMap.begin(), mRegionMap.end());
678        }
679        //--------------------------------------------------------------------------
680        //--------------------------------------------------------------------------
681        StaticGeometry::Region::Region(StaticGeometry* parent, const String& name,
682                SceneManager* mgr, uint32 regionID, const Vector3& centre)
683                : MovableObject(name), mParent(parent), mSceneMgr(mgr), mNode(0),
684                mRegionID(regionID), mCentre(centre), mBoundingRadius(0.0f),
685                mCurrentLod(0), mEdgeList(0), mVertexProgramInUse(false)
686        {
687                // First LOD mandatory, and always from 0
688                mLodSquaredDistances.push_back(0.0f);
689        }
690        //--------------------------------------------------------------------------
691        StaticGeometry::Region::~Region()
692        {
693                if (mNode)
694                {
695                        mNode->getParentSceneNode()->removeChild(mNode);
696                        mSceneMgr->destroySceneNode(mNode->getName());
697                        mNode = 0;
698                }
699                // delete
700                for (LODBucketList::iterator i = mLodBucketList.begin();
701                        i != mLodBucketList.end(); ++i)
702                {
703                        delete *i;
704                }
705                mLodBucketList.clear();
706
707                for (ShadowRenderableList::iterator s = mShadowRenderables.begin();
708                        s != mShadowRenderables.end(); ++s)
709                {
710                        delete *s;
711                }
712                mShadowRenderables.clear();
713                delete mEdgeList;
714
715                // no need to delete queued meshes, these are managed in StaticGeometry
716
717        }
718        //--------------------------------------------------------------------------
719        uint32 StaticGeometry::Region::getTypeFlags(void) const
720        {
721                return SceneManager::STATICGEOMETRY_TYPE_MASK;
722        }
723        //--------------------------------------------------------------------------
724        void StaticGeometry::Region::assign(QueuedSubMesh* qmesh)
725        {
726                mQueuedSubMeshes.push_back(qmesh);
727                // update lod distances
728                ushort lodLevels = qmesh->submesh->parent->getNumLodLevels();
729                assert(qmesh->geometryLodList->size() == lodLevels);
730
731                while(mLodSquaredDistances.size() < lodLevels)
732                {
733                        mLodSquaredDistances.push_back(0.0f);
734                }
735                // Make sure LOD levels are max of all at the requested level
736                for (ushort lod = 1; lod < lodLevels; ++lod)
737                {
738                        const MeshLodUsage& meshLod =
739                                qmesh->submesh->parent->getLodLevel(lod);
740                        mLodSquaredDistances[lod] = std::max(mLodSquaredDistances[lod],
741                                meshLod.fromDepthSquared);
742                }
743
744                // update bounds
745                // Transform world bounds relative to our centre
746                AxisAlignedBox localBounds(
747                        qmesh->worldBounds.getMinimum() - mCentre,
748                        qmesh->worldBounds.getMaximum() - mCentre);
749                mAABB.merge(localBounds);
750                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMinimum().length());
751                mBoundingRadius = std::max(mBoundingRadius, localBounds.getMaximum().length());
752
753        }
754        //--------------------------------------------------------------------------
755        void StaticGeometry::Region::build(bool stencilShadows)
756        {
757                // Create a node
758                mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName,
759                        mCentre);
760                mNode->attachObject(this);
761                // We need to create enough LOD buckets to deal with the highest LOD
762                // we encountered in all the meshes queued
763                for (ushort lod = 0; lod < mLodSquaredDistances.size(); ++lod)
764                {
765                        LODBucket* lodBucket =
766                                new LODBucket(this, lod, mLodSquaredDistances[lod]);
767                        mLodBucketList.push_back(lodBucket);
768                        // Now iterate over the meshes and assign to LODs
769                        // LOD bucket will pick the right LOD to use
770                        QueuedSubMeshList::iterator qi, qiend;
771                        qiend = mQueuedSubMeshes.end();
772                        for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi)
773                        {
774                                lodBucket->assign(*qi, lod);
775                        }
776                        // now build
777                        lodBucket->build(stencilShadows);
778                }
779
780                // Do we need to build an edge list?
781                if (stencilShadows)
782                {
783                        EdgeListBuilder eb;
784                        size_t vertexSet = 0;
785                        LODIterator lodIterator = getLODIterator();
786                        while (lodIterator.hasMoreElements())
787                        {
788                                LODBucket* lod = lodIterator.getNext();
789                                LODBucket::MaterialIterator matIt = lod->getMaterialIterator();
790                                while (matIt.hasMoreElements())
791                                {
792                                        MaterialBucket* mat = matIt.getNext();
793                                        MaterialBucket::GeometryIterator geomIt =
794                                                mat->getGeometryIterator();
795                                        // Check if we have vertex programs here
796                                        Technique* t = mat->getMaterial()->getBestTechnique();
797                                        if (t)
798                                        {
799                                                Pass* p = t->getPass(0);
800                                                if (p)
801                                                {
802                                                        if (p->hasVertexProgram())
803                                                        {
804                                                                mVertexProgramInUse = true;
805                                                        }
806                                                }
807                                        }
808
809                                        while (geomIt.hasMoreElements())
810                                        {
811                                                GeometryBucket* geom = geomIt.getNext();
812
813                                                // Check we're dealing with 16-bit indexes here
814                                                // Since stencil shadows can only deal with 16-bit
815                                                // More than that and stencil is probably too CPU-heavy
816                                                // in any case
817                                                assert(geom->getIndexData()->indexBuffer->getType()
818                                                        == HardwareIndexBuffer::IT_16BIT &&
819                                                        "Only 16-bit indexes allowed when using stencil shadows");
820                                                eb.addVertexData(geom->getVertexData());
821                                                eb.addIndexData(geom->getIndexData(), vertexSet++);
822                                        }
823                                }
824                        }
825                        mEdgeList = eb.build();
826
827                }
828
829
830        }
831        //--------------------------------------------------------------------------
832        const String& StaticGeometry::Region::getMovableType(void) const
833        {
834                static String sType = "StaticGeometry";
835                return sType;
836        }
837        //--------------------------------------------------------------------------
838        void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam)
839        {
840                // Calculate squared view depth
841                Vector3 diff = cam->getDerivedPosition() - mCentre;
842                Real squaredDepth = diff.squaredLength();
843
844                // Determine whether to still render
845                Real renderingDist = mParent->getRenderingDistance();
846                if (renderingDist > 0)
847                {
848                        // Max distance to still render
849                        Real maxDist = renderingDist + mBoundingRadius;
850                        if (squaredDepth > Math::Sqr(maxDist))
851                        {
852                                mBeyondFarDistance = true;
853                                return;
854                        }
855                }
856
857                mBeyondFarDistance = false;
858
859                // Distance from the edge of the bounding sphere
860                mCamDistanceSquared = squaredDepth - mBoundingRadius * mBoundingRadius;
861                // Clamp to 0
862                mCamDistanceSquared = std::max(static_cast<Real>(0.0), mCamDistanceSquared);
863
864                // Determine active lod
865                mCurrentLod = static_cast<ushort>(mLodSquaredDistances.size() - 1);
866                for (ushort i = 0; i < mLodSquaredDistances.size(); ++i)
867                {
868                        if (mLodSquaredDistances[i] > mCamDistanceSquared)
869                        {
870                                mCurrentLod = i - 1;
871                                break;
872                        }
873                }
874
875        }
876        //--------------------------------------------------------------------------
877        const AxisAlignedBox& StaticGeometry::Region::getBoundingBox(void) const
878        {
879                return mAABB;
880        }
881        //--------------------------------------------------------------------------
882        Real StaticGeometry::Region::getBoundingRadius(void) const
883        {
884                return mBoundingRadius;
885        }
886        //--------------------------------------------------------------------------
887        void StaticGeometry::Region::_updateRenderQueue(RenderQueue* queue)
888        {
889                mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID,
890                        mCamDistanceSquared);
891        }
892        //--------------------------------------------------------------------------
893        bool StaticGeometry::Region::isVisible(void) const
894        {
895                return mVisible && !mBeyondFarDistance;
896        }
897        //--------------------------------------------------------------------------
898        StaticGeometry::Region::LODIterator
899        StaticGeometry::Region::getLODIterator(void)
900        {
901                return LODIterator(mLodBucketList.begin(), mLodBucketList.end());
902        }
903        //--------------------------------------------------------------------------
904        ShadowCaster::ShadowRenderableListIterator
905        StaticGeometry::Region::getShadowVolumeRenderableIterator(
906                ShadowTechnique shadowTechnique, const Light* light,
907                HardwareIndexBufferSharedPtr* indexBuffer,
908                bool extrude, Real extrusionDistance, unsigned long flags)
909        {
910
911                assert(indexBuffer && "Only external index buffers are supported right now");
912                assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
913                        "Only 16-bit indexes supported for now");
914
915                // Calculate the object space light details
916                Vector4 lightPos = light->getAs4DVector();
917                Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine();
918                lightPos = world2Obj.transformAffine(lightPos);
919
920                // We need to search the edge list for silhouette edges
921                if (!mEdgeList)
922                {
923                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
924                                "You enabled stencil shadows after the buid process!",
925                                "StaticGeometry::Region::getShadowVolumeRenderableIterator");
926                }
927
928                // Init shadow renderable list if required
929                bool init = mShadowRenderables.empty();
930
931                EdgeData::EdgeGroupList::iterator egi;
932                ShadowRenderableList::iterator si, siend;
933                RegionShadowRenderable* esr = 0;
934                if (init)
935                        mShadowRenderables.resize(mEdgeList->edgeGroups.size());
936
937                //bool updatedSharedGeomNormals = false;
938                siend = mShadowRenderables.end();
939                egi = mEdgeList->edgeGroups.begin();
940                for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
941                {
942                        if (init)
943                        {
944                                // Create a new renderable, create a separate light cap if
945                                // we're using a vertex program (either for this model, or
946                                // for extruding the shadow volume) since otherwise we can
947                                // get depth-fighting on the light cap
948
949                                *si = new RegionShadowRenderable(this, indexBuffer,
950                                        egi->vertexData, mVertexProgramInUse || !extrude);
951                        }
952                        // Get shadow renderable
953                        esr = static_cast<RegionShadowRenderable*>(*si);
954                        HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
955                        // Extrude vertices in software if required
956                        if (extrude)
957                        {
958                                extrudeVertices(esrPositionBuffer,
959                                        egi->vertexData->vertexCount,
960                                        lightPos, extrusionDistance);
961
962                        }
963
964                }
965                // Calc triangle light facing
966                updateEdgeListLightFacing(mEdgeList, lightPos);
967
968                // Generate indexes and update renderables
969                generateShadowVolume(mEdgeList, *indexBuffer, light,
970                        mShadowRenderables, flags);
971
972
973                return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
974
975
976        }
977        //--------------------------------------------------------------------------
978        EdgeData* StaticGeometry::Region::getEdgeList(void)
979        {
980                return mEdgeList;
981        }
982        //--------------------------------------------------------------------------
983        bool StaticGeometry::Region::hasEdgeList(void)
984        {
985                return mEdgeList != 0;
986        }
987        //--------------------------------------------------------------------------
988        void StaticGeometry::Region::dump(std::ofstream& of) const
989        {
990                of << "Region " << mRegionID << std::endl;
991                of << "--------------------------" << std::endl;
992                of << "Centre: " << mCentre << std::endl;
993                of << "Local AABB: " << mAABB << std::endl;
994                of << "Bounding radius: " << mBoundingRadius << std::endl;
995                of << "Number of LODs: " << mLodBucketList.size() << std::endl;
996
997                for (LODBucketList::const_iterator i = mLodBucketList.begin();
998                        i != mLodBucketList.end(); ++i)
999                {
1000                        (*i)->dump(of);
1001                }
1002                of << "--------------------------" << std::endl;
1003        }
1004        //--------------------------------------------------------------------------
1005        //--------------------------------------------------------------------------
1006        StaticGeometry::Region::RegionShadowRenderable::RegionShadowRenderable(
1007                Region* parent, HardwareIndexBufferSharedPtr* indexBuffer,
1008                const VertexData* vertexData, bool createSeparateLightCap,
1009                bool isLightCap)
1010                : mParent(parent)
1011        {
1012                // Initialise render op
1013                mRenderOp.indexData = new IndexData();
1014                mRenderOp.indexData->indexBuffer = *indexBuffer;
1015                mRenderOp.indexData->indexStart = 0;
1016                // index start and count are sorted out later
1017
1018                // Create vertex data which just references position component (and 2 component)
1019                mRenderOp.vertexData = new VertexData();
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                uint8 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                uint8 group, Real camDistanceSquared)
1257        {
1258                // Determine the current material technique
1259                mTechnique = mMaterial->getBestTechnique(
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            // Close gaps in bindings for effective and safely
1368            mVertexData->closeGapsInBindings();
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()->queryLights();
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, 
1519                                                srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
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, 
1532                                        srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
1533                                        HardwareBuffer::HBL_READ_ONLY));
1534
1535                                copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset);
1536                                p16Dest += srcIdxData->indexCount;
1537                                srcIdxData->indexBuffer->unlock();
1538                        }
1539
1540                        // Now deal with vertex buffers
1541                        // we can rely on buffer counts / formats being the same
1542                        VertexData* srcVData = geom->geometry->vertexData;
1543                        VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding;
1544                        for (b = 0; b < binds->getBufferCount(); ++b)
1545                        {
1546                                // lock source
1547                                HardwareVertexBufferSharedPtr srcBuf =
1548                                        srcBinds->getBuffer(b);
1549                                uchar* pSrcBase = static_cast<uchar*>(
1550                                        srcBuf->lock(HardwareBuffer::HBL_READ_ONLY));
1551                                // Get buffer lock pointer, we'll update this later
1552                                uchar* pDstBase = destBufferLocks[b];
1553                                size_t bufInc = srcBuf->getVertexSize();
1554
1555                                // Iterate over vertices
1556                                float *pSrcReal, *pDstReal;
1557                                Vector3 tmp;
1558                                for (size_t v = 0; v < srcVData->vertexCount; ++v)
1559                                {
1560                                        // Iterate over vertex elements
1561                                        VertexDeclaration::VertexElementList& elems =
1562                                                bufferElements[b];
1563                                        VertexDeclaration::VertexElementList::iterator ei;
1564                                        for (ei = elems.begin(); ei != elems.end(); ++ei)
1565                                        {
1566                                                VertexElement& elem = *ei;
1567                                                elem.baseVertexPointerToElement(pSrcBase, &pSrcReal);
1568                                                elem.baseVertexPointerToElement(pDstBase, &pDstReal);
1569                                                switch (elem.getSemantic())
1570                                                {
1571                                                case VES_POSITION:
1572                                                        tmp.x = *pSrcReal++;
1573                                                        tmp.y = *pSrcReal++;
1574                                                        tmp.z = *pSrcReal++;
1575                                                        // transform
1576                                                        tmp = (geom->orientation * (tmp * geom->scale)) +
1577                                                                geom->position;
1578                                                        // Adjust for region centre
1579                                                        tmp -= regionCentre;
1580                                                        *pDstReal++ = tmp.x;
1581                                                        *pDstReal++ = tmp.y;
1582                                                        *pDstReal++ = tmp.z;
1583                                                        break;
1584                                                case VES_NORMAL:
1585                                                case VES_TANGENT:
1586                                                case VES_BINORMAL:
1587                                                        tmp.x = *pSrcReal++;
1588                                                        tmp.y = *pSrcReal++;
1589                                                        tmp.z = *pSrcReal++;
1590                                                        // scale (invert)
1591                                                        tmp = tmp / geom->scale;
1592                                                        tmp.normalise();
1593                                                        // rotation
1594                                                        tmp = geom->orientation * tmp;
1595                                                        *pDstReal++ = tmp.x;
1596                                                        *pDstReal++ = tmp.y;
1597                                                        *pDstReal++ = tmp.z;
1598                                                        break;
1599                                                default:
1600                                                        // just raw copy
1601                                                        memcpy(pDstReal, pSrcReal,
1602                                                                        VertexElement::getTypeSize(elem.getType()));
1603                                                        break;
1604                                                };
1605
1606                                        }
1607
1608                                        // Increment both pointers
1609                                        pDstBase += bufInc;
1610                                        pSrcBase += bufInc;
1611
1612                                }
1613
1614                                // Update pointer
1615                                destBufferLocks[b] = pDstBase;
1616                                srcBuf->unlock();
1617                        }
1618
1619                        indexOffset += geom->geometry->vertexData->vertexCount;
1620                }
1621
1622                // Unlock everything
1623                mIndexData->indexBuffer->unlock();
1624                for (b = 0; b < binds->getBufferCount(); ++b)
1625                {
1626                        binds->getBuffer(b)->unlock();
1627                }
1628
1629                // If we're dealing with stencil shadows, copy the position data from
1630                // the early half of the buffer to the latter part
1631                if (stencilShadows)
1632                {
1633                        HardwareVertexBufferSharedPtr buf = binds->getBuffer(posBufferIdx);
1634                        void* pSrc = buf->lock(HardwareBuffer::HBL_NORMAL);
1635                        // Point dest at second half (remember vertexcount is original count)
1636                        void* pDest = static_cast<uchar*>(pSrc) +
1637                                buf->getVertexSize() * mVertexData->vertexCount;
1638                        memcpy(pDest, pSrc, buf->getVertexSize() * mVertexData->vertexCount);
1639                        buf->unlock();
1640
1641                        // Also set up hardware W buffer if appropriate
1642                        RenderSystem* rend = Root::getSingleton().getRenderSystem();
1643                        if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
1644                        {
1645                                buf = HardwareBufferManager::getSingleton().createVertexBuffer(
1646                                        sizeof(float), mVertexData->vertexCount * 2,
1647                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
1648                                // Fill the first half with 1.0, second half with 0.0
1649                                float *pW = static_cast<float*>(
1650                                        buf->lock(HardwareBuffer::HBL_DISCARD));
1651                                size_t v;
1652                                for (v = 0; v < mVertexData->vertexCount; ++v)
1653                                {
1654                                        *pW++ = 1.0f;
1655                                }
1656                                for (v = 0; v < mVertexData->vertexCount; ++v)
1657                                {
1658                                        *pW++ = 0.0f;
1659                                }
1660                                buf->unlock();
1661                                mVertexData->hardwareShadowVolWBuffer = buf;
1662                        }
1663                }
1664
1665        }
1666        //--------------------------------------------------------------------------
1667        void StaticGeometry::GeometryBucket::dump(std::ofstream& of) const
1668        {
1669                of << "Geometry Bucket" << std::endl;
1670                of << "---------------" << std::endl;
1671                of << "Format string: " << mFormatString << std::endl;
1672                of << "Geometry items: " << mQueuedGeometry.size() << std::endl;
1673                of << "Vertex count: " << mVertexData->vertexCount << std::endl;
1674                of << "Index count: " << mIndexData->indexCount << std::endl;
1675                of << "---------------" << std::endl;
1676
1677        }
1678        //--------------------------------------------------------------------------
1679
1680}
1681
Note: See TracBrowser for help on using the repository browser.