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

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:25 2004