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         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