1 /* 2 ----------------------------------------------------------------------------- 3 This source file is part of OGRE 4 (Object-oriented Graphics Rendering Engine) 5 For the latest info, see http://www.ogre3d.org/ 6 7 Copyright (c) 2000-2014 Torus Knot Software Ltd 8 9 Permission is hereby granted, free of charge, to any person obtaining a copy 10 of this software and associated documentation files (the "Software"), to deal 11 in the Software without restriction, including without limitation the rights 12 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 copies of the Software, and to permit persons to whom the Software is 14 furnished to do so, subject to the following conditions: 15 16 The above copyright notice and this permission notice shall be included in 17 all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 THE SOFTWARE. 26 ----------------------------------------------------------------------------- 27 */ 28 #include "OgreStableHeaders.h" 29 30 #include "OgreSkeletonManager.h" 31 #include "OgreIteratorWrappers.h" 32 #include "OgreEdgeListBuilder.h" 33 #include "OgreAnimation.h" 34 #include "OgreAnimationState.h" 35 #include "OgreAnimationTrack.h" 36 #include "OgreOptimisedUtil.h" 37 #include "OgreTangentSpaceCalc.h" 38 #include "OgreLodStrategyManager.h" 39 #include "OgrePixelCountLodStrategy.h" 40 41 namespace Ogre { 42 //----------------------------------------------------------------------- Mesh(ResourceManager * creator,const String & name,ResourceHandle handle,const String & group,bool isManual,ManualResourceLoader * loader)43 Mesh::Mesh(ResourceManager* creator, const String& name, ResourceHandle handle, 44 const String& group, bool isManual, ManualResourceLoader* loader) 45 : Resource(creator, name, handle, group, isManual, loader), 46 mBoundRadius(0.0f), 47 mBoneBoundingRadius(0.0f), 48 mBoneAssignmentsOutOfDate(false), 49 mLodStrategy(LodStrategyManager::getSingleton().getDefaultStrategy()), 50 mHasManualLodLevel(false), 51 mNumLods(1), 52 mBufferManager(0), 53 mVertexBufferUsage(HardwareBuffer::HBU_STATIC_WRITE_ONLY), 54 mIndexBufferUsage(HardwareBuffer::HBU_STATIC_WRITE_ONLY), 55 mVertexBufferShadowBuffer(false), 56 mIndexBufferShadowBuffer(false), 57 mPreparedForShadowVolumes(false), 58 mEdgeListsBuilt(false), 59 mAutoBuildEdgeLists(true), // will be set to false by serializers of 1.30 and above 60 mSharedVertexDataAnimationType(VAT_NONE), 61 mSharedVertexDataAnimationIncludesNormals(false), 62 mAnimationTypesDirty(true), 63 mPosesIncludeNormals(false), 64 sharedVertexData(0) 65 { 66 // Init first (manual) lod 67 MeshLodUsage lod; 68 lod.userValue = 0; // User value not used for base LOD level 69 lod.value = getLodStrategy()->getBaseValue(); 70 lod.edgeData = NULL; 71 lod.manualMesh.reset(); 72 mMeshLodUsageList.push_back(lod); 73 } 74 //----------------------------------------------------------------------- ~Mesh()75 Mesh::~Mesh() 76 { 77 // have to call this here reather than in Resource destructor 78 // since calling virtual methods in base destructors causes crash 79 unload(); 80 } 81 //----------------------------------------------------------------------- getHardwareBufferManager()82 HardwareBufferManagerBase* Mesh::getHardwareBufferManager() 83 { 84 return mBufferManager ? mBufferManager : HardwareBufferManager::getSingletonPtr(); 85 } 86 //----------------------------------------------------------------------- createSubMesh()87 SubMesh* Mesh::createSubMesh() 88 { 89 SubMesh* sub = OGRE_NEW SubMesh(); 90 sub->parent = this; 91 92 mSubMeshList.push_back(sub); 93 94 if (isLoaded()) 95 _dirtyState(); 96 97 return sub; 98 } 99 //----------------------------------------------------------------------- createSubMesh(const String & name)100 SubMesh* Mesh::createSubMesh(const String& name) 101 { 102 SubMesh *sub = createSubMesh(); 103 nameSubMesh(name, (ushort)mSubMeshList.size()-1); 104 return sub ; 105 } 106 //----------------------------------------------------------------------- destroySubMesh(unsigned short index)107 void Mesh::destroySubMesh(unsigned short index) 108 { 109 if (index >= mSubMeshList.size()) 110 { 111 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 112 "Index out of bounds.", 113 "Mesh::removeSubMesh"); 114 } 115 SubMeshList::iterator i = mSubMeshList.begin(); 116 std::advance(i, index); 117 OGRE_DELETE *i; 118 mSubMeshList.erase(i); 119 120 // Fix up any name/index entries 121 for(SubMeshNameMap::iterator ni = mSubMeshNameMap.begin(); ni != mSubMeshNameMap.end();) 122 { 123 if (ni->second == index) 124 { 125 SubMeshNameMap::iterator eraseIt = ni++; 126 mSubMeshNameMap.erase(eraseIt); 127 } 128 else 129 { 130 // reduce indexes following 131 if (ni->second > index) 132 ni->second = ni->second - 1; 133 134 ++ni; 135 } 136 } 137 138 // fix edge list data by simply recreating all edge lists 139 if( mEdgeListsBuilt) 140 { 141 this->freeEdgeList(); 142 this->buildEdgeList(); 143 } 144 145 if (isLoaded()) 146 _dirtyState(); 147 148 } 149 //----------------------------------------------------------------------- destroySubMesh(const String & name)150 void Mesh::destroySubMesh(const String& name) 151 { 152 unsigned short index = _getSubMeshIndex(name); 153 destroySubMesh(index); 154 } 155 //--------------------------------------------------------------------- nameSubMesh(const String & name,ushort index)156 void Mesh::nameSubMesh(const String& name, ushort index) 157 { 158 mSubMeshNameMap[name] = index ; 159 } 160 161 //--------------------------------------------------------------------- unnameSubMesh(const String & name)162 void Mesh::unnameSubMesh(const String& name) 163 { 164 SubMeshNameMap::iterator i = mSubMeshNameMap.find(name); 165 if (i != mSubMeshNameMap.end()) 166 mSubMeshNameMap.erase(i); 167 } 168 //----------------------------------------------------------------------- getSubMesh(const String & name) const169 SubMesh* Mesh::getSubMesh(const String& name) const 170 { 171 ushort index = _getSubMeshIndex(name); 172 return getSubMesh(index); 173 } 174 //----------------------------------------------------------------------- postLoadImpl(void)175 void Mesh::postLoadImpl(void) 176 { 177 // Prepare for shadow volumes? 178 if (MeshManager::getSingleton().getPrepareAllMeshesForShadowVolumes()) 179 { 180 if (mEdgeListsBuilt || mAutoBuildEdgeLists) 181 { 182 prepareForShadowVolume(); 183 } 184 185 if (!mEdgeListsBuilt && mAutoBuildEdgeLists) 186 { 187 buildEdgeList(); 188 } 189 } 190 #if !OGRE_NO_MESHLOD 191 // The loading process accesses LOD usages directly, so 192 // transformation of user values must occur after loading is complete. 193 194 // Transform user LOD values (starting at index 1, no need to transform base value) 195 for (MeshLodUsageList::iterator i = mMeshLodUsageList.begin() + 1; i != mMeshLodUsageList.end(); ++i) 196 i->value = mLodStrategy->transformUserValue(i->userValue); 197 // Rewrite first value 198 mMeshLodUsageList[0].value = mLodStrategy->getBaseValue(); 199 #endif 200 } 201 //----------------------------------------------------------------------- prepareImpl()202 void Mesh::prepareImpl() 203 { 204 // Load from specified 'name' 205 if (getCreator()->getVerbose()) 206 LogManager::getSingleton().logMessage("Mesh: Loading "+mName+"."); 207 208 mFreshFromDisk = 209 ResourceGroupManager::getSingleton().openResource( 210 mName, mGroup, this); 211 212 // fully prebuffer into host RAM 213 mFreshFromDisk = DataStreamPtr(OGRE_NEW MemoryDataStream(mName,mFreshFromDisk)); 214 } 215 //----------------------------------------------------------------------- unprepareImpl()216 void Mesh::unprepareImpl() 217 { 218 mFreshFromDisk.reset(); 219 } loadImpl()220 void Mesh::loadImpl() 221 { 222 MeshSerializer serializer; 223 serializer.setListener(MeshManager::getSingleton().getListener()); 224 225 // If the only copy is local on the stack, it will be cleaned 226 // up reliably in case of exceptions, etc 227 DataStreamPtr data(mFreshFromDisk); 228 mFreshFromDisk.reset(); 229 230 if (!data) { 231 OGRE_EXCEPT(Exception::ERR_INVALID_STATE, 232 "Data doesn't appear to have been prepared in " + mName, 233 "Mesh::loadImpl()"); 234 } 235 236 serializer.importMesh(data, this); 237 238 /* check all submeshes to see if their materials should be 239 updated. If the submesh has texture aliases that match those 240 found in the current material then a new material is created using 241 the textures from the submesh. 242 */ 243 updateMaterialForAllSubMeshes(); 244 } 245 246 //----------------------------------------------------------------------- unloadImpl()247 void Mesh::unloadImpl() 248 { 249 // Teardown submeshes 250 for (SubMeshList::iterator i = mSubMeshList.begin(); 251 i != mSubMeshList.end(); ++i) 252 { 253 OGRE_DELETE *i; 254 } 255 if (sharedVertexData) 256 { 257 OGRE_DELETE sharedVertexData; 258 sharedVertexData = NULL; 259 } 260 // Clear SubMesh lists 261 mSubMeshList.clear(); 262 mSubMeshNameMap.clear(); 263 264 freeEdgeList(); 265 #if !OGRE_NO_MESHLOD 266 // Removes all LOD data 267 removeLodLevels(); 268 #endif 269 mPreparedForShadowVolumes = false; 270 271 // remove all poses & animations 272 removeAllAnimations(); 273 removeAllPoses(); 274 275 // Clear bone assignments 276 mBoneAssignments.clear(); 277 mBoneAssignmentsOutOfDate = false; 278 279 // Removes reference to skeleton 280 setSkeletonName(BLANKSTRING); 281 } 282 //----------------------------------------------------------------------- reload(LoadingFlags flags)283 void Mesh::reload(LoadingFlags flags) 284 { 285 bool wasPreparedForShadowVolumes = mPreparedForShadowVolumes; 286 bool wasEdgeListsBuilt = mEdgeListsBuilt; 287 bool wasAutoBuildEdgeLists = mAutoBuildEdgeLists; 288 289 Resource::reload(flags); 290 291 if(flags & LF_PRESERVE_STATE) 292 { 293 if(wasPreparedForShadowVolumes) 294 prepareForShadowVolume(); 295 if(wasEdgeListsBuilt) 296 buildEdgeList(); 297 setAutoBuildEdgeLists(wasAutoBuildEdgeLists); 298 } 299 } 300 //----------------------------------------------------------------------- clone(const String & newName,const String & newGroup)301 MeshPtr Mesh::clone(const String& newName, const String& newGroup) 302 { 303 // This is a bit like a copy constructor, but with the additional aspect of registering the clone with 304 // the MeshManager 305 306 // New Mesh is assumed to be manually defined rather than loaded since you're cloning it for a reason 307 String theGroup = newGroup.empty() ? this->getGroup() : newGroup; 308 MeshPtr newMesh = MeshManager::getSingleton().createManual(newName, theGroup); 309 310 if(!newMesh) // interception by collision handler 311 return newMesh; 312 313 newMesh->mBufferManager = mBufferManager; 314 newMesh->mVertexBufferUsage = mVertexBufferUsage; 315 newMesh->mIndexBufferUsage = mIndexBufferUsage; 316 newMesh->mVertexBufferShadowBuffer = mVertexBufferShadowBuffer; 317 newMesh->mIndexBufferShadowBuffer = mIndexBufferShadowBuffer; 318 319 // Copy submeshes first 320 std::vector<SubMesh*>::iterator subi; 321 for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi) 322 { 323 (*subi)->clone("", newMesh.get()); 324 } 325 326 // Copy shared geometry and index map, if any 327 if (sharedVertexData) 328 { 329 newMesh->sharedVertexData = sharedVertexData->clone(true, mBufferManager); 330 newMesh->sharedBlendIndexToBoneIndexMap = sharedBlendIndexToBoneIndexMap; 331 } 332 333 // Copy submesh names 334 newMesh->mSubMeshNameMap = mSubMeshNameMap ; 335 // Copy any bone assignments 336 newMesh->mBoneAssignments = mBoneAssignments; 337 newMesh->mBoneAssignmentsOutOfDate = mBoneAssignmentsOutOfDate; 338 // Copy bounds 339 newMesh->mAABB = mAABB; 340 newMesh->mBoundRadius = mBoundRadius; 341 newMesh->mBoneBoundingRadius = mBoneBoundingRadius; 342 newMesh->mAutoBuildEdgeLists = mAutoBuildEdgeLists; 343 newMesh->mEdgeListsBuilt = mEdgeListsBuilt; 344 345 #if !OGRE_NO_MESHLOD 346 newMesh->mHasManualLodLevel = mHasManualLodLevel; 347 newMesh->mLodStrategy = mLodStrategy; 348 newMesh->mNumLods = mNumLods; 349 newMesh->mMeshLodUsageList = mMeshLodUsageList; 350 #endif 351 // Unreference edge lists, otherwise we'll delete the same lot twice, build on demand 352 MeshLodUsageList::iterator lodi, lodOldi; 353 lodOldi = mMeshLodUsageList.begin(); 354 for (lodi = newMesh->mMeshLodUsageList.begin(); lodi != newMesh->mMeshLodUsageList.end(); ++lodi, ++lodOldi) { 355 MeshLodUsage& newLod = *lodi; 356 MeshLodUsage& lod = *lodOldi; 357 newLod.manualName = lod.manualName; 358 newLod.userValue = lod.userValue; 359 newLod.value = lod.value; 360 if (lod.edgeData) { 361 newLod.edgeData = lod.edgeData->clone(); 362 } 363 } 364 365 newMesh->mSkeletonName = mSkeletonName; 366 newMesh->mSkeleton = mSkeleton; 367 368 // Keep prepared shadow volume info (buffers may already be prepared) 369 newMesh->mPreparedForShadowVolumes = mPreparedForShadowVolumes; 370 371 newMesh->mEdgeListsBuilt = mEdgeListsBuilt; 372 373 // Clone vertex animation 374 for (AnimationList::iterator i = mAnimationsList.begin(); 375 i != mAnimationsList.end(); ++i) 376 { 377 Animation *newAnim = i->second->clone(i->second->getName()); 378 newMesh->mAnimationsList[i->second->getName()] = newAnim; 379 } 380 // Clone pose list 381 for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i) 382 { 383 Pose* newPose = (*i)->clone(); 384 newMesh->mPoseList.push_back(newPose); 385 } 386 newMesh->mSharedVertexDataAnimationType = mSharedVertexDataAnimationType; 387 newMesh->mAnimationTypesDirty = true; 388 389 newMesh->load(); 390 newMesh->touch(); 391 392 return newMesh; 393 } 394 //----------------------------------------------------------------------- getBounds(void) const395 const AxisAlignedBox& Mesh::getBounds(void) const 396 { 397 return mAABB; 398 } 399 //----------------------------------------------------------------------- _setBounds(const AxisAlignedBox & bounds,bool pad)400 void Mesh::_setBounds(const AxisAlignedBox& bounds, bool pad) 401 { 402 mAABB = bounds; 403 mBoundRadius = Math::boundingRadiusFromAABB(mAABB); 404 405 if( mAABB.isFinite() ) 406 { 407 Vector3 max = mAABB.getMaximum(); 408 Vector3 min = mAABB.getMinimum(); 409 410 if (pad) 411 { 412 // Pad out the AABB a little, helps with most bounds tests 413 Vector3 scaler = (max - min) * MeshManager::getSingleton().getBoundsPaddingFactor(); 414 mAABB.setExtents(min - scaler, max + scaler); 415 // Pad out the sphere a little too 416 mBoundRadius = mBoundRadius + (mBoundRadius * MeshManager::getSingleton().getBoundsPaddingFactor()); 417 } 418 } 419 } 420 //----------------------------------------------------------------------- _setBoundingSphereRadius(Real radius)421 void Mesh::_setBoundingSphereRadius(Real radius) 422 { 423 mBoundRadius = radius; 424 } 425 //----------------------------------------------------------------------- _setBoneBoundingRadius(Real radius)426 void Mesh::_setBoneBoundingRadius(Real radius) 427 { 428 mBoneBoundingRadius = radius; 429 } 430 //----------------------------------------------------------------------- _updateBoundsFromVertexBuffers(bool pad)431 void Mesh::_updateBoundsFromVertexBuffers(bool pad) 432 { 433 bool extendOnly = false; // First time we need full AABB of the given submesh, but on the second call just extend that one. 434 if (sharedVertexData){ 435 _calcBoundsFromVertexBuffer(sharedVertexData, mAABB, mBoundRadius, extendOnly); 436 extendOnly = true; 437 } 438 for (size_t i = 0; i < mSubMeshList.size(); i++){ 439 if (mSubMeshList[i]->vertexData){ 440 _calcBoundsFromVertexBuffer(mSubMeshList[i]->vertexData, mAABB, mBoundRadius, extendOnly); 441 extendOnly = true; 442 } 443 } 444 if (pad) 445 { 446 Vector3 max = mAABB.getMaximum(); 447 Vector3 min = mAABB.getMinimum(); 448 // Pad out the AABB a little, helps with most bounds tests 449 Vector3 scaler = (max - min) * MeshManager::getSingleton().getBoundsPaddingFactor(); 450 mAABB.setExtents(min - scaler, max + scaler); 451 // Pad out the sphere a little too 452 mBoundRadius = mBoundRadius + (mBoundRadius * MeshManager::getSingleton().getBoundsPaddingFactor()); 453 } 454 } _calcBoundsFromVertexBuffer(VertexData * vertexData,AxisAlignedBox & outAABB,Real & outRadius,bool extendOnly)455 void Mesh::_calcBoundsFromVertexBuffer(VertexData* vertexData, AxisAlignedBox& outAABB, Real& outRadius, bool extendOnly /*= false*/) 456 { 457 if (vertexData->vertexCount == 0) { 458 if (!extendOnly) { 459 outAABB = AxisAlignedBox(Vector3::ZERO, Vector3::ZERO); 460 outRadius = 0; 461 } 462 return; 463 } 464 const VertexElement* elemPos = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 465 HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(elemPos->getSource()); 466 HardwareBufferLockGuard vertexLock(vbuf, HardwareBuffer::HBL_READ_ONLY); 467 unsigned char* vertex = static_cast<unsigned char*>(vertexLock.pData); 468 469 if (!extendOnly){ 470 // init values 471 outRadius = 0; 472 float* pFloat; 473 elemPos->baseVertexPointerToElement(vertex, &pFloat); 474 Vector3 basePos(pFloat[0], pFloat[1], pFloat[2]); 475 outAABB.setExtents(basePos, basePos); 476 } 477 size_t vSize = vbuf->getVertexSize(); 478 unsigned char* vEnd = vertex + vertexData->vertexCount * vSize; 479 Real radiusSqr = outRadius * outRadius; 480 // Loop through all vertices. 481 for (; vertex < vEnd; vertex += vSize) { 482 float* pFloat; 483 elemPos->baseVertexPointerToElement(vertex, &pFloat); 484 Vector3 pos(pFloat[0], pFloat[1], pFloat[2]); 485 outAABB.getMinimum().makeFloor(pos); 486 outAABB.getMaximum().makeCeil(pos); 487 radiusSqr = std::max<Real>(radiusSqr, pos.squaredLength()); 488 } 489 outRadius = std::sqrt(radiusSqr); 490 } 491 //----------------------------------------------------------------------- setSkeletonName(const String & skelName)492 void Mesh::setSkeletonName(const String& skelName) 493 { 494 if (skelName != mSkeletonName) 495 { 496 mSkeletonName = skelName; 497 498 if (skelName.empty()) 499 { 500 // No skeleton 501 mSkeleton.reset(); 502 } 503 else 504 { 505 // Load skeleton 506 try { 507 mSkeleton = static_pointer_cast<Skeleton>(SkeletonManager::getSingleton().load(skelName, mGroup)); 508 } 509 catch (...) 510 { 511 mSkeleton.reset(); 512 // Log this error 513 String msg = "Unable to load skeleton '"; 514 msg += skelName + "' for Mesh '" + mName 515 + "'. This Mesh will not be animated. " 516 + "You can ignore this message if you are using an offline tool."; 517 LogManager::getSingleton().logError(msg); 518 519 } 520 521 522 } 523 if (isLoaded()) 524 _dirtyState(); 525 } 526 } 527 //----------------------------------------------------------------------- hasSkeleton(void) const528 bool Mesh::hasSkeleton(void) const 529 { 530 return !(mSkeletonName.empty()); 531 } 532 //----------------------------------------------------------------------- getSkeleton(void) const533 const SkeletonPtr& Mesh::getSkeleton(void) const 534 { 535 return mSkeleton; 536 } 537 //----------------------------------------------------------------------- addBoneAssignment(const VertexBoneAssignment & vertBoneAssign)538 void Mesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign) 539 { 540 mBoneAssignments.insert( 541 VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign)); 542 mBoneAssignmentsOutOfDate = true; 543 } 544 //----------------------------------------------------------------------- clearBoneAssignments(void)545 void Mesh::clearBoneAssignments(void) 546 { 547 mBoneAssignments.clear(); 548 mBoneAssignmentsOutOfDate = true; 549 } 550 //----------------------------------------------------------------------- _initAnimationState(AnimationStateSet * animSet)551 void Mesh::_initAnimationState(AnimationStateSet* animSet) 552 { 553 // Animation states for skeletal animation 554 if (mSkeleton) 555 { 556 // Delegate to Skeleton 557 mSkeleton->_initAnimationState(animSet); 558 559 // Take the opportunity to update the compiled bone assignments 560 _updateCompiledBoneAssignments(); 561 562 } 563 564 // Animation states for vertex animation 565 for (AnimationList::iterator i = mAnimationsList.begin(); 566 i != mAnimationsList.end(); ++i) 567 { 568 // Only create a new animation state if it doesn't exist 569 // We can have the same named animation in both skeletal and vertex 570 // with a shared animation state affecting both, for combined effects 571 // The animations should be the same length if this feature is used! 572 if (!animSet->hasAnimationState(i->second->getName())) 573 { 574 animSet->createAnimationState(i->second->getName(), 0.0, 575 i->second->getLength()); 576 } 577 578 } 579 580 } 581 //--------------------------------------------------------------------- _refreshAnimationState(AnimationStateSet * animSet)582 void Mesh::_refreshAnimationState(AnimationStateSet* animSet) 583 { 584 if (mSkeleton) 585 { 586 mSkeleton->_refreshAnimationState(animSet); 587 } 588 589 // Merge in any new vertex animations 590 AnimationList::iterator i; 591 for (i = mAnimationsList.begin(); i != mAnimationsList.end(); ++i) 592 { 593 Animation* anim = i->second; 594 // Create animation at time index 0, default params mean this has weight 1 and is disabled 595 const String& animName = anim->getName(); 596 if (!animSet->hasAnimationState(animName)) 597 { 598 animSet->createAnimationState(animName, 0.0, anim->getLength()); 599 } 600 else 601 { 602 // Update length incase changed 603 AnimationState* animState = animSet->getAnimationState(animName); 604 animState->setLength(anim->getLength()); 605 animState->setTimePosition(std::min(anim->getLength(), animState->getTimePosition())); 606 } 607 } 608 609 } 610 //----------------------------------------------------------------------- _updateCompiledBoneAssignments(void)611 void Mesh::_updateCompiledBoneAssignments(void) 612 { 613 if (mBoneAssignmentsOutOfDate) 614 _compileBoneAssignments(); 615 616 SubMeshList::iterator i; 617 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 618 { 619 if ((*i)->mBoneAssignmentsOutOfDate) 620 { 621 (*i)->_compileBoneAssignments(); 622 } 623 } 624 } 625 //----------------------------------------------------------------------- 626 typedef std::multimap<Real, Mesh::VertexBoneAssignmentList::iterator> WeightIteratorMap; _rationaliseBoneAssignments(size_t vertexCount,Mesh::VertexBoneAssignmentList & assignments)627 unsigned short Mesh::_rationaliseBoneAssignments(size_t vertexCount, Mesh::VertexBoneAssignmentList& assignments) 628 { 629 // Iterate through, finding the largest # bones per vertex 630 unsigned short maxBones = 0; 631 bool existsNonSkinnedVertices = false; 632 VertexBoneAssignmentList::iterator i; 633 634 for (size_t v = 0; v < vertexCount; ++v) 635 { 636 // Get number of entries for this vertex 637 short currBones = static_cast<unsigned short>(assignments.count(v)); 638 if (currBones <= 0) 639 existsNonSkinnedVertices = true; 640 641 // Deal with max bones update 642 // (note this will record maxBones even if they exceed limit) 643 if (maxBones < currBones) 644 maxBones = currBones; 645 // does the number of bone assignments exceed limit? 646 if (currBones > OGRE_MAX_BLEND_WEIGHTS) 647 { 648 // To many bone assignments on this vertex 649 // Find the start & end (end is in iterator terms ie exclusive) 650 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> range; 651 // map to sort by weight 652 WeightIteratorMap weightToAssignmentMap; 653 range = assignments.equal_range(v); 654 // Add all the assignments to map 655 for (i = range.first; i != range.second; ++i) 656 { 657 // insert value weight->iterator 658 weightToAssignmentMap.insert( 659 WeightIteratorMap::value_type(i->second.weight, i)); 660 } 661 // Reverse iterate over weight map, remove lowest n 662 unsigned short numToRemove = currBones - OGRE_MAX_BLEND_WEIGHTS; 663 WeightIteratorMap::iterator remIt = weightToAssignmentMap.begin(); 664 665 while (numToRemove--) 666 { 667 // Erase this one 668 assignments.erase(remIt->second); 669 ++remIt; 670 } 671 } // if (currBones > OGRE_MAX_BLEND_WEIGHTS) 672 673 // Make sure the weights are normalised 674 // Do this irrespective of whether we had to remove assignments or not 675 // since it gives us a guarantee that weights are normalised 676 // We assume this, so it's a good idea since some modellers may not 677 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> normalise_range = assignments.equal_range(v); 678 Real totalWeight = 0; 679 // Find total first 680 for (i = normalise_range.first; i != normalise_range.second; ++i) 681 { 682 totalWeight += i->second.weight; 683 } 684 // Now normalise if total weight is outside tolerance 685 if (!Math::RealEqual(totalWeight, 1.0f)) 686 { 687 for (i = normalise_range.first; i != normalise_range.second; ++i) 688 { 689 i->second.weight = i->second.weight / totalWeight; 690 } 691 } 692 693 } 694 695 if (maxBones > OGRE_MAX_BLEND_WEIGHTS) 696 { 697 // Warn that we've reduced bone assignments 698 LogManager::getSingleton().logWarning("the mesh '" + mName + "' " 699 "includes vertices with more than " + 700 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + " bone assignments. " 701 "The lowest weighted assignments beyond this limit have been removed, so " 702 "your animation may look slightly different. To eliminate this, reduce " 703 "the number of bone assignments per vertex on your mesh to " + 704 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + "."); 705 // we've adjusted them down to the max 706 maxBones = OGRE_MAX_BLEND_WEIGHTS; 707 708 } 709 710 if (existsNonSkinnedVertices) 711 { 712 // Warn that we've non-skinned vertices 713 LogManager::getSingleton().logWarning("the mesh '" + mName + "' " 714 "includes vertices without bone assignments. Those vertices will " 715 "transform to wrong position when skeletal animation enabled. " 716 "To eliminate this, assign at least one bone assignment per vertex " 717 "on your mesh."); 718 } 719 720 return maxBones; 721 } 722 //----------------------------------------------------------------------- _compileBoneAssignments(void)723 void Mesh::_compileBoneAssignments(void) 724 { 725 if (sharedVertexData) 726 { 727 unsigned short maxBones = _rationaliseBoneAssignments(sharedVertexData->vertexCount, mBoneAssignments); 728 729 if (maxBones != 0) 730 { 731 compileBoneAssignments(mBoneAssignments, maxBones, 732 sharedBlendIndexToBoneIndexMap, sharedVertexData); 733 } 734 } 735 mBoneAssignmentsOutOfDate = false; 736 } 737 //--------------------------------------------------------------------- buildIndexMap(const VertexBoneAssignmentList & boneAssignments,IndexMap & boneIndexToBlendIndexMap,IndexMap & blendIndexToBoneIndexMap)738 void Mesh::buildIndexMap(const VertexBoneAssignmentList& boneAssignments, 739 IndexMap& boneIndexToBlendIndexMap, IndexMap& blendIndexToBoneIndexMap) 740 { 741 if (boneAssignments.empty()) 742 { 743 // Just in case 744 boneIndexToBlendIndexMap.clear(); 745 blendIndexToBoneIndexMap.clear(); 746 return; 747 } 748 749 typedef std::set<unsigned short> BoneIndexSet; 750 BoneIndexSet usedBoneIndices; 751 752 // Collect actually used bones 753 VertexBoneAssignmentList::const_iterator itVBA, itendVBA; 754 itendVBA = boneAssignments.end(); 755 for (itVBA = boneAssignments.begin(); itVBA != itendVBA; ++itVBA) 756 { 757 usedBoneIndices.insert(itVBA->second.boneIndex); 758 } 759 760 // Allocate space for index map 761 blendIndexToBoneIndexMap.resize(usedBoneIndices.size()); 762 boneIndexToBlendIndexMap.resize(*usedBoneIndices.rbegin() + 1); 763 764 // Make index map between bone index and blend index 765 BoneIndexSet::const_iterator itBoneIndex, itendBoneIndex; 766 unsigned short blendIndex = 0; 767 itendBoneIndex = usedBoneIndices.end(); 768 for (itBoneIndex = usedBoneIndices.begin(); itBoneIndex != itendBoneIndex; ++itBoneIndex, ++blendIndex) 769 { 770 boneIndexToBlendIndexMap[*itBoneIndex] = blendIndex; 771 blendIndexToBoneIndexMap[blendIndex] = *itBoneIndex; 772 } 773 } 774 //--------------------------------------------------------------------- compileBoneAssignments(const VertexBoneAssignmentList & boneAssignments,unsigned short numBlendWeightsPerVertex,IndexMap & blendIndexToBoneIndexMap,VertexData * targetVertexData)775 void Mesh::compileBoneAssignments( 776 const VertexBoneAssignmentList& boneAssignments, 777 unsigned short numBlendWeightsPerVertex, 778 IndexMap& blendIndexToBoneIndexMap, 779 VertexData* targetVertexData) 780 { 781 // Create or reuse blend weight / indexes buffer 782 // Indices are always a UBYTE4 no matter how many weights per vertex 783 VertexDeclaration* decl = targetVertexData->vertexDeclaration; 784 VertexBufferBinding* bind = targetVertexData->vertexBufferBinding; 785 unsigned short bindIndex; 786 787 // Build the index map brute-force. It's possible to store the index map 788 // in .mesh, but maybe trivial. 789 IndexMap boneIndexToBlendIndexMap; 790 buildIndexMap(boneAssignments, boneIndexToBlendIndexMap, blendIndexToBoneIndexMap); 791 792 const VertexElement* testElem = 793 decl->findElementBySemantic(VES_BLEND_INDICES); 794 if (testElem) 795 { 796 // Already have a buffer, unset it & delete elements 797 bindIndex = testElem->getSource(); 798 // unset will cause deletion of buffer 799 bind->unsetBinding(bindIndex); 800 decl->removeElement(VES_BLEND_INDICES); 801 decl->removeElement(VES_BLEND_WEIGHTS); 802 } 803 else 804 { 805 // Get new binding 806 bindIndex = bind->getNextIndex(); 807 } 808 // type of Weights is settable on the MeshManager. 809 VertexElementType weightsBaseType = MeshManager::getSingleton().getBlendWeightsBaseElementType(); 810 VertexElementType weightsVertexElemType = VertexElement::multiplyTypeCount( weightsBaseType, numBlendWeightsPerVertex ); 811 HardwareVertexBufferSharedPtr vbuf = getHardwareBufferManager()->createVertexBuffer( 812 sizeof( unsigned char ) * 4 + VertexElement::getTypeSize( weightsVertexElemType ), 813 targetVertexData->vertexCount, 814 HardwareBuffer::HBU_STATIC_WRITE_ONLY, 815 true // use shadow buffer 816 ); 817 // bind new buffer 818 bind->setBinding(bindIndex, vbuf); 819 const VertexElement *pIdxElem, *pWeightElem; 820 821 // add new vertex elements 822 // Note, insert directly after all elements using the same source as 823 // position to abide by pre-Dx9 format restrictions 824 const VertexElement* firstElem = decl->getElement(0); 825 if(firstElem->getSemantic() == VES_POSITION) 826 { 827 unsigned short insertPoint = 1; 828 while (insertPoint < decl->getElementCount() && 829 decl->getElement(insertPoint)->getSource() == firstElem->getSource()) 830 { 831 ++insertPoint; 832 } 833 const VertexElement& idxElem = 834 decl->insertElement(insertPoint, bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 835 const VertexElement& wtElem = 836 decl->insertElement(insertPoint+1, bindIndex, sizeof(unsigned char)*4, weightsVertexElemType, VES_BLEND_WEIGHTS); 837 pIdxElem = &idxElem; 838 pWeightElem = &wtElem; 839 } 840 else 841 { 842 // Position is not the first semantic, therefore this declaration is 843 // not pre-Dx9 compatible anyway, so just tack it on the end 844 const VertexElement& idxElem = 845 decl->addElement(bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 846 const VertexElement& wtElem = 847 decl->addElement(bindIndex, sizeof(unsigned char)*4, weightsVertexElemType, VES_BLEND_WEIGHTS ); 848 pIdxElem = &idxElem; 849 pWeightElem = &wtElem; 850 } 851 852 unsigned int maxIntWt = 0; 853 // keeping a switch out of the loop 854 switch ( weightsBaseType ) 855 { 856 default: 857 OgreAssert(false, "Invalid BlendWeightsBaseElementType"); 858 break; 859 case VET_FLOAT1: 860 break; 861 case VET_UBYTE4_NORM: 862 maxIntWt = 0xff; 863 break; 864 case VET_USHORT2_NORM: 865 maxIntWt = 0xffff; 866 break; 867 case VET_SHORT2_NORM: 868 maxIntWt = 0x7fff; 869 break; 870 } 871 // Assign data 872 size_t v; 873 VertexBoneAssignmentList::const_iterator i, iend; 874 i = boneAssignments.begin(); 875 iend = boneAssignments.end(); 876 HardwareBufferLockGuard vertexLock(vbuf, HardwareBuffer::HBL_DISCARD); 877 unsigned char *pBase = static_cast<unsigned char*>(vertexLock.pData); 878 // Iterate by vertex 879 for (v = 0; v < targetVertexData->vertexCount; ++v) 880 { 881 // collect the indices/weights in these arrays 882 unsigned char indices[ 4 ] = { 0, 0, 0, 0 }; 883 float weights[ 4 ] = { 1.0f, 0.0f, 0.0f, 0.0f }; 884 for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone) 885 { 886 // Do we still have data for this vertex? 887 if (i != iend && i->second.vertexIndex == v) 888 { 889 // If so, grab weight and index 890 weights[ bone ] = i->second.weight; 891 indices[ bone ] = static_cast<unsigned char>( boneIndexToBlendIndexMap[ i->second.boneIndex ] ); 892 ++i; 893 } 894 } 895 // if weights are integers, 896 if ( weightsBaseType != VET_FLOAT1 ) 897 { 898 // pack the float weights into shorts/bytes 899 unsigned int intWeights[ 4 ]; 900 unsigned int sum = 0; 901 const unsigned int wtScale = maxIntWt; // this value corresponds to a weight of 1.0 902 for ( int ii = 0; ii < 4; ++ii ) 903 { 904 unsigned int bw = static_cast<unsigned int>( weights[ ii ] * wtScale ); 905 intWeights[ ii ] = bw; 906 sum += bw; 907 } 908 // if the sum doesn't add up due to roundoff error, we need to adjust the intWeights so that the sum is wtScale 909 if ( sum != maxIntWt ) 910 { 911 // find the largest weight (it isn't necessarily the first one...) 912 int iMaxWeight = 0; 913 unsigned int maxWeight = 0; 914 for ( int ii = 0; ii < 4; ++ii ) 915 { 916 unsigned int bw = intWeights[ ii ]; 917 if ( bw > maxWeight ) 918 { 919 iMaxWeight = ii; 920 maxWeight = bw; 921 } 922 } 923 // Adjust the largest weight to make sure the sum is correct. 924 // The idea is that changing the largest weight will have the smallest effect 925 // on the ratio of weights. This works best when there is one dominant weight, 926 // and worst when 2 or more weights are similar in magnitude. 927 // A better method could be used to reduce the quantization error, but this is 928 // being done at run-time so it needs to be quick. 929 intWeights[ iMaxWeight ] += maxIntWt - sum; 930 } 931 932 // now write the weights 933 if ( weightsBaseType == VET_UBYTE4_NORM ) 934 { 935 // write out the weights as bytes 936 unsigned char* pWeight; 937 pWeightElem->baseVertexPointerToElement( pBase, &pWeight ); 938 // NOTE: always writes out 4 regardless of numBlendWeightsPerVertex 939 for ( int ii = 0; ii < 4; ++ii ) 940 { 941 *pWeight++ = static_cast<unsigned char>( intWeights[ ii ] ); 942 } 943 } 944 else 945 { 946 // write out the weights as shorts 947 unsigned short* pWeight; 948 pWeightElem->baseVertexPointerToElement( pBase, &pWeight ); 949 for ( int ii = 0; ii < numBlendWeightsPerVertex; ++ii ) 950 { 951 *pWeight++ = static_cast<unsigned short>( intWeights[ ii ] ); 952 } 953 } 954 } 955 else 956 { 957 // write out the weights as floats 958 float* pWeight; 959 pWeightElem->baseVertexPointerToElement( pBase, &pWeight ); 960 for ( int ii = 0; ii < numBlendWeightsPerVertex; ++ii ) 961 { 962 *pWeight++ = weights[ ii ]; 963 } 964 } 965 unsigned char* pIndex; 966 pIdxElem->baseVertexPointerToElement( pBase, &pIndex ); 967 for ( int ii = 0; ii < 4; ++ii ) 968 { 969 *pIndex++ = indices[ ii ]; 970 } 971 pBase += vbuf->getVertexSize(); 972 } 973 } 974 //--------------------------------------------------------------------- distLineSegToPoint(const Vector3 & line0,const Vector3 & line1,const Vector3 & pt)975 static Real distLineSegToPoint( const Vector3& line0, const Vector3& line1, const Vector3& pt ) 976 { 977 Vector3 v01 = line1 - line0; 978 Real tt = v01.dotProduct( pt - line0 ) / std::max( v01.dotProduct(v01), std::numeric_limits<Real>::epsilon() ); 979 tt = Math::Clamp( tt, Real(0.0f), Real(1.0f) ); 980 Vector3 onLine = line0 + tt * v01; 981 return pt.distance( onLine ); 982 } 983 //--------------------------------------------------------------------- _computeBoneBoundingRadiusHelper(VertexData * vertexData,const Mesh::VertexBoneAssignmentList & boneAssignments,const std::vector<Vector3> & bonePositions,const std::vector<std::vector<ushort>> & boneChildren)984 static Real _computeBoneBoundingRadiusHelper( VertexData* vertexData, 985 const Mesh::VertexBoneAssignmentList& boneAssignments, 986 const std::vector<Vector3>& bonePositions, 987 const std::vector< std::vector<ushort> >& boneChildren 988 ) 989 { 990 std::vector<Vector3> vertexPositions; 991 { 992 // extract vertex positions 993 const VertexElement* posElem = vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 994 HardwareVertexBufferSharedPtr vbuf = vertexData->vertexBufferBinding->getBuffer(posElem->getSource()); 995 // if usage is write only, 996 if ( !vbuf->hasShadowBuffer() && (vbuf->getUsage() & HardwareBuffer::HBU_WRITE_ONLY) ) 997 { 998 // can't do it 999 return Real(0.0f); 1000 } 1001 vertexPositions.resize( vertexData->vertexCount ); 1002 HardwareBufferLockGuard vertexLock(vbuf, HardwareBuffer::HBL_READ_ONLY); 1003 unsigned char* vertex = static_cast<unsigned char*>(vertexLock.pData); 1004 float* pFloat; 1005 1006 for(size_t i = 0; i < vertexData->vertexCount; ++i) 1007 { 1008 posElem->baseVertexPointerToElement(vertex, &pFloat); 1009 vertexPositions[ i ] = Vector3( pFloat[0], pFloat[1], pFloat[2] ); 1010 vertex += vbuf->getVertexSize(); 1011 } 1012 } 1013 Real maxRadius = Real(0); 1014 Real minWeight = Real(0.01); 1015 // for each vertex-bone assignment, 1016 for (Mesh::VertexBoneAssignmentList::const_iterator i = boneAssignments.begin(); i != boneAssignments.end(); ++i) 1017 { 1018 // if weight is close to zero, ignore 1019 if (i->second.weight > minWeight) 1020 { 1021 // if we have a bounding box around all bone origins, we consider how far outside this box the 1022 // current vertex could ever get (assuming it is only attached to the given bone, and the bones all have unity scale) 1023 size_t iBone = i->second.boneIndex; 1024 const Vector3& v = vertexPositions[ i->second.vertexIndex ]; 1025 Vector3 diff = v - bonePositions[ iBone ]; 1026 Real dist = diff.length(); // max distance of vertex v outside of bounding box 1027 // if this bone has children, we can reduce the dist under the assumption that the children may rotate wrt their parent, but don't translate 1028 for (size_t iChild = 0; iChild < boneChildren[iBone].size(); ++iChild) 1029 { 1030 // given this assumption, we know that the bounding box will enclose both the bone origin as well as the origin of the child bone, 1031 // and therefore everything on a line segment between the bone origin and the child bone will be inside the bounding box as well 1032 size_t iChildBone = boneChildren[ iBone ][ iChild ]; 1033 // compute distance from vertex to line segment between bones 1034 Real distChild = distLineSegToPoint( bonePositions[ iBone ], bonePositions[ iChildBone ], v ); 1035 dist = std::min( dist, distChild ); 1036 } 1037 // scale the distance by the weight, this prevents the radius from being over-inflated because of a vertex that is lightly influenced by a faraway bone 1038 dist *= i->second.weight; 1039 maxRadius = std::max( maxRadius, dist ); 1040 } 1041 } 1042 return maxRadius; 1043 } 1044 //--------------------------------------------------------------------- _computeBoneBoundingRadius()1045 void Mesh::_computeBoneBoundingRadius() 1046 { 1047 if (mBoneBoundingRadius == Real(0) && mSkeleton) 1048 { 1049 Real radius = Real(0); 1050 std::vector<Vector3> bonePositions; 1051 std::vector< std::vector<ushort> > boneChildren; // for each bone, a list of children 1052 { 1053 // extract binding pose bone positions, and also indices for child bones 1054 uint16 numBones = mSkeleton->getNumBones(); 1055 mSkeleton->setBindingPose(); 1056 mSkeleton->_updateTransforms(); 1057 bonePositions.resize( numBones ); 1058 boneChildren.resize( numBones ); 1059 // for each bone, 1060 for (uint16 iBone = 0; iBone < numBones; ++iBone) 1061 { 1062 Bone* bone = mSkeleton->getBone( iBone ); 1063 bonePositions[ iBone ] = bone->_getDerivedPosition(); 1064 boneChildren[ iBone ].reserve( bone->numChildren() ); 1065 for (uint16 iChild = 0; iChild < bone->numChildren(); ++iChild) 1066 { 1067 Bone* child = static_cast<Bone*>( bone->getChild( iChild ) ); 1068 boneChildren[ iBone ].push_back( child->getHandle() ); 1069 } 1070 } 1071 } 1072 if (sharedVertexData) 1073 { 1074 // check shared vertices 1075 radius = _computeBoneBoundingRadiusHelper(sharedVertexData, mBoneAssignments, bonePositions, boneChildren); 1076 } 1077 1078 // check submesh vertices 1079 SubMeshList::const_iterator itor = mSubMeshList.begin(); 1080 SubMeshList::const_iterator end = mSubMeshList.end(); 1081 1082 while( itor != end ) 1083 { 1084 SubMesh* submesh = *itor; 1085 if (!submesh->useSharedVertices && submesh->vertexData) 1086 { 1087 Real r = _computeBoneBoundingRadiusHelper(submesh->vertexData, submesh->mBoneAssignments, bonePositions, boneChildren); 1088 radius = std::max( radius, r ); 1089 } 1090 ++itor; 1091 } 1092 if (radius > Real(0)) 1093 { 1094 mBoneBoundingRadius = radius; 1095 } 1096 else 1097 { 1098 // fallback if we failed to find the vertices 1099 mBoneBoundingRadius = mBoundRadius; 1100 } 1101 } 1102 } 1103 //--------------------------------------------------------------------- _notifySkeleton(SkeletonPtr & pSkel)1104 void Mesh::_notifySkeleton(SkeletonPtr& pSkel) 1105 { 1106 mSkeleton = pSkel; 1107 mSkeletonName = pSkel->getName(); 1108 } 1109 //--------------------------------------------------------------------- getBoneAssignmentIterator(void)1110 Mesh::BoneAssignmentIterator Mesh::getBoneAssignmentIterator(void) 1111 { 1112 return BoneAssignmentIterator(mBoneAssignments.begin(), 1113 mBoneAssignments.end()); 1114 } 1115 //--------------------------------------------------------------------- getSkeletonName(void) const1116 const String& Mesh::getSkeletonName(void) const 1117 { 1118 return mSkeletonName; 1119 } 1120 //--------------------------------------------------------------------- getNumLodLevels(void) const1121 ushort Mesh::getNumLodLevels(void) const 1122 { 1123 return mNumLods; 1124 } 1125 //--------------------------------------------------------------------- getLodLevel(ushort index) const1126 const MeshLodUsage& Mesh::getLodLevel(ushort index) const 1127 { 1128 #if !OGRE_NO_MESHLOD 1129 index = std::min(index, (ushort)(mMeshLodUsageList.size() - 1)); 1130 if (this->_isManualLodLevel(index) && index > 0 && !mMeshLodUsageList[index].manualMesh) 1131 { 1132 // Load the mesh now 1133 try { 1134 mMeshLodUsageList[index].manualMesh = 1135 MeshManager::getSingleton().load( 1136 mMeshLodUsageList[index].manualName, 1137 getGroup()); 1138 // get the edge data, if required 1139 if (!mMeshLodUsageList[index].edgeData) 1140 { 1141 mMeshLodUsageList[index].edgeData = 1142 mMeshLodUsageList[index].manualMesh->getEdgeList(0); 1143 } 1144 } 1145 catch (Exception& ) 1146 { 1147 LogManager::getSingleton().stream() 1148 << "Error while loading manual LOD level " 1149 << mMeshLodUsageList[index].manualName 1150 << " - this LOD level will not be rendered. You can " 1151 << "ignore this error in offline mesh tools."; 1152 } 1153 1154 } 1155 return mMeshLodUsageList[index]; 1156 #else 1157 return mMeshLodUsageList[0]; 1158 #endif 1159 } 1160 //--------------------------------------------------------------------- getLodIndex(Real value) const1161 ushort Mesh::getLodIndex(Real value) const 1162 { 1163 #if !OGRE_NO_MESHLOD 1164 // Get index from strategy 1165 return mLodStrategy->getIndex(value, mMeshLodUsageList); 1166 #else 1167 return 0; 1168 #endif 1169 } 1170 //--------------------------------------------------------------------- 1171 #if !OGRE_NO_MESHLOD updateManualLodLevel(ushort index,const String & meshName)1172 void Mesh::updateManualLodLevel(ushort index, const String& meshName) 1173 { 1174 1175 // Basic prerequisites 1176 assert(index != 0 && "Can't modify first LOD level (full detail)"); 1177 assert(index < mMeshLodUsageList.size() && "Idndex out of bounds"); 1178 // get lod 1179 MeshLodUsage* lod = &(mMeshLodUsageList[index]); 1180 1181 lod->manualName = meshName; 1182 lod->manualMesh.reset(); 1183 OGRE_DELETE lod->edgeData; 1184 lod->edgeData = 0; 1185 } 1186 //--------------------------------------------------------------------- _setLodInfo(unsigned short numLevels)1187 void Mesh::_setLodInfo(unsigned short numLevels) 1188 { 1189 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 1190 1191 // Basic prerequisites 1192 assert(numLevels > 0 && "Must be at least one level (full detail level must exist)"); 1193 1194 mNumLods = numLevels; 1195 mMeshLodUsageList.resize(numLevels); 1196 // Resize submesh face data lists too 1197 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 1198 { 1199 (*i)->mLodFaceList.resize(numLevels - 1); 1200 } 1201 } 1202 //--------------------------------------------------------------------- _setLodUsage(unsigned short level,const MeshLodUsage & usage)1203 void Mesh::_setLodUsage(unsigned short level, const MeshLodUsage& usage) 1204 { 1205 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 1206 1207 // Basic prerequisites 1208 assert(level != 0 && "Can't modify first LOD level (full detail)"); 1209 assert(level < mMeshLodUsageList.size() && "Index out of bounds"); 1210 1211 mMeshLodUsageList[level] = usage; 1212 1213 if(!mMeshLodUsageList[level].manualName.empty()){ 1214 mHasManualLodLevel = true; 1215 } 1216 } 1217 //--------------------------------------------------------------------- _setSubMeshLodFaceList(unsigned short subIdx,unsigned short level,IndexData * facedata)1218 void Mesh::_setSubMeshLodFaceList(unsigned short subIdx, unsigned short level, 1219 IndexData* facedata) 1220 { 1221 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 1222 1223 // Basic prerequisites 1224 assert(mMeshLodUsageList[level].manualName.empty() && "Not using generated LODs!"); 1225 assert(subIdx < mSubMeshList.size() && "Index out of bounds"); 1226 assert(level != 0 && "Can't modify first LOD level (full detail)"); 1227 assert(level-1 < (unsigned short)mSubMeshList[subIdx]->mLodFaceList.size() && "Index out of bounds"); 1228 1229 SubMesh* sm = mSubMeshList[subIdx]; 1230 sm->mLodFaceList[level - 1] = facedata; 1231 } 1232 #endif 1233 //--------------------------------------------------------------------- _isManualLodLevel(unsigned short level) const1234 bool Mesh::_isManualLodLevel( unsigned short level ) const 1235 { 1236 #if !OGRE_NO_MESHLOD 1237 return !mMeshLodUsageList[level].manualName.empty(); 1238 #else 1239 return false; 1240 #endif 1241 } 1242 //--------------------------------------------------------------------- _getSubMeshIndex(const String & name) const1243 ushort Mesh::_getSubMeshIndex(const String& name) const 1244 { 1245 SubMeshNameMap::const_iterator i = mSubMeshNameMap.find(name) ; 1246 if (i == mSubMeshNameMap.end()) 1247 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No SubMesh named " + name + " found.", 1248 "Mesh::_getSubMeshIndex"); 1249 1250 return i->second; 1251 } 1252 //-------------------------------------------------------------------- removeLodLevels(void)1253 void Mesh::removeLodLevels(void) 1254 { 1255 #if !OGRE_NO_MESHLOD 1256 // Remove data from SubMeshes 1257 SubMeshList::iterator isub, isubend; 1258 isubend = mSubMeshList.end(); 1259 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 1260 { 1261 (*isub)->removeLodLevels(); 1262 } 1263 1264 bool edgeListWasBuilt = isEdgeListBuilt(); 1265 freeEdgeList(); 1266 1267 // Reinitialise 1268 mNumLods = 1; 1269 mMeshLodUsageList.resize(1); 1270 mMeshLodUsageList[0].edgeData = NULL; 1271 1272 if(edgeListWasBuilt) 1273 buildEdgeList(); 1274 #endif 1275 } 1276 1277 //--------------------------------------------------------------------- getBoundingSphereRadius(void) const1278 Real Mesh::getBoundingSphereRadius(void) const 1279 { 1280 return mBoundRadius; 1281 } 1282 //--------------------------------------------------------------------- getBoneBoundingRadius(void) const1283 Real Mesh::getBoneBoundingRadius(void) const 1284 { 1285 return mBoneBoundingRadius; 1286 } 1287 //--------------------------------------------------------------------- setVertexBufferPolicy(HardwareBuffer::Usage vbUsage,bool shadowBuffer)1288 void Mesh::setVertexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 1289 { 1290 mVertexBufferUsage = vbUsage; 1291 mVertexBufferShadowBuffer = shadowBuffer; 1292 } 1293 //--------------------------------------------------------------------- setIndexBufferPolicy(HardwareBuffer::Usage vbUsage,bool shadowBuffer)1294 void Mesh::setIndexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 1295 { 1296 mIndexBufferUsage = vbUsage; 1297 mIndexBufferShadowBuffer = shadowBuffer; 1298 } 1299 //--------------------------------------------------------------------- mergeAdjacentTexcoords(unsigned short finalTexCoordSet,unsigned short texCoordSetToDestroy)1300 void Mesh::mergeAdjacentTexcoords( unsigned short finalTexCoordSet, 1301 unsigned short texCoordSetToDestroy ) 1302 { 1303 if( sharedVertexData ) 1304 mergeAdjacentTexcoords( finalTexCoordSet, texCoordSetToDestroy, sharedVertexData ); 1305 1306 SubMeshList::const_iterator itor = mSubMeshList.begin(); 1307 SubMeshList::const_iterator end = mSubMeshList.end(); 1308 1309 while( itor != end ) 1310 { 1311 if( !(*itor)->useSharedVertices ) 1312 mergeAdjacentTexcoords( finalTexCoordSet, texCoordSetToDestroy, (*itor)->vertexData ); 1313 ++itor; 1314 } 1315 } 1316 //--------------------------------------------------------------------- mergeAdjacentTexcoords(unsigned short finalTexCoordSet,unsigned short texCoordSetToDestroy,VertexData * vertexData)1317 void Mesh::mergeAdjacentTexcoords( unsigned short finalTexCoordSet, 1318 unsigned short texCoordSetToDestroy, 1319 VertexData *vertexData ) 1320 { 1321 VertexDeclaration *vDecl = vertexData->vertexDeclaration; 1322 1323 const VertexElement *uv0 = vDecl->findElementBySemantic( VES_TEXTURE_COORDINATES, 1324 finalTexCoordSet ); 1325 const VertexElement *uv1 = vDecl->findElementBySemantic( VES_TEXTURE_COORDINATES, 1326 texCoordSetToDestroy ); 1327 1328 if( uv0 && uv1 ) 1329 { 1330 //Check that both base types are compatible (mix floats w/ shorts) and there's enough space 1331 VertexElementType baseType0 = VertexElement::getBaseType( uv0->getType() ); 1332 VertexElementType baseType1 = VertexElement::getBaseType( uv1->getType() ); 1333 1334 unsigned short totalTypeCount = VertexElement::getTypeCount( uv0->getType() ) + 1335 VertexElement::getTypeCount( uv1->getType() ); 1336 if( baseType0 == baseType1 && totalTypeCount <= 4 ) 1337 { 1338 const VertexDeclaration::VertexElementList &veList = vDecl->getElements(); 1339 VertexDeclaration::VertexElementList::const_iterator uv0Itor = std::find( veList.begin(), 1340 veList.end(), *uv0 ); 1341 unsigned short elem_idx = std::distance( veList.begin(), uv0Itor ); 1342 VertexElementType newType = VertexElement::multiplyTypeCount( baseType0, 1343 totalTypeCount ); 1344 1345 if( ( uv0->getOffset() + uv0->getSize() == uv1->getOffset() || 1346 uv1->getOffset() + uv1->getSize() == uv0->getOffset() ) && 1347 uv0->getSource() == uv1->getSource() ) 1348 { 1349 //Special case where they adjacent, just change the declaration & we're done. 1350 size_t newOffset = std::min( uv0->getOffset(), uv1->getOffset() ); 1351 unsigned short newIdx = std::min( uv0->getIndex(), uv1->getIndex() ); 1352 1353 vDecl->modifyElement( elem_idx, uv0->getSource(), newOffset, newType, 1354 VES_TEXTURE_COORDINATES, newIdx ); 1355 vDecl->removeElement( VES_TEXTURE_COORDINATES, texCoordSetToDestroy ); 1356 uv1 = 0; 1357 } 1358 1359 vDecl->closeGapsInSource(); 1360 } 1361 } 1362 } 1363 //--------------------------------------------------------------------- organiseTangentsBuffer(VertexData * vertexData,VertexElementSemantic targetSemantic,unsigned short index,unsigned short sourceTexCoordSet)1364 void Mesh::organiseTangentsBuffer(VertexData *vertexData, 1365 VertexElementSemantic targetSemantic, unsigned short index, 1366 unsigned short sourceTexCoordSet) 1367 { 1368 VertexDeclaration *vDecl = vertexData->vertexDeclaration ; 1369 VertexBufferBinding *vBind = vertexData->vertexBufferBinding ; 1370 1371 const VertexElement *tangentsElem = vDecl->findElementBySemantic(targetSemantic, index); 1372 bool needsToBeCreated = false; 1373 1374 if (!tangentsElem) 1375 { // no tex coords with index 1 1376 needsToBeCreated = true ; 1377 } 1378 else if (tangentsElem->getType() != VET_FLOAT3) 1379 { 1380 // buffer exists, but not 3D 1381 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1382 "Target semantic set already exists but is not 3D, therefore " 1383 "cannot contain tangents. Pick an alternative destination semantic. ", 1384 "Mesh::organiseTangentsBuffer"); 1385 } 1386 1387 HardwareVertexBufferSharedPtr newBuffer; 1388 if (needsToBeCreated) 1389 { 1390 // To be most efficient with our vertex streams, 1391 // tack the new tangents onto the same buffer as the 1392 // source texture coord set 1393 const VertexElement* prevTexCoordElem = 1394 vertexData->vertexDeclaration->findElementBySemantic( 1395 VES_TEXTURE_COORDINATES, sourceTexCoordSet); 1396 if (!prevTexCoordElem) 1397 { 1398 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 1399 "Cannot locate the first texture coordinate element to " 1400 "which to append the new tangents.", 1401 "Mesh::orgagniseTangentsBuffer"); 1402 } 1403 // Find the buffer associated with this element 1404 HardwareVertexBufferSharedPtr origBuffer = 1405 vertexData->vertexBufferBinding->getBuffer( 1406 prevTexCoordElem->getSource()); 1407 // Now create a new buffer, which includes the previous contents 1408 // plus extra space for the 3D coords 1409 newBuffer = getHardwareBufferManager()->createVertexBuffer( 1410 origBuffer->getVertexSize() + 3*sizeof(float), 1411 vertexData->vertexCount, 1412 origBuffer->getUsage(), 1413 origBuffer->hasShadowBuffer() ); 1414 // Add the new element 1415 vDecl->addElement( 1416 prevTexCoordElem->getSource(), 1417 origBuffer->getVertexSize(), 1418 VET_FLOAT3, 1419 targetSemantic, 1420 index); 1421 // Now copy the original data across 1422 HardwareBufferLockGuard srcLock(origBuffer, HardwareBuffer::HBL_READ_ONLY); 1423 HardwareBufferLockGuard dstLock(newBuffer, HardwareBuffer::HBL_DISCARD); 1424 unsigned char* pSrc = static_cast<unsigned char*>(srcLock.pData); 1425 unsigned char* pDest = static_cast<unsigned char*>(dstLock.pData); 1426 size_t vertSize = origBuffer->getVertexSize(); 1427 for (size_t v = 0; v < vertexData->vertexCount; ++v) 1428 { 1429 // Copy original vertex data 1430 memcpy(pDest, pSrc, vertSize); 1431 pSrc += vertSize; 1432 pDest += vertSize; 1433 // Set the new part to 0 since we'll accumulate in this 1434 memset(pDest, 0, sizeof(float)*3); 1435 pDest += sizeof(float)*3; 1436 } 1437 1438 // Rebind the new buffer 1439 vBind->setBinding(prevTexCoordElem->getSource(), newBuffer); 1440 } 1441 } 1442 //--------------------------------------------------------------------- buildTangentVectors(VertexElementSemantic targetSemantic,unsigned short sourceTexCoordSet,unsigned short index,bool splitMirrored,bool splitRotated,bool storeParityInW)1443 void Mesh::buildTangentVectors(VertexElementSemantic targetSemantic, 1444 unsigned short sourceTexCoordSet, unsigned short index, 1445 bool splitMirrored, bool splitRotated, bool storeParityInW) 1446 { 1447 1448 TangentSpaceCalc tangentsCalc; 1449 tangentsCalc.setSplitMirrored(splitMirrored); 1450 tangentsCalc.setSplitRotated(splitRotated); 1451 tangentsCalc.setStoreParityInW(storeParityInW); 1452 1453 // shared geometry first 1454 if (sharedVertexData) 1455 { 1456 tangentsCalc.setVertexData(sharedVertexData); 1457 bool found = false; 1458 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 1459 { 1460 SubMesh* sm = *i; 1461 if (sm->useSharedVertices) 1462 { 1463 tangentsCalc.addIndexData(sm->indexData); 1464 found = true; 1465 } 1466 } 1467 if (found) 1468 { 1469 TangentSpaceCalc::Result res = 1470 tangentsCalc.build(targetSemantic, sourceTexCoordSet, index); 1471 1472 // If any vertex splitting happened, we have to give them bone assignments 1473 if (!getSkeletonName().empty()) 1474 { 1475 for (TangentSpaceCalc::IndexRemapList::iterator r = res.indexesRemapped.begin(); 1476 r != res.indexesRemapped.end(); ++r) 1477 { 1478 TangentSpaceCalc::IndexRemap& remap = *r; 1479 // Copy all bone assignments from the split vertex 1480 VertexBoneAssignmentList::iterator vbstart = mBoneAssignments.lower_bound(remap.splitVertex.first); 1481 VertexBoneAssignmentList::iterator vbend = mBoneAssignments.upper_bound(remap.splitVertex.first); 1482 for (VertexBoneAssignmentList::iterator vba = vbstart; vba != vbend; ++vba) 1483 { 1484 VertexBoneAssignment newAsgn = vba->second; 1485 newAsgn.vertexIndex = static_cast<unsigned int>(remap.splitVertex.second); 1486 // multimap insert doesn't invalidate iterators 1487 addBoneAssignment(newAsgn); 1488 } 1489 1490 } 1491 } 1492 1493 // Update poses (some vertices might have been duplicated) 1494 // we will just check which vertices have been split and copy 1495 // the offset for the original vertex to the corresponding new vertex 1496 PoseList::iterator pose_it; 1497 for( pose_it = mPoseList.begin(); pose_it != mPoseList.end(); ++pose_it) 1498 { 1499 Pose* current_pose = *pose_it; 1500 const Pose::VertexOffsetMap& offset_map = current_pose->getVertexOffsets(); 1501 1502 for( TangentSpaceCalc::VertexSplits::iterator it = res.vertexSplits.begin(); 1503 it != res.vertexSplits.end(); ++it ) 1504 { 1505 TangentSpaceCalc::VertexSplit& split = *it; 1506 1507 Pose::VertexOffsetMap::const_iterator found_offset = offset_map.find( split.first ); 1508 1509 // copy the offset 1510 if( found_offset != offset_map.end() ) 1511 { 1512 current_pose->addVertex( split.second, found_offset->second ); 1513 } 1514 } 1515 } 1516 } 1517 } 1518 1519 // Dedicated geometry 1520 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 1521 { 1522 SubMesh* sm = *i; 1523 if (!sm->useSharedVertices) 1524 { 1525 tangentsCalc.clear(); 1526 tangentsCalc.setVertexData(sm->vertexData); 1527 tangentsCalc.addIndexData(sm->indexData, sm->operationType); 1528 TangentSpaceCalc::Result res = 1529 tangentsCalc.build(targetSemantic, sourceTexCoordSet, index); 1530 1531 // If any vertex splitting happened, we have to give them bone assignments 1532 if (!getSkeletonName().empty()) 1533 { 1534 for (TangentSpaceCalc::IndexRemapList::iterator r = res.indexesRemapped.begin(); 1535 r != res.indexesRemapped.end(); ++r) 1536 { 1537 TangentSpaceCalc::IndexRemap& remap = *r; 1538 // Copy all bone assignments from the split vertex 1539 VertexBoneAssignmentList::const_iterator vbstart = 1540 sm->getBoneAssignments().lower_bound(remap.splitVertex.first); 1541 VertexBoneAssignmentList::const_iterator vbend = 1542 sm->getBoneAssignments().upper_bound(remap.splitVertex.first); 1543 for (VertexBoneAssignmentList::const_iterator vba = vbstart; vba != vbend; ++vba) 1544 { 1545 VertexBoneAssignment newAsgn = vba->second; 1546 newAsgn.vertexIndex = static_cast<unsigned int>(remap.splitVertex.second); 1547 // multimap insert doesn't invalidate iterators 1548 sm->addBoneAssignment(newAsgn); 1549 } 1550 1551 } 1552 1553 } 1554 } 1555 } 1556 1557 } 1558 //--------------------------------------------------------------------- suggestTangentVectorBuildParams(VertexElementSemantic targetSemantic,unsigned short & outSourceCoordSet,unsigned short & outIndex)1559 bool Mesh::suggestTangentVectorBuildParams(VertexElementSemantic targetSemantic, 1560 unsigned short& outSourceCoordSet, unsigned short& outIndex) 1561 { 1562 // Go through all the vertex data and locate source and dest (must agree) 1563 bool sharedGeometryDone = false; 1564 bool foundExisting = false; 1565 bool firstOne = true; 1566 SubMeshList::iterator i, iend; 1567 iend = mSubMeshList.end(); 1568 for (i = mSubMeshList.begin(); i != iend; ++i) 1569 { 1570 SubMesh* sm = *i; 1571 VertexData* vertexData; 1572 1573 if (sm->useSharedVertices) 1574 { 1575 if (sharedGeometryDone) 1576 continue; 1577 vertexData = sharedVertexData; 1578 sharedGeometryDone = true; 1579 } 1580 else 1581 { 1582 vertexData = sm->vertexData; 1583 } 1584 1585 const VertexElement *sourceElem = 0; 1586 unsigned short targetIndex = 0; 1587 for (targetIndex = 0; targetIndex < OGRE_MAX_TEXTURE_COORD_SETS; ++targetIndex) 1588 { 1589 const VertexElement* testElem = 1590 vertexData->vertexDeclaration->findElementBySemantic( 1591 VES_TEXTURE_COORDINATES, targetIndex); 1592 if (!testElem) 1593 break; // finish if we've run out, t will be the target 1594 1595 if (!sourceElem) 1596 { 1597 // We're still looking for the source texture coords 1598 if (testElem->getType() == VET_FLOAT2) 1599 { 1600 // Ok, we found it 1601 sourceElem = testElem; 1602 } 1603 } 1604 1605 if(!foundExisting && targetSemantic == VES_TEXTURE_COORDINATES) 1606 { 1607 // We're looking for the destination 1608 // Check to see if we've found a possible 1609 if (testElem->getType() == VET_FLOAT3) 1610 { 1611 // This is a 3D set, might be tangents 1612 foundExisting = true; 1613 } 1614 1615 } 1616 1617 } 1618 1619 if (!foundExisting && targetSemantic != VES_TEXTURE_COORDINATES) 1620 { 1621 targetIndex = 0; 1622 // Look for existing semantic 1623 const VertexElement* testElem = 1624 vertexData->vertexDeclaration->findElementBySemantic( 1625 targetSemantic, targetIndex); 1626 if (testElem) 1627 { 1628 foundExisting = true; 1629 } 1630 1631 } 1632 1633 // After iterating, we should have a source and a possible destination (t) 1634 if (!sourceElem) 1635 { 1636 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 1637 "Cannot locate an appropriate 2D texture coordinate set for " 1638 "all the vertex data in this mesh to create tangents from. ", 1639 "Mesh::suggestTangentVectorBuildParams"); 1640 } 1641 // Check that we agree with previous decisions, if this is not the 1642 // first one, and if we're not just using the existing one 1643 if (!firstOne && !foundExisting) 1644 { 1645 if (sourceElem->getIndex() != outSourceCoordSet) 1646 { 1647 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1648 "Multiple sets of vertex data in this mesh disagree on " 1649 "the appropriate index to use for the source texture coordinates. " 1650 "This ambiguity must be rectified before tangents can be generated.", 1651 "Mesh::suggestTangentVectorBuildParams"); 1652 } 1653 if (targetIndex != outIndex) 1654 { 1655 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 1656 "Multiple sets of vertex data in this mesh disagree on " 1657 "the appropriate index to use for the target texture coordinates. " 1658 "This ambiguity must be rectified before tangents can be generated.", 1659 "Mesh::suggestTangentVectorBuildParams"); 1660 } 1661 } 1662 1663 // Otherwise, save this result 1664 outSourceCoordSet = sourceElem->getIndex(); 1665 outIndex = targetIndex; 1666 1667 firstOne = false; 1668 1669 } 1670 1671 return foundExisting; 1672 1673 } 1674 //--------------------------------------------------------------------- buildEdgeList(void)1675 void Mesh::buildEdgeList(void) 1676 { 1677 if (mEdgeListsBuilt) 1678 return; 1679 #if !OGRE_NO_MESHLOD 1680 // Loop over LODs 1681 for (unsigned short lodIndex = 0; lodIndex < (unsigned short)mMeshLodUsageList.size(); ++lodIndex) 1682 { 1683 // use getLodLevel to enforce loading of manual mesh lods 1684 const MeshLodUsage& usage = getLodLevel(lodIndex); 1685 1686 if (!usage.manualName.empty() && lodIndex != 0) 1687 { 1688 // Delegate edge building to manual mesh 1689 // It should have already built it's own edge list while loading 1690 if (usage.manualMesh) 1691 { 1692 usage.edgeData = usage.manualMesh->getEdgeList(0); 1693 } 1694 } 1695 else 1696 { 1697 // Build 1698 EdgeListBuilder eb; 1699 size_t vertexSetCount = 0; 1700 bool atLeastOneIndexSet = false; 1701 1702 if (sharedVertexData) 1703 { 1704 eb.addVertexData(sharedVertexData); 1705 vertexSetCount++; 1706 } 1707 1708 // Prepare the builder using the submesh information 1709 SubMeshList::iterator i, iend; 1710 iend = mSubMeshList.end(); 1711 for (i = mSubMeshList.begin(); i != iend; ++i) 1712 { 1713 SubMesh* s = *i; 1714 if (s->operationType != RenderOperation::OT_TRIANGLE_FAN && 1715 s->operationType != RenderOperation::OT_TRIANGLE_LIST && 1716 s->operationType != RenderOperation::OT_TRIANGLE_STRIP) 1717 { 1718 continue; 1719 } 1720 if (s->useSharedVertices) 1721 { 1722 // Use shared vertex data, index as set 0 1723 if (lodIndex == 0) 1724 { 1725 eb.addIndexData(s->indexData, 0, s->operationType); 1726 } 1727 else 1728 { 1729 eb.addIndexData(s->mLodFaceList[lodIndex-1], 0, 1730 s->operationType); 1731 } 1732 } 1733 else if(s->isBuildEdgesEnabled()) 1734 { 1735 // own vertex data, add it and reference it directly 1736 eb.addVertexData(s->vertexData); 1737 if (lodIndex == 0) 1738 { 1739 // Base index data 1740 eb.addIndexData(s->indexData, vertexSetCount++, 1741 s->operationType); 1742 } 1743 else 1744 { 1745 // LOD index data 1746 eb.addIndexData(s->mLodFaceList[lodIndex-1], 1747 vertexSetCount++, s->operationType); 1748 } 1749 1750 } 1751 atLeastOneIndexSet = true; 1752 } 1753 1754 if (atLeastOneIndexSet) 1755 { 1756 usage.edgeData = eb.build(); 1757 1758 #if OGRE_DEBUG_MODE 1759 // Override default log 1760 Log* log = LogManager::getSingleton().createLog( 1761 mName + "_lod" + StringConverter::toString(lodIndex) + 1762 "_prepshadow.log", false, false); 1763 usage.edgeData->log(log); 1764 // clean up log & close file handle 1765 LogManager::getSingleton().destroyLog(log); 1766 #endif 1767 } 1768 else 1769 { 1770 // create empty edge data 1771 usage.edgeData = OGRE_NEW EdgeData(); 1772 } 1773 } 1774 } 1775 #else 1776 // Build 1777 EdgeListBuilder eb; 1778 size_t vertexSetCount = 0; 1779 if (sharedVertexData) 1780 { 1781 eb.addVertexData(sharedVertexData); 1782 vertexSetCount++; 1783 } 1784 1785 // Prepare the builder using the submesh information 1786 SubMeshList::iterator i, iend; 1787 iend = mSubMeshList.end(); 1788 for (i = mSubMeshList.begin(); i != iend; ++i) 1789 { 1790 SubMesh* s = *i; 1791 if (s->operationType != RenderOperation::OT_TRIANGLE_FAN && 1792 s->operationType != RenderOperation::OT_TRIANGLE_LIST && 1793 s->operationType != RenderOperation::OT_TRIANGLE_STRIP) 1794 { 1795 continue; 1796 } 1797 if (s->useSharedVertices) 1798 { 1799 eb.addIndexData(s->indexData, 0, s->operationType); 1800 } 1801 else if(s->isBuildEdgesEnabled()) 1802 { 1803 // own vertex data, add it and reference it directly 1804 eb.addVertexData(s->vertexData); 1805 // Base index data 1806 eb.addIndexData(s->indexData, vertexSetCount++, 1807 s->operationType); 1808 } 1809 } 1810 1811 mMeshLodUsageList[0].edgeData = eb.build(); 1812 1813 #if OGRE_DEBUG_MODE 1814 // Override default log 1815 Log* log = LogManager::getSingleton().createLog( 1816 mName + "_lod0"+ 1817 "_prepshadow.log", false, false); 1818 mMeshLodUsageList[0].edgeData->log(log); 1819 // clean up log & close file handle 1820 LogManager::getSingleton().destroyLog(log); 1821 #endif 1822 #endif 1823 mEdgeListsBuilt = true; 1824 } 1825 //--------------------------------------------------------------------- freeEdgeList(void)1826 void Mesh::freeEdgeList(void) 1827 { 1828 if (!mEdgeListsBuilt) 1829 return; 1830 #if !OGRE_NO_MESHLOD 1831 // Loop over LODs 1832 MeshLodUsageList::iterator i, iend; 1833 iend = mMeshLodUsageList.end(); 1834 unsigned short index = 0; 1835 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 1836 { 1837 MeshLodUsage& usage = *i; 1838 1839 if (usage.manualName.empty() || index == 0) 1840 { 1841 // Only delete if we own this data 1842 // Manual LODs > 0 own their own 1843 OGRE_DELETE usage.edgeData; 1844 } 1845 usage.edgeData = NULL; 1846 } 1847 #else 1848 OGRE_DELETE mMeshLodUsageList[0].edgeData; 1849 mMeshLodUsageList[0].edgeData = NULL; 1850 #endif 1851 mEdgeListsBuilt = false; 1852 } 1853 //--------------------------------------------------------------------- prepareForShadowVolume(void)1854 void Mesh::prepareForShadowVolume(void) 1855 { 1856 if (mPreparedForShadowVolumes) 1857 return; 1858 1859 if (sharedVertexData) 1860 { 1861 sharedVertexData->prepareForShadowVolume(); 1862 } 1863 SubMeshList::iterator i, iend; 1864 iend = mSubMeshList.end(); 1865 for (i = mSubMeshList.begin(); i != iend; ++i) 1866 { 1867 SubMesh* s = *i; 1868 if (!s->useSharedVertices && 1869 (s->operationType == RenderOperation::OT_TRIANGLE_FAN || 1870 s->operationType == RenderOperation::OT_TRIANGLE_LIST || 1871 s->operationType == RenderOperation::OT_TRIANGLE_STRIP)) 1872 { 1873 s->vertexData->prepareForShadowVolume(); 1874 } 1875 } 1876 mPreparedForShadowVolumes = true; 1877 } 1878 //--------------------------------------------------------------------- getEdgeList(unsigned short lodIndex)1879 EdgeData* Mesh::getEdgeList(unsigned short lodIndex) 1880 { 1881 // Build edge list on demand 1882 if (!mEdgeListsBuilt && mAutoBuildEdgeLists) 1883 { 1884 buildEdgeList(); 1885 } 1886 #if !OGRE_NO_MESHLOD 1887 return getLodLevel(lodIndex).edgeData; 1888 #else 1889 assert(lodIndex == 0); 1890 return mMeshLodUsageList[0].edgeData; 1891 #endif 1892 } 1893 //--------------------------------------------------------------------- getEdgeList(unsigned short lodIndex) const1894 const EdgeData* Mesh::getEdgeList(unsigned short lodIndex) const 1895 { 1896 #if !OGRE_NO_MESHLOD 1897 return getLodLevel(lodIndex).edgeData; 1898 #else 1899 assert(lodIndex == 0); 1900 return mMeshLodUsageList[0].edgeData; 1901 #endif 1902 } 1903 //--------------------------------------------------------------------- prepareMatricesForVertexBlend(const Affine3 ** blendMatrices,const Affine3 * boneMatrices,const IndexMap & indexMap)1904 void Mesh::prepareMatricesForVertexBlend(const Affine3** blendMatrices, 1905 const Affine3* boneMatrices, const IndexMap& indexMap) 1906 { 1907 assert(indexMap.size() <= 256); 1908 IndexMap::const_iterator it, itend; 1909 itend = indexMap.end(); 1910 for (it = indexMap.begin(); it != itend; ++it) 1911 { 1912 *blendMatrices++ = boneMatrices + *it; 1913 } 1914 } 1915 //--------------------------------------------------------------------- softwareVertexBlend(const VertexData * sourceVertexData,const VertexData * targetVertexData,const Affine3 * const * blendMatrices,size_t numMatrices,bool blendNormals)1916 void Mesh::softwareVertexBlend(const VertexData* sourceVertexData, 1917 const VertexData* targetVertexData, 1918 const Affine3* const* blendMatrices, size_t numMatrices, 1919 bool blendNormals) 1920 { 1921 float *pSrcPos = 0; 1922 float *pSrcNorm = 0; 1923 float *pDestPos = 0; 1924 float *pDestNorm = 0; 1925 float *pBlendWeight = 0; 1926 unsigned char* pBlendIdx = 0; 1927 size_t srcPosStride = 0; 1928 size_t srcNormStride = 0; 1929 size_t destPosStride = 0; 1930 size_t destNormStride = 0; 1931 size_t blendWeightStride = 0; 1932 size_t blendIdxStride = 0; 1933 1934 1935 // Get elements for source 1936 const VertexElement* srcElemPos = 1937 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 1938 const VertexElement* srcElemNorm = 1939 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 1940 const VertexElement* srcElemBlendIndices = 1941 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); 1942 const VertexElement* srcElemBlendWeights = 1943 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); 1944 OgreAssert(srcElemPos && srcElemBlendIndices && srcElemBlendWeights, 1945 "You must supply at least positions, blend indices and blend weights"); 1946 // Get elements for target 1947 const VertexElement* destElemPos = 1948 targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 1949 const VertexElement* destElemNorm = 1950 targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 1951 1952 // Do we have normals and want to blend them? 1953 bool includeNormals = blendNormals && (srcElemNorm != NULL) && (destElemNorm != NULL); 1954 1955 1956 // Get buffers for source 1957 HardwareVertexBufferSharedPtr srcPosBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemPos->getSource()); 1958 HardwareVertexBufferSharedPtr srcIdxBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendIndices->getSource()); 1959 HardwareVertexBufferSharedPtr srcWeightBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendWeights->getSource()); 1960 HardwareVertexBufferSharedPtr srcNormBuf; 1961 1962 srcPosStride = srcPosBuf->getVertexSize(); 1963 1964 blendIdxStride = srcIdxBuf->getVertexSize(); 1965 1966 blendWeightStride = srcWeightBuf->getVertexSize(); 1967 if (includeNormals) 1968 { 1969 srcNormBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemNorm->getSource()); 1970 srcNormStride = srcNormBuf->getVertexSize(); 1971 } 1972 // Get buffers for target 1973 HardwareVertexBufferSharedPtr destPosBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemPos->getSource()); 1974 HardwareVertexBufferSharedPtr destNormBuf; 1975 destPosStride = destPosBuf->getVertexSize(); 1976 if (includeNormals) 1977 { 1978 destNormBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemNorm->getSource()); 1979 destNormStride = destNormBuf->getVertexSize(); 1980 } 1981 1982 // Lock source buffers for reading 1983 HardwareBufferLockGuard srcPosLock(srcPosBuf, HardwareBuffer::HBL_READ_ONLY); 1984 srcElemPos->baseVertexPointerToElement(srcPosLock.pData, &pSrcPos); 1985 HardwareBufferLockGuard srcNormLock; 1986 if (includeNormals) 1987 { 1988 if (srcNormBuf != srcPosBuf) 1989 { 1990 // Different buffer 1991 srcNormLock.lock(srcNormBuf, HardwareBuffer::HBL_READ_ONLY); 1992 } 1993 srcElemNorm->baseVertexPointerToElement(srcNormBuf != srcPosBuf ? srcNormLock.pData : srcPosLock.pData, &pSrcNorm); 1994 } 1995 1996 // Indices must be 4 bytes 1997 assert(srcElemBlendIndices->getType() == VET_UBYTE4 && 1998 "Blend indices must be VET_UBYTE4"); 1999 HardwareBufferLockGuard srcIdxLock(srcIdxBuf, HardwareBuffer::HBL_READ_ONLY); 2000 srcElemBlendIndices->baseVertexPointerToElement(srcIdxLock.pData, &pBlendIdx); 2001 HardwareBufferLockGuard srcWeightLock; 2002 if (srcWeightBuf != srcIdxBuf) 2003 { 2004 // Lock buffer 2005 srcWeightLock.lock(srcWeightBuf, HardwareBuffer::HBL_READ_ONLY); 2006 } 2007 srcElemBlendWeights->baseVertexPointerToElement(srcWeightBuf != srcIdxBuf ? srcWeightLock.pData : srcIdxLock.pData, &pBlendWeight); 2008 unsigned short numWeightsPerVertex = 2009 VertexElement::getTypeCount(srcElemBlendWeights->getType()); 2010 2011 2012 // Lock destination buffers for writing 2013 HardwareBufferLockGuard destPosLock(destPosBuf, 2014 (destNormBuf != destPosBuf && destPosBuf->getVertexSize() == destElemPos->getSize()) || 2015 (destNormBuf == destPosBuf && destPosBuf->getVertexSize() == destElemPos->getSize() + destElemNorm->getSize()) ? 2016 HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL); 2017 destElemPos->baseVertexPointerToElement(destPosLock.pData, &pDestPos); 2018 HardwareBufferLockGuard destNormLock; 2019 if (includeNormals) 2020 { 2021 if (destNormBuf != destPosBuf) 2022 { 2023 destNormLock.lock(destNormBuf, 2024 destNormBuf->getVertexSize() == destElemNorm->getSize() ? 2025 HardwareBuffer::HBL_DISCARD : HardwareBuffer::HBL_NORMAL); 2026 } 2027 destElemNorm->baseVertexPointerToElement(destNormBuf != destPosBuf ? destNormLock.pData : destPosLock.pData, &pDestNorm); 2028 } 2029 2030 OptimisedUtil::getImplementation()->softwareVertexSkinning( 2031 pSrcPos, pDestPos, 2032 pSrcNorm, pDestNorm, 2033 pBlendWeight, pBlendIdx, 2034 blendMatrices, 2035 srcPosStride, destPosStride, 2036 srcNormStride, destNormStride, 2037 blendWeightStride, blendIdxStride, 2038 numWeightsPerVertex, 2039 targetVertexData->vertexCount); 2040 } 2041 //--------------------------------------------------------------------- softwareVertexMorph(Real t,const HardwareVertexBufferSharedPtr & b1,const HardwareVertexBufferSharedPtr & b2,VertexData * targetVertexData)2042 void Mesh::softwareVertexMorph(Real t, 2043 const HardwareVertexBufferSharedPtr& b1, 2044 const HardwareVertexBufferSharedPtr& b2, 2045 VertexData* targetVertexData) 2046 { 2047 HardwareBufferLockGuard b1Lock(b1, HardwareBuffer::HBL_READ_ONLY); 2048 float* pb1 = static_cast<float*>(b1Lock.pData); 2049 HardwareBufferLockGuard b2Lock; 2050 float* pb2; 2051 if (b1.get() != b2.get()) 2052 { 2053 b2Lock.lock(b2, HardwareBuffer::HBL_READ_ONLY); 2054 pb2 = static_cast<float*>(b2Lock.pData); 2055 } 2056 else 2057 { 2058 // Same buffer - track with only one entry or time index exactly matching 2059 // one keyframe 2060 // For simplicity of main code, interpolate still but with same val 2061 pb2 = pb1; 2062 } 2063 2064 const VertexElement* posElem = 2065 targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 2066 assert(posElem); 2067 const VertexElement* normElem = 2068 targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 2069 2070 bool morphNormals = false; 2071 if (normElem && normElem->getSource() == posElem->getSource() && 2072 b1->getVertexSize() == 24 && b2->getVertexSize() == 24) 2073 morphNormals = true; 2074 2075 HardwareVertexBufferSharedPtr destBuf = 2076 targetVertexData->vertexBufferBinding->getBuffer( 2077 posElem->getSource()); 2078 assert((posElem->getSize() == destBuf->getVertexSize() 2079 || (morphNormals && posElem->getSize() + normElem->getSize() == destBuf->getVertexSize())) && 2080 "Positions (or positions & normals) must be in a buffer on their own for morphing"); 2081 HardwareBufferLockGuard destLock(destBuf, HardwareBuffer::HBL_DISCARD); 2082 float* pdst = static_cast<float*>(destLock.pData); 2083 2084 OptimisedUtil::getImplementation()->softwareVertexMorph( 2085 t, pb1, pb2, pdst, 2086 b1->getVertexSize(), b2->getVertexSize(), destBuf->getVertexSize(), 2087 targetVertexData->vertexCount, 2088 morphNormals); 2089 } 2090 //--------------------------------------------------------------------- softwareVertexPoseBlend(Real weight,const std::map<size_t,Vector3> & vertexOffsetMap,const std::map<size_t,Vector3> & normalsMap,VertexData * targetVertexData)2091 void Mesh::softwareVertexPoseBlend(Real weight, 2092 const std::map<size_t, Vector3>& vertexOffsetMap, 2093 const std::map<size_t, Vector3>& normalsMap, 2094 VertexData* targetVertexData) 2095 { 2096 // Do nothing if no weight 2097 if (weight == 0.0f) 2098 return; 2099 2100 const VertexElement* posElem = 2101 targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 2102 const VertexElement* normElem = 2103 targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 2104 assert(posElem); 2105 // Support normals if they're in the same buffer as positions and pose includes them 2106 bool normals = normElem && !normalsMap.empty() && posElem->getSource() == normElem->getSource(); 2107 HardwareVertexBufferSharedPtr destBuf = 2108 targetVertexData->vertexBufferBinding->getBuffer( 2109 posElem->getSource()); 2110 2111 size_t elemsPerVertex = destBuf->getVertexSize()/sizeof(float); 2112 2113 // Have to lock in normal mode since this is incremental 2114 HardwareBufferLockGuard destLock(destBuf, HardwareBuffer::HBL_NORMAL); 2115 float* pBase = static_cast<float*>(destLock.pData); 2116 2117 // Iterate over affected vertices 2118 for (std::map<size_t, Vector3>::const_iterator i = vertexOffsetMap.begin(); 2119 i != vertexOffsetMap.end(); ++i) 2120 { 2121 // Adjust pointer 2122 float *pdst = pBase + i->first*elemsPerVertex; 2123 2124 *pdst = *pdst + (i->second.x * weight); 2125 ++pdst; 2126 *pdst = *pdst + (i->second.y * weight); 2127 ++pdst; 2128 *pdst = *pdst + (i->second.z * weight); 2129 ++pdst; 2130 2131 } 2132 2133 if (normals) 2134 { 2135 float* pNormBase; 2136 normElem->baseVertexPointerToElement((void*)pBase, &pNormBase); 2137 for (std::map<size_t, Vector3>::const_iterator i = normalsMap.begin(); 2138 i != normalsMap.end(); ++i) 2139 { 2140 // Adjust pointer 2141 float *pdst = pNormBase + i->first*elemsPerVertex; 2142 2143 *pdst = *pdst + (i->second.x * weight); 2144 ++pdst; 2145 *pdst = *pdst + (i->second.y * weight); 2146 ++pdst; 2147 *pdst = *pdst + (i->second.z * weight); 2148 ++pdst; 2149 2150 } 2151 } 2152 } 2153 //--------------------------------------------------------------------- calculateSize(void) const2154 size_t Mesh::calculateSize(void) const 2155 { 2156 // calculate GPU size 2157 size_t ret = 0; 2158 unsigned short i; 2159 // Shared vertices 2160 if (sharedVertexData) 2161 { 2162 for (i = 0; 2163 i < sharedVertexData->vertexBufferBinding->getBufferCount(); 2164 ++i) 2165 { 2166 ret += sharedVertexData->vertexBufferBinding 2167 ->getBuffer(i)->getSizeInBytes(); 2168 } 2169 } 2170 2171 SubMeshList::const_iterator si; 2172 for (si = mSubMeshList.begin(); si != mSubMeshList.end(); ++si) 2173 { 2174 // Dedicated vertices 2175 if (!(*si)->useSharedVertices) 2176 { 2177 for (i = 0; 2178 i < (*si)->vertexData->vertexBufferBinding->getBufferCount(); 2179 ++i) 2180 { 2181 ret += (*si)->vertexData->vertexBufferBinding 2182 ->getBuffer(i)->getSizeInBytes(); 2183 } 2184 } 2185 if ((*si)->indexData->indexBuffer) 2186 { 2187 // Index data 2188 ret += (*si)->indexData->indexBuffer->getSizeInBytes(); 2189 } 2190 2191 } 2192 return ret; 2193 } 2194 //----------------------------------------------------------------------------- hasVertexAnimation(void) const2195 bool Mesh::hasVertexAnimation(void) const 2196 { 2197 return !mAnimationsList.empty(); 2198 } 2199 //--------------------------------------------------------------------- getSharedVertexDataAnimationType(void) const2200 VertexAnimationType Mesh::getSharedVertexDataAnimationType(void) const 2201 { 2202 if (mAnimationTypesDirty) 2203 { 2204 _determineAnimationTypes(); 2205 } 2206 2207 return mSharedVertexDataAnimationType; 2208 } 2209 //--------------------------------------------------------------------- _determineAnimationTypes(void) const2210 void Mesh::_determineAnimationTypes(void) const 2211 { 2212 // Don't check flag here; since detail checks on track changes are not 2213 // done, allow caller to force if they need to 2214 2215 // Initialise all types to nothing 2216 mSharedVertexDataAnimationType = VAT_NONE; 2217 mSharedVertexDataAnimationIncludesNormals = false; 2218 for (SubMeshList::const_iterator i = mSubMeshList.begin(); 2219 i != mSubMeshList.end(); ++i) 2220 { 2221 (*i)->mVertexAnimationType = VAT_NONE; 2222 (*i)->mVertexAnimationIncludesNormals = false; 2223 } 2224 2225 mPosesIncludeNormals = false; 2226 for (PoseList::const_iterator i = mPoseList.begin(); i != mPoseList.end(); ++i) 2227 { 2228 if (i == mPoseList.begin()) 2229 mPosesIncludeNormals = (*i)->getIncludesNormals(); 2230 else if (mPosesIncludeNormals != (*i)->getIncludesNormals()) 2231 // only support normals if consistently included 2232 mPosesIncludeNormals = mPosesIncludeNormals && (*i)->getIncludesNormals(); 2233 } 2234 2235 // Scan all animations and determine the type of animation tracks 2236 // relating to each vertex data 2237 for(AnimationList::const_iterator ai = mAnimationsList.begin(); 2238 ai != mAnimationsList.end(); ++ai) 2239 { 2240 Animation* anim = ai->second; 2241 Animation::VertexTrackIterator vit = anim->getVertexTrackIterator(); 2242 while (vit.hasMoreElements()) 2243 { 2244 VertexAnimationTrack* track = vit.getNext(); 2245 ushort handle = track->getHandle(); 2246 if (handle == 0) 2247 { 2248 // shared data 2249 if (mSharedVertexDataAnimationType != VAT_NONE && 2250 mSharedVertexDataAnimationType != track->getAnimationType()) 2251 { 2252 // Mixing of morph and pose animation on same data is not allowed 2253 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2254 "Animation tracks for shared vertex data on mesh " 2255 + mName + " try to mix vertex animation types, which is " 2256 "not allowed.", 2257 "Mesh::_determineAnimationTypes"); 2258 } 2259 mSharedVertexDataAnimationType = track->getAnimationType(); 2260 if (track->getAnimationType() == VAT_MORPH) 2261 mSharedVertexDataAnimationIncludesNormals = track->getVertexAnimationIncludesNormals(); 2262 else 2263 mSharedVertexDataAnimationIncludesNormals = mPosesIncludeNormals; 2264 2265 } 2266 else 2267 { 2268 // submesh index (-1) 2269 SubMesh* sm = getSubMesh(handle-1); 2270 if (sm->mVertexAnimationType != VAT_NONE && 2271 sm->mVertexAnimationType != track->getAnimationType()) 2272 { 2273 // Mixing of morph and pose animation on same data is not allowed 2274 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2275 "Animation tracks for dedicated vertex data " 2276 + StringConverter::toString(handle-1) + " on mesh " 2277 + mName + " try to mix vertex animation types, which is " 2278 "not allowed.", 2279 "Mesh::_determineAnimationTypes"); 2280 } 2281 sm->mVertexAnimationType = track->getAnimationType(); 2282 if (track->getAnimationType() == VAT_MORPH) 2283 sm->mVertexAnimationIncludesNormals = track->getVertexAnimationIncludesNormals(); 2284 else 2285 sm->mVertexAnimationIncludesNormals = mPosesIncludeNormals; 2286 2287 } 2288 } 2289 } 2290 2291 mAnimationTypesDirty = false; 2292 } 2293 //--------------------------------------------------------------------- createAnimation(const String & name,Real length)2294 Animation* Mesh::createAnimation(const String& name, Real length) 2295 { 2296 // Check name not used 2297 if (mAnimationsList.find(name) != mAnimationsList.end()) 2298 { 2299 OGRE_EXCEPT( 2300 Exception::ERR_DUPLICATE_ITEM, 2301 "An animation with the name " + name + " already exists", 2302 "Mesh::createAnimation"); 2303 } 2304 2305 Animation* ret = OGRE_NEW Animation(name, length); 2306 ret->_notifyContainer(this); 2307 2308 // Add to list 2309 mAnimationsList[name] = ret; 2310 2311 // Mark animation types dirty 2312 mAnimationTypesDirty = true; 2313 2314 return ret; 2315 2316 } 2317 //--------------------------------------------------------------------- getAnimation(const String & name) const2318 Animation* Mesh::getAnimation(const String& name) const 2319 { 2320 Animation* ret = _getAnimationImpl(name); 2321 if (!ret) 2322 { 2323 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 2324 "No animation entry found named " + name, 2325 "Mesh::getAnimation"); 2326 } 2327 2328 return ret; 2329 } 2330 //--------------------------------------------------------------------- getAnimation(unsigned short index) const2331 Animation* Mesh::getAnimation(unsigned short index) const 2332 { 2333 // If you hit this assert, then the index is out of bounds. 2334 assert( index < mAnimationsList.size() ); 2335 2336 AnimationList::const_iterator i = mAnimationsList.begin(); 2337 2338 std::advance(i, index); 2339 2340 return i->second; 2341 2342 } 2343 //--------------------------------------------------------------------- getNumAnimations(void) const2344 unsigned short Mesh::getNumAnimations(void) const 2345 { 2346 return static_cast<unsigned short>(mAnimationsList.size()); 2347 } 2348 //--------------------------------------------------------------------- hasAnimation(const String & name) const2349 bool Mesh::hasAnimation(const String& name) const 2350 { 2351 return _getAnimationImpl(name) != 0; 2352 } 2353 //--------------------------------------------------------------------- _getAnimationImpl(const String & name) const2354 Animation* Mesh::_getAnimationImpl(const String& name) const 2355 { 2356 Animation* ret = 0; 2357 AnimationList::const_iterator i = mAnimationsList.find(name); 2358 2359 if (i != mAnimationsList.end()) 2360 { 2361 ret = i->second; 2362 } 2363 2364 return ret; 2365 2366 } 2367 //--------------------------------------------------------------------- removeAnimation(const String & name)2368 void Mesh::removeAnimation(const String& name) 2369 { 2370 AnimationList::iterator i = mAnimationsList.find(name); 2371 2372 if (i == mAnimationsList.end()) 2373 { 2374 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, "No animation entry found named " + name, 2375 "Mesh::getAnimation"); 2376 } 2377 2378 OGRE_DELETE i->second; 2379 2380 mAnimationsList.erase(i); 2381 2382 mAnimationTypesDirty = true; 2383 } 2384 //--------------------------------------------------------------------- removeAllAnimations(void)2385 void Mesh::removeAllAnimations(void) 2386 { 2387 AnimationList::iterator i = mAnimationsList.begin(); 2388 for (; i != mAnimationsList.end(); ++i) 2389 { 2390 OGRE_DELETE i->second; 2391 } 2392 mAnimationsList.clear(); 2393 mAnimationTypesDirty = true; 2394 } 2395 //--------------------------------------------------------------------- getVertexDataByTrackHandle(unsigned short handle)2396 VertexData* Mesh::getVertexDataByTrackHandle(unsigned short handle) 2397 { 2398 if (handle == 0) 2399 { 2400 return sharedVertexData; 2401 } 2402 else 2403 { 2404 return getSubMesh(handle-1)->vertexData; 2405 } 2406 } 2407 //--------------------------------------------------------------------- createPose(ushort target,const String & name)2408 Pose* Mesh::createPose(ushort target, const String& name) 2409 { 2410 Pose* retPose = OGRE_NEW Pose(target, name); 2411 mPoseList.push_back(retPose); 2412 return retPose; 2413 } 2414 //--------------------------------------------------------------------- getPose(ushort index)2415 Pose* Mesh::getPose(ushort index) 2416 { 2417 if (index >= mPoseList.size()) 2418 { 2419 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2420 "Index out of bounds", 2421 "Mesh::getPose"); 2422 } 2423 2424 return mPoseList[index]; 2425 2426 } 2427 //--------------------------------------------------------------------- getPose(const String & name)2428 Pose* Mesh::getPose(const String& name) 2429 { 2430 for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i) 2431 { 2432 if ((*i)->getName() == name) 2433 return *i; 2434 } 2435 StringStream str; 2436 str << "No pose called " << name << " found in Mesh " << mName; 2437 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 2438 str.str(), 2439 "Mesh::getPose"); 2440 2441 } 2442 //--------------------------------------------------------------------- removePose(ushort index)2443 void Mesh::removePose(ushort index) 2444 { 2445 if (index >= mPoseList.size()) 2446 { 2447 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 2448 "Index out of bounds", 2449 "Mesh::removePose"); 2450 } 2451 PoseList::iterator i = mPoseList.begin(); 2452 std::advance(i, index); 2453 OGRE_DELETE *i; 2454 mPoseList.erase(i); 2455 2456 } 2457 //--------------------------------------------------------------------- removePose(const String & name)2458 void Mesh::removePose(const String& name) 2459 { 2460 for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i) 2461 { 2462 if ((*i)->getName() == name) 2463 { 2464 OGRE_DELETE *i; 2465 mPoseList.erase(i); 2466 return; 2467 } 2468 } 2469 StringStream str; 2470 str << "No pose called " << name << " found in Mesh " << mName; 2471 OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, 2472 str.str(), 2473 "Mesh::removePose"); 2474 } 2475 //--------------------------------------------------------------------- removeAllPoses(void)2476 void Mesh::removeAllPoses(void) 2477 { 2478 for (PoseList::iterator i = mPoseList.begin(); i != mPoseList.end(); ++i) 2479 { 2480 OGRE_DELETE *i; 2481 } 2482 mPoseList.clear(); 2483 } 2484 //--------------------------------------------------------------------- getPoseIterator(void)2485 Mesh::PoseIterator Mesh::getPoseIterator(void) 2486 { 2487 return PoseIterator(mPoseList.begin(), mPoseList.end()); 2488 } 2489 //--------------------------------------------------------------------- getPoseIterator(void) const2490 Mesh::ConstPoseIterator Mesh::getPoseIterator(void) const 2491 { 2492 return ConstPoseIterator(mPoseList.begin(), mPoseList.end()); 2493 } 2494 //----------------------------------------------------------------------------- getPoseList(void) const2495 const PoseList& Mesh::getPoseList(void) const 2496 { 2497 return mPoseList; 2498 } 2499 //--------------------------------------------------------------------- updateMaterialForAllSubMeshes(void)2500 void Mesh::updateMaterialForAllSubMeshes(void) 2501 { 2502 // iterate through each sub mesh and request the submesh to update its material 2503 std::vector<SubMesh*>::iterator subi; 2504 for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi) 2505 { 2506 (*subi)->updateMaterialUsingTextureAliases(); 2507 } 2508 2509 } 2510 //--------------------------------------------------------------------- getLodStrategy() const2511 const LodStrategy *Mesh::getLodStrategy() const 2512 { 2513 return mLodStrategy; 2514 } 2515 #if !OGRE_NO_MESHLOD 2516 //--------------------------------------------------------------------- setLodStrategy(LodStrategy * lodStrategy)2517 void Mesh::setLodStrategy(LodStrategy *lodStrategy) 2518 { 2519 mLodStrategy = lodStrategy; 2520 2521 assert(mMeshLodUsageList.size()); 2522 2523 // Re-transform user LOD values (starting at index 1, no need to transform base value) 2524 for (MeshLodUsageList::iterator i = mMeshLodUsageList.begin()+1; i != mMeshLodUsageList.end(); ++i) 2525 i->value = mLodStrategy->transformUserValue(i->userValue); 2526 2527 // Rewrite first value 2528 mMeshLodUsageList[0].value = mLodStrategy->getBaseValue(); 2529 } 2530 #endif 2531 2532 } 2533 2534