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-2013 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 "OgreSubEntity.h"
32 #include "OgreSceneNode.h"
33 #include "OgreException.h"
34 #include "OgreMesh.h"
35 #include "OgreSubMesh.h"
36 #include "OgreLogManager.h"
37 #include "OgreSceneManager.h"
38 #include "OgreCamera.h"
39 #include "OgreMaterialManager.h"
40 #include "OgreRoot.h"
41 #include "OgreRenderSystem.h"
42 #include "OgreEdgeListBuilder.h"
43 
44 namespace Ogre {
45 
46 	#define REGION_RANGE 1024
47 	#define REGION_HALF_RANGE 512
48 	#define REGION_MAX_INDEX 511
49 	#define REGION_MIN_INDEX -512
50 
51 	//--------------------------------------------------------------------------
StaticGeometry(SceneManager * owner,const String & name)52 	StaticGeometry::StaticGeometry(SceneManager* owner, const String& name):
53 		mOwner(owner),
54 		mName(name),
55 		mBuilt(false),
56 		mUpperDistance(0.0f),
57 		mSquaredUpperDistance(0.0f),
58 		mCastShadows(false),
59 		mRegionDimensions(Vector3(1000,1000,1000)),
60 		mHalfRegionDimensions(Vector3(500,500,500)),
61 		mOrigin(Vector3(0,0,0)),
62 		mVisible(true),
63         mRenderQueueID(RENDER_QUEUE_MAIN),
64         mRenderQueueIDSet(false),
65 		mVisibilityFlags(Ogre::MovableObject::getDefaultVisibilityFlags())
66 	{
67 	}
68 	//--------------------------------------------------------------------------
~StaticGeometry()69 	StaticGeometry::~StaticGeometry()
70 	{
71 		reset();
72 	}
73 	//--------------------------------------------------------------------------
getRegion(const AxisAlignedBox & bounds,bool autoCreate)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 = 0, finaly = 0, finalz = 0;
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 	//--------------------------------------------------------------------------
getVolumeIntersection(const AxisAlignedBox & box,ushort x,ushort y,ushort z)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 	//--------------------------------------------------------------------------
getRegionBounds(ushort x,ushort y,ushort z)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 	//--------------------------------------------------------------------------
getRegionCentre(ushort x,ushort y,ushort z)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 	//--------------------------------------------------------------------------
getRegion(ushort x,ushort y,ushort z,bool autoCreate)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 = OGRE_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 	//--------------------------------------------------------------------------
getRegion(uint32 index)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 	//--------------------------------------------------------------------------
getRegionIndexes(const Vector3 & point,ushort & x,ushort & y,ushort & z)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 	//--------------------------------------------------------------------------
packIndex(ushort x,ushort y,ushort z)226 	uint32 StaticGeometry::packIndex(ushort x, ushort y, ushort z)
227 	{
228 		return x + (y << 10) + (z << 20);
229 	}
230 	//--------------------------------------------------------------------------
getRegion(const Vector3 & point,bool autoCreate)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 	//--------------------------------------------------------------------------
calculateBounds(VertexData * vertexData,const Vector3 & position,const Quaternion & orientation,const Vector3 & scale)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 = Vector3::ZERO, max = Vector3::UNIT_SCALE;
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 	//--------------------------------------------------------------------------
addEntity(Entity * ent,const Vector3 & position,const Quaternion & orientation,const Vector3 & scale)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(), LML_CRITICAL);
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 = OGRE_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*
determineGeometry(SubMesh * sm)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 = OGRE_NEW_T(SubMeshLodGeometryLinkList, MEMCATEGORY_GEOMETRY)();
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 	//--------------------------------------------------------------------------
splitGeometry(VertexData * vd,IndexData * id,StaticGeometry::SubMeshLodGeometryLink * targetGeomLink)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 		IndexRemap indexRemap;
396 		if (use32bitIndexes)
397 		{
398 			uint32 *p32 = static_cast<uint32*>(id->indexBuffer->lock(
399 				id->indexStart,
400 				id->indexCount * id->indexBuffer->getIndexSize(),
401 				HardwareBuffer::HBL_READ_ONLY));
402 			buildIndexRemap(p32, id->indexCount, indexRemap);
403 			id->indexBuffer->unlock();
404 		}
405 		else
406 		{
407 			uint16 *p16 = static_cast<uint16*>(id->indexBuffer->lock(
408 				id->indexStart,
409 				id->indexCount * id->indexBuffer->getIndexSize(),
410 				HardwareBuffer::HBL_READ_ONLY));
411 			buildIndexRemap(p16, id->indexCount, indexRemap);
412 			id->indexBuffer->unlock();
413 		}
414 		if (indexRemap.size() == vd->vertexCount)
415 		{
416 			// ha, complete usage after all
417 			targetGeomLink->vertexData = vd;
418 			targetGeomLink->indexData = id;
419 			return;
420 		}
421 
422 
423 		// Create the new vertex data records
424 		targetGeomLink->vertexData = vd->clone(false);
425 		// Convenience
426 		VertexData* newvd = targetGeomLink->vertexData;
427 		//IndexData* newid = targetGeomLink->indexData;
428 		// Update the vertex count
429 		newvd->vertexCount = indexRemap.size();
430 
431 		size_t numvbufs = vd->vertexBufferBinding->getBufferCount();
432 		// Copy buffers from old to new
433 		for (unsigned short b = 0; b < numvbufs; ++b)
434 		{
435 			// Lock old buffer
436 			HardwareVertexBufferSharedPtr oldBuf =
437 				vd->vertexBufferBinding->getBuffer(b);
438 			// Create new buffer
439 			HardwareVertexBufferSharedPtr newBuf =
440 				HardwareBufferManager::getSingleton().createVertexBuffer(
441 					oldBuf->getVertexSize(),
442 					indexRemap.size(),
443 					HardwareBuffer::HBU_STATIC);
444 			// rebind
445 			newvd->vertexBufferBinding->setBinding(b, newBuf);
446 
447 			// Copy all the elements of the buffer across, by iterating over
448 			// the IndexRemap which describes how to move the old vertices
449 			// to the new ones. By nature of the map the remap is in order of
450 			// indexes in the old buffer, but note that we're not guaranteed to
451 			// address every vertex (which is kinda why we're here)
452 			uchar* pSrcBase = static_cast<uchar*>(
453 				oldBuf->lock(HardwareBuffer::HBL_READ_ONLY));
454 			uchar* pDstBase = static_cast<uchar*>(
455 				newBuf->lock(HardwareBuffer::HBL_DISCARD));
456 			size_t vertexSize = oldBuf->getVertexSize();
457 			// Buffers should be the same size
458 			assert (vertexSize == newBuf->getVertexSize());
459 
460 			for (IndexRemap::iterator r = indexRemap.begin();
461 				r != indexRemap.end(); ++r)
462 			{
463 				assert (r->first < oldBuf->getNumVertices());
464 				assert (r->second < newBuf->getNumVertices());
465 
466 				uchar* pSrc = pSrcBase + r->first * vertexSize;
467 				uchar* pDst = pDstBase + r->second * vertexSize;
468 				memcpy(pDst, pSrc, vertexSize);
469 			}
470 			// unlock
471 			oldBuf->unlock();
472 			newBuf->unlock();
473 
474 		}
475 
476 		// Now create a new index buffer
477 		HardwareIndexBufferSharedPtr ibuf =
478 			HardwareBufferManager::getSingleton().createIndexBuffer(
479 				id->indexBuffer->getType(), id->indexCount,
480 				HardwareBuffer::HBU_STATIC);
481 
482 		if (use32bitIndexes)
483 		{
484 			uint32 *pSrc32, *pDst32;
485 			pSrc32 = static_cast<uint32*>(id->indexBuffer->lock(
486 				id->indexStart,
487 				id->indexCount * id->indexBuffer->getIndexSize(),
488 				HardwareBuffer::HBL_READ_ONLY));
489 			pDst32 = static_cast<uint32*>(ibuf->lock(
490 				HardwareBuffer::HBL_DISCARD));
491 			remapIndexes(pSrc32, pDst32, indexRemap, id->indexCount);
492 			id->indexBuffer->unlock();
493 			ibuf->unlock();
494 		}
495 		else
496 		{
497 			uint16 *pSrc16, *pDst16;
498 			pSrc16 = static_cast<uint16*>(id->indexBuffer->lock(
499 				id->indexStart,
500 				id->indexCount * id->indexBuffer->getIndexSize(),
501 				HardwareBuffer::HBL_READ_ONLY));
502 			pDst16 = static_cast<uint16*>(ibuf->lock(
503 				HardwareBuffer::HBL_DISCARD));
504 			remapIndexes(pSrc16, pDst16, indexRemap, id->indexCount);
505 			id->indexBuffer->unlock();
506 			ibuf->unlock();
507 		}
508 
509 		targetGeomLink->indexData = OGRE_NEW IndexData();
510 		targetGeomLink->indexData->indexStart = 0;
511 		targetGeomLink->indexData->indexCount = id->indexCount;
512 		targetGeomLink->indexData->indexBuffer = ibuf;
513 
514 		// Store optimised geometry for deallocation later
515 		OptimisedSubMeshGeometry *optGeom = OGRE_NEW OptimisedSubMeshGeometry();
516 		optGeom->indexData = targetGeomLink->indexData;
517 		optGeom->vertexData = targetGeomLink->vertexData;
518 		mOptimisedSubMeshGeometryList.push_back(optGeom);
519 	}
520 	//--------------------------------------------------------------------------
addSceneNode(const SceneNode * node)521 	void StaticGeometry::addSceneNode(const SceneNode* node)
522 	{
523 		SceneNode::ConstObjectIterator obji = node->getAttachedObjectIterator();
524 		while (obji.hasMoreElements())
525 		{
526 			MovableObject* mobj = obji.getNext();
527 			if (mobj->getMovableType() == "Entity")
528 			{
529 				addEntity(static_cast<Entity*>(mobj),
530 					node->_getDerivedPosition(),
531 					node->_getDerivedOrientation(),
532 					node->_getDerivedScale());
533 			}
534 		}
535 		// Iterate through all the child-nodes
536 		SceneNode::ConstChildNodeIterator nodei = node->getChildIterator();
537 
538 		while (nodei.hasMoreElements())
539 		{
540 			const SceneNode* subNode = static_cast<const SceneNode*>(nodei.getNext());
541 			// Add this subnode and its children...
542 			addSceneNode( subNode );
543 		}
544 	}
545 	//--------------------------------------------------------------------------
build(void)546 	void StaticGeometry::build(void)
547 	{
548 		// Make sure there's nothing from previous builds
549 		destroy();
550 
551 		// Firstly allocate meshes to regions
552 		for (QueuedSubMeshList::iterator qi = mQueuedSubMeshes.begin();
553 			qi != mQueuedSubMeshes.end(); ++qi)
554 		{
555 			QueuedSubMesh* qsm = *qi;
556 			Region* region = getRegion(qsm->worldBounds, true);
557 			region->assign(qsm);
558 		}
559 		bool stencilShadows = false;
560 		if (mCastShadows && mOwner->isShadowTechniqueStencilBased())
561 		{
562 			stencilShadows = true;
563 		}
564 
565 		// Now tell each region to build itself
566 		for (RegionMap::iterator ri = mRegionMap.begin();
567 			ri != mRegionMap.end(); ++ri)
568 		{
569 			ri->second->build(stencilShadows);
570 
571 			// Set the visibility flags on these regions
572 			ri->second->setVisibilityFlags(mVisibilityFlags);
573 		}
574 
575 	}
576 	//--------------------------------------------------------------------------
destroy(void)577 	void StaticGeometry::destroy(void)
578 	{
579 		// delete the regions
580 		for (RegionMap::iterator i = mRegionMap.begin();
581 			i != mRegionMap.end(); ++i)
582 		{
583 			mOwner->extractMovableObject(i->second);
584 			OGRE_DELETE i->second;
585 		}
586 		mRegionMap.clear();
587 	}
588 	//--------------------------------------------------------------------------
reset(void)589 	void StaticGeometry::reset(void)
590 	{
591 		destroy();
592 		for (QueuedSubMeshList::iterator i = mQueuedSubMeshes.begin();
593 			i != mQueuedSubMeshes.end(); ++i)
594 		{
595 			OGRE_DELETE *i;
596 		}
597 		mQueuedSubMeshes.clear();
598 		// Delete precached geoemtry lists
599 		for (SubMeshGeometryLookup::iterator l = mSubMeshGeometryLookup.begin();
600 			l != mSubMeshGeometryLookup.end(); ++l)
601 		{
602 			OGRE_DELETE_T(l->second, SubMeshLodGeometryLinkList, MEMCATEGORY_GEOMETRY);
603 		}
604 		mSubMeshGeometryLookup.clear();
605 		// Delete optimised geometry
606 		for (OptimisedSubMeshGeometryList::iterator o = mOptimisedSubMeshGeometryList.begin();
607 			o != mOptimisedSubMeshGeometryList.end(); ++o)
608 		{
609 			OGRE_DELETE *o;
610 		}
611 		mOptimisedSubMeshGeometryList.clear();
612 
613 	}
614 	//--------------------------------------------------------------------------
setVisible(bool visible)615 	void StaticGeometry::setVisible(bool visible)
616 	{
617 		mVisible = visible;
618 		// tell any existing regions
619 		for (RegionMap::iterator ri = mRegionMap.begin();
620 			ri != mRegionMap.end(); ++ri)
621 		{
622 			ri->second->setVisible(visible);
623 		}
624 	}
625 	//--------------------------------------------------------------------------
setCastShadows(bool castShadows)626 	void StaticGeometry::setCastShadows(bool castShadows)
627 	{
628 		mCastShadows = castShadows;
629 		// tell any existing regions
630 		for (RegionMap::iterator ri = mRegionMap.begin();
631 			ri != mRegionMap.end(); ++ri)
632 		{
633 			ri->second->setCastShadows(castShadows);
634 		}
635 
636 	}
637 	//--------------------------------------------------------------------------
setRenderQueueGroup(uint8 queueID)638     void StaticGeometry::setRenderQueueGroup(uint8 queueID)
639 	{
640 		assert(queueID <= RENDER_QUEUE_MAX && "Render queue out of range!");
641 		mRenderQueueIDSet = true;
642 		mRenderQueueID = queueID;
643 		// tell any existing regions
644 		for (RegionMap::iterator ri = mRegionMap.begin();
645 			ri != mRegionMap.end(); ++ri)
646 		{
647 			ri->second->setRenderQueueGroup(queueID);
648 		}
649 	}
650 	//--------------------------------------------------------------------------
getRenderQueueGroup(void) const651 	uint8 StaticGeometry::getRenderQueueGroup(void) const
652 	{
653 		return mRenderQueueID;
654 	}
655 	//--------------------------------------------------------------------------
setVisibilityFlags(uint32 flags)656 	void StaticGeometry::setVisibilityFlags(uint32 flags)
657 	{
658 		mVisibilityFlags = flags;
659 		for (RegionMap::const_iterator ri = mRegionMap.begin();
660 			ri != mRegionMap.end(); ++ri)
661 		{
662 			ri->second->setVisibilityFlags(flags);
663 		}
664 	}
665 	//--------------------------------------------------------------------------
getVisibilityFlags() const666 	uint32 StaticGeometry::getVisibilityFlags() const
667 	{
668 		if(mRegionMap.empty())
669 			return MovableObject::getDefaultVisibilityFlags();
670 
671 		RegionMap::const_iterator ri = mRegionMap.begin();
672 		return ri->second->getVisibilityFlags();
673 	}
674 	//--------------------------------------------------------------------------
dump(const String & filename) const675 	void StaticGeometry::dump(const String& filename) const
676 	{
677 		std::ofstream of(filename.c_str());
678 		of << "Static Geometry Report for " << mName << std::endl;
679 		of << "-------------------------------------------------" << std::endl;
680 		of << "Number of queued submeshes: " << mQueuedSubMeshes.size() << std::endl;
681 		of << "Number of regions: " << mRegionMap.size() << std::endl;
682 		of << "Region dimensions: " << mRegionDimensions << std::endl;
683 		of << "Origin: " << mOrigin << std::endl;
684 		of << "Max distance: " << mUpperDistance << std::endl;
685 		of << "Casts shadows?: " << mCastShadows << std::endl;
686 		of << std::endl;
687 		for (RegionMap::const_iterator ri = mRegionMap.begin();
688 			ri != mRegionMap.end(); ++ri)
689 		{
690 			ri->second->dump(of);
691 		}
692 		of << "-------------------------------------------------" << std::endl;
693 	}
694 	//---------------------------------------------------------------------
visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)695 	void StaticGeometry::visitRenderables(Renderable::Visitor* visitor,
696 		bool debugRenderables)
697 	{
698 		for (RegionMap::const_iterator ri = mRegionMap.begin();
699 			ri != mRegionMap.end(); ++ri)
700 		{
701 			ri->second->visitRenderables(visitor, debugRenderables);
702 		}
703 
704 	}
705 	//--------------------------------------------------------------------------
getRegionIterator(void)706 	StaticGeometry::RegionIterator StaticGeometry::getRegionIterator(void)
707 	{
708 		return RegionIterator(mRegionMap.begin(), mRegionMap.end());
709 	}
710 	//--------------------------------------------------------------------------
711 	//--------------------------------------------------------------------------
Region(StaticGeometry * parent,const String & name,SceneManager * mgr,uint32 regionID,const Vector3 & centre)712 	StaticGeometry::Region::Region(StaticGeometry* parent, const String& name,
713 		SceneManager* mgr, uint32 regionID, const Vector3& centre)
714 		: MovableObject(name), mParent(parent), mSceneMgr(mgr), mNode(0),
715 		mRegionID(regionID), mCentre(centre), mBoundingRadius(0.0f),
716 		mCurrentLod(0), mLodStrategy(0)
717 	{
718 	}
719 	//--------------------------------------------------------------------------
~Region()720 	StaticGeometry::Region::~Region()
721 	{
722 		if (mNode)
723 		{
724 			mNode->getParentSceneNode()->removeChild(mNode);
725 			mSceneMgr->destroySceneNode(mNode->getName());
726 			mNode = 0;
727 		}
728 		// delete
729 		for (LODBucketList::iterator i = mLodBucketList.begin();
730 			i != mLodBucketList.end(); ++i)
731 		{
732 			OGRE_DELETE *i;
733 		}
734 		mLodBucketList.clear();
735 
736 		// no need to delete queued meshes, these are managed in StaticGeometry
737 
738 	}
739 	//--------------------------------------------------------------------------
getTypeFlags(void) const740 	uint32 StaticGeometry::Region::getTypeFlags(void) const
741 	{
742 		return SceneManager::STATICGEOMETRY_TYPE_MASK;
743 	}
744 	//--------------------------------------------------------------------------
assign(QueuedSubMesh * qmesh)745 	void StaticGeometry::Region::assign(QueuedSubMesh* qmesh)
746 	{
747 		mQueuedSubMeshes.push_back(qmesh);
748 
749         // Set/check LOD strategy
750         const LodStrategy *lodStrategy = qmesh->submesh->parent->getLodStrategy();
751         if (mLodStrategy == 0)
752         {
753             mLodStrategy = lodStrategy;
754 
755             // First LOD mandatory, and always from base LOD value
756             mLodValues.push_back(mLodStrategy->getBaseValue());
757         }
758         else
759         {
760             if (mLodStrategy != lodStrategy)
761                 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Lod strategies do not match",
762                     "StaticGeometry::Region::assign");
763         }
764 
765 		// update LOD values
766 		ushort lodLevels = qmesh->submesh->parent->getNumLodLevels();
767 		assert(qmesh->geometryLodList->size() == lodLevels);
768 
769 		while(mLodValues.size() < lodLevels)
770 		{
771 			mLodValues.push_back(0.0f);
772 		}
773 		// Make sure LOD levels are max of all at the requested level
774 		for (ushort lod = 1; lod < lodLevels; ++lod)
775 		{
776 			const MeshLodUsage& meshLod =
777 				qmesh->submesh->parent->getLodLevel(lod);
778 			mLodValues[lod] = std::max(mLodValues[lod],
779 				meshLod.value);
780 		}
781 
782 		// update bounds
783 		// Transform world bounds relative to our centre
784 		AxisAlignedBox localBounds(
785 			qmesh->worldBounds.getMinimum() - mCentre,
786 			qmesh->worldBounds.getMaximum() - mCentre);
787 		mAABB.merge(localBounds);
788 		mBoundingRadius = Math::boundingRadiusFromAABB(mAABB);
789 
790 	}
791 	//--------------------------------------------------------------------------
build(bool stencilShadows)792 	void StaticGeometry::Region::build(bool stencilShadows)
793 	{
794 		// Create a node
795 		mNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(mName,
796 			mCentre);
797 		mNode->attachObject(this);
798 		// We need to create enough LOD buckets to deal with the highest LOD
799 		// we encountered in all the meshes queued
800 		for (ushort lod = 0; lod < mLodValues.size(); ++lod)
801 		{
802 			LODBucket* lodBucket =
803 				OGRE_NEW LODBucket(this, lod, mLodValues[lod]);
804 			mLodBucketList.push_back(lodBucket);
805 			// Now iterate over the meshes and assign to LODs
806 			// LOD bucket will pick the right LOD to use
807 			QueuedSubMeshList::iterator qi, qiend;
808 			qiend = mQueuedSubMeshes.end();
809 			for (qi = mQueuedSubMeshes.begin(); qi != qiend; ++qi)
810 			{
811 				lodBucket->assign(*qi, lod);
812 			}
813 			// now build
814 			lodBucket->build(stencilShadows);
815 		}
816 
817 
818 
819 	}
820 	//--------------------------------------------------------------------------
getMovableType(void) const821 	const String& StaticGeometry::Region::getMovableType(void) const
822 	{
823 		static String sType = "StaticGeometry";
824 		return sType;
825 	}
826 	//--------------------------------------------------------------------------
_notifyCurrentCamera(Camera * cam)827 	void StaticGeometry::Region::_notifyCurrentCamera(Camera* cam)
828 	{
829         // Set camera
830         mCamera = cam;
831 
832         // Cache squared view depth for use by GeometryBucket
833         mSquaredViewDepth = mParentNode->getSquaredViewDepth(cam->getLodCamera());
834 
835         // No LOD strategy set yet, skip (this indicates that there are no submeshes)
836         if (mLodStrategy == 0)
837             return;
838 
839         // Sanity check
840         assert(!mLodValues.empty());
841 
842         // Calculate LOD value
843         Real lodValue = mLodStrategy->getValue(this, cam);
844 
845         // Store LOD value for this strategy
846         mLodValue = lodValue;
847 
848         // Get LOD index
849         mCurrentLod = mLodStrategy->getIndex(lodValue, mLodValues);
850 	}
851 	//--------------------------------------------------------------------------
getBoundingBox(void) const852 	const AxisAlignedBox& StaticGeometry::Region::getBoundingBox(void) const
853 	{
854 		return mAABB;
855 	}
856 	//--------------------------------------------------------------------------
getBoundingRadius(void) const857 	Real StaticGeometry::Region::getBoundingRadius(void) const
858 	{
859 		return mBoundingRadius;
860 	}
861 	//--------------------------------------------------------------------------
_updateRenderQueue(RenderQueue * queue)862 	void StaticGeometry::Region::_updateRenderQueue(RenderQueue* queue)
863 	{
864 		mLodBucketList[mCurrentLod]->addRenderables(queue, mRenderQueueID,
865 			mLodValue);
866 	}
867 	//---------------------------------------------------------------------
visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)868 	void StaticGeometry::Region::visitRenderables(Renderable::Visitor* visitor,
869 		bool debugRenderables)
870 	{
871 		for (LODBucketList::iterator i = mLodBucketList.begin(); i != mLodBucketList.end(); ++i)
872 		{
873 			(*i)->visitRenderables(visitor, debugRenderables);
874 		}
875 
876 	}
877 	//--------------------------------------------------------------------------
isVisible(void) const878 	bool StaticGeometry::Region::isVisible(void) const
879 	{
880 		if(!mVisible || mBeyondFarDistance)
881 			return false;
882 
883 		SceneManager* sm = Root::getSingleton()._getCurrentSceneManager();
884         if (sm && !(mVisibilityFlags & sm->_getCombinedVisibilityMask()))
885             return false;
886 
887         return true;
888 	}
889 	//--------------------------------------------------------------------------
890 	StaticGeometry::Region::LODIterator
getLODIterator(void)891 	StaticGeometry::Region::getLODIterator(void)
892 	{
893 		return LODIterator(mLodBucketList.begin(), mLodBucketList.end());
894 	}
895 	//---------------------------------------------------------------------
896 	ShadowCaster::ShadowRenderableListIterator
getShadowVolumeRenderableIterator(ShadowTechnique shadowTechnique,const Light * light,HardwareIndexBufferSharedPtr * indexBuffer,size_t * indexBufferUsedSize,bool extrude,Real extrusionDistance,unsigned long flags)897 	StaticGeometry::Region::getShadowVolumeRenderableIterator(
898 		ShadowTechnique shadowTechnique, const Light* light,
899 		HardwareIndexBufferSharedPtr* indexBuffer, size_t* indexBufferUsedSize,
900 		bool extrude, Real extrusionDistance, unsigned long flags)
901 	{
902 		// Calculate the object space light details
903 		Vector4 lightPos = light->getAs4DVector();
904 		Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine();
905 		lightPos = world2Obj.transformAffine(lightPos);
906 		Matrix3 world2Obj3x3;
907 		world2Obj.extract3x3Matrix(world2Obj3x3);
908 		extrusionDistance *= Math::Sqrt(std::min(std::min(world2Obj3x3.GetColumn(0).squaredLength(), world2Obj3x3.GetColumn(1).squaredLength()), world2Obj3x3.GetColumn(2).squaredLength()));
909 
910 		// per-LOD shadow lists & edge data
911 		mLodBucketList[mCurrentLod]->updateShadowRenderables(
912 			shadowTechnique, lightPos, indexBuffer, extrude, extrusionDistance, flags);
913 
914 		EdgeData* edgeList = mLodBucketList[mCurrentLod]->getEdgeList();
915 		ShadowRenderableList& shadowRendList = mLodBucketList[mCurrentLod]->getShadowRenderableList();
916 
917 		// Calc triangle light facing
918 		updateEdgeListLightFacing(edgeList, lightPos);
919 
920 		// Generate indexes and update renderables
921 		generateShadowVolume(edgeList, *indexBuffer, *indexBufferUsedSize,
922 			light, shadowRendList, flags);
923 
924 
925 		return ShadowCaster::ShadowRenderableListIterator(shadowRendList.begin(), shadowRendList.end());
926 
927 	}
928 	//--------------------------------------------------------------------------
getEdgeList(void)929 	EdgeData* StaticGeometry::Region::getEdgeList(void)
930 	{
931 		return mLodBucketList[mCurrentLod]->getEdgeList();
932 	}
933 	//--------------------------------------------------------------------------
hasEdgeList(void)934 	bool StaticGeometry::Region::hasEdgeList(void)
935 	{
936 		return getEdgeList() != 0;
937 	}
938 	//--------------------------------------------------------------------------
dump(std::ofstream & of) const939 	void StaticGeometry::Region::dump(std::ofstream& of) const
940 	{
941 		of << "Region " << mRegionID << std::endl;
942 		of << "--------------------------" << std::endl;
943 		of << "Centre: " << mCentre << std::endl;
944 		of << "Local AABB: " << mAABB << std::endl;
945 		of << "Bounding radius: " << mBoundingRadius << std::endl;
946 		of << "Number of LODs: " << mLodBucketList.size() << std::endl;
947 
948 		for (LODBucketList::const_iterator i = mLodBucketList.begin();
949 			i != mLodBucketList.end(); ++i)
950 		{
951 			(*i)->dump(of);
952 		}
953 		of << "--------------------------" << std::endl;
954 	}
955 	//--------------------------------------------------------------------------
956 	//--------------------------------------------------------------------------
LODShadowRenderable(LODBucket * parent,HardwareIndexBufferSharedPtr * indexBuffer,const VertexData * vertexData,bool createSeparateLightCap,bool isLightCap)957 	StaticGeometry::LODBucket::LODShadowRenderable::LODShadowRenderable(
958 		LODBucket* parent, HardwareIndexBufferSharedPtr* indexBuffer,
959 		const VertexData* vertexData, bool createSeparateLightCap,
960 		bool isLightCap)
961 		: mParent(parent)
962 	{
963 		// Initialise render op
964 		mRenderOp.indexData = OGRE_NEW IndexData();
965 		mRenderOp.indexData->indexBuffer = *indexBuffer;
966 		mRenderOp.indexData->indexStart = 0;
967 		// index start and count are sorted out later
968 
969 		// Create vertex data which just references position component (and 2 component)
970 		mRenderOp.vertexData = OGRE_NEW VertexData();
971 		// Map in position data
972 		mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
973 		ushort origPosBind =
974 			vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
975 		mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(origPosBind);
976 		mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
977 		// Map in w-coord buffer (if present)
978 		if(!vertexData->hardwareShadowVolWBuffer.isNull())
979 		{
980 			mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
981 			mWBuffer = vertexData->hardwareShadowVolWBuffer;
982 			mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
983 		}
984 		// Use same vertex start as input
985 		mRenderOp.vertexData->vertexStart = vertexData->vertexStart;
986 
987 		if (isLightCap)
988 		{
989 			// Use original vertex count, no extrusion
990 			mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
991 		}
992 		else
993 		{
994 			// Vertex count must take into account the doubling of the buffer,
995 			// because second half of the buffer is the extruded copy
996 			mRenderOp.vertexData->vertexCount =
997 				vertexData->vertexCount * 2;
998 			if (createSeparateLightCap)
999 			{
1000 				// Create child light cap
1001 				mLightCap = OGRE_NEW LODShadowRenderable(parent,
1002 					indexBuffer, vertexData, false, true);
1003 			}
1004 		}
1005 	}
1006 	//--------------------------------------------------------------------------
~LODShadowRenderable()1007 	StaticGeometry::LODBucket::LODShadowRenderable::~LODShadowRenderable()
1008 	{
1009 		OGRE_DELETE mRenderOp.indexData;
1010 		OGRE_DELETE mRenderOp.vertexData;
1011 	}
1012 	//--------------------------------------------------------------------------
getWorldTransforms(Matrix4 * xform) const1013 	void StaticGeometry::LODBucket::LODShadowRenderable::getWorldTransforms(
1014 		Matrix4* xform) const
1015 	{
1016 		// pretransformed
1017 		*xform = mParent->getParent()->_getParentNodeFullTransform();
1018 	}
1019 	//-----------------------------------------------------------------------
rebindIndexBuffer(const HardwareIndexBufferSharedPtr & indexBuffer)1020 	void StaticGeometry::LODBucket::LODShadowRenderable::rebindIndexBuffer(const HardwareIndexBufferSharedPtr& indexBuffer)
1021 	{
1022 		mRenderOp.indexData->indexBuffer = indexBuffer;
1023 		if (mLightCap) mLightCap->rebindIndexBuffer(indexBuffer);
1024 	}
1025 	//--------------------------------------------------------------------------
1026 	//--------------------------------------------------------------------------
LODBucket(Region * parent,unsigned short lod,Real lodValue)1027 	StaticGeometry::LODBucket::LODBucket(Region* parent, unsigned short lod,
1028 		Real lodValue)
1029 		: mParent(parent), mLod(lod), mLodValue(lodValue), mEdgeList(0)
1030 		, mVertexProgramInUse(false)
1031 	{
1032 	}
1033 	//--------------------------------------------------------------------------
~LODBucket()1034 	StaticGeometry::LODBucket::~LODBucket()
1035 	{
1036 		OGRE_DELETE mEdgeList;
1037 		for (ShadowCaster::ShadowRenderableList::iterator s = mShadowRenderables.begin();
1038 			s != mShadowRenderables.end(); ++s)
1039 		{
1040 			OGRE_DELETE *s;
1041 		}
1042 		mShadowRenderables.clear();
1043 		// delete
1044 		for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1045 			i != mMaterialBucketMap.end(); ++i)
1046 		{
1047 			OGRE_DELETE i->second;
1048 		}
1049 		mMaterialBucketMap.clear();
1050 		for(QueuedGeometryList::iterator qi = mQueuedGeometryList.begin();
1051 			qi != mQueuedGeometryList.end(); ++qi)
1052 		{
1053 			OGRE_DELETE *qi;
1054 		}
1055 		mQueuedGeometryList.clear();
1056 
1057 		// no need to delete queued meshes, these are managed in StaticGeometry
1058 	}
1059 	//--------------------------------------------------------------------------
assign(QueuedSubMesh * qmesh,ushort atLod)1060 	void StaticGeometry::LODBucket::assign(QueuedSubMesh* qmesh, ushort atLod)
1061 	{
1062 		QueuedGeometry* q = OGRE_NEW QueuedGeometry();
1063 		mQueuedGeometryList.push_back(q);
1064 		q->position = qmesh->position;
1065 		q->orientation = qmesh->orientation;
1066 		q->scale = qmesh->scale;
1067 		if (qmesh->geometryLodList->size() > atLod)
1068 		{
1069 			// This submesh has enough lods, use the right one
1070 			q->geometry = &(*qmesh->geometryLodList)[atLod];
1071 		}
1072 		else
1073 		{
1074 			// Not enough lods, use the lowest one we have
1075 			q->geometry =
1076 				&(*qmesh->geometryLodList)[qmesh->geometryLodList->size() - 1];
1077 		}
1078 		// Locate a material bucket
1079 		MaterialBucket* mbucket = 0;
1080 		MaterialBucketMap::iterator m =
1081 			mMaterialBucketMap.find(qmesh->materialName);
1082 		if (m != mMaterialBucketMap.end())
1083 		{
1084 			mbucket = m->second;
1085 		}
1086 		else
1087 		{
1088 			mbucket = OGRE_NEW MaterialBucket(this, qmesh->materialName);
1089 			mMaterialBucketMap[qmesh->materialName] = mbucket;
1090 		}
1091 		mbucket->assign(q);
1092 	}
1093 	//--------------------------------------------------------------------------
build(bool stencilShadows)1094 	void StaticGeometry::LODBucket::build(bool stencilShadows)
1095 	{
1096 
1097 		EdgeListBuilder eb;
1098 		size_t vertexSet = 0;
1099 
1100 		// Just pass this on to child buckets
1101 		for (MaterialBucketMap::iterator i = mMaterialBucketMap.begin();
1102 			i != mMaterialBucketMap.end(); ++i)
1103 		{
1104 			MaterialBucket* mat = i->second;
1105 
1106 			mat->build(stencilShadows);
1107 
1108 			if (stencilShadows)
1109 			{
1110 				MaterialBucket::GeometryIterator geomIt =
1111 					mat->getGeometryIterator();
1112 				// Check if we have vertex programs here
1113 				Technique* t = mat->getMaterial()->getBestTechnique();
1114 				if (t)
1115 				{
1116 					Pass* p = t->getPass(0);
1117 					if (p)
1118 					{
1119 						if (p->hasVertexProgram())
1120 						{
1121 							mVertexProgramInUse = true;
1122                         }
1123                     }
1124 				}
1125 
1126 				while (geomIt.hasMoreElements())
1127 				{
1128 					GeometryBucket* geom = geomIt.getNext();
1129 
1130 					// Check we're dealing with 16-bit indexes here
1131 					// Since stencil shadows can only deal with 16-bit
1132 					// More than that and stencil is probably too CPU-heavy
1133 					// in any case
1134 					assert(geom->getIndexData()->indexBuffer->getType()
1135 						== HardwareIndexBuffer::IT_16BIT &&
1136 						"Only 16-bit indexes allowed when using stencil shadows");
1137 					eb.addVertexData(geom->getVertexData());
1138 					eb.addIndexData(geom->getIndexData(), vertexSet++);
1139 				}
1140 
1141 			}
1142 		}
1143 
1144 		if (stencilShadows)
1145 		{
1146 			mEdgeList = eb.build();
1147 		}
1148 	}
1149 	//--------------------------------------------------------------------------
addRenderables(RenderQueue * queue,uint8 group,Real lodValue)1150 	void StaticGeometry::LODBucket::addRenderables(RenderQueue* queue,
1151 		uint8 group, Real lodValue)
1152 	{
1153 		// Just pass this on to child buckets
1154 		MaterialBucketMap::iterator i, iend;
1155 		iend =  mMaterialBucketMap.end();
1156 		for (i = mMaterialBucketMap.begin(); i != iend; ++i)
1157 		{
1158 			i->second->addRenderables(queue, group, lodValue);
1159 		}
1160 	}
1161 	//--------------------------------------------------------------------------
1162 	StaticGeometry::LODBucket::MaterialIterator
getMaterialIterator(void)1163 	StaticGeometry::LODBucket::getMaterialIterator(void)
1164 	{
1165 		return MaterialIterator(
1166 			mMaterialBucketMap.begin(), mMaterialBucketMap.end());
1167 	}
1168 	//--------------------------------------------------------------------------
dump(std::ofstream & of) const1169 	void StaticGeometry::LODBucket::dump(std::ofstream& of) const
1170 	{
1171 		of << "LOD Bucket " << mLod << std::endl;
1172 		of << "------------------" << std::endl;
1173 		of << "LOD Value: " << mLodValue << std::endl;
1174 		of << "Number of Materials: " << mMaterialBucketMap.size() << std::endl;
1175 		for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin();
1176 			i != mMaterialBucketMap.end(); ++i)
1177 		{
1178 			i->second->dump(of);
1179 		}
1180 		of << "------------------" << std::endl;
1181 
1182 	}
1183 	//---------------------------------------------------------------------
visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)1184 	void StaticGeometry::LODBucket::visitRenderables(Renderable::Visitor* visitor,
1185 		bool debugRenderables)
1186 	{
1187 		for (MaterialBucketMap::const_iterator i = mMaterialBucketMap.begin();
1188 			i != mMaterialBucketMap.end(); ++i)
1189 		{
1190 			i->second->visitRenderables(visitor, debugRenderables);
1191 		}
1192 
1193 	}
1194 	//---------------------------------------------------------------------
updateShadowRenderables(ShadowTechnique shadowTechnique,const Vector4 & lightPos,HardwareIndexBufferSharedPtr * indexBuffer,bool extrude,Real extrusionDistance,unsigned long flags)1195 	void StaticGeometry::LODBucket::updateShadowRenderables(
1196 		ShadowTechnique shadowTechnique, const Vector4& lightPos,
1197 		HardwareIndexBufferSharedPtr* indexBuffer, bool extrude,
1198 		Real extrusionDistance, unsigned long flags /* = 0  */)
1199 	{
1200 		assert(indexBuffer && "Only external index buffers are supported right now");
1201 		assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
1202 			"Only 16-bit indexes supported for now");
1203 
1204 		// We need to search the edge list for silhouette edges
1205 		if (!mEdgeList)
1206 		{
1207 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1208 				"You enabled stencil shadows after the buid process!",
1209 				"StaticGeometry::LODBucket::getShadowVolumeRenderableIterator");
1210 		}
1211 
1212 		// Init shadow renderable list if required
1213 		bool init = mShadowRenderables.empty();
1214 
1215 		EdgeData::EdgeGroupList::iterator egi;
1216 		ShadowCaster::ShadowRenderableList::iterator si, siend;
1217 		LODShadowRenderable* esr = 0;
1218 		if (init)
1219 			mShadowRenderables.resize(mEdgeList->edgeGroups.size());
1220 
1221 		//bool updatedSharedGeomNormals = false;
1222 		siend = mShadowRenderables.end();
1223 		egi = mEdgeList->edgeGroups.begin();
1224 		for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
1225 		{
1226 			if (init)
1227 			{
1228 				// Create a new renderable, create a separate light cap if
1229 				// we're using a vertex program (either for this model, or
1230 				// for extruding the shadow volume) since otherwise we can
1231 				// get depth-fighting on the light cap
1232 
1233 				*si = OGRE_NEW LODShadowRenderable(this, indexBuffer,
1234 					egi->vertexData, mVertexProgramInUse || !extrude);
1235 			}
1236 			// Get shadow renderable
1237 			esr = static_cast<LODShadowRenderable*>(*si);
1238 			HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
1239 			// Extrude vertices in software if required
1240 			if (extrude)
1241 			{
1242 				mParent->extrudeVertices(esrPositionBuffer,
1243 					egi->vertexData->vertexCount,
1244 					lightPos, extrusionDistance);
1245 
1246 			}
1247 
1248 		}
1249 
1250 	}
1251 	//--------------------------------------------------------------------------
1252 	//--------------------------------------------------------------------------
MaterialBucket(LODBucket * parent,const String & materialName)1253 	StaticGeometry::MaterialBucket::MaterialBucket(LODBucket* parent,
1254 		const String& materialName)
1255 		: mParent(parent)
1256 		, mMaterialName(materialName)
1257 		, mTechnique(0)
1258 	{
1259 	}
1260 	//--------------------------------------------------------------------------
~MaterialBucket()1261 	StaticGeometry::MaterialBucket::~MaterialBucket()
1262 	{
1263 		// delete
1264 		for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1265 			i != mGeometryBucketList.end(); ++i)
1266 		{
1267 			OGRE_DELETE *i;
1268 		}
1269 		mGeometryBucketList.clear();
1270 
1271 		// no need to delete queued meshes, these are managed in StaticGeometry
1272 	}
1273 	//--------------------------------------------------------------------------
assign(QueuedGeometry * qgeom)1274 	void StaticGeometry::MaterialBucket::assign(QueuedGeometry* qgeom)
1275 	{
1276 		// Look up any current geometry
1277 		String formatString = getGeometryFormatString(qgeom->geometry);
1278 		CurrentGeometryMap::iterator gi = mCurrentGeometryMap.find(formatString);
1279 		bool newBucket = true;
1280 		if (gi != mCurrentGeometryMap.end())
1281 		{
1282 			// Found existing geometry, try to assign
1283 			newBucket = !gi->second->assign(qgeom);
1284 			// Note that this bucket will be replaced as the 'current'
1285 			// for this format string below since it's out of space
1286 		}
1287 		// Do we need to create a new one?
1288 		if (newBucket)
1289 		{
1290 			GeometryBucket* gbucket = OGRE_NEW GeometryBucket(this, formatString,
1291 				qgeom->geometry->vertexData, qgeom->geometry->indexData);
1292 			// Add to main list
1293 			mGeometryBucketList.push_back(gbucket);
1294 			// Also index in 'current' list
1295 			mCurrentGeometryMap[formatString] = gbucket;
1296 			if (!gbucket->assign(qgeom))
1297 			{
1298 				OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
1299 					"Somehow we couldn't fit the requested geometry even in a "
1300 					"brand new GeometryBucket!! Must be a bug, please report.",
1301 					"StaticGeometry::MaterialBucket::assign");
1302 			}
1303 		}
1304 	}
1305 	//--------------------------------------------------------------------------
build(bool stencilShadows)1306 	void StaticGeometry::MaterialBucket::build(bool stencilShadows)
1307 	{
1308 		mTechnique = 0;
1309 		mMaterial = MaterialManager::getSingleton().getByName(mMaterialName);
1310 		if (mMaterial.isNull())
1311 		{
1312 			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1313 				"Material '" + mMaterialName + "' not found.",
1314 				"StaticGeometry::MaterialBucket::build");
1315 		}
1316 		mMaterial->load();
1317 		// tell the geometry buckets to build
1318 		for (GeometryBucketList::iterator i = mGeometryBucketList.begin();
1319 			i != mGeometryBucketList.end(); ++i)
1320 		{
1321 			(*i)->build(stencilShadows);
1322 		}
1323 	}
1324 	//--------------------------------------------------------------------------
addRenderables(RenderQueue * queue,uint8 group,Real lodValue)1325 	void StaticGeometry::MaterialBucket::addRenderables(RenderQueue* queue,
1326 		uint8 group, Real lodValue)
1327 	{
1328         // Get region
1329         Region *region = mParent->getParent();
1330 
1331         // Get material LOD strategy
1332         const LodStrategy *materialLodStrategy = mMaterial->getLodStrategy();
1333 
1334         // If material strategy doesn't match, recompute LOD value with correct strategy
1335         if (materialLodStrategy != region->mLodStrategy)
1336             lodValue = materialLodStrategy->getValue(region, region->mCamera);
1337 
1338 		// Determine the current material technique
1339 		mTechnique = mMaterial->getBestTechnique(
1340 			mMaterial->getLodIndex(lodValue));
1341 		GeometryBucketList::iterator i, iend;
1342 		iend =  mGeometryBucketList.end();
1343 		for (i = mGeometryBucketList.begin(); i != iend; ++i)
1344 		{
1345 			queue->addRenderable(*i, group);
1346 		}
1347 
1348 	}
1349 	//--------------------------------------------------------------------------
getGeometryFormatString(SubMeshLodGeometryLink * geom)1350 	String StaticGeometry::MaterialBucket::getGeometryFormatString(
1351 		SubMeshLodGeometryLink* geom)
1352 	{
1353 		// Formulate an identifying string for the geometry format
1354 		// Must take into account the vertex declaration and the index type
1355 		// Format is (all lines separated by '|'):
1356 		// Index type
1357 		// Vertex element (repeating)
1358 		//   source
1359 		//   semantic
1360 		//   type
1361 		StringUtil::StrStreamType str;
1362 
1363 		str << geom->indexData->indexBuffer->getType() << "|";
1364 		const VertexDeclaration::VertexElementList& elemList =
1365 			geom->vertexData->vertexDeclaration->getElements();
1366 		VertexDeclaration::VertexElementList::const_iterator ei, eiend;
1367 		eiend = elemList.end();
1368 		for (ei = elemList.begin(); ei != eiend; ++ei)
1369 		{
1370 			const VertexElement& elem = *ei;
1371 			str << elem.getSource() << "|";
1372 			str << elem.getSource() << "|";
1373 			str << elem.getSemantic() << "|";
1374 			str << elem.getType() << "|";
1375 		}
1376 
1377 		return str.str();
1378 
1379 	}
1380 	//--------------------------------------------------------------------------
1381 	StaticGeometry::MaterialBucket::GeometryIterator
getGeometryIterator(void)1382 	StaticGeometry::MaterialBucket::getGeometryIterator(void)
1383 	{
1384 		return GeometryIterator(
1385 			mGeometryBucketList.begin(), mGeometryBucketList.end());
1386 	}
1387 	//--------------------------------------------------------------------------
dump(std::ofstream & of) const1388 	void StaticGeometry::MaterialBucket::dump(std::ofstream& of) const
1389 	{
1390 		of << "Material Bucket " << mMaterialName << std::endl;
1391 		of << "--------------------------------------------------" << std::endl;
1392 		of << "Geometry buckets: " << mGeometryBucketList.size() << std::endl;
1393 		for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin();
1394 			i != mGeometryBucketList.end(); ++i)
1395 		{
1396 			(*i)->dump(of);
1397 		}
1398 		of << "--------------------------------------------------" << std::endl;
1399 
1400 	}
1401 	//---------------------------------------------------------------------
visitRenderables(Renderable::Visitor * visitor,bool debugRenderables)1402 	void StaticGeometry::MaterialBucket::visitRenderables(Renderable::Visitor* visitor,
1403 		bool debugRenderables)
1404 	{
1405 		for (GeometryBucketList::const_iterator i = mGeometryBucketList.begin();
1406 			i != mGeometryBucketList.end(); ++i)
1407 		{
1408 			visitor->visit(*i, mParent->getLod(), false);
1409 		}
1410 
1411 	}
1412 	//--------------------------------------------------------------------------
1413 	//--------------------------------------------------------------------------
GeometryBucket(MaterialBucket * parent,const String & formatString,const VertexData * vData,const IndexData * iData)1414 	StaticGeometry::GeometryBucket::GeometryBucket(MaterialBucket* parent,
1415 		const String& formatString, const VertexData* vData,
1416 		const IndexData* iData)
1417 		: Renderable(), mParent(parent), mFormatString(formatString)
1418 	{
1419 		// Clone the structure from the example
1420 		mVertexData = vData->clone(false);
1421 		mIndexData = iData->clone(false);
1422 		mVertexData->vertexCount = 0;
1423 		mVertexData->vertexStart = 0;
1424 		mIndexData->indexCount = 0;
1425 		mIndexData->indexStart = 0;
1426 		mIndexType = iData->indexBuffer->getType();
1427 		// Derive the max vertices
1428 		if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1429 		{
1430 			mMaxVertexIndex = 0xFFFFFFFF;
1431 		}
1432 		else
1433 		{
1434 			mMaxVertexIndex = 0xFFFF;
1435 		}
1436 
1437 		// Check to see if we have blend indices / blend weights
1438 		// remove them if so, they can try to blend non-existent bones!
1439 		const VertexElement* blendIndices =
1440 			mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
1441 		const VertexElement* blendWeights =
1442 			mVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
1443 		if (blendIndices && blendWeights)
1444 		{
1445 			assert(blendIndices->getSource() == blendWeights->getSource()
1446 				&& "Blend indices and weights should be in the same buffer");
1447 			// Get the source
1448 			ushort source = blendIndices->getSource();
1449 			assert(blendIndices->getSize() + blendWeights->getSize() ==
1450 				mVertexData->vertexBufferBinding->getBuffer(source)->getVertexSize()
1451 				&& "Blend indices and blend buffers should have buffer to themselves!");
1452 			// Unset the buffer
1453 			mVertexData->vertexBufferBinding->unsetBinding(source);
1454 			// Remove the elements
1455 			mVertexData->vertexDeclaration->removeElement(VES_BLEND_INDICES);
1456 			mVertexData->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
1457             // Close gaps in bindings for effective and safely
1458             mVertexData->closeGapsInBindings();
1459 		}
1460 
1461 
1462 	}
1463 	//--------------------------------------------------------------------------
~GeometryBucket()1464 	StaticGeometry::GeometryBucket::~GeometryBucket()
1465 	{
1466 		OGRE_DELETE mVertexData;
1467 		OGRE_DELETE mIndexData;
1468 	}
1469 	//--------------------------------------------------------------------------
getMaterial(void) const1470 	const MaterialPtr& StaticGeometry::GeometryBucket::getMaterial(void) const
1471 	{
1472 		return mParent->getMaterial();
1473 	}
1474 	//--------------------------------------------------------------------------
getTechnique(void) const1475 	Technique* StaticGeometry::GeometryBucket::getTechnique(void) const
1476 	{
1477 		return mParent->getCurrentTechnique();
1478 	}
1479 	//--------------------------------------------------------------------------
getRenderOperation(RenderOperation & op)1480 	void StaticGeometry::GeometryBucket::getRenderOperation(RenderOperation& op)
1481 	{
1482 		op.indexData = mIndexData;
1483 		op.operationType = RenderOperation::OT_TRIANGLE_LIST;
1484 		op.srcRenderable = this;
1485 		op.useIndexes = true;
1486 		op.vertexData = mVertexData;
1487 	}
1488 	//--------------------------------------------------------------------------
getWorldTransforms(Matrix4 * xform) const1489 	void StaticGeometry::GeometryBucket::getWorldTransforms(Matrix4* xform) const
1490 	{
1491 		// Should be the identity transform, but lets allow transformation of the
1492 		// nodes the regions are attached to for kicks
1493 		*xform = mParent->getParent()->getParent()->_getParentNodeFullTransform();
1494 	}
1495 	//--------------------------------------------------------------------------
getSquaredViewDepth(const Camera * cam) const1496 	Real StaticGeometry::GeometryBucket::getSquaredViewDepth(const Camera* cam) const
1497 	{
1498         const Region *region = mParent->getParent()->getParent();
1499         if (cam == region->mCamera)
1500             return region->mSquaredViewDepth;
1501         else
1502             return region->getParentNode()->getSquaredViewDepth(cam->getLodCamera());
1503 	}
1504 	//--------------------------------------------------------------------------
getLights(void) const1505 	const LightList& StaticGeometry::GeometryBucket::getLights(void) const
1506 	{
1507 		return mParent->getParent()->getParent()->queryLights();
1508 	}
1509 	//--------------------------------------------------------------------------
getCastsShadows(void) const1510 	bool StaticGeometry::GeometryBucket::getCastsShadows(void) const
1511 	{
1512 		return mParent->getParent()->getParent()->getCastShadows();
1513 	}
1514 	//--------------------------------------------------------------------------
assign(QueuedGeometry * qgeom)1515 	bool StaticGeometry::GeometryBucket::assign(QueuedGeometry* qgeom)
1516 	{
1517 		// Do we have enough space?
1518 		// -2 first to avoid overflow (-1 to adjust count to index, -1 to ensure
1519 		// no overflow at 32 bits and use >= instead of >)
1520 		if ((mVertexData->vertexCount - 2 + qgeom->geometry->vertexData->vertexCount)
1521 			>= mMaxVertexIndex)
1522 		{
1523 			return false;
1524 		}
1525 
1526 		mQueuedGeometry.push_back(qgeom);
1527 		mVertexData->vertexCount += qgeom->geometry->vertexData->vertexCount;
1528 		mIndexData->indexCount += qgeom->geometry->indexData->indexCount;
1529 
1530 		return true;
1531 	}
1532 	//--------------------------------------------------------------------------
build(bool stencilShadows)1533 	void StaticGeometry::GeometryBucket::build(bool stencilShadows)
1534 	{
1535 		// Ok, here's where we transfer the vertices and indexes to the shared
1536 		// buffers
1537 		// Shortcuts
1538 		VertexDeclaration* dcl = mVertexData->vertexDeclaration;
1539 		VertexBufferBinding* binds = mVertexData->vertexBufferBinding;
1540 
1541 		// create index buffer, and lock
1542 		mIndexData->indexBuffer = HardwareBufferManager::getSingleton()
1543 			.createIndexBuffer(mIndexType, mIndexData->indexCount,
1544 				HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1545 		uint32* p32Dest = 0;
1546 		uint16* p16Dest = 0;
1547 		if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1548 		{
1549 			p32Dest = static_cast<uint32*>(
1550 				mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1551 		}
1552 		else
1553 		{
1554 			p16Dest = static_cast<uint16*>(
1555 				mIndexData->indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
1556 		}
1557 		// create all vertex buffers, and lock
1558 		ushort b;
1559 		ushort posBufferIdx = dcl->findElementBySemantic(VES_POSITION)->getSource();
1560 
1561 		vector<uchar*>::type destBufferLocks;
1562 		vector<VertexDeclaration::VertexElementList>::type bufferElements;
1563 		for (b = 0; b < binds->getBufferCount(); ++b)
1564 		{
1565 			size_t vertexCount = mVertexData->vertexCount;
1566 			// Need to double the vertex count for the position buffer
1567 			// if we're doing stencil shadows
1568 			if (stencilShadows && b == posBufferIdx)
1569 			{
1570 				vertexCount = vertexCount * 2;
1571 				assert(vertexCount <= mMaxVertexIndex &&
1572 					"Index range exceeded when using stencil shadows, consider "
1573 					"reducing your region size or reducing poly count");
1574 			}
1575 			HardwareVertexBufferSharedPtr vbuf =
1576 				HardwareBufferManager::getSingleton().createVertexBuffer(
1577 					dcl->getVertexSize(b),
1578 					vertexCount,
1579 					HardwareBuffer::HBU_STATIC_WRITE_ONLY);
1580 			binds->setBinding(b, vbuf);
1581 			uchar* pLock = static_cast<uchar*>(
1582 				vbuf->lock(HardwareBuffer::HBL_DISCARD));
1583 			destBufferLocks.push_back(pLock);
1584 			// Pre-cache vertex elements per buffer
1585 			bufferElements.push_back(dcl->findElementsBySource(b));
1586 		}
1587 
1588 
1589 		// Iterate over the geometry items
1590 		size_t indexOffset = 0;
1591 		QueuedGeometryList::iterator gi, giend;
1592 		giend = mQueuedGeometry.end();
1593 		Vector3 regionCentre = mParent->getParent()->getParent()->getCentre();
1594 		for (gi = mQueuedGeometry.begin(); gi != giend; ++gi)
1595 		{
1596 			QueuedGeometry* geom = *gi;
1597 			// Copy indexes across with offset
1598 			IndexData* srcIdxData = geom->geometry->indexData;
1599 			if (mIndexType == HardwareIndexBuffer::IT_32BIT)
1600 			{
1601 				// Lock source indexes
1602 				uint32* pSrc = static_cast<uint32*>(
1603 					srcIdxData->indexBuffer->lock(
1604 						srcIdxData->indexStart,
1605 						srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
1606 						HardwareBuffer::HBL_READ_ONLY));
1607 
1608 				copyIndexes(pSrc, p32Dest, srcIdxData->indexCount, indexOffset);
1609 				p32Dest += srcIdxData->indexCount;
1610 				srcIdxData->indexBuffer->unlock();
1611 			}
1612 			else
1613 			{
1614 				// Lock source indexes
1615 				uint16* pSrc = static_cast<uint16*>(
1616 					srcIdxData->indexBuffer->lock(
1617 					srcIdxData->indexStart,
1618 					srcIdxData->indexCount * srcIdxData->indexBuffer->getIndexSize(),
1619 					HardwareBuffer::HBL_READ_ONLY));
1620 
1621 				copyIndexes(pSrc, p16Dest, srcIdxData->indexCount, indexOffset);
1622 				p16Dest += srcIdxData->indexCount;
1623 				srcIdxData->indexBuffer->unlock();
1624 			}
1625 
1626 			// Now deal with vertex buffers
1627 			// we can rely on buffer counts / formats being the same
1628 			VertexData* srcVData = geom->geometry->vertexData;
1629 			VertexBufferBinding* srcBinds = srcVData->vertexBufferBinding;
1630 			for (b = 0; b < binds->getBufferCount(); ++b)
1631 			{
1632 				// lock source
1633 				HardwareVertexBufferSharedPtr srcBuf =
1634 					srcBinds->getBuffer(b);
1635 				uchar* pSrcBase = static_cast<uchar*>(
1636 					srcBuf->lock(HardwareBuffer::HBL_READ_ONLY));
1637 				// Get buffer lock pointer, we'll update this later
1638 				uchar* pDstBase = destBufferLocks[b];
1639 				size_t bufInc = srcBuf->getVertexSize();
1640 
1641 				// Iterate over vertices
1642 				float *pSrcReal, *pDstReal;
1643 				Vector3 tmp;
1644 				for (size_t v = 0; v < srcVData->vertexCount; ++v)
1645 				{
1646 					// Iterate over vertex elements
1647 					VertexDeclaration::VertexElementList& elems =
1648 						bufferElements[b];
1649 					VertexDeclaration::VertexElementList::iterator ei;
1650 					for (ei = elems.begin(); ei != elems.end(); ++ei)
1651 					{
1652 						VertexElement& elem = *ei;
1653 						elem.baseVertexPointerToElement(pSrcBase, &pSrcReal);
1654 						elem.baseVertexPointerToElement(pDstBase, &pDstReal);
1655 						switch (elem.getSemantic())
1656 						{
1657 						case VES_POSITION:
1658 							tmp.x = *pSrcReal++;
1659 							tmp.y = *pSrcReal++;
1660 							tmp.z = *pSrcReal++;
1661 							// transform
1662 							tmp = (geom->orientation * (tmp * geom->scale)) +
1663 								geom->position;
1664 							// Adjust for region centre
1665 							tmp -= regionCentre;
1666 							*pDstReal++ = tmp.x;
1667 							*pDstReal++ = tmp.y;
1668 							*pDstReal++ = tmp.z;
1669 							break;
1670 						case VES_NORMAL:
1671 						case VES_TANGENT:
1672 						case VES_BINORMAL:
1673 							tmp.x = *pSrcReal++;
1674 							tmp.y = *pSrcReal++;
1675 							tmp.z = *pSrcReal++;
1676 							// scale (invert)
1677 							tmp = tmp / geom->scale;
1678 							tmp.normalise();
1679 							// rotation
1680 							tmp = geom->orientation * tmp;
1681 							*pDstReal++ = tmp.x;
1682 							*pDstReal++ = tmp.y;
1683 							*pDstReal++ = tmp.z;
1684 							// copy parity for tangent.
1685 							if (elem.getType() == Ogre::VET_FLOAT4)
1686 								*pDstReal = *pSrcReal;
1687 							break;
1688 						default:
1689 							// just raw copy
1690 							memcpy(pDstReal, pSrcReal,
1691 									VertexElement::getTypeSize(elem.getType()));
1692 							break;
1693 						};
1694 
1695 					}
1696 
1697 					// Increment both pointers
1698 					pDstBase += bufInc;
1699 					pSrcBase += bufInc;
1700 
1701 				}
1702 
1703 				// Update pointer
1704 				destBufferLocks[b] = pDstBase;
1705 				srcBuf->unlock();
1706 			}
1707 
1708 			indexOffset += geom->geometry->vertexData->vertexCount;
1709 		}
1710 
1711 		// Unlock everything
1712 		mIndexData->indexBuffer->unlock();
1713 		for (b = 0; b < binds->getBufferCount(); ++b)
1714 		{
1715 			binds->getBuffer(b)->unlock();
1716 		}
1717 
1718 		// If we're dealing with stencil shadows, copy the position data from
1719 		// the early half of the buffer to the latter part
1720 		if (stencilShadows)
1721 		{
1722 			HardwareVertexBufferSharedPtr buf = binds->getBuffer(posBufferIdx);
1723 			void* pSrc = buf->lock(HardwareBuffer::HBL_NORMAL);
1724 			// Point dest at second half (remember vertexcount is original count)
1725 			void* pDest = static_cast<uchar*>(pSrc) +
1726 				buf->getVertexSize() * mVertexData->vertexCount;
1727 			memcpy(pDest, pSrc, buf->getVertexSize() * mVertexData->vertexCount);
1728 			buf->unlock();
1729 
1730 			// Also set up hardware W buffer if appropriate
1731 			RenderSystem* rend = Root::getSingleton().getRenderSystem();
1732 			if (rend && rend->getCapabilities()->hasCapability(RSC_VERTEX_PROGRAM))
1733 			{
1734 				buf = HardwareBufferManager::getSingleton().createVertexBuffer(
1735 					sizeof(float), mVertexData->vertexCount * 2,
1736 					HardwareBuffer::HBU_STATIC_WRITE_ONLY, false);
1737 				// Fill the first half with 1.0, second half with 0.0
1738 				float *pW = static_cast<float*>(
1739 					buf->lock(HardwareBuffer::HBL_DISCARD));
1740 				size_t v;
1741 				for (v = 0; v < mVertexData->vertexCount; ++v)
1742 				{
1743 					*pW++ = 1.0f;
1744 				}
1745 				for (v = 0; v < mVertexData->vertexCount; ++v)
1746 				{
1747 					*pW++ = 0.0f;
1748 				}
1749 				buf->unlock();
1750 				mVertexData->hardwareShadowVolWBuffer = buf;
1751 			}
1752 		}
1753 
1754 	}
1755 	//--------------------------------------------------------------------------
dump(std::ofstream & of) const1756 	void StaticGeometry::GeometryBucket::dump(std::ofstream& of) const
1757 	{
1758 		of << "Geometry Bucket" << std::endl;
1759 		of << "---------------" << std::endl;
1760 		of << "Format string: " << mFormatString << std::endl;
1761 		of << "Geometry items: " << mQueuedGeometry.size() << std::endl;
1762 		of << "Vertex count: " << mVertexData->vertexCount << std::endl;
1763 		of << "Index count: " << mIndexData->indexCount << std::endl;
1764 		of << "---------------" << std::endl;
1765 
1766 	}
1767 	//--------------------------------------------------------------------------
1768 
1769 }
1770 
1771