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 //mUpdateBounds = true; 00052 setSkeletonName(""); 00053 mBoneAssignmentsOutOfDate = false; 00054 mNumLods = 1; 00055 // Init first (manual) lod 00056 MeshLodUsage lod; 00057 lod.fromDepthSquared = 0.0f; 00058 lod.edgeData = NULL; 00059 lod.manualMesh = NULL; 00060 mMeshLodUsageList.push_back(lod); 00061 mIsLodManual = false; 00062 00063 mVertexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00064 mIndexBufferUsage = HardwareBuffer::HBU_STATIC_WRITE_ONLY; 00065 mVertexBufferShadowBuffer = true; 00066 mIndexBufferShadowBuffer = true; 00067 00068 mBoundRadius = 0.0f; 00069 00070 mPreparedForShadowVolumes = false; 00071 mEdgeListsBuilt = false; 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 = mName.split("."); 00144 00145 String& ext = extVec[extVec.size() - 1]; 00146 ext.toLowerCase(); 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 prepareForShadowVolume(); 00167 buildEdgeList(); 00168 } 00169 00170 mIsLoaded = true; 00171 00172 //_updateBounds(); 00173 00174 } 00175 00176 //----------------------------------------------------------------------- 00177 void Mesh::unload() 00178 { 00179 // Teardown submeshes 00180 for (SubMeshList::iterator i = mSubMeshList.begin(); 00181 i != mSubMeshList.end(); ++i) 00182 { 00183 delete *i; 00184 } 00185 if (sharedVertexData) 00186 { 00187 delete sharedVertexData; 00188 sharedVertexData = NULL; 00189 } 00190 // Destroy edge lists 00191 freeEdgeList(); 00192 // Clear SubMesh lists 00193 mSubMeshList.clear(); 00194 mSubMeshNameMap.clear(); 00195 mIsLoaded = false; 00196 } 00197 00198 //----------------------------------------------------------------------- 00199 void Mesh::setManuallyDefined(bool manual) 00200 { 00201 mManuallyDefined = manual; 00202 } 00203 00204 //----------------------------------------------------------------------- 00205 Mesh* Mesh::clone(const String& newName) 00206 { 00207 // This is a bit like a copy constructor, but with the additional aspect of registering the clone with 00208 // the MeshManager 00209 00210 // New Mesh is assumed to be manually defined rather than loaded since you're cloning it for a reason 00211 Mesh* newMesh = MeshManager::getSingleton().createManual(newName); 00212 00213 // Copy submeshes first 00214 std::vector<SubMesh*>::iterator subi; 00215 SubMesh* newSub; 00216 for (subi = mSubMeshList.begin(); subi != mSubMeshList.end(); ++subi) 00217 { 00218 newSub = newMesh->createSubMesh(); 00219 newSub->mMaterialName = (*subi)->mMaterialName; 00220 newSub->mMatInitialised = (*subi)->mMatInitialised; 00221 newSub->parent = newMesh; 00222 newSub->useSharedVertices = (*subi)->useSharedVertices; 00223 00224 if (!(*subi)->useSharedVertices) 00225 { 00226 // Copy unique vertex data 00227 newSub->vertexData = (*subi)->vertexData->clone(); 00228 } 00229 00230 // Copy index data 00231 newSub->indexData = (*subi)->indexData->clone(); 00232 // Copy any bone assignments 00233 newSub->mBoneAssignments = (*subi)->mBoneAssignments; 00234 newSub->mBoneAssignmentsOutOfDate = (*subi)->mBoneAssignmentsOutOfDate; 00235 newSub->mMatInitialised = (*subi)->mMatInitialised; 00236 00237 } 00238 00239 // Copy shared geometry, if any 00240 if (sharedVertexData) 00241 { 00242 newMesh->sharedVertexData = sharedVertexData->clone(); 00243 } 00244 00245 // Copy submesh names 00246 newMesh->mSubMeshNameMap = mSubMeshNameMap ; 00247 // Copy any bone assignments 00248 newMesh->mBoneAssignments = mBoneAssignments; 00249 // Copy bounds 00250 newMesh->mAABB = mAABB; 00251 newMesh->mBoundRadius = mBoundRadius; 00252 // copy BoneAssignment information 00253 newMesh->mBoneAssignmentsOutOfDate = mBoneAssignmentsOutOfDate; 00254 00255 newMesh->mIsLodManual = mIsLodManual; 00256 newMesh->mNumLods = mNumLods; 00257 newMesh->mMeshLodUsageList = mMeshLodUsageList; 00258 00259 newMesh->mVertexBufferUsage = mVertexBufferUsage; 00260 newMesh->mIndexBufferUsage = mIndexBufferUsage; 00261 newMesh->mVertexBufferShadowBuffer = mVertexBufferShadowBuffer; 00262 newMesh->mIndexBufferShadowBuffer = mIndexBufferShadowBuffer; 00263 00264 newMesh->mSkeletonName = mSkeletonName; 00265 newMesh->mSkeleton = mSkeleton; 00266 00267 newMesh->load(); 00268 newMesh->touch(); 00269 00270 return newMesh; 00271 00272 } 00273 //----------------------------------------------------------------------- 00274 /* 00275 void Mesh::_updateBounds(void) 00276 { 00277 Vector3 min, max; 00278 bool first = true; 00279 bool useShared = false; 00280 00281 Real maxSquaredLength = -1.0f; 00282 00283 // Loop through SubMeshes, find extents 00284 SubMeshList::iterator i; 00285 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00286 { 00287 if (!(*i)->useSharedVertices) 00288 { 00289 (*i)->vertexData->getBounds(&mAABB, &maxSquaredLength); 00290 } 00291 } 00292 00293 // Check shared 00294 if (sharedVertexData) 00295 { 00296 sharedVertexData->getBounds(&mAABB, &maxSquaredLength); 00297 } 00298 00299 // Pad out the AABB a little, helps with most bounds tests 00300 mAABB.setExtents(mAABB.getMinimum() - Vector3::UNIT_SCALE, 00301 mAABB.getMaximum() + Vector3::UNIT_SCALE); 00302 // Pad out the sphere a little too 00303 mBoundRadius = Math::Sqrt(maxSquaredLength) * 1.25; 00304 mUpdateBounds = false; 00305 00306 } 00307 */ 00308 //----------------------------------------------------------------------- 00309 const AxisAlignedBox& Mesh::getBounds(void) const 00310 { 00311 /* 00312 if (mUpdateBounds) 00313 _updateBounds(); 00314 */ 00315 return mAABB; 00316 } 00317 //----------------------------------------------------------------------- 00318 void Mesh::_setBounds(const AxisAlignedBox& bounds) 00319 { 00320 mAABB = bounds; 00321 // Pad out the AABB a little, helps with most bounds tests 00322 mAABB.setExtents(mAABB.getMinimum() - Vector3::UNIT_SCALE, 00323 mAABB.getMaximum() + Vector3::UNIT_SCALE); 00324 00325 // Set sphere bouds; not the tightest by since we're using 00326 // manual AABB it is the only way 00327 Real sqLen1 = mAABB.getMinimum().squaredLength(); 00328 Real sqLen2 = mAABB.getMaximum().squaredLength(); 00329 mBoundRadius = Math::Sqrt(std::max(sqLen1, sqLen2)); 00330 // Pad out the sphere a little too 00331 mBoundRadius = mBoundRadius + 1; 00332 00333 //mUpdateBounds = false; 00334 } 00335 //----------------------------------------------------------------------- 00336 void Mesh::_setBoundingSphereRadius(Real radius) 00337 { 00338 mBoundRadius = radius; 00339 } 00340 //----------------------------------------------------------------------- 00341 void Mesh::setSkeletonName(const String& skelName) 00342 { 00343 mSkeletonName = skelName; 00344 00345 if (skelName == "") 00346 { 00347 // No skeleton 00348 mSkeleton = 0; 00349 } 00350 else 00351 { 00352 // Load skeleton 00353 try { 00354 mSkeleton = SkeletonManager::getSingleton().load(skelName); 00355 } 00356 catch (...) 00357 { 00358 mSkeleton = 0; 00359 // Log this error 00360 String msg = "Unable to load skeleton "; 00361 msg << skelName << " for Mesh " << mName 00362 << " This Mesh will not be animated. "; 00363 LogManager::getSingleton().logMessage(msg); 00364 00365 } 00366 00367 00368 } 00369 } 00370 //----------------------------------------------------------------------- 00371 bool Mesh::hasSkeleton(void) const 00372 { 00373 return !(mSkeletonName.empty()); 00374 } 00375 //----------------------------------------------------------------------- 00376 Skeleton* Mesh::getSkeleton(void) const 00377 { 00378 return mSkeleton; 00379 } 00380 //----------------------------------------------------------------------- 00381 void Mesh::addBoneAssignment(const VertexBoneAssignment& vertBoneAssign) 00382 { 00383 mBoneAssignments.insert( 00384 VertexBoneAssignmentList::value_type(vertBoneAssign.vertexIndex, vertBoneAssign)); 00385 mBoneAssignmentsOutOfDate = true; 00386 } 00387 //----------------------------------------------------------------------- 00388 void Mesh::clearBoneAssignments(void) 00389 { 00390 mBoneAssignments.clear(); 00391 mBoneAssignmentsOutOfDate = true; 00392 } 00393 //----------------------------------------------------------------------- 00394 void Mesh::_initAnimationState(AnimationStateSet* animSet) 00395 { 00396 // Delegate to Skeleton 00397 assert(mSkeleton && "Skeleton not present"); 00398 mSkeleton->_initAnimationState(animSet); 00399 00400 // Take the opportunity to update the compiled bone assignments 00401 if (mBoneAssignmentsOutOfDate) 00402 _compileBoneAssignments(); 00403 00404 SubMeshList::iterator i; 00405 for (i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00406 { 00407 if ((*i)->mBoneAssignmentsOutOfDate) 00408 { 00409 (*i)->_compileBoneAssignments(); 00410 } 00411 } 00412 } 00413 //----------------------------------------------------------------------- 00414 typedef std::multimap<Real, Mesh::VertexBoneAssignmentList::iterator> WeightIteratorMap; 00415 unsigned short Mesh::_rationaliseBoneAssignments(size_t vertexCount, Mesh::VertexBoneAssignmentList& assignments) 00416 { 00417 // Iterate through, finding the largest # bones per vertex 00418 unsigned short maxBones = 0; 00419 unsigned short currBones; 00420 currBones = 0; 00421 VertexBoneAssignmentList::iterator i; 00422 00423 for (size_t v = 0; v < vertexCount; ++v) 00424 { 00425 // Get number of entries for this vertex 00426 currBones = static_cast<unsigned short>(assignments.count(v)); 00427 00428 // Deal with max bones update 00429 // (note this will record maxBones even if they exceed limit) 00430 if (maxBones < currBones) 00431 maxBones = currBones; 00432 // does the number of bone assignments exceed limit? 00433 if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00434 { 00435 // To many bone assignments on this vertex 00436 // Find the start & end (end is in iterator terms ie exclusive) 00437 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> range; 00438 // map to sort by weight 00439 WeightIteratorMap weightToAssignmentMap; 00440 range = assignments.equal_range(v); 00441 // Add all the assignments to map 00442 for (i = range.first; i != range.second; ++i) 00443 { 00444 // insert value weight->iterator 00445 weightToAssignmentMap.insert( 00446 WeightIteratorMap::value_type(i->second.weight, i)); 00447 } 00448 // Reverse iterate over weight map, remove lowest n 00449 unsigned short numToRemove = currBones - OGRE_MAX_BLEND_WEIGHTS; 00450 WeightIteratorMap::iterator remIt = weightToAssignmentMap.begin(); 00451 00452 while (numToRemove--) 00453 { 00454 // Erase this one 00455 assignments.erase(remIt->second); 00456 ++remIt; 00457 } 00458 } // if (currBones > OGRE_MAX_BLEND_WEIGHTS) 00459 00460 // Make sure the weights are normalised 00461 // Do this irrespective of whether we had to remove assignments or not 00462 // since it gives us a guarantee that weights are normalised 00463 // We assume this, so it's a good idea since some modellers may not 00464 std::pair<VertexBoneAssignmentList::iterator, VertexBoneAssignmentList::iterator> normalise_range = assignments.equal_range(v); 00465 Real totalWeight = 0; 00466 // Find total first 00467 for (i = normalise_range.first; i != normalise_range.second; ++i) 00468 { 00469 totalWeight += i->second.weight; 00470 } 00471 // Now normalise if total weight is outside tolerance 00472 if (!Math::RealEqual(totalWeight, 1.0f)) 00473 { 00474 for (i = normalise_range.first; i != normalise_range.second; ++i) 00475 { 00476 i->second.weight = i->second.weight / totalWeight; 00477 } 00478 } 00479 00480 } 00481 00482 if (maxBones > OGRE_MAX_BLEND_WEIGHTS) 00483 { 00484 // Warn that we've reduced bone assignments 00485 LogManager::getSingleton().logMessage("WARNING: the mesh '" + mName + "' " 00486 "includes vertices with more than " + 00487 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + " bone assignments. " 00488 "The lowest weighted assignments beyond this limit have been removed, so " 00489 "your animation may look slightly different. To eliminate this, reduce " 00490 "the number of bone assignments per vertex on your mesh to " + 00491 StringConverter::toString(OGRE_MAX_BLEND_WEIGHTS) + "."); 00492 // we've adjusted them down to the max 00493 maxBones = OGRE_MAX_BLEND_WEIGHTS; 00494 00495 } 00496 00497 return maxBones; 00498 } 00499 //----------------------------------------------------------------------- 00500 void Mesh::_compileBoneAssignments(void) 00501 { 00502 unsigned short maxBones = 00503 _rationaliseBoneAssignments(sharedVertexData->vertexCount, mBoneAssignments); 00504 00505 if (maxBones == 0) 00506 { 00507 // No bone assignments 00508 return; 00509 } 00510 00511 compileBoneAssignments(mBoneAssignments, maxBones, 00512 sharedVertexData); 00513 mBoneAssignmentsOutOfDate = false; 00514 00515 } 00516 //--------------------------------------------------------------------- 00517 void Mesh::compileBoneAssignments( 00518 const VertexBoneAssignmentList& boneAssignments, 00519 unsigned short numBlendWeightsPerVertex, 00520 VertexData* targetVertexData) 00521 { 00522 // Create or reuse blend weight / indexes buffer 00523 // Indices are always a UBYTE4 no matter how many weights per vertex 00524 // Weights are more specific though since they are Reals 00525 VertexDeclaration* decl = targetVertexData->vertexDeclaration; 00526 VertexBufferBinding* bind = targetVertexData->vertexBufferBinding; 00527 unsigned short bindIndex; 00528 00529 const VertexElement* testElem = 00530 decl->findElementBySemantic(VES_BLEND_INDICES); 00531 if (testElem) 00532 { 00533 // Already have a buffer, unset it & delete elements 00534 bindIndex = testElem->getSource(); 00535 // unset will cause deletion of buffer 00536 bind->unsetBinding(bindIndex); 00537 decl->removeElement(VES_BLEND_INDICES); 00538 decl->removeElement(VES_BLEND_WEIGHTS); 00539 } 00540 else 00541 { 00542 // Get new binding 00543 bindIndex = bind->getNextIndex(); 00544 } 00545 00546 HardwareVertexBufferSharedPtr vbuf = 00547 HardwareBufferManager::getSingleton().createVertexBuffer( 00548 sizeof(unsigned char)*4 + sizeof(Real)*numBlendWeightsPerVertex, 00549 targetVertexData->vertexCount, 00550 HardwareBuffer::HBU_STATIC_WRITE_ONLY, 00551 true // use shadow buffer 00552 ); 00553 // bind new buffer 00554 bind->setBinding(bindIndex, vbuf); 00555 const VertexElement *pIdxElem, *pWeightElem; 00556 00557 // add new vertex elements 00558 // Note, insert directly after position to abide by pre-Dx9 format restrictions 00559 if(decl->getElement(0)->getSemantic() == VES_POSITION) 00560 { 00561 const VertexElement& idxElem = 00562 decl->insertElement(1, bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 00563 const VertexElement& wtElem = 00564 decl->insertElement(2, bindIndex, sizeof(unsigned char)*4, 00565 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex), 00566 VES_BLEND_WEIGHTS); 00567 pIdxElem = &idxElem; 00568 pWeightElem = &wtElem; 00569 } 00570 else 00571 { 00572 // Position is not the first semantic, therefore this declaration is 00573 // not pre-Dx9 compatible anyway, so just tack it on the end 00574 const VertexElement& idxElem = 00575 decl->addElement(bindIndex, 0, VET_UBYTE4, VES_BLEND_INDICES); 00576 const VertexElement& wtElem = 00577 decl->addElement(bindIndex, sizeof(unsigned char)*4, 00578 VertexElement::multiplyTypeCount(VET_FLOAT1, numBlendWeightsPerVertex), 00579 VES_BLEND_WEIGHTS); 00580 pIdxElem = &idxElem; 00581 pWeightElem = &wtElem; 00582 } 00583 00584 // Assign data 00585 size_t v; 00586 VertexBoneAssignmentList::const_iterator i, iend; 00587 i = boneAssignments.begin(); 00588 iend = boneAssignments.end(); 00589 unsigned char *pBase = static_cast<unsigned char*>( 00590 vbuf->lock(HardwareBuffer::HBL_DISCARD)); 00591 // Iterate by vertex 00592 Real *pWeight; 00593 unsigned char *pIndex; 00594 for (v = 0; v < targetVertexData->vertexCount; ++v) 00595 { 00597 pWeightElem->baseVertexPointerToElement(pBase, &pWeight); 00598 pIdxElem->baseVertexPointerToElement(pBase, &pIndex); 00599 for (unsigned short bone = 0; bone < numBlendWeightsPerVertex; ++bone) 00600 { 00601 // Do we still have data for this vertex? 00602 if (i != iend && i->second.vertexIndex == v) 00603 { 00604 // If so, write weight 00605 *pWeight++ = i->second.weight; 00606 *pIndex++ = i->second.boneIndex; 00607 ++i; 00608 } 00609 else 00610 { 00611 // Ran out of assignments for this vertex, use weight 0 to indicate empty 00612 *pWeight++ = 0.0f; 00613 *pIndex++ = 0; 00614 } 00615 } 00616 pBase += vbuf->getVertexSize(); 00617 } 00618 00619 vbuf->unlock(); 00620 00621 } 00622 //--------------------------------------------------------------------- 00623 void Mesh::_notifySkeleton(Skeleton* pSkel) 00624 { 00625 mSkeleton = pSkel; 00626 mSkeletonName = pSkel->getName(); 00627 } 00628 //--------------------------------------------------------------------- 00629 Mesh::BoneAssignmentIterator Mesh::getBoneAssignmentIterator(void) 00630 { 00631 return BoneAssignmentIterator(mBoneAssignments.begin(), 00632 mBoneAssignments.end()); 00633 } 00634 //--------------------------------------------------------------------- 00635 const String& Mesh::getSkeletonName(void) const 00636 { 00637 return mSkeletonName; 00638 } 00639 //--------------------------------------------------------------------- 00640 void Mesh::generateLodLevels(const LodDistanceList& lodDistances, 00641 ProgressiveMesh::VertexReductionQuota reductionMethod, Real reductionValue) 00642 { 00643 mMeshLodUsageList.clear(); 00644 mIsLodManual = false; 00645 00646 char msg[128]; 00647 sprintf(msg, "Generating %d lower LODs for mesh %s.", 00648 lodDistances.size(), mName.c_str()); 00649 LogManager::getSingleton().logMessage(msg); 00650 00651 SubMeshList::iterator isub, isubend; 00652 isubend = mSubMeshList.end(); 00653 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00654 { 00655 // Set up data for reduction 00656 VertexData* pVertexData = (*isub)->useSharedVertices ? sharedVertexData : (*isub)->vertexData; 00657 00658 ProgressiveMesh pm(pVertexData, (*isub)->indexData); 00659 pm.build( 00660 static_cast<ushort>(lodDistances.size()), 00661 &((*isub)->mLodFaceList), 00662 reductionMethod, reductionValue); 00663 00664 } 00665 00666 // Iterate over the lods and record usage 00667 LodDistanceList::const_iterator idist, idistend; 00668 idistend = lodDistances.end(); 00669 // Record first LOD (full detail) 00670 MeshLodUsage lod; 00671 lod.fromDepthSquared = 0.0f; 00672 lod.edgeData = NULL; 00673 lod.manualMesh = NULL; 00674 mMeshLodUsageList.push_back(lod); 00675 00676 for (idist = lodDistances.begin(); idist != idistend; ++idist) 00677 { 00678 // Record usage 00679 lod.fromDepthSquared = (*idist) * (*idist); 00680 lod.edgeData = NULL; 00681 lod.manualMesh = NULL; 00682 mMeshLodUsageList.push_back(lod); 00683 00684 } 00685 mNumLods = static_cast<ushort>(lodDistances.size() + 1); 00686 } 00687 //--------------------------------------------------------------------- 00688 ushort Mesh::getNumLodLevels(void) const 00689 { 00690 return mNumLods; 00691 } 00692 //--------------------------------------------------------------------- 00693 const Mesh::MeshLodUsage& Mesh::getLodLevel(ushort index) const 00694 { 00695 assert(index < mMeshLodUsageList.size()); 00696 if (mIsLodManual && index > 0 && mMeshLodUsageList[index].manualMesh == NULL) 00697 { 00698 // Load the mesh now 00699 mMeshLodUsageList[index].manualMesh = 00700 MeshManager::getSingleton().load(mMeshLodUsageList[index].manualName); 00701 } 00702 return mMeshLodUsageList[index]; 00703 } 00704 //--------------------------------------------------------------------- 00705 struct ManualLodSortLess : 00706 public std::binary_function<const Mesh::MeshLodUsage&, const Mesh::MeshLodUsage&, bool> 00707 { 00708 bool operator() (const Mesh::MeshLodUsage& mesh1, const Mesh::MeshLodUsage& mesh2) 00709 { 00710 // sort ascending by depth 00711 return mesh1.fromDepthSquared < mesh2.fromDepthSquared; 00712 } 00713 }; 00714 void Mesh::createManualLodLevel(Real fromDepth, const String& meshName) 00715 { 00716 mIsLodManual = true; 00717 MeshLodUsage lod; 00718 lod.fromDepthSquared = fromDepth * fromDepth; 00719 lod.manualName = meshName; 00720 lod.manualMesh = NULL; 00721 lod.edgeData = NULL; 00722 mMeshLodUsageList.push_back(lod); 00723 ++mNumLods; 00724 00725 std::sort(mMeshLodUsageList.begin(), mMeshLodUsageList.end(), ManualLodSortLess()); 00726 } 00727 //--------------------------------------------------------------------- 00728 void Mesh::updateManualLodLevel(ushort index, const String& meshName) 00729 { 00730 // Basic prerequisites 00731 assert(mIsLodManual && "Not using manual LODs!"); 00732 assert(index != 0 && "Can't modify first lod level (full detail)"); 00733 assert(index < mMeshLodUsageList.size() && "Index out of bounds"); 00734 // get lod 00735 MeshLodUsage* lod = &(mMeshLodUsageList[index]); 00736 00737 lod->manualName = meshName; 00738 lod->manualMesh = NULL; 00739 if (lod->edgeData) delete lod->edgeData; 00740 lod->edgeData = NULL; 00741 } 00742 //--------------------------------------------------------------------- 00743 ushort Mesh::getLodIndex(Real depth) const 00744 { 00745 return getLodIndexSquaredDepth(depth * depth); 00746 } 00747 //--------------------------------------------------------------------- 00748 ushort Mesh::getLodIndexSquaredDepth(Real squaredDepth) const 00749 { 00750 MeshLodUsageList::const_iterator i, iend; 00751 iend = mMeshLodUsageList.end(); 00752 ushort index = 0; 00753 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 00754 { 00755 if (i->fromDepthSquared > squaredDepth) 00756 { 00757 return index - 1; 00758 } 00759 } 00760 00761 // If we fall all the way through, use the highest value 00762 return static_cast<ushort>(mMeshLodUsageList.size() - 1); 00763 00764 00765 } 00766 //--------------------------------------------------------------------- 00767 void Mesh::_setLodInfo(unsigned short numLevels, bool isManual) 00768 { 00769 mNumLods = numLevels; 00770 mMeshLodUsageList.resize(numLevels); 00771 // Resize submesh face data lists too 00772 for (SubMeshList::iterator i = mSubMeshList.begin(); i != mSubMeshList.end(); ++i) 00773 { 00774 (*i)->mLodFaceList.resize(numLevels - 1); 00775 } 00776 mIsLodManual = isManual; 00777 } 00778 //--------------------------------------------------------------------- 00779 void Mesh::_setLodUsage(unsigned short level, Mesh::MeshLodUsage& usage) 00780 { 00781 mMeshLodUsageList[level] = usage; 00782 } 00783 //--------------------------------------------------------------------- 00784 void Mesh::_setSubMeshLodFaceList(unsigned short subIdx, unsigned short level, 00785 IndexData* facedata) 00786 { 00787 SubMesh* sm = mSubMeshList[subIdx]; 00788 sm->mLodFaceList[level - 1] = facedata; 00789 00790 } 00791 //--------------------------------------------------------------------- 00792 ushort Mesh::_getSubMeshIndex(const String& name) const 00793 { 00794 SubMeshNameMap::const_iterator i = mSubMeshNameMap.find(name) ; 00795 if (i == mSubMeshNameMap.end()) 00796 Except(Exception::ERR_ITEM_NOT_FOUND, "No SubMesh named " + name + " found.", 00797 "Mesh::_getSubMeshIndex"); 00798 00799 return i->second; 00800 } 00801 //--------------------------------------------------------------------- 00802 void Mesh::removeLodLevels(void) 00803 { 00804 if (!mIsLodManual) 00805 { 00806 // Remove data from SubMeshes 00807 SubMeshList::iterator isub, isubend; 00808 isubend = mSubMeshList.end(); 00809 for (isub = mSubMeshList.begin(); isub != isubend; ++isub) 00810 { 00811 (*isub)->removeLodLevels(); 00812 } 00813 } 00814 00815 mMeshLodUsageList.clear(); 00816 00817 // Reinitialise 00818 mNumLods = 1; 00819 // Init first (manual) lod 00820 MeshLodUsage lod; 00821 lod.fromDepthSquared = 0.0f; 00822 mMeshLodUsageList.push_back(lod); 00823 mIsLodManual = false; 00824 00825 00826 } 00827 //--------------------------------------------------------------------- 00828 Real Mesh::getBoundingSphereRadius(void) const 00829 { 00830 return mBoundRadius; 00831 } 00832 //--------------------------------------------------------------------- 00833 void Mesh::setVertexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00834 { 00835 mVertexBufferUsage = vbUsage; 00836 mVertexBufferShadowBuffer = shadowBuffer; 00837 } 00838 //--------------------------------------------------------------------- 00839 void Mesh::setIndexBufferPolicy(HardwareBuffer::Usage vbUsage, bool shadowBuffer) 00840 { 00841 mIndexBufferUsage = vbUsage; 00842 mIndexBufferShadowBuffer = shadowBuffer; 00843 } 00844 //--------------------------------------------------------------------- 00845 HardwareVertexBufferSharedPtr Mesh::getTangentsBuffer(VertexData *vertexData, 00846 unsigned short texCoordSet) 00847 { 00848 VertexDeclaration *vDecl = vertexData->vertexDeclaration ; 00849 VertexBufferBinding *vBind = vertexData->vertexBufferBinding ; 00850 00851 const VertexElement *tex3D = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, texCoordSet); 00852 bool needsToBeCreated = false; 00853 00854 if (!tex3D) 00855 { // no tex coords with index 1 00856 needsToBeCreated = true ; 00857 } 00858 else if (tex3D->getType() != VET_FLOAT3) 00859 { // no 3d-coords tex buffer 00860 vDecl->removeElement(VES_TEXTURE_COORDINATES, texCoordSet); 00861 vBind->unsetBinding(tex3D->getSource()); 00862 needsToBeCreated = true ; 00863 } 00864 00865 HardwareVertexBufferSharedPtr tex3DBuf ; 00866 if (needsToBeCreated) 00867 { 00868 tex3DBuf = HardwareBufferManager::getSingleton().createVertexBuffer( 00869 3*sizeof(float), vertexData->vertexCount, 00870 HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, 00871 true ); 00872 int source = vBind->getNextIndex(); // find next available source 00873 vBind->setBinding(source, tex3DBuf); 00874 vDecl->addElement(source, 0, VET_FLOAT3, VES_TEXTURE_COORDINATES, texCoordSet); 00875 } 00876 else 00877 { 00878 tex3DBuf = vBind->getBuffer(tex3D->getSource()); 00879 } 00880 00881 return tex3DBuf; 00882 } 00883 //--------------------------------------------------------------------- 00884 void Mesh::buildTangentVectors(unsigned short sourceTexCoordSet, 00885 unsigned short destTexCoordSet) 00886 { 00887 00888 // our temp. buffers 00889 unsigned short vertInd[3]; 00890 Vector3 vertPos[3]; 00891 Real u[3], v[3]; 00892 // setup a new 3D texture coord-set buffer for every sub mesh 00893 int nSubMesh = getNumSubMeshes(); 00894 for (int sm = 0; sm < nSubMesh; sm++) 00895 { 00896 // retrieve buffer pointers 00897 unsigned short *pVIndices; // the face indices buffer, read only 00898 Real *p2DTC; // pointer to 2D tex.coords, read only 00899 Real *p3DTC; // pointer to 3D tex.coords, write/read (discard) 00900 Real *pVPos; // vertex position buffer, read only 00901 00902 SubMesh *pSubMesh = getSubMesh(sm); 00903 00904 // retrieve buffer pointers 00905 // first, indices 00906 IndexData *indexData = pSubMesh->indexData; 00907 HardwareIndexBufferSharedPtr buffIndex = indexData->indexBuffer ; 00908 pVIndices = (unsigned short*) buffIndex->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00909 // then, vertices 00910 VertexData *usedVertexData ; 00911 if (pSubMesh->useSharedVertices) { 00912 usedVertexData = sharedVertexData; 00913 } else { 00914 usedVertexData = pSubMesh->vertexData; 00915 } 00916 VertexDeclaration *vDecl = usedVertexData->vertexDeclaration; 00917 VertexBufferBinding *vBind = usedVertexData->vertexBufferBinding; 00918 00919 00920 // get a new 3D tex.coord.buffer or an existing one 00921 HardwareVertexBufferSharedPtr buff3DTC = getTangentsBuffer(usedVertexData, destTexCoordSet); 00922 // clear it 00923 p3DTC = (Real*) buff3DTC->lock(HardwareBuffer::HBL_DISCARD); // ***LOCK*** 00924 memset(p3DTC,0,buff3DTC->getSizeInBytes()); 00925 // find a 2D tex coord buffer 00926 const VertexElement *elem2DTC = vDecl->findElementBySemantic(VES_TEXTURE_COORDINATES, sourceTexCoordSet); 00927 00928 if (!elem2DTC || elem2DTC->getType() != VET_FLOAT2) 00929 { 00930 Except(Exception::ERR_INVALIDPARAMS, 00931 "SubMesh " + StringConverter::toString(sm) + " of Mesh " + mName + 00932 " has no 2D texture coordinates, therefore we cannot calculate tangents.", 00933 "Mesh::buildTangentVectors"); 00934 } 00935 HardwareVertexBufferSharedPtr buff2DTC = vBind->getBuffer(elem2DTC->getSource()); 00936 p2DTC = (Real*) buff2DTC->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00937 // find a vertex coord buffer 00938 const VertexElement *elemVPos = vDecl->findElementBySemantic(VES_POSITION); 00939 HardwareVertexBufferSharedPtr buffVPos = vBind->getBuffer(elemVPos->getSource()); 00940 pVPos = (Real*) buffVPos->lock(HardwareBuffer::HBL_READ_ONLY); // ***LOCK*** 00941 00942 size_t numFaces = indexData->indexCount / 3 ; 00943 00944 // loop through all faces to calculate the tangents and normals 00945 size_t n; 00946 for (n = 0; n < numFaces; ++n) 00947 { 00948 int i; 00949 for (i = 0; i < 3; ++i) 00950 { 00951 // get indexes of vertices that form a polygon in the position buffer 00952 vertInd[i] = *pVIndices++; 00953 // get the vertices positions from the position buffer 00954 vertPos[i].x = pVPos[3 * vertInd[i] + 0]; 00955 vertPos[i].y = pVPos[3 * vertInd[i] + 1]; 00956 vertPos[i].z = pVPos[3 * vertInd[i] + 2]; 00957 // get the vertices tex.coords from the 2D tex.coords buffer 00958 u[i] = p2DTC[2 * vertInd[i] + 0]; 00959 v[i] = p2DTC[2 * vertInd[i] + 1]; 00960 } 00961 // calculate the TSB 00962 Vector3 tangent = Math::calculateTangentSpaceVector( 00963 vertPos[0], vertPos[1], vertPos[2], 00964 u[0], v[0], u[1], v[1], u[2], v[2]); 00965 // write new tex.coords 00966 // note we only write the tangent, not the binormal since we can calculate 00967 // the binormal in the vertex program 00968 for (i = 0; i < 3; ++i) 00969 { 00970 // write values (they must be 0 and we must add them so we can average 00971 // all the contributions from all the faces 00972 p3DTC[3 * vertInd[i] + 0] += tangent.x; 00973 p3DTC[3 * vertInd[i] + 1] += tangent.y; 00974 p3DTC[3 * vertInd[i] + 2] += tangent.z; 00975 } 00976 } 00977 // now loop through all vertices and normalize them 00978 size_t numVerts = usedVertexData->vertexCount ; 00979 for (n = 0; n < numVerts * 3; n += 3) 00980 { 00981 // read the vertex 00982 Vector3 temp(p3DTC[n + 0], p3DTC[n + 1], p3DTC[n + 2]); 00983 // normalize the vertex 00984 temp.normalise(); 00985 // write it back 00986 p3DTC[n + 0] = temp.x; 00987 p3DTC[n + 1] = temp.y; 00988 p3DTC[n + 2] = temp.z; 00989 } 00990 // unlock buffers 00991 buffIndex->unlock(); 00992 buff3DTC->unlock(); 00993 buff2DTC->unlock(); 00994 buffVPos->unlock(); 00995 } 00996 00997 } 00998 00999 //--------------------------------------------------------------------- 01000 void Mesh::buildEdgeList(void) 01001 { 01002 if (mEdgeListsBuilt) 01003 { 01004 // destroy existing edge data 01005 freeEdgeList(); 01006 } 01007 01008 // Loop over LODs 01009 for (unsigned int lodIndex = 0; lodIndex < mMeshLodUsageList.size(); ++lodIndex) 01010 { 01011 // use getLodLevel to enforce loading of manual mesh lods 01012 MeshLodUsage& usage = const_cast<MeshLodUsage&>(getLodLevel(lodIndex)); 01013 01014 if (mIsLodManual && lodIndex != 0) 01015 { 01016 // Delegate edge building to manual mesh 01017 // It should have already built it's own edge list while loading 01018 usage.edgeData = usage.manualMesh->getEdgeList(0); 01019 } 01020 else 01021 { 01022 // Build 01023 EdgeListBuilder eb; 01024 size_t vertexSetCount = 0; 01025 01026 if (sharedVertexData) 01027 { 01028 eb.addVertexData(sharedVertexData); 01029 vertexSetCount++; 01030 } 01031 01032 // Prepare the builder using the submesh information 01033 SubMeshList::iterator i, iend; 01034 iend = mSubMeshList.end(); 01035 for (i = mSubMeshList.begin(); i != iend; ++i) 01036 { 01037 SubMesh* s = *i; 01038 if (s->useSharedVertices) 01039 { 01040 // Use shared vertex data, index as set 0 01041 if (lodIndex == 0) 01042 { 01043 eb.addIndexData(s->indexData, 0, s->operationType); 01044 } 01045 else 01046 { 01047 eb.addIndexData(s->mLodFaceList[lodIndex-1], 0, 01048 s->operationType); 01049 } 01050 } 01051 else 01052 { 01053 // own vertex data, add it and reference it directly 01054 eb.addVertexData(s->vertexData); 01055 if (lodIndex == 0) 01056 { 01057 // Base index data 01058 eb.addIndexData(s->indexData, vertexSetCount++, 01059 s->operationType); 01060 } 01061 else 01062 { 01063 // LOD index data 01064 eb.addIndexData(s->mLodFaceList[lodIndex-1], 01065 vertexSetCount++, s->operationType); 01066 } 01067 01068 } 01069 } 01070 01071 usage.edgeData = eb.build(); 01072 01073 #if OGRE_DEBUG_MODE 01074 // Override default log 01075 Log* log = LogManager::getSingleton().createLog( 01076 mName + "_lod" + StringConverter::toString(lodIndex) + 01077 "_prepshadow.log", false, false); 01078 usage.edgeData->log(log); 01079 #endif 01080 01081 } 01082 } 01083 } 01084 //--------------------------------------------------------------------- 01085 void Mesh::freeEdgeList(void) 01086 { 01087 // Loop over LODs 01088 MeshLodUsageList::iterator i, iend; 01089 iend = mMeshLodUsageList.end(); 01090 unsigned short index = 0; 01091 for (i = mMeshLodUsageList.begin(); i != iend; ++i, ++index) 01092 { 01093 MeshLodUsage& usage = *i; 01094 01095 if (!mIsLodManual || index == 0) 01096 { 01097 // Only delete if we own this data 01098 // Manual LODs > 0 own their own 01099 delete usage.edgeData; 01100 } 01101 usage.edgeData = NULL; 01102 } 01103 } 01104 //--------------------------------------------------------------------- 01105 void Mesh::prepareForShadowVolume(void) 01106 { 01107 if (sharedVertexData) 01108 { 01109 sharedVertexData->prepareForShadowVolume(); 01110 } 01111 SubMeshList::iterator i, iend; 01112 iend = mSubMeshList.end(); 01113 for (i = mSubMeshList.begin(); i != iend; ++i) 01114 { 01115 SubMesh* s = *i; 01116 if (!s->useSharedVertices) 01117 { 01118 s->vertexData->prepareForShadowVolume(); 01119 } 01120 } 01121 mPreparedForShadowVolumes = true; 01122 } 01123 //--------------------------------------------------------------------- 01124 EdgeData* Mesh::getEdgeList(unsigned int lodIndex) 01125 { 01126 return getLodLevel(lodIndex).edgeData; 01127 } 01128 //--------------------------------------------------------------------- 01129 void Mesh::softwareVertexBlend(const VertexData* sourceVertexData, 01130 const VertexData* targetVertexData, const Matrix4* pMatrices, 01131 bool blendNormals) 01132 { 01133 // Source vectors 01134 Vector3 sourceVec, sourceNorm; 01135 // Accumulation vectors 01136 Vector3 accumVecPos, accumVecNorm; 01137 01138 Real *pSrcPos, *pSrcNorm, *pDestPos, *pDestNorm, *pBlendWeight; 01139 unsigned char* pBlendIdx; 01140 bool srcPosNormShareBuffer = false; 01141 bool destPosNormShareBuffer = false; 01142 bool weightsIndexesShareBuffer = false; 01143 01144 01145 // Get elements for source 01146 const VertexElement* srcElemPos = 01147 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 01148 const VertexElement* srcElemNorm = 01149 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 01150 const VertexElement* srcElemBlendIndices = 01151 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_INDICES); 01152 const VertexElement* srcElemBlendWeights = 01153 sourceVertexData->vertexDeclaration->findElementBySemantic(VES_BLEND_WEIGHTS); 01154 assert (srcElemPos && srcElemBlendIndices && srcElemBlendWeights && 01155 "You must supply at least positions, blend indices and blend weights"); 01156 // Get elements for target 01157 const VertexElement* destElemPos = 01158 targetVertexData->vertexDeclaration->findElementBySemantic(VES_POSITION); 01159 const VertexElement* destElemNorm = 01160 targetVertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL); 01161 01162 // Do we have normals and want to blend them? 01163 bool includeNormals = blendNormals && (srcElemNorm != NULL) && (destElemNorm != NULL); 01164 01165 01166 // Get buffers for source 01167 HardwareVertexBufferSharedPtr srcPosBuf, srcNormBuf, srcIdxBuf, srcWeightBuf; 01168 srcPosBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemPos->getSource()); 01169 srcIdxBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendIndices->getSource()); 01170 srcWeightBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemBlendWeights->getSource()); 01171 if (includeNormals) 01172 { 01173 srcNormBuf = sourceVertexData->vertexBufferBinding->getBuffer(srcElemNorm->getSource()); 01174 srcPosNormShareBuffer = (srcPosBuf.get() == srcNormBuf.get()); 01175 } 01176 weightsIndexesShareBuffer = (srcIdxBuf.get() == srcWeightBuf.get()); 01177 // Get buffers for target 01178 HardwareVertexBufferSharedPtr destPosBuf, destNormBuf; 01179 destPosBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemPos->getSource()); 01180 if (includeNormals) 01181 { 01182 destNormBuf = targetVertexData->vertexBufferBinding->getBuffer(destElemNorm->getSource()); 01183 destPosNormShareBuffer = (destPosBuf.get() == destNormBuf.get()); 01184 } 01185 01186 // Lock source buffers for reading 01187 assert (srcElemPos->getOffset() == 0 && 01188 "Positions must be first element in dedicated buffer!"); 01189 pSrcPos = static_cast<Real*>( 01190 srcPosBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01191 if (includeNormals) 01192 { 01193 if (srcPosNormShareBuffer) 01194 { 01195 // Same buffer, must be packed directly after position 01196 assert (srcElemNorm->getOffset() == sizeof(Real) * 3 && 01197 "Normals must be packed directly after positions in buffer!"); 01198 // pSrcNorm will not be used 01199 } 01200 else 01201 { 01202 // Different buffer 01203 assert (srcElemNorm->getOffset() == 0 && 01204 "Normals must be first element in dedicated buffer!"); 01205 pSrcNorm = static_cast<Real*>( 01206 srcNormBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01207 } 01208 } 01209 01210 // Indices must be first in a buffer and be 4 bytes 01211 assert(srcElemBlendIndices->getOffset() == 0 && 01212 srcElemBlendIndices->getType() == VET_UBYTE4 && 01213 "Blend indices must be first in a buffer and be VET_UBYTE4"); 01214 pBlendIdx = static_cast<unsigned char*>( 01215 srcIdxBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01216 if (weightsIndexesShareBuffer) 01217 { 01218 // Weights must be packed directly after the indices 01219 assert(srcElemBlendWeights->getOffset() == sizeof(unsigned char)*4 && 01220 "Blend weights must be directly after indices in the buffer"); 01221 srcElemBlendWeights->baseVertexPointerToElement(pBlendIdx, &pBlendWeight); 01222 } 01223 else 01224 { 01225 // Weights must be at the start of the buffer 01226 assert(srcElemBlendWeights->getOffset() == 0 && 01227 "Blend weights must be at the start of a dedicated buffer"); 01228 // Lock buffer 01229 pBlendWeight = static_cast<Real*>( 01230 srcWeightBuf->lock(HardwareBuffer::HBL_READ_ONLY)); 01231 } 01232 unsigned short numWeightsPerVertex = 01233 VertexElement::getTypeCount(srcElemBlendWeights->getType()); 01234 01235 01236 // Lock destination buffers for writing 01237 assert (destElemPos->getOffset() == 0 && 01238 "Positions must be first element in dedicated buffer!"); 01239 pDestPos = static_cast<Real*>( 01240 destPosBuf->lock(HardwareBuffer::HBL_DISCARD)); 01241 if (includeNormals) 01242 { 01243 if (destPosNormShareBuffer) 01244 { 01245 // Same buffer, must be packed directly after position 01246 assert (destElemNorm->getOffset() == sizeof(Real) * 3 && 01247 "Normals must be packed directly after positions in buffer!"); 01248 // pDestNorm will not be used 01249 } 01250 else 01251 { 01252 // Different buffer 01253 assert (destElemNorm->getOffset() == 0 && 01254 "Normals must be first element in dedicated buffer!"); 01255 pDestNorm = static_cast<Real*>( 01256 destNormBuf->lock(HardwareBuffer::HBL_DISCARD)); 01257 } 01258 } 01259 01260 // Loop per vertex 01261 for (size_t vertIdx = 0; vertIdx < targetVertexData->vertexCount; ++vertIdx) 01262 { 01263 // Load source vertex elements 01264 sourceVec.x = *pSrcPos++; 01265 sourceVec.y = *pSrcPos++; 01266 sourceVec.z = *pSrcPos++; 01267 01268 if (includeNormals) 01269 { 01270 if (srcPosNormShareBuffer) 01271 { 01272 sourceNorm.x = *pSrcPos++; 01273 sourceNorm.y = *pSrcPos++; 01274 sourceNorm.z = *pSrcPos++; 01275 } 01276 else 01277 { 01278 sourceNorm.x = *pSrcNorm++; 01279 sourceNorm.y = *pSrcNorm++; 01280 sourceNorm.z = *pSrcNorm++; 01281 } 01282 } 01283 // Load accumulators 01284 accumVecPos = Vector3::ZERO; 01285 accumVecNorm = Vector3::ZERO; 01286 01287 // Loop per blend weight 01288 for (unsigned short blendIdx = 0; 01289 blendIdx < numWeightsPerVertex; ++blendIdx) 01290 { 01291 // Blend by multiplying source by blend matrix and scaling by weight 01292 // Add to accumulator 01293 // NB weights must be normalised!! 01294 if (*pBlendWeight != 0.0) 01295 { 01296 // Blend position, use 3x4 matrix 01297 const Matrix4& mat = pMatrices[*pBlendIdx]; 01298 accumVecPos.x += 01299 (mat[0][0] * sourceVec.x + 01300 mat[0][1] * sourceVec.y + 01301 mat[0][2] * sourceVec.z + 01302 mat[0][3]) 01303 * (*pBlendWeight); 01304 accumVecPos.y += 01305 (mat[1][0] * sourceVec.x + 01306 mat[1][1] * sourceVec.y + 01307 mat[1][2] * sourceVec.z + 01308 mat[1][3]) 01309 * (*pBlendWeight); 01310 accumVecPos.z += 01311 (mat[2][0] * sourceVec.x + 01312 mat[2][1] * sourceVec.y + 01313 mat[2][2] * sourceVec.z + 01314 mat[2][3]) 01315 * (*pBlendWeight); 01316 if (includeNormals) 01317 { 01318 // Blend normal 01319 // We should blend by inverse transpose here, but because we're assuming the 3x3 01320 // aspect of the matrix is orthogonal (no non-uniform scaling), the inverse transpose 01321 // is equal to the main 3x3 matrix 01322 // Note because it's a normal we just extract the rotational part, saves us renormalising here 01323 accumVecNorm.x += 01324 (mat[0][0] * sourceNorm.x + 01325 mat[0][1] * sourceNorm.y + 01326 mat[0][2] * sourceNorm.z) 01327 * (*pBlendWeight); 01328 accumVecNorm.y += 01329 (mat[1][0] * sourceNorm.x + 01330 mat[1][1] * sourceNorm.y + 01331 mat[1][2] * sourceNorm.z) 01332 * (*pBlendWeight); 01333 accumVecNorm.z += 01334 (mat[2][0] * sourceNorm.x + 01335 mat[2][1] * sourceNorm.y + 01336 mat[2][2] * sourceNorm.z) 01337 * (*pBlendWeight); 01338 } 01339 01340 } 01341 ++pBlendWeight; 01342 ++pBlendIdx; 01343 } 01344 // Finish off blend info pointers 01345 // Make sure we skip over 4 index elements no matter how many we used 01346 pBlendIdx += 4 - numWeightsPerVertex; 01347 if(weightsIndexesShareBuffer) 01348 { 01349 // Skip index over weights 01350 pBlendIdx += sizeof(Real) * numWeightsPerVertex; 01351 // Re-base weights 01352 srcElemBlendWeights->baseVertexPointerToElement(pBlendIdx, &pBlendWeight); 01353 } 01354 01355 01356 // Stored blended vertex in hardware buffer 01357 *pDestPos++ = accumVecPos.x; 01358 *pDestPos++ = accumVecPos.y; 01359 *pDestPos++ = accumVecPos.z; 01360 01361 // Stored blended vertex in temp buffer 01362 if (includeNormals) 01363 { 01364 // Normalise 01365 accumVecNorm.normalise(); 01366 if (destPosNormShareBuffer) 01367 { 01368 // Pack into same buffer 01369 *pDestPos++ = accumVecNorm.x; 01370 *pDestPos++ = accumVecNorm.y; 01371 *pDestPos++ = accumVecNorm.z; 01372 } 01373 else 01374 { 01375 *pDestNorm++ = accumVecNorm.x; 01376 *pDestNorm++ = accumVecNorm.y; 01377 *pDestNorm++ = accumVecNorm.z; 01378 } 01379 } 01380 } 01381 // Unlock source buffers 01382 srcPosBuf->unlock(); 01383 srcIdxBuf->unlock(); 01384 if (!weightsIndexesShareBuffer) 01385 { 01386 srcWeightBuf->unlock(); 01387 } 01388 if (includeNormals && !srcPosNormShareBuffer) 01389 { 01390 srcNormBuf->unlock(); 01391 } 01392 // Unlock destination buffers 01393 destPosBuf->unlock(); 01394 if (includeNormals && !destPosNormShareBuffer) 01395 { 01396 destNormBuf->unlock(); 01397 01398 } 01399 01400 01401 01402 } 01403 01404 } 01405
Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:25 2004