public static EntityAsset ExtractSceneClone(EntityAsset source, Guid sourceRootEntity) { if (source == null) throw new ArgumentNullException("source"); // Note: Instead of copying the whole asset (with its potentially big hierarchy), we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. // create the hierarchy of the sub-tree var subTreeRoot = source.Hierarchy.Entities[sourceRootEntity]; var subTreeHierarchy = new EntityHierarchyData { Entities = { subTreeRoot }, RootEntities = { sourceRootEntity } }; foreach (var subTreeEntity in subTreeRoot.EnumerateChildren(true)) subTreeHierarchy.Entities.Add(subTreeEntity); // clone the entities of the sub-tree var clonedHierarchy = (EntityHierarchyData)AssetCloner.Clone(subTreeHierarchy); clonedHierarchy.Entities[sourceRootEntity].Transform.Parent = null; // set to null reference outside of the sub-tree EntityAnalysis.FixupEntityReferences(clonedHierarchy); // temporary nullify the hierarchy to avoid to clone it var sourceHierarchy = source.Hierarchy; source.Hierarchy = null; // clone asset without hierarchy var clonedAsset = (EntityAsset)AssetCloner.Clone(source); clonedAsset.Hierarchy = clonedHierarchy; // revert the source hierarchy source.Hierarchy = sourceHierarchy; return clonedAsset; }
public static EntityAsset ExtractSceneClone(EntityAsset source, Guid sourceRootEntity) { if (source == null) { throw new ArgumentNullException("source"); } // Note: Instead of copying the whole asset (with its potentially big hierarchy), we first copy the asset only (without the hierarchy), then the sub-hierarchy to extract. // create the hierarchy of the sub-tree var subTreeRoot = source.Hierarchy.Entities[sourceRootEntity]; var subTreeHierarchy = new EntityHierarchyData { Entities = { subTreeRoot }, RootEntities = { sourceRootEntity } }; foreach (var subTreeEntity in subTreeRoot.EnumerateChildren(true)) { subTreeHierarchy.Entities.Add(subTreeEntity); } // clone the entities of the sub-tree var clonedHierarchy = (EntityHierarchyData)AssetCloner.Clone(subTreeHierarchy); clonedHierarchy.Entities[sourceRootEntity].Transform.Parent = null; // set to null reference outside of the sub-tree EntityAnalysis.FixupEntityReferences(clonedHierarchy); // temporary nullify the hierarchy to avoid to clone it var sourceHierarchy = source.Hierarchy; source.Hierarchy = null; // clone asset without hierarchy var clonedAsset = (EntityAsset)AssetCloner.Clone(source); clonedAsset.Hierarchy = clonedHierarchy; // revert the source hierarchy source.Hierarchy = sourceHierarchy; return(clonedAsset); }
public static EntityHierarchyData ImportScene(UFile sourceUrl, EntityAsset source, Guid sourceRootEntity, out EntityBase entityBase) { if (source == null) { throw new ArgumentNullException("source"); } // Extract the scene starting from given root var newAsset = ExtractSceneClone(source, sourceRootEntity); // Generate entity mapping var entityMapping = new Dictionary <Guid, Guid>(); var reverseEntityMapping = new Dictionary <Guid, Guid>(); foreach (var entity in newAsset.Hierarchy.Entities) { // Generate new Id var newEntityId = Guid.NewGuid(); // Update mappings entityMapping.Add(newEntityId, entity.Id); reverseEntityMapping.Add(entity.Id, newEntityId); // Update entity with new id entity.Id = newEntityId; } // Rewrite entity references // Should we nullify invalid references? EntityAnalysis.RemapEntitiesId(newAsset.Hierarchy, reverseEntityMapping); // Add asset base entityBase = new EntityBase { Base = new AssetBase(sourceUrl, newAsset), SourceRoot = sourceRootEntity, IdMapping = entityMapping }; return(newAsset.Hierarchy); }
public void TestEntitySerialization() { var entityAsset = new EntityAsset(); var entity1 = new Entity { Id = Guid.NewGuid() }; var entity2 = new Entity { Id = Guid.NewGuid() }; entity1.Transform.Children.Add(entity2.Transform); entityAsset.Hierarchy.Entities.Add(entity1); entityAsset.Hierarchy.Entities.Add(entity2); using (var stream = new MemoryStream()) { AssetSerializer.Save(stream, entityAsset); stream.Position = 0; var serializedVersion = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(serializedVersion); stream.Position = 0; var entityAsset2 = AssetSerializer.Load(stream, "pdxentity"); } }
private static Entity CreateTrackingEntity(EntityAsset entityAsset, Entity rootEntityAsset, ModelAsset modelAsset, string nodeName) { var childEntity = new Entity { Name = nodeName }; // Add TransformComponent childEntity.Add(TransformComponent.Key, new TransformComponent()); // Add ModelNodeLinkComponent childEntity.Add(ModelNodeLinkComponent.Key, new ModelNodeLinkComponent { NodeName = nodeName, Target = rootEntityAsset.Get(ModelComponent.Key), }); // Add this asset to the list entityAsset.Hierarchy.Entities.Add(childEntity); // Get or create transformation component var transformationComponent = rootEntityAsset.GetOrCreate(TransformComponent.Key); // Mark node as preserved modelAsset.PreserveNodes(new List<string> { nodeName }); // Add as children of model entity transformationComponent.Children.Add(childEntity.GetOrCreate(TransformComponent.Key)); return childEntity; }
public static void UpdateScene(EntityAsset source, EntityAsset dest, Guid destRootEntityId) { if (source == null) { throw new ArgumentNullException("source"); } if (dest == null) { throw new ArgumentNullException("dest"); } EntityBase entityBase; if (!dest.AssetBases.TryGetValue(destRootEntityId, out entityBase)) { throw new InvalidOperationException("This entity base was not found with given Id."); } var entityBaseAsset = (EntityAsset)entityBase.Base.Asset; // Extract the scene starting from given root var clonedSource = ExtractSceneClone(source, entityBase.SourceRoot); // Process entities in mapping var entitiesDiff3 = new List <EntityDiff3>(); var entitiesSourceId = new HashSet <Guid>(entityBase.IdMapping.Values); var oppositeMapping = entityBase.IdMapping.ToDictionary(x => x.Value, x => x.Key); foreach (var entityIdEntry in entityBase.IdMapping) { var entityDiff3 = new EntityDiff3(); var destEntityId = entityIdEntry.Key; var sourceEntityId = entityIdEntry.Value; // Get entity in dest asset (if not there anymore, we can simply skip them, they have been deleted so they can be ignored from future merges) if (!dest.Hierarchy.Entities.TryGetValue(destEntityId, out entityDiff3.Asset1)) { continue; } // Get entity in updated asset clonedSource.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Asset2); // Get entity in base (previous import) entityBaseAsset.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Base); entitiesDiff3.Add(entityDiff3); } // Merge foreach (var entityDiff3 in entitiesDiff3) { throw new NotImplementedException(); //entityDiff3.MergeResult = AssetMerge.Merge(entityDiff3.Base, entityDiff3.Asset1, entityDiff3.Asset2, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); // TODO: Proper logging and error recovery if (entityDiff3.MergeResult.HasErrors) { throw new InvalidOperationException("Merge error"); } } // We gather entities that were added in our source since last import // Note: We only cares about the ones that are in source but not in base -- everything else should be in entityBase.IdMapping // (otherwise it means entity has been deleted already in dest and/or source, so merge is deleted) var sourceExtraIds = new HashSet <Guid>(clonedSource.Hierarchy.Entities.Select(x => x.Id)); // Everything in source, sourceExtraIds.ExceptWith(entityBaseAsset.Hierarchy.Entities.Select(x => x.Id)); // but not in base, sourceExtraIds.ExceptWith(entitiesSourceId); // and not in entityBase.IdMapping... foreach (var sourceEntityId in sourceExtraIds) { var entityDiff3 = new EntityDiff3(); // Get entity in updated asset clonedSource.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Asset2); // Add it in our new entity, if possible at the same location var asset = entityDiff3.Asset2; var parentSourceEntity = FindParent(clonedSource.Hierarchy, entityDiff3.Asset2); Guid parentDestEntityId; if (!oppositeMapping.TryGetValue(parentSourceEntity.Id, out parentDestEntityId)) { continue; } } // Rebuild tree foreach (var entityDiff3 in entitiesDiff3) { // TODO: Try to propagate tree changes (it's not a big deal if we fail, but try to do it as good as possible) } }
public static void UpdateScene(EntityAsset source, EntityAsset dest, Guid destRootEntityId) { if (source == null) throw new ArgumentNullException("source"); if (dest == null) throw new ArgumentNullException("dest"); EntityBase entityBase; if (!dest.AssetBases.TryGetValue(destRootEntityId, out entityBase)) throw new InvalidOperationException("This entity base was not found with given Id."); var entityBaseAsset = (EntityAsset)entityBase.Base.Asset; // Extract the scene starting from given root var clonedSource = ExtractSceneClone(source, entityBase.SourceRoot); // Process entities in mapping var entitiesDiff3 = new List<EntityDiff3>(); var entitiesSourceId = new HashSet<Guid>(entityBase.IdMapping.Values); var oppositeMapping = entityBase.IdMapping.ToDictionary(x => x.Value, x => x.Key); foreach (var entityIdEntry in entityBase.IdMapping) { var entityDiff3 = new EntityDiff3(); var destEntityId = entityIdEntry.Key; var sourceEntityId = entityIdEntry.Value; // Get entity in dest asset (if not there anymore, we can simply skip them, they have been deleted so they can be ignored from future merges) if (!dest.Hierarchy.Entities.TryGetValue(destEntityId, out entityDiff3.Asset1)) continue; // Get entity in updated asset clonedSource.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Asset2); // Get entity in base (previous import) entityBaseAsset.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Base); entitiesDiff3.Add(entityDiff3); } // Merge foreach (var entityDiff3 in entitiesDiff3) { throw new NotImplementedException(); //entityDiff3.MergeResult = AssetMerge.Merge(entityDiff3.Base, entityDiff3.Asset1, entityDiff3.Asset2, AssetMergePolicies.MergePolicyAsset2AsNewBaseOfAsset1); // TODO: Proper logging and error recovery if (entityDiff3.MergeResult.HasErrors) throw new InvalidOperationException("Merge error"); } // We gather entities that were added in our source since last import // Note: We only cares about the ones that are in source but not in base -- everything else should be in entityBase.IdMapping // (otherwise it means entity has been deleted already in dest and/or source, so merge is deleted) var sourceExtraIds = new HashSet<Guid>(clonedSource.Hierarchy.Entities.Select(x => x.Id)); // Everything in source, sourceExtraIds.ExceptWith(entityBaseAsset.Hierarchy.Entities.Select(x => x.Id)); // but not in base, sourceExtraIds.ExceptWith(entitiesSourceId); // and not in entityBase.IdMapping... foreach (var sourceEntityId in sourceExtraIds) { var entityDiff3 = new EntityDiff3(); // Get entity in updated asset clonedSource.Hierarchy.Entities.TryGetValue(sourceEntityId, out entityDiff3.Asset2); // Add it in our new entity, if possible at the same location var asset = entityDiff3.Asset2; var parentSourceEntity = FindParent(clonedSource.Hierarchy, entityDiff3.Asset2); Guid parentDestEntityId; if (!oppositeMapping.TryGetValue(parentSourceEntity.Id, out parentDestEntityId)) continue; } // Rebuild tree foreach (var entityDiff3 in entitiesDiff3) { // TODO: Try to propagate tree changes (it's not a big deal if we fail, but try to do it as good as possible) } }
public static EntityHierarchyData ImportScene(UFile sourceUrl, EntityAsset source, Guid sourceRootEntity, out EntityBase entityBase) { if (source == null) throw new ArgumentNullException("source"); // Extract the scene starting from given root var newAsset = ExtractSceneClone(source, sourceRootEntity); // Generate entity mapping var entityMapping = new Dictionary<Guid, Guid>(); var reverseEntityMapping = new Dictionary<Guid, Guid>(); foreach (var entity in newAsset.Hierarchy.Entities) { // Generate new Id var newEntityId = Guid.NewGuid(); // Update mappings entityMapping.Add(newEntityId, entity.Id); reverseEntityMapping.Add(entity.Id, newEntityId); // Update entity with new id entity.Id = newEntityId; } // Rewrite entity references // Should we nullify invalid references? EntityAnalysis.RemapEntitiesId(newAsset.Hierarchy, reverseEntityMapping); // Add asset base entityBase = new EntityBase { Base = new AssetBase(sourceUrl, newAsset), SourceRoot = sourceRootEntity, IdMapping = entityMapping }; return newAsset.Hierarchy; }
private static AssetItem ImportEntity(List<AssetItem> assetReferences, UFile localPath, AssetItem modelItem) { var entityUrl = new UFile(localPath.GetFileName(), null); // TODO: Entities do not have source anymore, if this is needed again we should make scene assets that do not inherits from entity assets. var asset = new EntityAsset(); // { Source = localPath }; var rootEntityData = new Entity(); asset.Hierarchy.Entities.Add(rootEntityData); asset.Hierarchy.RootEntity = rootEntityData.Id; rootEntityData.Name = entityUrl; // Use modelUrl.Path to get the url without the extension rootEntityData.Add(ModelComponent.Key, new ModelComponent { Model = AttachedReferenceManager.CreateSerializableVersion<Rendering.Model>(modelItem.Id, modelItem.Location) }); var assetReference = new AssetItem(entityUrl, asset); assetReferences.Add(assetReference); return assetReference; }
private static AssetItem ImportEntity(List<AssetItem> assetReferences, UFile localPath, AssetItem modelItem) { var entityUrl = new UFile(localPath.GetFileName(), null); var asset = new EntityAsset { Source = localPath }; var rootEntityData = new Entity(); asset.Hierarchy.Entities.Add(rootEntityData); asset.Hierarchy.RootEntity = rootEntityData.Id; rootEntityData.Name = entityUrl; // Use modelUrl.Path to get the url without the extension rootEntityData.Add(ModelComponent.Key, new ModelComponent { Model = AttachedReferenceManager.CreateSerializableVersion<Rendering.Model>(modelItem.Id, modelItem.Location) }); var assetReference = new AssetItem(entityUrl, asset); assetReferences.Add(assetReference); return assetReference; }