bool Animation::Load(Deserializer& source) { PROFILE(LoadAnimation); unsigned memoryUse = sizeof(Animation); // Check ID if (source.ReadFileID() != "UANI") { LOGERROR(source.GetName() + " is not a valid animation file"); return false; } // Read name and length animationName_ = source.ReadString(); animationNameHash_ = animationName_; length_ = source.ReadFloat(); tracks_.Clear(); unsigned tracks = source.ReadUInt(); tracks_.Resize(tracks); memoryUse += tracks * sizeof(AnimationTrack); // Read tracks for (unsigned i = 0; i < tracks; ++i) { AnimationTrack& newTrack = tracks_[i]; newTrack.name_ = source.ReadString(); newTrack.nameHash_ = newTrack.name_; newTrack.channelMask_ = source.ReadUByte(); unsigned keyFrames = source.ReadUInt(); newTrack.keyFrames_.Resize(keyFrames); memoryUse += keyFrames * sizeof(AnimationKeyFrame); // Read keyframes of the track for (unsigned j = 0; j < keyFrames; ++j) { AnimationKeyFrame& newKeyFrame = newTrack.keyFrames_[j]; newKeyFrame.time_ = source.ReadFloat(); if (newTrack.channelMask_ & CHANNEL_POSITION) newKeyFrame.position_ = source.ReadVector3(); if (newTrack.channelMask_ & CHANNEL_ROTATION) newKeyFrame.rotation_ = source.ReadQuaternion(); if (newTrack.channelMask_ & CHANNEL_SCALE) newKeyFrame.scale_ = source.ReadVector3(); } } // Optionally read triggers from an XML file ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); if (cache->Exists(xmlName)) { XMLFile* file = cache->GetResource<XMLFile>(xmlName); if (file) { XMLElement rootElem = file->GetRoot(); XMLElement triggerElem = rootElem.GetChild("trigger"); while (triggerElem) { if (triggerElem.HasAttribute("normalizedtime")) AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant()); else if (triggerElem.HasAttribute("time")) AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant()); triggerElem = triggerElem.GetNext("trigger"); } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); } } SetMemoryUse(memoryUse); return true; }
bool Model::BeginLoad(Deserializer& source) { // Check ID String id = source.ReadFileID(); bool umdl = false; if (id == "UMDL") // we only support UMDL for some current legacy mdl's (ToonTown) umdl = true; if (!umdl && id != "AMDL") { LOGERROR(source.GetName() + " is not a valid model file"); return false; } geometries_.Clear(); geometryBoneMappings_.Clear(); geometryCenters_.Clear(); morphs_.Clear(); vertexBuffers_.Clear(); indexBuffers_.Clear(); unsigned memoryUse = sizeof(Model); bool async = GetAsyncLoadState() == ASYNC_LOADING; // Read vertex buffers unsigned numVertexBuffers = source.ReadUInt(); vertexBuffers_.Reserve(numVertexBuffers); morphRangeStarts_.Resize(numVertexBuffers); morphRangeCounts_.Resize(numVertexBuffers); loadVBData_.Resize(numVertexBuffers); for (unsigned i = 0; i < numVertexBuffers; ++i) { unsigned vertexCount = source.ReadUInt(); unsigned elementMask = source.ReadUInt(); morphRangeStarts_[i] = source.ReadUInt(); morphRangeCounts_[i] = source.ReadUInt(); SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_)); unsigned vertexSize = VertexBuffer::GetVertexSize(elementMask); // Prepare vertex buffer data to be uploaded during EndLoad() if (async) { loadVBData_[i].vertexCount_ = vertexCount; loadVBData_[i].elementMask_ = elementMask; loadVBData_[i].dataSize_ = vertexCount * vertexSize; loadVBData_[i].data_ = new unsigned char[loadVBData_[i].dataSize_]; source.Read(loadVBData_[i].data_.Get(), loadVBData_[i].dataSize_); } else { // If not async loading, use locking to avoid extra allocation & copy loadVBData_[i].data_.Reset(); // Make sure no previous data buffer->SetShadowed(true); buffer->SetSize(vertexCount, elementMask); void* dest = buffer->Lock(0, vertexCount); source.Read(dest, vertexCount * vertexSize); buffer->Unlock(); } memoryUse += sizeof(VertexBuffer) + vertexCount * vertexSize; vertexBuffers_.Push(buffer); } // Read index buffers unsigned numIndexBuffers = source.ReadUInt(); indexBuffers_.Reserve(numIndexBuffers); loadIBData_.Resize(numIndexBuffers); for (unsigned i = 0; i < numIndexBuffers; ++i) { unsigned indexCount = source.ReadUInt(); unsigned indexSize = source.ReadUInt(); SharedPtr<IndexBuffer> buffer(new IndexBuffer(context_)); // Prepare index buffer data to be uploaded during EndLoad() if (async) { loadIBData_[i].indexCount_ = indexCount; loadIBData_[i].indexSize_ = indexSize; loadIBData_[i].dataSize_ = indexCount * indexSize; loadIBData_[i].data_ = new unsigned char[loadIBData_[i].dataSize_]; source.Read(loadIBData_[i].data_.Get(), loadIBData_[i].dataSize_); } else { // If not async loading, use locking to avoid extra allocation & copy loadIBData_[i].data_.Reset(); // Make sure no previous data buffer->SetShadowed(true); buffer->SetSize(indexCount, indexSize > sizeof(unsigned short)); void* dest = buffer->Lock(0, indexCount); source.Read(dest, indexCount * indexSize); buffer->Unlock(); } memoryUse += sizeof(IndexBuffer) + indexCount * indexSize; indexBuffers_.Push(buffer); } // Read geometries unsigned numGeometries = source.ReadUInt(); geometries_.Reserve(numGeometries); geometryBoneMappings_.Reserve(numGeometries); geometryCenters_.Reserve(numGeometries); loadGeometries_.Resize(numGeometries); for (unsigned i = 0; i < numGeometries; ++i) { // Read bone mappings unsigned boneMappingCount = source.ReadUInt(); PODVector<unsigned> boneMapping(boneMappingCount); for (unsigned j = 0; j < boneMappingCount; ++j) boneMapping[j] = source.ReadUInt(); geometryBoneMappings_.Push(boneMapping); unsigned numLodLevels = source.ReadUInt(); Vector<SharedPtr<Geometry> > geometryLodLevels; geometryLodLevels.Reserve(numLodLevels); loadGeometries_[i].Resize(numLodLevels); for (unsigned j = 0; j < numLodLevels; ++j) { float distance = source.ReadFloat(); PrimitiveType type = (PrimitiveType)source.ReadUInt(); unsigned vbRef = source.ReadUInt(); unsigned ibRef = source.ReadUInt(); unsigned indexStart = source.ReadUInt(); unsigned indexCount = source.ReadUInt(); if (vbRef >= vertexBuffers_.Size()) { LOGERROR("Vertex buffer index out of bounds"); loadVBData_.Clear(); loadIBData_.Clear(); loadGeometries_.Clear(); return false; } if (ibRef >= indexBuffers_.Size()) { LOGERROR("Index buffer index out of bounds"); loadVBData_.Clear(); loadIBData_.Clear(); loadGeometries_.Clear(); return false; } SharedPtr<Geometry> geometry(new Geometry(context_)); geometry->SetLodDistance(distance); // Prepare geometry to be defined during EndLoad() loadGeometries_[i][j].type_ = type; loadGeometries_[i][j].vbRef_ = vbRef; loadGeometries_[i][j].ibRef_ = ibRef; loadGeometries_[i][j].indexStart_ = indexStart; loadGeometries_[i][j].indexCount_ = indexCount; geometryLodLevels.Push(geometry); memoryUse += sizeof(Geometry); } geometries_.Push(geometryLodLevels); } // Read morphs unsigned numMorphs = source.ReadUInt(); morphs_.Reserve(numMorphs); for (unsigned i = 0; i < numMorphs; ++i) { ModelMorph newMorph; newMorph.name_ = source.ReadString(); newMorph.nameHash_ = newMorph.name_; newMorph.weight_ = 0.0f; unsigned numBuffers = source.ReadUInt(); for (unsigned j = 0; j < numBuffers; ++j) { VertexBufferMorph newBuffer; unsigned bufferIndex = source.ReadUInt(); newBuffer.elementMask_ = source.ReadUInt(); newBuffer.vertexCount_ = source.ReadUInt(); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (newBuffer.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (newBuffer.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (newBuffer.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); newBuffer.dataSize_ = newBuffer.vertexCount_ * vertexSize; newBuffer.morphData_ = new unsigned char[newBuffer.dataSize_]; source.Read(&newBuffer.morphData_[0], newBuffer.vertexCount_ * vertexSize); newMorph.buffers_[bufferIndex] = newBuffer; memoryUse += sizeof(VertexBufferMorph) + newBuffer.vertexCount_ * vertexSize; } morphs_.Push(newMorph); memoryUse += sizeof(ModelMorph); } // Read skeleton skeleton_.Load(source); memoryUse += skeleton_.GetNumBones() * sizeof(Bone); // Read bounding box boundingBox_ = source.ReadBoundingBox(); // Read geometry centers for (unsigned i = 0; i < geometries_.Size() && !source.IsEof(); ++i) geometryCenters_.Push(source.ReadVector3()); while (geometryCenters_.Size() < geometries_.Size()) geometryCenters_.Push(Vector3::ZERO); memoryUse += sizeof(Vector3) * geometries_.Size(); if (umdl) { SetMemoryUse(memoryUse); return true; } // MODEL_VERSION unsigned version = source.ReadUInt(); ResourceRefList animList = source.ReadResourceRefList(); animationsResources_.Clear(); ResourceCache* cache = GetSubsystem<ResourceCache>(); for (unsigned i = 0; i < animList.names_.Size(); ++i) { AddAnimationResource(cache->GetResource<Animation>(animList.names_[i])); } SetMemoryUse(memoryUse); return true; }
bool Model::Load(Deserializer& source) { PROFILE(LoadModel); // Check ID if (source.ReadFileID() != "UMDL") { LOGERROR(source.GetName() + " is not a valid model file"); return false; } geometries_.Clear(); geometryBoneMappings_.Clear(); geometryCenters_.Clear(); morphs_.Clear(); vertexBuffers_.Clear(); indexBuffers_.Clear(); unsigned memoryUse = sizeof(Model); // Read vertex buffers unsigned numVertexBuffers = source.ReadUInt(); vertexBuffers_.Reserve(numVertexBuffers); morphRangeStarts_.Resize(numVertexBuffers); morphRangeCounts_.Resize(numVertexBuffers); for (unsigned i = 0; i < numVertexBuffers; ++i) { unsigned vertexCount = source.ReadUInt(); unsigned elementMask = source.ReadUInt(); morphRangeStarts_[i] = source.ReadUInt(); morphRangeCounts_[i] = source.ReadUInt(); SharedPtr<VertexBuffer> buffer(new VertexBuffer(context_)); buffer->SetShadowed(true); buffer->SetSize(vertexCount, elementMask); void* dest = buffer->Lock(0, vertexCount); unsigned vertexSize = buffer->GetVertexSize(); source.Read(dest, vertexCount * vertexSize); buffer->Unlock(); memoryUse += sizeof(VertexBuffer) + vertexCount * vertexSize; vertexBuffers_.Push(buffer); } // Read index buffers unsigned numIndexBuffers = source.ReadUInt(); indexBuffers_.Reserve(numIndexBuffers); for (unsigned i = 0; i < numIndexBuffers; ++i) { unsigned indexCount = source.ReadUInt(); unsigned indexSize = source.ReadUInt(); SharedPtr<IndexBuffer> buffer(new IndexBuffer(context_)); buffer->SetShadowed(true); buffer->SetSize(indexCount, indexSize > sizeof(unsigned short)); void* dest = buffer->Lock(0, indexCount); source.Read(dest, indexCount * indexSize); buffer->Unlock(); memoryUse += sizeof(IndexBuffer) + indexCount * indexSize; indexBuffers_.Push(buffer); } // Read geometries unsigned numGeometries = source.ReadUInt(); geometries_.Reserve(numGeometries); geometryBoneMappings_.Reserve(numGeometries); geometryCenters_.Reserve(numGeometries); for (unsigned i = 0; i < numGeometries; ++i) { // Read bone mappings unsigned boneMappingCount = source.ReadUInt(); PODVector<unsigned> boneMapping(boneMappingCount); for (unsigned j = 0; j < boneMappingCount; ++j) boneMapping[j] = source.ReadUInt(); geometryBoneMappings_.Push(boneMapping); unsigned numLodLevels = source.ReadUInt(); Vector<SharedPtr<Geometry> > geometryLodLevels; geometryLodLevels.Reserve(numLodLevels); for (unsigned j = 0; j < numLodLevels; ++j) { float distance = source.ReadFloat(); PrimitiveType type = (PrimitiveType)source.ReadUInt(); unsigned vertexBufferRef = source.ReadUInt(); unsigned indexBufferRef = source.ReadUInt(); unsigned indexStart = source.ReadUInt(); unsigned indexCount = source.ReadUInt(); if (vertexBufferRef >= vertexBuffers_.Size()) { LOGERROR("Vertex buffer index out of bounds"); return false; } if (indexBufferRef >= indexBuffers_.Size()) { LOGERROR("Index buffer index out of bounds"); return false; } SharedPtr<Geometry> geometry(new Geometry(context_)); geometry->SetVertexBuffer(0, vertexBuffers_[vertexBufferRef]); geometry->SetIndexBuffer(indexBuffers_[indexBufferRef]); geometry->SetDrawRange(type, indexStart, indexCount); geometry->SetLodDistance(distance); geometryLodLevels.Push(geometry); memoryUse += sizeof(Geometry); } geometries_.Push(geometryLodLevels); } // Read morphs unsigned numMorphs = source.ReadUInt(); morphs_.Reserve(numMorphs); for (unsigned i = 0; i < numMorphs; ++i) { ModelMorph newMorph; newMorph.name_ = source.ReadString(); newMorph.nameHash_ = newMorph.name_; newMorph.weight_ = 0.0f; unsigned nubuffers_ = source.ReadUInt(); for (unsigned j = 0; j < nubuffers_; ++j) { VertexBufferMorph newBuffer; unsigned bufferIndex = source.ReadUInt(); newBuffer.elementMask_ = source.ReadUInt(); newBuffer.vertexCount_ = source.ReadUInt(); // Base size: size of each vertex index unsigned vertexSize = sizeof(unsigned); // Add size of individual elements if (newBuffer.elementMask_ & MASK_POSITION) vertexSize += sizeof(Vector3); if (newBuffer.elementMask_ & MASK_NORMAL) vertexSize += sizeof(Vector3); if (newBuffer.elementMask_ & MASK_TANGENT) vertexSize += sizeof(Vector3); newBuffer.morphData_ = new unsigned char[newBuffer.vertexCount_ * vertexSize]; source.Read(&newBuffer.morphData_[0], newBuffer.vertexCount_ * vertexSize); newMorph.buffers_[bufferIndex] = newBuffer; memoryUse += sizeof(VertexBufferMorph) + newBuffer.vertexCount_ * vertexSize; } morphs_.Push(newMorph); memoryUse += sizeof(ModelMorph); } // Read skeleton skeleton_.Load(source); memoryUse += skeleton_.GetNumBones() * sizeof(Bone); // Read bounding box boundingBox_ = source.ReadBoundingBox(); // Read geometry centers for (unsigned i = 0; i < geometries_.Size() && !source.IsEof(); ++i) geometryCenters_.Push(source.ReadVector3()); while (geometryCenters_.Size() < geometries_.Size()) geometryCenters_.Push(Vector3::ZERO); memoryUse += sizeof(Vector3) * geometries_.Size(); SetMemoryUse(memoryUse); return true; }
bool ModelDefinition::Deserialize(Deserializer &deserializer) { // Clear everything. this->ClearMeshes(); this->ClearBones(); this->ClearAnimations(true); // <-- 'true' = clear animation segments, too. this->ClearConvexHulls(); // We keep looping until we hit the null or unknown chunk. Serialization::ChunkHeader header; while (deserializer.Peek(&header, sizeof(header)) == sizeof(header)) { bool finished = false; switch (header.id) { case Serialization::ChunkID_Model_Bones: { deserializer.Seek(sizeof(header)); if (header.version == 1) { uint32_t boneCount; deserializer.Read(boneCount); for (uint32_t iBone = 0; iBone < boneCount; ++iBone) { // Name. String name; deserializer.ReadString(name); // Local transform. glm::vec3 position; glm::quat rotation; glm::vec3 scale; deserializer.Read(position); deserializer.Read(rotation); deserializer.Read(scale); // 4x4 offset matrix. glm::mat4 offsetMatrix; deserializer.Read(offsetMatrix); auto bone = new Bone; bone->SetName(name.c_str()); bone->SetPosition(position); bone->SetRotation(rotation); bone->SetScale(scale); bone->SetOffsetMatrix(offsetMatrix); this->AddBone(bone); // We need to create a channel for this bone. We then need to map that channel to a bone. auto &channel = m_animation.CreateChannel(); this->animationChannelBones.Add(bone, &channel); } // Parents. auto boneParentIndices = static_cast<uint32_t*>(malloc(boneCount * sizeof(uint32_t))); deserializer.Read(boneParentIndices, boneCount * sizeof(uint32_t)); for (uint32_t iBone = 0; iBone < boneCount; ++iBone) { uint32_t parentIndex = boneParentIndices[iBone]; if (parentIndex != static_cast<uint32_t>(-1)) { m_bones[parentIndex]->AttachChild(*m_bones[iBone]); } } free(boneParentIndices); } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Model_Meshes: { deserializer.Seek(sizeof(header)); if (header.version == 1) { uint32_t meshCount; deserializer.Read(meshCount); for (uint32_t iMesh = 0; iMesh < meshCount; ++iMesh) { ModelDefinition::Mesh newMesh(m_context); // Name. deserializer.ReadString(newMesh.name); // Material String materialName; deserializer.ReadString(materialName); newMesh.material = m_context.GetMaterialLibrary().Create(materialName.c_str()); // Geometry VertexFormat vertexFormat; vertexFormat.Deserialize(deserializer); newMesh.geometry = Renderer::CreateVertexArray(VertexArrayUsage_Static, vertexFormat); // Vertices. uint32_t vertexCount; deserializer.Read(vertexCount); if (vertexCount > 0) { newMesh.geometry->SetVertexData(nullptr, static_cast<size_t>(vertexCount)); auto vertexData = newMesh.geometry->MapVertexData(); { deserializer.Read(vertexData, vertexCount * vertexFormat.GetSizeInBytes()); } newMesh.geometry->UnmapVertexData(); } // Indices. uint32_t indexCount; deserializer.Read(indexCount); if (indexCount > 0) { newMesh.geometry->SetIndexData(nullptr, static_cast<size_t>(indexCount)); auto indexData = newMesh.geometry->MapIndexData(); { deserializer.Read(indexData, indexCount * sizeof(uint32_t)); } newMesh.geometry->UnmapIndexData(); } // Skinning Vertex Attributes uint32_t skinningVertexAttributeCount; deserializer.Read(skinningVertexAttributeCount); if (skinningVertexAttributeCount > 0) { newMesh.skinningVertexAttributes = new SkinningVertexAttribute[skinningVertexAttributeCount]; auto counts = static_cast<uint16_t*>(malloc(skinningVertexAttributeCount * sizeof(uint16_t))); deserializer.Read(counts, skinningVertexAttributeCount * sizeof(uint16_t)); uint32_t totalBoneWeights; deserializer.Read(totalBoneWeights); auto boneWeights = static_cast<BoneWeightPair*>(malloc(totalBoneWeights * sizeof(BoneWeightPair))); deserializer.Read(boneWeights, totalBoneWeights * sizeof(BoneWeightPair)); auto currentBoneWeight = boneWeights; for (uint32_t iVertex = 0; iVertex < skinningVertexAttributeCount; ++iVertex) { auto count = counts[iVertex]; // Here we allocate the buffer for the bones. We trick the vector here by modifying attributes directly. newMesh.skinningVertexAttributes[iVertex].bones.Reserve(count); newMesh.skinningVertexAttributes[iVertex].bones.count = count; for (uint16_t iBone = 0; iBone < count; ++iBone) { newMesh.skinningVertexAttributes[iVertex].bones[iBone] = *currentBoneWeight++; } } free(counts); free(boneWeights); } // Uniforms. newMesh.defaultUniforms.Deserialize(deserializer); // Finally, add the mesh. this->AddMesh(newMesh); } } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Model_Animation: { deserializer.Seek(sizeof(header)); if (header.version == 1) { uint32_t keyFrameCount; deserializer.Read(keyFrameCount); for (size_t iKeyFrame = 0; iKeyFrame < keyFrameCount; ++iKeyFrame) { float time; deserializer.Read(time); size_t keyFrameIndex = m_animation.AppendKeyFrame(static_cast<double>(time)); // With the key frame added, we now need to iterate over each channel in the key frame. uint32_t channelCount; deserializer.Read(channelCount); for (uint32_t iChannel = 0; iChannel < channelCount; ++iChannel) { uint32_t boneIndex; deserializer.Read(boneIndex); auto bone = m_bones[boneIndex]; assert(bone != nullptr); { auto iChannelBone = this->animationChannelBones.Find(bone); assert(iChannelBone != nullptr); { auto channel = iChannelBone->value; glm::vec3 position; glm::quat rotation; glm::vec3 scale; deserializer.Read(position); deserializer.Read(rotation); deserializer.Read(scale); auto key = new TransformAnimationKey(position, rotation, scale); channel->SetKey(keyFrameIndex, key); // We need to cache the key. this->animationKeyCache.PushBack(key); } } } } deserializer.Read(this->animationAABBPadding); } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Model_AnimationSegments: { deserializer.Seek(sizeof(header)); if (header.version == 1) { uint32_t animationSegmentCount; deserializer.Read(animationSegmentCount); for (uint32_t iSegment = 0; iSegment < animationSegmentCount; ++iSegment) { String name; uint32_t startKeyFrame; uint32_t endKeyFrame; deserializer.ReadString(name); deserializer.Read(startKeyFrame); deserializer.Read(endKeyFrame); m_animation.AddNamedSegment(name.c_str(), static_cast<size_t>(startKeyFrame), static_cast<size_t>(endKeyFrame)); } } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Model_AnimationSequences: { deserializer.Seek(sizeof(header)); if (header.version == 1) { } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Model_ConvexHulls: { deserializer.Seek(sizeof(header)); if (header.version == 1) { uint32_t convexHullCount; deserializer.Read(convexHullCount); uint32_t* vertexCounts = static_cast<uint32_t*>(malloc(convexHullCount * sizeof(uint32_t))); uint32_t* indexCounts = static_cast<uint32_t*>(malloc(convexHullCount * sizeof(uint32_t))); deserializer.Read(vertexCounts, convexHullCount * sizeof(uint32_t)); deserializer.Read(indexCounts, convexHullCount * sizeof(uint32_t)); uint32_t totalVertexCount; deserializer.Read(totalVertexCount); uint32_t totalIndexCount; deserializer.Read(totalIndexCount); auto vertices = static_cast<float* >(malloc(totalVertexCount * sizeof(float))); auto indices = static_cast<uint32_t*>(malloc(totalIndexCount * sizeof(uint32_t))); deserializer.Read(vertices, totalVertexCount * sizeof(float)); deserializer.Read(indices, totalIndexCount * sizeof(uint32_t)); auto currentVertices = vertices; auto currentIndices = indices; for (uint32_t iConvexHull = 0; iConvexHull < convexHullCount; ++iConvexHull) { size_t vertexCount = static_cast<size_t>(vertexCounts[iConvexHull]); size_t indexCount = static_cast<size_t>(indexCounts[iConvexHull]); m_convexHulls.PushBack(new ConvexHull(currentVertices, vertexCount, currentIndices, indexCount)); // Now we need to move our pointers forward. currentVertices += vertexCount * 3; currentIndices += indexCount; } // Build Settings. deserializer.Read(this->convexHullBuildSettings); free(vertexCounts); free(indexCounts); free(vertices); free(indices); } else { // Unsupported Version. deserializer.Seek(header.sizeInBytes); } break; } case Serialization::ChunkID_Null: { deserializer.Seek(sizeof(header)); finished = true; break; } default: { // Unknown chunk = Error. finished = true; return false; } } if (finished) { break; } } // If we get here, we were successful. return true; }
bool Animation::BeginLoad(Deserializer& source) { unsigned memoryUse = sizeof(Animation); // Check ID if (source.ReadFileID() != "UANI") { URHO3D_LOGERROR(source.GetName() + " is not a valid animation file"); return false; } // Read name and length animationName_ = source.ReadString(); animationNameHash_ = animationName_; length_ = source.ReadFloat(); tracks_.Clear(); unsigned tracks = source.ReadUInt(); memoryUse += tracks * sizeof(AnimationTrack); // Read tracks for (unsigned i = 0; i < tracks; ++i) { AnimationTrack* newTrack = CreateTrack(source.ReadString()); newTrack->channelMask_ = source.ReadUByte(); unsigned keyFrames = source.ReadUInt(); newTrack->keyFrames_.Resize(keyFrames); memoryUse += keyFrames * sizeof(AnimationKeyFrame); // Read keyframes of the track for (unsigned j = 0; j < keyFrames; ++j) { AnimationKeyFrame& newKeyFrame = newTrack->keyFrames_[j]; newKeyFrame.time_ = source.ReadFloat(); if (newTrack->channelMask_ & CHANNEL_POSITION) newKeyFrame.position_ = source.ReadVector3(); if (newTrack->channelMask_ & CHANNEL_ROTATION) newKeyFrame.rotation_ = source.ReadQuaternion(); if (newTrack->channelMask_ & CHANNEL_SCALE) newKeyFrame.scale_ = source.ReadVector3(); } } // Optionally read triggers from an XML file ResourceCache* cache = GetSubsystem<ResourceCache>(); String xmlName = ReplaceExtension(GetName(), ".xml"); SharedPtr<XMLFile> file(cache->GetTempResource<XMLFile>(xmlName, false)); if (file) { XMLElement rootElem = file->GetRoot(); XMLElement triggerElem = rootElem.GetChild("trigger"); while (triggerElem) { if (triggerElem.HasAttribute("normalizedtime")) AddTrigger(triggerElem.GetFloat("normalizedtime"), true, triggerElem.GetVariant()); else if (triggerElem.HasAttribute("time")) AddTrigger(triggerElem.GetFloat("time"), false, triggerElem.GetVariant()); triggerElem = triggerElem.GetNext("trigger"); } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); SetMemoryUse(memoryUse); return true; } // Optionally read triggers from a JSON file String jsonName = ReplaceExtension(GetName(), ".json"); SharedPtr<JSONFile> jsonFile(cache->GetTempResource<JSONFile>(jsonName, false)); if (jsonFile) { const JSONValue& rootVal = jsonFile->GetRoot(); JSONArray triggerArray = rootVal.Get("triggers").GetArray(); for (unsigned i = 0; i < triggerArray.Size(); i++) { const JSONValue& triggerValue = triggerArray.At(i); JSONValue normalizedTimeValue = triggerValue.Get("normalizedTime"); if (!normalizedTimeValue.IsNull()) AddTrigger(normalizedTimeValue.GetFloat(), true, triggerValue.GetVariant()); else { JSONValue timeVal = triggerValue.Get("time"); if (!timeVal.IsNull()) AddTrigger(timeVal.GetFloat(), false, triggerValue.GetVariant()); } } memoryUse += triggers_.Size() * sizeof(AnimationTriggerPoint); SetMemoryUse(memoryUse); return true; } SetMemoryUse(memoryUse); return true; }
void ModelComponent::Deserialize(Deserializer &deserializer) { uint32_t whatChanged = 0; this->LockOnChanged(); Serialization::ChunkHeader header; deserializer.Read(header); assert(header.id == Serialization::ChunkID_ModelComponent_Main); { size_t deserializerStart = deserializer.Tell(); switch (header.version) { case 1: { // Flags are first. uint32_t newFlags; deserializer.Read(newFlags); if (newFlags != this->flags) { this->flags = newFlags; whatChanged |= ChangeFlag_Flags; } // Next is a boolean indicating whether or not a model is defined here. bool hasModel; deserializer.Read(hasModel); // We will only have additional data at this point if we have actually have a model defined. if (hasModel) { auto oldModel = this->model; String modelPath; deserializer.ReadString(modelPath); if (!modelPath.IsEmpty()) { this->SetModel(modelPath.c_str()); // If we failed to set the model (most likely due to the file not existing) we need to skip this chunk and return. if (this->model == nullptr) { const size_t bytesReadSoFar = deserializer.Tell() - deserializerStart; deserializer.Seek(header.sizeInBytes - bytesReadSoFar); return; } } else { if (this->GetContext() != NULL) { ModelDefinition nullDefinition(*this->GetContext()); this->SetModel(new Model(nullDefinition), true); } } assert(this->model != nullptr); { this->model->Deserialize(deserializer); } if (this->model != oldModel) { whatChanged |= ChangeFlag_Model; } } break; } default: { if (this->GetContext() != NULL) { this->GetContext()->Logf("Error deserializing ModelComponent. Main chunk has an unsupported version (%d).", header.version); } break; } } } this->UnlockOnChanged(); if (whatChanged != 0) { this->OnChanged(whatChanged); } }