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