diff --git a/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h b/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h index bf339a3ea..03a6739bd 100644 --- a/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h +++ b/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h @@ -21,12 +21,247 @@ public: { const Upgrader upgraders[] = { + { 4, 5, &Upgrade_4_To_5 }, // [Deprecated in v1.10] { 5, 30, Upgrade_5_To_30 }, // [Deprecated in v1.10] }; setup(upgraders, ARRAY_COUNT(upgraders)); } PRAGMA_DISABLE_DEPRECATION_WARNINGS + static bool Upgrade_4_To_5(AssetMigrationContext& context) + { + ASSERT(context.Input.SerializedVersion == 4 && context.Output.SerializedVersion == 5); + + // Changes: + // - added version number to header (for easier changes in future) + // - added version number to mesh data (for easier changes in future) + // - added skeleton retarget setups to header + + // Rewrite header chunk (added header version and retarget entries) + byte lodCount; + Array meshesCounts; + { + const auto srcData = context.Input.Header.Chunks[0]; + if (srcData == nullptr || srcData->IsMissing()) + { + LOG(Warning, "Missing model header chunk"); + return true; + } + MemoryReadStream stream(srcData->Get(), srcData->Size()); + MemoryWriteStream output(srcData->Size()); + + // Header Version + output.WriteByte(1); + + // Min Screen Size + float minScreenSize; + stream.ReadFloat(&minScreenSize); + output.WriteFloat(minScreenSize); + + // Amount of material slots + int32 materialSlotsCount; + stream.ReadInt32(&materialSlotsCount); + output.WriteInt32(materialSlotsCount); + + // For each material slot + for (int32 materialSlotIndex = 0; materialSlotIndex < materialSlotsCount; materialSlotIndex++) + { + // Material + Guid materialId; + stream.Read(materialId); + output.Write(materialId); + + // Shadows Mode + output.WriteByte(stream.ReadByte()); + + // Name + String name; + stream.ReadString(&name, 11); + output.WriteString(name, 11); + } + + // Amount of LODs + stream.ReadByte(&lodCount); + output.WriteByte(lodCount); + meshesCounts.Resize(lodCount); + + // For each LOD + for (int32 lodIndex = 0; lodIndex < lodCount; lodIndex++) + { + // Screen Size + float screenSize; + stream.ReadFloat(&screenSize); + output.WriteFloat(screenSize); + + // Amount of meshes + uint16 meshesCount; + stream.ReadUint16(&meshesCount); + output.WriteUint16(meshesCount); + meshesCounts[lodIndex] = meshesCount; + + // For each mesh + for (uint16 meshIndex = 0; meshIndex < meshesCount; meshIndex++) + { + // Material Slot index + int32 materialSlotIndex; + stream.ReadInt32(&materialSlotIndex); + output.WriteInt32(materialSlotIndex); + + // Box + BoundingBox box; + stream.Read(box); + output.Write(box); + + // Sphere + BoundingSphere sphere; + stream.Read(sphere); + output.Write(sphere); + + // Blend Shapes + uint16 blendShapes; + stream.ReadUint16(&blendShapes); + output.WriteUint16(blendShapes); + for (int32 blendShapeIndex = 0; blendShapeIndex < blendShapes; blendShapeIndex++) + { + String blendShapeName; + stream.ReadString(&blendShapeName, 13); + output.WriteString(blendShapeName, 13); + float blendShapeWeight; + stream.ReadFloat(&blendShapeWeight); + output.WriteFloat(blendShapeWeight); + } + } + } + + // Skeleton + { + int32 nodesCount; + stream.ReadInt32(&nodesCount); + output.WriteInt32(nodesCount); + + // For each node + for (int32 nodeIndex = 0; nodeIndex < nodesCount; nodeIndex++) + { + int32 parentIndex; + stream.ReadInt32(&parentIndex); + output.WriteInt32(parentIndex); + + Transform localTransform; + stream.Read(localTransform); + output.Write(localTransform); + + String name; + stream.ReadString(&name, 71); + output.WriteString(name, 71); + } + + int32 bonesCount; + stream.ReadInt32(&bonesCount); + output.WriteInt32(bonesCount); + + // For each bone + for (int32 boneIndex = 0; boneIndex < bonesCount; boneIndex++) + { + int32 parentIndex; + stream.ReadInt32(&parentIndex); + output.WriteInt32(parentIndex); + + int32 nodeIndex; + stream.ReadInt32(&nodeIndex); + output.WriteInt32(nodeIndex); + + Transform localTransform; + stream.Read(localTransform); + output.Write(localTransform); + + Matrix offsetMatrix; + stream.ReadBytes(&offsetMatrix, sizeof(Matrix)); + output.WriteBytes(&offsetMatrix, sizeof(Matrix)); + } + } + + // Retargeting + { + output.WriteInt32(0); + } + + // Save new data + if (stream.GetPosition() != stream.GetLength()) + { + LOG(Error, "Invalid position after upgrading skinned model header data."); + return true; + } + if (context.AllocateChunk(0)) + return true; + context.Output.Header.Chunks[0]->Data.Copy(output.GetHandle(), output.GetPosition()); + } + + // Rewrite meshes data chunks + for (int32 lodIndex = 0; lodIndex < lodCount; lodIndex++) + { + const int32 chunkIndex = lodIndex + 1; + const auto srcData = context.Input.Header.Chunks[chunkIndex]; + if (srcData == nullptr || srcData->IsMissing()) + { + LOG(Warning, "Missing skinned model LOD meshes data chunk"); + return true; + } + MemoryReadStream stream(srcData->Get(), srcData->Size()); + MemoryWriteStream output(srcData->Size()); + + // Mesh Data Version + output.WriteByte(1); + + for (int32 meshIndex = 0; meshIndex < meshesCounts[lodIndex]; meshIndex++) + { + uint32 vertices; + stream.ReadUint32(&vertices); + output.WriteUint32(vertices); + uint32 triangles; + stream.ReadUint32(&triangles); + output.WriteUint32(triangles); + uint16 blendShapesCount; + stream.ReadUint16(&blendShapesCount); + output.WriteUint16(blendShapesCount); + for (int32 blendShapeIndex = 0; blendShapeIndex < blendShapesCount; blendShapeIndex++) + { + output.WriteBool(stream.ReadBool()); + uint32 minVertexIndex, maxVertexIndex; + stream.ReadUint32(&minVertexIndex); + output.WriteUint32(minVertexIndex); + stream.ReadUint32(&maxVertexIndex); + output.WriteUint32(maxVertexIndex); + uint32 blendShapeVertices; + stream.ReadUint32(&blendShapeVertices); + output.WriteUint32(blendShapeVertices); + const uint32 blendShapeDataSize = blendShapeVertices * sizeof(BlendShapeVertex); + const auto blendShapeData = stream.Move(blendShapeDataSize); + output.WriteBytes(blendShapeData, blendShapeDataSize); + } + const uint32 indicesCount = triangles * 3; + const bool use16BitIndexBuffer = indicesCount <= MAX_uint16; + const uint32 ibStride = use16BitIndexBuffer ? sizeof(uint16) : sizeof(uint32); + if (vertices == 0 || triangles == 0) + return true; + const auto vb0 = stream.Move(vertices); + output.WriteBytes(vb0, vertices * sizeof(VB0SkinnedElementType)); + const auto ib = stream.Move(indicesCount * ibStride); + output.WriteBytes(ib, indicesCount * ibStride); + } + + // Save new data + if (stream.GetPosition() != stream.GetLength()) + { + LOG(Error, "Invalid position after upgrading skinned model LOD meshes data."); + return true; + } + if (context.AllocateChunk(chunkIndex)) + return true; + context.Output.Header.Chunks[chunkIndex]->Data.Copy(output.GetHandle(), output.GetPosition()); + } + + return false; + } static bool Upgrade_5_To_30(AssetMigrationContext& context) { // [Deprecated in v1.10] @@ -73,7 +308,7 @@ PRAGMA_DISABLE_DEPRECATION_WARNINGS // LODs stream.Read(lodsCount); output.Write(lodsCount); - CHECK_RETURN(materialSlotsCount <= 6, true); + CHECK_RETURN(lodsCount <= 6, true); meshesCountPerLod.Resize(lodsCount); for (int32 lodIndex = 0; lodIndex < lodsCount; lodIndex++) {