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 "OgreMesh.h"
30 
31 #include "OgreSubMesh.h"
32 #include "OgreLogManager.h"
33 #include "OgreMeshSerializer.h"
34 #include "OgreSkeletonManager.h"
35 #include "OgreHardwareBufferManager.h"
36 #include "OgreStringConverter.h"
37 #include "OgreException.h"
38 #include "OgreMeshManager.h"
39 #include "OgreEdgeListBuilder.h"
40 #include "OgreAnimation.h"
41 #include "OgreAnimationState.h"
42 #include "OgreAnimationTrack.h"
43 #include "OgreOptimisedUtil.h"
44 #include "OgreTangentSpaceCalc.h"
45 #include "OgreLodStrategyManager.h"
46 #include "OgreLodConfig.h"
47 #include "OgrePixelCountLodStrategy.h"
48 
49 namespace Ogre {
50     //-----------------------------------------------------------------------
Mesh(ResourceManager * creator,const String & name,ResourceHandle handle,const String & group,bool isManual,ManualResourceLoader * loader)51     Mesh::Mesh(ResourceManager* creator, const String& name, ResourceHandle handle,
52         const String& group, bool isManual, ManualResourceLoader* loader)
53         : Resource(creator, name, handle, group, isManual, loader),
54         mBoundRadius(0.0f),
55         mBoneAssignmentsOutOfDate(false),
56         mIsLodManual(false),
57         mNumLods(1),
58         mVertexBufferUsage(HardwareBuffer::HBU_STATIC_WRITE_ONLY),
59         mIndexBufferUsage(HardwareBuffer::HBU_STATIC_WRITE_ONLY),
60         mVertexBufferShadowBuffer(true),
61         mIndexBufferShadowBuffer(true),
62         mPreparedForShadowVolumes(false),
63         mEdgeListsBuilt(false),
64         mAutoBuildEdgeLists(true), // will be set to false by serializers of 1.30 and above
65 		mSharedVertexDataAnimationType(VAT_NONE),
66 		mSharedVertexDataAnimationIncludesNormals(false),
67 		mAnimationTypesDirty(true),
68 		mPosesIncludeNormals(false),
69 		sharedVertexData(0)
70     {
71 
72         // Initialise to default strategy
73         mLodStrategy = LodStrategyManager::getSingleton().getDefaultStrategy();
74 
75 		// Init first (manual) lod
76 		MeshLodUsage lod;
77         lod.userValue = 0; // User value not used for base LOD level
78 		lod.value = mLodStrategy->getBaseValue();
79         lod.edgeData = NULL;
80         lod.manualMesh.setNull();
81 		mMeshLodUsageList.push_back(lod);
82 
83     }
84     //-----------------------------------------------------------------------
~Mesh()85     Mesh::~Mesh()
86     {
87         // have to call this here reather than in Resource destructor
88         // since calling virtual methods in base destructors causes crash
89         unload();
90     }
91     //-----------------------------------------------------------------------
createSubMesh()92     SubMesh* Mesh::createSubMesh()
93     {
94         SubMesh* sub = OGRE_NEW SubMesh();
95         sub->parent = this;
96 
97         mSubMeshList.push_back(sub);
98 
99 		if (isLoaded())
100 			_dirtyState();
101 
102         return sub;
103     }
104     //-----------------------------------------------------------------------
createSubMesh(const String & name)105     SubMesh* Mesh::createSubMesh(const String& name)
106 	{
107 		SubMesh *sub = createSubMesh();
108 		nameSubMesh(name, (ushort)mSubMeshList.size()-1);
109 		return sub ;
110 	}
111     //-----------------------------------------------------------------------
destroySubMesh(unsigned short index)112 	void Mesh::destroySubMesh(unsigned short index)
113 	{
114         if (index >= mSubMeshList.size())
115         {
116             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
117 						"Index out of bounds.",
118 						"Mesh::removeSubMesh");
119         }
120 		SubMeshList::iterator i = mSubMeshList.begin();
121 		std::advance(i, index);
122 		mSubMeshList.erase(i);
123 
124 		// Fix up any name/index entries
125 		for(SubMeshNameMap::iterator ni = mSubMeshNameMap.begin(); ni != mSubMeshNameMap.end();)
126 		{
127 			if (ni->second == index)
128 			{
129 				SubMeshNameMap::iterator eraseIt = ni++;
130 				mSubMeshNameMap.erase(eraseIt);
131 			}
132 			else
133 			{
134 				// reduce indexes following
135 				if (ni->second > index)
136 					ni->second = ni->second - 1;
137 
138 				++ni;
139 			}
140 		}
141 
142 		// fix edge list data by simply recreating all edge lists
143 		if( mEdgeListsBuilt)
144 		{
145 			this->freeEdgeList();
146 			this->buildEdgeList();
147 		}
148 
149 		if (isLoaded())
150 			_dirtyState();
151 
152 	}
153     //-----------------------------------------------------------------------
destroySubMesh(const String & name)154     void Mesh::destroySubMesh(const String& name)
155 	{
156 		unsigned short index = _getSubMeshIndex(name);
157 		destroySubMesh(index);
158 	}
159 	//-----------------------------------------------------------------------
getNumSubMeshes() const160     unsigned short Mesh::getNumSubMeshes() const
161     {
162         return static_cast< unsigned short >( mSubMeshList.size() );
163     }
164 
165     //---------------------------------------------------------------------
nameSubMesh(const String & name,ushort index)166 	void Mesh::nameSubMesh(const String& name, ushort index)
167 	{
168 		mSubMeshNameMap[name] = index ;
169 	}
170 
171 	//---------------------------------------------------------------------
unnameSubMesh(const String & name)172 	void Mesh::unnameSubMesh(const String& name)
173 	{
174 		SubMeshNameMap::iterator i = mSubMeshNameMap.find(name);
175 		if (i != mSubMeshNameMap.end())
176 			mSubMeshNameMap.erase(i);
177 	}
178     //-----------------------------------------------------------------------
getSubMesh(const String & name) const179     SubMesh* Mesh::getSubMesh(const String& name) const
180 	{
181 		ushort index = _getSubMeshIndex(name);
182 		return getSubMesh(index);
183 	}
184     //-----------------------------------------------------------------------
getSubMesh(unsigned short index) const185     SubMesh* Mesh::getSubMesh(unsigned short index) const
186     {
187         if (index >= mSubMeshList.size())
188         {
189             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
190                 "Index out of bounds.",
191                 "Mesh::getSubMesh");
192         }
193 
194         return mSubMeshList[index];
195     }
196 	//-----------------------------------------------------------------------
postLoadImpl(void)197 	void Mesh::postLoadImpl(void)
198 	{
199 		// Prepare for shadow volumes?
200 		if (MeshManager::getSingleton().getPrepareAllMeshesForShadowVolumes())
201 		{
202 			if (mEdgeListsBuilt || mAutoBuildEdgeLists)
203 			{
204 				prepareForShadowVolume();
205 			}
206 
207 			if (!mEdgeListsBuilt && mAutoBuildEdgeLists)
208 			{
209 				buildEdgeList();
210 			}
211 		}
212 
213         // The loading process accesses LOD usages directly, so
214         // transformation of user values must occur after loading is complete.
215 
216         // Transform user LOD values (starting at index 1, no need to transform base value)
217 		for (MeshLodUsageList::iterator i = mMeshLodUsageList.begin(); i != mMeshLodUsageList.end(); ++i)
218             i->value = mLodStrategy->transformUserValue(i->userValue);
219 	}
220 	//-----------------------------------------------------------------------
prepareImpl()221     void Mesh::prepareImpl()
222     {
223         // Load from specified 'name'
224         if (getCreator()->getVerbose())
225             LogManager::getSingleton().logMessage("Mesh: Loading "+mName+".");
226 
227         mFreshFromDisk =
228             ResourceGroupManager::getSingleton().openResource(
229 				mName, mGroup, true, this);
230 
231         // fully prebuffer into host RAM
232         mFreshFromDisk = DataStreamPtr(OGRE_NEW MemoryDataStream(mName,mFreshFromDisk));
233     }
234     //-----------------------------------------------------------------------
unprepareImpl()235     void Mesh::unprepareImpl()
236     {
237         mFreshFromDisk.setNull();
238     }
loadImpl()239     void Mesh::loadImpl()
240     {
241         MeshSerializer serializer;
242         serializer.setListener(MeshManager::getSingleton().getListener());
243 
244         // If the only copy is local on the stack, it will be cleaned
245         // up reliably in case of exceptions, etc
246         DataStreamPtr data(mFreshFromDisk);
247         mFreshFromDisk.setNull();
248 
249         if (data.isNull()) {
250             OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
251                         "Data doesn't appear to have been prepared in " + mName,
252                         "Mesh::loadImpl()");
253         }
254 
255 		serializer.importMesh(data, this);
256 
257         /* check all submeshes to see if their materials should be
258            updated.  If the submesh has texture aliases that match those
259            found in the current material then a new material is created using
260            the textures from the submesh.
261         */
262         updateMaterialForAllSubMeshes();
263     }
264 
265     //-----------------------------------------------------------------------
unloadImpl()266     void Mesh::unloadImpl()
267     {
268         // Teardown submeshes
269         for (SubMeshList::iterator i = mSubMeshList.begin();
270             i != mSubMeshList.end(); ++i)
271         {
272             OGRE_DELETE *i;
273         }
274         if (sharedVertexData)
275         {
276             OGRE_DELETE sharedVertexData;
277             sharedVertexData = NULL;
278         }
279 		// Clear SubMesh lists
280 		mSubMeshList.clear();
281 		mSubMeshNameMap.clear();
282         // Removes all LOD data
283         removeLodLevels();
284         mPreparedForShadowVolumes = false;
285 
286 		// remove all poses & animations
287 		removeAllAnimations();
288 		removeAllPoses();
289 
290         // Clear bone assignments
291         mBoneAssignments.clear();
292         mBoneAssignmentsOutOfDate = false;
293 
294         // Removes reference to skeleton
295         setSkeletonName(StringUtil::BLANK);
296     }
297 
298     //-----------------------------------------------------------------------
clone(const String & newName,const String & newGroup)299     MeshPtr Mesh::clone(const String& newName, const String& newGroup)
300     {
301         // This is a bit like a copy constructor, but with the additional aspect of registering the clone with
302         //  the MeshManager
303 
304         // New Mesh is assumed to be manually defined rather than loaded since you're cloning it for a reason
305         String theGroup;
306         if (newGroup == StringUtil::BLANK)
307         {
308             theGroup = this->getGroup();
309         }
310         else
311         {
312             theGroup = newGroup;
313         }
314         MeshPtr newMesh = MeshManager::getSingleton().createManual(newName, theGroup);
315 
316         // Copy submeshes first
317         vector<SubMesh*>::type::iterator subi;
318         for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi)
319         {
320             (*subi)->clone("", newMesh.get());
321         }
322 
323         // Copy shared geometry and index map, if any
324         if (sharedVertexData)
325         {
326             newMesh->sharedVertexData = sharedVertexData->clone();
327             newMesh->sharedBlendIndexToBoneIndexMap = sharedBlendIndexToBoneIndexMap;
328         }
329 
330 		// Copy submesh names
331 		newMesh->mSubMeshNameMap = mSubMeshNameMap ;
332         // Copy any bone assignments
333         newMesh->mBoneAssignments = mBoneAssignments;
334         newMesh->mBoneAssignmentsOutOfDate = mBoneAssignmentsOutOfDate;
335         // Copy bounds
336         newMesh->mAABB = mAABB;
337         newMesh->mBoundRadius = mBoundRadius;
338 
339         newMesh->mLodStrategy = mLodStrategy;
340 		newMesh->mIsLodManual = mIsLodManual;
341 		newMesh->mNumLods = mNumLods;
342 		newMesh->mMeshLodUsageList = mMeshLodUsageList;
343         newMesh->mAutoBuildEdgeLists = mAutoBuildEdgeLists;
344         // Unreference edge lists, otherwise we'll delete the same lot twice, build on demand
345         MeshLodUsageList::iterator lodi;
346         for (lodi = newMesh->mMeshLodUsageList.begin(); lodi != newMesh->mMeshLodUsageList.end(); ++lodi) {
347             MeshLodUsage& lod = *lodi;
348             lod.edgeData = NULL;
349             // TODO: Copy manual LOD meshes
350         }
351 
352 		newMesh->mVertexBufferUsage = mVertexBufferUsage;
353 		newMesh->mIndexBufferUsage = mIndexBufferUsage;
354 		newMesh->mVertexBufferShadowBuffer = mVertexBufferShadowBuffer;
355 		newMesh->mIndexBufferShadowBuffer = mIndexBufferShadowBuffer;
356 
357         newMesh->mSkeletonName = mSkeletonName;
358         newMesh->mSkeleton = mSkeleton;
359 
360 		// Keep prepared shadow volume info (buffers may already be prepared)
361 		newMesh->mPreparedForShadowVolumes = mPreparedForShadowVolumes;
362 
363 		// mEdgeListsBuilt and edgeData of mMeshLodUsageList
364 		// will up to date on demand. Not copied since internal references, and mesh
365 		// data may be altered
366 
367 		// Clone vertex animation
368 		for (AnimationList::iterator i = mAnimationsList.begin();
369 			i != mAnimationsList.end(); ++i)
370 		{
371 			Animation *newAnim = i->second->clone(i->second->getName());
372 			newMesh->mAnimationsList[i->second->getName()] = newAnim;
373 		}
374 		// Clone pose list
375 		for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i)
376 		{
377 			Pose* newPose = (*i)->clone();
378 			newMesh->mPoseList.push_back(newPose);
379 		}
380 		newMesh->mSharedVertexDataAnimationType = mSharedVertexDataAnimationType;
381 		newMesh->mAnimationTypesDirty = true;
382 
383         newMesh->load();
384         newMesh->touch();
385 
386         return newMesh;
387     }
388     //-----------------------------------------------------------------------
getBounds(void) const389     const AxisAlignedBox& Mesh::getBounds(void) const
390     {
391         return mAABB;
392     }
393     //-----------------------------------------------------------------------
_setBounds(const AxisAlignedBox & bounds,bool pad)394     void Mesh::_setBounds(const AxisAlignedBox& bounds, bool pad)
395     {
396         mAABB = bounds;
397 		mBoundRadius = Math::boundingRadiusFromAABB(mAABB);
398 
399 		if( mAABB.isFinite() )
400 		{
401 			Vector3 max = mAABB.getMaximum();
402 			Vector3 min = mAABB.getMinimum();
403 
404 			if (pad)
405 			{
406 				// Pad out the AABB a little, helps with most bounds tests
407 				Vector3 scaler = (max - min) * MeshManager::getSingleton().getBoundsPaddingFactor();
408 				mAABB.setExtents(min  - scaler, max + scaler);
409 				// Pad out the sphere a little too
410 				mBoundRadius = mBoundRadius + (mBoundRadius * MeshManager::getSingleton().getBoundsPaddingFactor());
411 			}
412 		}
413     }
414     //-----------------------------------------------------------------------
_setBoundingSphereRadius(Real radius)415     void Mesh::_setBoundingSphereRadius(Real radius)
416     {
417         mBoundRadius = radius;
418     }
419     //-----------------------------------------------------------------------
setSkeletonName(const String & skelName)420     void Mesh::setSkeletonName(const String& skelName)
421     {
422 		if (skelName != mSkeletonName)
423 		{
424 			mSkeletonName = skelName;
425 
426 			if (skelName.empty())
427 			{
428 				// No skeleton
429 				mSkeleton.setNull();
430 			}
431 			else
432 			{
433 				// Load skeleton
434 				try {
435 					mSkeleton = SkeletonManager::getSingleton().load(skelName, mGroup).staticCast<Skeleton>();
436 				}
437 				catch (...)
438 				{
439 					mSkeleton.setNull();
440 					// Log this error
441 					String msg = "Unable to load skeleton ";
442 					msg += skelName + " for Mesh " + mName
443 						+ ". This Mesh will not be animated. "
444 						+ "You can ignore this message if you are using an offline tool.";
445 					LogManager::getSingleton().logMessage(msg);
446 
447 				}
448 
449 
450 			}
451 			if (isLoaded())
452 				_dirtyState();
453 		}
454     }
455     //-----------------------------------------------------------------------
hasSkeleton(void) const456     bool Mesh::hasSkeleton(void) const
457     {
458         return !(mSkeletonName.empty());
459     }
460     //-----------------------------------------------------------------------
getSkeleton(void) const461     const SkeletonPtr& Mesh::getSkeleton(void) const
462     {
463         return mSkeleton;
464     }
465     //-----------------------------------------------------------------------
addBoneAssignment(const VertexBoneAssignment & vertBoneAssign)466     void Mesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign)
467     {
468         mBoneAssignments.insert(
469             VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign));
470         mBoneAssignmentsOutOfDate = true;
471     }
472     //-----------------------------------------------------------------------
clearBoneAssignments(void)473     void Mesh::clearBoneAssignments(void)
474     {
475         mBoneAssignments.clear();
476         mBoneAssignmentsOutOfDate = true;
477     }
478     //-----------------------------------------------------------------------
_initAnimationState(AnimationStateSet * animSet)479     void Mesh::_initAnimationState(AnimationStateSet* animSet)
480     {
481 		// Animation states for skeletal animation
482 		if (!mSkeleton.isNull())
483 		{
484 			// Delegate to Skeleton
485 			mSkeleton->_initAnimationState(animSet);
486 
487 			// Take the opportunity to update the compiled bone assignments
488             _updateCompiledBoneAssignments();
489 		}
490 
491 		// Animation states for vertex animation
492 		for (AnimationList::iterator i = mAnimationsList.begin();
493 			i != mAnimationsList.end(); ++i)
494 		{
495 			// Only create a new animation state if it doesn't exist
496 			// We can have the same named animation in both skeletal and vertex
497 			// with a shared animation state affecting both, for combined effects
498 			// The animations should be the same length if this feature is used!
499 			if (!animSet->hasAnimationState(i->second->getName()))
500 			{
501 				animSet->createAnimationState(i->second->getName(), 0.0,
502 					i->second->getLength());
503 			}
504 
505 		}
506 
507     }
508 	//---------------------------------------------------------------------
_refreshAnimationState(AnimationStateSet * animSet)509 	void Mesh::_refreshAnimationState(AnimationStateSet* animSet)
510 	{
511 		if (!mSkeleton.isNull())
512 		{
513 			mSkeleton->_refreshAnimationState(animSet);
514 		}
515 
516 		// Merge in any new vertex animations
517 		AnimationList::iterator i;
518 		for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i)
519 		{
520 			Animation* anim = i->second;
521 			// Create animation at time index 0, default params mean this has weight 1 and is disabled
522 			const String& animName = anim->getName();
523 			if (!animSet->hasAnimationState(animName))
524 			{
525 				animSet->createAnimationState(animName, 0.0, anim->getLength());
526 			}
527 			else
528 			{
529 				// Update length incase changed
530 				AnimationState* animState = animSet->getAnimationState(animName);
531 				animState->setLength(anim->getLength());
532 				animState->setTimePosition(std::min(anim->getLength(), animState->getTimePosition()));
533 			}
534 		}
535 
536 	}
537     //-----------------------------------------------------------------------
_updateCompiledBoneAssignments(void)538     void Mesh::_updateCompiledBoneAssignments(void)
539     {
540         if (mBoneAssignmentsOutOfDate)
541             _compileBoneAssignments();
542 
543         SubMeshList::iterator i;
544         for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i)
545         {
546             if ((*i)->mBoneAssignmentsOutOfDate)
547             {
548                 (*i)->_compileBoneAssignments();
549             }
550         }
551     }
552     //-----------------------------------------------------------------------
553     typedef multimap<Real, Mesh::VertexBoneAssignmentList::iterator>::type WeightIteratorMap;
_rationaliseBoneAssignments(size_t vertexCount,Mesh::VertexBoneAssignmentList & assignments)554     unsigned short Mesh::_rationaliseBoneAssignments(size_t vertexCount, Mesh::VertexBoneAssignmentList& assignments)
555     {
556         // Iterate through, finding the largest # bones per vertex
557         unsigned short maxBones = 0;
558 		bool existsNonSkinnedVertices = false;
559         VertexBoneAssignmentList::iterator i;
560 
561         for (size_t v = 0; v < vertexCount; ++v)
562         {
563             // Get number of entries for this vertex
564             short currBones = static_cast<unsigned short>(assignments.count(v));
565 			if (currBones <= 0)
566 				existsNonSkinnedVertices = true;
567 
568             // Deal with max bones update
569             // (note this will record maxBones even if they exceed limit)
570             if (maxBones < currBones)
571                 maxBones = currBones;
572             // does the number of bone assignments exceed limit?
573             if (currBones > OGRE_MAX_BLEND_WEIGHTS)
574             {
575                 // To many bone assignments on this vertex
576                 // Find the start & end (end is in iterator terms ie exclusive)
577                 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> range;
578                 // map to sort by weight
579                 WeightIteratorMap weightToAssignmentMap;
580                 range = assignments.equal_range(v);
581                 // Add all the assignments to map
582                 for (i = range.first; i != range.second; ++i)
583                 {
584                     // insert value weight->iterator
585                     weightToAssignmentMap.insert(
586                         WeightIteratorMap::value_type(i->second.weight, i));
587                 }
588                 // Reverse iterate over weight map, remove lowest n
589                 unsigned short numToRemove = currBones - OGRE_MAX_BLEND_WEIGHTS;
590                 WeightIteratorMap::iterator remIt = weightToAssignmentMap.begin();
591 
592                 while (numToRemove--)
593                 {
594                     // Erase this one
595                     assignments.erase(remIt->second);
596                     ++remIt;
597                 }
598             } // if (currBones > OGRE_MAX_BLEND_WEIGHTS)
599 
600             // Make sure the weights are normalised
601             // Do this irrespective of whether we had to remove assignments or not
602             //   since it gives us a guarantee that weights are normalised
603             //  We assume this, so it's a good idea since some modellers may not
604             std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> normalise_range = assignments.equal_range(v);
605             Real totalWeight = 0;
606             // Find total first
607             for (i = normalise_range.first; i != normalise_range.second; ++i)
608             {
609                 totalWeight += i->second.weight;
610             }
611             // Now normalise if total weight is outside tolerance
612             if (!Math::RealEqual(totalWeight, 1.0f))
613             {
614                 for (i = normalise_range.first; i != normalise_range.second; ++i)
615                 {
616                     i->second.weight = i->second.weight / totalWeight;
617                 }
618             }
619 
620         }
621 
622 		if (maxBones > OGRE_MAX_BLEND_WEIGHTS)
623 		{
624             // Warn that we've reduced bone assignments
625             LogManager::getSingleton().logMessage("WARNING: the mesh '" + mName + "' "
626                 "includes vertices with more than " +
627                 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + " bone assignments. "
628                 "The lowest weighted assignments beyond this limit have been removed, so "
629                 "your animation may look slightly different. To eliminate this, reduce "
630                 "the number of bone assignments per vertex on your mesh to " +
631                 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + ".", LML_CRITICAL);
632             // we've adjusted them down to the max
633             maxBones = OGRE_MAX_BLEND_WEIGHTS;
634 
635         }
636 
637 		if (existsNonSkinnedVertices)
638 		{
639             // Warn that we've non-skinned vertices
640             LogManager::getSingleton().logMessage("WARNING: the mesh '" + mName + "' "
641                 "includes vertices without bone assignments. Those vertices will "
642 				"transform to wrong position when skeletal animation enabled. "
643 				"To eliminate this, assign at least one bone assignment per vertex "
644 				"on your mesh.", LML_CRITICAL);
645 		}
646 
647         return maxBones;
648     }
649     //-----------------------------------------------------------------------
_compileBoneAssignments(void)650     void  Mesh::_compileBoneAssignments(void)
651     {
652 		if (sharedVertexData)
653 		{
654 			unsigned short maxBones = _rationaliseBoneAssignments(sharedVertexData->vertexCount, mBoneAssignments);
655 
656 			if (maxBones != 0)
657 			{
658 				compileBoneAssignments(mBoneAssignments, maxBones,
659 					sharedBlendIndexToBoneIndexMap, sharedVertexData);
660 			}
661 		}
662         mBoneAssignmentsOutOfDate = false;
663     }
664     //---------------------------------------------------------------------
buildIndexMap(const VertexBoneAssignmentList & boneAssignments,IndexMap & boneIndexToBlendIndexMap,IndexMap & blendIndexToBoneIndexMap)665     void Mesh::buildIndexMap(const VertexBoneAssignmentList& boneAssignments,
666         IndexMap& boneIndexToBlendIndexMap, IndexMap& blendIndexToBoneIndexMap)
667     {
668         if (boneAssignments.empty())
669         {
670             // Just in case
671             boneIndexToBlendIndexMap.clear();
672             blendIndexToBoneIndexMap.clear();
673             return;
674         }
675 
676         typedef set<unsigned short>::type BoneIndexSet;
677         BoneIndexSet usedBoneIndices;
678 
679         // Collect actually used bones
680         VertexBoneAssignmentList::const_iterator itVBA, itendVBA;
681         itendVBA = boneAssignments.end();
682         for (itVBA = boneAssignments.begin(); itVBA != itendVBA; ++itVBA)
683         {
684             usedBoneIndices.insert(itVBA->second.boneIndex);
685         }
686 
687         // Allocate space for index map
688         blendIndexToBoneIndexMap.resize(usedBoneIndices.size());
689         boneIndexToBlendIndexMap.resize(*usedBoneIndices.rbegin() + 1);
690 
691         // Make index map between bone index and blend index
692         BoneIndexSet::const_iterator itBoneIndex, itendBoneIndex;
693         unsigned short blendIndex = 0;
694         itendBoneIndex = usedBoneIndices.end();
695         for (itBoneIndex = usedBoneIndices.begin(); itBoneIndex != itendBoneIndex; ++itBoneIndex, ++blendIndex)
696         {
697             boneIndexToBlendIndexMap[*itBoneIndex] = blendIndex;
698             blendIndexToBoneIndexMap[blendIndex] = *itBoneIndex;
699         }
700     }
701     //---------------------------------------------------------------------
compileBoneAssignments(const VertexBoneAssignmentList & boneAssignments,unsigned short numBlendWeightsPerVertex,IndexMap & blendIndexToBoneIndexMap,VertexData * targetVertexData)702     void Mesh::compileBoneAssignments(
703         const VertexBoneAssignmentList& boneAssignments,
704         unsigned short numBlendWeightsPerVertex,
705         IndexMap& blendIndexToBoneIndexMap,
706         VertexData* targetVertexData)
707     {
708         // Create or reuse blend weight / indexes buffer
709         // Indices are always a UBYTE4 no matter how many weights per vertex
710         // Weights are more specific though since they are Reals
711         VertexDeclaration* decl = targetVertexData->vertexDeclaration;
712         VertexBufferBinding* bind = targetVertexData->vertexBufferBinding;
713         unsigned short bindIndex;
714 
715         // Build the index map brute-force. It's possible to store the index map
716         // in .mesh, but maybe trivial.
717         IndexMap boneIndexToBlendIndexMap;
718         buildIndexMap(boneAssignments, boneIndexToBlendIndexMap, blendIndexToBoneIndexMap);
719 
720         const VertexElement* testElem =
721             decl->findElementBySemantic(VES_BLEND_INDICES);
722         if (testElem)
723         {
724             // Already have a buffer, unset it & delete elements
725             bindIndex = testElem->getSource();
726             // unset will cause deletion of buffer
727             bind->unsetBinding(bindIndex);
728             decl->removeElement(VES_BLEND_INDICES);
729             decl->removeElement(VES_BLEND_WEIGHTS);
730         }
731         else
732         {
733             // Get new binding
734             bindIndex = bind->getNextIndex();
735         }
736 
737         HardwareVertexBufferSharedPtr vbuf =
738             HardwareBufferManager::getSingleton().createVertexBuffer(
739                 sizeof(unsigned char)*4 + sizeof(float)*numBlendWeightsPerVertex,
740                 targetVertexData->vertexCount,
741                 HardwareBuffer::HBU_STATIC_WRITE_ONLY,
742                 true // use shadow buffer
743                 );
744         // bind new buffer
745         bind->setBinding(bindIndex, vbuf);
746         const VertexElement *pIdxElem, *pWeightElem;
747 
748         // add new vertex elements
749         // Note, insert directly after all elements using the same source as
750         // position to abide by pre-Dx9 format restrictions
751         const VertexElement* firstElem = decl->getElement(0);
752         if(firstElem->getSemantic() == VES_POSITION)
753         {
754             unsigned short insertPoint = 1;
755             while (insertPoint < decl->getElementCount() &&
756                 decl->getElement(insertPoint)->getSource() == firstElem->getSource())
757             {
758                 ++insertPoint;
759             }
760             const VertexElement& idxElem =
761                 decl->insertElement(insertPoint, bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES);
762             const VertexElement& wtElem =
763                 decl->insertElement(insertPoint+1, bindIndex, sizeof(unsigned char)*4,
764                 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex),
765                 VES_BLEND_WEIGHTS);
766             pIdxElem = &idxElem;
767             pWeightElem = &wtElem;
768         }
769         else
770         {
771             // Position is not the first semantic, therefore this declaration is
772             // not pre-Dx9 compatible anyway, so just tack it on the end
773             const VertexElement& idxElem =
774                 decl->addElement(bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES);
775             const VertexElement& wtElem =
776                 decl->addElement(bindIndex, sizeof(unsigned char)*4,
777                 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex),
778                 VES_BLEND_WEIGHTS);
779             pIdxElem = &idxElem;
780             pWeightElem = &wtElem;
781         }
782 
783         // Assign data
784         size_t v;
785         VertexBoneAssignmentList::const_iterator i, iend;
786         i = boneAssignments.begin();
787 		iend = boneAssignments.end();
788         unsigned char *pBase = static_cast<unsigned char*>(
789             vbuf->lock(HardwareBuffer::HBL_DISCARD));
790         // Iterate by vertex
791         float *pWeight;
792         unsigned char *pIndex;
793         for (v = 0; v < targetVertexData->vertexCount; ++v)
794         {
795             /// Convert to specific pointers
796             pWeightElem->baseVertexPointerToElement(pBase, &pWeight);
797             pIdxElem->baseVertexPointerToElement(pBase, &pIndex);
798             for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone)
799             {
800                 // Do we still have data for this vertex?
801                 if (i != iend && i->second.vertexIndex == v)
802                 {
803                     // If so, write weight
804                     *pWeight++ = i->second.weight;
805                     *pIndex++ = static_cast<unsigned char>(boneIndexToBlendIndexMap[i->second.boneIndex]);
806                     ++i;
807                 }
808                 else
809                 {
810                     // Ran out of assignments for this vertex, use weight 0 to indicate empty.
811 					// If no bones are defined (an error in itself) set bone 0 as the assigned bone.
812                     *pWeight++ = (bone == 0) ? 1.0f : 0.0f;
813                     *pIndex++ = 0;
814                 }
815             }
816             pBase += vbuf->getVertexSize();
817         }
818 
819         vbuf->unlock();
820 
821     }
822     //---------------------------------------------------------------------
_notifySkeleton(SkeletonPtr & pSkel)823     void Mesh::_notifySkeleton(SkeletonPtr& pSkel)
824     {
825         mSkeleton = pSkel;
826         mSkeletonName = pSkel->getName();
827     }
828     //---------------------------------------------------------------------
getBoneAssignmentIterator(void)829     Mesh::BoneAssignmentIterator Mesh::getBoneAssignmentIterator(void)
830     {
831         return BoneAssignmentIterator(mBoneAssignments.begin(),
832             mBoneAssignments.end());
833     }
834     //---------------------------------------------------------------------
getSkeletonName(void) const835     const String& Mesh::getSkeletonName(void) const
836     {
837         return mSkeletonName;
838     }
839     //---------------------------------------------------------------------
getNumLodLevels(void) const840     ushort Mesh::getNumLodLevels(void) const
841     {
842         return mNumLods;
843     }
844     //---------------------------------------------------------------------
getLodLevel(ushort index) const845     const MeshLodUsage& Mesh::getLodLevel(ushort index) const
846     {
847         index = std::min(index, (ushort)(mMeshLodUsageList.size() - 1));
848         if (mIsLodManual && index > 0 && mMeshLodUsageList[index].manualMesh.isNull())
849         {
850             // Load the mesh now
851 			try {
852 				String groupName = mMeshLodUsageList[index].manualGroup.empty() ?
853 					mGroup : mMeshLodUsageList[index].manualGroup;
854 				mMeshLodUsageList[index].manualMesh =
855 					MeshManager::getSingleton().load(
856 						mMeshLodUsageList[index].manualName,
857 						groupName);
858 				// get the edge data, if required
859 				if (!mMeshLodUsageList[index].edgeData)
860 				{
861 					mMeshLodUsageList[index].edgeData =
862 						mMeshLodUsageList[index].manualMesh->getEdgeList(0);
863 				}
864 			}
865 			catch (Exception& )
866 			{
867 				LogManager::getSingleton().stream()
868 					<< "Error while loading manual LOD level "
869 					<< mMeshLodUsageList[index].manualName
870 					<< " - this LOD level will not be rendered. You can "
871 					<< "ignore this error in offline mesh tools.";
872 			}
873 
874         }
875         return mMeshLodUsageList[index];
876     }
877     //---------------------------------------------------------------------
createManualLodLevel(Real lodValue,const String & meshName,const String & groupName)878 	void Mesh::createManualLodLevel(Real lodValue, const String& meshName, const String& groupName)
879 	{
880 
881 		// Basic prerequisites
882         assert((mIsLodManual || mNumLods == 1) && "Generated LODs already in use!");
883 
884 		mIsLodManual = true;
885 		MeshLodUsage lod;
886 		lod.userValue = lodValue;
887         lod.value = mLodStrategy->transformUserValue(lod.userValue);
888 		lod.manualName = meshName;
889 		lod.manualGroup = groupName.empty() ? mGroup : groupName;
890 		lod.manualMesh.setNull();
891         lod.edgeData = 0;
892 		mMeshLodUsageList.push_back(lod);
893 		++mNumLods;
894 
895         mLodStrategy->sort(mMeshLodUsageList);
896 	}
897     //---------------------------------------------------------------------
updateManualLodLevel(ushort index,const String & meshName)898 	void Mesh::updateManualLodLevel(ushort index, const String& meshName)
899 	{
900 
901 		// Basic prerequisites
902 		assert(mIsLodManual && "Not using manual LODs!");
903 		assert(index != 0 && "Can't modify first LOD level (full detail)");
904 		assert(index < mMeshLodUsageList.size() && "Idndex out of bounds");
905 		// get lod
906 		MeshLodUsage* lod = &(mMeshLodUsageList[index]);
907 
908 		lod->manualName = meshName;
909 		lod->manualMesh.setNull();
910         if (lod->edgeData) OGRE_DELETE lod->edgeData;
911         lod->edgeData = 0;
912 	}
913     //---------------------------------------------------------------------
getLodIndex(Real value) const914 	ushort Mesh::getLodIndex(Real value) const
915 	{
916         // Get index from strategy
917         return mLodStrategy->getIndex(value, mMeshLodUsageList);
918 	}
919     //---------------------------------------------------------------------
_setLodInfo(unsigned short numLevels,bool isManual)920 	void Mesh::_setLodInfo(unsigned short numLevels, bool isManual)
921 	{
922         assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built");
923 
924 		// Basic prerequisites
925         assert(numLevels > 0 && "Must be at least one level (full detail level must exist)");
926 
927 		mNumLods = numLevels;
928 		mMeshLodUsageList.resize(numLevels);
929 		// Resize submesh face data lists too
930 		for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i)
931 		{
932 			(*i)->mLodFaceList.resize(numLevels - 1);
933 		}
934 		mIsLodManual = isManual;
935 	}
936     //---------------------------------------------------------------------
_setLodUsage(unsigned short level,MeshLodUsage & usage)937 	void Mesh::_setLodUsage(unsigned short level, MeshLodUsage& usage)
938 	{
939         assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built");
940 
941 		// Basic prerequisites
942 		assert(level != 0 && "Can't modify first LOD level (full detail)");
943 		assert(level < mMeshLodUsageList.size() && "Index out of bounds");
944 
945 		mMeshLodUsageList[level] = usage;
946 	}
947     //---------------------------------------------------------------------
_setSubMeshLodFaceList(unsigned short subIdx,unsigned short level,IndexData * facedata)948 	void Mesh::_setSubMeshLodFaceList(unsigned short subIdx, unsigned short level,
949 		IndexData* facedata)
950 	{
951         assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built");
952 
953 		// Basic prerequisites
954 		assert(!mIsLodManual && "Not using generated LODs!");
955         assert(subIdx <= mSubMeshList.size() && "Index out of bounds");
956 		assert(level != 0 && "Can't modify first LOD level (full detail)");
957 		assert(level <= mSubMeshList[subIdx]->mLodFaceList.size() && "Index out of bounds");
958 
959 		SubMesh* sm = mSubMeshList[subIdx];
960 		sm->mLodFaceList[level - 1] = facedata;
961 
962 	}
963     //---------------------------------------------------------------------
_getSubMeshIndex(const String & name) const964 	ushort Mesh::_getSubMeshIndex(const String& name) const
965 	{
966 		SubMeshNameMap::const_iterator i = mSubMeshNameMap.find(name) ;
967 		if (i == mSubMeshNameMap.end())
968             OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No SubMesh named " + name + " found.",
969                 "Mesh::_getSubMeshIndex");
970 
971 		return i->second;
972 	}
973     //---------------------------------------------------------------------
removeLodLevels(void)974     void Mesh::removeLodLevels(void)
975     {
976         if (!mIsLodManual)
977         {
978             // Remove data from SubMeshes
979             SubMeshList::iterator isub, isubend;
980             isubend = mSubMeshList.end();
981             for (isub = mSubMeshList.begin(); isub != isubend; ++isub)
982             {
983                 (*isub)->removeLodLevels();
984             }
985         }
986 
987         freeEdgeList();
988         mMeshLodUsageList.clear();
989 
990         // Reinitialise
991         mNumLods = 1;
992 		// Init first (manual) lod
993 		MeshLodUsage lod;
994         lod.userValue = 0;
995 		lod.value = mLodStrategy->getBaseValue();
996         lod.edgeData = 0;
997         lod.manualMesh.setNull();
998 		mMeshLodUsageList.push_back(lod);
999 		mIsLodManual = false;
1000 
1001 
1002     }
1003     //---------------------------------------------------------------------
getBoundingSphereRadius(void) const1004     Real Mesh::getBoundingSphereRadius(void) const
1005     {
1006         return mBoundRadius;
1007     }
1008     //---------------------------------------------------------------------
setVertexBufferPolicy(HardwareBuffer::Usage vbUsage,bool shadowBuffer)1009 	void Mesh::setVertexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer)
1010 	{
1011 		mVertexBufferUsage = vbUsage;
1012 		mVertexBufferShadowBuffer = shadowBuffer;
1013 	}
1014     //---------------------------------------------------------------------
setIndexBufferPolicy(HardwareBuffer::Usage vbUsage,bool shadowBuffer)1015 	void Mesh::setIndexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer)
1016 	{
1017 		mIndexBufferUsage = vbUsage;
1018 		mIndexBufferShadowBuffer = shadowBuffer;
1019 	}
1020 	//---------------------------------------------------------------------
mergeAdjacentTexcoords(unsigned short finalTexCoordSet,unsigned short texCoordSetToDestroy)1021 	void Mesh::mergeAdjacentTexcoords( unsigned short finalTexCoordSet,
1022 										unsigned short texCoordSetToDestroy )
1023 	{
1024 		if( sharedVertexData )
1025 			mergeAdjacentTexcoords( finalTexCoordSet, texCoordSetToDestroy, sharedVertexData );
1026 
1027 		SubMeshList::const_iterator itor = mSubMeshList.begin();
1028 		SubMeshList::const_iterator end  = mSubMeshList.end();
1029 
1030 		while( itor != end )
1031 		{
1032 			if( !(*itor)->useSharedVertices )
1033 				mergeAdjacentTexcoords( finalTexCoordSet, texCoordSetToDestroy, (*itor)->vertexData );
1034 			++itor;
1035 		}
1036 	}
1037 	//---------------------------------------------------------------------
mergeAdjacentTexcoords(unsigned short finalTexCoordSet,unsigned short texCoordSetToDestroy,VertexData * vertexData)1038 	void Mesh::mergeAdjacentTexcoords( unsigned short finalTexCoordSet,
1039 										unsigned short texCoordSetToDestroy,
1040 										VertexData *vertexData )
1041 	{
1042 		VertexDeclaration *vDecl	= vertexData->vertexDeclaration;
1043 
1044 	    const VertexElement *uv0 = vDecl->findElementBySemantic( VES_TEXTURE_COORDINATES,
1045 																	finalTexCoordSet );
1046 		const VertexElement *uv1 = vDecl->findElementBySemantic( VES_TEXTURE_COORDINATES,
1047 																	texCoordSetToDestroy );
1048 
1049 		if( uv0 && uv1 )
1050 		{
1051 			//Check that both base types are compatible (mix floats w/ shorts) and there's enough space
1052 			VertexElementType baseType0 = VertexElement::getBaseType( uv0->getType() );
1053 			VertexElementType baseType1 = VertexElement::getBaseType( uv1->getType() );
1054 
1055 			unsigned short totalTypeCount = VertexElement::getTypeCount( uv0->getType() ) +
1056 											VertexElement::getTypeCount( uv1->getType() );
1057 			if( baseType0 == baseType1 && totalTypeCount <= 4 )
1058 			{
1059 				const VertexDeclaration::VertexElementList &veList = vDecl->getElements();
1060 				VertexDeclaration::VertexElementList::const_iterator uv0Itor = std::find( veList.begin(),
1061 																					veList.end(), *uv0 );
1062 				unsigned short elem_idx		= std::distance( veList.begin(), uv0Itor );
1063 				VertexElementType newType	= VertexElement::multiplyTypeCount( baseType0,
1064 																				totalTypeCount );
1065 
1066 				if( ( uv0->getOffset() + uv0->getSize() == uv1->getOffset() ||
1067 					  uv1->getOffset() + uv1->getSize() == uv0->getOffset() ) &&
1068 					uv0->getSource() == uv1->getSource() )
1069 				{
1070 					//Special case where they adjacent, just change the declaration & we're done.
1071 					size_t newOffset		= std::min( uv0->getOffset(), uv1->getOffset() );
1072 					unsigned short newIdx	= std::min( uv0->getIndex(), uv1->getIndex() );
1073 
1074 					vDecl->modifyElement( elem_idx, uv0->getSource(), newOffset, newType,
1075 											VES_TEXTURE_COORDINATES, newIdx );
1076 					vDecl->removeElement( VES_TEXTURE_COORDINATES, texCoordSetToDestroy );
1077 					uv1 = 0;
1078 				}
1079 
1080 				vDecl->closeGapsInSource();
1081 			}
1082 		}
1083 	}
1084     //---------------------------------------------------------------------
organiseTangentsBuffer(VertexData * vertexData,VertexElementSemantic targetSemantic,unsigned short index,unsigned short sourceTexCoordSet)1085     void Mesh::organiseTangentsBuffer(VertexData *vertexData,
1086         VertexElementSemantic targetSemantic, unsigned short index,
1087 		unsigned short sourceTexCoordSet)
1088     {
1089 	    VertexDeclaration *vDecl = vertexData->vertexDeclaration ;
1090 	    VertexBufferBinding *vBind = vertexData->vertexBufferBinding ;
1091 
1092 	    const VertexElement *tangentsElem = vDecl->findElementBySemantic(targetSemantic, index);
1093 	    bool needsToBeCreated = false;
1094 
1095 	    if (!tangentsElem)
1096         { // no tex coords with index 1
1097 			    needsToBeCreated = true ;
1098 	    }
1099         else if (tangentsElem->getType() != VET_FLOAT3)
1100         {
1101             //  buffer exists, but not 3D
1102             OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1103                 "Target semantic set already exists but is not 3D, therefore "
1104 				"cannot contain tangents. Pick an alternative destination semantic. ",
1105                 "Mesh::organiseTangentsBuffer");
1106 	    }
1107 
1108 	    HardwareVertexBufferSharedPtr newBuffer;
1109 	    if (needsToBeCreated)
1110         {
1111             // To be most efficient with our vertex streams,
1112             // tack the new tangents onto the same buffer as the
1113             // source texture coord set
1114             const VertexElement* prevTexCoordElem =
1115                 vertexData->vertexDeclaration->findElementBySemantic(
1116                     VES_TEXTURE_COORDINATES, sourceTexCoordSet);
1117             if (!prevTexCoordElem)
1118             {
1119                 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1120                     "Cannot locate the first texture coordinate element to "
1121 					"which to append the new tangents.",
1122 					"Mesh::orgagniseTangentsBuffer");
1123             }
1124             // Find the buffer associated with  this element
1125             HardwareVertexBufferSharedPtr origBuffer =
1126                 vertexData->vertexBufferBinding->getBuffer(
1127                     prevTexCoordElem->getSource());
1128             // Now create a new buffer, which includes the previous contents
1129             // plus extra space for the 3D coords
1130 		    newBuffer = HardwareBufferManager::getSingleton().createVertexBuffer(
1131                 origBuffer->getVertexSize() + 3*sizeof(float),
1132                 vertexData->vertexCount,
1133 			    origBuffer->getUsage(),
1134 			    origBuffer->hasShadowBuffer() );
1135             // Add the new element
1136 		    vDecl->addElement(
1137                 prevTexCoordElem->getSource(),
1138                 origBuffer->getVertexSize(),
1139                 VET_FLOAT3,
1140                 targetSemantic,
1141                 index);
1142             // Now copy the original data across
1143             unsigned char* pSrc = static_cast<unsigned char*>(
1144                 origBuffer->lock(HardwareBuffer::HBL_READ_ONLY));
1145             unsigned char* pDest = static_cast<unsigned char*>(
1146                 newBuffer->lock(HardwareBuffer::HBL_DISCARD));
1147             size_t vertSize = origBuffer->getVertexSize();
1148             for (size_t v = 0; v < vertexData->vertexCount; ++v)
1149             {
1150                 // Copy original vertex data
1151                 memcpy(pDest, pSrc, vertSize);
1152                 pSrc += vertSize;
1153                 pDest += vertSize;
1154                 // Set the new part to 0 since we'll accumulate in this
1155                 memset(pDest, 0, sizeof(float)*3);
1156                 pDest += sizeof(float)*3;
1157             }
1158             origBuffer->unlock();
1159             newBuffer->unlock();
1160 
1161             // Rebind the new buffer
1162             vBind->setBinding(prevTexCoordElem->getSource(), newBuffer);
1163 	    }
1164     }
1165     //---------------------------------------------------------------------
buildTangentVectors(VertexElementSemantic targetSemantic,unsigned short sourceTexCoordSet,unsigned short index,bool splitMirrored,bool splitRotated,bool storeParityInW)1166     void Mesh::buildTangentVectors(VertexElementSemantic targetSemantic,
1167 		unsigned short sourceTexCoordSet, unsigned short index,
1168 		bool splitMirrored, bool splitRotated, bool storeParityInW)
1169     {
1170 
1171 		TangentSpaceCalc tangentsCalc;
1172 		tangentsCalc.setSplitMirrored(splitMirrored);
1173 		tangentsCalc.setSplitRotated(splitRotated);
1174 		tangentsCalc.setStoreParityInW(storeParityInW);
1175 
1176 		// shared geometry first
1177 		if (sharedVertexData)
1178 		{
1179 			tangentsCalc.setVertexData(sharedVertexData);
1180 			bool found = false;
1181 			for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i)
1182 			{
1183 				SubMesh* sm = *i;
1184 				if (sm->useSharedVertices)
1185 				{
1186 					tangentsCalc.addIndexData(sm->indexData);
1187 					found = true;
1188 				}
1189 			}
1190 			if (found)
1191 			{
1192 				TangentSpaceCalc::Result res =
1193 					tangentsCalc.build(targetSemantic, sourceTexCoordSet, index);
1194 
1195 				// If any vertex splitting happened, we have to give them bone assignments
1196 				if (getSkeletonName() != StringUtil::BLANK)
1197 				{
1198 					for (TangentSpaceCalc::IndexRemapList::iterator r = res.indexesRemapped.begin();
1199 						r != res.indexesRemapped.end(); ++r)
1200 					{
1201 						TangentSpaceCalc::IndexRemap& remap = *r;
1202 						// Copy all bone assignments from the split vertex
1203 						VertexBoneAssignmentList::iterator vbstart = mBoneAssignments.lower_bound(remap.splitVertex.first);
1204 						VertexBoneAssignmentList::iterator vbend = mBoneAssignments.upper_bound(remap.splitVertex.first);
1205 						for (VertexBoneAssignmentList::iterator vba = vbstart; vba != vbend; ++vba)
1206 						{
1207 							VertexBoneAssignment newAsgn = vba->second;
1208 							newAsgn.vertexIndex = static_cast<unsigned int>(remap.splitVertex.second);
1209 							// multimap insert doesn't invalidate iterators
1210 							addBoneAssignment(newAsgn);
1211 						}
1212 
1213 					}
1214 				}
1215 
1216 				// Update poses (some vertices might have been duplicated)
1217 				// we will just check which vertices have been split and copy
1218 				// the offset for the original vertex to the corresponding new vertex
1219 				PoseIterator pose_it = getPoseIterator();
1220 
1221 				while( pose_it.hasMoreElements() )
1222 				{
1223 					Pose* current_pose = pose_it.getNext();
1224 					const Pose::VertexOffsetMap& offset_map = current_pose->getVertexOffsets();
1225 
1226 					for( TangentSpaceCalc::VertexSplits::iterator it = res.vertexSplits.begin();
1227 						it != res.vertexSplits.end(); ++it )
1228 					{
1229 						TangentSpaceCalc::VertexSplit& split = *it;
1230 
1231 						Pose::VertexOffsetMap::const_iterator found_offset = offset_map.find( split.first );
1232 
1233 						// copy the offset
1234 						if( found_offset != offset_map.end() )
1235 						{
1236 							current_pose->addVertex( split.second, found_offset->second );
1237 						}
1238 					}
1239 				}
1240 			}
1241 		}
1242 
1243 		// Dedicated geometry
1244 		for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i)
1245 		{
1246 			SubMesh* sm = *i;
1247 			if (!sm->useSharedVertices)
1248 			{
1249 				tangentsCalc.clear();
1250 				tangentsCalc.setVertexData(sm->vertexData);
1251                 tangentsCalc.addIndexData(sm->indexData, sm->operationType);
1252 				TangentSpaceCalc::Result res =
1253 					tangentsCalc.build(targetSemantic, sourceTexCoordSet, index);
1254 
1255 				// If any vertex splitting happened, we have to give them bone assignments
1256 				if (getSkeletonName() != StringUtil::BLANK)
1257 				{
1258 					for (TangentSpaceCalc::IndexRemapList::iterator r = res.indexesRemapped.begin();
1259 						r != res.indexesRemapped.end(); ++r)
1260 					{
1261 						TangentSpaceCalc::IndexRemap& remap = *r;
1262 						// Copy all bone assignments from the split vertex
1263 						VertexBoneAssignmentList::const_iterator vbstart =
1264 							sm->getBoneAssignments().lower_bound(remap.splitVertex.first);
1265 						VertexBoneAssignmentList::const_iterator vbend =
1266 							sm->getBoneAssignments().upper_bound(remap.splitVertex.first);
1267 						for (VertexBoneAssignmentList::const_iterator vba = vbstart; vba != vbend; ++vba)
1268 						{
1269 							VertexBoneAssignment newAsgn = vba->second;
1270 							newAsgn.vertexIndex = static_cast<unsigned int>(remap.splitVertex.second);
1271 							// multimap insert doesn't invalidate iterators
1272 							sm->addBoneAssignment(newAsgn);
1273 						}
1274 
1275 					}
1276 
1277 				}
1278 			}
1279 		}
1280 
1281     }
1282     //---------------------------------------------------------------------
suggestTangentVectorBuildParams(VertexElementSemantic targetSemantic,unsigned short & outSourceCoordSet,unsigned short & outIndex)1283     bool Mesh::suggestTangentVectorBuildParams(VertexElementSemantic targetSemantic,
1284 		unsigned short& outSourceCoordSet, unsigned short& outIndex)
1285     {
1286         // Go through all the vertex data and locate source and dest (must agree)
1287         bool sharedGeometryDone = false;
1288         bool foundExisting = false;
1289         bool firstOne = true;
1290         SubMeshList::iterator i, iend;
1291         iend = mSubMeshList.end();
1292         for (i = mSubMeshList.begin(); i != iend; ++i)
1293         {
1294             SubMesh* sm = *i;
1295             VertexData* vertexData;
1296 
1297             if (sm->useSharedVertices)
1298             {
1299                 if (sharedGeometryDone)
1300                     continue;
1301                 vertexData = sharedVertexData;
1302                 sharedGeometryDone = true;
1303             }
1304             else
1305             {
1306                 vertexData = sm->vertexData;
1307             }
1308 
1309             const VertexElement *sourceElem = 0;
1310             unsigned short targetIndex = 0;
1311             for (targetIndex = 0; targetIndex < OGRE_MAX_TEXTURE_COORD_SETS; ++targetIndex)
1312             {
1313                 const VertexElement* testElem =
1314                     vertexData->vertexDeclaration->findElementBySemantic(
1315                         VES_TEXTURE_COORDINATES, targetIndex);
1316                 if (!testElem)
1317                     break; // finish if we've run out, t will be the target
1318 
1319                 if (!sourceElem)
1320                 {
1321                     // We're still looking for the source texture coords
1322                     if (testElem->getType() == VET_FLOAT2)
1323                     {
1324                         // Ok, we found it
1325                         sourceElem = testElem;
1326                     }
1327                 }
1328 
1329 				if(!foundExisting && targetSemantic == VES_TEXTURE_COORDINATES)
1330                 {
1331                     // We're looking for the destination
1332                     // Check to see if we've found a possible
1333                     if (testElem->getType() == VET_FLOAT3)
1334                     {
1335                         // This is a 3D set, might be tangents
1336                         foundExisting = true;
1337                     }
1338 
1339                 }
1340 
1341             }
1342 
1343 			if (!foundExisting && targetSemantic != VES_TEXTURE_COORDINATES)
1344 			{
1345 				targetIndex = 0;
1346 				// Look for existing semantic
1347 				const VertexElement* testElem =
1348 					vertexData->vertexDeclaration->findElementBySemantic(
1349 					targetSemantic, targetIndex);
1350 				if (testElem)
1351 				{
1352 					foundExisting = true;
1353 				}
1354 
1355 			}
1356 
1357             // After iterating, we should have a source and a possible destination (t)
1358             if (!sourceElem)
1359             {
1360                 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1361                     "Cannot locate an appropriate 2D texture coordinate set for "
1362                     "all the vertex data in this mesh to create tangents from. ",
1363                     "Mesh::suggestTangentVectorBuildParams");
1364             }
1365             // Check that we agree with previous decisions, if this is not the
1366             // first one, and if we're not just using the existing one
1367             if (!firstOne && !foundExisting)
1368             {
1369                 if (sourceElem->getIndex() != outSourceCoordSet)
1370                 {
1371                     OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1372                         "Multiple sets of vertex data in this mesh disagree on "
1373                         "the appropriate index to use for the source texture coordinates. "
1374                         "This ambiguity must be rectified before tangents can be generated.",
1375                         "Mesh::suggestTangentVectorBuildParams");
1376                 }
1377                 if (targetIndex != outIndex)
1378                 {
1379                     OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1380                         "Multiple sets of vertex data in this mesh disagree on "
1381                         "the appropriate index to use for the target texture coordinates. "
1382                         "This ambiguity must be rectified before tangents can be generated.",
1383                         "Mesh::suggestTangentVectorBuildParams");
1384                 }
1385             }
1386 
1387             // Otherwise, save this result
1388             outSourceCoordSet = sourceElem->getIndex();
1389             outIndex = targetIndex;
1390 
1391             firstOne = false;
1392 
1393        }
1394 
1395         return foundExisting;
1396 
1397     }
1398     //---------------------------------------------------------------------
buildEdgeList(void)1399     void Mesh::buildEdgeList(void)
1400     {
1401         if (mEdgeListsBuilt)
1402             return;
1403 
1404         // Loop over LODs
1405         for (unsigned short lodIndex = 0; lodIndex < (unsigned short)mMeshLodUsageList.size(); ++lodIndex)
1406         {
1407             // use getLodLevel to enforce loading of manual mesh lods
1408             MeshLodUsage& usage = const_cast<MeshLodUsage&>(getLodLevel(lodIndex));
1409 
1410             if (mIsLodManual && lodIndex != 0)
1411             {
1412                 // Delegate edge building to manual mesh
1413                 // It should have already built it's own edge list while loading
1414 				if (!usage.manualMesh.isNull())
1415 				{
1416 					usage.edgeData = usage.manualMesh->getEdgeList(0);
1417 				}
1418             }
1419             else
1420             {
1421                 // Build
1422                 EdgeListBuilder eb;
1423                 size_t vertexSetCount = 0;
1424                 bool atLeastOneIndexSet = false;
1425 
1426                 if (sharedVertexData)
1427                 {
1428                     eb.addVertexData(sharedVertexData);
1429                     vertexSetCount++;
1430                 }
1431 
1432                 // Prepare the builder using the submesh information
1433                 SubMeshList::iterator i, iend;
1434                 iend = mSubMeshList.end();
1435                 for (i = mSubMeshList.begin(); i != iend; ++i)
1436                 {
1437                     SubMesh* s = *i;
1438 					if (s->operationType != RenderOperation::OT_TRIANGLE_FAN &&
1439 						s->operationType != RenderOperation::OT_TRIANGLE_LIST &&
1440 						s->operationType != RenderOperation::OT_TRIANGLE_STRIP)
1441 					{
1442                         continue;
1443 					}
1444                     if (s->useSharedVertices)
1445                     {
1446                         // Use shared vertex data, index as set 0
1447                         if (lodIndex == 0)
1448                         {
1449                             eb.addIndexData(s->indexData, 0, s->operationType);
1450                         }
1451                         else
1452                         {
1453                             eb.addIndexData(s->mLodFaceList[lodIndex-1], 0,
1454                                 s->operationType);
1455                         }
1456                     }
1457                     else if(s->isBuildEdgesEnabled())
1458                     {
1459                         // own vertex data, add it and reference it directly
1460                         eb.addVertexData(s->vertexData);
1461                         if (lodIndex == 0)
1462                         {
1463                             // Base index data
1464                             eb.addIndexData(s->indexData, vertexSetCount++,
1465                                 s->operationType);
1466                         }
1467                         else
1468                         {
1469                             // LOD index data
1470                             eb.addIndexData(s->mLodFaceList[lodIndex-1],
1471                                 vertexSetCount++, s->operationType);
1472                         }
1473 
1474                     }
1475 					atLeastOneIndexSet = true;
1476                 }
1477 
1478                 if (atLeastOneIndexSet)
1479 				{
1480 					usage.edgeData = eb.build();
1481 
1482                 #if OGRE_DEBUG_MODE
1483                     // Override default log
1484                     Log* log = LogManager::getSingleton().createLog(
1485                         mName + "_lod" + StringConverter::toString(lodIndex) +
1486                         "_prepshadow.log", false, false);
1487                     usage.edgeData->log(log);
1488 					// clean up log & close file handle
1489 					LogManager::getSingleton().destroyLog(log);
1490                 #endif
1491 				}
1492 				else
1493 				{
1494 					// create empty edge data
1495 					usage.edgeData = OGRE_NEW EdgeData();
1496 				}
1497             }
1498         }
1499         mEdgeListsBuilt = true;
1500     }
1501     //---------------------------------------------------------------------
freeEdgeList(void)1502     void Mesh::freeEdgeList(void)
1503     {
1504         if (!mEdgeListsBuilt)
1505             return;
1506 
1507         // Loop over LODs
1508         MeshLodUsageList::iterator i, iend;
1509         iend = mMeshLodUsageList.end();
1510         unsigned short index = 0;
1511         for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index)
1512         {
1513             MeshLodUsage& usage = *i;
1514 
1515             if (!mIsLodManual || index == 0)
1516             {
1517                 // Only delete if we own this data
1518                 // Manual LODs > 0 own their own
1519                 OGRE_DELETE usage.edgeData;
1520             }
1521             usage.edgeData = NULL;
1522         }
1523 
1524         mEdgeListsBuilt = false;
1525     }
1526     //---------------------------------------------------------------------
prepareForShadowVolume(void)1527     void Mesh::prepareForShadowVolume(void)
1528     {
1529         if (mPreparedForShadowVolumes)
1530             return;
1531 
1532         if (sharedVertexData)
1533         {
1534             sharedVertexData->prepareForShadowVolume();
1535         }
1536         SubMeshList::iterator i, iend;
1537         iend = mSubMeshList.end();
1538         for (i = mSubMeshList.begin(); i != iend; ++i)
1539         {
1540             SubMesh* s = *i;
1541             if (!s->useSharedVertices &&
1542 				(s->operationType == RenderOperation::OT_TRIANGLE_FAN ||
1543 				s->operationType == RenderOperation::OT_TRIANGLE_LIST ||
1544 				s->operationType == RenderOperation::OT_TRIANGLE_STRIP))
1545             {
1546                 s->vertexData->prepareForShadowVolume();
1547             }
1548         }
1549         mPreparedForShadowVolumes = true;
1550     }
1551     //---------------------------------------------------------------------
getEdgeList(unsigned short lodIndex)1552     EdgeData* Mesh::getEdgeList(unsigned short lodIndex)
1553     {
1554         // Build edge list on demand
1555         if (!mEdgeListsBuilt && mAutoBuildEdgeLists)
1556         {
1557             buildEdgeList();
1558         }
1559 
1560         return getLodLevel(lodIndex).edgeData;
1561     }
1562     //---------------------------------------------------------------------
getEdgeList(unsigned short lodIndex) const1563     const EdgeData* Mesh::getEdgeList(unsigned short lodIndex) const
1564     {
1565         return getLodLevel(lodIndex).edgeData;
1566     }
1567     //---------------------------------------------------------------------
prepareMatricesForVertexBlend(const Matrix4 ** blendMatrices,const Matrix4 * boneMatrices,const IndexMap & indexMap)1568     void Mesh::prepareMatricesForVertexBlend(const Matrix4** blendMatrices,
1569         const Matrix4* boneMatrices, const IndexMap& indexMap)
1570     {
1571         assert(indexMap.size() <= 256);
1572         IndexMap::const_iterator it, itend;
1573         itend = indexMap.end();
1574         for (it = indexMap.begin(); it != itend; ++it)
1575         {
1576             *blendMatrices++ = boneMatrices + *it;
1577         }
1578     }
1579     //---------------------------------------------------------------------
softwareVertexBlend(const VertexData * sourceVertexData,const VertexData * targetVertexData,const Matrix4 * const * blendMatrices,size_t numMatrices,bool blendNormals)1580     void Mesh::softwareVertexBlend(const VertexData* sourceVertexData,
1581         const VertexData* targetVertexData,
1582         const Matrix4* const* blendMatrices, size_t numMatrices,
1583         bool blendNormals)
1584     {
1585         float *pSrcPos = 0;
1586         float *pSrcNorm = 0;
1587         float *pDestPos = 0;
1588         float *pDestNorm = 0;
1589         float *pBlendWeight = 0;
1590         unsigned char* pBlendIdx = 0;
1591         size_t srcPosStride = 0;
1592         size_t srcNormStride = 0;
1593         size_t destPosStride = 0;
1594         size_t destNormStride = 0;
1595         size_t blendWeightStride = 0;
1596         size_t blendIdxStride = 0;
1597 
1598 
1599         // Get elements for source
1600         const VertexElement* srcElemPos =
1601             sourceVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1602         const VertexElement* srcElemNorm =
1603             sourceVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1604         const VertexElement* srcElemBlendIndices =
1605             sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
1606         const VertexElement* srcElemBlendWeights =
1607             sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
1608         assert (srcElemPos && srcElemBlendIndices && srcElemBlendWeights &&
1609             "You must supply at least positions, blend indices and blend weights");
1610         // Get elements for target
1611         const VertexElement* destElemPos =
1612             targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1613         const VertexElement* destElemNorm =
1614             targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1615 
1616         // Do we have normals and want to blend them?
1617         bool includeNormals = blendNormals && (srcElemNorm != NULL) && (destElemNorm != NULL);
1618 
1619 
1620         // Get buffers for source
1621         HardwareVertexBufferSharedPtr srcPosBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemPos->getSource());
1622 		HardwareVertexBufferSharedPtr srcIdxBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendIndices->getSource());
1623 		HardwareVertexBufferSharedPtr srcWeightBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendWeights->getSource());
1624 		HardwareVertexBufferSharedPtr srcNormBuf;
1625 
1626         srcPosStride = srcPosBuf->getVertexSize();
1627 
1628         blendIdxStride = srcIdxBuf->getVertexSize();
1629 
1630         blendWeightStride = srcWeightBuf->getVertexSize();
1631         if (includeNormals)
1632         {
1633             srcNormBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemNorm->getSource());
1634             srcNormStride = srcNormBuf->getVertexSize();
1635         }
1636         // Get buffers for target
1637         HardwareVertexBufferSharedPtr destPosBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemPos->getSource());
1638 		HardwareVertexBufferSharedPtr destNormBuf;
1639         destPosStride = destPosBuf->getVertexSize();
1640         if (includeNormals)
1641         {
1642             destNormBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemNorm->getSource());
1643             destNormStride = destNormBuf->getVertexSize();
1644         }
1645 
1646         void* pBuffer;
1647 
1648         // Lock source buffers for reading
1649         pBuffer = srcPosBuf->lock(HardwareBuffer::HBL_READ_ONLY);
1650         srcElemPos->baseVertexPointerToElement(pBuffer, &pSrcPos);
1651         if (includeNormals)
1652         {
1653             if (srcNormBuf != srcPosBuf)
1654             {
1655                 // Different buffer
1656                 pBuffer = srcNormBuf->lock(HardwareBuffer::HBL_READ_ONLY);
1657             }
1658             srcElemNorm->baseVertexPointerToElement(pBuffer, &pSrcNorm);
1659         }
1660 
1661         // Indices must be 4 bytes
1662         assert(srcElemBlendIndices->getType() == VET_UBYTE4 &&
1663                "Blend indices must be VET_UBYTE4");
1664         pBuffer = srcIdxBuf->lock(HardwareBuffer::HBL_READ_ONLY);
1665         srcElemBlendIndices->baseVertexPointerToElement(pBuffer, &pBlendIdx);
1666         if (srcWeightBuf != srcIdxBuf)
1667         {
1668             // Lock buffer
1669             pBuffer = srcWeightBuf->lock(HardwareBuffer::HBL_READ_ONLY);
1670         }
1671         srcElemBlendWeights->baseVertexPointerToElement(pBuffer, &pBlendWeight);
1672         unsigned short numWeightsPerVertex =
1673             VertexElement::getTypeCount(srcElemBlendWeights->getType());
1674 
1675 
1676         // Lock destination buffers for writing
1677         pBuffer = destPosBuf->lock(
1678             (destNormBuf != destPosBuf && destPosBuf->getVertexSize() == destElemPos->getSize()) ||
1679             (destNormBuf == destPosBuf && destPosBuf->getVertexSize() == destElemPos->getSize() + destElemNorm->getSize()) ?
1680             HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL);
1681         destElemPos->baseVertexPointerToElement(pBuffer, &pDestPos);
1682         if (includeNormals)
1683         {
1684             if (destNormBuf != destPosBuf)
1685             {
1686                 pBuffer = destNormBuf->lock(
1687                     destNormBuf->getVertexSize() == destElemNorm->getSize() ?
1688                     HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL);
1689             }
1690             destElemNorm->baseVertexPointerToElement(pBuffer, &pDestNorm);
1691         }
1692 
1693         OptimisedUtil::getImplementation()->softwareVertexSkinning(
1694             pSrcPos, pDestPos,
1695             pSrcNorm, pDestNorm,
1696             pBlendWeight, pBlendIdx,
1697             blendMatrices,
1698             srcPosStride, destPosStride,
1699             srcNormStride, destNormStride,
1700             blendWeightStride, blendIdxStride,
1701             numWeightsPerVertex,
1702             targetVertexData->vertexCount);
1703 
1704         // Unlock source buffers
1705         srcPosBuf->unlock();
1706         srcIdxBuf->unlock();
1707         if (srcWeightBuf != srcIdxBuf)
1708         {
1709             srcWeightBuf->unlock();
1710         }
1711         if (includeNormals && srcNormBuf != srcPosBuf)
1712         {
1713             srcNormBuf->unlock();
1714         }
1715         // Unlock destination buffers
1716         destPosBuf->unlock();
1717         if (includeNormals && destNormBuf != destPosBuf)
1718         {
1719             destNormBuf->unlock();
1720         }
1721 
1722     }
1723 	//---------------------------------------------------------------------
softwareVertexMorph(Real t,const HardwareVertexBufferSharedPtr & b1,const HardwareVertexBufferSharedPtr & b2,VertexData * targetVertexData)1724 	void Mesh::softwareVertexMorph(Real t,
1725 		const HardwareVertexBufferSharedPtr& b1,
1726 		const HardwareVertexBufferSharedPtr& b2,
1727 		VertexData* targetVertexData)
1728 	{
1729 		float* pb1 = static_cast<float*>(b1->lock(HardwareBuffer::HBL_READ_ONLY));
1730 		float* pb2;
1731 		if (b1.get() != b2.get())
1732 		{
1733 			pb2 = static_cast<float*>(b2->lock(HardwareBuffer::HBL_READ_ONLY));
1734 		}
1735 		else
1736 		{
1737 			// Same buffer - track with only one entry or time index exactly matching
1738 			// one keyframe
1739 			// For simplicity of main code, interpolate still but with same val
1740 			pb2 = pb1;
1741 		}
1742 
1743 		const VertexElement* posElem =
1744 			targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1745 		assert(posElem);
1746 		const VertexElement* normElem =
1747 			targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1748 
1749 		bool morphNormals = false;
1750 		if (normElem && normElem->getSource() == posElem->getSource() &&
1751 			b1->getVertexSize() == 24 && b2->getVertexSize() == 24)
1752 			morphNormals = true;
1753 
1754 		HardwareVertexBufferSharedPtr destBuf =
1755 			targetVertexData->vertexBufferBinding->getBuffer(
1756 				posElem->getSource());
1757 		assert((posElem->getSize() == destBuf->getVertexSize()
1758 				|| (morphNormals && posElem->getSize() + normElem->getSize() == destBuf->getVertexSize())) &&
1759 			"Positions (or positions & normals) must be in a buffer on their own for morphing");
1760 		float* pdst = static_cast<float*>(
1761 			destBuf->lock(HardwareBuffer::HBL_DISCARD));
1762 
1763         OptimisedUtil::getImplementation()->softwareVertexMorph(
1764             t, pb1, pb2, pdst,
1765 			b1->getVertexSize(), b2->getVertexSize(), destBuf->getVertexSize(),
1766             targetVertexData->vertexCount,
1767 			morphNormals);
1768 
1769 		destBuf->unlock();
1770 		b1->unlock();
1771 		if (b1.get() != b2.get())
1772 			b2->unlock();
1773 	}
1774 	//---------------------------------------------------------------------
softwareVertexPoseBlend(Real weight,const map<size_t,Vector3>::type & vertexOffsetMap,const map<size_t,Vector3>::type & normalsMap,VertexData * targetVertexData)1775 	void Mesh::softwareVertexPoseBlend(Real weight,
1776 		const map<size_t, Vector3>::type& vertexOffsetMap,
1777 		const map<size_t, Vector3>::type& normalsMap,
1778 		VertexData* targetVertexData)
1779 	{
1780 		// Do nothing if no weight
1781 		if (weight == 0.0f)
1782 			return;
1783 
1784 		const VertexElement* posElem =
1785 			targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
1786 		const VertexElement* normElem =
1787 			targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
1788 		assert(posElem);
1789 		// Support normals if they're in the same buffer as positions and pose includes them
1790 		bool normals = normElem && !normalsMap.empty() && posElem->getSource() == normElem->getSource();
1791 		HardwareVertexBufferSharedPtr destBuf =
1792 			targetVertexData->vertexBufferBinding->getBuffer(
1793 			posElem->getSource());
1794 
1795 		size_t elemsPerVertex = destBuf->getVertexSize()/sizeof(float);
1796 
1797 		// Have to lock in normal mode since this is incremental
1798 		float* pBase = static_cast<float*>(
1799 			destBuf->lock(HardwareBuffer::HBL_NORMAL));
1800 
1801 		// Iterate over affected vertices
1802 		for (map<size_t, Vector3>::type::const_iterator i = vertexOffsetMap.begin();
1803 			i != vertexOffsetMap.end(); ++i)
1804 		{
1805 			// Adjust pointer
1806 			float *pdst = pBase + i->first*elemsPerVertex;
1807 
1808 			*pdst = *pdst + (i->second.x * weight);
1809 			++pdst;
1810 			*pdst = *pdst + (i->second.y * weight);
1811 			++pdst;
1812 			*pdst = *pdst + (i->second.z * weight);
1813 			++pdst;
1814 
1815 		}
1816 
1817 		if (normals)
1818 		{
1819 			float* pNormBase;
1820 			normElem->baseVertexPointerToElement((void*)pBase, &pNormBase);
1821 			for (map<size_t, Vector3>::type::const_iterator i = normalsMap.begin();
1822 				i != normalsMap.end(); ++i)
1823 			{
1824 				// Adjust pointer
1825 				float *pdst = pNormBase + i->first*elemsPerVertex;
1826 
1827 				*pdst = *pdst + (i->second.x * weight);
1828 				++pdst;
1829 				*pdst = *pdst + (i->second.y * weight);
1830 				++pdst;
1831 				*pdst = *pdst + (i->second.z * weight);
1832 				++pdst;
1833 
1834 			}
1835 		}
1836 		destBuf->unlock();
1837 	}
1838     //---------------------------------------------------------------------
calculateSize(void) const1839 	size_t Mesh::calculateSize(void) const
1840 	{
1841 		// calculate GPU size
1842 		size_t ret = 0;
1843 		unsigned short i;
1844 		// Shared vertices
1845 		if (sharedVertexData)
1846 		{
1847 			for (i = 0;
1848 				i < sharedVertexData->vertexBufferBinding->getBufferCount();
1849 				++i)
1850 			{
1851 				ret += sharedVertexData->vertexBufferBinding
1852 					->getBuffer(i)->getSizeInBytes();
1853 			}
1854 		}
1855 
1856 		SubMeshList::const_iterator si;
1857 		for (si = mSubMeshList.begin(); si != mSubMeshList.end(); ++si)
1858 		{
1859 			// Dedicated vertices
1860 			if (!(*si)->useSharedVertices)
1861 			{
1862 				for (i = 0;
1863 					i < (*si)->vertexData->vertexBufferBinding->getBufferCount();
1864 					++i)
1865 				{
1866 					ret += (*si)->vertexData->vertexBufferBinding
1867 						->getBuffer(i)->getSizeInBytes();
1868 				}
1869 			}
1870 			if (!(*si)->indexData->indexBuffer.isNull())
1871 			{
1872 				// Index data
1873 				ret += (*si)->indexData->indexBuffer->getSizeInBytes();
1874 			}
1875 
1876 		}
1877 		return ret;
1878 	}
1879 	//-----------------------------------------------------------------------------
hasVertexAnimation(void) const1880 	bool Mesh::hasVertexAnimation(void) const
1881 	{
1882 		return !mAnimationsList.empty();
1883 	}
1884 	//---------------------------------------------------------------------
getSharedVertexDataAnimationType(void) const1885 	VertexAnimationType Mesh::getSharedVertexDataAnimationType(void) const
1886 	{
1887 		if (mAnimationTypesDirty)
1888 		{
1889 			_determineAnimationTypes();
1890 		}
1891 
1892 		return mSharedVertexDataAnimationType;
1893 	}
1894 	//---------------------------------------------------------------------
_determineAnimationTypes(void) const1895 	void Mesh::_determineAnimationTypes(void) const
1896 	{
1897 		// Don't check flag here; since detail checks on track changes are not
1898 		// done, allow caller to force if they need to
1899 
1900 		// Initialise all types to nothing
1901 		mSharedVertexDataAnimationType = VAT_NONE;
1902 		mSharedVertexDataAnimationIncludesNormals = false;
1903 		for (SubMeshList::const_iterator i = mSubMeshList.begin();
1904 			i != mSubMeshList.end(); ++i)
1905 		{
1906 			(*i)->mVertexAnimationType = VAT_NONE;
1907 			(*i)->mVertexAnimationIncludesNormals = false;
1908 		}
1909 
1910 		mPosesIncludeNormals = false;
1911 		for (PoseList::const_iterator i = mPoseList.begin(); i != mPoseList.end(); ++i)
1912 		{
1913 			if (i == mPoseList.begin())
1914 				mPosesIncludeNormals = (*i)->getIncludesNormals();
1915 			else if (mPosesIncludeNormals != (*i)->getIncludesNormals())
1916 				// only support normals if consistently included
1917 				mPosesIncludeNormals = mPosesIncludeNormals && (*i)->getIncludesNormals();
1918 		}
1919 
1920 		// Scan all animations and determine the type of animation tracks
1921 		// relating to each vertex data
1922 		for(AnimationList::const_iterator ai = mAnimationsList.begin();
1923 			ai != mAnimationsList.end(); ++ai)
1924 		{
1925 			Animation* anim = ai->second;
1926 			Animation::VertexTrackIterator vit = anim->getVertexTrackIterator();
1927 			while (vit.hasMoreElements())
1928 			{
1929 				VertexAnimationTrack* track = vit.getNext();
1930 				ushort handle = track->getHandle();
1931 				if (handle == 0)
1932 				{
1933 					// shared data
1934 					if (mSharedVertexDataAnimationType != VAT_NONE &&
1935 						mSharedVertexDataAnimationType != track->getAnimationType())
1936 					{
1937 						// Mixing of morph and pose animation on same data is not allowed
1938 						OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1939 							"Animation tracks for shared vertex data on mesh "
1940 							+ mName + " try to mix vertex animation types, which is "
1941 							"not allowed.",
1942 							"Mesh::_determineAnimationTypes");
1943 					}
1944 					mSharedVertexDataAnimationType = track->getAnimationType();
1945 					if (track->getAnimationType() == VAT_MORPH)
1946 						mSharedVertexDataAnimationIncludesNormals = track->getVertexAnimationIncludesNormals();
1947 					else
1948 						mSharedVertexDataAnimationIncludesNormals = mPosesIncludeNormals;
1949 
1950 				}
1951 				else
1952 				{
1953 					// submesh index (-1)
1954 					SubMesh* sm = getSubMesh(handle-1);
1955 					if (sm->mVertexAnimationType != VAT_NONE &&
1956 						sm->mVertexAnimationType != track->getAnimationType())
1957 					{
1958 						// Mixing of morph and pose animation on same data is not allowed
1959 						OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1960 							"Animation tracks for dedicated vertex data "
1961 							+ StringConverter::toString(handle-1) + " on mesh "
1962 							+ mName + " try to mix vertex animation types, which is "
1963 							"not allowed.",
1964 							"Mesh::_determineAnimationTypes");
1965 					}
1966 					sm->mVertexAnimationType = track->getAnimationType();
1967 					if (track->getAnimationType() == VAT_MORPH)
1968 						sm->mVertexAnimationIncludesNormals = track->getVertexAnimationIncludesNormals();
1969 					else
1970 						sm->mVertexAnimationIncludesNormals = mPosesIncludeNormals;
1971 
1972 				}
1973 			}
1974 		}
1975 
1976 		mAnimationTypesDirty = false;
1977 	}
1978 	//---------------------------------------------------------------------
createAnimation(const String & name,Real length)1979 	Animation* Mesh::createAnimation(const String& name, Real length)
1980 	{
1981 		// Check name not used
1982 		if (mAnimationsList.find(name) != mAnimationsList.end())
1983 		{
1984 			OGRE_EXCEPT(
1985 				Exception::ERR_DUPLICATE_ITEM,
1986 				"An animation with the name " + name + " already exists",
1987 				"Mesh::createAnimation");
1988 		}
1989 
1990 		Animation* ret = OGRE_NEW Animation(name, length);
1991 		ret->_notifyContainer(this);
1992 
1993 		// Add to list
1994 		mAnimationsList[name] = ret;
1995 
1996 		// Mark animation types dirty
1997 		mAnimationTypesDirty = true;
1998 
1999 		return ret;
2000 
2001 	}
2002 	//---------------------------------------------------------------------
getAnimation(const String & name) const2003 	Animation* Mesh::getAnimation(const String& name) const
2004 	{
2005 		Animation* ret = _getAnimationImpl(name);
2006 		if (!ret)
2007 		{
2008 			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2009 				"No animation entry found named " + name,
2010 				"Mesh::getAnimation");
2011 		}
2012 
2013 		return ret;
2014 	}
2015 	//---------------------------------------------------------------------
getAnimation(unsigned short index) const2016 	Animation* Mesh::getAnimation(unsigned short index) const
2017 	{
2018 		// If you hit this assert, then the index is out of bounds.
2019 		assert( index < mAnimationsList.size() );
2020 
2021 		AnimationList::const_iterator i = mAnimationsList.begin();
2022 
2023 		std::advance(i, index);
2024 
2025 		return i->second;
2026 
2027 	}
2028 	//---------------------------------------------------------------------
getNumAnimations(void) const2029 	unsigned short Mesh::getNumAnimations(void) const
2030 	{
2031 		return static_cast<unsigned short>(mAnimationsList.size());
2032 	}
2033 	//---------------------------------------------------------------------
hasAnimation(const String & name) const2034 	bool Mesh::hasAnimation(const String& name) const
2035 	{
2036 		return _getAnimationImpl(name) != 0;
2037 	}
2038 	//---------------------------------------------------------------------
_getAnimationImpl(const String & name) const2039 	Animation* Mesh::_getAnimationImpl(const String& name) const
2040 	{
2041 		Animation* ret = 0;
2042 		AnimationList::const_iterator i = mAnimationsList.find(name);
2043 
2044 		if (i != mAnimationsList.end())
2045 		{
2046 			ret = i->second;
2047 		}
2048 
2049 		return ret;
2050 
2051 	}
2052 	//---------------------------------------------------------------------
removeAnimation(const String & name)2053 	void Mesh::removeAnimation(const String& name)
2054 	{
2055 		AnimationList::iterator i = mAnimationsList.find(name);
2056 
2057 		if (i == mAnimationsList.end())
2058 		{
2059 			OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
2060 				"Mesh::getAnimation");
2061 		}
2062 
2063 		OGRE_DELETE i->second;
2064 
2065 		mAnimationsList.erase(i);
2066 
2067 		mAnimationTypesDirty = true;
2068 	}
2069 	//---------------------------------------------------------------------
removeAllAnimations(void)2070 	void Mesh::removeAllAnimations(void)
2071 	{
2072 		AnimationList::iterator i = mAnimationsList.begin();
2073 		for (; i != mAnimationsList.end(); ++i)
2074 		{
2075 			OGRE_DELETE i->second;
2076 		}
2077 		mAnimationsList.clear();
2078 		mAnimationTypesDirty = true;
2079 	}
2080 	//---------------------------------------------------------------------
getVertexDataByTrackHandle(unsigned short handle)2081 	VertexData* Mesh::getVertexDataByTrackHandle(unsigned short handle)
2082 	{
2083 		if (handle == 0)
2084 		{
2085 			return sharedVertexData;
2086 		}
2087 		else
2088 		{
2089 			return getSubMesh(handle-1)->vertexData;
2090 		}
2091 	}
2092 	//---------------------------------------------------------------------
createPose(ushort target,const String & name)2093 	Pose* Mesh::createPose(ushort target, const String& name)
2094 	{
2095 		Pose* retPose = OGRE_NEW Pose(target, name);
2096 		mPoseList.push_back(retPose);
2097 		return retPose;
2098 	}
2099 	//---------------------------------------------------------------------
getPose(ushort index)2100 	Pose* Mesh::getPose(ushort index)
2101 	{
2102 		if (index >= getPoseCount())
2103 		{
2104 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
2105 				"Index out of bounds",
2106 				"Mesh::getPose");
2107 		}
2108 
2109 		return mPoseList[index];
2110 
2111 	}
2112 	//---------------------------------------------------------------------
getPose(const String & name)2113 	Pose* Mesh::getPose(const String& name)
2114 	{
2115 		for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i)
2116 		{
2117 			if ((*i)->getName() == name)
2118 				return *i;
2119 		}
2120 		StringUtil::StrStreamType str;
2121 		str << "No pose called " << name << " found in Mesh " << mName;
2122 		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2123 			str.str(),
2124 			"Mesh::getPose");
2125 
2126 	}
2127 	//---------------------------------------------------------------------
removePose(ushort index)2128 	void Mesh::removePose(ushort index)
2129 	{
2130 		if (index >= getPoseCount())
2131 		{
2132 			OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
2133 				"Index out of bounds",
2134 				"Mesh::removePose");
2135 		}
2136 		PoseList::iterator i = mPoseList.begin();
2137 		std::advance(i, index);
2138 		OGRE_DELETE *i;
2139 		mPoseList.erase(i);
2140 
2141 	}
2142 	//---------------------------------------------------------------------
removePose(const String & name)2143 	void Mesh::removePose(const String& name)
2144 	{
2145 		for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i)
2146 		{
2147 			if ((*i)->getName() == name)
2148 			{
2149 				OGRE_DELETE *i;
2150 				mPoseList.erase(i);
2151 				return;
2152 			}
2153 		}
2154 		StringUtil::StrStreamType str;
2155 		str << "No pose called " << name << " found in Mesh " << mName;
2156 		OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
2157 			str.str(),
2158 			"Mesh::removePose");
2159 	}
2160 	//---------------------------------------------------------------------
removeAllPoses(void)2161 	void Mesh::removeAllPoses(void)
2162 	{
2163 		for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i)
2164 		{
2165 			OGRE_DELETE *i;
2166 		}
2167 		mPoseList.clear();
2168 	}
2169 	//---------------------------------------------------------------------
getPoseIterator(void)2170 	Mesh::PoseIterator Mesh::getPoseIterator(void)
2171 	{
2172 		return PoseIterator(mPoseList.begin(), mPoseList.end());
2173 	}
2174 	//---------------------------------------------------------------------
getPoseIterator(void) const2175 	Mesh::ConstPoseIterator Mesh::getPoseIterator(void) const
2176 	{
2177 		return ConstPoseIterator(mPoseList.begin(), mPoseList.end());
2178 	}
2179 	//-----------------------------------------------------------------------------
getPoseList(void) const2180 	const PoseList& Mesh::getPoseList(void) const
2181 	{
2182 		return mPoseList;
2183 	}
2184 	//---------------------------------------------------------------------
updateMaterialForAllSubMeshes(void)2185 	void Mesh::updateMaterialForAllSubMeshes(void)
2186 	{
2187         // iterate through each sub mesh and request the submesh to update its material
2188         vector<SubMesh*>::type::iterator subi;
2189         for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi)
2190         {
2191             (*subi)->updateMaterialUsingTextureAliases();
2192         }
2193 
2194     }
2195 	//---------------------------------------------------------------------
getLodStrategy() const2196     const LodStrategy *Mesh::getLodStrategy() const
2197     {
2198         return mLodStrategy;
2199     }
2200     //---------------------------------------------------------------------
setLodStrategy(LodStrategy * lodStrategy)2201     void Mesh::setLodStrategy(LodStrategy *lodStrategy)
2202     {
2203         mLodStrategy = lodStrategy;
2204 
2205         assert(mMeshLodUsageList.size());
2206         mMeshLodUsageList[0].value = mLodStrategy->getBaseValue();
2207 
2208         // Re-transform user LOD values (starting at index 1, no need to transform base value)
2209 		for (MeshLodUsageList::iterator i = mMeshLodUsageList.begin(); i != mMeshLodUsageList.end(); ++i)
2210             i->value = mLodStrategy->transformUserValue(i->userValue);
2211 
2212     }
2213     //--------------------------------------------------------------------
_configureMeshLodUsage(const LodConfig & lodConfig)2214     void Mesh::_configureMeshLodUsage( const LodConfig& lodConfig )
2215     {
2216         // In theory every mesh should have a submesh.
2217         assert(getNumSubMeshes() > 0);
2218         setLodStrategy(lodConfig.strategy);
2219         SubMesh* submesh = getSubMesh(0);
2220         mNumLods = submesh->mLodFaceList.size() + 1;
2221         mMeshLodUsageList.resize(mNumLods);
2222         for (size_t n = 0, i = 0; i < lodConfig.levels.size(); i++) {
2223             // Record usages. First LOD usage is the mesh itself.
2224 
2225             // Skip LODs, which have the same amount of vertices. No buffer generated for them.
2226             if (!lodConfig.levels[i].outSkipped) {
2227                 // Generated buffers are less then the reported by ProgressiveMesh.
2228                 // This would fail if you use QueuedProgressiveMesh and the MeshPtr is force unloaded before LOD generation completes.
2229                 assert(mMeshLodUsageList.size() > n + 1);
2230                 MeshLodUsage& lod = mMeshLodUsageList[++n];
2231                 lod.userValue = lodConfig.levels[i].distance;
2232                 lod.value = getLodStrategy()->transformUserValue(lod.userValue);
2233                 lod.edgeData = 0;
2234                 lod.manualMesh.setNull();
2235             }
2236         }
2237 
2238         // TODO: Fix this in PixelCountLodStrategy::getIndex()
2239         // Fix bug in Ogre with pixel count LOD strategy.
2240         // Changes [0, 20, 15, 10, 5] to [max, 20, 15, 10, 5].
2241         // Fixes PixelCountLodStrategy::getIndex() function, which returned always 0 index.
2242         if (lodConfig.strategy == AbsolutePixelCountLodStrategy::getSingletonPtr()) {
2243             mMeshLodUsageList[0].userValue = std::numeric_limits<Real>::max();
2244             mMeshLodUsageList[0].value = std::numeric_limits<Real>::max();
2245         } else {
2246             mMeshLodUsageList[0].userValue = 0;
2247             mMeshLodUsageList[0].value = 0;
2248         }
2249     }
2250     //---------------------------------------------------------------------
2251 }
2252 
2253