Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreMesh.cpp

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

Copyright © 2002-2003 by The OGRE Team
Last modified Wed Jan 21 00:10:18 2004