Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreEntity.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004 (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright ? 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreEntity.h"
00027 
00028 #include "OgreMesh.h"
00029 #include "OgreSubMesh.h"
00030 #include "OgreSubEntity.h"
00031 #include "OgreException.h"
00032 #include "OgreSceneManager.h"
00033 #include "OgreLogManager.h"
00034 #include "OgreSkeleton.h"
00035 #include "OgreBone.h"
00036 #include "OgreCamera.h"
00037 #include "OgreTagPoint.h"
00038 #include "OgreAxisAlignedBox.h"
00039 #include "OgreHardwareBufferManager.h"
00040 #include "OgreVector4.h"
00041 #include "OgreRoot.h"
00042 #include "OgreTechnique.h"
00043 #include "OgrePass.h"
00044 #include "OgreSkeletonInstance.h"
00045 #include "OgreEdgeListBuilder.h"
00046 #include "OgreStringConverter.h"
00047 
00048 namespace Ogre {
00049     String Entity::msMovableType = "Entity";
00050     //-----------------------------------------------------------------------
00051     Entity::Entity () 
00052     {
00053         mFullBoundingBox = new AxisAlignedBox;
00054         mNormaliseNormals = false;
00055         mFrameBonesLastUpdated = new unsigned long;
00056         *mFrameBonesLastUpdated = 0;
00057         mFrameAnimationLastUpdated = 0;
00058         mHardwareSkinning = false;
00059         mSkeletonInstance = 0;
00060     }
00061     //-----------------------------------------------------------------------
00062     Entity::Entity( const String& name, Mesh* mesh, SceneManager* creator) :
00063     mName(name),
00064         mMesh(mesh),
00065         mCreatorSceneManager(creator),
00066         mSharedSkeletonEntities(NULL)
00067     {
00068         mFullBoundingBox = new AxisAlignedBox;
00069         mHardwareSkinning = false;
00070         mSharedBlendedVertexData = NULL;
00071 
00072         // Is mesh skeletally animated?
00073         if (mMesh->hasSkeleton() && mMesh->getSkeleton() != NULL)
00074         {
00075             mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
00076             mSkeletonInstance->load();
00077         }
00078         else
00079         {
00080             mSkeletonInstance = 0;
00081         }
00082 
00083         // Build main subentity list
00084         buildSubEntityList(mesh, &mSubEntityList);
00085 
00086         // Check if mesh is using manual LOD
00087         if (mesh->isLodManual())
00088         {
00089             ushort i, numLod;
00090             numLod = mesh->getNumLodLevels();
00091             // NB skip LOD 0 which is the original
00092             for (i = 1; i < numLod; ++i)
00093             {
00094                 const Mesh::MeshLodUsage& usage = mesh->getLodLevel(i);
00095                 // Manually create entity
00096                 Entity* lodEnt = new Entity(name + "Lod" + StringConverter::toString(i), 
00097                     usage.manualMesh, mCreatorSceneManager);
00098                 mLodEntityList.push_back(lodEnt);
00099             }
00100 
00101         }
00102 
00103 
00104         // Initialise the AnimationState, if Mesh has animation
00105 
00106         if (hasSkeleton())
00107         {
00108             mAnimationState = new AnimationStateSet();
00109             mFrameBonesLastUpdated = new unsigned long;
00110             *mFrameBonesLastUpdated = 0;
00111             mesh->_initAnimationState(mAnimationState);
00112             mNumBoneMatrices = mSkeletonInstance->getNumBones();
00113             mBoneMatrices = new Matrix4[mNumBoneMatrices];
00114             prepareTempBlendBuffers();
00115         }
00116         else
00117         {
00118             mBoneMatrices = 0;
00119             mNumBoneMatrices = 0;
00120             mAnimationState = 0;
00121             mFrameBonesLastUpdated  = 0;
00122 
00123         }
00124 
00125         reevaluateVertexProcessing();
00126 
00127         mDisplaySkeleton = false;
00128 
00129         mMeshLodFactorInv = 1.0f;
00130         mMeshLodIndex = 0;
00131         mMaxMeshLodIndex = 0;       // Backwards, remember low value = high detail
00132         mMinMeshLodIndex = 99;
00133 
00134         mMaterialLodFactorInv = 1.0f;
00135         mMaxMaterialLodIndex = 0;       // Backwards, remember low value = high detail
00136         mMinMaterialLodIndex = 99;
00137 
00138 
00139         mFrameAnimationLastUpdated = 0;
00140 
00141         // Do we have a mesh where edge lists are not going to be available?
00142         if (!mesh->isEdgeListBuilt() && !mesh->getAutoBuildEdgeLists())
00143         {
00144             setCastShadows(false);
00145         }
00146     }
00147     //-----------------------------------------------------------------------
00148     Entity::~Entity()
00149     {
00150         // Delete submeshes
00151         SubEntityList::iterator i, iend;
00152         iend = mSubEntityList.end();
00153         for (i = mSubEntityList.begin(); i != iend; ++i)
00154         {
00155             // Delete SubEntity
00156             delete *i;
00157         }
00158         // Delete LOD entities
00159         LODEntityList::iterator li, liend;
00160         liend = mLodEntityList.end();
00161         for (li = mLodEntityList.begin(); li != liend; ++li)
00162         {
00163             // Delete 
00164             delete (*li);
00165         }
00166 
00167         delete mFullBoundingBox;
00168 
00169         // Delete shadow renderables
00170         ShadowRenderableList::iterator si, siend;
00171         siend = mShadowRenderables.end();
00172         for (si = mShadowRenderables.begin(); si != siend; ++si)
00173         {
00174             delete *si;
00175         }
00176 
00177         // Detach all child objects, do this manually to avoid needUpdate() call 
00178         // which can fail because of deleted items
00179         detachAllObjectsImpl();
00180 
00181         if (mSkeletonInstance) {
00182             if (mSharedSkeletonEntities) {
00183                 mSharedSkeletonEntities->erase(this);
00184                 if (mSharedSkeletonEntities->size() == 0) {
00185                     delete mSkeletonInstance;
00186                     delete [] mBoneMatrices;
00187                     delete mAnimationState;
00188                     delete mFrameBonesLastUpdated;
00189                     delete mSharedSkeletonEntities;
00190                 }   
00191             } else {
00192                 delete mSkeletonInstance;
00193                 delete [] mBoneMatrices;
00194                 delete mAnimationState;
00195                 delete mFrameBonesLastUpdated;
00196             }
00197         }
00198     }
00199     //-----------------------------------------------------------------------
00200     Mesh* Entity::getMesh(void)
00201     {
00202         return mMesh;
00203     }
00204     //-----------------------------------------------------------------------
00205     const String& Entity::getName(void) const
00206     {
00207         return mName;
00208     }
00209     //-----------------------------------------------------------------------
00210     SubEntity* Entity::getSubEntity(unsigned int index)
00211     {
00212         if (index >= mSubEntityList.size())
00213             Except(Exception::ERR_INVALIDPARAMS,
00214             "Index out of bounds.",
00215             "Entity::getSubEntity");
00216         return mSubEntityList[index];
00217     }
00218     //-----------------------------------------------------------------------
00219     SubEntity* Entity::getSubEntity(const String& name)
00220     {
00221         ushort index = mMesh->_getSubMeshIndex(name);
00222         return getSubEntity(index);
00223     }
00224     //-----------------------------------------------------------------------
00225     unsigned int Entity::getNumSubEntities(void) const
00226     {
00227         return static_cast< unsigned int >( mSubEntityList.size() );
00228     }
00229     //-----------------------------------------------------------------------
00230     Entity* Entity::clone( const String& newName)
00231     {
00232         Entity* newEnt;
00233         newEnt = mCreatorSceneManager->createEntity( newName, getMesh()->getName() );
00234         // Copy material settings
00235         SubEntityList::iterator i;
00236         unsigned int n = 0;
00237         for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i, ++n)
00238         {
00239             newEnt->getSubEntity(n)->setMaterialName((*i)->getMaterialName());
00240         }
00241         if (mAnimationState)
00242         {
00243             newEnt->mAnimationState = new AnimationStateSet(*mAnimationState);
00244         }
00245         return newEnt;
00246     }
00247     //-----------------------------------------------------------------------
00248     void Entity::setMaterialName(const String& name)
00249     {
00250         // Set for all subentities
00251         SubEntityList::iterator i;
00252         for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
00253         {
00254             (*i)->setMaterialName(name);
00255         }
00256 
00257     }
00258     //-----------------------------------------------------------------------
00259     void Entity::_notifyCurrentCamera(Camera* cam)
00260     {
00261         // Calculate the LOD
00262         if (mParentNode)
00263         {
00264             Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
00265 
00266             // Do Mesh LOD
00267             // Adjust this depth by the entity bias factor
00268             Real tmp = squaredDepth * mMeshLodFactorInv;
00269             // Now adjust it by the camera bias
00270             tmp = tmp * cam->_getLodBiasInverse();
00271             // Get the index at this biased depth
00272             mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp);
00273             // Apply maximum detail restriction (remember lower = higher detail)
00274             mMeshLodIndex = std::max(mMaxMeshLodIndex, mMeshLodIndex);
00275             // Apply minimum detail restriction (remember higher = lower detail)
00276             mMeshLodIndex = std::min(mMinMeshLodIndex, mMeshLodIndex);
00277 
00278             // Now do material LOD
00279             // Adjust this depth by the entity bias factor
00280             tmp = squaredDepth * mMaterialLodFactorInv;
00281             // Now adjust it by the camera bias
00282             tmp = tmp * cam->_getLodBiasInverse();
00283             SubEntityList::iterator i, iend;
00284             iend = mSubEntityList.end();
00285             for (i = mSubEntityList.begin(); i != iend; ++i)
00286             {
00287                 // Get the index at this biased depth
00288                 unsigned short idx = (*i)->mpMaterial->getLodIndexSquaredDepth(tmp);
00289                 // Apply maximum detail restriction (remember lower = higher detail)
00290                 idx = std::max(mMaxMaterialLodIndex, idx);
00291                 // Apply minimum detail restriction (remember higher = lower detail)
00292                 (*i)->mMaterialLodIndex = std::min(mMinMaterialLodIndex, idx);
00293             }
00294 
00295 
00296         }
00297         // Notify any child objects
00298         ChildObjectList::iterator child_itr = mChildObjectList.begin();
00299         ChildObjectList::iterator child_itr_end = mChildObjectList.end();
00300         for( ; child_itr != child_itr_end; child_itr++)
00301         {
00302             (*child_itr).second->_notifyCurrentCamera(cam);
00303         }
00304 
00305 
00306     }
00307     //-----------------------------------------------------------------------
00308     const AxisAlignedBox& Entity::getBoundingBox(void) const
00309     {
00310         // Get from Mesh
00311         *mFullBoundingBox = mMesh->getBounds();
00312         mFullBoundingBox->merge(getChildObjectsBoundingBox());
00313 
00314         // Don't scale here, this is taken into account when world BBox calculation is done
00315 
00316         return *mFullBoundingBox;
00317     }
00318     //-----------------------------------------------------------------------
00319     AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const
00320     {
00321         AxisAlignedBox aa_box;
00322         AxisAlignedBox full_aa_box;
00323         full_aa_box.setNull();
00324 
00325         ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
00326         ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
00327         for( ; child_itr != child_itr_end; child_itr++)
00328         {
00329             aa_box = child_itr->second->getBoundingBox();
00330             TagPoint* tp = (TagPoint*)child_itr->second->getParentNode();
00331             // Use transform local to skeleton since world xform comes later
00332             aa_box.transform(tp->_getFullLocalTransform());
00333 
00334             full_aa_box.merge(aa_box);
00335         }
00336 
00337         return full_aa_box;
00338     }
00339     //-----------------------------------------------------------------------
00340     void Entity::_updateRenderQueue(RenderQueue* queue)
00341     {
00342         // Check we're not using a manual LOD
00343         if (mMeshLodIndex > 0 && mMesh->isLodManual())
00344         {
00345             // Use alternate entity
00346             assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() && 
00347                 "No LOD EntityList - did you build the manual LODs after creating the entity?");
00348             // index - 1 as we skip index 0 (original lod)
00349             if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
00350             {
00351                 // Copy the animation state set to lod entity, we assume the lod
00352                 // entity only has a subset animation states
00353                 CopyAnimationStateSubset(*mLodEntityList[mMeshLodIndex - 1]->mAnimationState, *mAnimationState);
00354             }
00355             mLodEntityList[mMeshLodIndex - 1]->_updateRenderQueue(queue);
00356             return;
00357         }
00358 
00359         // Add each visible SubEntity to the queue
00360         SubEntityList::iterator i, iend;
00361         iend = mSubEntityList.end();
00362         for (i = mSubEntityList.begin(); i != iend; ++i)
00363         {
00364             if((*i)->isVisible())  
00365             {
00366                 if(mRenderQueueIDSet) 
00367                 {
00368                     queue->addRenderable(*i, mRenderQueueID);
00369                 } 
00370                 else 
00371                 {
00372                     queue->addRenderable(*i);
00373                 }
00374             }
00375         }
00376 
00377         // Since we know we're going to be rendered, take this opportunity to 
00378         // update the animation
00379         if (hasSkeleton())
00380         {
00381             updateAnimation();
00382 
00383             //--- pass this point,  we are sure that the transformation matrix of each bone and tagPoint have been updated          
00384             ChildObjectList::iterator child_itr = mChildObjectList.begin();
00385             ChildObjectList::iterator child_itr_end = mChildObjectList.end();
00386             for( ; child_itr != child_itr_end; child_itr++)
00387             {
00388                 if ((*child_itr).second->isVisible())
00389                     (*child_itr).second->_updateRenderQueue(queue);
00390             }
00391         }
00392 
00393         // HACK to display bones
00394         // This won't work if the entity is not centered at the origin
00395         // TODO work out a way to allow bones to be rendered when Entity not centered
00396         if (mDisplaySkeleton && hasSkeleton())
00397         {
00398             int numBones = mSkeletonInstance->getNumBones();
00399             for (int b = 0; b < numBones; ++b)
00400             {
00401                 Bone* bone = mSkeletonInstance->getBone(b);
00402                 if(mRenderQueueIDSet) 
00403                 {
00404                      queue->addRenderable(bone, mRenderQueueID);
00405                 } else {
00406                      queue->addRenderable(bone);
00407                 }
00408             }
00409         }
00410 
00411 
00412 
00413 
00414     }
00415     //-----------------------------------------------------------------------
00416     AnimationState* Entity::getAnimationState(const String& name)
00417     {
00418         if (!mAnimationState)
00419         {
00420             Except(Exception::ERR_ITEM_NOT_FOUND, "Entity is not animated", 
00421                 "Entity::getAnimationState");
00422         }
00423         AnimationStateSet::iterator i = mAnimationState->find(name);
00424 
00425         if (i == mAnimationState->end())
00426         {
00427             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
00428                 "Entity::getAnimationState");
00429         }
00430 
00431         return &(i->second);
00432     }
00433     //-----------------------------------------------------------------------
00434     AnimationStateSet* Entity::getAllAnimationStates(void)
00435     {
00436         return mAnimationState;
00437     }
00438     //-----------------------------------------------------------------------
00439     const String& Entity::getMovableType(void) const
00440     {
00441         return msMovableType;
00442     }
00443     //-----------------------------------------------------------------------
00444     void Entity::updateAnimation(void)
00445     {
00446         // We only do these tasks if they have not already been done for 
00447         // this frame 
00448         Root& root = Root::getSingleton();
00449         unsigned long currentFrameNumber = root.getCurrentFrameNumber();
00450         if (mFrameAnimationLastUpdated != currentFrameNumber)
00451         {
00452             cacheBoneMatrices();
00453 
00454             // Software blend?
00455             bool hwSkinning = isHardwareSkinningEnabled();
00456             if (!hwSkinning ||
00457                 root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_ADDITIVE ||
00458                 root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_MODULATIVE)
00459             {
00460                 // Ok, we need to do a software blend
00461                 // Blend normals in s/w only if we're not using h/w skinning,
00462                 // since shadows only require positions
00463                 bool blendNormals = !hwSkinning;
00464                 // Firstly, check out working vertex buffers
00465                 if (mSharedBlendedVertexData)
00466                 {
00467                     // Blend shared geometry
00468                     // NB we suppress hardware upload while doing blend if we're
00469                     // hardware skinned, because the only reason for doing this
00470                     // is for shadow, which need only be uploaded then
00471                     mTempBlendedBuffer.checkoutTempCopies(true, blendNormals);
00472                     mTempBlendedBuffer.bindTempCopies(mSharedBlendedVertexData, 
00473                         mHardwareSkinning);
00474                     Mesh::softwareVertexBlend(mMesh->sharedVertexData, 
00475                         mSharedBlendedVertexData, mBoneMatrices, blendNormals);
00476                 }
00477                 SubEntityList::iterator i, iend;
00478                 iend = mSubEntityList.end();
00479                 for (i = mSubEntityList.begin(); i != iend; ++i)
00480                 {
00481                     // Blend dedicated geometry
00482                     SubEntity* se = *i;
00483                     if (se->isVisible() && se->mBlendedVertexData)
00484                     {
00485                         se->mTempBlendedBuffer.checkoutTempCopies(true, blendNormals);
00486                         se->mTempBlendedBuffer.bindTempCopies(se->mBlendedVertexData, 
00487                             mHardwareSkinning);
00488                         Mesh::softwareVertexBlend(se->mSubMesh->vertexData, 
00489                             se->mBlendedVertexData, mBoneMatrices, blendNormals);
00490                     }
00491 
00492                 }
00493 
00494             }
00495 
00496             // Trigger update of bounding box if necessary
00497             if (!mChildObjectList.empty())
00498                 mParentNode->needUpdate();
00499             mFrameAnimationLastUpdated = currentFrameNumber;
00500         }
00501     }
00502     //-----------------------------------------------------------------------
00503     void Entity::cacheBoneMatrices(void)
00504     {
00505         Root& root = Root::getSingleton();
00506         unsigned long currentFrameNumber = root.getCurrentFrameNumber();        
00507         if (*mFrameBonesLastUpdated  != currentFrameNumber) {
00508 
00509             // Get the appropriate meshes skeleton here
00510             // Can use lower LOD mesh skeleton if mesh LOD is manual
00511             // We make the assumption that lower LOD meshes will have
00512             //   fewer bones than the full LOD, therefore marix stack will be
00513             //   big enough.
00514             Mesh* theMesh;
00515             if (mMesh->isLodManual() && mMeshLodIndex > 1)
00516             {
00517                 // Use lower detail skeleton
00518                 theMesh = mMesh->getLodLevel(mMeshLodIndex).manualMesh;
00519                 // Lower detail may not have skeleton
00520                 if (!theMesh->hasSkeleton())
00521                 {
00522                     mNumBoneMatrices = 0;
00523                     return;
00524                 }
00525             }
00526             else
00527             {
00528                 // Use normal mesh
00529                 theMesh = mMesh;
00530             }
00531 
00532             mSkeletonInstance->setAnimationState(*mAnimationState);
00533             mSkeletonInstance->_getBoneMatrices(mBoneMatrices);
00534             *mFrameBonesLastUpdated  = currentFrameNumber;
00535 
00536             if (sharesSkeletonInstance()) {
00537                 //---- update all sharing entities child objects transforms now
00538                 EntitySet::const_iterator entity_itr = mSharedSkeletonEntities->begin();
00539                 EntitySet::const_iterator entity_itr_end = mSharedSkeletonEntities->end();
00540                 for( ; entity_itr != entity_itr_end; entity_itr++)
00541                 {
00542                     ChildObjectList::iterator child_itr = (*entity_itr)->mChildObjectList.begin();
00543                     ChildObjectList::iterator child_itr_end = (*entity_itr)->mChildObjectList.end();
00544                     for( ; child_itr != child_itr_end; child_itr++)
00545                     {
00546                         (*child_itr).second->getParentNode()->_update(true, true);
00547                     }
00548                 }
00549             } else {
00550                 //--- Update the child object's transforms
00551                 ChildObjectList::iterator child_itr = mChildObjectList.begin();
00552                 ChildObjectList::iterator child_itr_end = mChildObjectList.end();
00553                 for( ; child_itr != child_itr_end; child_itr++)
00554                 {
00555                     (*child_itr).second->getParentNode()->_update(true, true);
00556                 }
00557             }
00558 
00559             // Apply our current world transform to these too, since these are used as
00560             // replacement world matrices
00561             unsigned short i;
00562             Matrix4 worldXform = _getParentNodeFullTransform();
00563             mNumBoneMatrices = mSkeletonInstance->getNumBones();
00564 
00565             for (i = 0; i < mNumBoneMatrices; ++i)
00566             {
00567                 mBoneMatrices[i] = worldXform * mBoneMatrices[i];
00568             }
00569         }
00570 
00571 
00572     }
00573     //-----------------------------------------------------------------------
00574     void Entity::setDisplaySkeleton(bool display)
00575     {
00576         mDisplaySkeleton = display;
00577     }
00578     //-----------------------------------------------------------------------
00579     void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
00580     {
00581         assert(factor > 0.0f && "Bias factor must be > 0!");
00582         mMeshLodFactorInv = 1.0f / factor;
00583         mMaxMeshLodIndex = maxDetailIndex;
00584         mMinMeshLodIndex = minDetailIndex;
00585 
00586     }
00587     //-----------------------------------------------------------------------
00588     void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
00589     {
00590         assert(factor > 0.0f && "Bias factor must be > 0!");
00591         mMaterialLodFactorInv = 1.0f / factor;
00592         mMaxMaterialLodIndex = maxDetailIndex;
00593         mMinMaterialLodIndex = minDetailIndex;
00594 
00595     }
00596     //-----------------------------------------------------------------------
00597     void Entity::buildSubEntityList(Mesh* mesh, SubEntityList* sublist)
00598     {
00599         // Create SubEntities
00600         unsigned short i, numSubMeshes;
00601         SubMesh* subMesh;
00602         SubEntity* subEnt;
00603 
00604         numSubMeshes = mesh->getNumSubMeshes();
00605         for (i = 0; i < numSubMeshes; ++i)
00606         {
00607             subMesh = mesh->getSubMesh(i);
00608             subEnt = new SubEntity(this, subMesh);
00609             if (subMesh->isMatInitialised())
00610                 subEnt->setMaterialName(subMesh->getMaterialName());
00611             sublist->push_back(subEnt);
00612         }
00613     }
00614     //-----------------------------------------------------------------------
00615     void Entity::setRenderDetail(SceneDetailLevel renderDetail) 
00616     {
00617         SubEntityList::iterator i, iend;
00618         iend = mSubEntityList.end();
00619 
00620         for( i = mSubEntityList.begin(); i != iend; ++i ) 
00621         { 
00622             (*i)->setRenderDetail(renderDetail); 
00623         } 
00624     }
00625 
00626     //-----------------------------------------------------------------------
00627     void Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
00628     {
00629         if (mChildObjectList.find(pMovable->getName()) != mChildObjectList.end())
00630         {
00631             Except(Exception::ERR_DUPLICATE_ITEM,
00632                 "An object with the name " + pMovable->getName() + " already attached",
00633                 "Entity::attachObjectToBone");
00634         }
00635         if(pMovable->isAttached())
00636         {
00637             Except(Exception::ERR_INVALIDPARAMS, "Object already attached to a sceneNode or a Bone", 
00638                 "Entity::attachObjectToBone");
00639         }
00640         if (!hasSkeleton())
00641         {
00642             Except(Exception::ERR_INVALIDPARAMS, "This entity's mesh has no skeleton to attach object to.", 
00643                 "Entity::attachObjectToBone");
00644         }
00645         Bone* bone = mSkeletonInstance->getBone(boneName);
00646         if (!bone)
00647         {
00648             Except(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName, 
00649                 "Entity::attachObjectToBone");
00650         }
00651 
00652         TagPoint *tp = mSkeletonInstance->createTagPointOnBone(
00653             bone, offsetOrientation, offsetPosition);
00654         tp->setParentEntity(this);
00655         tp->setChildObject(pMovable);
00656 
00657         attachObjectImpl(pMovable, tp);
00658 
00659         // Trigger update of bounding box if necessary
00660         if (mParentNode)
00661             mParentNode->needUpdate();
00662     }
00663 
00664     //-----------------------------------------------------------------------
00665     void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint)
00666     {
00667         assert(mChildObjectList.find(pObject->getName()) == mChildObjectList.end());
00668         mChildObjectList[pObject->getName()] = pObject;
00669         pObject->_notifyAttached(pAttachingPoint, true);
00670     }
00671 
00672     //-----------------------------------------------------------------------
00673     MovableObject* Entity::detachObjectFromBone(const String &name)
00674     {
00675         ChildObjectList::iterator i = mChildObjectList.find(name);
00676 
00677         if (i == mChildObjectList.end())
00678         {
00679             Except(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name, 
00680                 "Entity::detachObjectFromBone");
00681         }
00682         MovableObject *obj = i->second;
00683         detachObjectImpl(obj);
00684         mChildObjectList.erase(i);
00685 
00686         // Trigger update of bounding box if necessary
00687         if (mParentNode)
00688             mParentNode->needUpdate();
00689 
00690         return obj;
00691     }
00692     //-----------------------------------------------------------------------
00693     void Entity::detachObjectFromBone(MovableObject* obj)
00694     {
00695         ChildObjectList::iterator i, iend;
00696         iend = mChildObjectList.end();
00697         for (i = mChildObjectList.begin(); i != iend; ++i)
00698         {
00699             if (i->second == obj)
00700             {
00701                 detachObjectImpl(obj);
00702                 mChildObjectList.erase(i);
00703 
00704                 // Trigger update of bounding box if necessary
00705                 if (mParentNode)
00706                     mParentNode->needUpdate();
00707                 break;
00708             }
00709         }
00710     }
00711     //-----------------------------------------------------------------------
00712     void Entity::detachAllObjectsFromBone(void)
00713     {
00714         detachAllObjectsImpl();
00715 
00716         // Trigger update of bounding box if necessary
00717         if (mParentNode)
00718             mParentNode->needUpdate();
00719     }
00720     //-----------------------------------------------------------------------
00721     void Entity::detachObjectImpl(MovableObject* pObject)
00722     {
00723         TagPoint* tp = static_cast<TagPoint*>(pObject->getParentNode());
00724 
00725         // free the TagPoint so we can reuse it later
00726         mSkeletonInstance->freeTagPoint(tp);
00727 
00728         pObject->_notifyAttached((TagPoint*)0);
00729     }
00730     //-----------------------------------------------------------------------
00731     void Entity::detachAllObjectsImpl(void)
00732     {
00733         ChildObjectList::const_iterator i, iend;
00734         iend = mChildObjectList.end();
00735         for (i = mChildObjectList.begin(); i != iend; ++i)
00736         {
00737             detachObjectImpl(i->second);
00738         }
00739         mChildObjectList.clear();
00740     }
00741 
00742     //-----------------------------------------------------------------------
00743     Entity::ChildObjectListIterator Entity::getAttachedObjectIterator()
00744     {
00745         return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end());
00746     }
00747     //-----------------------------------------------------------------------
00748     Real Entity::getBoundingRadius(void) const
00749     {
00750         Real rad = mMesh->getBoundingSphereRadius();
00751         // Scale by largest scale factor
00752         if (mParentNode)
00753         {
00754             const Vector3& s = mParentNode->_getDerivedScale();
00755             rad *= std::max(s.x, std::max(s.y, s.z));
00756         }
00757         return rad;
00758     }
00759     //-----------------------------------------------------------------------
00760     void Entity::prepareTempBlendBuffers(void)
00761     {
00762         if (mSharedBlendedVertexData) 
00763         {
00764             delete mSharedBlendedVertexData;
00765             mSharedBlendedVertexData = 0;
00766         }
00767 
00768         if (hasSkeleton())
00769         {
00770             // Shared data
00771             if (mMesh->sharedVertexData)
00772             {
00773                 // Create temporary vertex blend info
00774                 // Prepare temp vertex data if needed
00775                 // Clone without copying data, remove blending info
00776                 // (since blend is performed in software)
00777                 mSharedBlendedVertexData = 
00778                     cloneVertexDataRemoveBlendInfo(mMesh->sharedVertexData);
00779                 extractTempBufferInfo(mSharedBlendedVertexData, &mTempBlendedBuffer);
00780             }
00781 
00782             SubEntityList::iterator i, iend;
00783             iend = mSubEntityList.end();
00784             for (i = mSubEntityList.begin(); i != iend; ++i)
00785             {
00786                 SubEntity* s = *i;
00787                 s->prepareTempBlendBuffers();
00788             }
00789 
00790 
00791         }
00792 
00793     }
00794     //-----------------------------------------------------------------------
00795     void Entity::extractTempBufferInfo(VertexData* sourceData, TempBlendedBufferInfo* info)
00796     {
00797         VertexDeclaration* decl = sourceData->vertexDeclaration;
00798         VertexBufferBinding* bind = sourceData->vertexBufferBinding;
00799         const VertexElement *posElem = decl->findElementBySemantic(VES_POSITION);
00800         const VertexElement *normElem = decl->findElementBySemantic(VES_NORMAL);
00801 
00802         assert(posElem && "Positions are required");
00803 
00804         info->posBindIndex = posElem->getSource();
00805         info->srcPositionBuffer = bind->getBuffer(info->posBindIndex);
00806 
00807         if (!normElem)
00808         {
00809             info->posNormalShareBuffer = false;
00810             info->srcNormalBuffer.setNull();
00811         }
00812         else
00813         {
00814             info->normBindIndex = normElem->getSource();
00815             if (info->normBindIndex == info->posBindIndex)
00816             {
00817                 info->posNormalShareBuffer = true;
00818                 info->srcNormalBuffer.setNull();
00819             }
00820             else
00821             {
00822                 info->posNormalShareBuffer = false;
00823                 info->srcNormalBuffer = bind->getBuffer(info->normBindIndex);
00824             }
00825         }
00826     }
00827     //-----------------------------------------------------------------------
00828     VertexData* Entity::cloneVertexDataRemoveBlendInfo(const VertexData* source)
00829     {
00830         // Clone without copying data
00831         VertexData* ret = source->clone(false);
00832         const VertexElement* blendIndexElem = 
00833             source->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
00834         const VertexElement* blendWeightElem = 
00835             source->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
00836         // Remove blend index
00837         if (blendIndexElem)
00838         {
00839             // Remove buffer reference
00840             ret->vertexBufferBinding->unsetBinding(blendIndexElem->getSource());
00841 
00842         }
00843         if (blendWeightElem && 
00844             blendWeightElem->getSource() != blendIndexElem->getSource())
00845         {
00846             // Remove buffer reference
00847             ret->vertexBufferBinding->unsetBinding(blendWeightElem->getSource());
00848         }
00849         // remove elements from declaration
00850         ret->vertexDeclaration->removeElement(VES_BLEND_INDICES);
00851         ret->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
00852 
00853         // Copy reference to wcoord buffer
00854         if (!source->hardwareShadowVolWBuffer.isNull())
00855             ret->hardwareShadowVolWBuffer = source->hardwareShadowVolWBuffer;
00856 
00857         return ret;
00858     }
00859     //-----------------------------------------------------------------------
00860     EdgeData* Entity::getEdgeList(void)
00861     {
00862         // Get from Mesh
00863         return mMesh->getEdgeList(mMeshLodIndex);
00864     }
00865     //-----------------------------------------------------------------------
00866     void Entity::reevaluateVertexProcessing(void)
00867     {
00868         // init
00869         mHardwareSkinning = false; 
00870         mVertexProgramInUse = false; // assume false because we just assign this
00871         bool firstPass = true;
00872 
00873         SubEntityList::iterator i, iend;
00874         iend = mSubEntityList.end();
00875         for (i = mSubEntityList.begin(); i != iend; ++i, firstPass = false)
00876         {
00877             Material* m = (*i)->getMaterial();
00878             // Make sure it's loaded
00879             m->load();
00880             Technique* t = m->getBestTechnique();
00881             if (!t)
00882             {
00883                 // No supported techniques
00884                 continue;
00885             }
00886             Pass* p = t->getPass(0);
00887             if (!p)
00888             {
00889                 // No passes, invalid
00890                 continue;
00891             }
00892             if (p->hasVertexProgram())
00893             {
00894                 // If one material uses a vertex program, set this flag 
00895                 // Causes some special processing like forcing a separate light cap
00896                 mVertexProgramInUse = true;
00897 
00898                 // All materials must support skinning for us to consider using
00899                 // hardware skinning - if one fails we use software
00900                 if (firstPass)
00901                 {
00902                     mHardwareSkinning = p->getVertexProgram()->isSkeletalAnimationIncluded();
00903                 }
00904                 else
00905                 {
00906                     mHardwareSkinning = mHardwareSkinning &&
00907                         p->getVertexProgram()->isSkeletalAnimationIncluded();
00908                 }
00909             }
00910         }
00911 
00912     }
00913     //-----------------------------------------------------------------------
00914     ShadowCaster::ShadowRenderableListIterator 
00915         Entity::getShadowVolumeRenderableIterator(
00916         ShadowTechnique shadowTechnique, const Light* light, 
00917         HardwareIndexBufferSharedPtr* indexBuffer, 
00918         bool extrude, Real extrusionDistance, unsigned long flags)
00919     {
00920         assert(indexBuffer && "Only external index buffers are supported right now");
00921         assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT && 
00922             "Only 16-bit indexes supported for now");
00923 
00924         // Potentially delegate to LOD entity
00925         if (mMesh->isLodManual() && mMeshLodIndex > 0)
00926         {
00927             // Use alternate entity
00928             assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() && 
00929                 "No LOD EntityList - did you build the manual LODs after creating the entity?");
00930             // delegate, we're using manual LOD and not the top lod index
00931             if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
00932             {
00933                 // Copy the animation state set to lod entity, we assume the lod
00934                 // entity only has a subset animation states
00935                 CopyAnimationStateSubset(*mLodEntityList[mMeshLodIndex - 1]->mAnimationState, *mAnimationState);
00936             }
00937             return mLodEntityList[mMeshLodIndex-1]->getShadowVolumeRenderableIterator(
00938                 shadowTechnique, light, indexBuffer, extrude, 
00939                 extrusionDistance, flags);
00940         }
00941 
00942         bool hasSkeleton = this->hasSkeleton();
00943 
00944 
00945         // Prep mesh if required
00946         // NB This seems to result in memory corruptions, having problems
00947         // tracking them down. For now, ensure that shadows are enabled
00948         // before any entities are created
00949         if(!mMesh->isPreparedForShadowVolumes())
00950         {
00951             mMesh->prepareForShadowVolume();
00952             // reset frame last updated to force update of buffers
00953             mFrameAnimationLastUpdated = 0;
00954             // re-prepare buffers
00955             prepareTempBlendBuffers();
00956         }
00957 
00958 
00959         // Update any animation 
00960         if (hasSkeleton)
00961         {
00962             updateAnimation();
00963         }
00964 
00965         // Calculate the object space light details
00966         Vector4 lightPos = light->getAs4DVector();
00967         // Only use object-space light if we're not doing transforms
00968         // Since when animating the positions are already transformed into 
00969         // world space so we need world space light position
00970         if (!hasSkeleton)
00971         {
00972             Matrix4 world2Obj = mParentNode->_getFullTransform().inverse();
00973             lightPos =  world2Obj * lightPos; 
00974         }
00975 
00976         // We need to search the edge list for silhouette edges
00977         EdgeData* edgeList = getEdgeList();
00978 
00979         if (!edgeList)
00980         {
00981             // we can't get an edge list for some reason, return blank
00982             // really we shouldn't be able to get here, but this is a safeguard
00983             return getLastShadowVolumeRenderableIterator();
00984         }
00985 
00986         // Init shadow renderable list if required
00987         bool init = mShadowRenderables.empty();
00988 
00989         EdgeData::EdgeGroupList::iterator egi;
00990         ShadowRenderableList::iterator si, siend;
00991         EntityShadowRenderable* esr = 0;
00992         if (init)
00993             mShadowRenderables.resize(edgeList->edgeGroups.size());
00994 
00995         bool updatedSharedGeomNormals = false;
00996         siend = mShadowRenderables.end();
00997         egi = edgeList->edgeGroups.begin();
00998         for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
00999         {
01000             if (init)
01001             {
01002                 const VertexData *pVertData = 0;
01003                 if (hasSkeleton)
01004                 {
01005                     // Use temp buffers
01006                     pVertData = findBlendedVertexData(egi->vertexData);
01007                 }
01008                 else
01009                 {
01010                     pVertData = egi->vertexData;
01011                 }
01012 
01013                 // Try to find corresponding SubEntity; this allows the 
01014                 // linkage of visibility between ShadowRenderable and SubEntity
01015                 SubEntity* subent = findSubEntityForVertexData(egi->vertexData);
01016                 // Create a new renderable, create a separate light cap if
01017                 // we're using a vertex program (either for this model, or
01018                 // for extruding the shadow volume) since otherwise we can 
01019                 // get depth-fighting on the light cap
01020 
01021                 *si = new EntityShadowRenderable(this, indexBuffer, pVertData, 
01022                     mVertexProgramInUse || !extrude, subent);
01023             }
01024             else if (hasSkeleton)
01025             {
01026                 // If we have a skeleton, we have no guarantee that the position
01027                 // buffer we used last frame is the same one we used last frame
01028                 // since a temporary buffer is requested each frame
01029                 // therefore, we need to update the EntityShadowRenderable
01030                 // with the current position buffer
01031                 static_cast<EntityShadowRenderable*>(*si)->rebindPositionBuffer();
01032 
01033             }
01034             // Get shadow renderable
01035             esr = static_cast<EntityShadowRenderable*>(*si);
01036             HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
01037             // For animated entities we need to recalculate the face normals
01038             if (hasSkeleton)
01039             {
01040                 if (egi->vertexData != mMesh->sharedVertexData || !updatedSharedGeomNormals)
01041                 {
01042                     // recalculate face normals
01043                     edgeList->updateFaceNormals(egi->vertexSet, esrPositionBuffer);
01044                     // If we're not extruding in software we still need to update 
01045                     // the latter part of the buffer (the hardware extruded part)
01046                     // with the latest animated positions
01047                     if (!extrude)
01048                     {
01049                         // Lock, we'll be locking the (suppressed hardware update) shadow buffer
01050                         Real* pSrc = static_cast<Real*>(
01051                             esrPositionBuffer->lock(HardwareBuffer::HBL_NORMAL));
01052                         Real* pDest = pSrc + (egi->vertexData->vertexCount * 3);
01053                         memcpy(pDest, pSrc, sizeof(Real) * 3 * egi->vertexData->vertexCount);
01054                         esrPositionBuffer->unlock();
01055                     }
01056                     if (egi->vertexData == mMesh->sharedVertexData)
01057                     {
01058                         updatedSharedGeomNormals = true;
01059                     }
01060                 }
01061             }
01062             // Extrude vertices in software if required
01063             if (extrude)
01064             {
01065                 extrudeVertices(esrPositionBuffer, 
01066                     egi->vertexData->vertexCount, 
01067                     lightPos, extrusionDistance);
01068 
01069             }
01070             // Stop suppressing hardware update now, if we were
01071             esrPositionBuffer->suppressHardwareUpdate(false);
01072 
01073         }
01074         // Calc triangle light facing
01075         updateEdgeListLightFacing(edgeList, lightPos);
01076 
01077         // Generate indexes and update renderables
01078         generateShadowVolume(edgeList, *indexBuffer, light,
01079             mShadowRenderables, flags);
01080 
01081 
01082         return getLastShadowVolumeRenderableIterator();
01083     }
01084     //-----------------------------------------------------------------------
01085     ShadowCaster::ShadowRenderableListIterator 
01086         Entity::getLastShadowVolumeRenderableIterator(void)
01087     {
01088         return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
01089     }
01090     //-----------------------------------------------------------------------
01091     const VertexData* Entity::findBlendedVertexData(const VertexData* orig)
01092     {
01093         if (orig == mMesh->sharedVertexData)
01094         {
01095             return mSharedBlendedVertexData;
01096         }
01097         SubEntityList::iterator i, iend;
01098         iend = mSubEntityList.end();
01099         for (i = mSubEntityList.begin(); i != iend; ++i)
01100         {
01101             SubEntity* se = *i;
01102             if (orig == se->getSubMesh()->vertexData)
01103             {
01104                 return se->getBlendedVertexData();
01105             }
01106         }
01107         // None found
01108         Except(Exception::ERR_ITEM_NOT_FOUND, 
01109             "Cannot find blended version of the vertex data specified.",
01110             "Entity::findBlendedVertexData");
01111     }
01112     //-----------------------------------------------------------------------
01113     SubEntity* Entity::findSubEntityForVertexData(const VertexData* orig)
01114     {
01115         if (orig == mMesh->sharedVertexData)
01116         {
01117             return 0;
01118         }
01119 
01120         SubEntityList::iterator i, iend;
01121         iend = mSubEntityList.end();
01122         for (i = mSubEntityList.begin(); i != iend; ++i)
01123         {
01124             SubEntity* se = *i;
01125             if (orig == se->getSubMesh()->vertexData)
01126             {
01127                 return se;
01128             }
01129         }
01130 
01131         // None found
01132         return 0;
01133     }
01134     //-----------------------------------------------------------------------
01135     void Entity::_notifyAttached(Node* parent, bool isTagPoint)
01136     {
01137         MovableObject::_notifyAttached(parent, isTagPoint);
01138         // Also notify LOD entities
01139         LODEntityList::iterator i, iend;
01140         iend = mLodEntityList.end();
01141         for (i = mLodEntityList.begin(); i != iend; ++i)
01142         {
01143             (*i)->_notifyAttached(parent, isTagPoint);
01144         }
01145 
01146     }
01147     //-----------------------------------------------------------------------
01148     //-----------------------------------------------------------------------
01149     Entity::EntityShadowRenderable::EntityShadowRenderable(Entity* parent, 
01150         HardwareIndexBufferSharedPtr* indexBuffer, const VertexData* vertexData,
01151         bool createSeparateLightCap, SubEntity* subent, bool isLightCap)
01152         : mParent(parent), mSubEntity(subent)
01153     {
01154         // Save link to vertex data
01155         mOriginalVertexData = vertexData;
01156 
01157         // Initialise render op
01158         mRenderOp.indexData = new IndexData();
01159         mRenderOp.indexData->indexBuffer = *indexBuffer;
01160         mRenderOp.indexData->indexStart = 0;
01161         // index start and count are sorted out later
01162 
01163         // Create vertex data which just references position component (and 2 component)
01164         mRenderOp.vertexData = new VertexData();
01165         mRenderOp.vertexData->vertexDeclaration = 
01166             HardwareBufferManager::getSingleton().createVertexDeclaration();
01167         mRenderOp.vertexData->vertexBufferBinding = 
01168             HardwareBufferManager::getSingleton().createVertexBufferBinding();
01169         // Map in position data
01170         mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
01171         mOriginalPosBufferBinding = 
01172             vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
01173         mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(mOriginalPosBufferBinding);
01174         mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
01175         // Map in w-coord buffer (if present)
01176         if(!vertexData->hardwareShadowVolWBuffer.isNull())
01177         {
01178             mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
01179             mWBuffer = vertexData->hardwareShadowVolWBuffer;
01180             mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
01181         }
01182         // Use same vertex start as input
01183         mRenderOp.vertexData->vertexStart = vertexData->vertexStart;
01184 
01185         if (isLightCap)
01186         {
01187             // Use original vertex count, no extrusion
01188             mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
01189         }
01190         else
01191         {
01192             // Vertex count must take into account the doubling of the buffer,
01193             // because second half of the buffer is the extruded copy
01194             mRenderOp.vertexData->vertexCount = 
01195                 vertexData->vertexCount * 2;
01196             if (createSeparateLightCap)
01197             {
01198                 // Create child light cap
01199                 mLightCap = new EntityShadowRenderable(parent, 
01200                     indexBuffer, vertexData, false, subent, true);
01201             }
01202         }
01203 
01204     }
01205     //-----------------------------------------------------------------------
01206     Entity::EntityShadowRenderable::~EntityShadowRenderable()
01207     {
01208         delete mRenderOp.indexData;
01209         delete mRenderOp.vertexData;
01210     }
01211     //-----------------------------------------------------------------------
01212     void Entity::EntityShadowRenderable::getWorldTransforms(Matrix4* xform) const
01213     {
01214         unsigned short numBones = mParent->_getNumBoneMatrices();
01215 
01216         if (!numBones)
01217         {
01218             *xform = mParent->_getParentNodeFullTransform();
01219         }
01220         else
01221         {
01222             // pretransformed
01223             *xform = Matrix4::IDENTITY;
01224         }
01225     }
01226     //-----------------------------------------------------------------------
01227     const Quaternion& Entity::EntityShadowRenderable::getWorldOrientation(void) const
01228     {
01229         return mParent->getParentNode()->_getDerivedOrientation();
01230     }
01231     //-----------------------------------------------------------------------
01232     const Vector3& Entity::EntityShadowRenderable::getWorldPosition(void) const
01233     {
01234         return mParent->getParentNode()->_getDerivedPosition();
01235     }
01236     //-----------------------------------------------------------------------
01237     void Entity::EntityShadowRenderable::rebindPositionBuffer(void)
01238     {
01239         mPositionBuffer = mOriginalVertexData->vertexBufferBinding->getBuffer(
01240             mOriginalPosBufferBinding);
01241         mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
01242         if (mLightCap)
01243         {
01244             static_cast<EntityShadowRenderable*>(mLightCap)->rebindPositionBuffer();
01245         }
01246 
01247     }
01248     //-----------------------------------------------------------------------
01249     bool Entity::EntityShadowRenderable::isVisible(void) const
01250     {
01251         if (mSubEntity)
01252         {
01253             return mSubEntity->isVisible();
01254         }
01255         else
01256         {
01257             return ShadowRenderable::isVisible();
01258         }
01259     }
01260     //-----------------------------------------------------------------------
01261     void Entity::setRenderQueueGroup(RenderQueueGroupID queueID)
01262     {
01263         MovableObject::setRenderQueueGroup(queueID);
01264 
01265         // Set render queue for all manual LOD entities
01266         if (mMesh->isLodManual())
01267         {
01268             LODEntityList::iterator li, liend;
01269             liend = mLodEntityList.end();
01270             for (li = mLodEntityList.begin(); li != liend; ++li)
01271             {
01272                 (*li)->setRenderQueueGroup(queueID);
01273             }
01274         }
01275     }
01276     //-----------------------------------------------------------------------
01277     void Entity::shareSkeletonInstanceWith(Entity* entity)
01278     {
01279         if (entity->getMesh()->getSkeleton() != getMesh()->getSkeleton()) 
01280         {
01281             Except(Exception::ERR_RT_ASSERTION_FAILED, 
01282                 "The supplied entity has a different skeleton.",
01283                 "Entity::shareSkeletonWith");   
01284         }
01285         if (!mSkeletonInstance)
01286         {
01287             Except(Exception::ERR_RT_ASSERTION_FAILED, 
01288                 "This entity has no skeleton.",
01289                 "Entity::shareSkeletonWith");   
01290         }   
01291         if (mSharedSkeletonEntities != NULL && entity->mSharedSkeletonEntities != NULL) 
01292         {
01293             Except(Exception::ERR_RT_ASSERTION_FAILED, 
01294                 "Both entities already shares their SkeletonInstances! At least "
01295                 "one of the instances must not share it's instance.",
01296                 "Entity::shareSkeletonWith");   
01297         }   
01298 
01299         //check if we already share our skeletoninstance, we don't want to delete it if so
01300         if (mSharedSkeletonEntities != NULL) 
01301         {
01302             entity->shareSkeletonInstanceWith(this);
01303         }
01304         else 
01305         {
01306             delete mSkeletonInstance;
01307             delete mBoneMatrices;
01308             delete mAnimationState;
01309             delete mFrameBonesLastUpdated;
01310             mSkeletonInstance = entity->mSkeletonInstance;
01311             mNumBoneMatrices = entity->mNumBoneMatrices;
01312             mBoneMatrices = entity->mBoneMatrices;
01313             mAnimationState = entity->mAnimationState;
01314             mFrameBonesLastUpdated = entity->mFrameBonesLastUpdated;
01315             if (entity->mSharedSkeletonEntities == NULL) 
01316             {
01317                 entity->mSharedSkeletonEntities = new EntitySet();
01318                 entity->mSharedSkeletonEntities->insert(entity);
01319             }
01320             mSharedSkeletonEntities = entity->mSharedSkeletonEntities;
01321             mSharedSkeletonEntities->insert(this);
01322         }
01323     }    
01324     //-----------------------------------------------------------------------
01325     void Entity::stopSharingSkeletonInstance()
01326     {
01327         if (mSharedSkeletonEntities == NULL) 
01328         {
01329             Except(Exception::ERR_RT_ASSERTION_FAILED, 
01330                 "This entity is not sharing it's skeletoninstance.",
01331                 "Entity::shareSkeletonWith");   
01332         }   
01333         //check if there's no other than us sharing the skeleton instance
01334         if (mSharedSkeletonEntities->size() == 1) 
01335         {
01336             //just reset
01337             delete mSharedSkeletonEntities;
01338             mSharedSkeletonEntities = 0;
01339         }
01340         else 
01341         {
01342             //do some cloning
01343             /*          mSkeletonInstance = new SkeletonInstance(*mSkeletonInstance);
01344             mBoneMatrices = new Matrix4(*mBoneMatrices);
01345             mAnimationState = new AnimationStateSet(*mAnimationState);
01346             mFrameBonesLastUpdated = new unsigned long(*mFrameBonesLastUpdated);
01347             */
01348 
01349             mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
01350             mSkeletonInstance->load();
01351             mAnimationState = new AnimationStateSet();
01352             mMesh->_initAnimationState(mAnimationState);
01353             mNumBoneMatrices = mSkeletonInstance->getNumBones();
01354             mBoneMatrices = new Matrix4[mNumBoneMatrices];
01355             prepareTempBlendBuffers();
01356             mFrameBonesLastUpdated = new unsigned long;
01357 
01358             mSharedSkeletonEntities->erase(this);
01359             if (mSharedSkeletonEntities->size() == 1) 
01360             {
01361                 (*mSharedSkeletonEntities->begin())->stopSharingSkeletonInstance();
01362             }
01363             mSharedSkeletonEntities = 0;
01364         }
01365     }
01366     //-----------------------------------------------------------------------
01367 
01368 }

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:23 2004