[692] | 1 | /*
|
---|
| 2 | -----------------------------------------------------------------------------
|
---|
| 3 | This source file is part of OGRE
|
---|
| 4 | (Object-oriented Graphics Rendering Engine)
|
---|
| 5 | For the latest info, see http://ogre.sourceforge.net/
|
---|
| 6 |
|
---|
| 7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
| 8 | Also see acknowledgements in Readme.html
|
---|
| 9 |
|
---|
| 10 | This program is free software; you can redistribute it and/or modify it under
|
---|
| 11 | the terms of the GNU Lesser General Public License as published by the Free Software
|
---|
| 12 | Foundation; either version 2 of the License, or (at your option) any later
|
---|
| 13 | version.
|
---|
| 14 |
|
---|
| 15 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
| 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
---|
| 17 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
---|
| 18 |
|
---|
| 19 | You should have received a copy of the GNU Lesser General Public License along with
|
---|
| 20 | this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
---|
| 21 | Place - Suite 330, Boston, MA 02111-1307, USA, or go to
|
---|
| 22 | http://www.gnu.org/copyleft/lesser.txt.
|
---|
| 23 | -----------------------------------------------------------------------------
|
---|
| 24 | */
|
---|
| 25 | #include "OgreStableHeaders.h"
|
---|
| 26 | #include "OgreEntity.h"
|
---|
| 27 |
|
---|
| 28 | #include "OgreMeshManager.h"
|
---|
| 29 | #include "OgreSubMesh.h"
|
---|
| 30 | #include "OgreSubEntity.h"
|
---|
| 31 | #include "OgreException.h"
|
---|
| 32 | #include "OgreSceneManager.h"
|
---|
| 33 | #include "OgreLogManager.h"
|
---|
| 34 | #include "OgreSkeleton.h"
|
---|
| 35 | #include "OgreBone.h"
|
---|
| 36 | #include "OgreCamera.h"
|
---|
| 37 | #include "OgreTagPoint.h"
|
---|
| 38 | #include "OgreAxisAlignedBox.h"
|
---|
| 39 | #include "OgreHardwareBufferManager.h"
|
---|
| 40 | #include "OgreVector4.h"
|
---|
| 41 | #include "OgreRoot.h"
|
---|
| 42 | #include "OgreTechnique.h"
|
---|
| 43 | #include "OgrePass.h"
|
---|
| 44 | #include "OgreSkeletonInstance.h"
|
---|
| 45 | #include "OgreEdgeListBuilder.h"
|
---|
| 46 | #include "OgreStringConverter.h"
|
---|
| 47 | #include "OgreAnimation.h"
|
---|
| 48 |
|
---|
| 49 | namespace Ogre {
|
---|
| 50 | //-----------------------------------------------------------------------
|
---|
| 51 | Entity::Entity ()
|
---|
| 52 | : mAnimationState(NULL),
|
---|
| 53 | mSkelAnimVertexData(0),
|
---|
| 54 | mSoftwareVertexAnimVertexData(0),
|
---|
| 55 | mHardwareVertexAnimVertexData(0),
|
---|
| 56 | mPreparedForShadowVolumes(false),
|
---|
| 57 | mBoneWorldMatrices(NULL),
|
---|
| 58 | mBoneMatrices(NULL),
|
---|
| 59 | mNumBoneMatrices(0),
|
---|
| 60 | mFrameAnimationLastUpdated(std::numeric_limits<unsigned long>::max()),
|
---|
| 61 | mFrameBonesLastUpdated(NULL),
|
---|
| 62 | mSharedSkeletonEntities(NULL),
|
---|
| 63 | mDisplaySkeleton(false),
|
---|
| 64 | mHardwareAnimation(false),
|
---|
| 65 | mVertexProgramInUse(false),
|
---|
| 66 | mSoftwareAnimationRequests(0),
|
---|
| 67 | mSoftwareAnimationNormalsRequests(0),
|
---|
| 68 | mMeshLodIndex(0),
|
---|
| 69 | mMeshLodFactorInv(1.0f),
|
---|
| 70 | mMinMeshLodIndex(99),
|
---|
| 71 | mMaxMeshLodIndex(0), // Backwards, remember low value = high detail
|
---|
| 72 | mMaterialLodFactorInv(1.0f),
|
---|
| 73 | mMinMaterialLodIndex(99),
|
---|
| 74 | mMaxMaterialLodIndex(0), // Backwards, remember low value = high detail
|
---|
| 75 | mSkeletonInstance(0),
|
---|
| 76 | mLastParentXform(Matrix4::ZERO),
|
---|
| 77 | mFullBoundingBox(),
|
---|
| 78 | mNormaliseNormals(false)
|
---|
| 79 | {
|
---|
| 80 | }
|
---|
| 81 | //-----------------------------------------------------------------------
|
---|
| 82 | Entity::Entity( const String& name, MeshPtr& mesh) :
|
---|
| 83 | MovableObject(name),
|
---|
| 84 | mMesh(mesh),
|
---|
| 85 | mAnimationState(NULL),
|
---|
| 86 | mSkelAnimVertexData(0),
|
---|
| 87 | mSoftwareVertexAnimVertexData(0),
|
---|
| 88 | mHardwareVertexAnimVertexData(0),
|
---|
| 89 | mPreparedForShadowVolumes(false),
|
---|
| 90 | mBoneWorldMatrices(NULL),
|
---|
| 91 | mBoneMatrices(NULL),
|
---|
| 92 | mNumBoneMatrices(0),
|
---|
| 93 | mFrameAnimationLastUpdated(std::numeric_limits<unsigned long>::max()),
|
---|
| 94 | mFrameBonesLastUpdated(NULL),
|
---|
| 95 | mSharedSkeletonEntities(NULL),
|
---|
| 96 | mDisplaySkeleton(false),
|
---|
| 97 | mHardwareAnimation(false),
|
---|
| 98 | mVertexProgramInUse(false),
|
---|
| 99 | mSoftwareAnimationRequests(0),
|
---|
| 100 | mSoftwareAnimationNormalsRequests(0),
|
---|
| 101 | mMeshLodIndex(0),
|
---|
| 102 | mMeshLodFactorInv(1.0f),
|
---|
| 103 | mMinMeshLodIndex(99),
|
---|
| 104 | mMaxMeshLodIndex(0), // Backwards, remember low value = high detail
|
---|
| 105 | mMaterialLodFactorInv(1.0f),
|
---|
| 106 | mMinMaterialLodIndex(99),
|
---|
| 107 | mMaxMaterialLodIndex(0), // Backwards, remember low value = high detail
|
---|
| 108 | mSkeletonInstance(0),
|
---|
| 109 | mLastParentXform(Matrix4::ZERO),
|
---|
| 110 | mFullBoundingBox(),
|
---|
| 111 | mNormaliseNormals(false)
|
---|
| 112 | {
|
---|
| 113 | // Is mesh skeletally animated?
|
---|
| 114 | if (mMesh->hasSkeleton() && !mMesh->getSkeleton().isNull())
|
---|
| 115 | {
|
---|
| 116 | mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
|
---|
| 117 | mSkeletonInstance->load();
|
---|
| 118 | }
|
---|
| 119 |
|
---|
| 120 | // Build main subentity list
|
---|
| 121 | buildSubEntityList(mesh, &mSubEntityList);
|
---|
| 122 |
|
---|
| 123 | // Check if mesh is using manual LOD
|
---|
| 124 | if (mesh->isLodManual())
|
---|
| 125 | {
|
---|
| 126 | ushort i, numLod;
|
---|
| 127 | numLod = mesh->getNumLodLevels();
|
---|
| 128 | // NB skip LOD 0 which is the original
|
---|
| 129 | for (i = 1; i < numLod; ++i)
|
---|
| 130 | {
|
---|
| 131 | const MeshLodUsage& usage = mesh->getLodLevel(i);
|
---|
| 132 | // Manually create entity
|
---|
| 133 | Entity* lodEnt = new Entity(name + "Lod" + StringConverter::toString(i),
|
---|
| 134 | usage.manualMesh);
|
---|
| 135 | mLodEntityList.push_back(lodEnt);
|
---|
| 136 | }
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 |
|
---|
| 140 | // Initialise the AnimationState, if Mesh has animation
|
---|
| 141 | if (hasSkeleton())
|
---|
| 142 | {
|
---|
| 143 | mFrameBonesLastUpdated = new unsigned long(std::numeric_limits<unsigned long>::max());
|
---|
| 144 | mNumBoneMatrices = mSkeletonInstance->getNumBones();
|
---|
| 145 | mBoneMatrices = new Matrix4[mNumBoneMatrices];
|
---|
| 146 | }
|
---|
| 147 | if (hasSkeleton() || hasVertexAnimation())
|
---|
| 148 | {
|
---|
| 149 | mAnimationState = new AnimationStateSet();
|
---|
| 150 | mesh->_initAnimationState(mAnimationState);
|
---|
| 151 | prepareTempBlendBuffers();
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | reevaluateVertexProcessing();
|
---|
| 155 |
|
---|
| 156 |
|
---|
| 157 | // Do we have a mesh where edge lists are not going to be available?
|
---|
| 158 | if (!mesh->isEdgeListBuilt() && !mesh->getAutoBuildEdgeLists())
|
---|
| 159 | {
|
---|
| 160 | setCastShadows(false);
|
---|
| 161 | }
|
---|
| 162 | }
|
---|
| 163 | //-----------------------------------------------------------------------
|
---|
| 164 | Entity::~Entity()
|
---|
| 165 | {
|
---|
| 166 | // Delete submeshes
|
---|
| 167 | SubEntityList::iterator i, iend;
|
---|
| 168 | iend = mSubEntityList.end();
|
---|
| 169 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 170 | {
|
---|
| 171 | // Delete SubEntity
|
---|
| 172 | delete *i;
|
---|
| 173 | }
|
---|
| 174 | // Delete LOD entities
|
---|
| 175 | LODEntityList::iterator li, liend;
|
---|
| 176 | liend = mLodEntityList.end();
|
---|
| 177 | for (li = mLodEntityList.begin(); li != liend; ++li)
|
---|
| 178 | {
|
---|
| 179 | // Delete
|
---|
| 180 | delete (*li);
|
---|
| 181 | }
|
---|
| 182 |
|
---|
| 183 | // Delete shadow renderables
|
---|
| 184 | ShadowRenderableList::iterator si, siend;
|
---|
| 185 | siend = mShadowRenderables.end();
|
---|
| 186 | for (si = mShadowRenderables.begin(); si != siend; ++si)
|
---|
| 187 | {
|
---|
| 188 | delete *si;
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | // Detach all child objects, do this manually to avoid needUpdate() call
|
---|
| 192 | // which can fail because of deleted items
|
---|
| 193 | detachAllObjectsImpl();
|
---|
| 194 |
|
---|
| 195 | if (mSkeletonInstance) {
|
---|
| 196 | delete [] mBoneWorldMatrices;
|
---|
| 197 |
|
---|
| 198 | if (mSharedSkeletonEntities) {
|
---|
| 199 | mSharedSkeletonEntities->erase(this);
|
---|
| 200 | if (mSharedSkeletonEntities->empty()) {
|
---|
| 201 | delete mSharedSkeletonEntities;
|
---|
| 202 | delete mFrameBonesLastUpdated;
|
---|
| 203 | delete mSkeletonInstance;
|
---|
| 204 | delete [] mBoneMatrices;
|
---|
| 205 | delete mAnimationState;
|
---|
| 206 | }
|
---|
| 207 | } else {
|
---|
| 208 | delete mFrameBonesLastUpdated;
|
---|
| 209 | delete mSkeletonInstance;
|
---|
| 210 | delete [] mBoneMatrices;
|
---|
| 211 | delete mAnimationState;
|
---|
| 212 | }
|
---|
| 213 | }
|
---|
| 214 | else if (hasVertexAnimation())
|
---|
| 215 | {
|
---|
| 216 | delete mAnimationState;
|
---|
| 217 | }
|
---|
| 218 |
|
---|
| 219 | delete mSkelAnimVertexData;
|
---|
| 220 | delete mSoftwareVertexAnimVertexData;
|
---|
| 221 | delete mHardwareVertexAnimVertexData;
|
---|
| 222 |
|
---|
| 223 | }
|
---|
| 224 | //-----------------------------------------------------------------------
|
---|
| 225 | bool Entity::hasVertexAnimation(void) const
|
---|
| 226 | {
|
---|
| 227 | return mMesh->hasVertexAnimation();
|
---|
| 228 | }
|
---|
| 229 | //-----------------------------------------------------------------------
|
---|
| 230 | const MeshPtr& Entity::getMesh(void) const
|
---|
| 231 | {
|
---|
| 232 | return mMesh;
|
---|
| 233 | }
|
---|
| 234 | //-----------------------------------------------------------------------
|
---|
| 235 | SubEntity* Entity::getSubEntity(unsigned int index) const
|
---|
| 236 | {
|
---|
| 237 | if (index >= mSubEntityList.size())
|
---|
| 238 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
|
---|
| 239 | "Index out of bounds.",
|
---|
| 240 | "Entity::getSubEntity");
|
---|
| 241 | return mSubEntityList[index];
|
---|
| 242 | }
|
---|
| 243 | //-----------------------------------------------------------------------
|
---|
| 244 | SubEntity* Entity::getSubEntity(const String& name) const
|
---|
| 245 | {
|
---|
| 246 | ushort index = mMesh->_getSubMeshIndex(name);
|
---|
| 247 | return getSubEntity(index);
|
---|
| 248 | }
|
---|
| 249 | //-----------------------------------------------------------------------
|
---|
| 250 | unsigned int Entity::getNumSubEntities(void) const
|
---|
| 251 | {
|
---|
| 252 | return static_cast< unsigned int >( mSubEntityList.size() );
|
---|
| 253 | }
|
---|
| 254 | //-----------------------------------------------------------------------
|
---|
| 255 | Entity* Entity::clone( const String& newName) const
|
---|
| 256 | {
|
---|
| 257 | if (!mManager)
|
---|
| 258 | {
|
---|
| 259 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
|
---|
| 260 | "Cannot clone an Entity that wasn't created through a "
|
---|
| 261 | "SceneManager", "Entity::clone");
|
---|
| 262 | }
|
---|
| 263 | Entity* newEnt = mManager->createEntity(newName, getMesh()->getName() );
|
---|
| 264 | // Copy material settings
|
---|
| 265 | SubEntityList::const_iterator i;
|
---|
| 266 | unsigned int n = 0;
|
---|
| 267 | for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i, ++n)
|
---|
| 268 | {
|
---|
| 269 | newEnt->getSubEntity(n)->setMaterialName((*i)->getMaterialName());
|
---|
| 270 | }
|
---|
| 271 | if (mAnimationState)
|
---|
| 272 | {
|
---|
| 273 | delete newEnt->mAnimationState;
|
---|
| 274 | newEnt->mAnimationState = new AnimationStateSet(*mAnimationState);
|
---|
| 275 | }
|
---|
| 276 | return newEnt;
|
---|
| 277 | }
|
---|
| 278 | //-----------------------------------------------------------------------
|
---|
| 279 | void Entity::setMaterialName(const String& name)
|
---|
| 280 | {
|
---|
| 281 | // Set for all subentities
|
---|
| 282 | SubEntityList::iterator i;
|
---|
| 283 | for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
|
---|
| 284 | {
|
---|
| 285 | (*i)->setMaterialName(name);
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | }
|
---|
| 289 | //-----------------------------------------------------------------------
|
---|
| 290 | void Entity::_notifyCurrentCamera(Camera* cam)
|
---|
| 291 | {
|
---|
| 292 | MovableObject::_notifyCurrentCamera(cam);
|
---|
| 293 |
|
---|
| 294 | // Calculate the LOD
|
---|
| 295 | if (mParentNode)
|
---|
| 296 | {
|
---|
| 297 | Real squaredDepth = mParentNode->getSquaredViewDepth(cam);
|
---|
| 298 |
|
---|
| 299 | // Do Mesh LOD
|
---|
| 300 | // Adjust this depth by the entity bias factor
|
---|
| 301 | Real tmp = squaredDepth * mMeshLodFactorInv;
|
---|
| 302 | // Now adjust it by the camera bias
|
---|
| 303 | tmp = tmp * cam->_getLodBiasInverse();
|
---|
| 304 | // Get the index at this biased depth
|
---|
| 305 | mMeshLodIndex = mMesh->getLodIndexSquaredDepth(tmp);
|
---|
| 306 | // Apply maximum detail restriction (remember lower = higher detail)
|
---|
| 307 | mMeshLodIndex = std::max(mMaxMeshLodIndex, mMeshLodIndex);
|
---|
| 308 | // Apply minimum detail restriction (remember higher = lower detail)
|
---|
| 309 | mMeshLodIndex = std::min(mMinMeshLodIndex, mMeshLodIndex);
|
---|
| 310 |
|
---|
| 311 | // Now do material LOD
|
---|
| 312 | // Adjust this depth by the entity bias factor
|
---|
| 313 | tmp = squaredDepth * mMaterialLodFactorInv;
|
---|
| 314 | // Now adjust it by the camera bias
|
---|
| 315 | tmp = tmp * cam->_getLodBiasInverse();
|
---|
| 316 | SubEntityList::iterator i, iend;
|
---|
| 317 | iend = mSubEntityList.end();
|
---|
| 318 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 319 | {
|
---|
| 320 | // Get the index at this biased depth
|
---|
| 321 | unsigned short idx = (*i)->mpMaterial->getLodIndexSquaredDepth(tmp);
|
---|
| 322 | // Apply maximum detail restriction (remember lower = higher detail)
|
---|
| 323 | idx = std::max(mMaxMaterialLodIndex, idx);
|
---|
| 324 | // Apply minimum detail restriction (remember higher = lower detail)
|
---|
| 325 | (*i)->mMaterialLodIndex = std::min(mMinMaterialLodIndex, idx);
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 |
|
---|
| 329 | }
|
---|
| 330 | // Notify any child objects
|
---|
| 331 | ChildObjectList::iterator child_itr = mChildObjectList.begin();
|
---|
| 332 | ChildObjectList::iterator child_itr_end = mChildObjectList.end();
|
---|
| 333 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 334 | {
|
---|
| 335 | (*child_itr).second->_notifyCurrentCamera(cam);
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 |
|
---|
| 339 | }
|
---|
| 340 | //-----------------------------------------------------------------------
|
---|
| 341 | const AxisAlignedBox& Entity::getBoundingBox(void) const
|
---|
| 342 | {
|
---|
| 343 | // Get from Mesh
|
---|
| 344 | mFullBoundingBox = mMesh->getBounds();
|
---|
| 345 | mFullBoundingBox.merge(getChildObjectsBoundingBox());
|
---|
| 346 |
|
---|
| 347 | // Don't scale here, this is taken into account when world BBox calculation is done
|
---|
| 348 |
|
---|
| 349 | return mFullBoundingBox;
|
---|
| 350 | }
|
---|
| 351 | //-----------------------------------------------------------------------
|
---|
| 352 | AxisAlignedBox Entity::getChildObjectsBoundingBox(void) const
|
---|
| 353 | {
|
---|
| 354 | AxisAlignedBox aa_box;
|
---|
| 355 | AxisAlignedBox full_aa_box;
|
---|
| 356 | full_aa_box.setNull();
|
---|
| 357 |
|
---|
| 358 | ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
|
---|
| 359 | ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
|
---|
| 360 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 361 | {
|
---|
| 362 | aa_box = child_itr->second->getBoundingBox();
|
---|
| 363 | TagPoint* tp = (TagPoint*)child_itr->second->getParentNode();
|
---|
| 364 | // Use transform local to skeleton since world xform comes later
|
---|
| 365 | aa_box.transform(tp->_getFullLocalTransform());
|
---|
| 366 |
|
---|
| 367 | full_aa_box.merge(aa_box);
|
---|
| 368 | }
|
---|
| 369 |
|
---|
| 370 | return full_aa_box;
|
---|
| 371 | }
|
---|
| 372 | //-----------------------------------------------------------------------
|
---|
| 373 | const AxisAlignedBox& Entity::getWorldBoundingBox(bool derive) const
|
---|
| 374 | {
|
---|
| 375 | if (derive)
|
---|
| 376 | {
|
---|
| 377 | // derive child bounding boxes
|
---|
| 378 | ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
|
---|
| 379 | ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
|
---|
| 380 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 381 | {
|
---|
| 382 | child_itr->second->getWorldBoundingBox(true);
|
---|
| 383 | }
|
---|
| 384 | }
|
---|
| 385 | return MovableObject::getWorldBoundingBox(derive);
|
---|
| 386 | }
|
---|
| 387 | //-----------------------------------------------------------------------
|
---|
| 388 | const Sphere& Entity::getWorldBoundingSphere(bool derive) const
|
---|
| 389 | {
|
---|
| 390 | if (derive)
|
---|
| 391 | {
|
---|
| 392 | // derive child bounding boxes
|
---|
| 393 | ChildObjectList::const_iterator child_itr = mChildObjectList.begin();
|
---|
| 394 | ChildObjectList::const_iterator child_itr_end = mChildObjectList.end();
|
---|
| 395 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 396 | {
|
---|
| 397 | child_itr->second->getWorldBoundingSphere(true);
|
---|
| 398 | }
|
---|
| 399 | }
|
---|
| 400 | return MovableObject::getWorldBoundingSphere(derive);
|
---|
| 401 |
|
---|
| 402 | }
|
---|
| 403 | //-----------------------------------------------------------------------
|
---|
| 404 | void Entity::_updateRenderQueue(RenderQueue* queue)
|
---|
| 405 | {
|
---|
| 406 | // Check we're not using a manual LOD
|
---|
| 407 | if (mMeshLodIndex > 0 && mMesh->isLodManual())
|
---|
| 408 | {
|
---|
| 409 | // Use alternate entity
|
---|
| 410 | assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
|
---|
| 411 | "No LOD EntityList - did you build the manual LODs after creating the entity?");
|
---|
| 412 | // index - 1 as we skip index 0 (original lod)
|
---|
| 413 | if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
|
---|
| 414 | {
|
---|
| 415 | // Copy the animation state set to lod entity, we assume the lod
|
---|
| 416 | // entity only has a subset animation states
|
---|
| 417 | mAnimationState->copyMatchingState(
|
---|
| 418 | mLodEntityList[mMeshLodIndex - 1]->mAnimationState);
|
---|
| 419 | }
|
---|
| 420 | mLodEntityList[mMeshLodIndex - 1]->_updateRenderQueue(queue);
|
---|
| 421 | return;
|
---|
| 422 | }
|
---|
| 423 |
|
---|
| 424 | // Add each visible SubEntity to the queue
|
---|
| 425 | SubEntityList::iterator i, iend;
|
---|
| 426 | iend = mSubEntityList.end();
|
---|
| 427 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 428 | {
|
---|
| 429 | if((*i)->isVisible())
|
---|
| 430 | {
|
---|
| 431 | if(mRenderQueueIDSet)
|
---|
| 432 | {
|
---|
| 433 | queue->addRenderable(*i, mRenderQueueID);
|
---|
| 434 | }
|
---|
| 435 | else
|
---|
| 436 | {
|
---|
| 437 | queue->addRenderable(*i);
|
---|
| 438 | }
|
---|
| 439 | }
|
---|
| 440 | }
|
---|
| 441 |
|
---|
| 442 | // Since we know we're going to be rendered, take this opportunity to
|
---|
| 443 | // update the animation
|
---|
| 444 | if (hasSkeleton() || hasVertexAnimation())
|
---|
| 445 | {
|
---|
| 446 | updateAnimation();
|
---|
| 447 |
|
---|
| 448 | //--- pass this point, we are sure that the transformation matrix of each bone and tagPoint have been updated
|
---|
| 449 | ChildObjectList::iterator child_itr = mChildObjectList.begin();
|
---|
| 450 | ChildObjectList::iterator child_itr_end = mChildObjectList.end();
|
---|
| 451 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 452 | {
|
---|
| 453 | if ((*child_itr).second->isVisible())
|
---|
| 454 | (*child_itr).second->_updateRenderQueue(queue);
|
---|
| 455 | }
|
---|
| 456 | }
|
---|
| 457 |
|
---|
| 458 | // HACK to display bones
|
---|
| 459 | // This won't work if the entity is not centered at the origin
|
---|
| 460 | // TODO work out a way to allow bones to be rendered when Entity not centered
|
---|
| 461 | if (mDisplaySkeleton && hasSkeleton())
|
---|
| 462 | {
|
---|
| 463 | int numBones = mSkeletonInstance->getNumBones();
|
---|
| 464 | for (int b = 0; b < numBones; ++b)
|
---|
| 465 | {
|
---|
| 466 | Bone* bone = mSkeletonInstance->getBone(b);
|
---|
| 467 | if(mRenderQueueIDSet)
|
---|
| 468 | {
|
---|
| 469 | queue->addRenderable(bone, mRenderQueueID);
|
---|
| 470 | } else {
|
---|
| 471 | queue->addRenderable(bone);
|
---|
| 472 | }
|
---|
| 473 | }
|
---|
| 474 | }
|
---|
| 475 |
|
---|
| 476 |
|
---|
| 477 |
|
---|
| 478 |
|
---|
| 479 | }
|
---|
| 480 | //-----------------------------------------------------------------------
|
---|
| 481 | AnimationState* Entity::getAnimationState(const String& name) const
|
---|
| 482 | {
|
---|
| 483 | if (!mAnimationState)
|
---|
| 484 | {
|
---|
| 485 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "Entity is not animated",
|
---|
| 486 | "Entity::getAnimationState");
|
---|
| 487 | }
|
---|
| 488 |
|
---|
| 489 | return mAnimationState->getAnimationState(name);
|
---|
| 490 | }
|
---|
| 491 | //-----------------------------------------------------------------------
|
---|
| 492 | AnimationStateSet* Entity::getAllAnimationStates(void) const
|
---|
| 493 | {
|
---|
| 494 | return mAnimationState;
|
---|
| 495 | }
|
---|
| 496 | //-----------------------------------------------------------------------
|
---|
| 497 | const String& Entity::getMovableType(void) const
|
---|
| 498 | {
|
---|
| 499 | return EntityFactory::FACTORY_TYPE_NAME;
|
---|
| 500 | }
|
---|
| 501 | //-----------------------------------------------------------------------
|
---|
| 502 | bool Entity::tempVertexAnimBuffersBound(void) const
|
---|
| 503 | {
|
---|
| 504 | // Do we still have temp buffers for software vertex animation bound?
|
---|
| 505 | bool ret = true;
|
---|
| 506 | if (mMesh->sharedVertexData && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
|
---|
| 507 | {
|
---|
| 508 | ret = ret && mTempVertexAnimInfo.buffersCheckedOut(true, false);
|
---|
| 509 | }
|
---|
| 510 | for (SubEntityList::const_iterator i = mSubEntityList.begin();
|
---|
| 511 | i != mSubEntityList.end(); ++i)
|
---|
| 512 | {
|
---|
| 513 | SubEntity* sub = *i;
|
---|
| 514 | if (!sub->getSubMesh()->useSharedVertices
|
---|
| 515 | && sub->getSubMesh()->getVertexAnimationType() != VAT_NONE)
|
---|
| 516 | {
|
---|
| 517 | ret = ret && sub->_getVertexAnimTempBufferInfo()->buffersCheckedOut(true, false);
|
---|
| 518 | }
|
---|
| 519 | }
|
---|
| 520 | return ret;
|
---|
| 521 | }
|
---|
| 522 | //-----------------------------------------------------------------------
|
---|
| 523 | bool Entity::tempSkelAnimBuffersBound(bool requestNormals) const
|
---|
| 524 | {
|
---|
| 525 | // Do we still have temp buffers for software skeleton animation bound?
|
---|
| 526 | if (mSkelAnimVertexData)
|
---|
| 527 | {
|
---|
| 528 | if (!mTempSkelAnimInfo.buffersCheckedOut(true, requestNormals))
|
---|
| 529 | return false;
|
---|
| 530 | }
|
---|
| 531 | for (SubEntityList::const_iterator i = mSubEntityList.begin();
|
---|
| 532 | i != mSubEntityList.end(); ++i)
|
---|
| 533 | {
|
---|
| 534 | SubEntity* sub = *i;
|
---|
| 535 | if (sub->isVisible() && sub->mSkelAnimVertexData)
|
---|
| 536 | {
|
---|
| 537 | if (!sub->mTempSkelAnimInfo.buffersCheckedOut(true, requestNormals))
|
---|
| 538 | return false;
|
---|
| 539 | }
|
---|
| 540 | }
|
---|
| 541 | return true;
|
---|
| 542 | }
|
---|
| 543 | //-----------------------------------------------------------------------
|
---|
| 544 | void Entity::updateAnimation(void)
|
---|
| 545 | {
|
---|
| 546 | Root& root = Root::getSingleton();
|
---|
| 547 | bool hwAnimation = isHardwareAnimationEnabled();
|
---|
| 548 | bool forcedSwAnimation = getSoftwareAnimationRequests()>0;
|
---|
| 549 | bool forcedNormals = getSoftwareAnimationNormalsRequests()>0;
|
---|
| 550 | bool stencilShadows = false;
|
---|
| 551 | if (root._getCurrentSceneManager())
|
---|
| 552 | stencilShadows = root._getCurrentSceneManager()->isShadowTechniqueStencilBased();
|
---|
| 553 | // If all animations are disabled, we'll use origin vertex buffer for
|
---|
| 554 | // rendering. But still perform software animation if user required,
|
---|
| 555 | // because need to keep same behavior in user standpoint.
|
---|
| 556 | bool softwareAnimation = forcedSwAnimation ||
|
---|
| 557 | (!hwAnimation || stencilShadows) && _isAnimated();
|
---|
| 558 | // Blend normals in s/w only if we're not using h/w animation,
|
---|
| 559 | // since shadows only require positions
|
---|
| 560 | bool blendNormals = !hwAnimation || forcedNormals;
|
---|
| 561 | // Animation dirty if animation state modified or manual bones modified
|
---|
| 562 | bool animationDirty =
|
---|
| 563 | (mFrameAnimationLastUpdated != mAnimationState->getDirtyFrameNumber()) ||
|
---|
| 564 | (hasSkeleton() && getSkeleton()->getManualBonesDirty());
|
---|
| 565 |
|
---|
| 566 | // We only do these tasks if animation is dirty
|
---|
| 567 | // Or, if we're using a skeleton and manual bones have been moved
|
---|
| 568 | // Or, if we're using software animation and temp buffers are unbound
|
---|
| 569 | if (animationDirty ||
|
---|
| 570 | (softwareAnimation && hasVertexAnimation() && !tempVertexAnimBuffersBound()) ||
|
---|
| 571 | (softwareAnimation && hasSkeleton() && !tempSkelAnimBuffersBound(blendNormals)))
|
---|
| 572 | {
|
---|
| 573 | if (hasVertexAnimation())
|
---|
| 574 | {
|
---|
| 575 | if (softwareAnimation)
|
---|
| 576 | {
|
---|
| 577 | // grab & bind temporary buffer for positions
|
---|
| 578 | if (mSoftwareVertexAnimVertexData
|
---|
| 579 | && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
|
---|
| 580 | {
|
---|
| 581 | mTempVertexAnimInfo.checkoutTempCopies(true, false);
|
---|
| 582 | // NB we suppress hardware upload while doing blend if we're
|
---|
| 583 | // hardware animation, because the only reason for doing this
|
---|
| 584 | // is for shadow, which need only be uploaded then
|
---|
| 585 | mTempVertexAnimInfo.bindTempCopies(mSoftwareVertexAnimVertexData,
|
---|
| 586 | hwAnimation);
|
---|
| 587 | }
|
---|
| 588 | SubEntityList::iterator i, iend;
|
---|
| 589 | iend = mSubEntityList.end();
|
---|
| 590 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 591 | {
|
---|
| 592 | // Blend dedicated geometry
|
---|
| 593 | SubEntity* se = *i;
|
---|
| 594 | if (se->isVisible() && se->mSoftwareVertexAnimVertexData
|
---|
| 595 | && se->getSubMesh()->getVertexAnimationType() != VAT_NONE)
|
---|
| 596 | {
|
---|
| 597 | se->mTempVertexAnimInfo.checkoutTempCopies(true, false);
|
---|
| 598 | se->mTempVertexAnimInfo.bindTempCopies(se->mSoftwareVertexAnimVertexData,
|
---|
| 599 | hwAnimation);
|
---|
| 600 | }
|
---|
| 601 |
|
---|
| 602 | }
|
---|
| 603 | }
|
---|
| 604 | applyVertexAnimation(hwAnimation, stencilShadows);
|
---|
| 605 | }
|
---|
| 606 |
|
---|
| 607 | if (hasSkeleton())
|
---|
| 608 | {
|
---|
| 609 | cacheBoneMatrices();
|
---|
| 610 |
|
---|
| 611 | // Software blend?
|
---|
| 612 | if (softwareAnimation)
|
---|
| 613 | {
|
---|
| 614 | // Ok, we need to do a software blend
|
---|
| 615 | // Firstly, check out working vertex buffers
|
---|
| 616 | if (mSkelAnimVertexData)
|
---|
| 617 | {
|
---|
| 618 | // Blend shared geometry
|
---|
| 619 | // NB we suppress hardware upload while doing blend if we're
|
---|
| 620 | // hardware animation, because the only reason for doing this
|
---|
| 621 | // is for shadow, which need only be uploaded then
|
---|
| 622 | mTempSkelAnimInfo.checkoutTempCopies(true, blendNormals);
|
---|
| 623 | mTempSkelAnimInfo.bindTempCopies(mSkelAnimVertexData,
|
---|
| 624 | hwAnimation);
|
---|
| 625 | // Blend, taking source from either mesh data or morph data
|
---|
| 626 | Mesh::softwareVertexBlend(
|
---|
| 627 | (mMesh->getSharedVertexDataAnimationType() != VAT_NONE) ?
|
---|
| 628 | mSoftwareVertexAnimVertexData : mMesh->sharedVertexData,
|
---|
| 629 | mSkelAnimVertexData,
|
---|
| 630 | mBoneMatrices, &mMesh->sharedBlendIndexToBoneIndexMap[0],
|
---|
| 631 | blendNormals);
|
---|
| 632 | }
|
---|
| 633 | SubEntityList::iterator i, iend;
|
---|
| 634 | iend = mSubEntityList.end();
|
---|
| 635 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 636 | {
|
---|
| 637 | // Blend dedicated geometry
|
---|
| 638 | SubEntity* se = *i;
|
---|
| 639 | if (se->isVisible() && se->mSkelAnimVertexData)
|
---|
| 640 | {
|
---|
| 641 | se->mTempSkelAnimInfo.checkoutTempCopies(true, blendNormals);
|
---|
| 642 | se->mTempSkelAnimInfo.bindTempCopies(se->mSkelAnimVertexData,
|
---|
| 643 | hwAnimation);
|
---|
| 644 | // Blend, taking source from either mesh data or morph data
|
---|
| 645 | Mesh::softwareVertexBlend(
|
---|
| 646 | (se->getSubMesh()->getVertexAnimationType() != VAT_NONE)?
|
---|
| 647 | se->mSoftwareVertexAnimVertexData : se->mSubMesh->vertexData,
|
---|
| 648 | se->mSkelAnimVertexData,
|
---|
| 649 | mBoneMatrices, &se->mSubMesh->blendIndexToBoneIndexMap[0],
|
---|
| 650 | blendNormals);
|
---|
| 651 | }
|
---|
| 652 |
|
---|
| 653 | }
|
---|
| 654 |
|
---|
| 655 | }
|
---|
| 656 | }
|
---|
| 657 |
|
---|
| 658 | // Trigger update of bounding box if necessary
|
---|
| 659 | if (!mChildObjectList.empty())
|
---|
| 660 | mParentNode->needUpdate();
|
---|
| 661 |
|
---|
| 662 | mFrameAnimationLastUpdated = mAnimationState->getDirtyFrameNumber();
|
---|
| 663 | }
|
---|
| 664 |
|
---|
| 665 | // Also calculate bone world matrices, since are used as replacement world matrices,
|
---|
| 666 | // but only if it's used and changed:
|
---|
| 667 | // 1. It's used when using hardware animation and skeleton animated.
|
---|
| 668 | // 2. It's changed when animation dirty or parent node transform has altered.
|
---|
| 669 | if (hwAnimation && _isSkeletonAnimated() &&
|
---|
| 670 | (animationDirty || mLastParentXform != getParentSceneNode()->_getFullTransform()))
|
---|
| 671 | {
|
---|
| 672 | // Allocate bone world matrices on demand, for better memory footprint
|
---|
| 673 | // when using software animation.
|
---|
| 674 | if (!mBoneWorldMatrices)
|
---|
| 675 | {
|
---|
| 676 | mBoneWorldMatrices = new Matrix4[mNumBoneMatrices];
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 | // Cache last parent transform for next frame use too.
|
---|
| 680 | mLastParentXform = getParentSceneNode()->_getFullTransform();
|
---|
| 681 |
|
---|
| 682 | for (unsigned short i = 0; i < mNumBoneMatrices; ++i)
|
---|
| 683 | {
|
---|
| 684 | mBoneWorldMatrices[i] = mLastParentXform * mBoneMatrices[i];
|
---|
| 685 | }
|
---|
| 686 | }
|
---|
| 687 | }
|
---|
| 688 | //-----------------------------------------------------------------------
|
---|
| 689 | void Entity::initHardwareAnimationElements(VertexData* vdata,
|
---|
| 690 | ushort numberOfElements)
|
---|
| 691 | {
|
---|
| 692 | if (vdata->hwAnimationDataList.size() < numberOfElements)
|
---|
| 693 | {
|
---|
| 694 | vdata->allocateHardwareAnimationElements(numberOfElements);
|
---|
| 695 | }
|
---|
| 696 | // Initialise parametrics incase we don't use all of them
|
---|
| 697 | for (size_t i = 0; i < vdata->hwAnimationDataList.size(); ++i)
|
---|
| 698 | {
|
---|
| 699 | vdata->hwAnimationDataList[i].parametric = 0.0f;
|
---|
| 700 | }
|
---|
| 701 | // reset used count
|
---|
| 702 | vdata->hwAnimDataItemsUsed = 0;
|
---|
| 703 |
|
---|
| 704 | }
|
---|
| 705 | //-----------------------------------------------------------------------
|
---|
| 706 | void Entity::applyVertexAnimation(bool hardwareAnimation, bool stencilShadows)
|
---|
| 707 | {
|
---|
| 708 | const MeshPtr& msh = getMesh();
|
---|
| 709 | bool swAnim = !hardwareAnimation || stencilShadows || (mSoftwareAnimationRequests>0);
|
---|
| 710 |
|
---|
| 711 | // make sure we have enough hardware animation elements to play with
|
---|
| 712 | if (hardwareAnimation)
|
---|
| 713 | {
|
---|
| 714 | if (mHardwareVertexAnimVertexData
|
---|
| 715 | && msh->getSharedVertexDataAnimationType() != VAT_NONE)
|
---|
| 716 | {
|
---|
| 717 | initHardwareAnimationElements(mHardwareVertexAnimVertexData,
|
---|
| 718 | (msh->getSharedVertexDataAnimationType() == VAT_POSE)
|
---|
| 719 | ? mHardwarePoseCount : 1);
|
---|
| 720 | }
|
---|
| 721 | for (SubEntityList::iterator si = mSubEntityList.begin();
|
---|
| 722 | si != mSubEntityList.end(); ++si)
|
---|
| 723 | {
|
---|
| 724 | SubEntity* sub = *si;
|
---|
| 725 | if (sub->getSubMesh()->getVertexAnimationType() != VAT_NONE &&
|
---|
| 726 | !sub->getSubMesh()->useSharedVertices)
|
---|
| 727 | {
|
---|
| 728 | initHardwareAnimationElements(
|
---|
| 729 | sub->_getHardwareVertexAnimVertexData(),
|
---|
| 730 | (sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
|
---|
| 731 | ? sub->mHardwarePoseCount : 1);
|
---|
| 732 | }
|
---|
| 733 | }
|
---|
| 734 |
|
---|
| 735 | }
|
---|
| 736 | else
|
---|
| 737 | {
|
---|
| 738 | // May be blending multiple poses in software
|
---|
| 739 | // Suppress hardware upload of buffers
|
---|
| 740 | if (mSoftwareVertexAnimVertexData &&
|
---|
| 741 | mMesh->getSharedVertexDataAnimationType() == VAT_POSE)
|
---|
| 742 | {
|
---|
| 743 | const VertexElement* elem = mSoftwareVertexAnimVertexData
|
---|
| 744 | ->vertexDeclaration->findElementBySemantic(VES_POSITION);
|
---|
| 745 | HardwareVertexBufferSharedPtr buf = mSoftwareVertexAnimVertexData
|
---|
| 746 | ->vertexBufferBinding->getBuffer(elem->getSource());
|
---|
| 747 | buf->suppressHardwareUpdate(true);
|
---|
| 748 | }
|
---|
| 749 | for (SubEntityList::iterator si = mSubEntityList.begin();
|
---|
| 750 | si != mSubEntityList.end(); ++si)
|
---|
| 751 | {
|
---|
| 752 | SubEntity* sub = *si;
|
---|
| 753 | if (!sub->getSubMesh()->useSharedVertices &&
|
---|
| 754 | sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
|
---|
| 755 | {
|
---|
| 756 | VertexData* data = sub->_getSoftwareVertexAnimVertexData();
|
---|
| 757 | const VertexElement* elem = data->vertexDeclaration
|
---|
| 758 | ->findElementBySemantic(VES_POSITION);
|
---|
| 759 | HardwareVertexBufferSharedPtr buf = data
|
---|
| 760 | ->vertexBufferBinding->getBuffer(elem->getSource());
|
---|
| 761 | buf->suppressHardwareUpdate(true);
|
---|
| 762 | }
|
---|
| 763 | }
|
---|
| 764 | }
|
---|
| 765 |
|
---|
| 766 |
|
---|
| 767 | // Now apply the animation(s)
|
---|
| 768 | // Note - you should only apply one morph animation to each set of vertex data
|
---|
| 769 | // at once; if you do more, only the last one will actually apply
|
---|
| 770 | markBuffersUnusedForAnimation();
|
---|
| 771 | ConstEnabledAnimationStateIterator animIt = mAnimationState->getEnabledAnimationStateIterator();
|
---|
| 772 | while(animIt.hasMoreElements())
|
---|
| 773 | {
|
---|
| 774 | const AnimationState* state = animIt.getNext();
|
---|
| 775 | Animation* anim = msh->_getAnimationImpl(state->getAnimationName());
|
---|
| 776 | if (anim)
|
---|
| 777 | {
|
---|
| 778 | anim->apply(this, state->getTimePosition(), state->getWeight(),
|
---|
| 779 | swAnim, hardwareAnimation);
|
---|
| 780 | }
|
---|
| 781 | }
|
---|
| 782 | // Deal with cases where no animation applied
|
---|
| 783 | restoreBuffersForUnusedAnimation(hardwareAnimation);
|
---|
| 784 |
|
---|
| 785 | // Unsuppress hardware upload if we suppressed it
|
---|
| 786 | if (!hardwareAnimation)
|
---|
| 787 | {
|
---|
| 788 | if (mSoftwareVertexAnimVertexData &&
|
---|
| 789 | msh->getSharedVertexDataAnimationType() == VAT_POSE)
|
---|
| 790 | {
|
---|
| 791 | const VertexElement* elem = mSoftwareVertexAnimVertexData
|
---|
| 792 | ->vertexDeclaration->findElementBySemantic(VES_POSITION);
|
---|
| 793 | HardwareVertexBufferSharedPtr buf = mSoftwareVertexAnimVertexData
|
---|
| 794 | ->vertexBufferBinding->getBuffer(elem->getSource());
|
---|
| 795 | buf->suppressHardwareUpdate(false);
|
---|
| 796 | }
|
---|
| 797 | for (SubEntityList::iterator si = mSubEntityList.begin();
|
---|
| 798 | si != mSubEntityList.end(); ++si)
|
---|
| 799 | {
|
---|
| 800 | SubEntity* sub = *si;
|
---|
| 801 | if (!sub->getSubMesh()->useSharedVertices &&
|
---|
| 802 | sub->getSubMesh()->getVertexAnimationType() == VAT_POSE)
|
---|
| 803 | {
|
---|
| 804 | VertexData* data = sub->_getSoftwareVertexAnimVertexData();
|
---|
| 805 | const VertexElement* elem = data->vertexDeclaration
|
---|
| 806 | ->findElementBySemantic(VES_POSITION);
|
---|
| 807 | HardwareVertexBufferSharedPtr buf = data
|
---|
| 808 | ->vertexBufferBinding->getBuffer(elem->getSource());
|
---|
| 809 | buf->suppressHardwareUpdate(false);
|
---|
| 810 | }
|
---|
| 811 | }
|
---|
| 812 | }
|
---|
| 813 |
|
---|
| 814 | }
|
---|
| 815 | //-----------------------------------------------------------------------------
|
---|
| 816 | void Entity::markBuffersUnusedForAnimation(void)
|
---|
| 817 | {
|
---|
| 818 | mVertexAnimationAppliedThisFrame = false;
|
---|
| 819 | for (SubEntityList::iterator i = mSubEntityList.begin();
|
---|
| 820 | i != mSubEntityList.end(); ++i)
|
---|
| 821 | {
|
---|
| 822 | (*i)->_markBuffersUnusedForAnimation();
|
---|
| 823 | }
|
---|
| 824 | }
|
---|
| 825 | //-----------------------------------------------------------------------------
|
---|
| 826 | void Entity::_markBuffersUsedForAnimation(void)
|
---|
| 827 | {
|
---|
| 828 | mVertexAnimationAppliedThisFrame = true;
|
---|
| 829 | // no cascade
|
---|
| 830 | }
|
---|
| 831 | //-----------------------------------------------------------------------------
|
---|
| 832 | void Entity::restoreBuffersForUnusedAnimation(bool hardwareAnimation)
|
---|
| 833 | {
|
---|
| 834 | // Rebind original positions if:
|
---|
| 835 | // We didn't apply any animation and
|
---|
| 836 | // We're morph animated (hardware binds keyframe, software is missing)
|
---|
| 837 | // or we're pose animated and software (hardware is fine, still bound)
|
---|
| 838 | if (mMesh->sharedVertexData &&
|
---|
| 839 | !mVertexAnimationAppliedThisFrame &&
|
---|
| 840 | (!hardwareAnimation || mMesh->getSharedVertexDataAnimationType() == VAT_MORPH))
|
---|
| 841 | {
|
---|
| 842 | const VertexElement* srcPosElem =
|
---|
| 843 | mMesh->sharedVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
|
---|
| 844 | HardwareVertexBufferSharedPtr srcBuf =
|
---|
| 845 | mMesh->sharedVertexData->vertexBufferBinding->getBuffer(
|
---|
| 846 | srcPosElem->getSource());
|
---|
| 847 |
|
---|
| 848 | // Bind to software
|
---|
| 849 | const VertexElement* destPosElem =
|
---|
| 850 | mSoftwareVertexAnimVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
|
---|
| 851 | mSoftwareVertexAnimVertexData->vertexBufferBinding->setBinding(
|
---|
| 852 | destPosElem->getSource(), srcBuf);
|
---|
| 853 |
|
---|
| 854 | }
|
---|
| 855 |
|
---|
| 856 | for (SubEntityList::iterator i = mSubEntityList.begin();
|
---|
| 857 | i != mSubEntityList.end(); ++i)
|
---|
| 858 | {
|
---|
| 859 | (*i)->_restoreBuffersForUnusedAnimation(hardwareAnimation);
|
---|
| 860 | }
|
---|
| 861 | }
|
---|
| 862 | //-----------------------------------------------------------------------
|
---|
| 863 | void Entity::_updateAnimation(void)
|
---|
| 864 | {
|
---|
| 865 | // Externally visible method
|
---|
| 866 | if (hasSkeleton() || hasVertexAnimation())
|
---|
| 867 | {
|
---|
| 868 | updateAnimation();
|
---|
| 869 | }
|
---|
| 870 | }
|
---|
| 871 | //-----------------------------------------------------------------------
|
---|
| 872 | bool Entity::_isAnimated(void) const
|
---|
| 873 | {
|
---|
| 874 | return (mAnimationState && mAnimationState->hasEnabledAnimationState()) ||
|
---|
| 875 | (getSkeleton() && getSkeleton()->hasManualBones());
|
---|
| 876 | }
|
---|
| 877 | //-----------------------------------------------------------------------
|
---|
| 878 | bool Entity::_isSkeletonAnimated(void) const
|
---|
| 879 | {
|
---|
| 880 | return getSkeleton() &&
|
---|
| 881 | (mAnimationState->hasEnabledAnimationState() || getSkeleton()->hasManualBones());
|
---|
| 882 | }
|
---|
| 883 | //-----------------------------------------------------------------------
|
---|
| 884 | VertexData* Entity::_getSkelAnimVertexData(void) const
|
---|
| 885 | {
|
---|
| 886 | assert (mSkelAnimVertexData && "Not software skinned!");
|
---|
| 887 | return mSkelAnimVertexData;
|
---|
| 888 | }
|
---|
| 889 | //-----------------------------------------------------------------------
|
---|
| 890 | VertexData* Entity::_getSoftwareVertexAnimVertexData(void) const
|
---|
| 891 | {
|
---|
| 892 | assert (mSoftwareVertexAnimVertexData && "Not vertex animated!");
|
---|
| 893 | return mSoftwareVertexAnimVertexData;
|
---|
| 894 | }
|
---|
| 895 | //-----------------------------------------------------------------------
|
---|
| 896 | VertexData* Entity::_getHardwareVertexAnimVertexData(void) const
|
---|
| 897 | {
|
---|
| 898 | assert (mHardwareVertexAnimVertexData && "Not vertex animated!");
|
---|
| 899 | return mHardwareVertexAnimVertexData;
|
---|
| 900 | }
|
---|
| 901 | //-----------------------------------------------------------------------
|
---|
| 902 | TempBlendedBufferInfo* Entity::_getSkelAnimTempBufferInfo(void)
|
---|
| 903 | {
|
---|
| 904 | return &mTempSkelAnimInfo;
|
---|
| 905 | }
|
---|
| 906 | //-----------------------------------------------------------------------
|
---|
| 907 | TempBlendedBufferInfo* Entity::_getVertexAnimTempBufferInfo(void)
|
---|
| 908 | {
|
---|
| 909 | return &mTempVertexAnimInfo;
|
---|
| 910 | }
|
---|
| 911 | //-----------------------------------------------------------------------
|
---|
| 912 | void Entity::cacheBoneMatrices(void)
|
---|
| 913 | {
|
---|
| 914 | Root& root = Root::getSingleton();
|
---|
| 915 | unsigned long currentFrameNumber = root.getCurrentFrameNumber();
|
---|
| 916 | if (*mFrameBonesLastUpdated != currentFrameNumber) {
|
---|
| 917 |
|
---|
| 918 | mSkeletonInstance->setAnimationState(*mAnimationState);
|
---|
| 919 | mSkeletonInstance->_getBoneMatrices(mBoneMatrices);
|
---|
| 920 | *mFrameBonesLastUpdated = currentFrameNumber;
|
---|
| 921 |
|
---|
| 922 | if (sharesSkeletonInstance()) {
|
---|
| 923 | //---- update all sharing entities child objects transforms now
|
---|
| 924 | EntitySet::const_iterator entity_itr = mSharedSkeletonEntities->begin();
|
---|
| 925 | EntitySet::const_iterator entity_itr_end = mSharedSkeletonEntities->end();
|
---|
| 926 | for( ; entity_itr != entity_itr_end; entity_itr++)
|
---|
| 927 | {
|
---|
| 928 | ChildObjectList::iterator child_itr = (*entity_itr)->mChildObjectList.begin();
|
---|
| 929 | ChildObjectList::iterator child_itr_end = (*entity_itr)->mChildObjectList.end();
|
---|
| 930 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 931 | {
|
---|
| 932 | (*child_itr).second->getParentNode()->_update(true, true);
|
---|
| 933 | }
|
---|
| 934 | }
|
---|
| 935 | } else {
|
---|
| 936 | //--- Update the child object's transforms
|
---|
| 937 | ChildObjectList::iterator child_itr = mChildObjectList.begin();
|
---|
| 938 | ChildObjectList::iterator child_itr_end = mChildObjectList.end();
|
---|
| 939 | for( ; child_itr != child_itr_end; child_itr++)
|
---|
| 940 | {
|
---|
| 941 | (*child_itr).second->getParentNode()->_update(true, true);
|
---|
| 942 | }
|
---|
| 943 | }
|
---|
| 944 | }
|
---|
| 945 | }
|
---|
| 946 | //-----------------------------------------------------------------------
|
---|
| 947 | void Entity::setDisplaySkeleton(bool display)
|
---|
| 948 | {
|
---|
| 949 | mDisplaySkeleton = display;
|
---|
| 950 | }
|
---|
| 951 | //-----------------------------------------------------------------------
|
---|
| 952 | bool Entity::getDisplaySkeleton(void) const
|
---|
| 953 | {
|
---|
| 954 | return mDisplaySkeleton;
|
---|
| 955 | }
|
---|
| 956 | //-----------------------------------------------------------------------
|
---|
| 957 | Entity* Entity::getManualLodLevel(size_t index) const
|
---|
| 958 | {
|
---|
| 959 | assert(index < mLodEntityList.size());
|
---|
| 960 |
|
---|
| 961 | return mLodEntityList[index];
|
---|
| 962 | }
|
---|
| 963 | //-----------------------------------------------------------------------
|
---|
| 964 | size_t Entity::getNumManualLodLevels(void) const
|
---|
| 965 | {
|
---|
| 966 | return mLodEntityList.size();
|
---|
| 967 | }
|
---|
| 968 | //-----------------------------------------------------------------------
|
---|
| 969 | void Entity::setMeshLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
|
---|
| 970 | {
|
---|
| 971 | assert(factor > 0.0f && "Bias factor must be > 0!");
|
---|
| 972 | mMeshLodFactorInv = 1.0f / factor;
|
---|
| 973 | mMaxMeshLodIndex = maxDetailIndex;
|
---|
| 974 | mMinMeshLodIndex = minDetailIndex;
|
---|
| 975 |
|
---|
| 976 | }
|
---|
| 977 | //-----------------------------------------------------------------------
|
---|
| 978 | void Entity::setMaterialLodBias(Real factor, ushort maxDetailIndex, ushort minDetailIndex)
|
---|
| 979 | {
|
---|
| 980 | assert(factor > 0.0f && "Bias factor must be > 0!");
|
---|
| 981 | mMaterialLodFactorInv = 1.0f / factor;
|
---|
| 982 | mMaxMaterialLodIndex = maxDetailIndex;
|
---|
| 983 | mMinMaterialLodIndex = minDetailIndex;
|
---|
| 984 |
|
---|
| 985 | }
|
---|
| 986 | //-----------------------------------------------------------------------
|
---|
| 987 | void Entity::buildSubEntityList(MeshPtr& mesh, SubEntityList* sublist)
|
---|
| 988 | {
|
---|
| 989 | // Create SubEntities
|
---|
| 990 | unsigned short i, numSubMeshes;
|
---|
| 991 | SubMesh* subMesh;
|
---|
| 992 | SubEntity* subEnt;
|
---|
| 993 |
|
---|
| 994 | numSubMeshes = mesh->getNumSubMeshes();
|
---|
| 995 | for (i = 0; i < numSubMeshes; ++i)
|
---|
| 996 | {
|
---|
| 997 | subMesh = mesh->getSubMesh(i);
|
---|
| 998 | subEnt = new SubEntity(this, subMesh);
|
---|
| 999 | if (subMesh->isMatInitialised())
|
---|
| 1000 | subEnt->setMaterialName(subMesh->getMaterialName());
|
---|
| 1001 | sublist->push_back(subEnt);
|
---|
| 1002 | }
|
---|
| 1003 | }
|
---|
| 1004 | //-----------------------------------------------------------------------
|
---|
| 1005 | void Entity::setPolygonModeOverrideable(bool overrideable)
|
---|
| 1006 | {
|
---|
| 1007 | SubEntityList::iterator i, iend;
|
---|
| 1008 | iend = mSubEntityList.end();
|
---|
| 1009 |
|
---|
| 1010 | for( i = mSubEntityList.begin(); i != iend; ++i )
|
---|
| 1011 | {
|
---|
| 1012 | (*i)->setPolygonModeOverrideable(overrideable);
|
---|
| 1013 | }
|
---|
| 1014 | }
|
---|
| 1015 |
|
---|
| 1016 | //-----------------------------------------------------------------------
|
---|
| 1017 | TagPoint* Entity::attachObjectToBone(const String &boneName, MovableObject *pMovable, const Quaternion &offsetOrientation, const Vector3 &offsetPosition)
|
---|
| 1018 | {
|
---|
| 1019 | if (mChildObjectList.find(pMovable->getName()) != mChildObjectList.end())
|
---|
| 1020 | {
|
---|
| 1021 | OGRE_EXCEPT(Exception::ERR_DUPLICATE_ITEM,
|
---|
| 1022 | "An object with the name " + pMovable->getName() + " already attached",
|
---|
| 1023 | "Entity::attachObjectToBone");
|
---|
| 1024 | }
|
---|
| 1025 | if(pMovable->isAttached())
|
---|
| 1026 | {
|
---|
| 1027 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Object already attached to a sceneNode or a Bone",
|
---|
| 1028 | "Entity::attachObjectToBone");
|
---|
| 1029 | }
|
---|
| 1030 | if (!hasSkeleton())
|
---|
| 1031 | {
|
---|
| 1032 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "This entity's mesh has no skeleton to attach object to.",
|
---|
| 1033 | "Entity::attachObjectToBone");
|
---|
| 1034 | }
|
---|
| 1035 | Bone* bone = mSkeletonInstance->getBone(boneName);
|
---|
| 1036 | if (!bone)
|
---|
| 1037 | {
|
---|
| 1038 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Cannot locate bone named " + boneName,
|
---|
| 1039 | "Entity::attachObjectToBone");
|
---|
| 1040 | }
|
---|
| 1041 |
|
---|
| 1042 | TagPoint *tp = mSkeletonInstance->createTagPointOnBone(
|
---|
| 1043 | bone, offsetOrientation, offsetPosition);
|
---|
| 1044 | tp->setParentEntity(this);
|
---|
| 1045 | tp->setChildObject(pMovable);
|
---|
| 1046 |
|
---|
| 1047 | attachObjectImpl(pMovable, tp);
|
---|
| 1048 |
|
---|
| 1049 | // Trigger update of bounding box if necessary
|
---|
| 1050 | if (mParentNode)
|
---|
| 1051 | mParentNode->needUpdate();
|
---|
| 1052 |
|
---|
| 1053 | return tp;
|
---|
| 1054 | }
|
---|
| 1055 |
|
---|
| 1056 | //-----------------------------------------------------------------------
|
---|
| 1057 | void Entity::attachObjectImpl(MovableObject *pObject, TagPoint *pAttachingPoint)
|
---|
| 1058 | {
|
---|
| 1059 | assert(mChildObjectList.find(pObject->getName()) == mChildObjectList.end());
|
---|
| 1060 | mChildObjectList[pObject->getName()] = pObject;
|
---|
| 1061 | pObject->_notifyAttached(pAttachingPoint, true);
|
---|
| 1062 | }
|
---|
| 1063 |
|
---|
| 1064 | //-----------------------------------------------------------------------
|
---|
| 1065 | MovableObject* Entity::detachObjectFromBone(const String &name)
|
---|
| 1066 | {
|
---|
| 1067 | ChildObjectList::iterator i = mChildObjectList.find(name);
|
---|
| 1068 |
|
---|
| 1069 | if (i == mChildObjectList.end())
|
---|
| 1070 | {
|
---|
| 1071 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No child object entry found named " + name,
|
---|
| 1072 | "Entity::detachObjectFromBone");
|
---|
| 1073 | }
|
---|
| 1074 | MovableObject *obj = i->second;
|
---|
| 1075 | detachObjectImpl(obj);
|
---|
| 1076 | mChildObjectList.erase(i);
|
---|
| 1077 |
|
---|
| 1078 | // Trigger update of bounding box if necessary
|
---|
| 1079 | if (mParentNode)
|
---|
| 1080 | mParentNode->needUpdate();
|
---|
| 1081 |
|
---|
| 1082 | return obj;
|
---|
| 1083 | }
|
---|
| 1084 | //-----------------------------------------------------------------------
|
---|
| 1085 | void Entity::detachObjectFromBone(MovableObject* obj)
|
---|
| 1086 | {
|
---|
| 1087 | ChildObjectList::iterator i, iend;
|
---|
| 1088 | iend = mChildObjectList.end();
|
---|
| 1089 | for (i = mChildObjectList.begin(); i != iend; ++i)
|
---|
| 1090 | {
|
---|
| 1091 | if (i->second == obj)
|
---|
| 1092 | {
|
---|
| 1093 | detachObjectImpl(obj);
|
---|
| 1094 | mChildObjectList.erase(i);
|
---|
| 1095 |
|
---|
| 1096 | // Trigger update of bounding box if necessary
|
---|
| 1097 | if (mParentNode)
|
---|
| 1098 | mParentNode->needUpdate();
|
---|
| 1099 | break;
|
---|
| 1100 | }
|
---|
| 1101 | }
|
---|
| 1102 | }
|
---|
| 1103 | //-----------------------------------------------------------------------
|
---|
| 1104 | void Entity::detachAllObjectsFromBone(void)
|
---|
| 1105 | {
|
---|
| 1106 | detachAllObjectsImpl();
|
---|
| 1107 |
|
---|
| 1108 | // Trigger update of bounding box if necessary
|
---|
| 1109 | if (mParentNode)
|
---|
| 1110 | mParentNode->needUpdate();
|
---|
| 1111 | }
|
---|
| 1112 | //-----------------------------------------------------------------------
|
---|
| 1113 | void Entity::detachObjectImpl(MovableObject* pObject)
|
---|
| 1114 | {
|
---|
| 1115 | TagPoint* tp = static_cast<TagPoint*>(pObject->getParentNode());
|
---|
| 1116 |
|
---|
| 1117 | // free the TagPoint so we can reuse it later
|
---|
| 1118 | mSkeletonInstance->freeTagPoint(tp);
|
---|
| 1119 |
|
---|
| 1120 | pObject->_notifyAttached((TagPoint*)0);
|
---|
| 1121 | }
|
---|
| 1122 | //-----------------------------------------------------------------------
|
---|
| 1123 | void Entity::detachAllObjectsImpl(void)
|
---|
| 1124 | {
|
---|
| 1125 | ChildObjectList::const_iterator i, iend;
|
---|
| 1126 | iend = mChildObjectList.end();
|
---|
| 1127 | for (i = mChildObjectList.begin(); i != iend; ++i)
|
---|
| 1128 | {
|
---|
| 1129 | detachObjectImpl(i->second);
|
---|
| 1130 | }
|
---|
| 1131 | mChildObjectList.clear();
|
---|
| 1132 | }
|
---|
| 1133 |
|
---|
| 1134 | //-----------------------------------------------------------------------
|
---|
| 1135 | Entity::ChildObjectListIterator Entity::getAttachedObjectIterator()
|
---|
| 1136 | {
|
---|
| 1137 | return ChildObjectListIterator(mChildObjectList.begin(), mChildObjectList.end());
|
---|
| 1138 | }
|
---|
| 1139 | //-----------------------------------------------------------------------
|
---|
| 1140 | Real Entity::getBoundingRadius(void) const
|
---|
| 1141 | {
|
---|
| 1142 | Real rad = mMesh->getBoundingSphereRadius();
|
---|
| 1143 | // Scale by largest scale factor
|
---|
| 1144 | if (mParentNode)
|
---|
| 1145 | {
|
---|
| 1146 | const Vector3& s = mParentNode->_getDerivedScale();
|
---|
| 1147 | rad *= std::max(s.x, std::max(s.y, s.z));
|
---|
| 1148 | }
|
---|
| 1149 | return rad;
|
---|
| 1150 | }
|
---|
| 1151 | //-----------------------------------------------------------------------
|
---|
| 1152 | void Entity::prepareTempBlendBuffers(void)
|
---|
| 1153 | {
|
---|
| 1154 | if (mSkelAnimVertexData)
|
---|
| 1155 | {
|
---|
| 1156 | delete mSkelAnimVertexData;
|
---|
| 1157 | mSkelAnimVertexData = 0;
|
---|
| 1158 | }
|
---|
| 1159 | if (mSoftwareVertexAnimVertexData)
|
---|
| 1160 | {
|
---|
| 1161 | delete mSoftwareVertexAnimVertexData;
|
---|
| 1162 | mSoftwareVertexAnimVertexData = 0;
|
---|
| 1163 | }
|
---|
| 1164 | if (mHardwareVertexAnimVertexData)
|
---|
| 1165 | {
|
---|
| 1166 | delete mHardwareVertexAnimVertexData;
|
---|
| 1167 | mHardwareVertexAnimVertexData = 0;
|
---|
| 1168 | }
|
---|
| 1169 |
|
---|
| 1170 | if (hasVertexAnimation())
|
---|
| 1171 | {
|
---|
| 1172 | // Shared data
|
---|
| 1173 | if (mMesh->sharedVertexData
|
---|
| 1174 | && mMesh->getSharedVertexDataAnimationType() != VAT_NONE)
|
---|
| 1175 | {
|
---|
| 1176 | // Create temporary vertex blend info
|
---|
| 1177 | // Prepare temp vertex data if needed
|
---|
| 1178 | // Clone without copying data, remove blending info
|
---|
| 1179 | // (since blend is performed in software)
|
---|
| 1180 | mSoftwareVertexAnimVertexData =
|
---|
| 1181 | cloneVertexDataRemoveBlendInfo(mMesh->sharedVertexData);
|
---|
| 1182 | extractTempBufferInfo(mSoftwareVertexAnimVertexData, &mTempVertexAnimInfo);
|
---|
| 1183 |
|
---|
| 1184 | // Also clone for hardware usage, don't remove blend info since we'll
|
---|
| 1185 | // need it if we also hardware skeletally animate
|
---|
| 1186 | mHardwareVertexAnimVertexData = mMesh->sharedVertexData->clone(false);
|
---|
| 1187 | }
|
---|
| 1188 | }
|
---|
| 1189 |
|
---|
| 1190 | if (hasSkeleton())
|
---|
| 1191 | {
|
---|
| 1192 | // Shared data
|
---|
| 1193 | if (mMesh->sharedVertexData)
|
---|
| 1194 | {
|
---|
| 1195 | // Create temporary vertex blend info
|
---|
| 1196 | // Prepare temp vertex data if needed
|
---|
| 1197 | // Clone without copying data, remove blending info
|
---|
| 1198 | // (since blend is performed in software)
|
---|
| 1199 | mSkelAnimVertexData =
|
---|
| 1200 | cloneVertexDataRemoveBlendInfo(mMesh->sharedVertexData);
|
---|
| 1201 | extractTempBufferInfo(mSkelAnimVertexData, &mTempSkelAnimInfo);
|
---|
| 1202 | }
|
---|
| 1203 |
|
---|
| 1204 | }
|
---|
| 1205 |
|
---|
| 1206 | // Do SubEntities
|
---|
| 1207 | SubEntityList::iterator i, iend;
|
---|
| 1208 | iend = mSubEntityList.end();
|
---|
| 1209 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 1210 | {
|
---|
| 1211 | SubEntity* s = *i;
|
---|
| 1212 | s->prepareTempBlendBuffers();
|
---|
| 1213 | }
|
---|
| 1214 |
|
---|
| 1215 | // It's prepared for shadow volumes only if mesh has been prepared for shadow volumes.
|
---|
| 1216 | mPreparedForShadowVolumes = mMesh->isPreparedForShadowVolumes();
|
---|
| 1217 | }
|
---|
| 1218 | //-----------------------------------------------------------------------
|
---|
| 1219 | void Entity::extractTempBufferInfo(VertexData* sourceData, TempBlendedBufferInfo* info)
|
---|
| 1220 | {
|
---|
| 1221 | info->extractFrom(sourceData);
|
---|
| 1222 | }
|
---|
| 1223 | //-----------------------------------------------------------------------
|
---|
| 1224 | VertexData* Entity::cloneVertexDataRemoveBlendInfo(const VertexData* source)
|
---|
| 1225 | {
|
---|
| 1226 | // Clone without copying data
|
---|
| 1227 | VertexData* ret = source->clone(false);
|
---|
| 1228 | const VertexElement* blendIndexElem =
|
---|
| 1229 | source->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES);
|
---|
| 1230 | const VertexElement* blendWeightElem =
|
---|
| 1231 | source->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS);
|
---|
| 1232 | // Remove blend index
|
---|
| 1233 | if (blendIndexElem)
|
---|
| 1234 | {
|
---|
| 1235 | // Remove buffer reference
|
---|
| 1236 | ret->vertexBufferBinding->unsetBinding(blendIndexElem->getSource());
|
---|
| 1237 |
|
---|
| 1238 | }
|
---|
| 1239 | if (blendWeightElem &&
|
---|
| 1240 | blendWeightElem->getSource() != blendIndexElem->getSource())
|
---|
| 1241 | {
|
---|
| 1242 | // Remove buffer reference
|
---|
| 1243 | ret->vertexBufferBinding->unsetBinding(blendWeightElem->getSource());
|
---|
| 1244 | }
|
---|
| 1245 | // remove elements from declaration
|
---|
| 1246 | ret->vertexDeclaration->removeElement(VES_BLEND_INDICES);
|
---|
| 1247 | ret->vertexDeclaration->removeElement(VES_BLEND_WEIGHTS);
|
---|
| 1248 |
|
---|
| 1249 | // Copy reference to wcoord buffer
|
---|
| 1250 | if (!source->hardwareShadowVolWBuffer.isNull())
|
---|
| 1251 | ret->hardwareShadowVolWBuffer = source->hardwareShadowVolWBuffer;
|
---|
| 1252 |
|
---|
| 1253 | return ret;
|
---|
| 1254 | }
|
---|
| 1255 | //-----------------------------------------------------------------------
|
---|
| 1256 | EdgeData* Entity::getEdgeList(void)
|
---|
| 1257 | {
|
---|
| 1258 | // Get from Mesh
|
---|
| 1259 | return mMesh->getEdgeList(mMeshLodIndex);
|
---|
| 1260 | }
|
---|
| 1261 | //-----------------------------------------------------------------------
|
---|
| 1262 | void Entity::reevaluateVertexProcessing(void)
|
---|
| 1263 | {
|
---|
| 1264 | // init
|
---|
| 1265 | mHardwareAnimation = false;
|
---|
| 1266 | mVertexProgramInUse = false; // assume false because we just assign this
|
---|
| 1267 | bool firstPass = true;
|
---|
| 1268 |
|
---|
| 1269 | SubEntityList::iterator i, iend;
|
---|
| 1270 | iend = mSubEntityList.end();
|
---|
| 1271 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 1272 | {
|
---|
| 1273 | SubEntity* sub = *i;
|
---|
| 1274 | const MaterialPtr& m = sub->getMaterial();
|
---|
| 1275 | // Make sure it's loaded
|
---|
| 1276 | m->load();
|
---|
| 1277 | Technique* t = m->getBestTechnique();
|
---|
| 1278 | if (!t)
|
---|
| 1279 | {
|
---|
| 1280 | // No supported techniques
|
---|
| 1281 | continue;
|
---|
| 1282 | }
|
---|
| 1283 | Pass* p = t->getPass(0);
|
---|
| 1284 | if (!p)
|
---|
| 1285 | {
|
---|
| 1286 | // No passes, invalid
|
---|
| 1287 | continue;
|
---|
| 1288 | }
|
---|
| 1289 | if (p->hasVertexProgram())
|
---|
| 1290 | {
|
---|
| 1291 | // If one material uses a vertex program, set this flag
|
---|
| 1292 | // Causes some special processing like forcing a separate light cap
|
---|
| 1293 | mVertexProgramInUse = true;
|
---|
| 1294 |
|
---|
| 1295 | if (hasSkeleton())
|
---|
| 1296 | {
|
---|
| 1297 | // All materials must support skinning for us to consider using
|
---|
| 1298 | // hardware animation - if one fails we use software
|
---|
| 1299 | if (firstPass)
|
---|
| 1300 | {
|
---|
| 1301 | mHardwareAnimation = p->getVertexProgram()->isSkeletalAnimationIncluded();
|
---|
| 1302 | firstPass = false;
|
---|
| 1303 | }
|
---|
| 1304 | else
|
---|
| 1305 | {
|
---|
| 1306 | mHardwareAnimation = mHardwareAnimation &&
|
---|
| 1307 | p->getVertexProgram()->isSkeletalAnimationIncluded();
|
---|
| 1308 | }
|
---|
| 1309 | }
|
---|
| 1310 |
|
---|
| 1311 | VertexAnimationType animType = VAT_NONE;
|
---|
| 1312 | if (sub->getSubMesh()->useSharedVertices)
|
---|
| 1313 | {
|
---|
| 1314 | animType = mMesh->getSharedVertexDataAnimationType();
|
---|
| 1315 | }
|
---|
| 1316 | else
|
---|
| 1317 | {
|
---|
| 1318 | animType = sub->getSubMesh()->getVertexAnimationType();
|
---|
| 1319 | }
|
---|
| 1320 | if (animType == VAT_MORPH)
|
---|
| 1321 | {
|
---|
| 1322 | // All materials must support morph animation for us to consider using
|
---|
| 1323 | // hardware animation - if one fails we use software
|
---|
| 1324 | if (firstPass)
|
---|
| 1325 | {
|
---|
| 1326 | mHardwareAnimation = p->getVertexProgram()->isMorphAnimationIncluded();
|
---|
| 1327 | firstPass = false;
|
---|
| 1328 | }
|
---|
| 1329 | else
|
---|
| 1330 | {
|
---|
| 1331 | mHardwareAnimation = mHardwareAnimation &&
|
---|
| 1332 | p->getVertexProgram()->isMorphAnimationIncluded();
|
---|
| 1333 | }
|
---|
| 1334 | }
|
---|
| 1335 | else if (animType == VAT_POSE)
|
---|
| 1336 | {
|
---|
| 1337 | // All materials must support pose animation for us to consider using
|
---|
| 1338 | // hardware animation - if one fails we use software
|
---|
| 1339 | if (firstPass)
|
---|
| 1340 | {
|
---|
| 1341 | mHardwareAnimation = p->getVertexProgram()->isPoseAnimationIncluded();
|
---|
| 1342 | if (sub->getSubMesh()->useSharedVertices)
|
---|
| 1343 | mHardwarePoseCount = p->getVertexProgram()->getNumberOfPosesIncluded();
|
---|
| 1344 | else
|
---|
| 1345 | sub->mHardwarePoseCount = p->getVertexProgram()->getNumberOfPosesIncluded();
|
---|
| 1346 | firstPass = false;
|
---|
| 1347 | }
|
---|
| 1348 | else
|
---|
| 1349 | {
|
---|
| 1350 | mHardwareAnimation = mHardwareAnimation &&
|
---|
| 1351 | p->getVertexProgram()->isPoseAnimationIncluded();
|
---|
| 1352 | if (sub->getSubMesh()->useSharedVertices)
|
---|
| 1353 | mHardwarePoseCount = std::max(mHardwarePoseCount,
|
---|
| 1354 | p->getVertexProgram()->getNumberOfPosesIncluded());
|
---|
| 1355 | else
|
---|
| 1356 | sub->mHardwarePoseCount = std::max(sub->mHardwarePoseCount,
|
---|
| 1357 | p->getVertexProgram()->getNumberOfPosesIncluded());
|
---|
| 1358 | }
|
---|
| 1359 | }
|
---|
| 1360 |
|
---|
| 1361 | }
|
---|
| 1362 | }
|
---|
| 1363 |
|
---|
| 1364 | }
|
---|
| 1365 | //-----------------------------------------------------------------------
|
---|
| 1366 | ShadowCaster::ShadowRenderableListIterator
|
---|
| 1367 | Entity::getShadowVolumeRenderableIterator(
|
---|
| 1368 | ShadowTechnique shadowTechnique, const Light* light,
|
---|
| 1369 | HardwareIndexBufferSharedPtr* indexBuffer,
|
---|
| 1370 | bool extrude, Real extrusionDistance, unsigned long flags)
|
---|
| 1371 | {
|
---|
| 1372 | assert(indexBuffer && "Only external index buffers are supported right now");
|
---|
| 1373 | assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
|
---|
| 1374 | "Only 16-bit indexes supported for now");
|
---|
| 1375 |
|
---|
| 1376 | // Potentially delegate to LOD entity
|
---|
| 1377 | if (mMesh->isLodManual() && mMeshLodIndex > 0)
|
---|
| 1378 | {
|
---|
| 1379 | // Use alternate entity
|
---|
| 1380 | assert( static_cast< size_t >( mMeshLodIndex - 1 ) < mLodEntityList.size() &&
|
---|
| 1381 | "No LOD EntityList - did you build the manual LODs after creating the entity?");
|
---|
| 1382 | // delegate, we're using manual LOD and not the top lod index
|
---|
| 1383 | if (hasSkeleton() && mLodEntityList[mMeshLodIndex - 1]->hasSkeleton())
|
---|
| 1384 | {
|
---|
| 1385 | // Copy the animation state set to lod entity, we assume the lod
|
---|
| 1386 | // entity only has a subset animation states
|
---|
| 1387 | mAnimationState->copyMatchingState(
|
---|
| 1388 | mLodEntityList[mMeshLodIndex - 1]->mAnimationState);
|
---|
| 1389 | }
|
---|
| 1390 | return mLodEntityList[mMeshLodIndex-1]->getShadowVolumeRenderableIterator(
|
---|
| 1391 | shadowTechnique, light, indexBuffer, extrude,
|
---|
| 1392 | extrusionDistance, flags);
|
---|
| 1393 | }
|
---|
| 1394 |
|
---|
| 1395 |
|
---|
| 1396 | // Prepare temp buffers if required
|
---|
| 1397 | if (!mPreparedForShadowVolumes)
|
---|
| 1398 | {
|
---|
| 1399 | mMesh->prepareForShadowVolume();
|
---|
| 1400 | // reset frame last updated to force update of animations if they exist
|
---|
| 1401 | if (mAnimationState)
|
---|
| 1402 | mFrameAnimationLastUpdated = mAnimationState->getDirtyFrameNumber() - 1;
|
---|
| 1403 | // re-prepare buffers
|
---|
| 1404 | prepareTempBlendBuffers();
|
---|
| 1405 | }
|
---|
| 1406 |
|
---|
| 1407 |
|
---|
| 1408 | bool hasAnimation = (hasSkeleton() || hasVertexAnimation());
|
---|
| 1409 |
|
---|
| 1410 | // Update any animation
|
---|
| 1411 | if (hasAnimation)
|
---|
| 1412 | {
|
---|
| 1413 | updateAnimation();
|
---|
| 1414 | }
|
---|
| 1415 |
|
---|
| 1416 | // Calculate the object space light details
|
---|
| 1417 | Vector4 lightPos = light->getAs4DVector();
|
---|
| 1418 | Matrix4 world2Obj = mParentNode->_getFullTransform().inverse();
|
---|
| 1419 | lightPos = world2Obj * lightPos;
|
---|
| 1420 |
|
---|
| 1421 | // We need to search the edge list for silhouette edges
|
---|
| 1422 | EdgeData* edgeList = getEdgeList();
|
---|
| 1423 |
|
---|
| 1424 | if (!edgeList)
|
---|
| 1425 | {
|
---|
| 1426 | // we can't get an edge list for some reason, return blank
|
---|
| 1427 | // really we shouldn't be able to get here, but this is a safeguard
|
---|
| 1428 | return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
|
---|
| 1429 | }
|
---|
| 1430 |
|
---|
| 1431 | // Init shadow renderable list if required
|
---|
| 1432 | bool init = mShadowRenderables.empty();
|
---|
| 1433 |
|
---|
| 1434 | EdgeData::EdgeGroupList::iterator egi;
|
---|
| 1435 | ShadowRenderableList::iterator si, siend;
|
---|
| 1436 | EntityShadowRenderable* esr = 0;
|
---|
| 1437 | if (init)
|
---|
| 1438 | mShadowRenderables.resize(edgeList->edgeGroups.size());
|
---|
| 1439 |
|
---|
| 1440 | bool isAnimated = _isAnimated();
|
---|
| 1441 | bool updatedSharedGeomNormals = false;
|
---|
| 1442 | siend = mShadowRenderables.end();
|
---|
| 1443 | egi = edgeList->edgeGroups.begin();
|
---|
| 1444 | for (si = mShadowRenderables.begin(); si != siend; ++si, ++egi)
|
---|
| 1445 | {
|
---|
| 1446 | const VertexData *pVertData;
|
---|
| 1447 | if (isAnimated)
|
---|
| 1448 | {
|
---|
| 1449 | // Use temp buffers
|
---|
| 1450 | pVertData = findBlendedVertexData(egi->vertexData);
|
---|
| 1451 | }
|
---|
| 1452 | else
|
---|
| 1453 | {
|
---|
| 1454 | pVertData = egi->vertexData;
|
---|
| 1455 | }
|
---|
| 1456 | if (init)
|
---|
| 1457 | {
|
---|
| 1458 | // Try to find corresponding SubEntity; this allows the
|
---|
| 1459 | // linkage of visibility between ShadowRenderable and SubEntity
|
---|
| 1460 | SubEntity* subent = findSubEntityForVertexData(egi->vertexData);
|
---|
| 1461 | // Create a new renderable, create a separate light cap if
|
---|
| 1462 | // we're using a vertex program (either for this model, or
|
---|
| 1463 | // for extruding the shadow volume) since otherwise we can
|
---|
| 1464 | // get depth-fighting on the light cap
|
---|
| 1465 |
|
---|
| 1466 | *si = new EntityShadowRenderable(this, indexBuffer, pVertData,
|
---|
| 1467 | mVertexProgramInUse || !extrude, subent);
|
---|
| 1468 | }
|
---|
| 1469 | else
|
---|
| 1470 | {
|
---|
| 1471 | // If we have animation, we have no guarantee that the position
|
---|
| 1472 | // buffer we used last frame is the same one we used last frame
|
---|
| 1473 | // since a temporary buffer is requested each frame
|
---|
| 1474 | // therefore, we need to update the EntityShadowRenderable
|
---|
| 1475 | // with the current position buffer
|
---|
| 1476 | static_cast<EntityShadowRenderable*>(*si)->rebindPositionBuffer(pVertData, hasAnimation);
|
---|
| 1477 |
|
---|
| 1478 | }
|
---|
| 1479 | // Get shadow renderable
|
---|
| 1480 | esr = static_cast<EntityShadowRenderable*>(*si);
|
---|
| 1481 | HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
|
---|
| 1482 | // For animated entities we need to recalculate the face normals
|
---|
| 1483 | if (hasAnimation)
|
---|
| 1484 | {
|
---|
| 1485 | if (egi->vertexData != mMesh->sharedVertexData || !updatedSharedGeomNormals)
|
---|
| 1486 | {
|
---|
| 1487 | // recalculate face normals
|
---|
| 1488 | edgeList->updateFaceNormals(egi->vertexSet, esrPositionBuffer);
|
---|
| 1489 | // If we're not extruding in software we still need to update
|
---|
| 1490 | // the latter part of the buffer (the hardware extruded part)
|
---|
| 1491 | // with the latest animated positions
|
---|
| 1492 | if (!extrude)
|
---|
| 1493 | {
|
---|
| 1494 | // Lock, we'll be locking the (suppressed hardware update) shadow buffer
|
---|
| 1495 | float* pSrc = static_cast<float*>(
|
---|
| 1496 | esrPositionBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
---|
| 1497 | float* pDest = pSrc + (egi->vertexData->vertexCount * 3);
|
---|
| 1498 | memcpy(pDest, pSrc, sizeof(float) * 3 * egi->vertexData->vertexCount);
|
---|
| 1499 | esrPositionBuffer->unlock();
|
---|
| 1500 | }
|
---|
| 1501 | if (egi->vertexData == mMesh->sharedVertexData)
|
---|
| 1502 | {
|
---|
| 1503 | updatedSharedGeomNormals = true;
|
---|
| 1504 | }
|
---|
| 1505 | }
|
---|
| 1506 | }
|
---|
| 1507 | // Extrude vertices in software if required
|
---|
| 1508 | if (extrude)
|
---|
| 1509 | {
|
---|
| 1510 | extrudeVertices(esrPositionBuffer,
|
---|
| 1511 | egi->vertexData->vertexCount,
|
---|
| 1512 | lightPos, extrusionDistance);
|
---|
| 1513 |
|
---|
| 1514 | }
|
---|
| 1515 | // Stop suppressing hardware update now, if we were
|
---|
| 1516 | esrPositionBuffer->suppressHardwareUpdate(false);
|
---|
| 1517 |
|
---|
| 1518 | }
|
---|
| 1519 | // Calc triangle light facing
|
---|
| 1520 | updateEdgeListLightFacing(edgeList, lightPos);
|
---|
| 1521 |
|
---|
| 1522 | // Generate indexes and update renderables
|
---|
| 1523 | generateShadowVolume(edgeList, *indexBuffer, light,
|
---|
| 1524 | mShadowRenderables, flags);
|
---|
| 1525 |
|
---|
| 1526 |
|
---|
| 1527 | return ShadowRenderableListIterator(mShadowRenderables.begin(), mShadowRenderables.end());
|
---|
| 1528 | }
|
---|
| 1529 | //-----------------------------------------------------------------------
|
---|
| 1530 | const VertexData* Entity::findBlendedVertexData(const VertexData* orig)
|
---|
| 1531 | {
|
---|
| 1532 | bool skel = _isSkeletonAnimated();
|
---|
| 1533 |
|
---|
| 1534 | if (orig == mMesh->sharedVertexData)
|
---|
| 1535 | {
|
---|
| 1536 | return skel? mSkelAnimVertexData : mSoftwareVertexAnimVertexData;
|
---|
| 1537 | }
|
---|
| 1538 | SubEntityList::iterator i, iend;
|
---|
| 1539 | iend = mSubEntityList.end();
|
---|
| 1540 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 1541 | {
|
---|
| 1542 | SubEntity* se = *i;
|
---|
| 1543 | if (orig == se->getSubMesh()->vertexData)
|
---|
| 1544 | {
|
---|
| 1545 | return skel? se->_getSkelAnimVertexData() : se->_getSoftwareVertexAnimVertexData();
|
---|
| 1546 | }
|
---|
| 1547 | }
|
---|
| 1548 | // None found
|
---|
| 1549 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND,
|
---|
| 1550 | "Cannot find blended version of the vertex data specified.",
|
---|
| 1551 | "Entity::findBlendedVertexData");
|
---|
| 1552 | }
|
---|
| 1553 | //-----------------------------------------------------------------------
|
---|
| 1554 | SubEntity* Entity::findSubEntityForVertexData(const VertexData* orig)
|
---|
| 1555 | {
|
---|
| 1556 | if (orig == mMesh->sharedVertexData)
|
---|
| 1557 | {
|
---|
| 1558 | return 0;
|
---|
| 1559 | }
|
---|
| 1560 |
|
---|
| 1561 | SubEntityList::iterator i, iend;
|
---|
| 1562 | iend = mSubEntityList.end();
|
---|
| 1563 | for (i = mSubEntityList.begin(); i != iend; ++i)
|
---|
| 1564 | {
|
---|
| 1565 | SubEntity* se = *i;
|
---|
| 1566 | if (orig == se->getSubMesh()->vertexData)
|
---|
| 1567 | {
|
---|
| 1568 | return se;
|
---|
| 1569 | }
|
---|
| 1570 | }
|
---|
| 1571 |
|
---|
| 1572 | // None found
|
---|
| 1573 | return 0;
|
---|
| 1574 | }
|
---|
| 1575 | //-----------------------------------------------------------------------
|
---|
| 1576 | void Entity::addSoftwareAnimationRequest(bool normalsAlso)
|
---|
| 1577 | {
|
---|
| 1578 | mSoftwareAnimationRequests++;
|
---|
| 1579 | if (normalsAlso) {
|
---|
| 1580 | mSoftwareAnimationNormalsRequests++;
|
---|
| 1581 | }
|
---|
| 1582 | }
|
---|
| 1583 | //-----------------------------------------------------------------------
|
---|
| 1584 | void Entity::removeSoftwareAnimationRequest(bool normalsAlso)
|
---|
| 1585 | {
|
---|
| 1586 | if (mSoftwareAnimationRequests == 0 ||
|
---|
| 1587 | (normalsAlso && mSoftwareAnimationNormalsRequests == 0))
|
---|
| 1588 | {
|
---|
| 1589 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
|
---|
| 1590 | "Attempt to remove nonexistant request.",
|
---|
| 1591 | "Entity::removeSoftwareAnimationRequest");
|
---|
| 1592 | }
|
---|
| 1593 | mSoftwareAnimationRequests--;
|
---|
| 1594 | if (normalsAlso) {
|
---|
| 1595 | mSoftwareAnimationNormalsRequests--;
|
---|
| 1596 | }
|
---|
| 1597 | }
|
---|
| 1598 | //-----------------------------------------------------------------------
|
---|
| 1599 | void Entity::_notifyAttached(Node* parent, bool isTagPoint)
|
---|
| 1600 | {
|
---|
| 1601 | MovableObject::_notifyAttached(parent, isTagPoint);
|
---|
| 1602 | // Also notify LOD entities
|
---|
| 1603 | LODEntityList::iterator i, iend;
|
---|
| 1604 | iend = mLodEntityList.end();
|
---|
| 1605 | for (i = mLodEntityList.begin(); i != iend; ++i)
|
---|
| 1606 | {
|
---|
| 1607 | (*i)->_notifyAttached(parent, isTagPoint);
|
---|
| 1608 | }
|
---|
| 1609 |
|
---|
| 1610 | }
|
---|
| 1611 | //-----------------------------------------------------------------------
|
---|
| 1612 | //-----------------------------------------------------------------------
|
---|
| 1613 | Entity::EntityShadowRenderable::EntityShadowRenderable(Entity* parent,
|
---|
| 1614 | HardwareIndexBufferSharedPtr* indexBuffer, const VertexData* vertexData,
|
---|
| 1615 | bool createSeparateLightCap, SubEntity* subent, bool isLightCap)
|
---|
| 1616 | : mParent(parent), mSubEntity(subent)
|
---|
| 1617 | {
|
---|
| 1618 | // Save link to vertex data
|
---|
| 1619 | mCurrentVertexData = vertexData;
|
---|
| 1620 |
|
---|
| 1621 | // Initialise render op
|
---|
| 1622 | mRenderOp.indexData = new IndexData();
|
---|
| 1623 | mRenderOp.indexData->indexBuffer = *indexBuffer;
|
---|
| 1624 | mRenderOp.indexData->indexStart = 0;
|
---|
| 1625 | // index start and count are sorted out later
|
---|
| 1626 |
|
---|
| 1627 | // Create vertex data which just references position component (and 2 component)
|
---|
| 1628 | mRenderOp.vertexData = new VertexData();
|
---|
| 1629 | mRenderOp.vertexData->vertexDeclaration =
|
---|
| 1630 | HardwareBufferManager::getSingleton().createVertexDeclaration();
|
---|
| 1631 | mRenderOp.vertexData->vertexBufferBinding =
|
---|
| 1632 | HardwareBufferManager::getSingleton().createVertexBufferBinding();
|
---|
| 1633 | // Map in position data
|
---|
| 1634 | mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
|
---|
| 1635 | mOriginalPosBufferBinding =
|
---|
| 1636 | vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
|
---|
| 1637 | mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(mOriginalPosBufferBinding);
|
---|
| 1638 | mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
|
---|
| 1639 | // Map in w-coord buffer (if present)
|
---|
| 1640 | if(!vertexData->hardwareShadowVolWBuffer.isNull())
|
---|
| 1641 | {
|
---|
| 1642 | mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
|
---|
| 1643 | mWBuffer = vertexData->hardwareShadowVolWBuffer;
|
---|
| 1644 | mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
|
---|
| 1645 | }
|
---|
| 1646 | // Use same vertex start as input
|
---|
| 1647 | mRenderOp.vertexData->vertexStart = vertexData->vertexStart;
|
---|
| 1648 |
|
---|
| 1649 | if (isLightCap)
|
---|
| 1650 | {
|
---|
| 1651 | // Use original vertex count, no extrusion
|
---|
| 1652 | mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
|
---|
| 1653 | }
|
---|
| 1654 | else
|
---|
| 1655 | {
|
---|
| 1656 | // Vertex count must take into account the doubling of the buffer,
|
---|
| 1657 | // because second half of the buffer is the extruded copy
|
---|
| 1658 | mRenderOp.vertexData->vertexCount =
|
---|
| 1659 | vertexData->vertexCount * 2;
|
---|
| 1660 | if (createSeparateLightCap)
|
---|
| 1661 | {
|
---|
| 1662 | // Create child light cap
|
---|
| 1663 | mLightCap = new EntityShadowRenderable(parent,
|
---|
| 1664 | indexBuffer, vertexData, false, subent, true);
|
---|
| 1665 | }
|
---|
| 1666 | }
|
---|
| 1667 |
|
---|
| 1668 | }
|
---|
| 1669 | //-----------------------------------------------------------------------
|
---|
| 1670 | Entity::EntityShadowRenderable::~EntityShadowRenderable()
|
---|
| 1671 | {
|
---|
| 1672 | delete mRenderOp.indexData;
|
---|
| 1673 | delete mRenderOp.vertexData;
|
---|
| 1674 | }
|
---|
| 1675 | //-----------------------------------------------------------------------
|
---|
| 1676 | void Entity::EntityShadowRenderable::getWorldTransforms(Matrix4* xform) const
|
---|
| 1677 | {
|
---|
| 1678 | *xform = mParent->_getParentNodeFullTransform();
|
---|
| 1679 | }
|
---|
| 1680 | //-----------------------------------------------------------------------
|
---|
| 1681 | const Quaternion& Entity::EntityShadowRenderable::getWorldOrientation(void) const
|
---|
| 1682 | {
|
---|
| 1683 | return mParent->getParentNode()->_getDerivedOrientation();
|
---|
| 1684 | }
|
---|
| 1685 | //-----------------------------------------------------------------------
|
---|
| 1686 | const Vector3& Entity::EntityShadowRenderable::getWorldPosition(void) const
|
---|
| 1687 | {
|
---|
| 1688 | return mParent->getParentNode()->_getDerivedPosition();
|
---|
| 1689 | }
|
---|
| 1690 | //-----------------------------------------------------------------------
|
---|
| 1691 | void Entity::EntityShadowRenderable::rebindPositionBuffer(const VertexData* vertexData, bool force)
|
---|
| 1692 | {
|
---|
| 1693 | if (force || mCurrentVertexData != vertexData)
|
---|
| 1694 | {
|
---|
| 1695 | mCurrentVertexData = vertexData;
|
---|
| 1696 | mPositionBuffer = mCurrentVertexData->vertexBufferBinding->getBuffer(
|
---|
| 1697 | mOriginalPosBufferBinding);
|
---|
| 1698 | mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
|
---|
| 1699 | if (mLightCap)
|
---|
| 1700 | {
|
---|
| 1701 | static_cast<EntityShadowRenderable*>(mLightCap)->rebindPositionBuffer(vertexData, force);
|
---|
| 1702 | }
|
---|
| 1703 | }
|
---|
| 1704 | }
|
---|
| 1705 | //-----------------------------------------------------------------------
|
---|
| 1706 | bool Entity::EntityShadowRenderable::isVisible(void) const
|
---|
| 1707 | {
|
---|
| 1708 | if (mSubEntity)
|
---|
| 1709 | {
|
---|
| 1710 | return mSubEntity->isVisible();
|
---|
| 1711 | }
|
---|
| 1712 | else
|
---|
| 1713 | {
|
---|
| 1714 | return ShadowRenderable::isVisible();
|
---|
| 1715 | }
|
---|
| 1716 | }
|
---|
| 1717 | //-----------------------------------------------------------------------
|
---|
| 1718 | void Entity::setRenderQueueGroup(uint8 queueID)
|
---|
| 1719 | {
|
---|
| 1720 | MovableObject::setRenderQueueGroup(queueID);
|
---|
| 1721 |
|
---|
| 1722 | // Set render queue for all manual LOD entities
|
---|
| 1723 | if (mMesh->isLodManual())
|
---|
| 1724 | {
|
---|
| 1725 | LODEntityList::iterator li, liend;
|
---|
| 1726 | liend = mLodEntityList.end();
|
---|
| 1727 | for (li = mLodEntityList.begin(); li != liend; ++li)
|
---|
| 1728 | {
|
---|
| 1729 | (*li)->setRenderQueueGroup(queueID);
|
---|
| 1730 | }
|
---|
| 1731 | }
|
---|
| 1732 | }
|
---|
| 1733 | //-----------------------------------------------------------------------
|
---|
| 1734 | void Entity::shareSkeletonInstanceWith(Entity* entity)
|
---|
| 1735 | {
|
---|
| 1736 | if (entity->getMesh()->getSkeleton() != getMesh()->getSkeleton())
|
---|
| 1737 | {
|
---|
| 1738 | OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
|
---|
| 1739 | "The supplied entity has a different skeleton.",
|
---|
| 1740 | "Entity::shareSkeletonWith");
|
---|
| 1741 | }
|
---|
| 1742 | if (!mSkeletonInstance)
|
---|
| 1743 | {
|
---|
| 1744 | OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
|
---|
| 1745 | "This entity has no skeleton.",
|
---|
| 1746 | "Entity::shareSkeletonWith");
|
---|
| 1747 | }
|
---|
| 1748 | if (mSharedSkeletonEntities != NULL && entity->mSharedSkeletonEntities != NULL)
|
---|
| 1749 | {
|
---|
| 1750 | OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
|
---|
| 1751 | "Both entities already shares their SkeletonInstances! At least "
|
---|
| 1752 | "one of the instances must not share it's instance.",
|
---|
| 1753 | "Entity::shareSkeletonWith");
|
---|
| 1754 | }
|
---|
| 1755 |
|
---|
| 1756 | //check if we already share our skeletoninstance, we don't want to delete it if so
|
---|
| 1757 | if (mSharedSkeletonEntities != NULL)
|
---|
| 1758 | {
|
---|
| 1759 | entity->shareSkeletonInstanceWith(this);
|
---|
| 1760 | }
|
---|
| 1761 | else
|
---|
| 1762 | {
|
---|
| 1763 | delete mSkeletonInstance;
|
---|
| 1764 | delete [] mBoneMatrices;
|
---|
| 1765 | delete mAnimationState;
|
---|
| 1766 | delete mFrameBonesLastUpdated;
|
---|
| 1767 | mSkeletonInstance = entity->mSkeletonInstance;
|
---|
| 1768 | mNumBoneMatrices = entity->mNumBoneMatrices;
|
---|
| 1769 | mBoneMatrices = entity->mBoneMatrices;
|
---|
| 1770 | mAnimationState = entity->mAnimationState;
|
---|
| 1771 | mFrameBonesLastUpdated = entity->mFrameBonesLastUpdated;
|
---|
| 1772 | if (entity->mSharedSkeletonEntities == NULL)
|
---|
| 1773 | {
|
---|
| 1774 | entity->mSharedSkeletonEntities = new EntitySet();
|
---|
| 1775 | entity->mSharedSkeletonEntities->insert(entity);
|
---|
| 1776 | }
|
---|
| 1777 | mSharedSkeletonEntities = entity->mSharedSkeletonEntities;
|
---|
| 1778 | mSharedSkeletonEntities->insert(this);
|
---|
| 1779 | }
|
---|
| 1780 |
|
---|
| 1781 | if (mSkelAnimVertexData)
|
---|
| 1782 | {
|
---|
| 1783 | delete mSkelAnimVertexData;
|
---|
| 1784 | mSkelAnimVertexData = 0;
|
---|
| 1785 | }
|
---|
| 1786 | if (mHardwareVertexAnimVertexData)
|
---|
| 1787 | {
|
---|
| 1788 | delete mHardwareVertexAnimVertexData;
|
---|
| 1789 | mHardwareVertexAnimVertexData = 0;
|
---|
| 1790 | }
|
---|
| 1791 | if (mSoftwareVertexAnimVertexData)
|
---|
| 1792 | {
|
---|
| 1793 | delete mSoftwareVertexAnimVertexData;
|
---|
| 1794 | mSoftwareVertexAnimVertexData = 0;
|
---|
| 1795 | }
|
---|
| 1796 |
|
---|
| 1797 |
|
---|
| 1798 | }
|
---|
| 1799 | //-----------------------------------------------------------------------
|
---|
| 1800 | void Entity::stopSharingSkeletonInstance()
|
---|
| 1801 | {
|
---|
| 1802 | if (mSharedSkeletonEntities == NULL)
|
---|
| 1803 | {
|
---|
| 1804 | OGRE_EXCEPT(Exception::ERR_RT_ASSERTION_FAILED,
|
---|
| 1805 | "This entity is not sharing it's skeletoninstance.",
|
---|
| 1806 | "Entity::shareSkeletonWith");
|
---|
| 1807 | }
|
---|
| 1808 | //check if there's no other than us sharing the skeleton instance
|
---|
| 1809 | if (mSharedSkeletonEntities->size() == 1)
|
---|
| 1810 | {
|
---|
| 1811 | //just reset
|
---|
| 1812 | delete mSharedSkeletonEntities;
|
---|
| 1813 | mSharedSkeletonEntities = 0;
|
---|
| 1814 | }
|
---|
| 1815 | else
|
---|
| 1816 | {
|
---|
| 1817 | mSkeletonInstance = new SkeletonInstance(mMesh->getSkeleton());
|
---|
| 1818 | mSkeletonInstance->load();
|
---|
| 1819 | mAnimationState = new AnimationStateSet();
|
---|
| 1820 | mMesh->_initAnimationState(mAnimationState);
|
---|
| 1821 | mFrameBonesLastUpdated = new unsigned long(std::numeric_limits<unsigned long>::max());
|
---|
| 1822 | mNumBoneMatrices = mSkeletonInstance->getNumBones();
|
---|
| 1823 | mBoneMatrices = new Matrix4[mNumBoneMatrices];
|
---|
| 1824 | prepareTempBlendBuffers();
|
---|
| 1825 |
|
---|
| 1826 | mSharedSkeletonEntities->erase(this);
|
---|
| 1827 | if (mSharedSkeletonEntities->size() == 1)
|
---|
| 1828 | {
|
---|
| 1829 | (*mSharedSkeletonEntities->begin())->stopSharingSkeletonInstance();
|
---|
| 1830 | }
|
---|
| 1831 | mSharedSkeletonEntities = 0;
|
---|
| 1832 | }
|
---|
| 1833 | }
|
---|
| 1834 | //-----------------------------------------------------------------------
|
---|
| 1835 | void Entity::refreshAvailableAnimationState(void)
|
---|
| 1836 | {
|
---|
| 1837 | if (hasSkeleton())
|
---|
| 1838 | {
|
---|
| 1839 | mSkeletonInstance->_refreshAnimationState(mAnimationState);
|
---|
| 1840 | }
|
---|
| 1841 | }
|
---|
| 1842 | //-----------------------------------------------------------------------
|
---|
| 1843 | uint32 Entity::getTypeFlags(void) const
|
---|
| 1844 | {
|
---|
| 1845 | return SceneManager::ENTITY_TYPE_MASK;
|
---|
| 1846 | }
|
---|
| 1847 | //-----------------------------------------------------------------------
|
---|
| 1848 | VertexData* Entity::getVertexDataForBinding(void)
|
---|
| 1849 | {
|
---|
| 1850 | Entity::VertexDataBindChoice c =
|
---|
| 1851 | chooseVertexDataForBinding(mMesh->getSharedVertexDataAnimationType() != VAT_NONE);
|
---|
| 1852 | switch(c)
|
---|
| 1853 | {
|
---|
| 1854 | case BIND_ORIGINAL:
|
---|
| 1855 | return mMesh->sharedVertexData;
|
---|
| 1856 | case BIND_HARDWARE_MORPH:
|
---|
| 1857 | return mHardwareVertexAnimVertexData;
|
---|
| 1858 | case BIND_SOFTWARE_MORPH:
|
---|
| 1859 | return mSoftwareVertexAnimVertexData;
|
---|
| 1860 | case BIND_SOFTWARE_SKELETAL:
|
---|
| 1861 | return mSkelAnimVertexData;
|
---|
| 1862 | };
|
---|
| 1863 | // keep compiler happy
|
---|
| 1864 | return mMesh->sharedVertexData;
|
---|
| 1865 | }
|
---|
| 1866 | //-----------------------------------------------------------------------
|
---|
| 1867 | Entity::VertexDataBindChoice Entity::chooseVertexDataForBinding(bool vertexAnim) const
|
---|
| 1868 | {
|
---|
| 1869 | if (!_isAnimated())
|
---|
| 1870 | {
|
---|
| 1871 | // no animation or all animations disabled.
|
---|
| 1872 | return BIND_ORIGINAL;
|
---|
| 1873 | }
|
---|
| 1874 |
|
---|
| 1875 | if (_isSkeletonAnimated())
|
---|
| 1876 | {
|
---|
| 1877 | if (!mHardwareAnimation)
|
---|
| 1878 | {
|
---|
| 1879 | // all software skeletal binds same vertex data
|
---|
| 1880 | // may be a 2-stage s/w transform including morph earlier though
|
---|
| 1881 | return BIND_SOFTWARE_SKELETAL;
|
---|
| 1882 | }
|
---|
| 1883 | else if (vertexAnim)
|
---|
| 1884 | {
|
---|
| 1885 | // hardware morph animation
|
---|
| 1886 | return BIND_HARDWARE_MORPH;
|
---|
| 1887 | }
|
---|
| 1888 | else
|
---|
| 1889 | {
|
---|
| 1890 | // hardware skeletal, no morphing
|
---|
| 1891 | return BIND_ORIGINAL;
|
---|
| 1892 | }
|
---|
| 1893 | }
|
---|
| 1894 | else if (vertexAnim)
|
---|
| 1895 | {
|
---|
| 1896 | // morph only, no skeletal
|
---|
| 1897 | if (mHardwareAnimation)
|
---|
| 1898 | {
|
---|
| 1899 | return BIND_HARDWARE_MORPH;
|
---|
| 1900 | }
|
---|
| 1901 | else
|
---|
| 1902 | {
|
---|
| 1903 | return BIND_SOFTWARE_MORPH;
|
---|
| 1904 | }
|
---|
| 1905 |
|
---|
| 1906 | }
|
---|
| 1907 | else
|
---|
| 1908 | {
|
---|
| 1909 | return BIND_ORIGINAL;
|
---|
| 1910 | }
|
---|
| 1911 |
|
---|
| 1912 | }
|
---|
| 1913 | //-----------------------------------------------------------------------
|
---|
| 1914 | //-----------------------------------------------------------------------
|
---|
| 1915 | String EntityFactory::FACTORY_TYPE_NAME = "Entity";
|
---|
| 1916 | //-----------------------------------------------------------------------
|
---|
| 1917 | const String& EntityFactory::getType(void) const
|
---|
| 1918 | {
|
---|
| 1919 | return FACTORY_TYPE_NAME;
|
---|
| 1920 | }
|
---|
| 1921 | //-----------------------------------------------------------------------
|
---|
| 1922 | MovableObject* EntityFactory::createInstanceImpl( const String& name,
|
---|
| 1923 | const NameValuePairList* params)
|
---|
| 1924 | {
|
---|
| 1925 | // must have mesh parameter
|
---|
| 1926 | MeshPtr pMesh;
|
---|
| 1927 | if (params != 0)
|
---|
| 1928 | {
|
---|
| 1929 | NameValuePairList::const_iterator ni = params->find("mesh");
|
---|
| 1930 | if (ni != params->end())
|
---|
| 1931 | {
|
---|
| 1932 | // Get mesh (load if required)
|
---|
| 1933 | pMesh = MeshManager::getSingleton().load(
|
---|
| 1934 | ni->second,
|
---|
| 1935 | // autodetect group location
|
---|
| 1936 | ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME );
|
---|
| 1937 | }
|
---|
| 1938 |
|
---|
| 1939 | }
|
---|
| 1940 | if (pMesh.isNull())
|
---|
| 1941 | {
|
---|
| 1942 | OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
|
---|
| 1943 | "'mesh' parameter required when constructing an Entity.",
|
---|
| 1944 | "EntityFactory::createInstance");
|
---|
| 1945 | }
|
---|
| 1946 |
|
---|
| 1947 | return new Entity(name, pMesh);
|
---|
| 1948 |
|
---|
| 1949 | }
|
---|
| 1950 | //-----------------------------------------------------------------------
|
---|
| 1951 | void EntityFactory::destroyInstance( MovableObject* obj)
|
---|
| 1952 | {
|
---|
| 1953 | delete obj;
|
---|
| 1954 | }
|
---|
| 1955 |
|
---|
| 1956 |
|
---|
| 1957 | }
|
---|