/* ========================================================================== * (C) 2005 Universitat Jaume I * ========================================================================== * PROYECT: GAME TOOLS * ==========================================================================*/ /** CONTENT: * * * @file GeoMeshSaver.cpp /*===========================================================================*/ #include using namespace Geometry; using namespace std; //------------------------------------------ // Public: //------------------------------------------ //////////////////// // Constructors. // //////////////////// GeoMeshSaver::GeoMeshSaver() { mMaterialName = ""; mSkeletallyAnimated = false; // Initializa the mesh bounds. mMeshBounds.minx = 0.0; mMeshBounds.miny = 0.0; mMeshBounds.minz = 0.0; mMeshBounds.maxx = 0.0; mMeshBounds.maxy = 0.0; mMeshBounds.maxz = 0.0; mMeshBounds.radius = 0.0; } GeoMeshSaver::GeoMeshSaver(GeometryBounds bounds) { mMaterialName = ""; mSkeletallyAnimated = false; // Initializa the mesh bounds. mMeshBounds.minx = bounds.minx; mMeshBounds.miny = bounds.miny; mMeshBounds.minz = bounds.minz; mMeshBounds.maxx = bounds.maxx; mMeshBounds.maxy = bounds.maxy; mMeshBounds.maxz = bounds.maxz; mMeshBounds.radius = bounds.radius; } ////////////////// // Destroyer. // ////////////////// GeoMeshSaver::~GeoMeshSaver() { } // Saves a Mesh into a file. int GeoMeshSaver::save(Mesh *geoMesh, const char *fileNameMesh) { int size; String name(fileNameMesh); // Open the file. mSerializer = new Serializer( name, Serializer::WRITE); // Set the mesh. mGeoMesh = geoMesh; // Write the file header. writeFileHeader(); // Write the mesh data. writeMesh(geoMesh); // Debug. cout << "Write mesh finish" << endl; size = mSerializer->GetSize(); // Close the file. delete mSerializer; // Return the number of bytes written. return size; } //------------------------------------------ // Private: //------------------------------------------ // Write the main mesh. void GeoMeshSaver::writeMesh(Mesh *geoMesh) { // Debug. cout << "Write the chunk header" << endl; // Header writeChunkHeader(M_MESH, calcMeshSize(geoMesh)); // Write the skeletally animated flag. writeBools(mSkeletallyAnimated,1); cout << "1 - VertexCount: " << geoMesh->mVertexBuffer->mVertexCount << endl; // Write shared geometry. if (geoMesh->mVertexBuffer->mVertexCount > 0) { // Debug. cout << "Write the shared vertex buffer" << endl; writeGeometry(geoMesh->mVertexBuffer); } // Write submeshes. for (int i = 0; i < geoMesh->mSubMeshCount; i++) { // Debug. cout << "Write the submesh " << i << endl; writeSubMesh(&geoMesh->mSubMesh[i]); } // Write the mesh bounds. writeMeshBounds(mMeshBounds); /* // Write skeleton info if required if (pMesh->hasSkeleton()) { LogManager::getSingleton().logMessage("Exporting skeleton link..."); // Write skeleton link writeSkeletonLink(pMesh->getSkeletonName()); LogManager::getSingleton().logMessage("Skeleton link exported."); // Write bone assignments if (!pMesh->mBoneAssignments.empty()) { LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments..."); Mesh::VertexBoneAssignmentList::const_iterator vi; for (vi = pMesh->mBoneAssignments.begin(); vi != pMesh->mBoneAssignments.end(); ++vi) { writeMeshBoneAssignment(vi->second); } LogManager::getSingleton().logMessage("Shared geometry bone assignments exported."); } } // Write LOD data if any if (pMesh->getNumLodLevels() > 1) { LogManager::getSingleton().logMessage("Exporting LOD information...."); writeLodInfo(pMesh); LogManager::getSingleton().logMessage("LOD information exported."); } // Write bounds information LogManager::getSingleton().logMessage("Exporting bounds information...."); writeBoundsInfo(pMesh); LogManager::getSingleton().logMessage("Bounds information exported."); // Write submesh name table LogManager::getSingleton().logMessage("Exporting submesh name table..."); writeSubMeshNameTable(pMesh); LogManager::getSingleton().logMessage("Submesh name table exported."); // Write edge lists if (pMesh->isEdgeListBuilt()) { LogManager::getSingleton().logMessage("Exporting edge lists..."); writeEdgeList(pMesh); LogManager::getSingleton().logMessage("Edge lists exported"); } */ } // Write a submesh. void GeoMeshSaver::writeSubMesh(SubMesh *geoSubMesh) { bool idx32bit; unsigned long indexCount; String materialName; Index *index; Index *indexBegin; Index *indexEnd; // Debug. cout << "Write the submesh chunk header" << endl; // Header. writeChunkHeader(M_SUBMESH, calcSubMeshSize(geoSubMesh)); // Debug. cout << "Write the material name" << endl; // Material Name. materialName = getMaterialName(); writeString(materialName); // Debug. cout << "Write the shared vertex buffer flag: " << endl; // bool useSharedVertices writeBools(geoSubMesh->mSharedVertexBuffer, 1); indexCount = geoSubMesh->mIndexCount; // If the submesh is in triangle strips. if (geoSubMesh->mType == GEO_TRIANGLE_STRIPS) { indexCount += 2 * geoSubMesh->mStripCount - 2; } writeInts(indexCount, 1); // bool indexes32Bit idx32bit = true; writeBools(idx32bit, 1); // Debug. cout << "Write the mIndex array" << endl; // If the submesh is in triangle strips. if (geoSubMesh->mType == GEO_TRIANGLE_STRIPS) { // Debug. cout << "Write triangle strips" << endl; // For each one of the strips. for (int strip = 0; strip < geoSubMesh->mStripCount; strip++) { // First index of the strip. indexBegin = geoSubMesh->mStrip[strip]; // If is the final strip if (strip == (geoSubMesh->mStripCount - 1)) { // The end of the index array. indexEnd = &geoSubMesh->mIndex[geoSubMesh->mIndexCount]; } else { // The beginning of the next strip. indexEnd = geoSubMesh->mStrip[strip + 1]; } int i; i = 0; if (strip != 0) { writeInts(indexBegin[i], 1); } // For each index of the strip. for (index = indexBegin; index < indexEnd; index++) { writeInts(indexBegin[i], 1); // Increments i. i++; } if (strip != (geoSubMesh->mStripCount - 1)) { writeInts(indexBegin[i - 1], 1); } } } // If the submesh is in triangle list. else { // Write the index array. for (int i = 0; i < geoSubMesh->mIndexCount; i++) { writeInts(geoSubMesh->mIndex[i], 1); } } // M_GEOMETRY stream (Optional: present only if useSharedVertices = false) if (!geoSubMesh->mSharedVertexBuffer) { // Debug. cout << "Write the geometry of the submesh" << endl; writeGeometry(geoSubMesh->mVertexBuffer); } // Debug. cout << "mIndex array written" << endl; // Operation type writeSubMeshOperation(geoSubMesh); //TODO:Bones. /* // Bone assignments if (!s->mBoneAssignments.empty()) { LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments..."); SubMesh::VertexBoneAssignmentList::const_iterator vi; for (vi = s->mBoneAssignments.begin(); vi != s->mBoneAssignments.end(); ++vi) { writeSubMeshBoneAssignment(vi->second); } LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported."); } */ } // Write the submesh operation chunk and data. void GeoMeshSaver::writeSubMeshOperation(const SubMesh *geoSubMesh) { unsigned short opType; unsigned long size; // Debug. cout << "Write submesh operation" << endl; size = CHUNK_OVERHEAD_SIZE + sizeof(unsigned short); // Header writeChunkHeader(M_SUBMESH_OPERATION, size); // If the mesh is in triangle strips. if (geoSubMesh->mType == GEO_TRIANGLE_STRIPS) { opType = 5; } // If the mesh is in triangle list. else { opType = 4; } writeShorts(opType, 1); // Debug. cout << "Submesh operation Written" << endl; } // Write geometry. void GeoMeshSaver::writeGeometry(VertexBuffer *vertexBuffer) { unsigned short element; unsigned long size; unsigned short buffer_count; buffer_count = 3; // Calc the size in bytes of the geometry chunk. size = calcGeometrySize(vertexBuffer); // Header. // // Write the M_GEOMETRY header. writeChunkHeader(M_GEOMETRY, size); writeInts(vertexBuffer->mVertexCount,1); // Vertex declaration. // Calculate the size of vertex declaration. size = CHUNK_OVERHEAD_SIZE + buffer_count * (CHUNK_OVERHEAD_SIZE + (sizeof(unsigned short) * 5)); // Write the vertex declaration header. writeChunkHeader( M_GEOMETRY_VERTEX_DECLARATION,size); // Obtain the size of the vertex element chunk. size = CHUNK_OVERHEAD_SIZE + (sizeof(unsigned short) * 5); // Positions. // Write the vertex element header for position. writeChunkHeader( M_GEOMETRY_VERTEX_ELEMENT,size); element = 0; writeShorts(element,1); element = VET_FLOAT3; writeShorts(element,1); element = VES_POSITION; writeShorts(element,1); element = 0; writeShorts(element,1); element = 0; writeShorts(element,1); // Normals. // Write the vertex element header for position. writeChunkHeader( M_GEOMETRY_VERTEX_ELEMENT,size); element = 1; writeShorts(element,1); element = VET_FLOAT3; writeShorts(element,1); element = VES_NORMAL; writeShorts(element,1); element = 0; writeShorts(element,1); element = 0; writeShorts(element,1); // Textures. // Write the vertex element header for position. writeChunkHeader(M_GEOMETRY_VERTEX_ELEMENT,size); element = 2; writeShorts(element,1); element = VET_FLOAT2; writeShorts(element,1); element = VES_TEXTURE_COORDINATES; writeShorts(element,1); element = 0; writeShorts(element,1); element = 0; writeShorts(element,1); // Obtain the size for vertex buffer header for positons. size = (2 * CHUNK_OVERHEAD_SIZE) + (2 * sizeof(unsigned short)); // Write the vertex buffer header for positions. writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER, size); element = 0; writeShorts(element,1); element = 12; writeShorts(element,1); // Obtain the size for the vertex buffer data header for positions. size = CHUNK_OVERHEAD_SIZE + ((sizeof(float) * 3) * vertexBuffer->mVertexCount); // Write the vertex buffer data header for positions. writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size); // Write all the positions coords. mSerializer->WriteArray(vertexBuffer->mPosition, vertexBuffer->mVertexCount); // Obtain the size for vertex buffer header for normals. size = (2 * CHUNK_OVERHEAD_SIZE) + (2 * sizeof(unsigned short)); // Write the vertex buffer header. writeChunkHeader( M_GEOMETRY_VERTEX_BUFFER, size); element = 1; writeShorts(element,1); element = 12; writeShorts(element,1); // Obtain the size for the vertex buffer data header for normals. size = CHUNK_OVERHEAD_SIZE + ((sizeof(float) * 3) * vertexBuffer->mVertexCount); // Write the vertex buffer data header for normals. writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size); // Write all the normals coords. mSerializer->WriteArray(vertexBuffer->mNormal, vertexBuffer->mVertexCount); // Obtain the size for vertex buffer header for textures. size = (2 * CHUNK_OVERHEAD_SIZE) + (2 * sizeof(unsigned short)); // Write the vertex buffer header for textures. writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER, size); element = 2; writeShorts(element,1); element = 8; writeShorts(element,1); // Obtain the size for the vertex buffer data header for textures. size = CHUNK_OVERHEAD_SIZE + ((sizeof(float) * 2) * vertexBuffer->mVertexCount); // Write the vertex buffer data header for textures. writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA, size); // Debug. cout << "-7-" << endl; // Write all the texture coords. mSerializer->WriteArray(vertexBuffer->mTexCoords, vertexBuffer->mVertexCount); // Debug. cout << "-8-" << endl; } // TODO: Write Mesh Bounds. void GeoMeshSaver::writeMeshBounds(GeometryBounds bounds) { size_t size; size = CHUNK_OVERHEAD_SIZE + (sizeof(float) * 7); writeChunkHeader(M_MESH_BOUNDS, size); writeFloats(bounds.minx,1); writeFloats(bounds.miny,1); writeFloats(bounds.minz,1); writeFloats(bounds.maxx,1); writeFloats(bounds.maxy,1); writeFloats(bounds.maxz,1); writeFloats(bounds.radius,1); } // Calc the mesh size in bytes. size_t GeoMeshSaver::calcMeshSize(const Mesh *geoMesh) { size_t size = CHUNK_OVERHEAD_SIZE; // Debug. cout << "Calc the size of the mesh" << endl; // Num shared vertices size += sizeof(uint32); // Debug. cout << "VertexCount: " << geoMesh->mVertexBuffer->mVertexCount << endl; // Geometry if (geoMesh->mVertexBuffer->mVertexCount > 0) { // Debug. cout << "Calc the size of the shared vertex buffer" << endl; size += calcGeometrySize(geoMesh->mVertexBuffer); } // Submeshes for (unsigned short i = 0; i < geoMesh->mSubMeshCount; ++i) { // Debug. cout << "Calc the size of the submesh " << i << endl; size += calcSubMeshSize(&geoMesh->mSubMesh[i]); } // Mesh Bounds size added. size += CHUNK_OVERHEAD_SIZE + (sizeof(float) * 7); /* // Skeleton link if (geoMesh->hasSkeleton()) { size += calcSkeletonLinkSize(geoMesh->getSkeletonName()); } */ /* // Submesh name table size += calcSubMeshNameTableSize(geoMesh); // Edge list if (geoMesh->isEdgeListBuilt()) { size += calcEdgeListSize(geoMesh); } */ return size; } // Calc the size in bytes for the submesh. size_t GeoMeshSaver::calcSubMeshSize(const SubMesh *geoSubMesh) { size_t size = CHUNK_OVERHEAD_SIZE; // Material name size += getMaterialName().length() + 1; // bool useSharedVertices size += sizeof(bool); // unsigned int indexCount size += sizeof(unsigned int); // bool indexes32bit size += sizeof(bool); // unsigned int* faceVertexIndices size += sizeof(unsigned int) * geoSubMesh->mIndexCount; // Geometry if (!geoSubMesh->mSharedVertexBuffer) { size += calcGeometrySize(geoSubMesh->mVertexBuffer); } return size; } // Calc the geometry size in bytes. size_t GeoMeshSaver::calcGeometrySize(const VertexBuffer* vertexBuffer) { unsigned long size; unsigned long buffer_count; // and another for normals. buffer_count = 3; // Calculate the size of the Geometry chunk. size = CHUNK_OVERHEAD_SIZE + sizeof(unsigned int); size = size + CHUNK_OVERHEAD_SIZE + buffer_count * (CHUNK_OVERHEAD_SIZE + (sizeof(unsigned short) * 5)); size = size + buffer_count * ( (CHUNK_OVERHEAD_SIZE * 2) + (sizeof(unsigned short) * 2) + vertexBuffer->mVertexCount ); return size; } // Write the file header. void GeoMeshSaver::writeFileHeader(void) { String mesh_version("[MeshSerializer_v1.30]"); writeShorts(M_HEADER, 1); writeString(mesh_version); } // Write a header chunk given. void GeoMeshSaver::writeChunkHeader(unsigned short id, unsigned long size) { mSerializer->WriteData(&id,sizeof(unsigned short),1); mSerializer->WriteData(&size,sizeof(unsigned long),1); } // Write integers into the file. void GeoMeshSaver::writeInts(unsigned long id, unsigned long count) { mSerializer->WriteData(&id,sizeof(id),count); } // Write shorts into the file void GeoMeshSaver::writeShorts(unsigned short id, unsigned long count) { mSerializer->WriteData(&id,sizeof(id),count); } // Write float into the file. void GeoMeshSaver::writeFloats(float id, unsigned long count) { mSerializer->WriteData(&id,sizeof(id),count); } // Write a string into the file. void GeoMeshSaver::writeString(const String &string) { mSerializer->WriteData(string); } // Write booleans into the file. void GeoMeshSaver::writeBools( const bool id, unsigned long count) { mSerializer->WriteData(&id,sizeof(bool),count); } // Sets the material of the mesh. void GeoMeshSaver::setMaterialName(String materialName) { mMaterialName = materialName; } // Gets the material of the mesh. String GeoMeshSaver::getMaterialName() { return mMaterialName; } // Set Mesh Bounds. void GeoMeshSaver::setMeshBounds(GeometryBounds bounds) { mMeshBounds.minx = bounds.minx; mMeshBounds.miny = bounds.miny; mMeshBounds.minz = bounds.minz; mMeshBounds.maxx = bounds.maxx; mMeshBounds.maxy = bounds.maxy; mMeshBounds.maxz = bounds.maxz; mMeshBounds.radius = bounds.radius; }