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

Revision 657, 67.5 KB checked in by mattausch, 19 years ago (diff)

added ogre dependencies and patched ogre sources

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