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

Copyright © 2002-2003 by The OGRE Team
Last modified Sun Nov 28 19:48:34 2004