bool Model::Save(Serializer& dest) const { // Write ID if (!dest.WriteFileID("UMD2")) return false; // Write vertex buffers dest.WriteUInt(vertexBuffers_.Size()); for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { VertexBuffer* buffer = vertexBuffers_[i]; dest.WriteUInt(buffer->GetVertexCount()); const PODVector<VertexElement>& elements = buffer->GetElements(); dest.WriteUInt(elements.Size()); for (unsigned j = 0; j < elements.Size(); ++j) { unsigned elementDesc = ((unsigned)elements[j].type_) | (((unsigned)elements[j].semantic_) << 8) | (((unsigned)elements[j].index_) << 16); dest.WriteUInt(elementDesc); } dest.WriteUInt(morphRangeStarts_[i]); dest.WriteUInt(morphRangeCounts_[i]); dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize()); } // Write index buffers dest.WriteUInt(indexBuffers_.Size()); for (unsigned i = 0; i < indexBuffers_.Size(); ++i) { IndexBuffer* buffer = indexBuffers_[i]; dest.WriteUInt(buffer->GetIndexCount()); dest.WriteUInt(buffer->GetIndexSize()); dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize()); } // Write geometries dest.WriteUInt(geometries_.Size()); for (unsigned i = 0; i < geometries_.Size(); ++i) { // Write bone mappings dest.WriteUInt(geometryBoneMappings_[i].Size()); for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j) dest.WriteUInt(geometryBoneMappings_[i][j]); // Write the LOD levels dest.WriteUInt(geometries_[i].Size()); for (unsigned j = 0; j < geometries_[i].Size(); ++j) { Geometry* geometry = geometries_[i][j]; dest.WriteFloat(geometry->GetLodDistance()); dest.WriteUInt(geometry->GetPrimitiveType()); dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_)); dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_)); dest.WriteUInt(geometry->GetIndexStart()); dest.WriteUInt(geometry->GetIndexCount()); } } // Write morphs dest.WriteUInt(morphs_.Size()); for (unsigned i = 0; i < morphs_.Size(); ++i) { dest.WriteString(morphs_[i].name_); dest.WriteUInt(morphs_[i].buffers_.Size()); // Write morph vertex buffers for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin(); j != morphs_[i].buffers_.End(); ++j) { dest.WriteUInt(j->first_); dest.WriteUInt(j->second_.elementMask_); dest.WriteUInt(j->second_.vertexCount_); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (j->second_.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_); } } // Write skeleton skeleton_.Save(dest); // Write bounding box dest.WriteBoundingBox(boundingBox_); // Write geometry centers for (unsigned i = 0; i < geometryCenters_.Size(); ++i) dest.WriteVector3(geometryCenters_[i]); // Write metadata if (HasMetadata()) { File* destFile = dynamic_cast<File*>(&dest); if (destFile) { String xmlName = ReplaceExtension(destFile->GetName(), ".xml"); SharedPtr<XMLFile> xml(new XMLFile(context_)); XMLElement rootElem = xml->CreateRoot("model"); SaveMetadataToXML(rootElem); File xmlFile(context_, xmlName, FILE_WRITE); xml->Save(xmlFile); } else URHO3D_LOGWARNING("Can not save model metadata when not saving into a file"); } return true; }
bool Model::Save(Serializer& dest) const { // Write ID if (!dest.WriteFileID("AMDL")) // atomic model specifier return false; // Write vertex buffers dest.WriteUInt(vertexBuffers_.Size()); for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { VertexBuffer* buffer = vertexBuffers_[i]; dest.WriteUInt(buffer->GetVertexCount()); dest.WriteUInt(buffer->GetElementMask()); dest.WriteUInt(morphRangeStarts_[i]); dest.WriteUInt(morphRangeCounts_[i]); dest.Write(buffer->GetShadowData(), buffer->GetVertexCount() * buffer->GetVertexSize()); } // Write index buffers dest.WriteUInt(indexBuffers_.Size()); for (unsigned i = 0; i < indexBuffers_.Size(); ++i) { IndexBuffer* buffer = indexBuffers_[i]; dest.WriteUInt(buffer->GetIndexCount()); dest.WriteUInt(buffer->GetIndexSize()); dest.Write(buffer->GetShadowData(), buffer->GetIndexCount() * buffer->GetIndexSize()); } // Write geometries dest.WriteUInt(geometries_.Size()); for (unsigned i = 0; i < geometries_.Size(); ++i) { // Write bone mappings dest.WriteUInt(geometryBoneMappings_[i].Size()); for (unsigned j = 0; j < geometryBoneMappings_[i].Size(); ++j) dest.WriteUInt(geometryBoneMappings_[i][j]); // Write the LOD levels dest.WriteUInt(geometries_[i].Size()); for (unsigned j = 0; j < geometries_[i].Size(); ++j) { Geometry* geometry = geometries_[i][j]; dest.WriteFloat(geometry->GetLodDistance()); dest.WriteUInt(geometry->GetPrimitiveType()); dest.WriteUInt(LookupVertexBuffer(geometry->GetVertexBuffer(0), vertexBuffers_)); dest.WriteUInt(LookupIndexBuffer(geometry->GetIndexBuffer(), indexBuffers_)); dest.WriteUInt(geometry->GetIndexStart()); dest.WriteUInt(geometry->GetIndexCount()); } } // Write morphs dest.WriteUInt(morphs_.Size()); for (unsigned i = 0; i < morphs_.Size(); ++i) { dest.WriteString(morphs_[i].name_); dest.WriteUInt(morphs_[i].buffers_.Size()); // Write morph vertex buffers for (HashMap<unsigned, VertexBufferMorph>::ConstIterator j = morphs_[i].buffers_.Begin(); j != morphs_[i].buffers_.End(); ++j) { dest.WriteUInt(j->first_); dest.WriteUInt(j->second_.elementMask_); dest.WriteUInt(j->second_.vertexCount_); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (j->second_.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (j->second_.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); dest.Write(j->second_.morphData_.Get(), vertexSize * j->second_.vertexCount_); } } // Write skeleton skeleton_.Save(dest); // Write bounding box dest.WriteBoundingBox(boundingBox_); // Write geometry centers for (unsigned i = 0; i < geometryCenters_.Size(); ++i) dest.WriteVector3(geometryCenters_[i]); // ATOMIC BEGIN dest.WriteUInt(MODEL_VERSION); // animation resources ResourceRefList animList(Animation::GetTypeStatic()); animList.names_.Resize(animationsResources_.Size()); for (unsigned i = 0; i < animationsResources_.Size(); ++i) animList.names_[i] = GetResourceName(animationsResources_[i]); dest.WriteResourceRefList(animList); // ATOMIC END return true; }