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