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