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