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 
00040 namespace Ogre {
00041     String Entity::msMovableType = "Entity";
00042     //-----------------------------------------------------------------------
00043     Entity::Entity () 
00044     {
00045         mFullBoundingBox = new AxisAlignedBox;
00046         mNormaliseNormals = false;
00047     }
00048     //-----------------------------------------------------------------------
00049     Entity::Entity( const String& name, Mesh* mesh, SceneManager* creator) :
00050         mName(name),
00051         mMesh(mesh),
00052         mCreatorSceneManager(creator)
00053     {
00054         mFullBoundingBox = new AxisAlignedBox;
00055     
00056         // Build main subentity list
00057         buildSubEntityList(mesh, &mSubEntityList);
00058 
00059         // Check if mesh is using manual LOD
00060         if (mesh->isLodManual())
00061         {
00062             ushort i, numLod;
00063             numLod = mesh->getNumLodLevels();
00064             // NB skip LOD 0 which is the original
00065             for (i = 1; i < numLod; ++i)
00066             {
00067                 SubEntityList* sublist = new SubEntityList();
00068                 const Mesh::MeshLodUsage& usage = mesh->getLodLevel(i);
00069                 buildSubEntityList(usage.manualMesh, sublist);
00070                 mLodSubEntityList.push_back(sublist);
00071             }
00072 
00073         }
00074 
00075 
00076         // Initialise the AnimationState, if Mesh has animation
00077         if (mesh->hasSkeleton())
00078         {
00079             mesh->_initAnimationState(&mAnimationState);
00080             mNumBoneMatrices = mesh->_getNumBoneMatrices();
00081             mBoneMatrices = new Matrix4[mNumBoneMatrices];
00082         }
00083         else
00084         {
00085             mBoneMatrices = 0;
00086             mNumBoneMatrices = 0;
00087         }
00088 
00089         mDisplaySkeleton = false;
00090 
00091         mMeshLodFactorInv = 1.0f;
00092         mMeshLodIndex = 0;
00093         mMaxMeshLodIndex = 0;       // Backwards, remember low value = high detail
00094         mMinMeshLodIndex = 99;
00095 
00096         mMaterialLodFactorInv = 1.0f;
00097         mMaxMaterialLodIndex = 0;       // Backwards, remember low value = high detail
00098         mMinMaterialLodIndex = 99;
00099 
00100 
00101     }
00102     //-----------------------------------------------------------------------
00103     Entity::~Entity()
00104     {
00105         // Delete submeshes
00106         SubEntityList::iterator i, iend;
00107         iend = mSubEntityList.end();
00108         for (i = mSubEntityList.begin(); i != iend; ++i)
00109         {
00110             // Delete SubEntity
00111             delete *i;
00112         }
00113         // Delete LOD submeshes
00114         LODSubEntityList::iterator li, liend;
00115         liend = mLodSubEntityList.end();
00116         for (li = mLodSubEntityList.begin(); li != liend; ++li)
00117         {
00118             iend = (*li)->end();
00119             for (i = (*li)->begin(); i != iend; ++i)
00120             {
00121                 // Delete SubEntity
00122                 delete *i;
00123             }
00124             // Delete SubMeshList itself
00125             delete (*li);
00126 
00127         }
00128         if (mBoneMatrices)
00129             delete [] mBoneMatrices;
00130 
00131         delete mFullBoundingBox;
00132     }
00133     //-----------------------------------------------------------------------
00134     Mesh* Entity::getMesh(void)
00135     {
00136         return mMesh;
00137     }
00138     //-----------------------------------------------------------------------
00139     const String& Entity::getName(void) const
00140     {
00141         return mName;
00142     }
00143     //-----------------------------------------------------------------------
00144     SubEntity* Entity::getSubEntity(unsigned int index)
00145     {
00146         if (index >= mSubEntityList.size())
00147             Except(Exception::ERR_INVALIDPARAMS,
00148                 "Index out of bounds.",
00149                 "Entity::getSubEntity");
00150         return mSubEntityList[index];
00151     }
00152     //-----------------------------------------------------------------------
00153     SubEntity* Entity::getSubEntity(const String& name)
00154     {
00155         ushort index = mMesh->_getSubMeshIndex(name);
00156         return getSubEntity(index);
00157     }
00158     //-----------------------------------------------------------------------
00159     unsigned int Entity::getNumSubEntities(void) const
00160     {
00161         return static_cast< unsigned int >( mSubEntityList.size() );
00162     }
00163     //-----------------------------------------------------------------------
00164     Entity* Entity::clone( const String& newName)
00165     {
00166         Entity* newEnt;
00167         newEnt = mCreatorSceneManager->createEntity( newName, getMesh()->getName() );
00168         // Copy material settings
00169         SubEntityList::iterator i;
00170         unsigned int n = 0;
00171         for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i, ++n)
00172         {
00173             newEnt->getSubEntity(n)->setMaterialName((*i)->getMaterialName());
00174         }
00175         newEnt->mAnimationState = mAnimationState;
00176         return newEnt;
00177     }
00178     //-----------------------------------------------------------------------
00179     void Entity::setMaterialName(const String& name)
00180     {
00181         // Set for all subentities
00182         SubEntityList::iterator i;
00183         for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
00184         {
00185             (*i)->setMaterialName(name);
00186         }
00187 
00188     }
00189     //-----------------------------------------------------------------------
00190     void Entity::_notifyCurrentCamera(Camera* cam)
00191     {
00192         // Calculate the LOD
00193         if (mParentNode)
00194         {
00195             Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
00196 
00197             // Do Mesh LOD
00198             // Adjust this depth by the entity bias factor
00199             Real tmp = squaredDepth * mMeshLodFactorInv;
00200             // Now adjust it by the camera bias
00201             tmp = tmp * cam->_getLodBiasInverse();
00202             // Get the index at this biased depth
00203             mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp);
00204             // Apply maximum detail restriction (remember lower = higher detail)
00205             mMeshLodIndex = std::max(mMaxMeshLodIndex, mMeshLodIndex);
00206             // Apply minimum detail restriction (remember higher = lower detail)
00207             mMeshLodIndex = std::min(mMinMeshLodIndex, mMeshLodIndex);
00208             
00209             // Now do material LOD
00210             // Adjust this depth by the entity bias factor
00211             tmp = squaredDepth * mMaterialLodFactorInv;
00212             // Now adjust it by the camera bias
00213             tmp = tmp * cam->_getLodBiasInverse();
00214             SubEntityList::iterator i, iend;
00215             iend = mSubEntityList.end();
00216             for (i = mSubEntityList.begin(); i != iend; ++i)
00217             {
00218                 // Get the index at this biased depth
00219                 unsigned short idx = (*i)->mpMaterial->getLodIndexSquaredDepth(tmp);
00220                 // Apply maximum detail restriction (remember lower = higher detail)
00221                 idx = std::max(mMaxMaterialLodIndex, idx);
00222                 // Apply minimum detail restriction (remember higher = lower detail)
00223                 (*i)->mMaterialLodIndex = std::min(mMinMaterialLodIndex, idx);
00224             }
00225 
00226 
00227         }
00228         // Notify any child objects
00229         ChildObjectList::iterator child_itr = mChildObjectList.begin();
00230         ChildObjectList::iterator child_itr_end = mChildObjectList.end();
00231         for( ; child_itr != child_itr_end; child_itr++)
00232         {
00233             (*child_itr).second->_notifyCurrentCamera(cam);
00234         }
00235 
00236 
00237     }
00238     //-----------------------------------------------------------------------
00239     const AxisAlignedBox& Entity::getBoundingBox(void) const
00240     {
00241         // Get from Mesh
00242         *mFullBoundingBox = mMesh->getBounds();
00243         mFullBoundingBox->merge(getChildObjectsBoundingBox());
00244 
00245         // Scale
00246         if (mParentNode)
00247         {
00248             mFullBoundingBox->scale(mParentNode->_getDerivedScale());
00249         }
00250 
00251         return *mFullBoundingBox;
00252     }
00253     //-----------------------------------------------------------------------
00254     AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const
00255     {
00256         AxisAlignedBox aa_box;
00257         AxisAlignedBox full_aa_box;
00258         full_aa_box.setNull();
00259         
00260         ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
00261         ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
00262         for( ; child_itr != child_itr_end; child_itr++)
00263         {
00264             aa_box = child_itr->second->getBoundingBox();
00265             TagPoint* tp = (TagPoint*)child_itr->second->getParentNode();
00266             // Use transform local to skeleton since world xform comes later
00267             aa_box.transform(tp->_getFullLocalTransform());
00268             
00269             full_aa_box.merge(aa_box);
00270         }
00271 
00272         return full_aa_box;
00273     }
00274     //-----------------------------------------------------------------------
00275     void Entity::_updateRenderQueue(RenderQueue* queue)
00276     {
00277         SubEntityList* subEntList;
00278         // Check we're not using a manual LOD
00279         if (mMeshLodIndex > 0 && mMesh->isLodManual())
00280         {
00281             // Use alternate subentities
00282             assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodSubEntityList.size() && 
00283                 "No LOD SubEntityList - did you build the manual LODs after creating the entity?");
00284             // index - 1 as we skip index 0 (original lod)
00285             subEntList = mLodSubEntityList[mMeshLodIndex - 1];
00286         }
00287         else
00288         {
00289             subEntList = &mSubEntityList;
00290         }
00291 
00292         // Add each SubEntity to the queue
00293         SubEntityList::iterator i, iend;
00294         iend = subEntList->end();
00295         for (i = subEntList->begin(); i != iend; ++i)
00296         {
00297             queue->addRenderable(*i, mRenderQueueID, RENDERABLE_DEFAULT_PRIORITY);
00298         }
00299 
00300         // Since we know we're going to be rendered, take this opportunity to 
00301         // cache bone matrices & apply world matrix to them
00302         if (mMesh->hasSkeleton())
00303         {
00304             cacheBoneMatrices();
00305             
00306             //--- pass this point,  we are sure that the transformation matrix of each bone and tagPoint have been updated          
00307             ChildObjectList::iterator child_itr = mChildObjectList.begin();
00308             ChildObjectList::iterator child_itr_end = mChildObjectList.end();
00309             for( ; child_itr != child_itr_end; child_itr++)
00310             {
00311                 (*child_itr).second->_updateRenderQueue(queue);
00312             }
00313         }
00314 
00315         // HACK to display bones
00316         // This won't work if the entity is not centered at the origin
00317         // TODO work out a way to allow bones to be rendered when Entity not centered
00318         if (mDisplaySkeleton && mMesh->hasSkeleton())
00319         {
00320             Skeleton* pSkel = mMesh->getSkeleton();
00321             int numBones = pSkel->getNumBones();
00322             for (int b = 0; b < numBones; ++b)
00323             {
00324                 Bone* bone = pSkel->getBone(b);
00325                 queue->addRenderable(bone, mRenderQueueID);
00326             }
00327         }
00328 
00329 
00330 
00331 
00332     }
00333     //-----------------------------------------------------------------------
00334     AnimationState* Entity::getAnimationState(const String& name)
00335     {
00336         AnimationStateSet::iterator i = mAnimationState.find(name);
00337 
00338         if (i == mAnimationState.end())
00339         {
00340             Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 
00341             "Entity::getAnimationState");
00342         }
00343 
00344         return &(i->second);
00345     }
00346     //-----------------------------------------------------------------------
00347     AnimationStateSet* Entity::getAllAnimationStates(void)
00348     {
00349         return &mAnimationState;
00350     }
00351     //-----------------------------------------------------------------------
00352     const String& Entity::getMovableType(void) const
00353     {
00354         return msMovableType;
00355     }
00356     //-----------------------------------------------------------------------
00357     void Entity::cacheBoneMatrices(void)
00358     {
00359         // Get the appropriate meshes skeleton here
00360         // Can use lower LOD mesh skeleton if mesh LOD is manual
00361         // We make the assumption that lower LOD meshes will have
00362         //   fewer bones than the full LOD, therefore marix stack will be
00363         //   big enough.
00364         Mesh* theMesh;
00365         if (mMesh->isLodManual() && mMeshLodIndex > 1)
00366         {
00367             // Use lower detail skeleton
00368             theMesh = mMesh->getLodLevel(mMeshLodIndex).manualMesh;
00369             // Lower detail may not have skeleton
00370             if (!theMesh->hasSkeleton())
00371             {
00372                 mNumBoneMatrices = 0;
00373                 return;
00374             }
00375         }
00376         else
00377         {
00378             // Use normal mesh
00379             theMesh = mMesh;
00380         }
00381     
00382         // Tell the skeleton who's making a call to update him
00383         theMesh->getSkeleton()->setCurrentEntity(this);
00384 
00385         theMesh->_getBoneMatrices(mAnimationState, mBoneMatrices);
00386         // Reset the skeleton to 'no caller'
00387         theMesh->getSkeleton()->setCurrentEntity(0);
00388         
00389         // Apply our current world transform to these too, since these are used as
00390         // replacement world matrices
00391         unsigned short i;
00392         Matrix4 worldXform = _getParentNodeFullTransform();
00393         mNumBoneMatrices = theMesh->_getNumBoneMatrices();
00394 
00395         for (i = 0; i < mNumBoneMatrices; ++i)
00396         {
00397             mBoneMatrices[i] = worldXform * mBoneMatrices[i];
00398         }
00399 
00400     }
00401     //-----------------------------------------------------------------------
00402     void Entity::setDisplaySkeleton(bool display)
00403     {
00404         mDisplaySkeleton = display;
00405     }
00406     //-----------------------------------------------------------------------
00407     void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
00408     {
00409         assert(factor > 0.0f && "Bias factor must be > 0!");
00410         mMeshLodFactorInv = 1.0f / factor;
00411         mMaxMeshLodIndex = maxDetailIndex;
00412         mMinMeshLodIndex = minDetailIndex;
00413 
00414     }
00415     //-----------------------------------------------------------------------
00416     void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
00417     {
00418         assert(factor > 0.0f && "Bias factor must be > 0!");
00419         mMaterialLodFactorInv = 1.0f / factor;
00420         mMaxMaterialLodIndex = maxDetailIndex;
00421         mMinMaterialLodIndex = minDetailIndex;
00422 
00423     }
00424     //-----------------------------------------------------------------------
00425     void Entity::buildSubEntityList(Mesh* mesh, SubEntityList* sublist)
00426     {
00427         // Create SubEntities
00428         unsigned short i, numSubMeshes;
00429         SubMesh* subMesh;
00430         SubEntity* subEnt;
00431 
00432         numSubMeshes = mesh->getNumSubMeshes();
00433         for (i = 0; i < numSubMeshes; ++i)
00434         {
00435             subMesh = mesh->getSubMesh(i);
00436             subEnt = new SubEntity();
00437             subEnt->mParentEntity = this;
00438             subEnt->mSubMesh = subMesh;
00439             if (subMesh->isMatInitialised())
00440                 subEnt->setMaterialName(subMesh->getMaterialName());
00441             sublist->push_back(subEnt);
00442         }
00443     }
00444     //-----------------------------------------------------------------------
00445     void Entity::setRenderDetail(SceneDetailLevel renderDetail) 
00446     {
00447         SubEntityList::iterator i, iend;
00448         iend = mSubEntityList.end();
00449 
00450         for( i = mSubEntityList.begin(); i != iend; ++i ) 
00451         { 
00452             (*i)->setRenderDetail(renderDetail); 
00453         } 
00454     }
00455 
00456     //-----------------------------------------------------------------------
00457     void Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
00458     {
00459         if(pMovable->isAttached())
00460         {
00461             Except(Exception::ERR_INVALIDPARAMS, "Object already attached to a sceneNode or a Bone", 
00462             "Entity::attachObjectToBone");
00463         }
00464         if (!mMesh->hasSkeleton())
00465         {
00466             Except(Exception::ERR_INVALIDPARAMS, "This entity's mesh has no skeleton to attach object to.", 
00467             "Entity::attachObjectToBone");
00468         }
00469         Bone* bone = mMesh->getSkeleton()->getBone(boneName);
00470         if (!bone)
00471         {
00472             Except(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName, 
00473             "Entity::attachObjectToBone");
00474         }
00475 
00476         TagPoint *tp = bone->createChildTagPoint(offsetOrientation, offsetPosition);
00477         tp->setParentEntity(this);
00478         tp->setChildObject(pMovable);
00479         
00480         attachObjectImpl(pMovable, tp);
00481     }
00482 
00483     //-----------------------------------------------------------------------
00484     void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint)
00485     {
00486         mChildObjectList[pObject->getName()] = pObject;
00487         pObject->_notifyAttached(pAttachingPoint, true);
00488     }
00489 
00490     //-----------------------------------------------------------------------
00491     MovableObject* Entity::detachObjectFromBone(const String &name)
00492     {
00493         ChildObjectList::iterator i = mChildObjectList.find(name);
00494 
00495         if (i == mChildObjectList.end())
00496         {
00497             Except(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name, 
00498             "Entity::detachObjectFromBone");
00499         }
00500 
00501         i->second->_notifyAttached((TagPoint*)0);
00502         mChildObjectList.erase(i);
00503         return i->second;
00504     }
00505     //-----------------------------------------------------------------------
00506     Entity::ChildObjectListIterator Entity::getAttachedObjectIterator()
00507     {
00508         return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end());
00509     }
00510     //-----------------------------------------------------------------------
00511     Real Entity::getBoundingRadius(void) const
00512     {
00513         Real rad = mMesh->getBoundingSphereRadius();
00514         // Scale by largest scale factor
00515         if (mParentNode)
00516         {
00517             const Vector3& s = mParentNode->_getDerivedScale();
00518             rad *= std::max(s.x, std::max(s.y, s.z));
00519         }
00520         return rad;
00521     }
00522 
00523 }

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:10 2004