00001 /* 00002 ----------------------------------------------------------------------------- 00003 This source file is part of OGRE 00004 (Object-oriented Graphics Rendering Engine) 00005 For the latest info, see http://www.ogre3d.org/ 00006 00007 Copyright © 2000-2002 The OGRE Team 00008 Also see acknowledgements in Readme.html 00009 00010 This program is free software; you can redistribute it and/or modify it under 00011 the terms of the GNU Lesser General Public License as published by the Free Software 00012 Foundation; either version 2 of the License, or (at your option) any later 00013 version. 00014 00015 This program is distributed in the hope that it will be useful, but WITHOUT 00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 00018 00019 You should have received a copy of the GNU Lesser General Public License along with 00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to 00022 http://www.gnu.org/copyleft/lesser.txt. 00023 ----------------------------------------------------------------------------- 00024 */ 00025 #include "OgreStableHeaders.h" 00026 #include "OgreMesh.h" 00027 00028 #include "OgreSubMesh.h" 00029 #include "OgreMaterialManager.h" 00030 #include "OgreLogManager.h" 00031 #include "OgreDataChunk.h" 00032 #include "OgreMeshSerializer.h" 00033 #include "OgreSkeletonManager.h" 00034 #include "OgreSkeleton.h" 00035 #include "OgreHardwareBufferManager.h" 00036 #include "OgreStringConverter.h" 00037 #include "OgreException.h" 00038 #include "OgreMeshManager.h" 00039 00040 00041 namespace Ogre { 00042 00043 //----------------------------------------------------------------------- 00044 Mesh::Mesh(const String& name) 00045 { 00046 mName = name; 00047 sharedVertexData = NULL; 00048 // Default to load from file 00049 mManuallyDefined = false; 00050 //mUpdateBounds = true; 00051 setSkeletonName(""); 00052 mBoneAssignmentsOutOfDate = false; 00053 mNumLods = 1; 00054 // Init first (manual) lod 00055 MeshLodUsage lod; 00056 lod.fromDepthSquared = 0.0f; 00057 mMeshLodUsageList.push_back(lod); 00058 mIsLodManual = false; 00059 00060 mVertexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00061 mIndexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00062 mVertexBufferShadowBuffer = false; 00063 mIndexBufferShadowBuffer = false; 00064 00065 mBoundRadius = 0.0f; 00066 00067 // Always use software blending for now 00068 mUseSoftwareBlending = true; 00069 00070 } 00071 00072 //----------------------------------------------------------------------- 00073 Mesh::~Mesh() 00074 { 00075 if (mIsLoaded) 00076 { 00077 unload(); 00078 } 00079 } 00080 00081 //----------------------------------------------------------------------- 00082 SubMesh* Mesh::createSubMesh() 00083 { 00084 SubMesh* sub = new SubMesh(); 00085 sub->parent = this; 00086 00087 mSubMeshList.push_back(sub); 00088 00089 return sub; 00090 } 00091 //----------------------------------------------------------------------- 00092 SubMesh* Mesh::createSubMesh(const String& name) 00093 { 00094 SubMesh *sub = createSubMesh(); 00095 nameSubMesh(name, (ushort)mSubMeshList.size()-1); 00096 return sub ; 00097 } 00098 //----------------------------------------------------------------------- 00099 unsigned short Mesh::getNumSubMeshes() const 00100 { 00101 return static_cast< unsigned short >( mSubMeshList.size() ); 00102 } 00103 00104 //--------------------------------------------------------------------- 00105 void Mesh::nameSubMesh(const String& name, ushort index) 00106 { 00107 mSubMeshNameMap[name] = index ; 00108 } 00109 00110 //----------------------------------------------------------------------- 00111 SubMesh* Mesh::getSubMesh(const String& name) const 00112 { 00113 ushort index = _getSubMeshIndex(name); 00114 return getSubMesh(index); 00115 } 00116 //----------------------------------------------------------------------- 00117 SubMesh* Mesh::getSubMesh(unsigned short index) const 00118 { 00119 SubMeshList::const_iterator i = mSubMeshList.begin(); 00120 return const_cast<SubMesh*>(i[index]); 00121 } 00122 //----------------------------------------------------------------------- 00123 void Mesh::load() 00124 { 00125 // Load from specified 'name' 00126 if (mIsLoaded) 00127 { 00128 unload(); 00129 } 00130 00131 if (!mManuallyDefined) 00132 { 00133 MeshSerializer serializer; 00134 LogManager::getSingleton().logMessage("Mesh: Loading " + mName + "."); 00135 00136 DataChunk chunk; 00137 MeshManager::getSingleton()._findResourceData(mName, chunk); 00138 00139 // Determine file type 00140 std::vector<String> extVec = mName.split("."); 00141 00142 String& ext = extVec[extVec.size() - 1]; 00143 ext.toLowerCase(); 00144 00145 if (ext == "mesh") 00146 { 00147 serializer.importMesh(chunk, this); 00148 } 00149 else 00150 { 00151 // Unsupported format 00152 chunk.clear(); 00153 Except(999, "Unsupported object file format.", 00154 "Mesh::load"); 00155 } 00156 00157 chunk.clear(); 00158 } 00159 00160 mIsLoaded = true; 00161 00162 //_updateBounds(); 00163 00164 } 00165 00166 //----------------------------------------------------------------------- 00167 void Mesh::unload() 00168 { 00169 // Teardown submeshes 00170 for (SubMeshList::iterator i = mSubMeshList.begin(); 00171 i != mSubMeshList.end(); ++i) 00172 { 00173 delete *i; 00174 } 00175 if (sharedVertexData) 00176 { 00177 delete sharedVertexData; 00178 sharedVertexData = NULL; 00179 } 00180 // Clear SubMesh lists 00181 mSubMeshList.clear(); 00182 mSubMeshNameMap.clear(); 00183 mIsLoaded = false; 00184 } 00185 00186 //----------------------------------------------------------------------- 00187 void Mesh::setManuallyDefined(bool manual) 00188 { 00189 mManuallyDefined = manual; 00190 } 00191 00192 //----------------------------------------------------------------------- 00193 Mesh* Mesh::clone(const String& newName) 00194 { 00195 // This is a bit like a copy constructor, but with the additional aspect of registering the clone with 00196 // the MeshManager 00197 00198 // New Mesh is assumed to be manually defined rather than loaded since you're cloning it for a reason 00199 Mesh* newMesh = MeshManager::getSingleton().createManual(newName); 00200 00201 // Copy submeshes first 00202 std::vector<SubMesh*>::iterator subi; 00203 SubMesh* newSub; 00204 for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi) 00205 { 00206 newSub = newMesh->createSubMesh(); 00207 newSub->mMaterialName = (*subi)->mMaterialName; 00208 newSub->mMatInitialised = (*subi)->mMatInitialised; 00209 newSub->parent = newMesh; 00210 newSub->useSharedVertices = (*subi)->useSharedVertices; 00211 00212 if (!(*subi)->useSharedVertices) 00213 { 00214 // Copy unique vertex data 00215 newSub->vertexData = (*subi)->vertexData->clone(); 00216 } 00217 00218 // Copy index data 00219 newSub->indexData = (*subi)->indexData->clone(); 00220 // Copy any bone assignments 00221 newSub->mBoneAssignments = (*subi)->mBoneAssignments; 00222 newSub->mBoneAssignmentsOutOfDate = (*subi)->mBoneAssignmentsOutOfDate; 00223 newSub->mMatInitialised = (*subi)->mMatInitialised; 00224 00225 } 00226 00227 // Copy shared geometry, if any 00228 if (sharedVertexData) 00229 { 00230 newMesh->sharedVertexData = sharedVertexData->clone(); 00231 } 00232 00233 // Copy submesh names 00234 newMesh->mSubMeshNameMap = mSubMeshNameMap ; 00235 // Copy any bone assignments 00236 newMesh->mBoneAssignments = mBoneAssignments; 00237 // Copy bounds 00238 newMesh->mAABB = mAABB; 00239 newMesh->mBoundRadius = mBoundRadius; 00240 // copy BoneAssignment information 00241 newMesh->mBoneAssignmentsOutOfDate = mBoneAssignmentsOutOfDate; 00242 newMesh->mUseSoftwareBlending = mUseSoftwareBlending; 00243 00244 newMesh->mIsLodManual = mIsLodManual; 00245 newMesh->mNumLods = mNumLods; 00246 newMesh->mMeshLodUsageList = mMeshLodUsageList; 00247 00248 newMesh->mVertexBufferUsage = mVertexBufferUsage; 00249 newMesh->mIndexBufferUsage = mIndexBufferUsage; 00250 newMesh->mVertexBufferShadowBuffer = mVertexBufferShadowBuffer; 00251 newMesh->mIndexBufferShadowBuffer = mIndexBufferShadowBuffer; 00252 00253 newMesh->mSkeletonName = mSkeletonName; 00254 newMesh->mSkeleton = mSkeleton; 00255 00256 return newMesh; 00257 00258 } 00259 //----------------------------------------------------------------------- 00260 /* 00261 void Mesh::_updateBounds(void) 00262 { 00263 Vector3 min, max; 00264 bool first = true; 00265 bool useShared = false; 00266 00267 Real maxSquaredLength = -1.0f; 00268 00269 // Loop through SubMeshes, find extents 00270 SubMeshList::iterator i; 00271 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00272 { 00273 if (!(*i)->useSharedVertices) 00274 { 00275 (*i)->vertexData->getBounds(&mAABB, &maxSquaredLength); 00276 } 00277 } 00278 00279 // Check shared 00280 if (sharedVertexData) 00281 { 00282 sharedVertexData->getBounds(&mAABB, &maxSquaredLength); 00283 } 00284 00285 // Pad out the AABB a little, helps with most bounds tests 00286 mAABB.setExtents(mAABB.getMinimum() - Vector3::UNIT_SCALE, 00287 mAABB.getMaximum() + Vector3::UNIT_SCALE); 00288 // Pad out the sphere a little too 00289 mBoundRadius = Math::Sqrt(maxSquaredLength) * 1.25; 00290 mUpdateBounds = false; 00291 00292 } 00293 */ 00294 //----------------------------------------------------------------------- 00295 const AxisAlignedBox& Mesh::getBounds(void) const 00296 { 00297 /* 00298 if (mUpdateBounds) 00299 _updateBounds(); 00300 */ 00301 return mAABB; 00302 } 00303 //----------------------------------------------------------------------- 00304 void Mesh::_setBounds(const AxisAlignedBox& bounds) 00305 { 00306 mAABB = bounds; 00307 // Pad out the AABB a little, helps with most bounds tests 00308 mAABB.setExtents(mAABB.getMinimum() - Vector3::UNIT_SCALE, 00309 mAABB.getMaximum() + Vector3::UNIT_SCALE); 00310 00311 // Set sphere bouds; not the tightest by since we're using 00312 // manual AABB it is the only way 00313 Real sqLen1 = mAABB.getMinimum().squaredLength(); 00314 Real sqLen2 = mAABB.getMaximum().squaredLength(); 00315 mBoundRadius = Math::Sqrt(std::max(sqLen1, sqLen2)); 00316 // Pad out the sphere a little too 00317 mBoundRadius = mBoundRadius + 1; 00318 00319 //mUpdateBounds = false; 00320 } 00321 //----------------------------------------------------------------------- 00322 void Mesh::_setBoundingSphereRadius(Real radius) 00323 { 00324 mBoundRadius = radius; 00325 } 00326 //----------------------------------------------------------------------- 00327 void Mesh::setSkeletonName(const String& skelName) 00328 { 00329 mSkeletonName = skelName; 00330 00331 if (skelName == "") 00332 { 00333 // No skeleton 00334 mSkeleton = 0; 00335 } 00336 else 00337 { 00338 // Load skeleton 00339 try { 00340 mSkeleton = SkeletonManager::getSingleton().load(skelName); 00341 } 00342 catch (...) 00343 { 00344 mSkeleton = 0; 00345 // Log this error 00346 String msg = "Unable to load skeleton "; 00347 msg << skelName << " for Mesh " << mName 00348 << " This Mesh will not be animated. "; 00349 LogManager::getSingleton().logMessage(msg); 00350 00351 } 00352 00353 00354 } 00355 } 00356 //----------------------------------------------------------------------- 00357 bool Mesh::hasSkeleton(void) const 00358 { 00359 return !(mSkeletonName.empty()); 00360 } 00361 //----------------------------------------------------------------------- 00362 Skeleton* Mesh::getSkeleton(void) const 00363 { 00364 return mSkeleton; 00365 } 00366 //----------------------------------------------------------------------- 00367 void Mesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign) 00368 { 00369 mBoneAssignments.insert( 00370 VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign)); 00371 mBoneAssignmentsOutOfDate = true; 00372 } 00373 //----------------------------------------------------------------------- 00374 void Mesh::clearBoneAssignments(void) 00375 { 00376 mBoneAssignments.clear(); 00377 mBoneAssignmentsOutOfDate = true; 00378 } 00379 //----------------------------------------------------------------------- 00380 void Mesh::_initAnimationState(AnimationStateSet* animSet) 00381 { 00382 // Delegate to Skeleton 00383 assert(mSkeleton && "Skeleton not present"); 00384 mSkeleton->_initAnimationState(animSet); 00385 00386 // Take the opportunity to update the compiled bone assignments 00387 if (mBoneAssignmentsOutOfDate) 00388 _compileBoneAssignments(); 00389 00390 SubMeshList::iterator i; 00391 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00392 { 00393 if ((*i)->mBoneAssignmentsOutOfDate) 00394 { 00395 (*i)->_compileBoneAssignments(); 00396 } 00397 } 00398 } 00399 //----------------------------------------------------------------------- 00400 unsigned short Mesh::_getNumBoneMatrices(void) const 00401 { 00402 // Delegate to Skeleton 00403 assert(mSkeleton && "Skeleton not present"); 00404 00405 return mSkeleton->getNumBones(); 00406 } 00407 //----------------------------------------------------------------------- 00408 void Mesh::_getBoneMatrices(const AnimationStateSet& animSet, Matrix4* pMatrices) 00409 { 00410 // Delegate to Skeleton 00411 assert(mSkeleton && "Skeleton not present"); 00412 00413 mSkeleton->setAnimationState(animSet); 00414 mSkeleton->_getBoneMatrices(pMatrices); 00415 00416 } 00417 //----------------------------------------------------------------------- 00418 typedef std::multimap<Real, Mesh::VertexBoneAssignmentList::iterator> WeightIteratorMap; 00419 unsigned short Mesh::_rationaliseBoneAssignments(size_t vertexCount, Mesh::VertexBoneAssignmentList& assignments) 00420 { 00421 // Iterate through, finding the largest # bones per vertex 00422 unsigned short maxBones = 0; 00423 unsigned short currBones; 00424 currBones = 0; 00425 VertexBoneAssignmentList::iterator i; 00426 00427 for (size_t v = 0; v < vertexCount; ++v) 00428 { 00429 // Get number of entries for this vertex 00430 currBones = static_cast<unsigned short>(assignments.count(v)); 00431 00432 // Deal with max bones update 00433 // (note this will record maxBones even if they exceed limit) 00434 if (maxBones < currBones) 00435 maxBones = currBones; 00436 // does the number of bone assignments exceed limit? 00437 if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00438 { 00439 // To many bone assignments on this vertex 00440 // Find the start & end (end is in iterator terms ie exclusive) 00441 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> range; 00442 // map to sort by weight 00443 WeightIteratorMap weightToAssignmentMap; 00444 range = assignments.equal_range(v); 00445 // Add all the assignments to map 00446 for (i = range.first; i != range.second; ++i) 00447 { 00448 // insert value weight->iterator 00449 weightToAssignmentMap.insert( 00450 WeightIteratorMap::value_type(i->second.weight, i)); 00451 } 00452 // Reverse iterate over weight map, remove lowest n 00453 unsigned short numToRemove = currBones - OGRE_MAX_BLEND_WEIGHTS; 00454 WeightIteratorMap::iterator remIt = weightToAssignmentMap.begin(); 00455 00456 while (numToRemove--) 00457 { 00458 // Erase this one 00459 assignments.erase(remIt->second); 00460 ++remIt; 00461 } 00462 } // if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00463 00464 // Make sure the weights are normalised 00465 // Do this irrespective of whether we had to remove assignments or not 00466 // since it gives us a guarantee that weights are normalised 00467 // We assume this, so it's a good idea since some modellers may not 00468 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> normalise_range = assignments.equal_range(v); 00469 Real totalWeight = 0; 00470 // Find total first 00471 for (i = normalise_range.first; i != normalise_range.second; ++i) 00472 { 00473 totalWeight += i->second.weight; 00474 } 00475 // Now normalise if total weight is outside tolerance 00476 if (!Math::RealEqual(totalWeight, 1.0f)) 00477 { 00478 for (i = normalise_range.first; i != normalise_range.second; ++i) 00479 { 00480 i->second.weight = i->second.weight / totalWeight; 00481 } 00482 } 00483 00484 } 00485 00486 if (maxBones > OGRE_MAX_BLEND_WEIGHTS) 00487 { 00488 // Warn that we've reduced bone assignments 00489 LogManager::getSingleton().logMessage("WARNING: the mesh '" + mName + "' " 00490 "includes vertices with more than " + 00491 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + " bone assignments. " 00492 "The lowest weighted assignments beyond this limit have been removed, so " 00493 "your animation may look slightly different. To eliminate this, reduce " 00494 "the number of bone assignments per vertex on your mesh to " + 00495 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + "."); 00496 // we've adjusted them down to the max 00497 maxBones = OGRE_MAX_BLEND_WEIGHTS; 00498 00499 } 00500 00501 return maxBones; 00502 } 00503 //----------------------------------------------------------------------- 00504 void Mesh::_compileBoneAssignments(void) 00505 { 00506 unsigned short maxBones = 00507 _rationaliseBoneAssignments(sharedVertexData->vertexCount, mBoneAssignments); 00508 00509 if (maxBones == 0) 00510 { 00511 // No bone assignments 00512 return; 00513 } 00514 00515 if (mUseSoftwareBlending) 00516 { 00517 compileBoneAssignmentsSoftware(mBoneAssignments, maxBones, sharedVertexData); 00518 } 00519 else 00520 { 00521 compileBoneAssignmentsHardware(mBoneAssignments, maxBones, sharedVertexData); 00522 } 00523 00524 mBoneAssignmentsOutOfDate = false; 00525 00526 } 00527 //--------------------------------------------------------------------- 00528 void Mesh::compileBoneAssignmentsSoftware( 00529 const VertexBoneAssignmentList& boneAssignments, 00530 unsigned short numBlendWeightsPerVertex, VertexData* targetVertexData) 00531 { 00532 // Delete old data if it's there 00533 if (targetVertexData->softwareBlendInfo->pBlendIndexes) 00534 delete[] targetVertexData->softwareBlendInfo->pBlendIndexes; 00535 if (targetVertexData->softwareBlendInfo->pBlendWeights) 00536 delete[] targetVertexData->softwareBlendInfo->pBlendWeights; 00537 // Allocate new data 00538 targetVertexData->softwareBlendInfo->pBlendIndexes = 00539 new unsigned char[targetVertexData->vertexCount * numBlendWeightsPerVertex]; 00540 targetVertexData->softwareBlendInfo->pBlendWeights = 00541 new Real[targetVertexData->vertexCount * numBlendWeightsPerVertex]; 00542 // Assign data 00543 size_t v; 00544 VertexBoneAssignmentList::const_iterator i; 00545 i = boneAssignments.begin(); 00546 Real *pWeight = targetVertexData->softwareBlendInfo->pBlendWeights; 00547 unsigned char* pIndex = targetVertexData->softwareBlendInfo->pBlendIndexes; 00548 // Iterate by vertex 00549 for (v = 0; v < targetVertexData->vertexCount; ++v) 00550 { 00551 for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone) 00552 { 00553 // Do we still have data for this vertex? 00554 if (i->second.vertexIndex == v) 00555 { 00556 // If so, write weight 00557 *pWeight++ = i->second.weight; 00558 *pIndex++ = i->second.boneIndex; 00559 ++i; 00560 } 00561 else 00562 { 00563 // Ran out of assignments for this vertex, use weight 0 to indicate empty 00564 *pWeight++ = 0.0f; 00565 *pIndex++ = 0; 00566 } 00567 } 00568 } 00569 00570 // Set blend weight info 00571 targetVertexData->softwareBlendInfo->numWeightsPerVertex = numBlendWeightsPerVertex; 00572 00573 } 00574 //--------------------------------------------------------------------- 00575 void Mesh::compileBoneAssignmentsHardware( 00576 const VertexBoneAssignmentList& boneAssignments, 00577 unsigned short numBlendWeightsPerVertex, VertexData* targetVertexData) 00578 00579 { 00580 // No deallocation required, shared ptr will deal with that 00581 // Update vertex declaration - remove existing if present 00582 bool shareBindIndex = false; 00583 unsigned short bindIndex; 00584 VertexDeclaration* decl = targetVertexData->vertexDeclaration; 00585 if (const VertexElement* elem = decl->findElementBySemantic(VES_BLEND_INDICES)) 00586 { 00587 bindIndex = elem->getIndex(); // reuse 00588 shareBindIndex = true; 00589 decl->removeElement(VES_BLEND_INDICES); 00590 } 00591 if (decl->findElementBySemantic(VES_BLEND_WEIGHTS)) 00592 { 00593 decl->removeElement(VES_BLEND_WEIGHTS); 00594 } 00595 // If binding not found already, get next 00596 if (!shareBindIndex) 00597 bindIndex = targetVertexData->vertexBufferBinding->getNextIndex(); 00598 // Add declarations for weights and indices 00599 decl->addElement( 00600 bindIndex, 00601 0, 00602 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex), 00603 VES_BLEND_WEIGHTS); 00604 decl->addElement( 00605 bindIndex, 00606 sizeof(float) * numBlendWeightsPerVertex, 00607 VertexElement::multiplyTypeCount(VET_SHORT1, numBlendWeightsPerVertex), 00608 VES_BLEND_INDICES); 00609 // Create buffer (will destroy old one because of reference counting) 00610 // NB we create in system memory because we need to read this back later 00611 mBlendingVB = HardwareBufferManager::getSingleton().createVertexBuffer( 00612 decl->getVertexSize(bindIndex), targetVertexData->vertexCount, 00613 HardwareBuffer::HBU_DYNAMIC, true); 00614 // Set binding 00615 targetVertexData->vertexBufferBinding->setBinding(bindIndex, mBlendingVB); 00616 00617 // Assign data 00618 size_t v; 00619 VertexBoneAssignmentList::const_iterator i; 00620 i = boneAssignments.begin(); 00621 Real *pWeight = static_cast<Real*>( 00622 mBlendingVB->lock(HardwareBuffer::HBL_DISCARD)); 00623 // Iterate by vertex 00624 for (v = 0; v < targetVertexData->vertexCount; ++v) 00625 { 00627 unsigned short *pIndex = static_cast<unsigned short*>( 00628 static_cast<void*>( 00629 pWeight + numBlendWeightsPerVertex) 00630 ); 00631 for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone) 00632 { 00633 // Do we still have data for this vertex? 00634 if (i->second.vertexIndex == v) 00635 { 00636 // If so, write weight 00637 *pWeight++ = i->second.weight; 00638 *pIndex++ = i->second.boneIndex; 00639 ++i; 00640 } 00641 else 00642 { 00643 // Ran out of assignments for this vertex, use weight 0 to indicate empty 00644 *pWeight++ = 0.0f; 00645 *pIndex++ = 0; 00646 } 00647 } 00648 } 00649 00650 mBlendingVB->unlock(); 00651 } 00652 //--------------------------------------------------------------------- 00653 void Mesh::_notifySkeleton(Skeleton* pSkel) 00654 { 00655 mSkeleton = pSkel; 00656 mSkeletonName = pSkel->getName(); 00657 } 00658 //--------------------------------------------------------------------- 00659 Mesh::BoneAssignmentIterator Mesh::getBoneAssignmentIterator(void) 00660 { 00661 return BoneAssignmentIterator(mBoneAssignments.begin(), 00662 mBoneAssignments.end()); 00663 } 00664 //--------------------------------------------------------------------- 00665 const String& Mesh::getSkeletonName(void) const 00666 { 00667 return mSkeletonName; 00668 } 00669 //--------------------------------------------------------------------- 00670 void Mesh::generateLodLevels(const LodDistanceList& lodDistances, 00671 ProgressiveMesh::VertexReductionQuota reductionMethod, Real reductionValue) 00672 { 00673 mMeshLodUsageList.clear(); 00674 mIsLodManual = false; 00675 00676 char msg[128]; 00677 sprintf(msg, "Generating %d lower LODs for mesh %s.", 00678 lodDistances.size(), mName.c_str()); 00679 LogManager::getSingleton().logMessage(msg); 00680 00681 SubMeshList::iterator isub, isubend; 00682 isubend = mSubMeshList.end(); 00683 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00684 { 00685 // Set up data for reduction 00686 VertexData* pVertexData = (*isub)->useSharedVertices ? sharedVertexData : (*isub)->vertexData; 00687 00688 ProgressiveMesh pm(pVertexData, (*isub)->indexData); 00689 pm.build( 00690 static_cast<ushort>(lodDistances.size()), 00691 &((*isub)->mLodFaceList), 00692 reductionMethod, reductionValue); 00693 00694 } 00695 00696 // Iterate over the lods and record usage 00697 LodDistanceList::const_iterator idist, idistend; 00698 idistend = lodDistances.end(); 00699 // Record first LOD (full detail) 00700 MeshLodUsage lod; 00701 lod.fromDepthSquared = 0.0f; 00702 mMeshLodUsageList.push_back(lod); 00703 00704 for (idist = lodDistances.begin(); idist != idistend; ++idist) 00705 { 00706 // Record usage 00707 lod.fromDepthSquared = (*idist) * (*idist); 00708 mMeshLodUsageList.push_back(lod); 00709 00710 } 00711 mNumLods = static_cast<ushort>(lodDistances.size() + 1); 00712 } 00713 //--------------------------------------------------------------------- 00714 ushort Mesh::getNumLodLevels(void) const 00715 { 00716 return mNumLods; 00717 } 00718 //--------------------------------------------------------------------- 00719 const Mesh::MeshLodUsage& Mesh::getLodLevel(ushort index) const 00720 { 00721 assert(index < mMeshLodUsageList.size()); 00722 if (mIsLodManual && mMeshLodUsageList[index].manualMesh == NULL) 00723 { 00724 // Load the mesh now 00725 mMeshLodUsageList[index].manualMesh = 00726 MeshManager::getSingleton().load(mMeshLodUsageList[index].manualName); 00727 } 00728 return mMeshLodUsageList[index]; 00729 } 00730 //--------------------------------------------------------------------- 00731 struct ManualLodSortLess : 00732 public std::binary_function<const Mesh::MeshLodUsage&, const Mesh::MeshLodUsage&, bool> 00733 { 00734 bool operator() (const Mesh::MeshLodUsage& mesh1, const Mesh::MeshLodUsage& mesh2) 00735 { 00736 // sort ascending by depth 00737 return mesh1.fromDepthSquared < mesh2.fromDepthSquared; 00738 } 00739 }; 00740 void Mesh::createManualLodLevel(Real fromDepth, const String& meshName) 00741 { 00742 mIsLodManual = true; 00743 MeshLodUsage lod; 00744 lod.fromDepthSquared = fromDepth * fromDepth; 00745 lod.manualName = meshName; 00746 lod.manualMesh = NULL; 00747 mMeshLodUsageList.push_back(lod); 00748 ++mNumLods; 00749 00750 std::sort(mMeshLodUsageList.begin(), mMeshLodUsageList.end(), ManualLodSortLess()); 00751 } 00752 //--------------------------------------------------------------------- 00753 void Mesh::updateManualLodLevel(ushort index, const String& meshName) 00754 { 00755 // Basic prerequisites 00756 assert(mIsLodManual && "Not using manual LODs!"); 00757 assert(index != 0 && "Can't modify first lod level (full detail)"); 00758 assert(index < mMeshLodUsageList.size() && "Index out of bounds"); 00759 // get lod 00760 MeshLodUsage* lod = &(mMeshLodUsageList[index]); 00761 00762 lod->manualName = meshName; 00763 lod->manualMesh = NULL; 00764 } 00765 //--------------------------------------------------------------------- 00766 ushort Mesh::getLodIndex(Real depth) const 00767 { 00768 return getLodIndexSquaredDepth(depth * depth); 00769 } 00770 //--------------------------------------------------------------------- 00771 ushort Mesh::getLodIndexSquaredDepth(Real squaredDepth) const 00772 { 00773 MeshLodUsageList::const_iterator i, iend; 00774 iend = mMeshLodUsageList.end(); 00775 ushort index = 0; 00776 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 00777 { 00778 if (i->fromDepthSquared > squaredDepth) 00779 { 00780 return index - 1; 00781 } 00782 } 00783 00784 // If we fall all the way through, use the highest value 00785 return static_cast<ushort>(mMeshLodUsageList.size() - 1); 00786 00787 00788 } 00789 //--------------------------------------------------------------------- 00790 void Mesh::_setLodInfo(unsigned short numLevels, bool isManual) 00791 { 00792 mNumLods = numLevels; 00793 mMeshLodUsageList.resize(numLevels); 00794 // Resize submesh face data lists too 00795 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00796 { 00797 (*i)->mLodFaceList.resize(numLevels - 1); 00798 } 00799 mIsLodManual = isManual; 00800 } 00801 //--------------------------------------------------------------------- 00802 void Mesh::_setLodUsage(unsigned short level, Mesh::MeshLodUsage& usage) 00803 { 00804 mMeshLodUsageList[level] = usage; 00805 } 00806 //--------------------------------------------------------------------- 00807 void Mesh::_setSubMeshLodFaceList(unsigned short subIdx, unsigned short level, 00808 IndexData* facedata) 00809 { 00810 SubMesh* sm = mSubMeshList[subIdx]; 00811 sm->mLodFaceList[level - 1] = facedata; 00812 00813 } 00814 //--------------------------------------------------------------------- 00815 ushort Mesh::_getSubMeshIndex(const String& name) const 00816 { 00817 SubMeshNameMap::const_iterator i = mSubMeshNameMap.find(name) ; 00818 if (i == mSubMeshNameMap.end()) 00819 Except(Exception::ERR_ITEM_NOT_FOUND, "No SubMesh named " + name + " found.", 00820 "Mesh::_getSubMeshIndex"); 00821 00822 return i->second; 00823 } 00824 //--------------------------------------------------------------------- 00825 void Mesh::removeLodLevels(void) 00826 { 00827 if (!mIsLodManual) 00828 { 00829 // Remove data from SubMeshes 00830 SubMeshList::iterator isub, isubend; 00831 isubend = mSubMeshList.end(); 00832 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00833 { 00834 (*isub)->removeLodLevels(); 00835 } 00836 } 00837 00838 mMeshLodUsageList.clear(); 00839 00840 // Reinitialise 00841 mNumLods = 1; 00842 // Init first (manual) lod 00843 MeshLodUsage lod; 00844 lod.fromDepthSquared = 0.0f; 00845 mMeshLodUsageList.push_back(lod); 00846 mIsLodManual = false; 00847 00848 00849 } 00850 //--------------------------------------------------------------------- 00851 Real Mesh::getBoundingSphereRadius(void) const 00852 { 00853 return mBoundRadius; 00854 } 00855 //--------------------------------------------------------------------- 00856 void Mesh::setVertexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00857 { 00858 mVertexBufferUsage = vbUsage; 00859 mVertexBufferShadowBuffer = shadowBuffer; 00860 } 00861 //--------------------------------------------------------------------- 00862 void Mesh::setIndexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00863 { 00864 mIndexBufferUsage = vbUsage; 00865 mIndexBufferShadowBuffer = shadowBuffer; 00866 } 00867 //--------------------------------------------------------------------- 00868 HardwareVertexBufferSharedPtr Mesh::getTangentsBuffer(VertexData *vertexData, 00869 unsigned short texCoordSet) 00870 { 00871 VertexDeclaration *vDecl = vertexData->vertexDeclaration ; 00872 VertexBufferBinding *vBind = vertexData->vertexBufferBinding ; 00873 00874 const VertexElement *tex3D = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, texCoordSet); 00875 bool needsToBeCreated = false; 00876 00877 if (!tex3D) 00878 { // no tex coords with index 1 00879 needsToBeCreated = true ; 00880 } 00881 else if (tex3D->getType() != VET_FLOAT3) 00882 { // no 3d-coords tex buffer 00883 vDecl->removeElement(VES_TEXTURE_COORDINATES, texCoordSet); 00884 vBind->unsetBinding(tex3D->getSource()); 00885 needsToBeCreated = true ; 00886 } 00887 00888 HardwareVertexBufferSharedPtr tex3DBuf ; 00889 if (needsToBeCreated) 00890 { 00891 tex3DBuf = HardwareBufferManager::getSingleton().createVertexBuffer( 00892 3*sizeof(float), vertexData->vertexCount, 00893 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 00894 true ); 00895 int source = vBind->getNextIndex()+1; // find next available source 00896 vBind->setBinding(source, tex3DBuf); 00897 vDecl->addElement(source, 0, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoordSet); 00898 } 00899 else 00900 { 00901 tex3DBuf = vBind->getBuffer(tex3D->getSource()); 00902 } 00903 00904 return tex3DBuf; 00905 } 00906 //--------------------------------------------------------------------- 00907 void Mesh::buildTangentVectors(unsigned short sourceTexCoordSet, 00908 unsigned short destTexCoordSet) 00909 { 00910 00911 // our temp. buffers 00912 unsigned short vertInd[3]; 00913 Vector3 vertPos[3]; 00914 Real u[3], v[3]; 00915 // setup a new 3D texture coord-set buffer for every sub mesh 00916 int nSubMesh = getNumSubMeshes(); 00917 for (int sm = 0; sm < nSubMesh; sm++) 00918 { 00919 // retrieve buffer pointers 00920 unsigned short *pVIndices; // the face indices buffer, read only 00921 Real *p2DTC; // pointer to 2D tex.coords, read only 00922 Real *p3DTC; // pointer to 3D tex.coords, write/read (discard) 00923 Real *pVPos; // vertex position buffer, read only 00924 00925 SubMesh *pSubMesh = getSubMesh(sm); 00926 00927 // retrieve buffer pointers 00928 // first, indices 00929 IndexData *indexData = pSubMesh->indexData; 00930 HardwareIndexBufferSharedPtr buffIndex = indexData->indexBuffer ; 00931 pVIndices = (unsigned short*) buffIndex->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00932 // then, vertices 00933 VertexData *usedVertexData ; 00934 if (pSubMesh->useSharedVertices) { 00935 usedVertexData = sharedVertexData; 00936 } else { 00937 usedVertexData = pSubMesh->vertexData; 00938 } 00939 VertexDeclaration *vDecl = usedVertexData->vertexDeclaration; 00940 VertexBufferBinding *vBind = usedVertexData->vertexBufferBinding; 00941 00942 00943 // get a new 3D tex.coord.buffer or an existing one 00944 HardwareVertexBufferSharedPtr buff3DTC = getTangentsBuffer(usedVertexData, destTexCoordSet); 00945 // clear it 00946 p3DTC = (Real*) buff3DTC->lock(HardwareBuffer::HBL_DISCARD); // ***LOCK*** 00947 memset(p3DTC,0,buff3DTC->getSizeInBytes()); 00948 // find a 2D tex coord buffer 00949 const VertexElement *elem2DTC = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, sourceTexCoordSet); 00950 00951 if (!elem2DTC || elem2DTC->getType() != VET_FLOAT2) 00952 { 00953 Except(Exception::ERR_INVALIDPARAMS, 00954 "SubMesh " + StringConverter::toString(sm) + " of Mesh " + mName + 00955 " has no 2D texture coordinates, therefore we cannot calculate tangents.", 00956 "Mesh::buildTangentVectors"); 00957 } 00958 HardwareVertexBufferSharedPtr buff2DTC = vBind->getBuffer(elem2DTC->getSource()); 00959 p2DTC = (Real*) buff2DTC->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00960 // find a vertex coord buffer 00961 const VertexElement *elemVPos = vDecl->findElementBySemantic(VES_POSITION); 00962 HardwareVertexBufferSharedPtr buffVPos = vBind->getBuffer(elemVPos->getSource()); 00963 pVPos = (Real*) buffVPos->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00964 00965 size_t numFaces = indexData->indexCount / 3 ; 00966 00967 // loop through all faces to calculate the tangents and normals 00968 size_t n; 00969 for (n = 0; n < numFaces; ++n) 00970 { 00971 int i; 00972 for (i = 0; i < 3; ++i) 00973 { 00974 // get indexes of vertices that form a polygon in the position buffer 00975 vertInd[i] = *pVIndices++; 00976 // get the vertices positions from the position buffer 00977 vertPos[i].x = pVPos[3 * vertInd[i] + 0]; 00978 vertPos[i].y = pVPos[3 * vertInd[i] + 1]; 00979 vertPos[i].z = pVPos[3 * vertInd[i] + 2]; 00980 // get the vertices tex.coords from the 2D tex.coords buffer 00981 u[i] = p2DTC[2 * vertInd[i] + 0]; 00982 v[i] = p2DTC[2 * vertInd[i] + 1]; 00983 } 00984 // calculate the TSB 00985 Vector3 tangent = Math::calculateTangentSpaceVector( 00986 vertPos[0], vertPos[1], vertPos[2], 00987 u[0], v[0], u[1], v[1], u[2], v[2]); 00988 // write new tex.coords 00989 // note we only write the tangent, not the binormal since we can calculate 00990 // the binormal in the vertex program 00991 for (i = 0; i < 3; ++i) 00992 { 00993 // write values (they must be 0 and we must add them so we can average 00994 // all the contributions from all the faces 00995 p3DTC[3 * vertInd[i] + 0] += tangent.x; 00996 p3DTC[3 * vertInd[i] + 1] += tangent.y; 00997 p3DTC[3 * vertInd[i] + 2] += tangent.z; 00998 } 00999 } 01000 // now loop through all vertices and normalize them 01001 size_t numVerts = usedVertexData->vertexCount ; 01002 for (n = 0; n < numVerts * 3; n += 3) 01003 { 01004 // read the vertex 01005 Vector3 temp(p3DTC[n + 0], p3DTC[n + 1], p3DTC[n + 2]); 01006 // normalize the vertex 01007 temp.normalise(); 01008 // write it back 01009 p3DTC[n + 0] = temp.x; 01010 p3DTC[n + 1] = temp.y; 01011 p3DTC[n + 2] = temp.z; 01012 } 01013 // unlock buffers 01014 buffIndex->unlock(); 01015 buff3DTC->unlock(); 01016 buff2DTC->unlock(); 01017 buffVPos->unlock(); 01018 } 01019 01020 } 01021 01022 } 01023
Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:18 2004