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

OgreEntity.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004     (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://ogre.sourceforge.net/
00006 
00007 Copyright © 2000-2002 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreEntity.h"
00027 
00028 #include "OgreMesh.h"
00029 #include "OgreSubMesh.h"
00030 #include "OgreSubEntity.h"
00031 #include "OgreException.h"
00032 #include "OgreSceneManager.h"
00033 #include "OgreLogManager.h"
00034 #include "OgreSkeleton.h"
00035 #include "OgreBone.h"
00036 #include "OgreCamera.h"
00037 #include "OgreTagPoint.h"
00038 #include "OgreAxisAlignedBox.h"
00039 #include "OgreHardwareBufferManager.h"
00040 #include "OgreVector4.h"
00041 #include "OgreRoot.h"
00042 #include "OgreTechnique.h"
00043 #include "OgrePass.h"
00044 #include "OgreSkeletonInstance.h"
00045 #include "OgreEdgeListBuilder.h"
00046 #include "OgreStringConverter.h"
00047 
00048 namespace Ogre {
00049     String Entity::msMovableType = "Entity";
00050     //-----------------------------------------------------------------------
00051     Entity::Entity () 
00052     {
00053         mFullBoundingBox = new AxisAlignedBox;
00054         mNormaliseNormals = false;
00055         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