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

OgreMeshSerializerImpl.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 
00027 #include "OgreMeshSerializerImpl.h"
00028 #include "OgreMeshFileFormat.h"
00029 #include "OgreMesh.h"
00030 #include "OgreSubMesh.h"
00031 #include "OgreException.h"
00032 #include "OgreMaterialManager.h"
00033 #include "OgreLogManager.h"
00034 #include "OgreSkeleton.h"
00035 #include "OgreHardwareBufferManager.h"
00036 #include "OgreMaterial.h"
00037 #include "OgreTechnique.h"
00038 #include "OgrePass.h"
00039 
00040 
00041 namespace Ogre {
00042 
00044     const unsigned long CHUNK_OVERHEAD_SIZE = sizeof(unsigned short) + sizeof(unsigned long);
00045     //---------------------------------------------------------------------
00046     MeshSerializerImpl::MeshSerializerImpl()
00047     {
00048         mpMesh = 0;
00049 
00050         // Version number
00051         mVersion = "[MeshSerializer_v1.20]";
00052     }
00053     //---------------------------------------------------------------------
00054     MeshSerializerImpl::~MeshSerializerImpl()
00055     {
00056     }
00057     //---------------------------------------------------------------------
00058     void MeshSerializerImpl::exportMesh(const Mesh* pMesh, const String& filename)
00059     {
00060         LogManager::getSingleton().logMessage("MeshSerializer writing mesh data to " + filename + "...");
00061 
00062         // Check that the mesh has it's bounds set
00063         if (pMesh->getBounds().isNull() || pMesh->getBoundingSphereRadius() == 0.0f)
00064         {
00065             Except(Exception::ERR_INVALIDPARAMS, "The Mesh you have supplied does not have its"
00066                 " bounds completely defined. Define them first before exporting.", 
00067                 "MeshSerializerImpl::exportMesh");
00068         }
00069         mpfFile = fopen(filename, "wb");
00070 
00071         writeFileHeader();
00072         LogManager::getSingleton().logMessage("File header written.");
00073 
00074 
00075         LogManager::getSingleton().logMessage("Writing mesh data...");
00076         writeMesh(pMesh);
00077         LogManager::getSingleton().logMessage("Mesh data exported.");
00078 
00079         fclose(mpfFile);
00080         LogManager::getSingleton().logMessage("MeshSerializer export successful.");
00081     }
00082     //---------------------------------------------------------------------
00083     void MeshSerializerImpl::importMesh(DataChunk& chunk, Mesh* pDest)
00084     {
00085         mpMesh = pDest;
00086 
00087         // Check header
00088         readFileHeader(chunk);
00089 
00090         unsigned short chunkID;
00091         while(!chunk.isEOF())
00092         {
00093             chunkID = readChunk(chunk);
00094             switch (chunkID)
00095             {
00096             case M_MESH:
00097                 readMesh(chunk);
00098                 break;
00099             case M_MATERIAL:     // removed in 1.1 but still present in 1.0
00100                  readMaterial(chunk);    
00101                  break;                
00102             }
00103         }
00104     }
00105     //---------------------------------------------------------------------
00106     void MeshSerializerImpl::writeMesh(const Mesh* pMesh)
00107     {
00108         // Header
00109         writeChunkHeader(M_MESH, calcMeshSize(pMesh));
00110 
00111         // bool skeletallyAnimated
00112         bool skelAnim = pMesh->hasSkeleton();
00113         writeBools(&skelAnim, 1);
00114 
00115         // Write shared geometry
00116         if (pMesh->sharedVertexData)
00117             writeGeometry(pMesh->sharedVertexData);
00118 
00119         // Write Submeshes
00120         for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
00121         {
00122             LogManager::getSingleton().logMessage("Writing submesh...");
00123             writeSubMesh(pMesh->getSubMesh(i));
00124             LogManager::getSingleton().logMessage("Submesh exported.");
00125         }
00126 
00127         // Write skeleton info if required
00128         if (pMesh->hasSkeleton())
00129         {
00130             LogManager::getSingleton().logMessage("Exporting skeleton link...");
00131             // Write skeleton link
00132             writeSkeletonLink(pMesh->getSkeletonName());
00133             LogManager::getSingleton().logMessage("Skeleton link exported.");
00134 
00135             // Write bone assignments
00136             if (!pMesh->mBoneAssignments.empty())
00137             {
00138                 LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");
00139 
00140                 Mesh::VertexBoneAssignmentList::const_iterator vi;
00141                 for (vi = pMesh->mBoneAssignments.begin(); 
00142                 vi != pMesh->mBoneAssignments.end(); ++vi)
00143                 {
00144                     writeMeshBoneAssignment(&(vi->second));
00145                 }
00146 
00147                 LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
00148             }
00149         }
00150 
00151         // Write LOD data if any
00152         if (pMesh->getNumLodLevels() > 1)
00153         {
00154             LogManager::getSingleton().logMessage("Exporting LOD information....");
00155             writeLodInfo(pMesh);
00156             LogManager::getSingleton().logMessage("LOD information exported.");
00157             
00158         }
00159         // Write bounds information
00160         LogManager::getSingleton().logMessage("Exporting bounds information....");
00161         writeBoundsInfo(pMesh);
00162         LogManager::getSingleton().logMessage("Bounds information exported.");
00163 
00164 
00165     }
00166     //---------------------------------------------------------------------
00167     void MeshSerializerImpl::writeSubMesh(const SubMesh* s)
00168     {
00169         // Header
00170         writeChunkHeader(M_SUBMESH, calcSubMeshSize(s));
00171 
00172         // char* materialName
00173         writeString(s->getMaterialName());
00174 
00175         // bool useSharedVertices
00176         writeBools(&s->useSharedVertices, 1);
00177 
00178         // unsigned int indexCount
00179         writeInts(&s->indexData->indexCount, 1);
00180 
00181         // bool indexes32Bit
00182         bool idx32bit = (s->indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT);
00183         writeBools(&idx32bit, 1);
00184 
00185         // unsigned short* faceVertexIndices ((indexCount)
00186         HardwareIndexBufferSharedPtr ibuf = s->indexData->indexBuffer;
00187         void* pIdx = ibuf->lock(HardwareBuffer::HBL_READ_ONLY);
00188         if (idx32bit)
00189         {
00190             unsigned int* pIdx32 = static_cast<unsigned int*>(pIdx);
00191             writeInts(pIdx32, s->indexData->indexCount);
00192         }
00193         else
00194         {
00195             unsigned short* pIdx16 = static_cast<unsigned short*>(pIdx);
00196             writeShorts(pIdx16, s->indexData->indexCount);
00197         }
00198         ibuf->unlock();
00199 
00200         // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
00201         if (!s->useSharedVertices)
00202         {
00203             writeGeometry(s->vertexData);
00204         }
00205         
00206         // Operation type
00207         writeSubMeshOperation(s);
00208 
00209         // Bone assignments
00210         if (!s->mBoneAssignments.empty())
00211         {
00212             LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");
00213 
00214             SubMesh::VertexBoneAssignmentList::const_iterator vi;
00215             for (vi = s->mBoneAssignments.begin(); 
00216             vi != s->mBoneAssignments.end(); ++vi)
00217             {
00218                 writeSubMeshBoneAssignment(&(vi->second));
00219             }
00220 
00221             LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
00222         }
00223 
00224 
00225     }
00226     //---------------------------------------------------------------------
00227     void MeshSerializerImpl::writeSubMeshOperation(const SubMesh* sm)
00228     {
00229         // Header
00230         writeChunkHeader(M_SUBMESH_OPERATION, calcSubMeshOperationSize(sm));
00231 
00232         // unsigned short operationType
00233         unsigned short opType = static_cast<unsigned short>(sm->operationType);
00234         writeShorts(&opType, 1);
00235     }
00236     //---------------------------------------------------------------------
00237     void MeshSerializerImpl::writeCondensedVertexBuffer(HardwareVertexBufferSharedPtr vbuf, 
00238         const VertexElement* elem, size_t vertexCount)
00239     {
00240         // Hacky method, turns shared buffers into unshared
00241         // Needed because for now the mesh format only supports unshared for simplicity
00242         // This will probably be upgraded in the next version, but there were enough
00243         // changes going on as it is!
00244         void* pVert = vbuf->lock(HardwareBuffer::HBL_READ_ONLY);
00245 
00246         // Check see if already unshared
00247         if (vbuf->getVertexSize() == elem->getSize())
00248         {
00249             // Bulk copy
00250             writeReals(static_cast<Real*>(pVert), vertexCount * VertexElement::getTypeCount(elem->getType()));
00251         }
00252         else
00253         {
00254             // Do it the hard way
00255             Real* pReal;
00256             while (vertexCount--)
00257             {
00258                 elem->baseVertexPointerToElement(pVert, &pReal);
00259                 writeReals(pReal, VertexElement::getTypeCount(elem->getType()));
00260                 pVert = static_cast<void*>(
00261                     static_cast<unsigned char*>(pVert) + vbuf->getVertexSize() );
00262             }
00263         }
00264         
00265         vbuf->unlock();
00266     }
00267     //---------------------------------------------------------------------
00268     void MeshSerializerImpl::writeGeometry(const VertexData* vertexData)
00269     {
00270         // Header
00271         writeChunkHeader(M_GEOMETRY, calcGeometrySize(vertexData));
00272 
00273         // unsigned int numVertices
00274         writeInts(&vertexData->vertexCount, 1);
00275 
00276         // Real* pVertices (x, y, z order x numVertices)
00277         const VertexElement* elem = 
00278             vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION);
00279         if (!elem)
00280         {
00281             Except(Exception::ERR_ITEM_NOT_FOUND, "Can't find position elements in the "
00282             "mesh to be written!", "MeshSerializerImpl::writeGeometry");
00283         }
00284         HardwareVertexBufferSharedPtr vbuf = 
00285             vertexData->vertexBufferBinding->getBuffer(elem->getSource());
00286         writeCondensedVertexBuffer(vbuf, elem, vertexData->vertexCount);
00287         //writeReals(pReal, vertexData->vertexCount * 3);
00288 
00289         elem = vertexData->vertexDeclaration->findElementBySemantic(VES_NORMAL);
00290         if (elem)
00291         {
00292             writeChunkHeader(M_GEOMETRY_NORMALS, 
00293                 static_cast<unsigned long>(elem->getSize() * vertexData->vertexCount));
00294 
00295             // Real* pNormals (x, y, z order x numVertices)
00296             vbuf = vertexData->vertexBufferBinding->getBuffer(elem->getSource());
00297             writeCondensedVertexBuffer(vbuf, elem, vertexData->vertexCount);
00298         }
00299 
00300         elem = vertexData->vertexDeclaration->findElementBySemantic(VES_DIFFUSE);
00301         if (elem)
00302         {
00303             writeChunkHeader(M_GEOMETRY_COLOURS, 
00304                 static_cast<unsigned long>(elem->getSize() * vertexData->vertexCount));
00305             // unsigned long* pColours (RGBA 8888 format x numVertices)
00306             vbuf = vertexData->vertexBufferBinding->getBuffer(elem->getSource());
00307             writeCondensedVertexBuffer(vbuf, elem, vertexData->vertexCount);
00308         }
00309 
00310         for (int t = 0; t < OGRE_MAX_TEXTURE_COORD_SETS; ++t)
00311         {
00312             elem = vertexData->vertexDeclaration->findElementBySemantic(VES_TEXTURE_COORDINATES, t);
00313             if (elem)
00314             {
00315                 writeChunkHeader(M_GEOMETRY_TEXCOORDS, 
00316                     static_cast<unsigned long>(elem->getSize() * vertexData->vertexCount));
00317                 vbuf = vertexData->vertexBufferBinding->getBuffer(elem->getSource());
00318                 // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
00319                 unsigned short dims = VertexElement::getTypeCount(elem->getType());
00320                 writeShorts(&dims, 1);
00321                 // Real* pTexCoords  (u [v] [w] order, dimensions x numVertices)
00322                 writeCondensedVertexBuffer(vbuf, elem, vertexData->vertexCount);
00323             }
00324 
00325         }
00326 
00327 
00328     }
00329     //---------------------------------------------------------------------
00330     unsigned long MeshSerializerImpl::calcMeshSize(const Mesh* pMesh)
00331     {
00332         unsigned long size = CHUNK_OVERHEAD_SIZE;
00333 
00334         // Num shared vertices
00335         size += sizeof(unsigned int);
00336 
00337         // Geometry
00338         if (pMesh->sharedVertexData && pMesh->sharedVertexData->vertexCount > 0)
00339         {
00340             size += calcGeometrySize(pMesh->sharedVertexData);
00341         }
00342 
00343         // Submeshes
00344         for (int i = 0; i < pMesh->getNumSubMeshes(); ++i)
00345         {
00346             size += calcSubMeshSize(pMesh->getSubMesh(i));
00347         }
00348 
00349         // Skeleton link
00350         if (pMesh->hasSkeleton())
00351         {
00352             size += calcSkeletonLinkSize(pMesh->getSkeletonName());
00353         }
00354 
00355         return size;
00356 
00357     }
00358     //---------------------------------------------------------------------
00359     unsigned long MeshSerializerImpl::calcSubMeshSize(const SubMesh* pSub)
00360     {
00361         size_t size = CHUNK_OVERHEAD_SIZE;
00362 
00363         // Material name
00364         size += (unsigned long)pSub->getMaterialName().length() + 1;
00365 
00366         // bool useSharedVertices
00367         size += sizeof(bool);
00368         // unsigned int indexCount
00369         size += sizeof(unsigned int);
00370         // bool indexes32bit
00371         size += sizeof(bool);
00372         // unsigned int* faceVertexIndices 
00373         size += sizeof(unsigned int) * pSub->indexData->indexCount;
00374 
00375         // Geometry
00376         if (!pSub->useSharedVertices)
00377         {
00378             size += calcGeometrySize(pSub->vertexData);
00379         }
00380 
00381         return static_cast<unsigned long>(size);
00382     }
00383     //---------------------------------------------------------------------
00384     unsigned long MeshSerializerImpl::calcSubMeshOperationSize(const SubMesh* pSub)
00385     {
00386         return CHUNK_OVERHEAD_SIZE + sizeof(unsigned short);
00387     }
00388     //---------------------------------------------------------------------
00389     unsigned long MeshSerializerImpl::calcGeometrySize(const VertexData* vertexData)
00390     {
00391         size_t size = CHUNK_OVERHEAD_SIZE;
00392 
00393         // Num vertices
00394         size += sizeof(unsigned int);
00395 
00396         const VertexDeclaration::VertexElementList& elems = 
00397             vertexData->vertexDeclaration->getElements();
00398 
00399         VertexDeclaration::VertexElementList::const_iterator i, iend;
00400         iend = elems.end();
00401         for (i = elems.begin(); i != iend; ++i)
00402         {
00403             const VertexElement& elem = *i;
00404             // Vertex element
00405             size += VertexElement::getTypeSize(elem.getType()) * vertexData->vertexCount;
00406         }
00407         return static_cast<unsigned long>(size);
00408     }
00409     //---------------------------------------------------------------------
00410     void MeshSerializerImpl::readMesh(DataChunk& chunk)
00411     {
00412         unsigned short chunkID;
00413 
00414         // bool skeletallyAnimated
00415         readBools(chunk, &mIsSkeletallyAnimated, 1);
00416         if (mIsSkeletallyAnimated)
00417         {
00418             // If we're skeletally animated, we need to set the vertex buffer
00419             // policy to dynamic and NOT shadowed, so we can update regularly
00420             mpMesh->setVertexBufferPolicy(HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, false);
00421             // Note that later on we'll have to set up a system memory copy of the 
00422             // positions & normals which will be used as the reference data
00423         }
00424 
00425 
00426         // Find all subchunks 
00427         if (!chunk.isEOF())
00428         {
00429             chunkID = readChunk(chunk);
00430             while(!chunk.isEOF() &&
00431                 (chunkID == M_GEOMETRY ||
00432                  chunkID == M_SUBMESH ||
00433                  chunkID == M_MESH_SKELETON_LINK ||
00434                  chunkID == M_MESH_BONE_ASSIGNMENT ||
00435                  chunkID == M_MESH_LOD ||
00436                  chunkID == M_MESH_BOUNDS))
00437             {
00438                 switch(chunkID)
00439                 {
00440                 case M_GEOMETRY:
00441                     mpMesh->sharedVertexData = new VertexData();
00442                     try {
00443                         readGeometry(chunk, mpMesh->sharedVertexData);
00444                     }
00445                     catch (Exception& e)
00446                     {
00447                         if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
00448                         {
00449                             // duff geometry data entry with 0 vertices
00450                             delete mpMesh->sharedVertexData;
00451                             mpMesh->sharedVertexData = 0;
00452                             // Skip this chunk (pointer will have been returned to just after header)
00453                             chunk.skip(mCurrentChunkLen - CHUNK_OVERHEAD_SIZE);
00454                         }
00455                         else
00456                         {
00457                             throw;
00458                         }
00459                     }
00460                     break;
00461                 case M_SUBMESH:
00462                     readSubMesh(chunk);
00463                     break;
00464                 case M_MESH_SKELETON_LINK:
00465                     readSkeletonLink(chunk);
00466                     break;
00467                 case M_MESH_BONE_ASSIGNMENT:
00468                     readMeshBoneAssignment(chunk);
00469                     break;
00470                 case M_MESH_LOD:
00471                     readMeshLodInfo(chunk);
00472                     break;
00473                 case M_MESH_BOUNDS:
00474                     readBoundsInfo(chunk);
00475                     break;
00476                 }
00477 
00478                 if (!chunk.isEOF())
00479                 {
00480                     chunkID = readChunk(chunk);
00481                 }
00482 
00483             }
00484             if (!chunk.isEOF())
00485             {
00486                 // Backpedal back to start of chunk
00487                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
00488             }
00489         }
00490 
00491     }
00492     //---------------------------------------------------------------------
00493     void MeshSerializerImpl::readSubMesh(DataChunk& chunk)
00494     {
00495         unsigned short chunkID;
00496 
00497         SubMesh* sm = mpMesh->createSubMesh();
00498         // char* materialName
00499         String materialName = readString(chunk);
00500         sm->setMaterialName(materialName);
00501 
00502         // bool useSharedVertices
00503         readBools(chunk,&sm->useSharedVertices, 1);
00504 
00505         // unsigned int indexCount
00506         sm->indexData->indexStart = 0;
00507         readInts(chunk, &sm->indexData->indexCount, 1);
00508 
00509         HardwareIndexBufferSharedPtr ibuf;
00510         // bool indexes32Bit
00511         bool idx32bit;
00512         readBools(chunk, &idx32bit, 1);
00513         if (idx32bit)
00514         {
00515             ibuf = HardwareBufferManager::getSingleton().
00516                 createIndexBuffer(
00517                     HardwareIndexBuffer::IT_32BIT, 
00518                     sm->indexData->indexCount, 
00519                     mpMesh->mIndexBufferUsage,
00520                     mpMesh->mIndexBufferShadowBuffer);
00521             // unsigned int* faceVertexIndices 
00522             unsigned int* pIdx = static_cast<unsigned int*>(
00523                 ibuf->lock(HardwareBuffer::HBL_DISCARD)
00524                 );
00525             readInts(chunk, pIdx, sm->indexData->indexCount);
00526             ibuf->unlock();
00527 
00528         }
00529         else // 16-bit
00530         {
00531             ibuf = HardwareBufferManager::getSingleton().
00532                 createIndexBuffer(
00533                     HardwareIndexBuffer::IT_16BIT, 
00534                     sm->indexData->indexCount, 
00535                     mpMesh->mIndexBufferUsage,
00536                     mpMesh->mIndexBufferShadowBuffer);
00537             // unsigned short* faceVertexIndices 
00538             unsigned short* pIdx = static_cast<unsigned short*>(
00539                 ibuf->lock(HardwareBuffer::HBL_DISCARD)
00540                 );
00541             readShorts(chunk, pIdx, sm->indexData->indexCount);
00542             ibuf->unlock();
00543         }
00544         sm->indexData->indexBuffer = ibuf;
00545 
00546         // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
00547         if (!sm->useSharedVertices)
00548         {
00549             chunkID = readChunk(chunk);
00550             if (chunkID != M_GEOMETRY)
00551             {
00552                 Except(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file", 
00553                     "MeshSerializerImpl::readSubMesh");
00554             }
00555             sm->vertexData = new VertexData();
00556             readGeometry(chunk, sm->vertexData);
00557         }
00558 
00559 
00560         // Find all bone assignments (if present) 
00561         if (!chunk.isEOF())
00562         {
00563             chunkID = readChunk(chunk);
00564             while(!chunk.isEOF() &&
00565                 (chunkID == M_SUBMESH_BONE_ASSIGNMENT ||
00566                  chunkID == M_SUBMESH_OPERATION))
00567             {
00568                 switch(chunkID)
00569                 {
00570                 case M_SUBMESH_OPERATION:
00571                     readSubMeshOperation(chunk, sm);
00572                     break;
00573                 case M_SUBMESH_BONE_ASSIGNMENT:
00574                     readSubMeshBoneAssignment(chunk, sm);
00575                     break;
00576                 }
00577 
00578                 if (!chunk.isEOF())
00579                 {
00580                     chunkID = readChunk(chunk);
00581                 }
00582 
00583             }
00584             if (!chunk.isEOF())
00585             {
00586                 // Backpedal back to start of chunk
00587                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
00588             }
00589         }
00590     
00591 
00592     }
00593     //---------------------------------------------------------------------
00594     void MeshSerializerImpl::readSubMeshOperation(DataChunk& chunk, SubMesh* sm)
00595     {
00596         // unsigned short operationType
00597         unsigned short opType;
00598         readShorts(chunk, &opType, 1);
00599         sm->operationType = static_cast<RenderOperation::OperationType>(opType);
00600     }
00601     //---------------------------------------------------------------------
00602     void MeshSerializerImpl::readGeometry(DataChunk& chunk, VertexData* dest)
00603     {
00604         unsigned short texCoordSet = 0;
00605         
00606         unsigned short bindIdx = 0;
00607 
00608         if (mIsSkeletallyAnimated)
00609         {
00610             // Create software blending structure
00611             dest->softwareBlendInfo = new VertexData::SoftwareBlendInfo();
00612             // Automatic blending on
00613             dest->softwareBlendInfo->automaticBlend = true;
00614         }
00615         dest->vertexStart = 0;
00616 
00617         // unsigned int numVertices
00618         readInts(chunk, &dest->vertexCount, 1);
00619 
00620         // Vertex buffers
00621         // TODO: consider redesigning this so vertex buffers can be combined
00622 
00623         readGeometryPositions(bindIdx, chunk, dest);
00624         ++bindIdx;
00625 
00626         // Find optional geometry chunks
00627         if (!chunk.isEOF())
00628         {
00629             unsigned short chunkID = readChunk(chunk);
00630             while(!chunk.isEOF() && 
00631                 (chunkID == M_GEOMETRY_NORMALS || 
00632                  chunkID == M_GEOMETRY_COLOURS ||
00633                  chunkID == M_GEOMETRY_TEXCOORDS ))
00634             {
00635                 switch (chunkID)
00636                 {
00637                 case M_GEOMETRY_NORMALS:
00638                     readGeometryNormals(bindIdx++, chunk, dest);
00639                     break;
00640                 case M_GEOMETRY_COLOURS:
00641                     readGeometryColours(bindIdx++, chunk, dest);
00642                     break;
00643                 case M_GEOMETRY_TEXCOORDS:
00644                     readGeometryTexCoords(bindIdx++, chunk, dest, texCoordSet++);
00645                     break;
00646                 }
00647                 // Get next chunk
00648                 if (!chunk.isEOF())
00649                 {
00650                     chunkID = readChunk(chunk);
00651                 }
00652             }
00653             if (!chunk.isEOF())
00654             {
00655                 // Backpedal back to start of non-submesh chunk
00656                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
00657             }
00658         }
00659     }
00660     //---------------------------------------------------------------------
00661     void MeshSerializerImpl::readGeometryPositions(unsigned short bindIdx, 
00662         DataChunk& chunk, VertexData* dest)
00663     {
00664         Real *pReal = 0;
00665         HardwareVertexBufferSharedPtr vbuf;
00666         // Real* pVertices (x, y, z order x numVertices)
00667         dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_POSITION);
00668         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
00669             dest->vertexDeclaration->getVertexSize(bindIdx),
00670             dest->vertexCount,
00671             mpMesh->mVertexBufferUsage, 
00672             mpMesh->mIndexBufferShadowBuffer);
00673         pReal = static_cast<Real*>(
00674             vbuf->lock(HardwareBuffer::HBL_DISCARD));
00675         if (mIsSkeletallyAnimated)
00676         {
00677             // Copy data into software buffers for source of blending
00678             dest->softwareBlendInfo->pSrcPositions = new Real[dest->vertexCount * 3];
00679             readReals(chunk, dest->softwareBlendInfo->pSrcPositions, dest->vertexCount * 3);
00680             // Copy into hardware buffer
00681             memcpy(pReal, dest->softwareBlendInfo->pSrcPositions, 
00682                 sizeof(Real) * dest->vertexCount * 3);
00683         }
00684         else
00685         {
00686             // Read direct into hardware buffer
00687             readReals(chunk, pReal, dest->vertexCount * 3);
00688         }
00689         vbuf->unlock();
00690         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
00691     }
00692     //---------------------------------------------------------------------
00693     void MeshSerializerImpl::readGeometryNormals(unsigned short bindIdx, 
00694         DataChunk& chunk, VertexData* dest)
00695     {
00696         Real *pReal = 0;
00697         HardwareVertexBufferSharedPtr vbuf;
00698         // Real* pNormals (x, y, z order x numVertices)
00699         dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_NORMAL);
00700         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
00701             dest->vertexDeclaration->getVertexSize(bindIdx),
00702             dest->vertexCount,
00703             mpMesh->mVertexBufferUsage,
00704             mpMesh->mVertexBufferShadowBuffer);
00705         pReal = static_cast<Real*>(
00706             vbuf->lock(HardwareBuffer::HBL_DISCARD));
00707         if (mIsSkeletallyAnimated)
00708         {
00709             // Copy data into software buffers for source of blending
00710             dest->softwareBlendInfo->pSrcNormals = new Real[dest->vertexCount * 3];
00711             readReals(chunk, 
00712                 dest->softwareBlendInfo->pSrcNormals, dest->vertexCount * 3);
00713             // Copy into hardware buffer
00714             memcpy(pReal, dest->softwareBlendInfo->pSrcNormals, 
00715                 sizeof(Real) * dest->vertexCount * 3);
00716         }
00717         else
00718         {
00719             // Read direct into hardware buffer
00720             readReals(chunk, pReal, dest->vertexCount * 3);
00721         }
00722         vbuf->unlock();
00723         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
00724     }
00725     //---------------------------------------------------------------------
00726     void MeshSerializerImpl::readGeometryColours(unsigned short bindIdx, 
00727         DataChunk& chunk, VertexData* dest)
00728     {
00729         RGBA* pRGBA = 0;
00730         HardwareVertexBufferSharedPtr vbuf;
00731         // unsigned long* pColours (RGBA 8888 format x numVertices)
00732         dest->vertexDeclaration->addElement(bindIdx, 0, VET_COLOUR, VES_DIFFUSE);
00733         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
00734             dest->vertexDeclaration->getVertexSize(bindIdx),
00735             dest->vertexCount,
00736             mpMesh->mVertexBufferUsage,
00737             mpMesh->mVertexBufferShadowBuffer);
00738         pRGBA = static_cast<RGBA*>(
00739             vbuf->lock(HardwareBuffer::HBL_DISCARD));
00740         readLongs(chunk, pRGBA, dest->vertexCount);
00741         vbuf->unlock();
00742         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
00743     }
00744     //---------------------------------------------------------------------
00745     void MeshSerializerImpl::readGeometryTexCoords(unsigned short bindIdx, 
00746         DataChunk& chunk, VertexData* dest, unsigned short texCoordSet)
00747     {
00748         Real *pReal = 0;
00749         HardwareVertexBufferSharedPtr vbuf;
00750         // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
00751         unsigned short dim;
00752         readShorts(chunk, &dim, 1);
00753         // Real* pTexCoords  (u [v] [w] order, dimensions x numVertices)
00754         dest->vertexDeclaration->addElement(
00755             bindIdx, 
00756             0, 
00757             VertexElement::multiplyTypeCount(VET_FLOAT1, dim), 
00758             VES_TEXTURE_COORDINATES,
00759             texCoordSet);
00760         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
00761             dest->vertexDeclaration->getVertexSize(bindIdx),
00762             dest->vertexCount,
00763             mpMesh->mVertexBufferUsage,
00764             mpMesh->mVertexBufferShadowBuffer);
00765         pReal = static_cast<Real*>(
00766             vbuf->lock(HardwareBuffer::HBL_DISCARD));
00767         readReals(chunk, pReal, dest->vertexCount * dim);
00768         vbuf->unlock();
00769         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
00770     }
00771     //---------------------------------------------------------------------
00772     void MeshSerializerImpl::writeSkeletonLink(const String& skelName)
00773     {
00774         writeChunkHeader(M_MESH_SKELETON_LINK, calcSkeletonLinkSize(skelName));
00775 
00776         writeString(skelName);
00777 
00778     }
00779     //---------------------------------------------------------------------
00780     void MeshSerializerImpl::readSkeletonLink(DataChunk &chunk)
00781     {
00782         String skelName = readString(chunk);
00783         mpMesh->setSkeletonName(skelName);
00784     }
00785     //---------------------------------------------------------------------
00786     void MeshSerializerImpl::readMaterial(DataChunk& chunk)
00787     {
00788 
00789         // Material definition section phased out of 1.1
00790 
00791     }
00792     //---------------------------------------------------------------------
00793     void MeshSerializerImpl::readTextureLayer(DataChunk& chunk, Material* pMat)
00794     {
00795         // Material definition section phased out of 1.1
00796     }
00797     //---------------------------------------------------------------------
00798     unsigned long MeshSerializerImpl::calcSkeletonLinkSize(const String& skelName)
00799     {
00800         unsigned long size = CHUNK_OVERHEAD_SIZE;
00801 
00802         size += (unsigned long)skelName.length() + 1;
00803 
00804         return size;
00805 
00806     }
00807     //---------------------------------------------------------------------
00808     void MeshSerializerImpl::writeMeshBoneAssignment(const VertexBoneAssignment* assign)
00809     {
00810         writeChunkHeader(M_MESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
00811 
00812         // unsigned int vertexIndex;
00813         writeInts(&(assign->vertexIndex), 1);
00814         // unsigned short boneIndex;
00815         writeShorts(&(assign->boneIndex), 1);
00816         // Real weight;
00817         writeReals(&(assign->weight), 1);
00818     }
00819     //---------------------------------------------------------------------
00820     void MeshSerializerImpl::writeSubMeshBoneAssignment(const VertexBoneAssignment* assign)
00821     {
00822         writeChunkHeader(M_SUBMESH_BONE_ASSIGNMENT, calcBoneAssignmentSize());
00823 
00824         // unsigned int vertexIndex;
00825         writeInts(&(assign->vertexIndex), 1);
00826         // unsigned short boneIndex;
00827         writeShorts(&(assign->boneIndex), 1);
00828         // Real weight;
00829         writeReals(&(assign->weight), 1);
00830     }
00831     //---------------------------------------------------------------------
00832     void MeshSerializerImpl::readMeshBoneAssignment(DataChunk& chunk)
00833     {
00834         VertexBoneAssignment assign;
00835 
00836         // unsigned int vertexIndex;
00837         readInts(chunk, &(assign.vertexIndex),1);
00838         // unsigned short boneIndex;
00839         readShorts(chunk, &(assign.boneIndex),1);
00840         // Real weight;
00841         readReals(chunk, &(assign.weight), 1);
00842 
00843         mpMesh->addBoneAssignment(assign);
00844 
00845     }
00846     //---------------------------------------------------------------------
00847     void MeshSerializerImpl::readSubMeshBoneAssignment(DataChunk& chunk, SubMesh* sub)
00848     {
00849         VertexBoneAssignment assign;
00850 
00851         // unsigned int vertexIndex;
00852         readInts(chunk, &(assign.vertexIndex),1);
00853         // unsigned short boneIndex;
00854         readShorts(chunk, &(assign.boneIndex),1);
00855         // Real weight;
00856         readReals(chunk, &(assign.weight), 1);
00857 
00858         sub->addBoneAssignment(assign);
00859 
00860     }
00861     //---------------------------------------------------------------------
00862     unsigned long MeshSerializerImpl::calcBoneAssignmentSize(void)
00863     {
00864         unsigned long size;
00865 
00866         size = CHUNK_OVERHEAD_SIZE;
00867 
00868         // Vert index
00869         size += sizeof(unsigned int);
00870         // Bone index
00871         size += sizeof(unsigned short);
00872         // weight
00873         size += sizeof(Real);
00874 
00875         return size;
00876     }
00877     //---------------------------------------------------------------------
00878     void MeshSerializerImpl::writeLodInfo(const Mesh* pMesh)
00879     {
00880         unsigned short numLods = pMesh->getNumLodLevels();
00881         bool manual = pMesh->isLodManual();
00882         writeLodSummary(numLods, manual);
00883 
00884         // Loop from LOD 1 (not 0, this is full detail)
00885         for (unsigned short i = 1; i < numLods; ++i)
00886         {
00887             const Mesh::MeshLodUsage& usage = pMesh->getLodLevel(i);
00888             if (manual)
00889             {
00890                 writeLodUsageManual(usage);
00891             }
00892             else
00893             {
00894                 writeLodUsageGenerated(pMesh, usage, i);
00895             }
00896             
00897         }
00898         
00899 
00900     }
00901     //---------------------------------------------------------------------
00902     void MeshSerializerImpl::writeLodSummary(unsigned short numLevels, bool manual)
00903     {
00904         // Header
00905         unsigned long size = CHUNK_OVERHEAD_SIZE;
00906         // unsigned short numLevels;
00907         size += sizeof(unsigned short);
00908         // bool manual;  (true for manual alternate meshes, false for generated)
00909         size += sizeof(bool);
00910         writeChunkHeader(M_MESH_LOD, size);
00911 
00912         // Details
00913         // unsigned short numLevels;
00914         writeShorts(&numLevels, 1);
00915         // bool manual;  (true for manual alternate meshes, false for generated)
00916         writeBools(&manual, 1);
00917 
00918         
00919     }
00920     //---------------------------------------------------------------------
00921     void MeshSerializerImpl::writeLodUsageManual(const Mesh::MeshLodUsage& usage)
00922     {
00923         // Header
00924         unsigned long size = CHUNK_OVERHEAD_SIZE;
00925         unsigned long manualSize = CHUNK_OVERHEAD_SIZE;
00926         // Real fromDepthSquared;
00927         size += sizeof(Real);
00928         // Manual part size
00929 
00930         // String manualMeshName;
00931         manualSize += static_cast<unsigned long>(usage.manualName.length() + 1);
00932 
00933         size += manualSize;
00934 
00935         writeChunkHeader(M_MESH_LOD_USAGE, size);
00936         writeReals(&(usage.fromDepthSquared), 1);
00937 
00938         writeChunkHeader(M_MESH_LOD_MANUAL, manualSize);
00939         writeString(usage.manualName);
00940         
00941 
00942     }
00943     //---------------------------------------------------------------------
00944     void MeshSerializerImpl::writeLodUsageGenerated(const Mesh* pMesh, const Mesh::MeshLodUsage& usage,
00945         unsigned short lodNum)
00946     {
00947         // Usage Header
00948         unsigned long size = CHUNK_OVERHEAD_SIZE;
00949         unsigned short subidx;
00950 
00951         // Real fromDepthSquared;
00952         size += sizeof(Real);
00953 
00954         // Calc generated SubMesh sections size
00955         for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
00956         {
00957             // header
00958             size += CHUNK_OVERHEAD_SIZE;
00959             // unsigned int numFaces;
00960             size += sizeof(unsigned int);
00961             SubMesh* sm = pMesh->getSubMesh(subidx);
00962             const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
00963 
00964             // bool indexes32Bit
00965             size += sizeof(bool);
00966             // unsigned short*/int* faceIndexes;  
00967             if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
00968             {
00969                 size += static_cast<unsigned long>(
00970                     sizeof(unsigned int) * indexData->indexCount);
00971             }
00972             else
00973             {
00974                 size += static_cast<unsigned long>(
00975                     sizeof(unsigned short) * indexData->indexCount);
00976             }
00977 
00978         }
00979 
00980         writeChunkHeader(M_MESH_LOD_USAGE, size);
00981         writeReals(&(usage.fromDepthSquared), 1);
00982 
00983         // Now write sections
00984         // Calc generated SubMesh sections size
00985         for(subidx = 0; subidx < pMesh->getNumSubMeshes(); ++subidx)
00986         {
00987             size = CHUNK_OVERHEAD_SIZE;
00988             // unsigned int numFaces;
00989             size += sizeof(unsigned int);
00990             SubMesh* sm = pMesh->getSubMesh(subidx);
00991             const IndexData* indexData = sm->mLodFaceList[lodNum - 1];
00992             // bool indexes32Bit
00993             size += sizeof(bool);
00994             // unsigned short*/int* faceIndexes;  
00995             if (indexData->indexBuffer->getType() == HardwareIndexBuffer::IT_32BIT)
00996             {
00997                 size += static_cast<unsigned long>(
00998                     sizeof(unsigned int) * indexData->indexCount);
00999             }
01000             else
01001             {
01002                 size += static_cast<unsigned long>(
01003                     sizeof(unsigned short) * indexData->indexCount);
01004             }
01005 
01006             writeChunkHeader(M_MESH_LOD_GENERATED, size);
01007             unsigned int idxCount = static_cast<unsigned int>(indexData->indexCount);
01008             writeInts(&idxCount, 1);
01009             // Lock index buffer to write
01010             HardwareIndexBufferSharedPtr ibuf = indexData->indexBuffer;
01011             // bool indexes32bit
01012             bool idx32 = (ibuf->getType() == HardwareIndexBuffer::IT_32BIT);
01013             writeBools(&idx32, 1);
01014             if (idx32)
01015             {
01016                 unsigned int* pIdx = static_cast<unsigned int*>(
01017                     ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
01018                 writeInts(pIdx, indexData->indexCount);
01019                 ibuf->unlock();
01020             }
01021             else
01022             {
01023                 unsigned short* pIdx = static_cast<unsigned short*>(
01024                     ibuf->lock(HardwareBuffer::HBL_READ_ONLY));
01025                 writeShorts(pIdx, indexData->indexCount);
01026                 ibuf->unlock();
01027             }
01028         }
01029     
01030 
01031     }
01032     //---------------------------------------------------------------------
01033     void MeshSerializerImpl::writeBoundsInfo(const Mesh* pMesh)
01034     {
01035         // Usage Header
01036         unsigned long size = CHUNK_OVERHEAD_SIZE;
01037 
01038         size += sizeof(Real) * 7;
01039         writeChunkHeader(M_MESH_BOUNDS, size);
01040 
01041         // Real minx, miny, minz
01042         const Vector3& min = pMesh->mAABB.getMinimum();
01043         const Vector3& max = pMesh->mAABB.getMaximum();
01044         writeReals(&min.x, 1);
01045         writeReals(&min.y, 1);
01046         writeReals(&min.z, 1);
01047         // Real maxx, maxy, maxz
01048         writeReals(&max.x, 1);
01049         writeReals(&max.y, 1);
01050         writeReals(&max.z, 1);
01051         // Real radius
01052         writeReals(&pMesh->mBoundRadius, 1);
01053 
01054     }
01055     //---------------------------------------------------------------------
01056     void MeshSerializerImpl::readBoundsInfo(DataChunk& chunk)
01057     {
01058         Vector3 min, max;
01059         // Real minx, miny, minz
01060         readReals(chunk, &min.x, 1);
01061         readReals(chunk, &min.y, 1);
01062         readReals(chunk, &min.z, 1);
01063         // Real maxx, maxy, maxz
01064         readReals(chunk, &max.x, 1);
01065         readReals(chunk, &max.y, 1);
01066         readReals(chunk, &max.z, 1);
01067         AxisAlignedBox box(min, max);
01068         mpMesh->_setBounds(box);
01069         // Real radius
01070         Real radius;
01071         readReals(chunk, &radius, 1);
01072         mpMesh->_setBoundingSphereRadius(radius);
01073 
01074 
01075 
01076     }
01077     //---------------------------------------------------------------------
01078     void MeshSerializerImpl::readMeshLodInfo(DataChunk& chunk)
01079     {
01080         unsigned short chunkID, i;
01081 
01082         // unsigned short numLevels;
01083         readShorts(chunk, &(mpMesh->mNumLods), 1);
01084         // bool manual;  (true for manual alternate meshes, false for generated)
01085         readBools(chunk, &(mpMesh->mIsLodManual), 1);
01086 
01087         // Preallocate submesh lod face data if not manual
01088         if (!mpMesh->mIsLodManual)
01089         {
01090             unsigned short numsubs = mpMesh->getNumSubMeshes();
01091             for (i = 0; i < numsubs; ++i)
01092             {
01093                 SubMesh* sm = mpMesh->getSubMesh(i);
01094                 sm->mLodFaceList.resize(mpMesh->mNumLods-1);
01095             }
01096         }
01097 
01098         // Loop from 1 rather than 0 (full detail index is not in file)
01099         for (i = 1; i < mpMesh->mNumLods; ++i)
01100         {
01101             chunkID = readChunk(chunk);
01102             if (chunkID != M_MESH_LOD_USAGE)
01103             {
01104                 Except(Exception::ERR_ITEM_NOT_FOUND, 
01105                     "Missing M_MESH_LOD_USAGE chunk in " + mpMesh->getName(), 
01106                     "MeshSerializerImpl::readMeshLodInfo");
01107             }
01108             // Read depth
01109             Mesh::MeshLodUsage usage;
01110             readReals(chunk, &(usage.fromDepthSquared), 1);
01111 
01112             if (mpMesh->isLodManual())
01113             {
01114                 readMeshLodUsageManual(chunk, i, usage);
01115             }
01116             else //(!mpMesh->isLodManual)
01117             {
01118                 readMeshLodUsageGenerated(chunk, i, usage);
01119             }
01120 
01121             // Save usage
01122             mpMesh->mMeshLodUsageList.push_back(usage);
01123         }
01124 
01125 
01126     }
01127     //---------------------------------------------------------------------
01128     void MeshSerializerImpl::readMeshLodUsageManual(DataChunk& chunk, 
01129         unsigned short lodNum, Mesh::MeshLodUsage& usage)
01130     {
01131         unsigned long chunkID;
01132         // Read detail chunk
01133         chunkID = readChunk(chunk);
01134         if (chunkID != M_MESH_LOD_MANUAL)
01135         {
01136             Except(Exception::ERR_ITEM_NOT_FOUND, 
01137                 "Missing M_MESH_LOD_MANUAL chunk in " + mpMesh->getName(),
01138                 "MeshSerializerImpl::readMeshLodUsageManual");
01139         }
01140 
01141         usage.manualName = readString(chunk);
01142         usage.manualMesh = NULL; // will trigger load later
01143     }
01144     //---------------------------------------------------------------------
01145     void MeshSerializerImpl::readMeshLodUsageGenerated(DataChunk& chunk, 
01146         unsigned short lodNum, Mesh::MeshLodUsage& usage)
01147     {
01148         usage.manualName = "";
01149         usage.manualMesh = 0;
01150 
01151         // Get one set of detail per SubMesh
01152         unsigned short numSubs, i;
01153         unsigned long chunkID;
01154         numSubs = mpMesh->getNumSubMeshes();
01155         for (i = 0; i < numSubs; ++i)
01156         {
01157             chunkID = readChunk(chunk);
01158             if (chunkID != M_MESH_LOD_GENERATED)
01159             {
01160                 Except(Exception::ERR_ITEM_NOT_FOUND, 
01161                     "Missing M_MESH_LOD_GENERATED chunk in " + mpMesh->getName(),
01162                     "MeshSerializerImpl::readMeshLodUsageGenerated");
01163             }
01164 
01165             SubMesh* sm = mpMesh->getSubMesh(i);
01166             // lodNum - 1 because SubMesh doesn't store full detail LOD
01167             sm->mLodFaceList[lodNum - 1] = new IndexData();
01168             IndexData* indexData = sm->mLodFaceList[lodNum - 1];
01169             // unsigned int numIndexes
01170             unsigned int numIndexes;
01171             readInts(chunk, &numIndexes, 1);
01172             indexData->indexCount = static_cast<size_t>(numIndexes);
01173             // bool indexes32Bit
01174             bool idx32Bit;
01175             readBools(chunk, &idx32Bit, 1);
01176             // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
01177             if (idx32Bit)
01178             {
01179                 indexData->indexBuffer = HardwareBufferManager::getSingleton().
01180                     createIndexBuffer(HardwareIndexBuffer::IT_32BIT, indexData->indexCount,
01181                     mpMesh->mIndexBufferUsage, mpMesh->mIndexBufferShadowBuffer);
01182                 unsigned int* pIdx = static_cast<unsigned int*>(
01183                     indexData->indexBuffer->lock(
01184                         0, 
01185                         indexData->indexBuffer->getSizeInBytes(), 
01186                         HardwareBuffer::HBL_DISCARD) );
01187 
01188                 readInts(chunk, pIdx, indexData->indexCount);
01189                 indexData->indexBuffer->unlock();
01190 
01191             }
01192             else
01193             {
01194                 indexData->indexBuffer = HardwareBufferManager::getSingleton().
01195                     createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
01196                     mpMesh->mIndexBufferUsage, mpMesh->mIndexBufferShadowBuffer);
01197                 unsigned short* pIdx = static_cast<unsigned short*>(
01198                     indexData->indexBuffer->lock(
01199                         0, 
01200                         indexData->indexBuffer->getSizeInBytes(), 
01201                         HardwareBuffer::HBL_DISCARD) );
01202                 readShorts(chunk, pIdx, indexData->indexCount);
01203                 indexData->indexBuffer->unlock();
01204 
01205             }
01206 
01207         }
01208     }
01209     //---------------------------------------------------------------------
01210     //---------------------------------------------------------------------
01211     //---------------------------------------------------------------------
01212     MeshSerializerImpl_v1_1::MeshSerializerImpl_v1_1()
01213     {
01214         // Version number
01215         mVersion = "[MeshSerializer_v1.10]";
01216     }
01217     //---------------------------------------------------------------------
01218     MeshSerializerImpl_v1_1::~MeshSerializerImpl_v1_1()
01219     {
01220     }
01221     //---------------------------------------------------------------------
01222     void MeshSerializerImpl_v1_1::readGeometryTexCoords(unsigned short bindIdx, 
01223         DataChunk& chunk, VertexData* dest, unsigned short texCoordSet)
01224     {
01225         Real *pReal = 0;
01226         HardwareVertexBufferSharedPtr vbuf;
01227         // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
01228         unsigned short dim;
01229         readShorts(chunk, &dim, 1);
01230         // Real* pTexCoords  (u [v] [w] order, dimensions x numVertices)
01231         dest->vertexDeclaration->addElement(
01232             bindIdx, 
01233             0, 
01234             VertexElement::multiplyTypeCount(VET_FLOAT1, dim), 
01235             VES_TEXTURE_COORDINATES,
01236             texCoordSet);
01237         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
01238             dest->vertexDeclaration->getVertexSize(bindIdx),
01239             dest->vertexCount,
01240             mpMesh->getVertexBufferUsage(),
01241             mpMesh->isVertexBufferShadowed());
01242         pReal = static_cast<Real*>(
01243             vbuf->lock(HardwareBuffer::HBL_DISCARD));
01244         readReals(chunk, pReal, dest->vertexCount * dim);
01245 
01246         // Adjust individual v values to (1 - v)
01247         if (dim == 2)
01248         {
01249             for (size_t i = 0; i < dest->vertexCount; ++i)
01250             {
01251                 ++pReal; // skip u
01252                 *pReal = 1.0 - *pReal; // v = 1 - v
01253                 ++pReal;
01254             }
01255             
01256         }
01257         vbuf->unlock();
01258         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
01259     }
01260     //---------------------------------------------------------------------
01261     //---------------------------------------------------------------------
01262     //---------------------------------------------------------------------
01263     MeshSerializerImpl_v1::MeshSerializerImpl_v1()
01264     {
01265         // Version number
01266         mVersion = "[MeshSerializer_v1.00]";
01267 
01268     }
01269     //---------------------------------------------------------------------
01270     void MeshSerializerImpl_v1::readMesh(DataChunk& chunk)
01271     {
01272         unsigned short chunkID;
01273 
01274         mFirstGeometry = true;
01275         mIsSkeletallyAnimated = false;
01276 
01277         // M_GEOMETRY chunk
01278         chunkID = readChunk(chunk);
01279         if (chunkID == M_GEOMETRY)
01280         {
01281             mpMesh->sharedVertexData = new VertexData();
01282             try {
01283                 readGeometry(chunk, mpMesh->sharedVertexData);
01284             }
01285             catch (Exception& e)
01286             {
01287                 if (e.getNumber() == Exception::ERR_ITEM_NOT_FOUND)
01288                 {
01289                     // duff geometry data entry with 0 vertices
01290                     delete mpMesh->sharedVertexData;
01291                     mpMesh->sharedVertexData = 0;
01292                     // Skip this chunk (pointer will have been returned to just after header)
01293                     chunk.skip(mCurrentChunkLen - CHUNK_OVERHEAD_SIZE);
01294                 }
01295                 else
01296                 {
01297                     throw;
01298                 }
01299             }
01300         }
01301 
01302         // Find all subchunks 
01303         if (!chunk.isEOF())
01304         {
01305             chunkID = readChunk(chunk);
01306             while(!chunk.isEOF() &&
01307                 (chunkID == M_SUBMESH ||
01308                  chunkID == M_MESH_SKELETON_LINK ||
01309                  chunkID == M_MESH_BONE_ASSIGNMENT ||
01310                  chunkID == M_MESH_LOD))
01311             {
01312                 switch(chunkID)
01313                 {
01314                 case M_SUBMESH:
01315                     readSubMesh(chunk);
01316                     break;
01317                 case M_MESH_SKELETON_LINK:
01318                     readSkeletonLink(chunk);
01319                     break;
01320                 case M_MESH_BONE_ASSIGNMENT:
01321                     readMeshBoneAssignment(chunk);
01322                     break;
01323                 case M_MESH_LOD:
01324                     readMeshLodInfo(chunk);
01325                     break;
01326                 }
01327 
01328                 if (!chunk.isEOF())
01329                 {
01330                     chunkID = readChunk(chunk);
01331                 }
01332 
01333             }
01334             if (!chunk.isEOF())
01335             {
01336                 // Backpedal back to start of chunk
01337                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
01338             }
01339         }
01340 
01341     }
01342     //---------------------------------------------------------------------
01343     void MeshSerializerImpl_v1::readSubMesh(DataChunk& chunk)
01344     {
01345         unsigned short chunkID;
01346 
01347         SubMesh* sm = mpMesh->createSubMesh();
01348         // char* materialName
01349         String materialName = readString(chunk);
01350         sm->setMaterialName(materialName);
01351 
01352         // bool useSharedVertices
01353         readBools(chunk,&sm->useSharedVertices, 1);
01354 
01355         // unsigned short faceCount
01356         sm->indexData->indexStart = 0;
01357         unsigned short faceCount;
01358         readShorts(chunk, &faceCount, 1);
01359         sm->indexData->indexCount = faceCount * 3;
01360 
01361         // Indexes always 16-bit in this version
01362         HardwareIndexBufferSharedPtr ibuf;
01363         ibuf = HardwareBufferManager::getSingleton().
01364             createIndexBuffer(
01365                 HardwareIndexBuffer::IT_16BIT, 
01366                 sm->indexData->indexCount, 
01367                 mpMesh->mIndexBufferUsage,
01368                 mpMesh->mIndexBufferShadowBuffer);
01369         sm->indexData->indexBuffer = ibuf;
01370         // unsigned short* faceVertexIndices 
01371         unsigned short* pIdx = static_cast<unsigned short*>(
01372             ibuf->lock(HardwareBuffer::HBL_DISCARD)
01373             );
01374         readShorts(chunk, pIdx, sm->indexData->indexCount);
01375         ibuf->unlock();
01376 
01377         // M_GEOMETRY chunk (Optional: present only if useSharedVertices = false)
01378         if (!sm->useSharedVertices)
01379         {
01380             chunkID = readChunk(chunk);
01381             if (chunkID != M_GEOMETRY)
01382             {
01383                 Except(Exception::ERR_INTERNAL_ERROR, "Missing geometry data in mesh file", 
01384                     "MeshSerializerImpl::readSubMesh");
01385             }
01386             sm->vertexData = new VertexData();
01387             readGeometry(chunk, sm->vertexData);
01388         }
01389 
01390 
01391         // Find all bone assignments (if present) 
01392         if (!chunk.isEOF())
01393         {
01394             chunkID = readChunk(chunk);
01395             while(!chunk.isEOF() &&
01396                 (chunkID == M_SUBMESH_BONE_ASSIGNMENT))
01397             {
01398                 switch(chunkID)
01399                 {
01400                 case M_SUBMESH_BONE_ASSIGNMENT:
01401                     readSubMeshBoneAssignment(chunk, sm);
01402                     break;
01403                 }
01404 
01405                 if (!chunk.isEOF())
01406                 {
01407                     chunkID = readChunk(chunk);
01408                 }
01409 
01410             }
01411             if (!chunk.isEOF())
01412             {
01413                 // Backpedal back to start of chunk
01414                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
01415             }
01416         }
01417     }
01418     //---------------------------------------------------------------------
01419     void MeshSerializerImpl_v1::readGeometry(DataChunk& chunk, VertexData* dest)
01420     {
01421         unsigned short texCoordSet = 0;
01422         HardwareVertexBufferSharedPtr vbuf;
01423         unsigned short bindIdx = 0;
01424         Real *pReal = 0;
01425         RGBA* pRGBA = 0;
01426 
01427         dest->vertexStart = 0;
01428         if (mIsSkeletallyAnimated)
01429         {
01430             // Create software blending structure
01431             dest->softwareBlendInfo = new VertexData::SoftwareBlendInfo();
01432             // Automatic blending on
01433             dest->softwareBlendInfo->automaticBlend = true;
01434         }
01435 
01436         // unsigned short numVertices
01437         unsigned short numVerts;
01438         readShorts(chunk, &numVerts, 1);
01439         dest->vertexCount = numVerts;
01440 
01441         if (dest->vertexCount == 0)
01442         {
01443             // Empty positions
01444             // skip back to where we were
01445             chunk.skip(0 - sizeof(unsigned short));
01446             Except(Exception::ERR_ITEM_NOT_FOUND, "Geometry section found but no "
01447                 "positions defined - you should upgrade this .mesh to the latest version "
01448                 "to eliminate this problem.", "MeshSerializerImpl::readGeometry");
01449         }
01450 
01451         // Vertex buffers
01452         // TODO: consider redesigning this so vertex buffers can be combined
01453 
01454         // Real* pVertices (x, y, z order x numVertices)
01455         dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_POSITION);
01456         vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
01457             dest->vertexDeclaration->getVertexSize(bindIdx),
01458             dest->vertexCount,
01459             mpMesh->mVertexBufferUsage,
01460             mpMesh->mVertexBufferShadowBuffer);
01461         pReal = static_cast<Real*>(
01462             vbuf->lock(HardwareBuffer::HBL_DISCARD));
01463         if (mIsSkeletallyAnimated)
01464         {
01465             // Copy data into software buffers for source of blending
01466             dest->softwareBlendInfo->pSrcPositions = new Real[dest->vertexCount * 3];
01467             readReals(chunk, dest->softwareBlendInfo->pSrcPositions, dest->vertexCount * 3);
01468             // Copy into hardware buffer
01469             memcpy(pReal, dest->softwareBlendInfo->pSrcPositions, 
01470                 sizeof(Real) * dest->vertexCount * 3);
01471         }
01472         else
01473         {
01474             // Read direct into hardware buffers
01475             readReals(chunk, pReal, dest->vertexCount * 3);
01476         }
01477 
01478         // Since in v1 we did not save mesh bounds, we need to calculate them now
01479         AxisAlignedBox localBox;
01480         Vector3 min, max;
01481         bool first = true;
01482         Real maxSquaredRadius = -1;
01483 
01484         for (size_t vert = 0; vert < dest->vertexCount; ++vert)
01485         {
01486             Vector3 vec(pReal[0], pReal[1], pReal[2]);
01487 
01488             // Update sphere bounds
01489             maxSquaredRadius = std::max(vec.squaredLength(), maxSquaredRadius);
01490 
01491             // Update box
01492             if (first)
01493             {
01494                 min = vec;
01495                 max = vec;
01496                 first = false;
01497             }
01498             else
01499             {
01500                 min.makeFloor(vec);
01501                 max.makeCeil(vec);
01502             }
01503 
01504             pReal += 3;
01505         }
01506         localBox.setExtents(min, max);
01507         
01508         if (mFirstGeometry)
01509         {
01510             mpMesh->_setBounds(localBox);
01511             mpMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
01512             mFirstGeometry = false;
01513         }
01514         else
01515         {
01516             localBox.merge(mpMesh->mAABB);
01517             mpMesh->_setBounds(localBox);
01518             maxSquaredRadius = std::max(maxSquaredRadius, mpMesh->mBoundRadius);
01519             mpMesh->_setBoundingSphereRadius(Math::Sqrt(maxSquaredRadius));
01520         }
01521 
01522         vbuf->unlock();
01523         dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
01524         ++bindIdx;
01525 
01526         // Find optional geometry chunks
01527         if (!chunk.isEOF())
01528         {
01529             unsigned short chunkID = readChunk(chunk);
01530             while(!chunk.isEOF() && 
01531                 (chunkID == M_GEOMETRY_NORMALS || 
01532                  chunkID == M_GEOMETRY_COLOURS ||
01533                  chunkID == M_GEOMETRY_TEXCOORDS ))
01534             {
01535                 switch (chunkID)
01536                 {
01537                 case M_GEOMETRY_NORMALS:
01538                     // Real* pNormals (x, y, z order x numVertices)
01539                     dest->vertexDeclaration->addElement(bindIdx, 0, VET_FLOAT3, VES_NORMAL);
01540                     vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
01541                         dest->vertexDeclaration->getVertexSize(bindIdx),
01542                         dest->vertexCount,
01543                         mpMesh->mVertexBufferUsage,
01544                         mpMesh->mVertexBufferShadowBuffer);
01545                     pReal = static_cast<Real*>(
01546                         vbuf->lock(HardwareBuffer::HBL_DISCARD));
01547                     if (mIsSkeletallyAnimated)
01548                     {
01549                         // Copy data into software buffers for source of blending
01550                         dest->softwareBlendInfo->pSrcNormals = new Real[dest->vertexCount * 3];
01551                         readReals(chunk, dest->softwareBlendInfo->pSrcNormals, dest->vertexCount * 3);
01552                         // Copy into hardware buffer
01553                         memcpy(pReal, dest->softwareBlendInfo->pSrcNormals, 
01554                             sizeof(Real) * dest->vertexCount * 3);
01555                     }
01556                     else
01557                     {
01558                         // Copy direct into hardware buffers
01559                         readReals(chunk, pReal, dest->vertexCount * 3);
01560                     }
01561                     vbuf->unlock();
01562                     dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
01563                     ++bindIdx;
01564                     break;
01565                 case M_GEOMETRY_COLOURS:
01566                     // unsigned long* pColours (RGBA 8888 format x numVertices)
01567                     dest->vertexDeclaration->addElement(bindIdx, 0, VET_COLOUR, VES_DIFFUSE);
01568                     vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
01569                         dest->vertexDeclaration->getVertexSize(bindIdx),
01570                         dest->vertexCount,
01571                         mpMesh->mVertexBufferUsage,
01572                         mpMesh->mVertexBufferShadowBuffer);
01573                     pRGBA = static_cast<RGBA*>(
01574                         vbuf->lock(HardwareBuffer::HBL_DISCARD));
01575                     readLongs(chunk, pRGBA, dest->vertexCount);
01576                     vbuf->unlock();
01577                     dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
01578                     ++bindIdx;
01579                     break;
01580                 case M_GEOMETRY_TEXCOORDS:
01581                     // unsigned short dimensions    (1 for 1D, 2 for 2D, 3 for 3D)
01582                     unsigned short dim;
01583                     readShorts(chunk, &dim, 1);
01584                     // Real* pTexCoords  (u [v] [w] order, dimensions x numVertices)
01585                     dest->vertexDeclaration->addElement(
01586                         bindIdx, 
01587                         0, 
01588                         VertexElement::multiplyTypeCount(VET_FLOAT1, dim), 
01589                         VES_TEXTURE_COORDINATES,
01590                         texCoordSet);
01591                     vbuf = HardwareBufferManager::getSingleton().createVertexBuffer(
01592                         dest->vertexDeclaration->getVertexSize(bindIdx),
01593                         dest->vertexCount,
01594                         mpMesh->mVertexBufferUsage,
01595                         mpMesh->mVertexBufferShadowBuffer);
01596                     pReal = static_cast<Real*>(
01597                         vbuf->lock(HardwareBuffer::HBL_DISCARD));
01598                     readReals(chunk, pReal, dest->vertexCount * dim);
01599 
01600                     // Adjust individual v values to (1 - v)
01601                     if (dim == 2)
01602                     {
01603                         for (size_t i = 0; i < dest->vertexCount; ++i)
01604                         {
01605                             ++pReal; // skip u
01606                             *pReal = 1.0 - *pReal; // v = 1 - v
01607                             ++pReal;
01608                         }
01609                         
01610                     }
01611 
01612                     vbuf->unlock();
01613                     dest->vertexBufferBinding->setBinding(bindIdx, vbuf);
01614                     ++texCoordSet;
01615                     ++bindIdx;
01616                     break;
01617                 }
01618                 // Get next chunk
01619                 if (!chunk.isEOF())
01620                 {
01621                     chunkID = readChunk(chunk);
01622                 }
01623             }
01624             if (!chunk.isEOF())
01625             {
01626                 // Backpedal back to start of non-submesh chunk
01627                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
01628             }
01629         }
01630     }
01631     //---------------------------------------------------------------------
01632     void MeshSerializerImpl_v1::readMeshBoneAssignment(DataChunk& chunk)
01633     {
01634         VertexBoneAssignment assign;
01635 
01636         // unsigned short vertexIndex;
01637         unsigned short vIndex;
01638         readShorts(chunk, &vIndex,1);
01639         assign.vertexIndex = vIndex;
01640         // unsigned short boneIndex;
01641         readShorts(chunk, &(assign.boneIndex),1);
01642         // Real weight;
01643         readReals(chunk, &(assign.weight), 1);
01644 
01645         mpMesh->addBoneAssignment(assign);
01646 
01647     }
01648     //---------------------------------------------------------------------
01649     void MeshSerializerImpl_v1::readSubMeshBoneAssignment(DataChunk& chunk, SubMesh* sub)
01650     {
01651         VertexBoneAssignment assign;
01652 
01653         // unsigned short vertexIndex;
01654         unsigned short vIndex;
01655         readShorts(chunk, &vIndex,1);
01656         assign.vertexIndex = vIndex;
01657         // unsigned short boneIndex;
01658         readShorts(chunk, &(assign.boneIndex),1);
01659         // Real weight;
01660         readReals(chunk, &(assign.weight), 1);
01661 
01662         sub->addBoneAssignment(assign);
01663     }
01664     //---------------------------------------------------------------------
01665     void MeshSerializerImpl_v1::readMeshLodUsageGenerated(DataChunk& chunk, unsigned short lodNum, Mesh::MeshLodUsage& usage)
01666     {
01667         usage.manualName = "";
01668         usage.manualMesh = 0;
01669 
01670         // Get one set of detail per SubMesh
01671         unsigned short numSubs, i;
01672         unsigned long chunkID;
01673         numSubs = mpMesh->getNumSubMeshes();
01674         for (i = 0; i < numSubs; ++i)
01675         {
01676             chunkID = readChunk(chunk);
01677             if (chunkID != M_MESH_LOD_GENERATED)
01678             {
01679                 Except(Exception::ERR_ITEM_NOT_FOUND, 
01680                     "Missing M_MESH_LOD_GENERATED chunk in " + mpMesh->getName(),
01681                     "MeshSerializerImpl::readMeshLodUsageGenerated");
01682             }
01683 
01684             SubMesh* sm = mpMesh->getSubMesh(i);
01685             // lodNum - 1 because SubMesh doesn't store full detail LOD
01686             sm->mLodFaceList[lodNum - 1] = new IndexData();
01687             IndexData* indexData = sm->mLodFaceList[lodNum - 1];
01688             // unsigned short numFaces
01689             unsigned short numFaces;
01690             readShorts(chunk, &numFaces, 1);
01691             indexData->indexCount = static_cast<size_t>(numFaces * 3);
01692             // unsigned short*/int* faceIndexes;  ((v1, v2, v3) * numFaces)
01693             // Always 16-bit in 1.0
01694             indexData->indexBuffer = HardwareBufferManager::getSingleton().
01695                 createIndexBuffer(HardwareIndexBuffer::IT_16BIT, indexData->indexCount,
01696                 mpMesh->mIndexBufferUsage, mpMesh->mIndexBufferShadowBuffer);
01697             unsigned short* pIdx = static_cast<unsigned short*>(
01698                 indexData->indexBuffer->lock(
01699                     0, 
01700                     indexData->indexBuffer->getSizeInBytes(), 
01701                     HardwareBuffer::HBL_DISCARD) );
01702             readShorts(chunk, pIdx, indexData->indexCount);
01703             indexData->indexBuffer->unlock();
01704 
01705         }
01706     }
01707     //---------------------------------------------------------------------
01708     void MeshSerializerImpl_v1::readMaterial(DataChunk& chunk)
01709     {
01710         ColourValue col;
01711         Real rVal;
01712 
01713         // Material definition section phased out of 1.1
01714         LogManager::getSingleton().logMessage(
01715             "Warning: Material definitions are no longer supported in .mesh files, "
01716             "you should move these definitions to a material script when you "
01717             "upgrade this mesh to the latest version. ");
01718 
01719         // char* name 
01720         String name = readString(chunk);
01721 
01722         // Create a new material
01723         Material* pMat;
01724         try 
01725         {
01726             pMat = (Material*)MaterialManager::getSingleton().create(name);
01727             Pass* p = pMat->createTechnique()->createPass();
01728         }
01729         catch (Exception& e)
01730         {
01731             if(e.getNumber() == Exception::ERR_DUPLICATE_ITEM)
01732             {
01733                 // Material already exists
01734                 char msg[256];
01735                 sprintf(msg, "Material '%s' in model '%s' has been ignored "
01736                     "because a material with the same name has already "
01737                     "been registered.", name.c_str(),
01738                     mpMesh->getName().c_str());
01739                 LogManager::getSingleton().logMessage(msg);
01740                 // Skip the rest of this material
01741                 chunk.skip(mCurrentChunkLen - name.length() - 1 - CHUNK_OVERHEAD_SIZE);
01742                 return;
01743 
01744             }
01745             else
01746             {
01747                 throw;
01748             }
01749         }
01750 
01751         // AMBIENT
01752         // Real r, g, b
01753         readReals(chunk, &col.r, 1);
01754         readReals(chunk, &col.g, 1);
01755         readReals(chunk, &col.b, 1);
01756         pMat->setAmbient(col);
01757 
01758         // DIFFUSE
01759         // Real r, g, b
01760         readReals(chunk, &col.r, 1);
01761         readReals(chunk, &col.g, 1);
01762         readReals(chunk, &col.b, 1);
01763         pMat->setDiffuse(col);
01764 
01765         // SPECULAR
01766         // Real r, g, b
01767         readReals(chunk, &col.r, 1);
01768         readReals(chunk, &col.g, 1);
01769         readReals(chunk, &col.b, 1);
01770         pMat->setSpecular(col);
01771 
01772         // SHININESS
01773         // Real val;
01774         readReals(chunk, &rVal, 1);
01775         pMat->setShininess(rVal);
01776 
01777         // Read any texture layers
01778         if (!chunk.isEOF())
01779         {
01780             unsigned short chunkID = readChunk(chunk);
01781             while(chunkID == M_TEXTURE_LAYER && !chunk.isEOF())
01782             {
01783                 readTextureLayer(chunk, pMat);
01784                 if (!chunk.isEOF())
01785                 {
01786                     chunkID = readChunk(chunk);
01787                 }
01788             }
01789             // Get next chunk
01790             if (!chunk.isEOF())
01791             {
01792                 // Backpedal back to start of non-texture layer chunk
01793                 chunk.skip(-(long)CHUNK_OVERHEAD_SIZE);
01794             }
01795         }
01796 
01797     }
01798     //---------------------------------------------------------------------
01799     void MeshSerializerImpl_v1::readTextureLayer(DataChunk& chunk, Material* pMat)
01800     {
01801         // Just name for now
01802         String name = readString(chunk);
01803 
01804         pMat->getTechnique(0)->getPass(0)->createTextureUnitState(name);
01805     }
01806 
01807 
01808 
01809 
01810 }
01811 

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