296 lines
13 KiB
C#
296 lines
13 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Windows;
|
|
using System.Xml;
|
|
using System.Xml.Serialization;
|
|
using DynamicData;
|
|
using Intromat.Helpers;
|
|
using Intromat.PersistentModel.Nodes;
|
|
using Intromat.ViewModels;
|
|
using Intromat.ViewModels.Nodes;
|
|
using NodeNetwork.ViewModels;
|
|
|
|
namespace Intromat.PersistentModel
|
|
{
|
|
internal class ProjectSerializer
|
|
{
|
|
public static async Task<ProjectViewModel?> LoadProject(MainViewModel mainVm, string fullPath)
|
|
{
|
|
await using var stream = new FileStream(fullPath, FileMode.Open);
|
|
var projectSerializer = new XmlSerializer(typeof(ProjectModel));
|
|
var project = (ProjectModel)projectSerializer.Deserialize(stream)!;
|
|
var projectVm = new ProjectViewModel(project.Name, Path.GetFullPath(fullPath));
|
|
var directory = Path.GetDirectoryName(projectVm.FullPath)!;
|
|
foreach (var modulePath in project.Modules)
|
|
{
|
|
var moduleFullPath = Path.Combine(directory, modulePath);
|
|
var moduleVm = await LoadModule(mainVm, projectVm, moduleFullPath);
|
|
projectVm.Modules.Add(moduleVm);
|
|
}
|
|
|
|
return projectVm;
|
|
}
|
|
|
|
public static async Task<ModuleViewModel> LoadModule(MainViewModel mainVm, ProjectViewModel parent, string fullPath)
|
|
{
|
|
var moduleVm = new ModuleViewModel(parent, Path.GetFileName(fullPath)!, fullPath);
|
|
await LoadFolder(mainVm, moduleVm, moduleVm, moduleVm, fullPath);
|
|
return moduleVm;
|
|
}
|
|
|
|
private static async Task LoadFolder(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel parent, FolderViewModel target, string folderPath)
|
|
{
|
|
foreach (var subFolderPath in Directory.EnumerateDirectories(folderPath))
|
|
{
|
|
var subFolderVm = new FolderViewModel(moduleVm, parent, Path.GetDirectoryName(folderPath)!);
|
|
await LoadFolder(mainVm, moduleVm, target, subFolderVm, subFolderPath);
|
|
target.Folders.Add(subFolderVm);
|
|
}
|
|
|
|
foreach (var filePath in Directory.EnumerateFiles(folderPath))
|
|
{
|
|
switch (Path.GetExtension(filePath))
|
|
{
|
|
case ".igraph":
|
|
{
|
|
target.Files.Add(await LoadDocument(mainVm, moduleVm, target, filePath));
|
|
break;
|
|
}
|
|
case ".hlsl":
|
|
{
|
|
target.Files.Add(await LoadShader(mainVm, moduleVm, target, filePath));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task<DocumentViewModel> LoadDocument(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel folderVm, string filePath)
|
|
{
|
|
await using var stream = new FileStream(filePath, FileMode.Open);
|
|
var networkSerializer = new XmlSerializer(typeof(NetworkModel));
|
|
var network = (NetworkModel)networkSerializer.Deserialize(stream)!;
|
|
var documentVm = new DocumentViewModel(mainVm, moduleVm, folderVm, Path.GetFileNameWithoutExtension(filePath));
|
|
LoadNetwork(documentVm.MainNetwork, network, documentVm);
|
|
return documentVm;
|
|
}
|
|
|
|
private static async Task<ShaderFileViewModel> LoadShader(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel folderVm, string filePath)
|
|
{
|
|
await using var stream = new FileStream(filePath, FileMode.Open);
|
|
var shaderFileVm = new ShaderFileViewModel(mainVm, moduleVm, folderVm, Path.GetFileNameWithoutExtension(filePath));
|
|
using var reader = new StreamReader(stream);
|
|
shaderFileVm.Source = await reader.ReadToEndAsync();
|
|
return shaderFileVm;
|
|
}
|
|
|
|
public static CodeGenNetworkViewModel LoadNetwork(CodeGenNetworkViewModel networkVm, NetworkModel network, DocumentViewModel documentVm, GroupNodeViewModel? baseGroup = null)
|
|
{
|
|
PreLoadNetwork(network, documentVm, baseGroup, networkVm, out var nodeMap);
|
|
PostLoadNetwork(network, networkVm, nodeMap);
|
|
|
|
return networkVm;
|
|
}
|
|
|
|
private static void PreLoadNetwork(NetworkModel network, DocumentViewModel documentVm, GroupNodeViewModel? baseGroup, CodeGenNetworkViewModel networkVm, out Dictionary<Guid, NodeViewModel> outNodeMap)
|
|
{
|
|
var nodeMap = outNodeMap = new Dictionary<Guid, NodeViewModel>();
|
|
GroupSubnetIONodeViewModel? entrance = null, exit = null;
|
|
var groups = new List<GroupModel>();
|
|
networkVm.Nodes.Edit(nodes =>
|
|
{
|
|
foreach (var node in network.Nodes.Items)
|
|
{
|
|
var nodeVm = node.CreateViewModel()!;
|
|
nodeVm.LoadModel(node);
|
|
nodes.Add(nodeVm);
|
|
nodeMap.Add(node.Guid, nodeVm);
|
|
if (nodeVm is GroupSubnetIONodeViewModel subnetIONodeVm)
|
|
{
|
|
Debug.Assert(baseGroup != null, nameof(baseGroup) + " != null");
|
|
if (subnetIONodeVm.IsEntranceNode)
|
|
{
|
|
entrance = subnetIONodeVm;
|
|
}
|
|
else
|
|
{
|
|
exit = subnetIONodeVm;
|
|
}
|
|
}
|
|
else if (node is GroupModel group)
|
|
{
|
|
groups.Add(group);
|
|
}
|
|
}
|
|
});
|
|
|
|
if (baseGroup != null && entrance != null && exit != null)
|
|
{
|
|
var groupBinding = new CodeNodeGroupIOBinding(baseGroup, entrance, exit);
|
|
baseGroup.IOBinding = groupBinding;
|
|
entrance.IOBinding = groupBinding;
|
|
exit.IOBinding = groupBinding;
|
|
}
|
|
|
|
foreach (var group in groups)
|
|
{
|
|
var groupVm = (GroupNodeViewModel)nodeMap[group.Guid];
|
|
var subNetworkVm = new CodeGenNetworkViewModel(documentVm, group.Name);
|
|
PreLoadNetwork(group.Network, documentVm, groupVm, subNetworkVm, out var subNetworkNodeMap);
|
|
var ioBinding = groupVm.IOBinding!;
|
|
groupVm.Inputs.Edit(inputs =>
|
|
{
|
|
foreach (var input in group.Inputs)
|
|
{
|
|
var valueType = Type.GetType(input.EndpointType)!;
|
|
var inputVm = ioBinding.CreateInput(input.PortType, input.Name, valueType);
|
|
inputVm.SortIndex = input.SortIndex;
|
|
inputs.Add(inputVm);
|
|
}
|
|
});
|
|
groupVm.Outputs.Edit(outputs =>
|
|
{
|
|
foreach (var output in group.Outputs)
|
|
{
|
|
var valueType = Type.GetType(output.EndpointType)!;
|
|
var outputVm = ioBinding.CreateOutput(output.PortType, output.Name, valueType, output.List);
|
|
outputVm.SortIndex = output.SortIndex;
|
|
outputs.Add(outputVm);
|
|
}
|
|
});
|
|
|
|
groupVm.Subnet = subNetworkVm;
|
|
groupVm.Name = subNetworkVm.Name;
|
|
PostLoadNetwork(group.Network, subNetworkVm, subNetworkNodeMap);
|
|
}
|
|
}
|
|
|
|
private static void PostLoadNetwork(NetworkModel network, CodeGenNetworkViewModel networkVm, Dictionary<Guid, NodeViewModel> nodeMap)
|
|
{
|
|
networkVm.Connections.Edit(connections =>
|
|
{
|
|
foreach (var connection in network.Connections)
|
|
{
|
|
var inputVm = nodeMap[connection.Input.Node];
|
|
var outputVm = nodeMap[connection.Output.Node];
|
|
var input = inputVm.Inputs.Items.Single(i => i.Name == connection.Input.Name);
|
|
var output = outputVm.Outputs.Items.Single(o => o.Name == connection.Output.Name);
|
|
((CodeGenPortViewModel)input.Port).IsPortVisible = true;
|
|
((CodeGenPortViewModel)output.Port).IsPortVisible = true;
|
|
var connectionVm = new ConnectionViewModel(networkVm, input, output);
|
|
connections.Add(connectionVm);
|
|
}
|
|
});
|
|
|
|
foreach (var metaData in network.MetaData)
|
|
{
|
|
var nodeVm = nodeMap[metaData.Node];
|
|
nodeVm.Position = new Point(metaData.Position.X, metaData.Position.Y);
|
|
nodeVm.IsCollapsed = metaData.IsCollapsed;
|
|
}
|
|
}
|
|
|
|
public static async Task<ProjectModel> SaveModel(ProjectViewModel projectVm)
|
|
{
|
|
var directoryName = Path.GetDirectoryName(projectVm.FullPath)!;
|
|
Directory.CreateDirectory(directoryName);
|
|
await using var stream = new FileStream(projectVm.FullPath, FileMode.Create);
|
|
await using var writer = new XmlTextWriter(stream, Encoding.UTF8) { Formatting = Formatting.Indented };
|
|
var project = new ProjectModel { Name = projectVm.Name };
|
|
foreach (var moduleVm in projectVm.Modules)
|
|
{
|
|
project.Modules.Add(IOHelper.GetRelativePath(directoryName, moduleVm.FullPath));
|
|
await SaveModel(moduleVm);
|
|
}
|
|
var projectSerializer = new XmlSerializer(typeof(ProjectModel));
|
|
projectSerializer.Serialize(writer, project, NodeCollectionModel._nameSpaces);
|
|
return project;
|
|
}
|
|
|
|
public static async Task SaveModel(FolderViewModel folderVm)
|
|
{
|
|
foreach (var subFolderVm in folderVm.Folders.Items)
|
|
{
|
|
await SaveModel(subFolderVm);
|
|
}
|
|
foreach (var documentVm in folderVm.Files.Items)
|
|
{
|
|
await SaveModel(documentVm);
|
|
}
|
|
}
|
|
|
|
private static async Task SaveModel(FileViewModel fileVm)
|
|
{
|
|
Directory.CreateDirectory(Path.GetDirectoryName(fileVm.FullPath)!);
|
|
await using var stream = new FileStream(fileVm.FullPath, FileMode.Create);
|
|
switch (fileVm)
|
|
{
|
|
case DocumentViewModel documentVm:
|
|
{
|
|
var network = SaveModel(documentVm.MainNetwork);
|
|
await using var writer = new XmlTextWriter(stream, Encoding.UTF8) { Formatting = Formatting.Indented };
|
|
var moduleSerializer = new XmlSerializer(typeof(NetworkModel));
|
|
moduleSerializer.Serialize(writer, network, NodeCollectionModel._nameSpaces);
|
|
break;
|
|
}
|
|
case ShaderFileViewModel shaderVm:
|
|
{
|
|
var shader = shaderVm.Source;
|
|
await using var writer = new StreamWriter(stream);
|
|
await writer.WriteAsync(shader);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
}
|
|
}
|
|
|
|
public static NetworkModel SaveModel(CodeGenNetworkViewModel networkVm)
|
|
{
|
|
Debug.Assert(networkVm.Name != null, $"{nameof(networkVm)}.{nameof(networkVm.Name)} != null");
|
|
var network = new NetworkModel();
|
|
|
|
foreach (var item in networkVm.Nodes.Items)
|
|
{
|
|
var nodeVm = (CodeGenNodeViewModel)item;
|
|
var node = nodeVm.CreateModel();
|
|
nodeVm.SaveModel(node);
|
|
network.Nodes.Items.Add(node);
|
|
}
|
|
|
|
foreach (var connectionVm in networkVm.Connections.Items)
|
|
{
|
|
var connection = new ConnectionModel
|
|
{
|
|
Input = new EndpointModel { Name = connectionVm.Input.Name, Node = ((CodeGenNodeViewModel)connectionVm.Input.Parent).Guid },
|
|
Output = new EndpointModel { Name = connectionVm.Output.Name, Node = ((CodeGenNodeViewModel)connectionVm.Output.Parent).Guid },
|
|
};
|
|
network.Connections.Add(connection);
|
|
}
|
|
|
|
foreach (var nodeVm in networkVm.Nodes.Items)
|
|
{
|
|
var metaData = new NodeMetaData
|
|
{
|
|
Position = new PositionModel
|
|
{
|
|
X = nodeVm.Position.X,
|
|
Y = nodeVm.Position.Y
|
|
},
|
|
IsCollapsed = nodeVm.IsCollapsed,
|
|
Node = ((CodeGenNodeViewModel)nodeVm).Guid
|
|
};
|
|
network.MetaData.Add(metaData);
|
|
}
|
|
|
|
return network;
|
|
}
|
|
}
|
|
} |