source: OGRE/trunk/ogrenew/OgreMain/src/OgreMesh.cpp @ 692

Revision 692, 82.0 KB checked in by mattausch, 19 years ago (diff)

adding ogre 1.2 and dependencies

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