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