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

Revision 657, 57.2 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://ogre.sourceforge.net/
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 "OgreEntity.h"
27
28#include "OgreSubMesh.h"
29#include "OgreSubEntity.h"
30#include "OgreException.h"
31#include "OgreSceneManager.h"
32#include "OgreLogManager.h"
33#include "OgreSkeleton.h"
34#include "OgreBone.h"
35#include "OgreCamera.h"
36#include "OgreTagPoint.h"
37#include "OgreAxisAlignedBox.h"
38#include "OgreHardwareBufferManager.h"
39#include "OgreVector4.h"
40#include "OgreRoot.h"
41#include "OgreTechnique.h"
42#include "OgrePass.h"
43#include "OgreSkeletonInstance.h"
44#include "OgreEdgeListBuilder.h"
45#include "OgreStringConverter.h"
46
47namespace Ogre {
48    String Entity::msMovableType = "Entity";
49    //-----------------------------------------------------------------------
50    Entity::Entity ()
51    {
52        mFullBoundingBox = new AxisAlignedBox;
53        mNormaliseNormals = false;
54        mFrameBonesLastUpdated = new unsigned long;
55                *mFrameBonesLastUpdated = std::numeric_limits<unsigned long>::max();
56        mFrameAnimationLastUpdated = std::numeric_limits<unsigned long>::max();
57        mHardwareSkinning = false;
58        mSoftwareSkinningRequests = 0;
59        mSoftwareSkinningNormalsRequests = 0;
60        mSkeletonInstance = 0;
61    }
62    //-----------------------------------------------------------------------
63    Entity::Entity( const String& name, MeshPtr& mesh, SceneManager* creator) :
64    mName(name),
65        mMesh(mesh),
66        mCreatorSceneManager(creator),
67        mSharedSkeletonEntities(NULL)
68    {
69        mFullBoundingBox = new AxisAlignedBox;
70        mHardwareSkinning = false;
71        mSoftwareSkinningRequests = 0;
72        mSoftwareSkinningNormalsRequests = 0;
73        mSharedBlendedVertexData = NULL;
74
75        // Is mesh skeletally animated?
76        if (mMesh->hasSkeleton() && !mMesh->getSkeleton().isNull())
77        {
78            mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
79            mSkeletonInstance->load();
80        }
81        else
82        {
83            mSkeletonInstance = 0;
84        }
85
86        // Build main subentity list
87        buildSubEntityList(mesh, &mSubEntityList);
88
89        // Check if mesh is using manual LOD
90        if (mesh->isLodManual())
91        {
92            ushort i, numLod;
93            numLod = mesh->getNumLodLevels();
94            // NB skip LOD 0 which is the original
95            for (i = 1; i < numLod; ++i)
96            {
97                const MeshLodUsage& usage = mesh->getLodLevel(i);
98                // Manually create entity
99                Entity* lodEnt = new Entity(name + "Lod" + StringConverter::toString(i),
100                    usage.manualMesh, mCreatorSceneManager);
101                mLodEntityList.push_back(lodEnt);
102            }
103
104        }
105
106
107        // Initialise the AnimationState, if Mesh has animation
108        if (hasSkeleton())
109        {
110            mAnimationState = new AnimationStateSet();
111            mFrameBonesLastUpdated = new unsigned long;
112            *mFrameBonesLastUpdated = std::numeric_limits<unsigned long>::max();
113            mesh->_initAnimationState(mAnimationState);
114            mNumBoneMatrices = mSkeletonInstance->getNumBones();
115            mBoneMatrices = new Matrix4[mNumBoneMatrices];
116            prepareTempBlendBuffers();
117        }
118        else
119        {
120            mBoneMatrices = 0;
121            mNumBoneMatrices = 0;
122            mAnimationState = 0;
123            mFrameBonesLastUpdated  = 0;
124
125        }
126
127        reevaluateVertexProcessing();
128
129        mDisplaySkeleton = false;
130
131        mMeshLodFactorInv = 1.0f;
132        mMeshLodIndex = 0;
133        mMaxMeshLodIndex = 0;           // Backwards, remember low value = high detail
134        mMinMeshLodIndex = 99;
135
136        mMaterialLodFactorInv = 1.0f;
137        mMaxMaterialLodIndex = 0;               // Backwards, remember low value = high detail
138        mMinMaterialLodIndex = 99;
139
140
141        mFrameAnimationLastUpdated = std::numeric_limits<unsigned long>::max();
142
143        // Do we have a mesh where edge lists are not going to be available?
144        if (!mesh->isEdgeListBuilt() && !mesh->getAutoBuildEdgeLists())
145        {
146            setCastShadows(false);
147        }
148    }
149    //-----------------------------------------------------------------------
150    Entity::~Entity()
151    {
152        // Delete submeshes
153        SubEntityList::iterator i, iend;
154        iend = mSubEntityList.end();
155        for (i = mSubEntityList.begin(); i != iend; ++i)
156        {
157            // Delete SubEntity
158            delete *i;
159        }
160        // Delete LOD entities
161        LODEntityList::iterator li, liend;
162        liend = mLodEntityList.end();
163        for (li = mLodEntityList.begin(); li != liend; ++li)
164        {
165            // Delete
166            delete (*li);
167        }
168
169        delete mFullBoundingBox;
170
171        // Delete shadow renderables
172        ShadowRenderableList::iterator si, siend;
173        siend = mShadowRenderables.end();
174        for (si = mShadowRenderables.begin(); si != siend; ++si)
175        {
176            delete *si;
177        }
178
179        // Detach all child objects, do this manually to avoid needUpdate() call
180        // which can fail because of deleted items
181        detachAllObjectsImpl();
182
183        if (mSkeletonInstance) {
184            if (mSharedSkeletonEntities) {
185                mSharedSkeletonEntities->erase(this);
186                if (mSharedSkeletonEntities->size() == 0) {
187                    delete mSkeletonInstance;
188                    delete [] mBoneMatrices;
189                    delete mAnimationState;
190                    delete mFrameBonesLastUpdated;
191                    delete mSharedSkeletonEntities;
192                }       
193            } else {
194                delete mSkeletonInstance;
195                delete [] mBoneMatrices;
196                delete mAnimationState;
197                delete mFrameBonesLastUpdated;
198            }
199        }
200
201                delete mSharedBlendedVertexData;
202    }
203    //-----------------------------------------------------------------------
204    MeshPtr& Entity::getMesh(void)
205    {
206        return mMesh;
207    }
208    //-----------------------------------------------------------------------
209    const String& Entity::getName(void) const
210    {
211        return mName;
212    }
213    //-----------------------------------------------------------------------
214    SubEntity* Entity::getSubEntity(unsigned int index)
215    {
216        if (index >= mSubEntityList.size())
217            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
218            "Index out of bounds.",
219            "Entity::getSubEntity");
220        return mSubEntityList[index];
221    }
222    //-----------------------------------------------------------------------
223    SubEntity* Entity::getSubEntity(const String& name)
224    {
225        ushort index = mMesh->_getSubMeshIndex(name);
226        return getSubEntity(index);
227    }
228    //-----------------------------------------------------------------------
229    unsigned int Entity::getNumSubEntities(void) const
230    {
231        return static_cast< unsigned int >( mSubEntityList.size() );
232    }
233    //-----------------------------------------------------------------------
234    Entity* Entity::clone( const String& newName)
235    {
236        Entity* newEnt;
237        newEnt = mCreatorSceneManager->createEntity( newName, getMesh()->getName() );
238        // Copy material settings
239        SubEntityList::iterator i;
240        unsigned int n = 0;
241        for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i, ++n)
242        {
243            newEnt->getSubEntity(n)->setMaterialName((*i)->getMaterialName());
244        }
245        if (mAnimationState)
246        {
247            newEnt->mAnimationState = new AnimationStateSet(*mAnimationState);
248        }
249        return newEnt;
250    }
251    //-----------------------------------------------------------------------
252    void Entity::setMaterialName(const String& name)
253    {
254        // Set for all subentities
255        SubEntityList::iterator i;
256        for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
257        {
258            (*i)->setMaterialName(name);
259        }
260
261    }
262    //-----------------------------------------------------------------------
263    void Entity::_notifyCurrentCamera(Camera* cam)
264    {
265        // Calculate the LOD
266        if (mParentNode)
267        {
268            Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
269
270            // Do Mesh LOD
271            // Adjust this depth by the entity bias factor
272            Real tmp = squaredDepth * mMeshLodFactorInv;
273            // Now adjust it by the camera bias
274            tmp = tmp * cam->_getLodBiasInverse();
275            // Get the index at this biased depth
276            mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp);
277            // Apply maximum detail restriction (remember lower = higher detail)
278            mMeshLodIndex = std::max(mMaxMeshLodIndex, mMeshLodIndex);
279            // Apply minimum detail restriction (remember higher = lower detail)
280            mMeshLodIndex = std::min(mMinMeshLodIndex, mMeshLodIndex);
281
282            // Now do material LOD
283            // Adjust this depth by the entity bias factor
284            tmp = squaredDepth * mMaterialLodFactorInv;
285            // Now adjust it by the camera bias
286            tmp = tmp * cam->_getLodBiasInverse();
287            SubEntityList::iterator i, iend;
288            iend = mSubEntityList.end();
289            for (i = mSubEntityList.begin(); i != iend; ++i)
290            {
291                // Get the index at this biased depth
292                unsigned short idx = (*i)->mpMaterial->getLodIndexSquaredDepth(tmp);
293                // Apply maximum detail restriction (remember lower = higher detail)
294                idx = std::max(mMaxMaterialLodIndex, idx);
295                // Apply minimum detail restriction (remember higher = lower detail)
296                (*i)->mMaterialLodIndex = std::min(mMinMaterialLodIndex, idx);
297            }
298
299
300        }
301        // Notify any child objects
302        ChildObjectList::iterator child_itr = mChildObjectList.begin();
303        ChildObjectList::iterator child_itr_end = mChildObjectList.end();
304        for( ; child_itr != child_itr_end; child_itr++)
305        {
306            (*child_itr).second->_notifyCurrentCamera(cam);
307        }
308
309
310    }
311    //-----------------------------------------------------------------------
312    const AxisAlignedBox& Entity::getBoundingBox(void) const
313    {
314        // Get from Mesh
315        *mFullBoundingBox = mMesh->getBounds();
316        mFullBoundingBox->merge(getChildObjectsBoundingBox());
317
318        // Don't scale here, this is taken into account when world BBox calculation is done
319
320        return *mFullBoundingBox;
321    }
322    //-----------------------------------------------------------------------
323    AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const
324    {
325        AxisAlignedBox aa_box;
326        AxisAlignedBox full_aa_box;
327        full_aa_box.setNull();
328
329        ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
330        ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
331        for( ; child_itr != child_itr_end; child_itr++)
332        {
333            aa_box = child_itr->second->getBoundingBox();
334            TagPoint* tp = (TagPoint*)child_itr->second->getParentNode();
335            // Use transform local to skeleton since world xform comes later
336            aa_box.transform(tp->_getFullLocalTransform());
337
338            full_aa_box.merge(aa_box);
339        }
340
341        return full_aa_box;
342    }
343        //-----------------------------------------------------------------------
344        const AxisAlignedBox& Entity::getWorldBoundingBox(bool derive) const
345        {
346                if (derive)
347                {
348                        // derive child bounding boxes
349                        ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
350                        ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
351                        for( ; child_itr != child_itr_end; child_itr++)
352                        {
353                                child_itr->second->getWorldBoundingBox(true);
354                        }
355                }
356                return MovableObject::getWorldBoundingBox(derive);
357        }
358        //-----------------------------------------------------------------------
359        const Sphere& Entity::getWorldBoundingSphere(bool derive) const
360        {
361                if (derive)
362                {
363                        // derive child bounding boxes
364                        ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
365                        ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
366                        for( ; child_itr != child_itr_end; child_itr++)
367                        {
368                                child_itr->second->getWorldBoundingSphere(true);
369                        }
370                }
371                return MovableObject::getWorldBoundingSphere(derive);
372
373        }
374    //-----------------------------------------------------------------------
375    void Entity::_updateRenderQueue(RenderQueue* queue)
376    {
377        // Check we're not using a manual LOD
378        if (mMeshLodIndex > 0 && mMesh->isLodManual())
379        {
380            // Use alternate entity
381            assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
382                "No LOD EntityList - did you build the manual LODs after creating the entity?");
383            // index - 1 as we skip index 0 (original lod)
384            if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
385            {
386                // Copy the animation state set to lod entity, we assume the lod
387                // entity only has a subset animation states
388                CopyAnimationStateSubset(*mLodEntityList[mMeshLodIndex - 1]->mAnimationState, *mAnimationState);
389            }
390            mLodEntityList[mMeshLodIndex - 1]->_updateRenderQueue(queue);
391            return;
392        }
393
394        // Add each visible SubEntity to the queue
395        SubEntityList::iterator i, iend;
396        iend = mSubEntityList.end();
397        for (i = mSubEntityList.begin(); i != iend; ++i)
398        {
399            if((*i)->isVisible()) 
400            {
401                if(mRenderQueueIDSet)
402                {
403                    queue->addRenderable(*i, mRenderQueueID);
404                }
405                else
406                {
407                    queue->addRenderable(*i);
408                }
409            }
410        }
411
412        // Since we know we're going to be rendered, take this opportunity to
413        // update the animation
414        if (hasSkeleton())
415        {
416            updateAnimation();
417
418            //--- pass this point,  we are sure that the transformation matrix of each bone and tagPoint have been updated                     
419            ChildObjectList::iterator child_itr = mChildObjectList.begin();
420            ChildObjectList::iterator child_itr_end = mChildObjectList.end();
421            for( ; child_itr != child_itr_end; child_itr++)
422            {
423                if ((*child_itr).second->isVisible())
424                    (*child_itr).second->_updateRenderQueue(queue);
425            }
426        }
427
428        // HACK to display bones
429        // This won't work if the entity is not centered at the origin
430        // TODO work out a way to allow bones to be rendered when Entity not centered
431        if (mDisplaySkeleton && hasSkeleton())
432        {
433            int numBones = mSkeletonInstance->getNumBones();
434            for (int b = 0; b < numBones; ++b)
435            {
436                Bone* bone = mSkeletonInstance->getBone(b);
437                if(mRenderQueueIDSet)
438                {
439                     queue->addRenderable(bone, mRenderQueueID);
440                } else {
441                     queue->addRenderable(bone);
442                }
443            }
444        }
445
446
447
448
449    }
450    //-----------------------------------------------------------------------
451    AnimationState* Entity::getAnimationState(const String& name)
452    {
453        if (!mAnimationState)
454        {
455            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Entity is not animated",
456                "Entity::getAnimationState");
457        }
458        AnimationStateSet::iterator i = mAnimationState->find(name);
459
460        if (i == mAnimationState->end())
461        {
462            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name,
463                "Entity::getAnimationState");
464        }
465
466        return &(i->second);
467    }
468    //-----------------------------------------------------------------------
469    AnimationStateSet* Entity::getAllAnimationStates(void)
470    {
471        return mAnimationState;
472    }
473    //-----------------------------------------------------------------------
474    const String& Entity::getMovableType(void) const
475    {
476        return msMovableType;
477    }
478    //-----------------------------------------------------------------------
479    void Entity::updateAnimation(void)
480    {
481        // We only do these tasks if they have not already been done for
482        // this frame
483        Root& root = Root::getSingleton();
484        unsigned long currentFrameNumber = root.getCurrentFrameNumber();
485        if (mFrameAnimationLastUpdated != currentFrameNumber)
486        {
487            cacheBoneMatrices();
488
489            // Software blend?
490            bool hwSkinning = isHardwareSkinningEnabled();
491            bool forcedSwSkinning = getSoftwareSkinningRequests()>0;
492            bool forcedNormals = getSoftwareSkinningNormalsRequests()>0;
493            if (!hwSkinning || forcedSwSkinning ||
494                root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_ADDITIVE ||
495                root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_MODULATIVE)
496            {
497                bool blendNormals = !hwSkinning || forcedNormals;
498
499                // Ok, we need to do a software blend
500                // Blend normals in s/w only if we're not using h/w skinning,
501                // since shadows only require positions
502                // Firstly, check out working vertex buffers
503                if (mSharedBlendedVertexData)
504                {
505                    // Blend shared geometry
506                    // NB we suppress hardware upload while doing blend if we're
507                    // hardware skinned, because the only reason for doing this
508                    // is for shadow, which need only be uploaded then
509                    mTempBlendedBuffer.checkoutTempCopies(true, blendNormals);
510                    mTempBlendedBuffer.bindTempCopies(mSharedBlendedVertexData,
511                        mHardwareSkinning);
512                    Mesh::softwareVertexBlend(mMesh->sharedVertexData,
513                        mSharedBlendedVertexData, mBoneMatrices, blendNormals);
514                }
515                SubEntityList::iterator i, iend;
516                iend = mSubEntityList.end();
517                for (i = mSubEntityList.begin(); i != iend; ++i)
518                {
519                    // Blend dedicated geometry
520                    SubEntity* se = *i;
521                    if (se->isVisible() && se->mBlendedVertexData)
522                    {
523                        se->mTempBlendedBuffer.checkoutTempCopies(true, blendNormals);
524                        se->mTempBlendedBuffer.bindTempCopies(se->mBlendedVertexData,
525                            mHardwareSkinning);
526                        Mesh::softwareVertexBlend(se->mSubMesh->vertexData,
527                            se->mBlendedVertexData, mBoneMatrices, blendNormals);
528                    }
529
530                }
531            }
532            // Trigger update of bounding box if necessary
533            if (!mChildObjectList.empty())
534                mParentNode->needUpdate();
535            mFrameAnimationLastUpdated = currentFrameNumber;
536        }
537    }
538        //-----------------------------------------------------------------------
539        void Entity::_updateAnimation(void)
540        {
541                // Externally visible method
542                if (hasSkeleton())
543                {
544                        updateAnimation();
545                }
546        }
547        //-----------------------------------------------------------------------
548        const VertexData* Entity::_getSharedBlendedVertexData(void) const
549        {
550                assert (mSharedBlendedVertexData && "Not software skinned!");
551        return mSharedBlendedVertexData;
552        }
553    //-----------------------------------------------------------------------
554    void Entity::cacheBoneMatrices(void)
555    {
556        Root& root = Root::getSingleton();
557        unsigned long currentFrameNumber = root.getCurrentFrameNumber();               
558        if (*mFrameBonesLastUpdated  != currentFrameNumber) {
559
560            // Get the appropriate meshes skeleton here
561            // Can use lower LOD mesh skeleton if mesh LOD is manual
562            // We make the assumption that lower LOD meshes will have
563            //   fewer bones than the full LOD, therefore marix stack will be
564            //   big enough.
565            Mesh* theMesh; // raw to avoid reference counting overhead (don't need it)
566            if (mMesh->isLodManual() && mMeshLodIndex > 1)
567            {
568                // Use lower detail skeleton
569                theMesh = mMesh->getLodLevel(mMeshLodIndex).manualMesh.getPointer();
570                // Lower detail may not have skeleton
571                if (!theMesh->hasSkeleton())
572                {
573                    mNumBoneMatrices = 0;
574                    return;
575                }
576            }
577            else
578            {
579                // Use normal mesh
580                theMesh = mMesh.getPointer();
581            }
582
583            mSkeletonInstance->setAnimationState(*mAnimationState);
584            mSkeletonInstance->_getBoneMatrices(mBoneMatrices);
585            *mFrameBonesLastUpdated  = currentFrameNumber;
586
587            if (sharesSkeletonInstance()) {
588                //---- update all sharing entities child objects transforms now
589                EntitySet::const_iterator entity_itr = mSharedSkeletonEntities->begin();
590                EntitySet::const_iterator entity_itr_end = mSharedSkeletonEntities->end();
591                for( ; entity_itr != entity_itr_end; entity_itr++)
592                {
593                    ChildObjectList::iterator child_itr = (*entity_itr)->mChildObjectList.begin();
594                    ChildObjectList::iterator child_itr_end = (*entity_itr)->mChildObjectList.end();
595                    for( ; child_itr != child_itr_end; child_itr++)
596                    {
597                        (*child_itr).second->getParentNode()->_update(true, true);
598                    }
599                }
600            } else {
601                //--- Update the child object's transforms
602                ChildObjectList::iterator child_itr = mChildObjectList.begin();
603                ChildObjectList::iterator child_itr_end = mChildObjectList.end();
604                for( ; child_itr != child_itr_end; child_itr++)
605                {
606                    (*child_itr).second->getParentNode()->_update(true, true);
607                }
608            }
609
610            // Apply our current world transform to these too, since these are used as
611            // replacement world matrices
612            unsigned short i;
613            Matrix4 worldXform = _getParentNodeFullTransform();
614            assert (mNumBoneMatrices==mSkeletonInstance->getNumBones());
615            mNumBoneMatrices = mSkeletonInstance->getNumBones();
616
617            for (i = 0; i < mNumBoneMatrices; ++i)
618            {
619                mBoneMatrices[i] = worldXform * mBoneMatrices[i];
620            }
621        }
622
623
624    }
625    //-----------------------------------------------------------------------
626    void Entity::setDisplaySkeleton(bool display)
627    {
628        mDisplaySkeleton = display;
629    }
630    //-----------------------------------------------------------------------
631    bool Entity::getDisplaySkeleton(void) const
632    {
633        return mDisplaySkeleton;
634    }
635    //-----------------------------------------------------------------------
636    Entity* Entity::getManualLodLevel(size_t index) const
637    {
638        assert(index < mLodEntityList.size());
639
640        return mLodEntityList[index];
641    }
642    //-----------------------------------------------------------------------
643    size_t Entity::getNumManualLodLevels(void) const
644    {
645        return mLodEntityList.size();
646    }
647    //-----------------------------------------------------------------------
648    void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
649    {
650        assert(factor > 0.0f && "Bias factor must be > 0!");
651        mMeshLodFactorInv = 1.0f / factor;
652        mMaxMeshLodIndex = maxDetailIndex;
653        mMinMeshLodIndex = minDetailIndex;
654
655    }
656    //-----------------------------------------------------------------------
657    void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
658    {
659        assert(factor > 0.0f && "Bias factor must be > 0!");
660        mMaterialLodFactorInv = 1.0f / factor;
661        mMaxMaterialLodIndex = maxDetailIndex;
662        mMinMaterialLodIndex = minDetailIndex;
663
664    }
665    //-----------------------------------------------------------------------
666    void Entity::buildSubEntityList(MeshPtr& mesh, SubEntityList* sublist)
667    {
668        // Create SubEntities
669        unsigned short i, numSubMeshes;
670        SubMesh* subMesh;
671        SubEntity* subEnt;
672
673        numSubMeshes = mesh->getNumSubMeshes();
674        for (i = 0; i < numSubMeshes; ++i)
675        {
676            subMesh = mesh->getSubMesh(i);
677            subEnt = new SubEntity(this, subMesh);
678            if (subMesh->isMatInitialised())
679                subEnt->setMaterialName(subMesh->getMaterialName());
680            sublist->push_back(subEnt);
681        }
682    }
683    //-----------------------------------------------------------------------
684    void Entity::setRenderDetail(SceneDetailLevel renderDetail)
685    {
686        SubEntityList::iterator i, iend;
687        iend = mSubEntityList.end();
688
689        for( i = mSubEntityList.begin(); i != iend; ++i )
690        {
691            (*i)->setRenderDetail(renderDetail);
692        }
693    }
694    //-----------------------------------------------------------------------
695    void Entity::setRenderDetailOverrideable(bool renderDetailOverrideable)
696    {
697        SubEntityList::iterator i, iend;
698        iend = mSubEntityList.end();
699
700        for( i = mSubEntityList.begin(); i != iend; ++i )
701        {
702            (*i)->setRenderDetailOverrideable(renderDetailOverrideable);
703        }
704    }
705
706    //-----------------------------------------------------------------------
707    void Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
708    {
709        if (mChildObjectList.find(pMovable->getName()) != mChildObjectList.end())
710        {
711            OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
712                "An object with the name " + pMovable->getName() + " already attached",
713                "Entity::attachObjectToBone");
714        }
715        if(pMovable->isAttached())
716        {
717            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object already attached to a sceneNode or a Bone",
718                "Entity::attachObjectToBone");
719        }
720        if (!hasSkeleton())
721        {
722            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "This entity's mesh has no skeleton to attach object to.",
723                "Entity::attachObjectToBone");
724        }
725        Bone* bone = mSkeletonInstance->getBone(boneName);
726        if (!bone)
727        {
728            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName,
729                "Entity::attachObjectToBone");
730        }
731
732        TagPoint *tp = mSkeletonInstance->createTagPointOnBone(
733            bone, offsetOrientation, offsetPosition);
734        tp->setParentEntity(this);
735        tp->setChildObject(pMovable);
736
737        attachObjectImpl(pMovable, tp);
738
739        // Trigger update of bounding box if necessary
740        if (mParentNode)
741            mParentNode->needUpdate();
742    }
743
744    //-----------------------------------------------------------------------
745    void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint)
746    {
747        assert(mChildObjectList.find(pObject->getName()) == mChildObjectList.end());
748        mChildObjectList[pObject->getName()] = pObject;
749        pObject->_notifyAttached(pAttachingPoint, true);
750    }
751
752    //-----------------------------------------------------------------------
753    MovableObject* Entity::detachObjectFromBone(const String &name)
754    {
755        ChildObjectList::iterator i = mChildObjectList.find(name);
756
757        if (i == mChildObjectList.end())
758        {
759            OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name,
760                "Entity::detachObjectFromBone");
761        }
762        MovableObject *obj = i->second;
763        detachObjectImpl(obj);
764        mChildObjectList.erase(i);
765
766        // Trigger update of bounding box if necessary
767        if (mParentNode)
768            mParentNode->needUpdate();
769
770        return obj;
771    }
772    //-----------------------------------------------------------------------
773    void Entity::detachObjectFromBone(MovableObject* obj)
774    {
775        ChildObjectList::iterator i, iend;
776        iend = mChildObjectList.end();
777        for (i = mChildObjectList.begin(); i != iend; ++i)
778        {
779            if (i->second == obj)
780            {
781                detachObjectImpl(obj);
782                mChildObjectList.erase(i);
783
784                // Trigger update of bounding box if necessary
785                if (mParentNode)
786                    mParentNode->needUpdate();
787                break;
788            }
789        }
790    }
791    //-----------------------------------------------------------------------
792    void Entity::detachAllObjectsFromBone(void)
793    {
794        detachAllObjectsImpl();
795
796        // Trigger update of bounding box if necessary
797        if (mParentNode)
798            mParentNode->needUpdate();
799    }
800    //-----------------------------------------------------------------------
801    void Entity::detachObjectImpl(MovableObject* pObject)
802    {
803        TagPoint* tp = static_cast<TagPoint*>(pObject->getParentNode());
804
805        // free the TagPoint so we can reuse it later
806        mSkeletonInstance->freeTagPoint(tp);
807
808        pObject->_notifyAttached((TagPoint*)0);
809    }
810    //-----------------------------------------------------------------------
811    void Entity::detachAllObjectsImpl(void)
812    {
813        ChildObjectList::const_iterator i, iend;
814        iend = mChildObjectList.end();
815        for (i = mChildObjectList.begin(); i != iend; ++i)
816        {
817            detachObjectImpl(i->second);
818        }
819        mChildObjectList.clear();
820    }
821
822    //-----------------------------------------------------------------------
823    Entity::ChildObjectListIterator Entity::getAttachedObjectIterator()
824    {
825        return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end());
826    }
827    //-----------------------------------------------------------------------
828    Real Entity::getBoundingRadius(void) const
829    {
830        Real rad = mMesh->getBoundingSphereRadius();
831        // Scale by largest scale factor
832        if (mParentNode)
833        {
834            const Vector3& s = mParentNode->_getDerivedScale();
835            rad *= std::max(s.x, std::max(s.y, s.z));
836        }
837        return rad;
838    }
839    //-----------------------------------------------------------------------
840    void Entity::prepareTempBlendBuffers(void)
841    {
842        if (mSharedBlendedVertexData)
843        {
844            delete mSharedBlendedVertexData;
845            mSharedBlendedVertexData = 0;
846        }
847
848        if (hasSkeleton())
849        {
850            // Shared data
851            if (mMesh->sharedVertexData)
852            {
853                // Create temporary vertex blend info
854                // Prepare temp vertex data if needed
855                // Clone without copying data, remove blending info
856                // (since blend is performed in software)
857                mSharedBlendedVertexData =
858                    cloneVertexDataRemoveBlendInfo(mMesh->sharedVertexData);
859                extractTempBufferInfo(mSharedBlendedVertexData, &mTempBlendedBuffer);
860            }
861
862            SubEntityList::iterator i, iend;
863            iend = mSubEntityList.end();
864            for (i = mSubEntityList.begin(); i != iend; ++i)
865            {
866                SubEntity* s = *i;
867                s->prepareTempBlendBuffers();
868            }
869
870
871        }
872
873    }
874    //-----------------------------------------------------------------------
875    void Entity::extractTempBufferInfo(VertexData* sourceData, TempBlendedBufferInfo* info)
876    {
877        VertexDeclaration* decl = sourceData->vertexDeclaration;
878        VertexBufferBinding* bind = sourceData->vertexBufferBinding;
879        const VertexElement *posElem = decl->findElementBySemantic(VES_POSITION);
880        const VertexElement *normElem = decl->findElementBySemantic(VES_NORMAL);
881
882        assert(posElem && "Positions are required");
883
884        info->posBindIndex = posElem->getSource();
885        info->srcPositionBuffer = bind->getBuffer(info->posBindIndex);
886
887        if (!normElem)
888        {
889            info->posNormalShareBuffer = false;
890            info->srcNormalBuffer.setNull();
891        }
892        else
893        {
894            info->normBindIndex = normElem->getSource();
895            if (info->normBindIndex == info->posBindIndex)
896            {
897                info->posNormalShareBuffer = true;
898                info->srcNormalBuffer.setNull();
899            }
900            else
901            {
902                info->posNormalShareBuffer = false;
903                info->srcNormalBuffer = bind->getBuffer(info->normBindIndex);
904            }
905        }
906    }
907    //-----------------------------------------------------------------------
908    VertexData* Entity::cloneVertexDataRemoveBlendInfo(const VertexData* source)
909    {
910        // Clone without copying data
911        VertexData* ret = source->clone(false);
912        const VertexElement* blendIndexElem =
913            source->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
914        const VertexElement* blendWeightElem =
915            source->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
916        // Remove blend index
917        if (blendIndexElem)
918        {
919            // Remove buffer reference
920            ret->vertexBufferBinding->unsetBinding(blendIndexElem->getSource());
921
922        }
923        if (blendWeightElem &&
924            blendWeightElem->getSource() != blendIndexElem->getSource())
925        {
926            // Remove buffer reference
927            ret->vertexBufferBinding->unsetBinding(blendWeightElem->getSource());
928        }
929        // remove elements from declaration
930        ret->vertexDeclaration->removeElement(VES_BLEND_INDICES);
931        ret->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
932
933        // Copy reference to wcoord buffer
934        if (!source->hardwareShadowVolWBuffer.isNull())
935            ret->hardwareShadowVolWBuffer = source->hardwareShadowVolWBuffer;
936
937        return ret;
938    }
939    //-----------------------------------------------------------------------
940    EdgeData* Entity::getEdgeList(void)
941    {
942        // Get from Mesh
943        return mMesh->getEdgeList(mMeshLodIndex);
944    }
945    //-----------------------------------------------------------------------
946    void Entity::reevaluateVertexProcessing(void)
947    {
948        // init
949        mHardwareSkinning = false;
950        mVertexProgramInUse = false; // assume false because we just assign this
951        bool firstPass = true;
952
953        SubEntityList::iterator i, iend;
954        iend = mSubEntityList.end();
955        for (i = mSubEntityList.begin(); i != iend; ++i, firstPass = false)
956        {
957            const MaterialPtr& m = (*i)->getMaterial();
958            // Make sure it's loaded
959            m->load();
960            Technique* t = m->getBestTechnique();
961            if (!t)
962            {
963                // No supported techniques
964                continue;
965            }
966            Pass* p = t->getPass(0);
967            if (!p)
968            {
969                // No passes, invalid
970                continue;
971            }
972            if (p->hasVertexProgram())
973            {
974                // If one material uses a vertex program, set this flag
975                // Causes some special processing like forcing a separate light cap
976                mVertexProgramInUse = true;
977
978                // All materials must support skinning for us to consider using
979                // hardware skinning - if one fails we use software
980                if (firstPass)
981                {
982                    mHardwareSkinning = p->getVertexProgram()->isSkeletalAnimationIncluded();
983                }
984                else
985                {
986                    mHardwareSkinning = mHardwareSkinning &&
987                        p->getVertexProgram()->isSkeletalAnimationIncluded();
988                }
989            }
990        }
991
992    }
993    //-----------------------------------------------------------------------
994    ShadowCaster::ShadowRenderableListIterator
995        Entity::getShadowVolumeRenderableIterator(
996        ShadowTechnique shadowTechnique, const Light* light,
997        HardwareIndexBufferSharedPtr* indexBuffer,
998        bool extrude, Real extrusionDistance, unsigned long flags)
999    {
1000        assert(indexBuffer && "Only external index buffers are supported right now");
1001        assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
1002            "Only 16-bit indexes supported for now");
1003
1004        // Potentially delegate to LOD entity
1005        if (mMesh->isLodManual() && mMeshLodIndex > 0)
1006        {
1007            // Use alternate entity
1008            assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
1009                "No LOD EntityList - did you build the manual LODs after creating the entity?");
1010            // delegate, we're using manual LOD and not the top lod index
1011            if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
1012            {
1013                // Copy the animation state set to lod entity, we assume the lod
1014                // entity only has a subset animation states
1015                CopyAnimationStateSubset(*mLodEntityList[mMeshLodIndex - 1]->mAnimationState, *mAnimationState);
1016            }
1017            return mLodEntityList[mMeshLodIndex-1]->getShadowVolumeRenderableIterator(
1018                shadowTechnique, light, indexBuffer, extrude,
1019                extrusionDistance, flags);
1020        }
1021
1022        bool hasSkeleton = this->hasSkeleton();
1023
1024
1025        // Prep mesh if required
1026        // NB This seems to result in memory corruptions, having problems
1027        // tracking them down. For now, ensure that shadows are enabled
1028        // before any entities are created
1029        if(!mMesh->isPreparedForShadowVolumes())
1030        {
1031            mMesh->prepareForShadowVolume();
1032            // reset frame last updated to force update of buffers
1033            mFrameAnimationLastUpdated = std::numeric_limits<unsigned long>::max();
1034            // re-prepare buffers
1035            prepareTempBlendBuffers();
1036        }
1037
1038
1039        // Update any animation
1040        if (hasSkeleton)
1041        {
1042            updateAnimation();
1043        }
1044
1045        // Calculate the object space light details
1046        Vector4 lightPos = light->getAs4DVector();
1047        // Only use object-space light if we're not doing transforms
1048        // Since when animating the positions are already transformed into
1049        // world space so we need world space light position
1050        if (!hasSkeleton)
1051        {
1052            Matrix4 world2Obj = mParentNode->_getFullTransform().inverse();
1053            lightPos =  world2Obj * lightPos;
1054        }
1055
1056        // We need to search the edge list for silhouette edges
1057        EdgeData* edgeList = getEdgeList();
1058
1059                if (!edgeList)
1060                {
1061                        // we can't get an edge list for some reason, return blank
1062                        // really we shouldn't be able to get here, but this is a safeguard
1063                        return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
1064                }
1065
1066        // Init shadow renderable list if required
1067        bool init = mShadowRenderables.empty();
1068
1069        EdgeData::EdgeGroupList::iterator egi;
1070        ShadowRenderableList::iterator si, siend;
1071        EntityShadowRenderable* esr = 0;
1072        if (init)
1073            mShadowRenderables.resize(edgeList->edgeGroups.size());
1074
1075        bool updatedSharedGeomNormals = false;
1076        siend = mShadowRenderables.end();
1077        egi = edgeList->edgeGroups.begin();
1078        for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
1079        {
1080            if (init)
1081            {
1082                const VertexData *pVertData = 0;
1083                if (hasSkeleton)
1084                {
1085                    // Use temp buffers
1086                    pVertData = findBlendedVertexData(egi->vertexData);
1087                }
1088                else
1089                {
1090                    pVertData = egi->vertexData;
1091                }
1092
1093                // Try to find corresponding SubEntity; this allows the
1094                // linkage of visibility between ShadowRenderable and SubEntity
1095                SubEntity* subent = findSubEntityForVertexData(egi->vertexData);
1096                // Create a new renderable, create a separate light cap if
1097                // we're using a vertex program (either for this model, or
1098                // for extruding the shadow volume) since otherwise we can
1099                // get depth-fighting on the light cap
1100
1101                *si = new EntityShadowRenderable(this, indexBuffer, pVertData,
1102                    mVertexProgramInUse || !extrude, subent);
1103            }
1104            else if (hasSkeleton)
1105            {
1106                // If we have a skeleton, we have no guarantee that the position
1107                // buffer we used last frame is the same one we used last frame
1108                // since a temporary buffer is requested each frame
1109                // therefore, we need to update the EntityShadowRenderable
1110                // with the current position buffer
1111                static_cast<EntityShadowRenderable*>(*si)->rebindPositionBuffer();
1112
1113            }
1114            // Get shadow renderable
1115            esr = static_cast<EntityShadowRenderable*>(*si);
1116            HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
1117            // For animated entities we need to recalculate the face normals
1118            if (hasSkeleton)
1119            {
1120                if (egi->vertexData != mMesh->sharedVertexData || !updatedSharedGeomNormals)
1121                {
1122                    // recalculate face normals
1123                    edgeList->updateFaceNormals(egi->vertexSet, esrPositionBuffer);
1124                    // If we're not extruding in software we still need to update
1125                    // the latter part of the buffer (the hardware extruded part)
1126                    // with the latest animated positions
1127                    if (!extrude)
1128                    {
1129                        // Lock, we'll be locking the (suppressed hardware update) shadow buffer
1130                        float* pSrc = static_cast<float*>(
1131                            esrPositionBuffer->lock(HardwareBuffer::HBL_NORMAL));
1132                        float* pDest = pSrc + (egi->vertexData->vertexCount * 3);
1133                        memcpy(pDest, pSrc, sizeof(float) * 3 * egi->vertexData->vertexCount);
1134                        esrPositionBuffer->unlock();
1135                    }
1136                    if (egi->vertexData == mMesh->sharedVertexData)
1137                    {
1138                        updatedSharedGeomNormals = true;
1139                    }
1140                }
1141            }
1142            // Extrude vertices in software if required
1143            if (extrude)
1144            {
1145                extrudeVertices(esrPositionBuffer,
1146                    egi->vertexData->vertexCount,
1147                    lightPos, extrusionDistance);
1148
1149            }
1150            // Stop suppressing hardware update now, if we were
1151            esrPositionBuffer->suppressHardwareUpdate(false);
1152
1153        }
1154        // Calc triangle light facing
1155        updateEdgeListLightFacing(edgeList, lightPos);
1156
1157        // Generate indexes and update renderables
1158        generateShadowVolume(edgeList, *indexBuffer, light,
1159            mShadowRenderables, flags);
1160
1161
1162        return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
1163    }
1164    //-----------------------------------------------------------------------
1165    const VertexData* Entity::findBlendedVertexData(const VertexData* orig)
1166    {
1167        if (orig == mMesh->sharedVertexData)
1168        {
1169            return mSharedBlendedVertexData;
1170        }
1171        SubEntityList::iterator i, iend;
1172        iend = mSubEntityList.end();
1173        for (i = mSubEntityList.begin(); i != iend; ++i)
1174        {
1175            SubEntity* se = *i;
1176            if (orig == se->getSubMesh()->vertexData)
1177            {
1178                return se->getBlendedVertexData();
1179            }
1180        }
1181        // None found
1182        OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
1183            "Cannot find blended version of the vertex data specified.",
1184            "Entity::findBlendedVertexData");
1185    }
1186    //-----------------------------------------------------------------------
1187    SubEntity* Entity::findSubEntityForVertexData(const VertexData* orig)
1188    {
1189        if (orig == mMesh->sharedVertexData)
1190        {
1191            return 0;
1192        }
1193
1194        SubEntityList::iterator i, iend;
1195        iend = mSubEntityList.end();
1196        for (i = mSubEntityList.begin(); i != iend; ++i)
1197        {
1198            SubEntity* se = *i;
1199            if (orig == se->getSubMesh()->vertexData)
1200            {
1201                return se;
1202            }
1203        }
1204
1205        // None found
1206        return 0;
1207    }
1208    //-----------------------------------------------------------------------
1209    void Entity::addSoftwareSkinningRequest(bool normalsAlso)
1210    {
1211        mSoftwareSkinningRequests++;
1212        if (normalsAlso) {
1213            mSoftwareSkinningNormalsRequests++;
1214        }
1215        if(!mMesh->isPreparedForShadowVolumes())
1216        {
1217            mMesh->prepareForShadowVolume();
1218            // re-prepare buffers
1219            prepareTempBlendBuffers();
1220        }
1221    }
1222    //-----------------------------------------------------------------------
1223    void Entity::removeSoftwareSkinningRequest(bool normalsAlso)
1224    {
1225        if (mSoftwareSkinningRequests == 0 ||
1226            (normalsAlso && mSoftwareSkinningNormalsRequests == 0))
1227        {
1228            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
1229                        "Attempt to remove nonexistant request.",
1230                        "Entity::removeSoftwareSkinningRequest");
1231        }
1232        mSoftwareSkinningRequests--;
1233        if (normalsAlso) {
1234            mSoftwareSkinningNormalsRequests--;
1235        }
1236        // TODO: possibly undo "shadow volume" prep if no longer needed
1237    }
1238    //-----------------------------------------------------------------------
1239    void Entity::_notifyAttached(Node* parent, bool isTagPoint)
1240    {
1241        MovableObject::_notifyAttached(parent, isTagPoint);
1242        // Also notify LOD entities
1243        LODEntityList::iterator i, iend;
1244        iend = mLodEntityList.end();
1245        for (i = mLodEntityList.begin(); i != iend; ++i)
1246        {
1247            (*i)->_notifyAttached(parent, isTagPoint);
1248        }
1249
1250    }
1251    //-----------------------------------------------------------------------
1252    //-----------------------------------------------------------------------
1253    Entity::EntityShadowRenderable::EntityShadowRenderable(Entity* parent,
1254        HardwareIndexBufferSharedPtr* indexBuffer, const VertexData* vertexData,
1255        bool createSeparateLightCap, SubEntity* subent, bool isLightCap)
1256        : mParent(parent), mSubEntity(subent)
1257    {
1258        // Save link to vertex data
1259        mOriginalVertexData = vertexData;
1260
1261        // Initialise render op
1262        mRenderOp.indexData = new IndexData();
1263        mRenderOp.indexData->indexBuffer = *indexBuffer;
1264        mRenderOp.indexData->indexStart = 0;
1265        // index start and count are sorted out later
1266
1267        // Create vertex data which just references position component (and 2 component)
1268        mRenderOp.vertexData = new VertexData();
1269        mRenderOp.vertexData->vertexDeclaration =
1270            HardwareBufferManager::getSingleton().createVertexDeclaration();
1271        mRenderOp.vertexData->vertexBufferBinding =
1272            HardwareBufferManager::getSingleton().createVertexBufferBinding();
1273        // Map in position data
1274        mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
1275        mOriginalPosBufferBinding =
1276            vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
1277        mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(mOriginalPosBufferBinding);
1278        mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
1279        // Map in w-coord buffer (if present)
1280        if(!vertexData->hardwareShadowVolWBuffer.isNull())
1281        {
1282            mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
1283            mWBuffer = vertexData->hardwareShadowVolWBuffer;
1284            mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
1285        }
1286        // Use same vertex start as input
1287        mRenderOp.vertexData->vertexStart = vertexData->vertexStart;
1288
1289        if (isLightCap)
1290        {
1291            // Use original vertex count, no extrusion
1292            mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
1293        }
1294        else
1295        {
1296            // Vertex count must take into account the doubling of the buffer,
1297            // because second half of the buffer is the extruded copy
1298            mRenderOp.vertexData->vertexCount =
1299                vertexData->vertexCount * 2;
1300            if (createSeparateLightCap)
1301            {
1302                // Create child light cap
1303                mLightCap = new EntityShadowRenderable(parent,
1304                    indexBuffer, vertexData, false, subent, true);
1305            }
1306        }
1307
1308    }
1309    //-----------------------------------------------------------------------
1310    Entity::EntityShadowRenderable::~EntityShadowRenderable()
1311    {
1312        delete mRenderOp.indexData;
1313        delete mRenderOp.vertexData;
1314    }
1315    //-----------------------------------------------------------------------
1316    void Entity::EntityShadowRenderable::getWorldTransforms(Matrix4* xform) const
1317    {
1318        unsigned short numBones = mParent->_getNumBoneMatrices();
1319
1320        if (!numBones)
1321        {
1322            *xform = mParent->_getParentNodeFullTransform();
1323        }
1324        else
1325        {
1326            // pretransformed
1327            *xform = Matrix4::IDENTITY;
1328        }
1329    }
1330    //-----------------------------------------------------------------------
1331    const Quaternion& Entity::EntityShadowRenderable::getWorldOrientation(void) const
1332    {
1333        return mParent->getParentNode()->_getDerivedOrientation();
1334    }
1335    //-----------------------------------------------------------------------
1336    const Vector3& Entity::EntityShadowRenderable::getWorldPosition(void) const
1337    {
1338        return mParent->getParentNode()->_getDerivedPosition();
1339    }
1340    //-----------------------------------------------------------------------
1341    void Entity::EntityShadowRenderable::rebindPositionBuffer(void)
1342    {
1343        mPositionBuffer = mOriginalVertexData->vertexBufferBinding->getBuffer(
1344            mOriginalPosBufferBinding);
1345        mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
1346        if (mLightCap)
1347        {
1348            static_cast<EntityShadowRenderable*>(mLightCap)->rebindPositionBuffer();
1349        }
1350
1351    }
1352    //-----------------------------------------------------------------------
1353    bool Entity::EntityShadowRenderable::isVisible(void) const
1354    {
1355        if (mSubEntity)
1356        {
1357            return mSubEntity->isVisible();
1358        }
1359        else
1360        {
1361            return ShadowRenderable::isVisible();
1362        }
1363    }
1364    //-----------------------------------------------------------------------
1365    void Entity::setRenderQueueGroup(RenderQueueGroupID queueID)
1366    {
1367        MovableObject::setRenderQueueGroup(queueID);
1368
1369        // Set render queue for all manual LOD entities
1370        if (mMesh->isLodManual())
1371        {
1372            LODEntityList::iterator li, liend;
1373            liend = mLodEntityList.end();
1374            for (li = mLodEntityList.begin(); li != liend; ++li)
1375            {
1376                (*li)->setRenderQueueGroup(queueID);
1377            }
1378        }
1379    }
1380    //-----------------------------------------------------------------------
1381    void Entity::shareSkeletonInstanceWith(Entity* entity)
1382    {
1383        if (entity->getMesh()->getSkeleton() != getMesh()->getSkeleton())
1384        {
1385            OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
1386                "The supplied entity has a different skeleton.",
1387                "Entity::shareSkeletonWith");   
1388        }
1389        if (!mSkeletonInstance)
1390        {
1391            OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
1392                "This entity has no skeleton.",
1393                "Entity::shareSkeletonWith");   
1394        }       
1395        if (mSharedSkeletonEntities != NULL && entity->mSharedSkeletonEntities != NULL)
1396        {
1397            OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
1398                "Both entities already shares their SkeletonInstances! At least "
1399                "one of the instances must not share it's instance.",
1400                "Entity::shareSkeletonWith");   
1401        }       
1402
1403        //check if we already share our skeletoninstance, we don't want to delete it if so
1404        if (mSharedSkeletonEntities != NULL)
1405        {
1406            entity->shareSkeletonInstanceWith(this);
1407        }
1408        else
1409        {
1410            delete mSkeletonInstance;
1411            delete [] mBoneMatrices;
1412            delete mAnimationState;
1413            delete mFrameBonesLastUpdated;
1414            mSkeletonInstance = entity->mSkeletonInstance;
1415            mNumBoneMatrices = entity->mNumBoneMatrices;
1416            mBoneMatrices = entity->mBoneMatrices;
1417            mAnimationState = entity->mAnimationState;
1418            mFrameBonesLastUpdated = entity->mFrameBonesLastUpdated;
1419            if (entity->mSharedSkeletonEntities == NULL)
1420            {
1421                entity->mSharedSkeletonEntities = new EntitySet();
1422                entity->mSharedSkeletonEntities->insert(entity);
1423            }
1424            mSharedSkeletonEntities = entity->mSharedSkeletonEntities;
1425            mSharedSkeletonEntities->insert(this);
1426        }
1427    }   
1428    //-----------------------------------------------------------------------
1429    void Entity::stopSharingSkeletonInstance()
1430    {
1431        if (mSharedSkeletonEntities == NULL)
1432        {
1433            OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
1434                "This entity is not sharing it's skeletoninstance.",
1435                "Entity::shareSkeletonWith");   
1436        }       
1437        //check if there's no other than us sharing the skeleton instance
1438        if (mSharedSkeletonEntities->size() == 1)
1439        {
1440            //just reset
1441            delete mSharedSkeletonEntities;
1442            mSharedSkeletonEntities = 0;
1443        }
1444        else
1445        {
1446            //do some cloning
1447            /*                  mSkeletonInstance = new SkeletonInstance(*mSkeletonInstance);
1448            mBoneMatrices = new Matrix4(*mBoneMatrices);
1449            mAnimationState = new AnimationStateSet(*mAnimationState);
1450            mFrameBonesLastUpdated = new unsigned long(*mFrameBonesLastUpdated);
1451            */
1452
1453            mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
1454            mSkeletonInstance->load();
1455            mAnimationState = new AnimationStateSet();
1456            mMesh->_initAnimationState(mAnimationState);
1457            mNumBoneMatrices = mSkeletonInstance->getNumBones();
1458            mBoneMatrices = new Matrix4[mNumBoneMatrices];
1459            prepareTempBlendBuffers();
1460            mFrameBonesLastUpdated = new unsigned long;
1461
1462            mSharedSkeletonEntities->erase(this);
1463            if (mSharedSkeletonEntities->size() == 1)
1464            {
1465                (*mSharedSkeletonEntities->begin())->stopSharingSkeletonInstance();
1466            }
1467            mSharedSkeletonEntities = 0;
1468        }
1469    }
1470    //-----------------------------------------------------------------------
1471        void Entity::refreshAvailableAnimationState(void)
1472        {
1473                if (hasSkeleton())
1474                {
1475                        mSkeletonInstance->_refreshAnimationState(mAnimationState);
1476                }
1477        }
1478
1479}
Note: See TracBrowser for help on using the repository browser.