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