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 #include "OgreEdgeListBuilder.h" 00040 00041 namespace Ogre { 00042 00043 //----------------------------------------------------------------------- 00044 Mesh::Mesh(const String& name) 00045 { 00046 mName = name; 00047 sharedVertexData = NULL; 00048 00049 // Default to load from file 00050 mManuallyDefined = false; 00051 setSkeletonName(""); 00052 mBoneAssignmentsOutOfDate = false; 00053 mNumLods = 1; 00054 // Init first (manual) lod 00055 MeshLodUsage lod; 00056 lod.fromDepthSquared = 0.0f; 00057 lod.edgeData = NULL; 00058 lod.manualMesh = NULL; 00059 mMeshLodUsageList.push_back(lod); 00060 mIsLodManual = false; 00061 00062 mVertexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00063 mIndexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00064 mVertexBufferShadowBuffer = true; 00065 mIndexBufferShadowBuffer = true; 00066 00067 mBoundRadius = 0.0f; 00068 00069 mPreparedForShadowVolumes = false; 00070 mEdgeListsBuilt = false; 00071 mAutoBuildEdgeLists = true; // will be set to false by serializers of 1.30 and above 00072 00073 } 00074 00075 //----------------------------------------------------------------------- 00076 Mesh::~Mesh() 00077 { 00078 if (mIsLoaded) 00079 { 00080 unload(); 00081 } 00082 } 00083 00084 //----------------------------------------------------------------------- 00085 SubMesh* Mesh::createSubMesh() 00086 { 00087 SubMesh* sub = new SubMesh(); 00088 sub->parent = this; 00089 00090 mSubMeshList.push_back(sub); 00091 00092 return sub; 00093 } 00094 //----------------------------------------------------------------------- 00095 SubMesh* Mesh::createSubMesh(const String& name) 00096 { 00097 SubMesh *sub = createSubMesh(); 00098 nameSubMesh(name, (ushort)mSubMeshList.size()-1); 00099 return sub ; 00100 } 00101 //----------------------------------------------------------------------- 00102 unsigned short Mesh::getNumSubMeshes() const 00103 { 00104 return static_cast< unsigned short >( mSubMeshList.size() ); 00105 } 00106 00107 //--------------------------------------------------------------------- 00108 void Mesh::nameSubMesh(const String& name, ushort index) 00109 { 00110 mSubMeshNameMap[name] = index ; 00111 } 00112 00113 //----------------------------------------------------------------------- 00114 SubMesh* Mesh::getSubMesh(const String& name) const 00115 { 00116 ushort index = _getSubMeshIndex(name); 00117 return getSubMesh(index); 00118 } 00119 //----------------------------------------------------------------------- 00120 SubMesh* Mesh::getSubMesh(unsigned short index) const 00121 { 00122 SubMeshList::const_iterator i = mSubMeshList.begin(); 00123 return const_cast<SubMesh*>(i[index]); 00124 } 00125 //----------------------------------------------------------------------- 00126 void Mesh::load() 00127 { 00128 // Load from specified 'name' 00129 if (mIsLoaded) 00130 { 00131 unload(); 00132 } 00133 00134 if (!mManuallyDefined) 00135 { 00136 MeshSerializer serializer; 00137 LogManager::getSingleton().logMessage("Mesh: Loading " + mName + "."); 00138 00139 DataChunk chunk; 00140 MeshManager::getSingleton()._findResourceData(mName, chunk); 00141 00142 // Determine file type 00143 std::vector<String> extVec = StringUtil::split(mName, "."); 00144 00145 String& ext = extVec[extVec.size() - 1]; 00146 StringUtil::toLowerCase(ext); 00147 00148 if (ext == "mesh") 00149 { 00150 serializer.importMesh(chunk, this); 00151 } 00152 else 00153 { 00154 // Unsupported format 00155 chunk.clear(); 00156 Except(999, "Unsupported object file format.", 00157 "Mesh::load"); 00158 } 00159 00160 chunk.clear(); 00161 } 00162 00163 // Prepare for shadow volumes? 00164 if (MeshManager::getSingleton().getPrepareAllMeshesForShadowVolumes()) 00165 { 00166 if (mEdgeListsBuilt || mAutoBuildEdgeLists) 00167 { 00168 prepareForShadowVolume(); 00169 } 00170 00171 if (!mEdgeListsBuilt && mAutoBuildEdgeLists) 00172 { 00173 buildEdgeList(); 00174 } 00175 } 00176 00177 mIsLoaded = true; 00178 00179 //_updateBounds(); 00180 00181 } 00182 00183 //----------------------------------------------------------------------- 00184 void Mesh::unload() 00185 { 00186 // Teardown submeshes 00187 for (SubMeshList::iterator i = mSubMeshList.begin(); 00188 i != mSubMeshList.end(); ++i) 00189 { 00190 delete *i; 00191 } 00192 if (sharedVertexData) 00193 { 00194 delete sharedVertexData; 00195 sharedVertexData = NULL; 00196 } 00197 // Clear SubMesh lists 00198 mSubMeshList.clear(); 00199 mSubMeshNameMap.clear(); 00200 // Removes all LOD data 00201 removeLodLevels(); 00202 mPreparedForShadowVolumes = false; 00203 mIsLoaded = false; 00204 } 00205 00206 //----------------------------------------------------------------------- 00207 void Mesh::setManuallyDefined(bool manual) 00208 { 00209 mManuallyDefined = manual; 00210 } 00211 00212 //----------------------------------------------------------------------- 00213 Mesh* Mesh::clone(const String& newName) 00214 { 00215 // This is a bit like a copy constructor, but with the additional aspect of registering the clone with 00216 // the MeshManager 00217 00218 // New Mesh is assumed to be manually defined rather than loaded since you're cloning it for a reason 00219 Mesh* newMesh = MeshManager::getSingleton().createManual(newName); 00220 00221 // Copy submeshes first 00222 std::vector<SubMesh*>::iterator subi; 00223 SubMesh* newSub; 00224 for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi) 00225 { 00226 newSub = newMesh->createSubMesh(); 00227 newSub->mMaterialName = (*subi)->mMaterialName; 00228 newSub->mMatInitialised = (*subi)->mMatInitialised; 00229 newSub->operationType = (*subi)->operationType; 00230 newSub->useSharedVertices = (*subi)->useSharedVertices; 00231 00232 if (!(*subi)->useSharedVertices) 00233 { 00234 // Copy unique vertex data 00235 newSub->vertexData = (*subi)->vertexData->clone(); 00236 } 00237 00238 // Copy index data 00239 delete newSub->indexData; 00240 newSub->indexData = (*subi)->indexData->clone(); 00241 // Copy any bone assignments 00242 newSub->mBoneAssignments = (*subi)->mBoneAssignments; 00243 newSub->mBoneAssignmentsOutOfDate = (*subi)->mBoneAssignmentsOutOfDate; 00244 00245 // Copy lod face lists 00246 newSub->mLodFaceList.reserve((*subi)->mLodFaceList.size()); 00247 ProgressiveMesh::LODFaceList::const_iterator facei; 00248 for (facei = (*subi)->mLodFaceList.begin(); facei != (*subi)->mLodFaceList.end(); ++facei) { 00249 IndexData* newIndexData = (*facei)->clone(); 00250 newSub->mLodFaceList.push_back(newIndexData); 00251 } 00252 } 00253 00254 // Copy shared geometry, if any 00255 if (sharedVertexData) 00256 { 00257 newMesh->sharedVertexData = sharedVertexData->clone(); 00258 } 00259 00260 // Copy submesh names 00261 newMesh->mSubMeshNameMap = mSubMeshNameMap ; 00262 // Copy any bone assignments 00263 newMesh->mBoneAssignments = mBoneAssignments; 00264 newMesh->mBoneAssignmentsOutOfDate = mBoneAssignmentsOutOfDate; 00265 // Copy bounds 00266 newMesh->mAABB = mAABB; 00267 newMesh->mBoundRadius = mBoundRadius; 00268 00269 newMesh->mIsLodManual = mIsLodManual; 00270 newMesh->mNumLods = mNumLods; 00271 newMesh->mMeshLodUsageList = mMeshLodUsageList; 00272 // Unreference edge lists, otherwise we'll delete the same lot twice, build on demand 00273 MeshLodUsageList::iterator lodi; 00274 for (lodi = newMesh->mMeshLodUsageList.begin(); lodi != newMesh->mMeshLodUsageList.end(); ++lodi) { 00275 MeshLodUsage& lod = *lodi; 00276 lod.edgeData = NULL; 00277 // TODO: Copy manual lod meshes 00278 } 00279 00280 newMesh->mVertexBufferUsage = mVertexBufferUsage; 00281 newMesh->mIndexBufferUsage = mIndexBufferUsage; 00282 newMesh->mVertexBufferShadowBuffer = mVertexBufferShadowBuffer; 00283 newMesh->mIndexBufferShadowBuffer = mIndexBufferShadowBuffer; 00284 00285 newMesh->mSkeletonName = mSkeletonName; 00286 newMesh->mSkeleton = mSkeleton; 00287 00288 // mPreparedForShadowVolumes, mEdgeListsBuilt and edgeData of mMeshLodUsageList 00289 // will up to date on demand 00290 00291 newMesh->load(); 00292 newMesh->touch(); 00293 00294 return newMesh; 00295 00296 } 00297 //----------------------------------------------------------------------- 00298 const AxisAlignedBox& Mesh::getBounds(void) const 00299 { 00300 return mAABB; 00301 } 00302 //----------------------------------------------------------------------- 00303 void Mesh::_setBounds(const AxisAlignedBox& bounds, bool pad) 00304 { 00305 mAABB = bounds; 00306 Vector3 max = mAABB.getMaximum(); 00307 Vector3 min = mAABB.getMinimum(); 00308 00309 // Set sphere bounds; not the tightest by since we're using 00310 // manual AABB it is the only way 00311 Real sqLen1 = min.squaredLength(); 00312 Real sqLen2 = max.squaredLength(); 00313 00314 mBoundRadius = Math::Sqrt(std::max(sqLen1, sqLen2)); 00315 if (pad) 00316 { 00317 // Pad out the AABB a little, helps with most bounds tests 00318 Vector3 scaler = (max - min) * MeshManager::getSingleton().getBoundsPaddingFactor(); 00319 mAABB.setExtents(min - scaler, max + scaler); 00320 // Pad out the sphere a little too 00321 mBoundRadius = mBoundRadius + (mBoundRadius * MeshManager::getSingleton().getBoundsPaddingFactor()); 00322 } 00323 else 00324 { 00325 mAABB.setExtents(min, max); 00326 mBoundRadius = mBoundRadius; 00327 } 00328 00329 } 00330 //----------------------------------------------------------------------- 00331 void Mesh::_setBoundingSphereRadius(Real radius) 00332 { 00333 mBoundRadius = radius; 00334 } 00335 //----------------------------------------------------------------------- 00336 void Mesh::setSkeletonName(const String& skelName) 00337 { 00338 mSkeletonName = skelName; 00339 00340 if (skelName == "") 00341 { 00342 // No skeleton 00343 mSkeleton = 0; 00344 } 00345 else 00346 { 00347 // Load skeleton 00348 try { 00349 mSkeleton = SkeletonManager::getSingleton().load(skelName); 00350 } 00351 catch (...) 00352 { 00353 mSkeleton = 0; 00354 // Log this error 00355 String msg = "Unable to load skeleton "; 00356 msg += skelName + " for Mesh " + mName 00357 + ". This Mesh will not be animated. " 00358 + "You can ignore this message if you are using an offline tool."; 00359 LogManager::getSingleton().logMessage(msg); 00360 00361 } 00362 00363 00364 } 00365 } 00366 //----------------------------------------------------------------------- 00367 bool Mesh::hasSkeleton(void) const 00368 { 00369 return !(mSkeletonName.empty()); 00370 } 00371 //----------------------------------------------------------------------- 00372 Skeleton* Mesh::getSkeleton(void) const 00373 { 00374 return mSkeleton; 00375 } 00376 //----------------------------------------------------------------------- 00377 void Mesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign) 00378 { 00379 mBoneAssignments.insert( 00380 VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign)); 00381 mBoneAssignmentsOutOfDate = true; 00382 } 00383 //----------------------------------------------------------------------- 00384 void Mesh::clearBoneAssignments(void) 00385 { 00386 mBoneAssignments.clear(); 00387 mBoneAssignmentsOutOfDate = true; 00388 } 00389 //----------------------------------------------------------------------- 00390 void Mesh::_initAnimationState(AnimationStateSet* animSet) 00391 { 00392 // Delegate to Skeleton 00393 assert(mSkeleton && "Skeleton not present"); 00394 mSkeleton->_initAnimationState(animSet); 00395 00396 // Take the opportunity to update the compiled bone assignments 00397 if (mBoneAssignmentsOutOfDate) 00398 _compileBoneAssignments(); 00399 00400 SubMeshList::iterator i; 00401 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00402 { 00403 if ((*i)->mBoneAssignmentsOutOfDate) 00404 { 00405 (*i)->_compileBoneAssignments(); 00406 } 00407 } 00408 } 00409 //----------------------------------------------------------------------- 00410 typedef std::multimap<Real, Mesh::VertexBoneAssignmentList::iterator> WeightIteratorMap; 00411 unsigned short Mesh::_rationaliseBoneAssignments(size_t vertexCount, Mesh::VertexBoneAssignmentList& assignments) 00412 { 00413 // Iterate through, finding the largest # bones per vertex 00414 unsigned short maxBones = 0; 00415 unsigned short currBones; 00416 currBones = 0; 00417 VertexBoneAssignmentList::iterator i; 00418 00419 for (size_t v = 0; v < vertexCount; ++v) 00420 { 00421 // Get number of entries for this vertex 00422 currBones = static_cast<unsigned short>(assignments.count(v)); 00423 00424 // Deal with max bones update 00425 // (note this will record maxBones even if they exceed limit) 00426 if (maxBones < currBones) 00427 maxBones = currBones; 00428 // does the number of bone assignments exceed limit? 00429 if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00430 { 00431 // To many bone assignments on this vertex 00432 // Find the start & end (end is in iterator terms ie exclusive) 00433 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> range; 00434 // map to sort by weight 00435 WeightIteratorMap weightToAssignmentMap; 00436 range = assignments.equal_range(v); 00437 // Add all the assignments to map 00438 for (i = range.first; i != range.second; ++i) 00439 { 00440 // insert value weight->iterator 00441 weightToAssignmentMap.insert( 00442 WeightIteratorMap::value_type(i->second.weight, i)); 00443 } 00444 // Reverse iterate over weight map, remove lowest n 00445 unsigned short numToRemove = currBones - OGRE_MAX_BLEND_WEIGHTS; 00446 WeightIteratorMap::iterator remIt = weightToAssignmentMap.begin(); 00447 00448 while (numToRemove--) 00449 { 00450 // Erase this one 00451 assignments.erase(remIt->second); 00452 ++remIt; 00453 } 00454 } // if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00455 00456 // Make sure the weights are normalised 00457 // Do this irrespective of whether we had to remove assignments or not 00458 // since it gives us a guarantee that weights are normalised 00459 // We assume this, so it's a good idea since some modellers may not 00460 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> normalise_range = assignments.equal_range(v); 00461 Real totalWeight = 0; 00462 // Find total first 00463 for (i = normalise_range.first; i != normalise_range.second; ++i) 00464 { 00465 totalWeight += i->second.weight; 00466 } 00467 // Now normalise if total weight is outside tolerance 00468 if (!Math::RealEqual(totalWeight, 1.0f)) 00469 { 00470 for (i = normalise_range.first; i != normalise_range.second; ++i) 00471 { 00472 i->second.weight = i->second.weight / totalWeight; 00473 } 00474 } 00475 00476 } 00477 00478 if (maxBones > OGRE_MAX_BLEND_WEIGHTS) 00479 { 00480 // Warn that we've reduced bone assignments 00481 LogManager::getSingleton().logMessage("WARNING: the mesh '" + mName + "' " 00482 "includes vertices with more than " + 00483 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + " bone assignments. " 00484 "The lowest weighted assignments beyond this limit have been removed, so " 00485 "your animation may look slightly different. To eliminate this, reduce " 00486 "the number of bone assignments per vertex on your mesh to " + 00487 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + "."); 00488 // we've adjusted them down to the max 00489 maxBones = OGRE_MAX_BLEND_WEIGHTS; 00490 00491 } 00492 00493 return maxBones; 00494 } 00495 //----------------------------------------------------------------------- 00496 void Mesh::_compileBoneAssignments(void) 00497 { 00498 unsigned short maxBones = 00499 _rationaliseBoneAssignments(sharedVertexData->vertexCount, mBoneAssignments); 00500 00501 if (maxBones == 0) 00502 { 00503 // No bone assignments 00504 return; 00505 } 00506 00507 compileBoneAssignments(mBoneAssignments, maxBones, 00508 sharedVertexData); 00509 mBoneAssignmentsOutOfDate = false; 00510 00511 } 00512 //--------------------------------------------------------------------- 00513 void Mesh::compileBoneAssignments( 00514 const VertexBoneAssignmentList& boneAssignments, 00515 unsigned short numBlendWeightsPerVertex, 00516 VertexData* targetVertexData) 00517 { 00518 // Create or reuse blend weight / indexes buffer 00519 // Indices are always a UBYTE4 no matter how many weights per vertex 00520 // Weights are more specific though since they are Reals 00521 VertexDeclaration* decl = targetVertexData->vertexDeclaration; 00522 VertexBufferBinding* bind = targetVertexData->vertexBufferBinding; 00523 unsigned short bindIndex; 00524 00525 const VertexElement* testElem = 00526 decl->findElementBySemantic(VES_BLEND_INDICES); 00527 if (testElem) 00528 { 00529 // Already have a buffer, unset it & delete elements 00530 bindIndex = testElem->getSource(); 00531 // unset will cause deletion of buffer 00532 bind->unsetBinding(bindIndex); 00533 decl->removeElement(VES_BLEND_INDICES); 00534 decl->removeElement(VES_BLEND_WEIGHTS); 00535 } 00536 else 00537 { 00538 // Get new binding 00539 bindIndex = bind->getNextIndex(); 00540 } 00541 00542 HardwareVertexBufferSharedPtr vbuf = 00543 HardwareBufferManager::getSingleton().createVertexBuffer( 00544 sizeof(unsigned char)*4 + sizeof(Real)*numBlendWeightsPerVertex, 00545 targetVertexData->vertexCount, 00546 HardwareBuffer::HBU_STATIC_WRITE_ONLY, 00547 true // use shadow buffer 00548 ); 00549 // bind new buffer 00550 bind->setBinding(bindIndex, vbuf); 00551 const VertexElement *pIdxElem, *pWeightElem; 00552 00553 // add new vertex elements 00554 // Note, insert directly after all elements using the same source as 00555 // position to abide by pre-Dx9 format restrictions 00556 const VertexElement* firstElem = decl->getElement(0); 00557 if(firstElem->getSemantic() == VES_POSITION) 00558 { 00559 unsigned short insertPoint = 1; 00560 while (insertPoint < decl->getElementCount() && 00561 decl->getElement(insertPoint)->getSource() == firstElem->getSource()) 00562 { 00563 ++insertPoint; 00564 } 00565 const VertexElement& idxElem = 00566 decl->insertElement(insertPoint, bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 00567 const VertexElement& wtElem = 00568 decl->insertElement(insertPoint+1, bindIndex, sizeof(unsigned char)*4, 00569 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex), 00570 VES_BLEND_WEIGHTS); 00571 pIdxElem = &idxElem; 00572 pWeightElem = &wtElem; 00573 } 00574 else 00575 { 00576 // Position is not the first semantic, therefore this declaration is 00577 // not pre-Dx9 compatible anyway, so just tack it on the end 00578 const VertexElement& idxElem = 00579 decl->addElement(bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 00580 const VertexElement& wtElem = 00581 decl->addElement(bindIndex, sizeof(unsigned char)*4, 00582 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex), 00583 VES_BLEND_WEIGHTS); 00584 pIdxElem = &idxElem; 00585 pWeightElem = &wtElem; 00586 } 00587 00588 // Assign data 00589 size_t v; 00590 VertexBoneAssignmentList::const_iterator i, iend; 00591 i = boneAssignments.begin(); 00592 iend = boneAssignments.end(); 00593 unsigned char *pBase = static_cast<unsigned char*>( 00594 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 00595 // Iterate by vertex 00596 Real *pWeight; 00597 unsigned char *pIndex; 00598 for (v = 0; v < targetVertexData->vertexCount; ++v) 00599 { 00601 pWeightElem->baseVertexPointerToElement(pBase, &pWeight); 00602 pIdxElem->baseVertexPointerToElement(pBase, &pIndex); 00603 for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone) 00604 { 00605 // Do we still have data for this vertex? 00606 if (i != iend && i->second.vertexIndex == v) 00607 { 00608 // If so, write weight 00609 *pWeight++ = i->second.weight; 00610 *pIndex++ = i->second.boneIndex; 00611 ++i; 00612 } 00613 else 00614 { 00615 // Ran out of assignments for this vertex, use weight 0 to indicate empty 00616 *pWeight++ = 0.0f; 00617 *pIndex++ = 0; 00618 } 00619 } 00620 pBase += vbuf->getVertexSize(); 00621 } 00622 00623 vbuf->unlock(); 00624 00625 } 00626 //--------------------------------------------------------------------- 00627 void Mesh::_notifySkeleton(Skeleton* pSkel) 00628 { 00629 mSkeleton = pSkel; 00630 mSkeletonName = pSkel->getName(); 00631 } 00632 //--------------------------------------------------------------------- 00633 Mesh::BoneAssignmentIterator Mesh::getBoneAssignmentIterator(void) 00634 { 00635 return BoneAssignmentIterator(mBoneAssignments.begin(), 00636 mBoneAssignments.end()); 00637 } 00638 //--------------------------------------------------------------------- 00639 const String& Mesh::getSkeletonName(void) const 00640 { 00641 return mSkeletonName; 00642 } 00643 //--------------------------------------------------------------------- 00644 void Mesh::generateLodLevels(const LodDistanceList& lodDistances, 00645 ProgressiveMesh::VertexReductionQuota reductionMethod, Real reductionValue) 00646 { 00647 #if OGRE_DEBUG_MODE 00648 Real prev = 0; 00649 for (LodDistanceList::const_iterator it = lodDistances.begin(); 00650 it != lodDistances.end(); ++it) 00651 { 00652 Real cur = (*it) * (*it); 00653 assert(cur >= prev && "The lod distances must be sort ascending"); 00654 prev = cur; 00655 } 00656 #endif 00657 00658 removeLodLevels(); 00659 00660 char msg[128]; 00661 sprintf(msg, "Generating %d lower LODs for mesh %s.", 00662 lodDistances.size(), mName.c_str()); 00663 LogManager::getSingleton().logMessage(msg); 00664 00665 SubMeshList::iterator isub, isubend; 00666 isubend = mSubMeshList.end(); 00667 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00668 { 00669 // Set up data for reduction 00670 VertexData* pVertexData = (*isub)->useSharedVertices ? sharedVertexData : (*isub)->vertexData; 00671 00672 ProgressiveMesh pm(pVertexData, (*isub)->indexData); 00673 pm.build( 00674 static_cast<ushort>(lodDistances.size()), 00675 &((*isub)->mLodFaceList), 00676 reductionMethod, reductionValue); 00677 00678 } 00679 00680 // Iterate over the lods and record usage 00681 LodDistanceList::const_iterator idist, idistend; 00682 idistend = lodDistances.end(); 00683 mMeshLodUsageList.resize(lodDistances.size() + 1); 00684 MeshLodUsageList::iterator ilod = mMeshLodUsageList.begin(); 00685 for (idist = lodDistances.begin(); idist != idistend; ++idist) 00686 { 00687 // Record usage 00688 MeshLodUsage& lod = *++ilod; 00689 lod.fromDepthSquared = (*idist) * (*idist); 00690 lod.edgeData = NULL; 00691 lod.manualMesh = NULL; 00692 } 00693 mNumLods = static_cast<ushort>(lodDistances.size() + 1); 00694 } 00695 //--------------------------------------------------------------------- 00696 ushort Mesh::getNumLodLevels(void) const 00697 { 00698 return mNumLods; 00699 } 00700 //--------------------------------------------------------------------- 00701 const Mesh::MeshLodUsage& Mesh::getLodLevel(ushort index) const 00702 { 00703 assert(index < mMeshLodUsageList.size()); 00704 if (mIsLodManual && index > 0) 00705 { 00706 if (!mMeshLodUsageList[index].manualMesh) 00707 { 00708 // Load the mesh now 00709 mMeshLodUsageList[index].manualMesh = 00710 MeshManager::getSingleton().load(mMeshLodUsageList[index].manualName); 00711 } 00712 // get the edge data, if required 00713 if (!mMeshLodUsageList[index].edgeData) 00714 { 00715 mMeshLodUsageList[index].edgeData = 00716 mMeshLodUsageList[index].manualMesh->getEdgeList(0); 00717 } 00718 00719 } 00720 return mMeshLodUsageList[index]; 00721 } 00722 //--------------------------------------------------------------------- 00723 struct ManualLodSortLess : 00724 public std::binary_function<const Mesh::MeshLodUsage&, const Mesh::MeshLodUsage&, bool> 00725 { 00726 bool operator() (const Mesh::MeshLodUsage& mesh1, const Mesh::MeshLodUsage& mesh2) 00727 { 00728 // sort ascending by depth 00729 return mesh1.fromDepthSquared < mesh2.fromDepthSquared; 00730 } 00731 }; 00732 void Mesh::createManualLodLevel(Real fromDepth, const String& meshName) 00733 { 00734 00735 // Basic prerequisites 00736 assert(fromDepth > 0 && "The LOD depth must be greater than zero"); 00737 assert((mIsLodManual || mNumLods == 1) && "Generated LODs already in use!"); 00738 00739 mIsLodManual = true; 00740 MeshLodUsage lod; 00741 lod.fromDepthSquared = fromDepth * fromDepth; 00742 lod.manualName = meshName; 00743 lod.manualMesh = NULL; 00744 lod.edgeData = NULL; 00745 mMeshLodUsageList.push_back(lod); 00746 ++mNumLods; 00747 00748 std::sort(mMeshLodUsageList.begin(), mMeshLodUsageList.end(), ManualLodSortLess()); 00749 } 00750 //--------------------------------------------------------------------- 00751 void Mesh::updateManualLodLevel(ushort index, const String& meshName) 00752 { 00753 00754 // Basic prerequisites 00755 assert(mIsLodManual && "Not using manual LODs!"); 00756 assert(index != 0 && "Can't modify first lod level (full detail)"); 00757 assert(index < mMeshLodUsageList.size() && "Index out of bounds"); 00758 // get lod 00759 MeshLodUsage* lod = &(mMeshLodUsageList[index]); 00760 00761 lod->manualName = meshName; 00762 lod->manualMesh = NULL; 00763 if (lod->edgeData) delete lod->edgeData; 00764 lod->edgeData = NULL; 00765 } 00766 //--------------------------------------------------------------------- 00767 ushort Mesh::getLodIndex(Real depth) const 00768 { 00769 return getLodIndexSquaredDepth(depth * depth); 00770 } 00771 //--------------------------------------------------------------------- 00772 ushort Mesh::getLodIndexSquaredDepth(Real squaredDepth) const 00773 { 00774 MeshLodUsageList::const_iterator i, iend; 00775 iend = mMeshLodUsageList.end(); 00776 ushort index = 0; 00777 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 00778 { 00779 if (i->fromDepthSquared > squaredDepth) 00780 { 00781 return index - 1; 00782 } 00783 } 00784 00785 // If we fall all the way through, use the highest value 00786 return static_cast<ushort>(mMeshLodUsageList.size() - 1); 00787 00788 00789 } 00790 //--------------------------------------------------------------------- 00791 void Mesh::_setLodInfo(unsigned short numLevels, bool isManual) 00792 { 00793 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 00794 00795 // Basic prerequisites 00796 assert(numLevels > 0 && "Must be at least one level (full detail level must exist)"); 00797 00798 mNumLods = numLevels; 00799 mMeshLodUsageList.resize(numLevels); 00800 // Resize submesh face data lists too 00801 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00802 { 00803 (*i)->mLodFaceList.resize(numLevels - 1); 00804 } 00805 mIsLodManual = isManual; 00806 } 00807 //--------------------------------------------------------------------- 00808 void Mesh::_setLodUsage(unsigned short level, Mesh::MeshLodUsage& usage) 00809 { 00810 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 00811 00812 // Basic prerequisites 00813 assert(level != 0 && "Can't modify first lod level (full detail)"); 00814 assert(level < mMeshLodUsageList.size() && "Index out of bounds"); 00815 00816 mMeshLodUsageList[level] = usage; 00817 } 00818 //--------------------------------------------------------------------- 00819 void Mesh::_setSubMeshLodFaceList(unsigned short subIdx, unsigned short level, 00820 IndexData* facedata) 00821 { 00822 assert(!mEdgeListsBuilt && "Can't modify LOD after edge lists built"); 00823 00824 // Basic prerequisites 00825 assert(!mIsLodManual && "Not using generated LODs!"); 00826 assert(subIdx <= mSubMeshList.size() && "Index out of bounds"); 00827 assert(level != 0 && "Can't modify first lod level (full detail)"); 00828 assert(level <= mSubMeshList[subIdx]->mLodFaceList.size() && "Index out of bounds"); 00829 00830 SubMesh* sm = mSubMeshList[subIdx]; 00831 sm->mLodFaceList[level - 1] = facedata; 00832 00833 } 00834 //--------------------------------------------------------------------- 00835 ushort Mesh::_getSubMeshIndex(const String& name) const 00836 { 00837 SubMeshNameMap::const_iterator i = mSubMeshNameMap.find(name) ; 00838 if (i == mSubMeshNameMap.end()) 00839 Except(Exception::ERR_ITEM_NOT_FOUND, "No SubMesh named " + name + " found.", 00840 "Mesh::_getSubMeshIndex"); 00841 00842 return i->second; 00843 } 00844 //--------------------------------------------------------------------- 00845 void Mesh::removeLodLevels(void) 00846 { 00847 if (!mIsLodManual) 00848 { 00849 // Remove data from SubMeshes 00850 SubMeshList::iterator isub, isubend; 00851 isubend = mSubMeshList.end(); 00852 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00853 { 00854 (*isub)->removeLodLevels(); 00855 } 00856 } 00857 00858 freeEdgeList(); 00859 mMeshLodUsageList.clear(); 00860 00861 // Reinitialise 00862 mNumLods = 1; 00863 // Init first (manual) lod 00864 MeshLodUsage lod; 00865 lod.fromDepthSquared = 0.0f; 00866 lod.edgeData = NULL; 00867 lod.manualMesh = NULL; 00868 mMeshLodUsageList.push_back(lod); 00869 mIsLodManual = false; 00870 00871 00872 } 00873 //--------------------------------------------------------------------- 00874 Real Mesh::getBoundingSphereRadius(void) const 00875 { 00876 return mBoundRadius; 00877 } 00878 //--------------------------------------------------------------------- 00879 void Mesh::setVertexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00880 { 00881 mVertexBufferUsage = vbUsage; 00882 mVertexBufferShadowBuffer = shadowBuffer; 00883 } 00884 //--------------------------------------------------------------------- 00885 void Mesh::setIndexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00886 { 00887 mIndexBufferUsage = vbUsage; 00888 mIndexBufferShadowBuffer = shadowBuffer; 00889 } 00890 //--------------------------------------------------------------------- 00891 void Mesh::organiseTangentsBuffer(VertexData *vertexData, 00892 unsigned short destCoordSet) 00893 { 00894 VertexDeclaration *vDecl = vertexData->vertexDeclaration ; 00895 VertexBufferBinding *vBind = vertexData->vertexBufferBinding ; 00896 00897 const VertexElement *tex3D = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, destCoordSet); 00898 bool needsToBeCreated = false; 00899 00900 if (!tex3D) 00901 { // no tex coords with index 1 00902 needsToBeCreated = true ; 00903 } 00904 else if (tex3D->getType() != VET_FLOAT3) 00905 { 00906 // tex buffer exists, but not 3D 00907 Except(Exception::ERR_INVALIDPARAMS, 00908 "Texture coordinate set " + StringConverter::toString(destCoordSet) + 00909 "already exists but is not 3D, therefore cannot contain tangents. Pick " 00910 "an alternative destination coordinate set. ", 00911 "Mesh::organiseTangentsBuffer"); 00912 } 00913 00914 HardwareVertexBufferSharedPtr newBuffer; 00915 if (needsToBeCreated) 00916 { 00917 // What we need to do, to be most efficient with our vertex streams, 00918 // is to tack the new 3D coordinate set onto the same buffer as the 00919 // previous texture coord set 00920 const VertexElement* prevTexCoordElem = 00921 vertexData->vertexDeclaration->findElementBySemantic( 00922 VES_TEXTURE_COORDINATES, destCoordSet - 1); 00923 if (!prevTexCoordElem) 00924 { 00925 Except(Exception::ERR_ITEM_NOT_FOUND, 00926 "Cannot locate the texture coordinate element preceding the " 00927 "destination texture coordinate set to which to append the new " 00928 "tangents.", "Mesh::orgagniseTangentsBuffer"); 00929 } 00930 // Find the buffer associated with this element 00931 HardwareVertexBufferSharedPtr origBuffer = 00932 vertexData->vertexBufferBinding->getBuffer( 00933 prevTexCoordElem->getSource()); 00934 // Now create a new buffer, which includes the previous contents 00935 // plus extra space for the 3D coords 00936 newBuffer = HardwareBufferManager::getSingleton().createVertexBuffer( 00937 origBuffer->getVertexSize() + 3*sizeof(float), 00938 vertexData->vertexCount, 00939 origBuffer->getUsage(), 00940 origBuffer->hasShadowBuffer() ); 00941 // Add the new element 00942 vDecl->addElement( 00943 prevTexCoordElem->getSource(), 00944 origBuffer->getVertexSize(), 00945 VET_FLOAT3, 00946 VES_TEXTURE_COORDINATES, 00947 destCoordSet); 00948 // Now copy the original data across 00949 unsigned char* pSrc = static_cast<unsigned char*>( 00950 origBuffer->lock(HardwareBuffer::HBL_READ_ONLY)); 00951 unsigned char* pDest = static_cast<unsigned char*>( 00952 newBuffer->lock(HardwareBuffer::HBL_DISCARD)); 00953 size_t vertSize = origBuffer->getVertexSize(); 00954 for (int v = 0; v < vertexData->vertexCount; ++v) 00955 { 00956 // Copy original vertex data 00957 memcpy(pDest, pSrc, vertSize); 00958 pSrc += vertSize; 00959 pDest += vertSize; 00960 // Set the new part to 0 since we'll accumulate in this 00961 memset(pDest, 0, sizeof(float)*3); 00962 pDest += sizeof(float)*3; 00963 } 00964 origBuffer->unlock(); 00965 newBuffer->unlock(); 00966 00967 // Rebind the new buffer 00968 vBind->setBinding(prevTexCoordElem->getSource(), newBuffer); 00969 } 00970 } 00971 //--------------------------------------------------------------------- 00972 void Mesh::buildTangentVectors(unsigned short sourceTexCoordSet, 00973 unsigned short destTexCoordSet) 00974 { 00975 if (destTexCoordSet == 0) 00976 { 00977 Except(Exception::ERR_INVALIDPARAMS, 00978 "Destination texture coordinate set must be greater than 0", 00979 "Mesh::buildTangentVectors"); 00980 } 00981 00982 // our temp. buffers 00983 unsigned short vertInd[3]; 00984 Vector3 vertPos[3]; 00985 Real u[3], v[3]; 00986 // setup a new 3D texture coord-set buffer for every sub mesh 00987 int nSubMesh = getNumSubMeshes(); 00988 bool sharedGeometryDone = false; 00989 for (int sm = 0; sm < nSubMesh; sm++) 00990 { 00991 // retrieve buffer pointers 00992 unsigned short *pVIndices; // the face indices buffer, read only 00993 Real *p2DTC; // pointer to 2D tex.coords, read only 00994 Real *p3DTC; // pointer to 3D tex.coords, write/read (discard) 00995 Real *pVPos; // vertex position buffer, read only 00996 00997 SubMesh *pSubMesh = getSubMesh(sm); 00998 00999 // retrieve buffer pointers 01000 // first, indices 01001 IndexData *indexData = pSubMesh->indexData; 01002 HardwareIndexBufferSharedPtr buffIndex = indexData->indexBuffer ; 01003 pVIndices = (unsigned short*) buffIndex->lock(HardwareBuffer::HBL_READ_ONLY); 01004 // then, vertices 01005 VertexData *usedVertexData ; 01006 if (pSubMesh->useSharedVertices) { 01007 // Don't do shared geometry more than once 01008 if (sharedGeometryDone) 01009 continue; 01010 usedVertexData = sharedVertexData; 01011 sharedGeometryDone = true; 01012 } else { 01013 usedVertexData = pSubMesh->vertexData; 01014 } 01015 VertexDeclaration *vDecl = usedVertexData->vertexDeclaration; 01016 VertexBufferBinding *vBind = usedVertexData->vertexBufferBinding; 01017 01018 01019 // make sure we have a 3D coord to place data in 01020 organiseTangentsBuffer(usedVertexData, destTexCoordSet); 01021 01022 // Get the target element 01023 const VertexElement* destElem = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, destTexCoordSet); 01024 // Get the source element 01025 const VertexElement* srcElem = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, sourceTexCoordSet); 01026 01027 if (!srcElem || srcElem->getType() != VET_FLOAT2) 01028 { 01029 Except(Exception::ERR_INVALIDPARAMS, 01030 "SubMesh " + StringConverter::toString(sm) + " of Mesh " + mName + 01031 " has no 2D texture coordinates at the selected set, therefore we cannot calculate tangents.", 01032 "Mesh::buildTangentVectors"); 01033 } 01034 HardwareVertexBufferSharedPtr srcBuf, destBuf, posBuf; 01035 unsigned char *pSrcBase, *pDestBase, *pPosBase; 01036 size_t srcInc, destInc, posInc; 01037 01038 srcBuf = vBind->getBuffer(srcElem->getSource()); 01039 // Is the source and destination buffer the same? 01040 if (srcElem->getSource() == destElem->getSource()) 01041 { 01042 // lock source for read and write 01043 pSrcBase = static_cast<unsigned char*>( 01044 srcBuf->lock(HardwareBuffer::HBL_NORMAL)); 01045 srcInc = srcBuf->getVertexSize(); 01046 pDestBase = pSrcBase; 01047 destInc = srcInc; 01048 } 01049 else 01050 { 01051 pSrcBase = static_cast<unsigned char*>( 01052 srcBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01053 srcInc = srcBuf->getVertexSize(); 01054 destBuf = vBind->getBuffer(destElem->getSource()); 01055 destInc = destBuf->getVertexSize(); 01056 pDestBase = static_cast<unsigned char*>( 01057 destBuf->lock(HardwareBuffer::HBL_NORMAL)); 01058 } 01059 01060 // find a vertex coord buffer 01061 const VertexElement *elemVPos = vDecl->findElementBySemantic(VES_POSITION); 01062 if (elemVPos->getSource() == srcElem->getSource()) 01063 { 01064 pPosBase = pSrcBase; 01065 posInc = srcInc; 01066 } 01067 else if (elemVPos->getSource() == destElem->getSource()) 01068 { 01069 pPosBase = pDestBase; 01070 posInc = destInc; 01071 } 01072 else 01073 { 01074 // A different buffer 01075 posBuf = vBind->getBuffer(elemVPos->getSource()); 01076 pPosBase = static_cast<unsigned char*>( 01077 posBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01078 posInc = posBuf->getVertexSize(); 01079 } 01080 01081 size_t numFaces = indexData->indexCount / 3 ; 01082 01083 // loop through all faces to calculate the tangents and normals 01084 size_t n; 01085 for (n = 0; n < numFaces; ++n) 01086 { 01087 int i; 01088 for (i = 0; i < 3; ++i) 01089 { 01090 // get indexes of vertices that form a polygon in the position buffer 01091 vertInd[i] = *pVIndices++; 01092 // get the vertices positions from the position buffer 01093 unsigned char* vBase = pPosBase + (posInc * vertInd[i]); 01094 elemVPos->baseVertexPointerToElement(vBase, &pVPos); 01095 vertPos[i].x = pVPos[0]; 01096 vertPos[i].y = pVPos[1]; 01097 vertPos[i].z = pVPos[2]; 01098 // get the vertices tex.coords from the 2D tex.coords buffer 01099 vBase = pSrcBase + (srcInc * vertInd[i]); 01100 srcElem->baseVertexPointerToElement(vBase, &p2DTC); 01101 u[i] = p2DTC[0]; 01102 v[i] = p2DTC[1]; 01103 } 01104 // calculate the TSB 01105 Vector3 tangent = Math::calculateTangentSpaceVector( 01106 vertPos[0], vertPos[1], vertPos[2], 01107 u[0], v[0], u[1], v[1], u[2], v[2]); 01108 // write new tex.coords 01109 // note we only write the tangent, not the binormal since we can calculate 01110 // the binormal in the vertex program 01111 for (i = 0; i < 3; ++i) 01112 { 01113 // write values (they must be 0 and we must add them so we can average 01114 // all the contributions from all the faces 01115 unsigned char* vBase = pDestBase + (destInc * vertInd[i]); 01116 destElem->baseVertexPointerToElement(vBase, &p3DTC); 01117 p3DTC[0] += tangent.x; 01118 p3DTC[1] += tangent.y; 01119 p3DTC[2] += tangent.z; 01120 } 01121 } 01122 // now loop through all vertices and normalize them 01123 size_t numVerts = usedVertexData->vertexCount ; 01124 for (n = 0; n < numVerts; ++n) 01125 { 01126 destElem->baseVertexPointerToElement(pDestBase, &p3DTC); 01127 // read the vertex 01128 Vector3 temp(p3DTC[0], p3DTC[1], p3DTC[2]); 01129 // normalize the vertex 01130 temp.normalise(); 01131 // write it back 01132 p3DTC[0] = temp.x; 01133 p3DTC[1] = temp.y; 01134 p3DTC[2] = temp.z; 01135 01136 pDestBase += destInc; 01137 } 01138 // unlock buffers 01139 srcBuf->unlock(); 01140 if (!destBuf.isNull()) 01141 { 01142 destBuf->unlock(); 01143 } 01144 if (!posBuf.isNull()) 01145 { 01146 posBuf->unlock(); 01147 } 01148 buffIndex->unlock(); 01149 } 01150 01151 } 01152 01153 //--------------------------------------------------------------------- 01154 bool Mesh::suggestTangentVectorBuildParams(unsigned short& outSourceCoordSet, 01155 unsigned short& outDestCoordSet) 01156 { 01157 // Go through all the vertex data and locate source and dest (must agree) 01158 bool sharedGeometryDone = false; 01159 bool foundExisting = false; 01160 bool firstOne = true; 01161 SubMeshList::iterator i, iend; 01162 iend = mSubMeshList.end(); 01163 for (i = mSubMeshList.begin(); i != iend; ++i) 01164 { 01165 SubMesh* sm = *i; 01166 VertexData* vertexData; 01167 01168 if (sm->useSharedVertices) 01169 { 01170 if (sharedGeometryDone) 01171 continue; 01172 vertexData = sharedVertexData; 01173 sharedGeometryDone = true; 01174 } 01175 else 01176 { 01177 vertexData = sm->vertexData; 01178 } 01179 01180 const VertexElement *sourceElem = 0; 01181 unsigned short proposedDest = 0; 01182 unsigned short t = 0; 01183 for (t = 0; t < OGRE_MAX_TEXTURE_COORD_SETS; ++t) 01184 { 01185 const VertexElement* testElem = 01186 vertexData->vertexDeclaration->findElementBySemantic( 01187 VES_TEXTURE_COORDINATES, t); 01188 if (!testElem) 01189 break; // finish if we've run out, t will be the target 01190 01191 if (!sourceElem) 01192 { 01193 // We're still looking for the source texture coords 01194 if (testElem->getType() == VET_FLOAT2) 01195 { 01196 // Ok, we found it 01197 sourceElem = testElem; 01198 } 01199 } 01200 else 01201 { 01202 // We're looking for the destination 01203 // Check to see if we've found a possible 01204 if (testElem->getType() == VET_FLOAT3) 01205 { 01206 // This is a 3D set, might be tangents 01207 foundExisting = true; 01208 } 01209 01210 } 01211 01212 } 01213 01214 // After iterating, we should have a source and a possible destination (t) 01215 if (!sourceElem) 01216 { 01217 Except(Exception::ERR_ITEM_NOT_FOUND, 01218 "Cannot locate an appropriate 2D texture coordinate set for " 01219 "all the vertex data in this mesh to create tangents from. ", 01220 "Mesh::suggestTangentVectorBuildParams"); 01221 } 01222 // Check that we agree with previous decisions, if this is not the 01223 // first one 01224 if (!firstOne) 01225 { 01226 if (sourceElem->getIndex() != outSourceCoordSet) 01227 { 01228 Except(Exception::ERR_INVALIDPARAMS, 01229 "Multiple sets of vertex data in this mesh disagree on " 01230 "the appropriate index to use for the source texture coordinates. " 01231 "This ambiguity must be rectified before tangents can be generated.", 01232 "Mesh::suggestTangentVectorBuildParams"); 01233 } 01234 if (t != outDestCoordSet) 01235 { 01236 Except(Exception::ERR_INVALIDPARAMS, 01237 "Multiple sets of vertex data in this mesh disagree on " 01238 "the appropriate index to use for the target texture coordinates. " 01239 "This ambiguity must be rectified before tangents can be generated.", 01240 "Mesh::suggestTangentVectorBuildParams"); 01241 } 01242 } 01243 01244 // Otherwise, save this result 01245 outSourceCoordSet = sourceElem->getIndex(); 01246 outDestCoordSet = t; 01247 01248 firstOne = false; 01249 01250 } 01251 01252 return foundExisting; 01253 01254 } 01255 //--------------------------------------------------------------------- 01256 void Mesh::buildEdgeList(void) 01257 { 01258 if (mEdgeListsBuilt) 01259 return; 01260 01261 // Loop over LODs 01262 for (unsigned int lodIndex = 0; lodIndex < mMeshLodUsageList.size(); ++lodIndex) 01263 { 01264 // use getLodLevel to enforce loading of manual mesh lods 01265 MeshLodUsage& usage = const_cast<MeshLodUsage&>(getLodLevel(lodIndex)); 01266 01267 if (mIsLodManual && lodIndex != 0) 01268 { 01269 // Delegate edge building to manual mesh 01270 // It should have already built it's own edge list while loading 01271 usage.edgeData = usage.manualMesh->getEdgeList(0); 01272 } 01273 else 01274 { 01275 // Build 01276 EdgeListBuilder eb; 01277 size_t vertexSetCount = 0; 01278 01279 if (sharedVertexData) 01280 { 01281 eb.addVertexData(sharedVertexData); 01282 vertexSetCount++; 01283 } 01284 01285 // Prepare the builder using the submesh information 01286 SubMeshList::iterator i, iend; 01287 iend = mSubMeshList.end(); 01288 for (i = mSubMeshList.begin(); i != iend; ++i) 01289 { 01290 SubMesh* s = *i; 01291 if (s->useSharedVertices) 01292 { 01293 // Use shared vertex data, index as set 0 01294 if (lodIndex == 0) 01295 { 01296 eb.addIndexData(s->indexData, 0, s->operationType); 01297 } 01298 else 01299 { 01300 eb.addIndexData(s->mLodFaceList[lodIndex-1], 0, 01301 s->operationType); 01302 } 01303 } 01304 else 01305 { 01306 // own vertex data, add it and reference it directly 01307 eb.addVertexData(s->vertexData); 01308 if (lodIndex == 0) 01309 { 01310 // Base index data 01311 eb.addIndexData(s->indexData, vertexSetCount++, 01312 s->operationType); 01313 } 01314 else 01315 { 01316 // LOD index data 01317 eb.addIndexData(s->mLodFaceList[lodIndex-1], 01318 vertexSetCount++, s->operationType); 01319 } 01320 01321 } 01322 } 01323 01324 usage.edgeData = eb.build(); 01325 01326 #if OGRE_DEBUG_MODE 01327 // Override default log 01328 Log* log = LogManager::getSingleton().createLog( 01329 mName + "_lod" + StringConverter::toString(lodIndex) + 01330 "_prepshadow.log", false, false); 01331 usage.edgeData->log(log); 01332 #endif 01333 01334 } 01335 } 01336 mEdgeListsBuilt = true; 01337 } 01338 //--------------------------------------------------------------------- 01339 void Mesh::freeEdgeList(void) 01340 { 01341 if (!mEdgeListsBuilt) 01342 return; 01343 01344 // Loop over LODs 01345 MeshLodUsageList::iterator i, iend; 01346 iend = mMeshLodUsageList.end(); 01347 unsigned short index = 0; 01348 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 01349 { 01350 MeshLodUsage& usage = *i; 01351 01352 if (!mIsLodManual || index == 0) 01353 { 01354 // Only delete if we own this data 01355 // Manual LODs > 0 own their own 01356 delete usage.edgeData; 01357 } 01358 usage.edgeData = NULL; 01359 } 01360 01361 mEdgeListsBuilt = false; 01362 } 01363 //--------------------------------------------------------------------- 01364 void Mesh::prepareForShadowVolume(void) 01365 { 01366 if (mPreparedForShadowVolumes) 01367 return; 01368 01369 if (sharedVertexData) 01370 { 01371 sharedVertexData->prepareForShadowVolume(); 01372 } 01373 SubMeshList::iterator i, iend; 01374 iend = mSubMeshList.end(); 01375 for (i = mSubMeshList.begin(); i != iend; ++i) 01376 { 01377 SubMesh* s = *i; 01378 if (!s->useSharedVertices) 01379 { 01380 s->vertexData->prepareForShadowVolume(); 01381 } 01382 } 01383 mPreparedForShadowVolumes = true; 01384 } 01385 //--------------------------------------------------------------------- 01386 EdgeData* Mesh::getEdgeList(unsigned int lodIndex) 01387 { 01388 // Build edge list on demand 01389 if (!mEdgeListsBuilt && mAutoBuildEdgeLists) 01390 { 01391 buildEdgeList(); 01392 } 01393 01394 return getLodLevel(lodIndex).edgeData; 01395 } 01396 //--------------------------------------------------------------------- 01397 const EdgeData* Mesh::getEdgeList(unsigned int lodIndex) const 01398 { 01399 return getLodLevel(lodIndex).edgeData; 01400 } 01401 //--------------------------------------------------------------------- 01402 void Mesh::softwareVertexBlend(const VertexData* sourceVertexData, 01403 const VertexData* targetVertexData, const Matrix4* pMatrices, 01404 bool blendNormals) 01405 { 01406 // Source vectors 01407 Vector3 sourceVec, sourceNorm; 01408 // Accumulation vectors 01409 Vector3 accumVecPos, accumVecNorm; 01410 01411 Real *pSrcPos, *pSrcNorm, *pDestPos, *pDestNorm, *pBlendWeight; 01412 unsigned char* pBlendIdx; 01413 bool srcPosNormShareBuffer = false; 01414 bool destPosNormShareBuffer = false; 01415 bool weightsIndexesShareBuffer = false; 01416 01417 01418 // Get elements for source 01419 const VertexElement* srcElemPos = 01420 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 01421 const VertexElement* srcElemNorm = 01422 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 01423 const VertexElement* srcElemBlendIndices = 01424 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); 01425 const VertexElement* srcElemBlendWeights = 01426 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); 01427 assert (srcElemPos && srcElemBlendIndices && srcElemBlendWeights && 01428 "You must supply at least positions, blend indices and blend weights"); 01429 // Get elements for target 01430 const VertexElement* destElemPos = 01431 targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 01432 const VertexElement* destElemNorm = 01433 targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 01434 01435 // Do we have normals and want to blend them? 01436 bool includeNormals = blendNormals && (srcElemNorm != NULL) && (destElemNorm != NULL); 01437 01438 01439 // Get buffers for source 01440 HardwareVertexBufferSharedPtr srcPosBuf, srcNormBuf, srcIdxBuf, srcWeightBuf; 01441 srcPosBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemPos->getSource()); 01442 srcIdxBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendIndices->getSource()); 01443 srcWeightBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendWeights->getSource()); 01444 if (includeNormals) 01445 { 01446 srcNormBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemNorm->getSource()); 01447 srcPosNormShareBuffer = (srcPosBuf.get() == srcNormBuf.get()); 01448 } 01449 weightsIndexesShareBuffer = (srcIdxBuf.get() == srcWeightBuf.get()); 01450 // Get buffers for target 01451 HardwareVertexBufferSharedPtr destPosBuf, destNormBuf; 01452 destPosBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemPos->getSource()); 01453 if (includeNormals) 01454 { 01455 destNormBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemNorm->getSource()); 01456 destPosNormShareBuffer = (destPosBuf.get() == destNormBuf.get()); 01457 } 01458 01459 // Lock source buffers for reading 01460 assert (srcElemPos->getOffset() == 0 && 01461 "Positions must be first element in dedicated buffer!"); 01462 pSrcPos = static_cast<Real*>( 01463 srcPosBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01464 if (includeNormals) 01465 { 01466 if (srcPosNormShareBuffer) 01467 { 01468 // Same buffer, must be packed directly after position 01469 assert (srcElemNorm->getOffset() == sizeof(Real) * 3 && 01470 "Normals must be packed directly after positions in buffer!"); 01471 // pSrcNorm will not be used 01472 } 01473 else 01474 { 01475 // Different buffer 01476 assert (srcElemNorm->getOffset() == 0 && 01477 "Normals must be first element in dedicated buffer!"); 01478 pSrcNorm = static_cast<Real*>( 01479 srcNormBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01480 } 01481 } 01482 01483 // Indices must be first in a buffer and be 4 bytes 01484 assert(srcElemBlendIndices->getOffset() == 0 && 01485 srcElemBlendIndices->getType() == VET_UBYTE4 && 01486 "Blend indices must be first in a buffer and be VET_UBYTE4"); 01487 pBlendIdx = static_cast<unsigned char*>( 01488 srcIdxBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01489 if (weightsIndexesShareBuffer) 01490 { 01491 // Weights must be packed directly after the indices 01492 assert(srcElemBlendWeights->getOffset() == sizeof(unsigned char)*4 && 01493 "Blend weights must be directly after indices in the buffer"); 01494 srcElemBlendWeights->baseVertexPointerToElement(pBlendIdx, &pBlendWeight); 01495 } 01496 else 01497 { 01498 // Weights must be at the start of the buffer 01499 assert(srcElemBlendWeights->getOffset() == 0 && 01500 "Blend weights must be at the start of a dedicated buffer"); 01501 // Lock buffer 01502 pBlendWeight = static_cast<Real*>( 01503 srcWeightBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01504 } 01505 unsigned short numWeightsPerVertex = 01506 VertexElement::getTypeCount(srcElemBlendWeights->getType()); 01507 01508 01509 // Lock destination buffers for writing 01510 assert (destElemPos->getOffset() == 0 && 01511 "Positions must be first element in dedicated buffer!"); 01512 pDestPos = static_cast<Real*>( 01513 destPosBuf->lock(HardwareBuffer::HBL_DISCARD)); 01514 if (includeNormals) 01515 { 01516 if (destPosNormShareBuffer) 01517 { 01518 // Same buffer, must be packed directly after position 01519 assert (destElemNorm->getOffset() == sizeof(Real) * 3 && 01520 "Normals must be packed directly after positions in buffer!"); 01521 // Must be no other information in the buffer 01522 assert(destPosBuf->getVertexSize() == 01523 destElemPos->getSize() + destElemNorm->getSize() && 01524 "When software skinning, position & normal buffer must not include " 01525 "any other vertex elements!"); 01526 // pDestNorm will not be used 01527 } 01528 else 01529 { 01530 // Different buffer 01531 assert (destElemNorm->getOffset() == 0 && 01532 "Normals must be first element in dedicated buffer!"); 01533 // Must be no other information in the buffer 01534 assert(destPosBuf->getVertexSize() == 01535 destElemPos->getSize() && 01536 "When software skinning, dedicated position buffer must not include " 01537 "any other vertex elements!"); 01538 assert(destNormBuf->getVertexSize() == 01539 destElemNorm->getSize() && 01540 "When software skinning, dedicated normal buffer must not include " 01541 "any other vertex elements!"); 01542 pDestNorm = static_cast<Real*>( 01543 destNormBuf->lock(HardwareBuffer::HBL_DISCARD)); 01544 } 01545 } 01546 01547 // Loop per vertex 01548 for (size_t vertIdx = 0; vertIdx < targetVertexData->vertexCount; ++vertIdx) 01549 { 01550 // Load source vertex elements 01551 sourceVec.x = *pSrcPos++; 01552 sourceVec.y = *pSrcPos++; 01553 sourceVec.z = *pSrcPos++; 01554 01555 if (includeNormals) 01556 { 01557 if (srcPosNormShareBuffer) 01558 { 01559 sourceNorm.x = *pSrcPos++; 01560 sourceNorm.y = *pSrcPos++; 01561 sourceNorm.z = *pSrcPos++; 01562 } 01563 else 01564 { 01565 sourceNorm.x = *pSrcNorm++; 01566 sourceNorm.y = *pSrcNorm++; 01567 sourceNorm.z = *pSrcNorm++; 01568 } 01569 } 01570 // Load accumulators 01571 accumVecPos = Vector3::ZERO; 01572 accumVecNorm = Vector3::ZERO; 01573 01574 // Loop per blend weight 01575 for (unsigned short blendIdx = 0; 01576 blendIdx < numWeightsPerVertex; ++blendIdx) 01577 { 01578 // Blend by multiplying source by blend matrix and scaling by weight 01579 // Add to accumulator 01580 // NB weights must be normalised!! 01581 if (*pBlendWeight != 0.0) 01582 { 01583 // Blend position, use 3x4 matrix 01584 const Matrix4& mat = pMatrices[*pBlendIdx]; 01585 accumVecPos.x += 01586 (mat[0][0] * sourceVec.x + 01587 mat[0][1] * sourceVec.y + 01588 mat[0][2] * sourceVec.z + 01589 mat[0][3]) 01590 * (*pBlendWeight); 01591 accumVecPos.y += 01592 (mat[1][0] * sourceVec.x + 01593 mat[1][1] * sourceVec.y + 01594 mat[1][2] * sourceVec.z + 01595 mat[1][3]) 01596 * (*pBlendWeight); 01597 accumVecPos.z += 01598 (mat[2][0] * sourceVec.x + 01599 mat[2][1] * sourceVec.y + 01600 mat[2][2] * sourceVec.z + 01601 mat[2][3]) 01602 * (*pBlendWeight); 01603 if (includeNormals) 01604 { 01605 // Blend normal 01606 // We should blend by inverse transpose here, but because we're assuming the 3x3 01607 // aspect of the matrix is orthogonal (no non-uniform scaling), the inverse transpose 01608 // is equal to the main 3x3 matrix 01609 // Note because it's a normal we just extract the rotational part, saves us renormalising here 01610 accumVecNorm.x += 01611 (mat[0][0] * sourceNorm.x + 01612 mat[0][1] * sourceNorm.y + 01613 mat[0][2] * sourceNorm.z) 01614 * (*pBlendWeight); 01615 accumVecNorm.y += 01616 (mat[1][0] * sourceNorm.x + 01617 mat[1][1] * sourceNorm.y + 01618 mat[1][2] * sourceNorm.z) 01619 * (*pBlendWeight); 01620 accumVecNorm.z += 01621 (mat[2][0] * sourceNorm.x + 01622 mat[2][1] * sourceNorm.y + 01623 mat[2][2] * sourceNorm.z) 01624 * (*pBlendWeight); 01625 } 01626 01627 } 01628 ++pBlendWeight; 01629 ++pBlendIdx; 01630 } 01631 // Finish off blend info pointers 01632 // Make sure we skip over 4 index elements no matter how many we used 01633 pBlendIdx += 4 - numWeightsPerVertex; 01634 if(weightsIndexesShareBuffer) 01635 { 01636 // Skip index over weights 01637 pBlendIdx += sizeof(Real) * numWeightsPerVertex; 01638 // Re-base weights 01639 srcElemBlendWeights->baseVertexPointerToElement(pBlendIdx, &pBlendWeight); 01640 } 01641 01642 01643 // Stored blended vertex in hardware buffer 01644 *pDestPos++ = accumVecPos.x; 01645 *pDestPos++ = accumVecPos.y; 01646 *pDestPos++ = accumVecPos.z; 01647 01648 // Stored blended vertex in temp buffer 01649 if (includeNormals) 01650 { 01651 // Normalise 01652 accumVecNorm.normalise(); 01653 if (destPosNormShareBuffer) 01654 { 01655 // Pack into same buffer 01656 *pDestPos++ = accumVecNorm.x; 01657 *pDestPos++ = accumVecNorm.y; 01658 *pDestPos++ = accumVecNorm.z; 01659 } 01660 else 01661 { 01662 *pDestNorm++ = accumVecNorm.x; 01663 *pDestNorm++ = accumVecNorm.y; 01664 *pDestNorm++ = accumVecNorm.z; 01665 } 01666 } 01667 } 01668 // Unlock source buffers 01669 srcPosBuf->unlock(); 01670 srcIdxBuf->unlock(); 01671 if (!weightsIndexesShareBuffer) 01672 { 01673 srcWeightBuf->unlock(); 01674 } 01675 if (includeNormals && !srcPosNormShareBuffer) 01676 { 01677 srcNormBuf->unlock(); 01678 } 01679 // Unlock destination buffers 01680 destPosBuf->unlock(); 01681 if (includeNormals && !destPosNormShareBuffer) 01682 { 01683 destNormBuf->unlock(); 01684 01685 } 01686 01687 01688 01689 } 01690 01691 } 01692
Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:34 2004