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 mFrameAnimationLastUpdated = 0; 00056 mHardwareSkinning = false; 00057 mSkeletonInstance = 0; 00058 } 00059 //----------------------------------------------------------------------- 00060 Entity::Entity( const String& name, Mesh* mesh, SceneManager* creator) : 00061 mName(name), 00062 mMesh(mesh), 00063 mCreatorSceneManager(creator) 00064 { 00065 mFullBoundingBox = new AxisAlignedBox; 00066 mHardwareSkinning = false; 00067 mSharedBlendedVertexData = NULL; 00068 00069 // Is mesh skeletally animated? 00070 if (mMesh->hasSkeleton() && mMesh->getSkeleton() != NULL) 00071 { 00072 mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton()); 00073 mSkeletonInstance->load(); 00074 } 00075 else 00076 { 00077 mSkeletonInstance = 0; 00078 } 00079 00080 // Build main subentity list 00081 buildSubEntityList(mesh, &mSubEntityList); 00082 00083 // Check if mesh is using manual LOD 00084 if (mesh->isLodManual()) 00085 { 00086 ushort i, numLod; 00087 numLod = mesh->getNumLodLevels(); 00088 // NB skip LOD 0 which is the original 00089 for (i = 1; i < numLod; ++i) 00090 { 00091 SubEntityList* sublist = new SubEntityList(); 00092 const Mesh::MeshLodUsage& usage = mesh->getLodLevel(i); 00093 // Manually create entity 00094 Entity* lodEnt = new Entity(name + "Lod" + StringConverter::toString(i), 00095 usage.manualMesh, mCreatorSceneManager); 00096 mLodEntityList.push_back(lodEnt); 00097 } 00098 00099 } 00100 00101 00102 // Initialise the AnimationState, if Mesh has animation 00103 if (hasSkeleton()) 00104 { 00105 mesh->_initAnimationState(&mAnimationState); 00106 mNumBoneMatrices = mSkeletonInstance->getNumBones(); 00107 mBoneMatrices = new Matrix4[mNumBoneMatrices]; 00108 prepareTempBlendBuffers(); 00109 } 00110 else 00111 { 00112 mBoneMatrices = 0; 00113 mNumBoneMatrices = 0; 00114 } 00115 00116 reevaluateVertexProcessing(); 00117 00118 mDisplaySkeleton = false; 00119 00120 mMeshLodFactorInv = 1.0f; 00121 mMeshLodIndex = 0; 00122 mMaxMeshLodIndex = 0; // Backwards, remember low value = high detail 00123 mMinMeshLodIndex = 99; 00124 00125 mMaterialLodFactorInv = 1.0f; 00126 mMaxMaterialLodIndex = 0; // Backwards, remember low value = high detail 00127 mMinMaterialLodIndex = 99; 00128 00129 00130 mFrameAnimationLastUpdated = 0; 00131 } 00132 //----------------------------------------------------------------------- 00133 Entity::~Entity() 00134 { 00135 // Delete submeshes 00136 SubEntityList::iterator i, iend; 00137 iend = mSubEntityList.end(); 00138 for (i = mSubEntityList.begin(); i != iend; ++i) 00139 { 00140 // Delete SubEntity 00141 delete *i; 00142 } 00143 // Delete LOD entities 00144 LODEntityList::iterator li, liend; 00145 liend = mLodEntityList.end(); 00146 for (li = mLodEntityList.begin(); li != liend; ++li) 00147 { 00148 // Delete 00149 delete (*li); 00150 } 00151 if (mBoneMatrices) 00152 delete [] mBoneMatrices; 00153 00154 delete mFullBoundingBox; 00155 00156 // Delete shadow renderables 00157 ShadowRenderableList::iterator si, siend; 00158 siend = mShadowRenderables.end(); 00159 for (si = mShadowRenderables.begin(); si != siend; ++si) 00160 { 00161 delete *si; 00162 } 00163 // Delete skeleton instance 00164 if (mSkeletonInstance) 00165 delete mSkeletonInstance; 00166 } 00167 //----------------------------------------------------------------------- 00168 Mesh* Entity::getMesh(void) 00169 { 00170 return mMesh; 00171 } 00172 //----------------------------------------------------------------------- 00173 const String& Entity::getName(void) const 00174 { 00175 return mName; 00176 } 00177 //----------------------------------------------------------------------- 00178 SubEntity* Entity::getSubEntity(unsigned int index) 00179 { 00180 if (index >= mSubEntityList.size()) 00181 Except(Exception::ERR_INVALIDPARAMS, 00182 "Index out of bounds.", 00183 "Entity::getSubEntity"); 00184 return mSubEntityList[index]; 00185 } 00186 //----------------------------------------------------------------------- 00187 SubEntity* Entity::getSubEntity(const String& name) 00188 { 00189 ushort index = mMesh->_getSubMeshIndex(name); 00190 return getSubEntity(index); 00191 } 00192 //----------------------------------------------------------------------- 00193 unsigned int Entity::getNumSubEntities(void) const 00194 { 00195 return static_cast< unsigned int >( mSubEntityList.size() ); 00196 } 00197 //----------------------------------------------------------------------- 00198 Entity* Entity::clone( const String& newName) 00199 { 00200 Entity* newEnt; 00201 newEnt = mCreatorSceneManager->createEntity( newName, getMesh()->getName() ); 00202 // Copy material settings 00203 SubEntityList::iterator i; 00204 unsigned int n = 0; 00205 for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i, ++n) 00206 { 00207 newEnt->getSubEntity(n)->setMaterialName((*i)->getMaterialName()); 00208 } 00209 newEnt->mAnimationState = mAnimationState; 00210 return newEnt; 00211 } 00212 //----------------------------------------------------------------------- 00213 void Entity::setMaterialName(const String& name) 00214 { 00215 // Set for all subentities 00216 SubEntityList::iterator i; 00217 for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i) 00218 { 00219 (*i)->setMaterialName(name); 00220 } 00221 00222 } 00223 //----------------------------------------------------------------------- 00224 void Entity::_notifyCurrentCamera(Camera* cam) 00225 { 00226 // Calculate the LOD 00227 if (mParentNode) 00228 { 00229 Real squaredDepth = mParentNode->getSquaredViewDepth(cam); 00230 00231 // Do Mesh LOD 00232 // Adjust this depth by the entity bias factor 00233 Real tmp = squaredDepth * mMeshLodFactorInv; 00234 // Now adjust it by the camera bias 00235 tmp = tmp * cam->_getLodBiasInverse(); 00236 // Get the index at this biased depth 00237 mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp); 00238 // Apply maximum detail restriction (remember lower = higher detail) 00239 mMeshLodIndex = std::max(mMaxMeshLodIndex, mMeshLodIndex); 00240 // Apply minimum detail restriction (remember higher = lower detail) 00241 mMeshLodIndex = std::min(mMinMeshLodIndex, mMeshLodIndex); 00242 00243 // Now do material LOD 00244 // Adjust this depth by the entity bias factor 00245 tmp = squaredDepth * mMaterialLodFactorInv; 00246 // Now adjust it by the camera bias 00247 tmp = tmp * cam->_getLodBiasInverse(); 00248 SubEntityList::iterator i, iend; 00249 iend = mSubEntityList.end(); 00250 for (i = mSubEntityList.begin(); i != iend; ++i) 00251 { 00252 // Get the index at this biased depth 00253 unsigned short idx = (*i)->mpMaterial->getLodIndexSquaredDepth(tmp); 00254 // Apply maximum detail restriction (remember lower = higher detail) 00255 idx = std::max(mMaxMaterialLodIndex, idx); 00256 // Apply minimum detail restriction (remember higher = lower detail) 00257 (*i)->mMaterialLodIndex = std::min(mMinMaterialLodIndex, idx); 00258 } 00259 00260 00261 } 00262 // Notify any child objects 00263 ChildObjectList::iterator child_itr = mChildObjectList.begin(); 00264 ChildObjectList::iterator child_itr_end = mChildObjectList.end(); 00265 for( ; child_itr != child_itr_end; child_itr++) 00266 { 00267 (*child_itr).second->_notifyCurrentCamera(cam); 00268 } 00269 00270 00271 } 00272 //----------------------------------------------------------------------- 00273 const AxisAlignedBox& Entity::getBoundingBox(void) const 00274 { 00275 // Get from Mesh 00276 *mFullBoundingBox = mMesh->getBounds(); 00277 mFullBoundingBox->merge(getChildObjectsBoundingBox()); 00278 00279 // Don't scale here, this is taken into account when world BBox calculation is done 00280 00281 return *mFullBoundingBox; 00282 } 00283 //----------------------------------------------------------------------- 00284 AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const 00285 { 00286 AxisAlignedBox aa_box; 00287 AxisAlignedBox full_aa_box; 00288 full_aa_box.setNull(); 00289 00290 ChildObjectList::const_iterator child_itr = mChildObjectList.begin(); 00291 ChildObjectList::const_iterator child_itr_end = mChildObjectList.end(); 00292 for( ; child_itr != child_itr_end; child_itr++) 00293 { 00294 aa_box = child_itr->second->getBoundingBox(); 00295 TagPoint* tp = (TagPoint*)child_itr->second->getParentNode(); 00296 // Use transform local to skeleton since world xform comes later 00297 aa_box.transform(tp->_getFullLocalTransform()); 00298 00299 full_aa_box.merge(aa_box); 00300 } 00301 00302 return full_aa_box; 00303 } 00304 //----------------------------------------------------------------------- 00305 void Entity::_updateRenderQueue(RenderQueue* queue) 00306 { 00307 // Check we're not using a manual LOD 00308 if (mMeshLodIndex > 0 && mMesh->isLodManual()) 00309 { 00310 // Use alternate entity 00311 assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() && 00312 "No LOD EntityList - did you build the manual LODs after creating the entity?"); 00313 // index - 1 as we skip index 0 (original lod) 00314 mLodEntityList[mMeshLodIndex - 1]->_updateRenderQueue(queue); 00315 return; 00316 } 00317 00318 // Add each visible SubEntity to the queue 00319 SubEntityList::iterator i, iend; 00320 iend = mSubEntityList.end(); 00321 for (i = mSubEntityList.begin(); i != iend; ++i) 00322 { 00323 if((*i)->isVisible()) 00324 queue->addRenderable(*i, mRenderQueueID, RENDERABLE_DEFAULT_PRIORITY); 00325 } 00326 00327 // Since we know we're going to be rendered, take this opportunity to 00328 // update the animation 00329 if (hasSkeleton()) 00330 { 00331 updateAnimation(); 00332 00333 //--- pass this point, we are sure that the transformation matrix of each bone and tagPoint have been updated 00334 ChildObjectList::iterator child_itr = mChildObjectList.begin(); 00335 ChildObjectList::iterator child_itr_end = mChildObjectList.end(); 00336 for( ; child_itr != child_itr_end; child_itr++) 00337 { 00338 (*child_itr).second->_updateRenderQueue(queue); 00339 } 00340 } 00341 00342 // HACK to display bones 00343 // This won't work if the entity is not centered at the origin 00344 // TODO work out a way to allow bones to be rendered when Entity not centered 00345 if (mDisplaySkeleton && hasSkeleton()) 00346 { 00347 int numBones = mSkeletonInstance->getNumBones(); 00348 for (int b = 0; b < numBones; ++b) 00349 { 00350 Bone* bone = mSkeletonInstance->getBone(b); 00351 queue->addRenderable(bone, mRenderQueueID); 00352 } 00353 } 00354 00355 00356 00357 00358 } 00359 //----------------------------------------------------------------------- 00360 AnimationState* Entity::getAnimationState(const String& name) 00361 { 00362 AnimationStateSet::iterator i = mAnimationState.find(name); 00363 00364 if (i == mAnimationState.end()) 00365 { 00366 Except(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 00367 "Entity::getAnimationState"); 00368 } 00369 00370 return &(i->second); 00371 } 00372 //----------------------------------------------------------------------- 00373 AnimationStateSet* Entity::getAllAnimationStates(void) 00374 { 00375 return &mAnimationState; 00376 } 00377 //----------------------------------------------------------------------- 00378 const String& Entity::getMovableType(void) const 00379 { 00380 return msMovableType; 00381 } 00382 //----------------------------------------------------------------------- 00383 void Entity::updateAnimation(void) 00384 { 00385 // We only do these tasks if they have not already been done for 00386 // this frame 00387 Root& root = Root::getSingleton(); 00388 unsigned long currentFrameNumber = root.getCurrentFrameNumber(); 00389 if (mFrameAnimationLastUpdated != currentFrameNumber) 00390 { 00391 cacheBoneMatrices(); 00392 00393 // Software blend? 00394 bool hwSkinning = isHardwareSkinningEnabled(); 00395 if (!hwSkinning || 00396 root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_ADDITIVE || 00397 root._getCurrentSceneManager()->getShadowTechnique() == SHADOWTYPE_STENCIL_MODULATIVE) 00398 { 00399 // Ok, we need to do a software blend 00400 // Blend normals in s/w only if we're not using h/w skinning, 00401 // since shadows only require positions 00402 bool blendNormals = !hwSkinning; 00403 // Firstly, check out working vertex buffers 00404 if (mSharedBlendedVertexData) 00405 { 00406 // Blend shared geometry 00407 // NB we suppress hardware upload while doing blend if we're 00408 // hardware skinned, because the only reason for doing this 00409 // is for shadow, which need only be uploaded then 00410 mTempBlendedBuffer.checkoutTempCopies(true, blendNormals); 00411 mTempBlendedBuffer.bindTempCopies(mSharedBlendedVertexData, 00412 mHardwareSkinning); 00413 Mesh::softwareVertexBlend(mMesh->sharedVertexData, 00414 mSharedBlendedVertexData, mBoneMatrices, blendNormals); 00415 } 00416 SubEntityList::iterator i, iend; 00417 iend = mSubEntityList.end(); 00418 for (i = mSubEntityList.begin(); i != iend; ++i) 00419 { 00420 // Blend dedicated geometry 00421 SubEntity* se = *i; 00422 if (se->isVisible() && se->mBlendedVertexData) 00423 { 00424 se->mTempBlendedBuffer.checkoutTempCopies(true, blendNormals); 00425 se->mTempBlendedBuffer.bindTempCopies(se->mBlendedVertexData, 00426 mHardwareSkinning); 00427 Mesh::softwareVertexBlend(se->mSubMesh->vertexData, 00428 se->mBlendedVertexData, mBoneMatrices, blendNormals); 00429 } 00430 00431 } 00432 00433 } 00434 00435 // Trigger update of bounding box if necessary 00436 if (!mChildObjectList.empty()) 00437 mParentNode->needUpdate(); 00438 mFrameAnimationLastUpdated = currentFrameNumber; 00439 } 00440 } 00441 //----------------------------------------------------------------------- 00442 void Entity::cacheBoneMatrices(void) 00443 { 00444 // Get the appropriate meshes skeleton here 00445 // Can use lower LOD mesh skeleton if mesh LOD is manual 00446 // We make the assumption that lower LOD meshes will have 00447 // fewer bones than the full LOD, therefore marix stack will be 00448 // big enough. 00449 Mesh* theMesh; 00450 if (mMesh->isLodManual() && mMeshLodIndex > 1) 00451 { 00452 // Use lower detail skeleton 00453 theMesh = mMesh->getLodLevel(mMeshLodIndex).manualMesh; 00454 // Lower detail may not have skeleton 00455 if (!theMesh->hasSkeleton()) 00456 { 00457 mNumBoneMatrices = 0; 00458 return; 00459 } 00460 } 00461 else 00462 { 00463 // Use normal mesh 00464 theMesh = mMesh; 00465 } 00466 00467 mSkeletonInstance->setAnimationState(mAnimationState); 00468 mSkeletonInstance->_getBoneMatrices(mBoneMatrices); 00469 //--- Update the child object's transforms 00470 ChildObjectList::iterator child_itr = mChildObjectList.begin(); 00471 ChildObjectList::iterator child_itr_end = mChildObjectList.end(); 00472 for( ; child_itr != child_itr_end; child_itr++) 00473 { 00474 (*child_itr).second->getParentNode()->_update(true, true); 00475 } 00476 00477 // Apply our current world transform to these too, since these are used as 00478 // replacement world matrices 00479 unsigned short i; 00480 Matrix4 worldXform = _getParentNodeFullTransform(); 00481 mNumBoneMatrices = mSkeletonInstance->getNumBones(); 00482 00483 for (i = 0; i < mNumBoneMatrices; ++i) 00484 { 00485 mBoneMatrices[i] = worldXform * mBoneMatrices[i]; 00486 } 00487 00488 } 00489 //----------------------------------------------------------------------- 00490 void Entity::setDisplaySkeleton(bool display) 00491 { 00492 mDisplaySkeleton = display; 00493 } 00494 //----------------------------------------------------------------------- 00495 void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex) 00496 { 00497 assert(factor > 0.0f && "Bias factor must be > 0!"); 00498 mMeshLodFactorInv = 1.0f / factor; 00499 mMaxMeshLodIndex = maxDetailIndex; 00500 mMinMeshLodIndex = minDetailIndex; 00501 00502 } 00503 //----------------------------------------------------------------------- 00504 void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex) 00505 { 00506 assert(factor > 0.0f && "Bias factor must be > 0!"); 00507 mMaterialLodFactorInv = 1.0f / factor; 00508 mMaxMaterialLodIndex = maxDetailIndex; 00509 mMinMaterialLodIndex = minDetailIndex; 00510 00511 } 00512 //----------------------------------------------------------------------- 00513 void Entity::buildSubEntityList(Mesh* mesh, SubEntityList* sublist) 00514 { 00515 // Create SubEntities 00516 unsigned short i, numSubMeshes; 00517 SubMesh* subMesh; 00518 SubEntity* subEnt; 00519 00520 numSubMeshes = mesh->getNumSubMeshes(); 00521 for (i = 0; i < numSubMeshes; ++i) 00522 { 00523 subMesh = mesh->getSubMesh(i); 00524 subEnt = new SubEntity(this, subMesh); 00525 if (subMesh->isMatInitialised()) 00526 subEnt->setMaterialName(subMesh->getMaterialName()); 00527 sublist->push_back(subEnt); 00528 } 00529 } 00530 //----------------------------------------------------------------------- 00531 void Entity::setRenderDetail(SceneDetailLevel renderDetail) 00532 { 00533 SubEntityList::iterator i, iend; 00534 iend = mSubEntityList.end(); 00535 00536 for( i = mSubEntityList.begin(); i != iend; ++i ) 00537 { 00538 (*i)->setRenderDetail(renderDetail); 00539 } 00540 } 00541 00542 //----------------------------------------------------------------------- 00543 void Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition) 00544 { 00545 if(pMovable->isAttached()) 00546 { 00547 Except(Exception::ERR_INVALIDPARAMS, "Object already attached to a sceneNode or a Bone", 00548 "Entity::attachObjectToBone"); 00549 } 00550 if (!hasSkeleton()) 00551 { 00552 Except(Exception::ERR_INVALIDPARAMS, "This entity's mesh has no skeleton to attach object to.", 00553 "Entity::attachObjectToBone"); 00554 } 00555 Bone* bone = mSkeletonInstance->getBone(boneName); 00556 if (!bone) 00557 { 00558 Except(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName, 00559 "Entity::attachObjectToBone"); 00560 } 00561 00562 TagPoint *tp = mSkeletonInstance->createTagPointOnBone( 00563 bone, offsetOrientation, offsetPosition); 00564 tp->setParentEntity(this); 00565 tp->setChildObject(pMovable); 00566 00567 attachObjectImpl(pMovable, tp); 00568 } 00569 00570 //----------------------------------------------------------------------- 00571 void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint) 00572 { 00573 mChildObjectList[pObject->getName()] = pObject; 00574 pObject->_notifyAttached(pAttachingPoint, true); 00575 } 00576 00577 //----------------------------------------------------------------------- 00578 MovableObject* Entity::detachObjectFromBone(const String &name) 00579 { 00580 ChildObjectList::iterator i = mChildObjectList.find(name); 00581 00582 if (i == mChildObjectList.end()) 00583 { 00584 Except(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name, 00585 "Entity::detachObjectFromBone"); 00586 } 00587 00588 i->second->_notifyAttached((TagPoint*)0); 00589 mChildObjectList.erase(i); 00590 return i->second; 00591 } 00592 //----------------------------------------------------------------------- 00593 Entity::ChildObjectListIterator Entity::getAttachedObjectIterator() 00594 { 00595 return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end()); 00596 } 00597 //----------------------------------------------------------------------- 00598 Real Entity::getBoundingRadius(void) const 00599 { 00600 Real rad = mMesh->getBoundingSphereRadius(); 00601 // Scale by largest scale factor 00602 if (mParentNode) 00603 { 00604 const Vector3& s = mParentNode->_getDerivedScale(); 00605 rad *= std::max(s.x, std::max(s.y, s.z)); 00606 } 00607 return rad; 00608 } 00609 //----------------------------------------------------------------------- 00610 void Entity::prepareTempBlendBuffers(void) 00611 { 00612 if (mSharedBlendedVertexData) 00613 { 00614 delete mSharedBlendedVertexData; 00615 mSharedBlendedVertexData = 0; 00616 } 00617 00618 if (hasSkeleton()) 00619 { 00620 // Shared data 00621 if (mMesh->sharedVertexData) 00622 { 00623 // Create temporary vertex blend info 00624 // Prepare temp vertex data if needed 00625 // Clone without copying data, remove blending info 00626 // (since blend is performed in software) 00627 mSharedBlendedVertexData = 00628 cloneVertexDataRemoveBlendInfo(mMesh->sharedVertexData); 00629 extractTempBufferInfo(mSharedBlendedVertexData, &mTempBlendedBuffer); 00630 } 00631 00632 SubEntityList::iterator i, iend; 00633 iend = mSubEntityList.end(); 00634 for (i = mSubEntityList.begin(); i != iend; ++i) 00635 { 00636 SubEntity* s = *i; 00637 s->prepareTempBlendBuffers(); 00638 } 00639 00640 00641 } 00642 00643 } 00644 //----------------------------------------------------------------------- 00645 void Entity::extractTempBufferInfo(VertexData* sourceData, TempBlendedBufferInfo* info) 00646 { 00647 VertexDeclaration* decl = sourceData->vertexDeclaration; 00648 VertexBufferBinding* bind = sourceData->vertexBufferBinding; 00649 const VertexElement *posElem = decl->findElementBySemantic(VES_POSITION); 00650 const VertexElement *normElem = decl->findElementBySemantic(VES_NORMAL); 00651 00652 assert(posElem && "Positions are required"); 00653 00654 info->posBindIndex = posElem->getSource(); 00655 info->srcPositionBuffer = bind->getBuffer(info->posBindIndex); 00656 00657 if (!normElem) 00658 { 00659 info->posNormalShareBuffer = false; 00660 info->srcNormalBuffer.release(); 00661 } 00662 else 00663 { 00664 info->normBindIndex = normElem->getSource(); 00665 if (info->normBindIndex == info->posBindIndex) 00666 { 00667 info->posNormalShareBuffer = true; 00668 info->srcNormalBuffer.release(); 00669 } 00670 else 00671 { 00672 info->posNormalShareBuffer = false; 00673 info->srcNormalBuffer = bind->getBuffer(info->normBindIndex); 00674 } 00675 } 00676 } 00677 //----------------------------------------------------------------------- 00678 VertexData* Entity::cloneVertexDataRemoveBlendInfo(const VertexData* source) 00679 { 00680 // Clone without copying data 00681 VertexData* ret = source->clone(false); 00682 const VertexElement* blendIndexElem = 00683 source->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); 00684 const VertexElement* blendWeightElem = 00685 source->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); 00686 // Remove blend index 00687 if (blendIndexElem) 00688 { 00689 // Remove buffer reference 00690 ret->vertexBufferBinding->unsetBinding(blendIndexElem->getSource()); 00691 00692 } 00693 if (blendWeightElem && 00694 blendWeightElem->getSource() != blendIndexElem->getSource()) 00695 { 00696 // Remove buffer reference 00697 ret->vertexBufferBinding->unsetBinding(blendWeightElem->getSource()); 00698 } 00699 // remove elements from declaration 00700 ret->vertexDeclaration->removeElement(VES_BLEND_INDICES); 00701 ret->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS); 00702 00703 // Copy reference to wcoord buffer 00704 if (!source->hardwareShadowVolWBuffer.isNull()) 00705 ret->hardwareShadowVolWBuffer = source->hardwareShadowVolWBuffer; 00706 00707 return ret; 00708 } 00709 //----------------------------------------------------------------------- 00710 EdgeData* Entity::getEdgeList(void) 00711 { 00712 // Get from Mesh 00713 return mMesh->getEdgeList(mMeshLodIndex); 00714 } 00715 //----------------------------------------------------------------------- 00716 void Entity::reevaluateVertexProcessing(void) 00717 { 00718 // init 00719 mHardwareSkinning = false; 00720 mVertexProgramInUse = false; // assume false because we just assign this 00721 bool firstPass = true; 00722 00723 SubEntityList::iterator i, iend; 00724 iend = mSubEntityList.end(); 00725 for (i = mSubEntityList.begin(); i != iend; ++i, firstPass = false) 00726 { 00727 Material* m = (*i)->getMaterial(); 00728 // Make sure it's loaded 00729 m->load(); 00730 Technique* t = m->getBestTechnique(); 00731 if (!t) 00732 { 00733 // No supported techniques 00734 continue; 00735 } 00736 Pass* p = t->getPass(0); 00737 if (!p) 00738 { 00739 // No passes, invalid 00740 continue; 00741 } 00742 if (p->hasVertexProgram()) 00743 { 00744 // If one material uses a vertex program, set this flag 00745 // Causes some special processing like forcing a separate light cap 00746 mVertexProgramInUse = true; 00747 00748 // All materials must support skinning for us to consider using 00749 // hardware skinning - if one fails we use software 00750 if (firstPass) 00751 { 00752 mHardwareSkinning = p->getVertexProgram()->isSkeletalAnimationIncluded(); 00753 } 00754 else 00755 { 00756 mHardwareSkinning = mHardwareSkinning && 00757 p->getVertexProgram()->isSkeletalAnimationIncluded(); 00758 } 00759 } 00760 } 00761 00762 } 00763 //----------------------------------------------------------------------- 00764 ShadowCaster::ShadowRenderableListIterator 00765 Entity::getShadowVolumeRenderableIterator( 00766 ShadowTechnique shadowTechnique, const Light* light, 00767 HardwareIndexBufferSharedPtr* indexBuffer, 00768 bool extrude, Real extrusionDistance, unsigned long flags) 00769 { 00770 assert(indexBuffer && "Only external index buffers are supported right now"); 00771 assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT && 00772 "Only 16-bit indexes supported for now"); 00773 00774 // Potentially delegate to LOD entity 00775 if (mMesh->isLodManual() && mMeshLodIndex > 0) 00776 { 00777 // delegate, we're using manual LOD and not the top lod index 00778 return mLodEntityList[mMeshLodIndex-1]->getShadowVolumeRenderableIterator( 00779 shadowTechnique, light, indexBuffer, extrude, 00780 extrusionDistance, flags); 00781 } 00782 00783 bool hasSkeleton = this->hasSkeleton(); 00784 00785 00786 // Prep mesh if required 00787 // NB This seems to result in memory corruptions, having problems 00788 // tracking them down. For now, ensure that shadows are enabled 00789 // before any entities are created 00790 if(!mMesh->isPreparedForShadowVolumes()) 00791 { 00792 mMesh->prepareForShadowVolume(); 00793 // reset frame last updated to force update of buffers 00794 mFrameAnimationLastUpdated = 0; 00795 // re-prepare buffers 00796 prepareTempBlendBuffers(); 00797 } 00798 00799 00800 // Update any animation 00801 if (hasSkeleton) 00802 { 00803 updateAnimation(); 00804 } 00805 00806 // Calculate the object space light details 00807 Vector4 lightPos = light->getAs4DVector(); 00808 // Only use object-space light if we're not doing transforms 00809 // Since when animating the positions are already transformed into 00810 // world space so we need world space light position 00811 if (!hasSkeleton) 00812 { 00813 Matrix4 world2Obj = mParentNode->_getFullTransform().inverse(); 00814 lightPos = world2Obj * lightPos; 00815 } 00816 00817 // We need to search the edge list for silhouette edges 00818 EdgeData* edgeList = getEdgeList(); 00819 00820 // Init shadow renderable list if required 00821 bool init = mShadowRenderables.empty(); 00822 00823 EdgeData::EdgeGroupList::iterator egi; 00824 ShadowRenderableList::iterator si, siend; 00825 EntityShadowRenderable* esr = 0; 00826 if (init) 00827 mShadowRenderables.resize(edgeList->edgeGroups.size()); 00828 00829 bool updatedSharedGeomNormals = false; 00830 siend = mShadowRenderables.end(); 00831 egi = edgeList->edgeGroups.begin(); 00832 for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi) 00833 { 00834 if (init) 00835 { 00836 const VertexData *pVertData = 0; 00837 if (hasSkeleton) 00838 { 00839 // Use temp buffers 00840 pVertData = findBlendedVertexData(egi->vertexData); 00841 } 00842 else 00843 { 00844 pVertData = egi->vertexData; 00845 } 00846 00847 // Try to find corresponding SubEntity; this allows the 00848 // linkage of visibility between ShadowRenderable and SubEntity 00849 SubEntity* subent = findSubEntityForVertexData(egi->vertexData); 00850 // Create a new renderable, create a separate light cap if 00851 // we're using a vertex program (either for this model, or 00852 // for extruding the shadow volume) since otherwise we can 00853 // get depth-fighting on the light cap 00854 00855 *si = new EntityShadowRenderable(this, indexBuffer, pVertData, 00856 mVertexProgramInUse || !extrude, subent); 00857 } 00858 else if (hasSkeleton) 00859 { 00860 // If we have a skeleton, we have no guarantee that the position 00861 // buffer we used last frame is the same one we used last frame 00862 // since a temporary buffer is requested each frame 00863 // therefore, we need to update the EntityShadowRenderable 00864 // with the current position buffer 00865 static_cast<EntityShadowRenderable*>(*si)->rebindPositionBuffer(); 00866 00867 } 00868 // Get shadow renderable 00869 esr = static_cast<EntityShadowRenderable*>(*si); 00870 HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer(); 00871 // For animated entities we need to recalculate the face normals 00872 if (hasSkeleton) 00873 { 00874 if (egi->vertexData != mMesh->sharedVertexData || !updatedSharedGeomNormals) 00875 { 00876 // recalculate face normals 00877 edgeList->updateFaceNormals(egi->vertexSet, esrPositionBuffer); 00878 // If we're not extruding in software we still need to update 00879 // the latter part of the buffer (the hardware extruded part) 00880 // with the latest animated positions 00881 if (!extrude) 00882 { 00883 // Lock, we'll be locking the (suppressed hardware update) shadow buffer 00884 Real* pSrc = static_cast<Real*>( 00885 esrPositionBuffer->lock(HardwareBuffer::HBL_NORMAL)); 00886 Real* pDest = pSrc + (egi->vertexData->vertexCount * 3); 00887 memcpy(pDest, pSrc, sizeof(Real) * 3 * egi->vertexData->vertexCount); 00888 esrPositionBuffer->unlock(); 00889 } 00890 if (egi->vertexData == mMesh->sharedVertexData) 00891 { 00892 updatedSharedGeomNormals = true; 00893 } 00894 } 00895 } 00896 // Extrude vertices in software if required 00897 if (extrude) 00898 { 00899 extrudeVertices(esrPositionBuffer, 00900 egi->vertexData->vertexCount, 00901 lightPos, extrusionDistance); 00902 00903 } 00904 // Stop suppressing hardware update now, if we were 00905 esrPositionBuffer->suppressHardwareUpdate(false); 00906 00907 } 00908 // Calc triangle light facing 00909 updateEdgeListLightFacing(edgeList, lightPos); 00910 00911 // Generate indexes and update renderables 00912 generateShadowVolume(edgeList, *indexBuffer, light, 00913 mShadowRenderables, flags); 00914 00915 00916 return ShadowRenderableListIterator(mShadowRenderables.begin(), 00917 mShadowRenderables.end()); 00918 } 00919 //----------------------------------------------------------------------- 00920 const VertexData* Entity::findBlendedVertexData(const VertexData* orig) 00921 { 00922 if (orig == mMesh->sharedVertexData) 00923 { 00924 return mSharedBlendedVertexData; 00925 } 00926 SubEntityList::iterator i, iend; 00927 iend = mSubEntityList.end(); 00928 for (i = mSubEntityList.begin(); i != iend; ++i) 00929 { 00930 SubEntity* se = *i; 00931 if (orig == se->getSubMesh()->vertexData) 00932 { 00933 return se->getBlendedVertexData(); 00934 } 00935 } 00936 // None found 00937 Except(Exception::ERR_ITEM_NOT_FOUND, 00938 "Cannot find blended version of the vertex data specified.", 00939 "Entity::findBlendedVertexData"); 00940 } 00941 //----------------------------------------------------------------------- 00942 SubEntity* Entity::findSubEntityForVertexData(const VertexData* orig) 00943 { 00944 if (orig == mMesh->sharedVertexData) 00945 { 00946 return 0; 00947 } 00948 00949 SubEntityList::iterator i, iend; 00950 iend = mSubEntityList.end(); 00951 for (i = mSubEntityList.begin(); i != iend; ++i) 00952 { 00953 SubEntity* se = *i; 00954 if (orig == se->getSubMesh()->vertexData) 00955 { 00956 return se; 00957 } 00958 } 00959 00960 // None found 00961 return 0; 00962 } 00963 //----------------------------------------------------------------------- 00964 void Entity::_notifyAttached(Node* parent, bool isTagPoint) 00965 { 00966 MovableObject::_notifyAttached(parent, isTagPoint); 00967 // Also notify LOD entities 00968 LODEntityList::iterator i, iend; 00969 iend = mLodEntityList.end(); 00970 for (i = mLodEntityList.begin(); i != iend; ++i) 00971 { 00972 (*i)->_notifyAttached(parent, isTagPoint); 00973 } 00974 00975 } 00976 //----------------------------------------------------------------------- 00977 //----------------------------------------------------------------------- 00978 Entity::EntityShadowRenderable::EntityShadowRenderable(Entity* parent, 00979 HardwareIndexBufferSharedPtr* indexBuffer, const VertexData* vertexData, 00980 bool createSeparateLightCap, SubEntity* subent, bool isLightCap) 00981 : mParent(parent), mSubEntity(subent) 00982 { 00983 // Save link to vertex data 00984 mOriginalVertexData = vertexData; 00985 00986 // Initialise render op 00987 mRenderOp.indexData = new IndexData(); 00988 mRenderOp.indexData->indexBuffer = *indexBuffer; 00989 mRenderOp.indexData->indexStart = 0; 00990 // index start and count are sorted out later 00991 00992 // Create vertex data which just references position component (and 2 component) 00993 mRenderOp.vertexData = new VertexData(); 00994 mRenderOp.vertexData->vertexDeclaration = 00995 HardwareBufferManager::getSingleton().createVertexDeclaration(); 00996 mRenderOp.vertexData->vertexBufferBinding = 00997 HardwareBufferManager::getSingleton().createVertexBufferBinding(); 00998 // Map in position data 00999 mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION); 01000 mOriginalPosBufferBinding = 01001 vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource(); 01002 mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(mOriginalPosBufferBinding); 01003 mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer); 01004 // Map in w-coord buffer (if present) 01005 if(!vertexData->hardwareShadowVolWBuffer.isNull()) 01006 { 01007 mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0); 01008 mWBuffer = vertexData->hardwareShadowVolWBuffer; 01009 mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer); 01010 } 01011 // Use same vertex start as input 01012 mRenderOp.vertexData->vertexStart = vertexData->vertexStart; 01013 01014 if (isLightCap) 01015 { 01016 // Use original vertex count, no extrusion 01017 mRenderOp.vertexData->vertexCount = vertexData->vertexCount; 01018 } 01019 else 01020 { 01021 // Vertex count must take into account the doubling of the buffer, 01022 // because second half of the buffer is the extruded copy 01023 mRenderOp.vertexData->vertexCount = 01024 vertexData->vertexCount * 2; 01025 if (createSeparateLightCap) 01026 { 01027 // Create child light cap 01028 mLightCap = new EntityShadowRenderable(parent, 01029 indexBuffer, vertexData, false, subent, true); 01030 } 01031 } 01032 01033 } 01034 //----------------------------------------------------------------------- 01035 Entity::EntityShadowRenderable::~EntityShadowRenderable() 01036 { 01037 delete mRenderOp.indexData; 01038 delete mRenderOp.vertexData; 01039 } 01040 //----------------------------------------------------------------------- 01041 void Entity::EntityShadowRenderable::getWorldTransforms(Matrix4* xform) const 01042 { 01043 unsigned short numBones = mParent->_getNumBoneMatrices(); 01044 01045 if (!numBones) 01046 { 01047 *xform = mParent->_getParentNodeFullTransform(); 01048 } 01049 else 01050 { 01051 // pretransformed 01052 *xform = Matrix4::IDENTITY; 01053 } 01054 } 01055 //----------------------------------------------------------------------- 01056 const Quaternion& Entity::EntityShadowRenderable::getWorldOrientation(void) const 01057 { 01058 return mParent->getParentNode()->_getDerivedOrientation(); 01059 } 01060 //----------------------------------------------------------------------- 01061 const Vector3& Entity::EntityShadowRenderable::getWorldPosition(void) const 01062 { 01063 return mParent->getParentNode()->_getDerivedPosition(); 01064 } 01065 //----------------------------------------------------------------------- 01066 void Entity::EntityShadowRenderable::rebindPositionBuffer(void) 01067 { 01068 mPositionBuffer = mOriginalVertexData->vertexBufferBinding->getBuffer( 01069 mOriginalPosBufferBinding); 01070 mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer); 01071 if (mLightCap) 01072 { 01073 static_cast<EntityShadowRenderable*>(mLightCap)->rebindPositionBuffer(); 01074 } 01075 01076 } 01077 //----------------------------------------------------------------------- 01078 bool Entity::EntityShadowRenderable::isVisible(void) const 01079 { 01080 if (mSubEntity) 01081 { 01082 return mSubEntity->isVisible(); 01083 } 01084 else 01085 { 01086 return ShadowRenderable::isVisible(); 01087 } 01088 } 01089 01090 01091 }
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:08 2004