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