Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/ogre/OgreMain/src/OgreMesh.cpp @ 45

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

=hoffentlich gehts jetzt

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