port from perforce

This commit is contained in:
2026-04-18 22:31:51 +02:00
commit 8d0ab5b7cc
8409 changed files with 3972376 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
namespace Intromat.PersistentModel
{
public class ConnectionModel
{
public EndpointModel Input { get; set; } = null!;
public EndpointModel Output { get; set; } = null!;
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.ComponentModel;
using System.Xml.Serialization;
namespace Intromat.PersistentModel
{
public class EndpointModel
{
[XmlAttribute]
public Guid Node { get; set; }
[XmlAttribute]
[DefaultValue(null)]
public string Name { get; set; } = null!;
}
}

View File

@@ -0,0 +1,27 @@
using System.ComponentModel;
using System.Xml.Serialization;
using Intromat.ViewModels;
namespace Intromat.PersistentModel
{
public class GroupEndpointModel
{
[XmlAttribute]
public string EndpointType { get; set; } = null!;
[XmlAttribute]
public EPortType PortType { get; set; }
[XmlAttribute]
[DefaultValue(false)]
public bool List { get; set; }
[XmlAttribute]
[DefaultValue(null)]
public string Name { get; set; } = null!;
[XmlAttribute]
[DefaultValue(0)]
public int SortIndex { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Intromat.PersistentModel
{
[XmlRoot("Network", Namespace = NodeModelBase._namespace)]
public class NetworkModel
{
[XmlElement]
public NodeCollectionModel Nodes { get; set; } = new();
[XmlArray]
public List<ConnectionModel> Connections { get; set; } = new();
[XmlArray]
public List<NodeMetaData> MetaData { get; set; } = new();
[XmlArray]
public List<NetworkModel> SubNetworks { get; set; } = new();
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
namespace Intromat.PersistentModel
{
public class NodeCollectionModel : IXmlSerializable
{
public static readonly Dictionary<string, Type> _nodeTypes;
public static readonly XmlSerializerNamespaces _nameSpaces;
static NodeCollectionModel()
{
_nodeTypes = typeof(NodeModelBase)
.Assembly
.GetTypes()
.Where(t => typeof(NodeModelBase).IsAssignableFrom(t) && !t.IsAbstract)
.Select(type =>
{
var attrib = (XmlRootAttribute)type.GetCustomAttribute(typeof(XmlRootAttribute))!;
return (attrib.ElementName, Type: type);
})
.ToDictionary(pair => pair.ElementName, pair => pair.Type);
_nameSpaces = new XmlSerializerNamespaces();
_nameSpaces.Add(string.Empty, NodeModelBase._namespace);
_nameSpaces.Add("x", "http://www.w3.org/2001/XMLSchema-instance");
}
public List<NodeModelBase> Items { get; set; } = new();
public XmlSchema? GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
reader.MoveToContent();
var isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
if (!isEmptyElement)
{
while (reader.NodeType != XmlNodeType.EndElement)
{
if (_nodeTypes.TryGetValue(reader.Name, out var nodeType))
{
var serializer = new XmlSerializer(nodeType);
var node = (NodeModelBase)serializer.Deserialize(reader)!;
Items.Add(node);
}
}
reader.ReadEndElement();
}
}
public void WriteXml(XmlWriter writer)
{
if (Items.Count == 0)
return;
foreach (var node in Items)
{
var serializer = new XmlSerializer(node.GetType());
serializer.Serialize(writer, node, _nameSpaces);
}
}
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.ComponentModel;
namespace Intromat.PersistentModel
{
public class NodeMetaData
{
public Guid Node { get; set; }
public PositionModel Position { get; set; }
[DefaultValue(false)]
public bool IsCollapsed { get; set; }
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.ComponentModel;
using System.Xml.Serialization;
using Intromat.ViewModels;
namespace Intromat.PersistentModel
{
public abstract class NodeModelBase
{
public abstract CodeGenNodeViewModel? CreateViewModel();
[XmlAttribute]
public Guid Guid { get; set; }
[XmlAttribute]
[DefaultValue("")]
public string Name { get; set; } = "";
public const string _namespace = "http://blu-flame.org/intromat";
}
}

View File

@@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using Intromat.ViewModels;
using Intromat.ViewModels.Nodes;
namespace Intromat.PersistentModel.Nodes
{
[XmlRoot("Group", Namespace = _namespace)]
public class GroupModel : NodeModelBase
{
public NetworkModel Network { get; set; } = null!;
public Guid Entrance { get; set; }
public Guid Exit { get; set; }
public List<GroupEndpointModel> Inputs { get; set; } = new();
public List<GroupEndpointModel> Outputs { get; set; } = new();
public override CodeGenNodeViewModel CreateViewModel()
{
return new GroupNodeViewModel();
}
}
}

View File

@@ -0,0 +1,18 @@
using System.Xml.Serialization;
using Intromat.ViewModels;
using Intromat.ViewModels.Nodes;
namespace Intromat.PersistentModel.Nodes
{
[XmlRoot("GroupSubnetIO", Namespace = _namespace)]
public class GroupSubnetIOModel : NodeModelBase
{
[XmlAttribute]
public bool IsEntrance { get; set; }
public override CodeGenNodeViewModel CreateViewModel()
{
return new GroupSubnetIONodeViewModel();
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Windows;
using System.Xml.Serialization;
namespace Intromat.PersistentModel
{
public struct PositionModel
{
[XmlAttribute]
public double X { get; set; }
[XmlAttribute]
public double Y { get; set; }
public static implicit operator Point(PositionModel position)
{
return new(position.X, position.Y);
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Collections.Generic;
using System.Xml.Serialization;
namespace Intromat.PersistentModel
{
[XmlRoot("Project", Namespace = NodeModelBase._namespace)]
public class ProjectModel
{
[XmlAttribute]
public string Name { get; set; } = null!;
[XmlElement("Module")]
public List<string> Modules { get; set; } = new();
}
}

View File

@@ -0,0 +1,296 @@
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;
}
}
}