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