/// <summary> /// Creates the new parameter of the given type. /// </summary> /// <param name="type">The type.</param> /// <returns></returns> public static SurfaceParameter Create(ParameterType type) { // Create new parameter with default values var param = new SurfaceParameter { ID = Guid.NewGuid(), IsPublic = true, IsStatic = false, IsUIEditable = true, IsUIVisible = true, Name = "New parameter", Type = type }; // Initialize default value in a proper way switch (type) { case ParameterType.Bool: param.Value = false; break; case ParameterType.Inteager: param.Value = 0; break; case ParameterType.Float: param.Value = 0.0f; break; case ParameterType.Vector2: param.Value = Vector2.Zero; break; case ParameterType.Vector3: param.Value = Vector3.Zero; break; case ParameterType.Vector4: param.Value = Vector4.Zero; break; case ParameterType.Color: param.Value = Color.White; break; case ParameterType.CubeTexture: case ParameterType.Texture: case ParameterType.NormalMap: case ParameterType.RenderTarget: param.Value = Guid.Empty; break; default: throw new IndexOutOfRangeException(); } return(param); }
/// <inheritdoc /> public void OnParamDeleted(SurfaceParameter param) { for (int i = 0; i < _nodes.Count; i++) { if (_nodes[i] is IParametersDependantNode node) { node.OnParamDeleted(param); } } MarkAsEdited(); }
/// <summary> /// Gets the parameter by the given name. /// </summary> /// <param name="name">The name.</param> /// <returns>Found parameter instance or null if missing.</returns> public SurfaceParameter GetParameter(string name) { SurfaceParameter result = null; for (int i = 0; i < Parameters.Count; i++) { var parameter = Parameters[i]; if (parameter.Name == name) { result = parameter; break; } } return(result); }
/// <summary> /// Gets the parameter by the given ID. /// </summary> /// <param name="id">The identifier.</param> /// <returns>Found parameter instance or null if missing.</returns> public SurfaceParameter GetParameter(Guid id) { SurfaceParameter result = null; for (int i = 0; i < Parameters.Count; i++) { var parameter = Parameters[i]; if (parameter.ID == id) { result = parameter; break; } } return(result); }
private void Add() { var type = Type; if (IsAdd && type.Type == typeof(NormalMap)) { type = new ScriptType(typeof(Texture)); } var param = SurfaceParameter.Create(type, Name); if (IsAdd && Type.Type == typeof(NormalMap)) { param.Value = FlaxEngine.Content.LoadAsyncInternal <Texture>("Engine/Textures/NormalTexture"); } Window.VisjectSurface.Parameters.Insert(Index, param); Window.VisjectSurface.OnParamCreated(param); Window.OnParamAddUndo(); }
/// <summary> /// Creates the new parameter of the given type. /// </summary> /// <param name="type">The type.</param> /// <returns>The created parameter.</returns> public static SurfaceParameter Create(ParameterType type) { // Create new parameter with default values var param = new SurfaceParameter { ID = Guid.NewGuid(), IsPublic = true, IsStatic = false, IsUIEditable = true, IsUIVisible = true, Name = "New parameter", Type = type }; // Initialize default value in a proper way switch (type) { case ParameterType.Bool: param.Value = false; break; case ParameterType.Integer: param.Value = 0; break; case ParameterType.Float: param.Value = 0.0f; break; case ParameterType.Vector2: param.Value = Vector2.Zero; break; case ParameterType.Vector3: param.Value = Vector3.Zero; break; case ParameterType.Vector4: param.Value = Vector4.Zero; break; case ParameterType.Color: param.Value = Color.White; break; case ParameterType.Matrix: param.Value = Matrix.Identity; break; case ParameterType.String: param.Value = string.Empty; break; case ParameterType.Box: param.Value = BoundingBox.Zero; break; case ParameterType.Rectangle: param.Value = Rectangle.Empty; break; case ParameterType.Rotation: param.Value = Quaternion.Identity; break; case ParameterType.Transform: param.Value = Transform.Identity; break; case ParameterType.SceneTexture: param.Value = 0; break; case ParameterType.Asset: case ParameterType.Actor: case ParameterType.CubeTexture: case ParameterType.Texture: case ParameterType.NormalMap: case ParameterType.RenderTarget: case ParameterType.RenderTargetArray: case ParameterType.RenderTargetCube: case ParameterType.RenderTargetVolume: param.Value = Guid.Empty; break; default: throw new IndexOutOfRangeException(); } return(param); }
private void LoadGraph(BinaryReader stream) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error throw new Exception("Invalid Graph format version"); } // Engine Build uint engineBuild = stream.ReadUInt32(); // Load1 { // Time saved (not used anymore to prevent binary diffs after saving unmodified surface) stream.ReadInt64(); byte[] guidBytes = new byte[16]; // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } List <ConnectionHint> tmpHints = _cachedConnections.Value; tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { // ID uint id = stream.ReadUInt32(); // Type ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node SurfaceNode node; if (groupId == Archetypes.Custom.GroupID) { node = new Archetypes.Custom.DummyCustomNode(id, this); } else { node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); } if (node == null) { // Error throw new Exception("Cannot create graph node."); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); // Properties param.Type = (ParameterType)stream.ReadByte(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = Utils.ReadStr(stream, 97); param.IsPublic = stream.ReadByte() != 0; param.IsStatic = stream.ReadByte() != 0; param.IsUIVisible = stream.ReadByte() != 0; param.IsUIEditable = stream.ReadByte() != 0; // References int refsCount = stream.ReadInt32(); param.ReferencedBy.Capacity = refsCount; for (int j = 0; j < refsCount; j++) { uint refID = stream.ReadUInt32(); var node = FindNode(refID); if (node == null) { // Error Editor.LogWarning($"Invalid node reference id (param: {param.Name}, node ref: {refID})"); } else { param.ReferencedBy.Add(node); } } // Value Utils.ReadCommonValue(stream, ref param.Value); // Meta param.Meta.Load(engineBuild, stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; int valuesCnt = stream.ReadInt32(); int firstValueReadIdx = 0; // Special case for custom nodes if (node is Archetypes.Custom.DummyCustomNode dummyCustom) { // TODO: maybe reuse the same dummy node (static) because is only a placeholder // Values check if (valuesCnt < 2) { throw new Exception("Missing custom nodes data."); } // Node typename check object typeName = null; Utils.ReadCommonValue(stream, ref typeName); firstValueReadIdx = 1; if (string.IsNullOrEmpty(typeName as string)) { throw new Exception("Missing custom node typename."); } // Find custom node archetype that matches this node type (it must be unique) var customNodes = _surface.GetCustomNodes(); if (customNodes?.Archetypes == null) { throw new Exception("Cannot find any custom nodes archetype."); } NodeArchetype arch = null; for (int j = 0; j < customNodes.Archetypes.Length; j++) { if (string.Equals(Archetypes.Custom.GetNodeTypeName(customNodes.Archetypes[j]), (string)typeName, StringComparison.OrdinalIgnoreCase)) { arch = customNodes.Archetypes[j]; break; } } if (arch == null) { throw new Exception("Missing custom node " + typeName); } // Create custom node and replace dummy placeholder node = NodeFactory.CreateNode(dummyCustom.ID, this, customNodes, arch); if (node == null) { throw new Exception("Failed to create custom node " + typeName); } Nodes[i] = node; // Store node typename in values container node.Values[0] = typeName; } // Values int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = firstValueReadIdx; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException Utils.ReadCommonValue(stream, ref node.Values[j]); } } else { Editor.LogWarning(String.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy = null; for (int j = firstValueReadIdx; j < valuesCnt; j++) { Utils.ReadCommonValue(stream, ref dummy); } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); uint type = stream.ReadUInt32(); ushort connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node.ID; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = targetNodeID; hint.BoxA = targetBoxID; tmpHints.Add(hint); } } // Meta node.Meta.Load(engineBuild, stream); OnControlLoaded(node); } // Visject Meta _meta.Load(engineBuild, stream); // Setup connections for (int i = 0; i < tmpHints.Count; i++) { var c = tmpHints[i]; var nodeA = FindNode(c.NodeA); var nodeB = FindNode(c.NodeB); if (nodeA == null || nodeB == null) { // Error Editor.LogWarning("Invalid connected node id."); continue; } var boxA = nodeA.GetBox(c.BoxA); var boxB = nodeB.GetBox(c.BoxB); if (boxA != null && boxB != null) { boxA.Connections.Add(boxB); } } // Ending char byte end = stream.ReadByte(); if (end != '\t') { // Error throw new Exception("Invalid data."); } } }
internal static GraphParameterData[] InitGraphParameters(IEnumerable <MaterialParameter> parameters, Material material) { int count = parameters.Count(); var data = new GraphParameterData[count]; int i = 0; // Load material surface parameters meta to use it for material instance parameters editing SurfaceParameter[] surfaceParameters = null; try { Profiler.BeginEvent("Init Material Parameters UI Data"); if (material != null && !material.WaitForLoaded()) { var surfaceData = material.LoadSurface(false); if (surfaceData != null && surfaceData.Length > 0) { using (var memoryStream = new MemoryStream(surfaceData)) using (var stream = new BinaryReader(memoryStream)) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error throw new Exception("Invalid Graph format version"); } // Version var version = stream.ReadUInt32(); var guidBytes = new byte[16]; if (version < 7000) { // Time saved (not used anymore to prevent binary diffs after saving unmodified surface) stream.ReadInt64(); // Nodes count int nodesCount = stream.ReadInt32(); // Parameters count int parametersCount = stream.ReadInt32(); // For each node for (int j = 0; j < nodesCount; j++) { // ID stream.ReadUInt32(); // Type stream.ReadUInt16(); stream.ReadUInt16(); } // For each param surfaceParameters = new SurfaceParameter[parametersCount]; for (int j = 0; j < parametersCount; j++) { // Create param var param = new SurfaceParameter(); surfaceParameters[j] = param; // Properties param.Type = new ScriptType(VisjectSurfaceContext.GetGraphParameterValueType((VisjectSurfaceContext.GraphParamType_Deprecated)stream.ReadByte())); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; var isStatic = stream.ReadByte() != 0; var isUIVisible = stream.ReadByte() != 0; var isUIEditable = stream.ReadByte() != 0; // References [Deprecated] int refsCount = stream.ReadInt32(); for (int k = 0; k < refsCount; k++) { stream.ReadUInt32(); } // Value stream.ReadCommonValue(ref param.Value); // Meta param.Meta.Load(stream); } } else if (version == 7000) { // Nodes count int nodesCount = stream.ReadInt32(); // Parameters count int parametersCount = stream.ReadInt32(); // For each node for (int j = 0; j < nodesCount; j++) { // ID stream.ReadUInt32(); // Type stream.ReadUInt16(); stream.ReadUInt16(); } // For each param surfaceParameters = new SurfaceParameter[parametersCount]; for (int j = 0; j < parametersCount; j++) { // Create param var param = new SurfaceParameter(); surfaceParameters[j] = param; // Properties param.Type = stream.ReadVariantScriptType(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; // Value param.Value = stream.ReadVariant(); // Meta param.Meta.Load(stream); } } } } } } catch (Exception ex) { Editor.LogError("Failed to get material parameters metadata."); Editor.LogWarning(ex); } finally { Profiler.EndEvent(); } foreach (var parameter in parameters) { var surfaceParameter = surfaceParameters?.FirstOrDefault(x => x.ID == parameter.ParameterID); var attributes = surfaceParameter?.Meta.GetAttributes() ?? FlaxEngine.Utils.GetEmptyArray <Attribute>(); data[i] = new GraphParameterData(null, parameter.Name, parameter.IsPublic, ToType(parameter.ParameterType), attributes, parameter); i++; } Array.Sort(data, GraphParameterData.Compare); return(data); }
private unsafe bool loadGraph(BinaryReader stream) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error Debug.LogWarning("Invalid Grpah format version"); return(true); } // Engine Build uint engineBuild = stream.ReadUInt32(); // Load1 { // Time saved DateTime tiemSaved = new DateTime(stream.ReadInt64()); byte[] guidBytes = new byte[16]; // Nodes count int nodesCount = stream.ReadInt32(); if (_nodes.Capacity < nodesCount) { _nodes.Capacity = nodesCount; } List <ConnectionHint> tmpHints = new List <ConnectionHint>(nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { // ID uint id = stream.ReadUInt32(); // Type ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node var node = NodeFactory.CreateNode(id, this, groupId, typeId); if (node == null) { // Error return(true); } _nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); // Properties param.Type = (ParameterType)stream.ReadByte(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = ReadStr(stream, 97); param.IsPublic = stream.ReadByte() != 0; param.IsStatic = stream.ReadByte() != 0; param.IsUIVisible = stream.ReadByte() != 0; param.IsUIEditable = stream.ReadByte() != 0; // References int refsCount = stream.ReadInt32(); param.ReferencedBy.Capacity = refsCount; for (int j = 0; j < refsCount; j++) { uint refID = stream.ReadUInt32(); var node = FindNode(refID); if (node == null) { // Error Debug.LogWarning($"Invalid node reference id (param: {param.Name}, node ref: {refID})"); } else { param.ReferencedBy.Add(node); } } // Value ReadCommonValue(stream, ref param.Value); // Meta param.Meta.Load(engineBuild, stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = _nodes[i]; // Values int valuesCnt = stream.ReadInt32(); int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = 0; j < valuesCnt; j++) { ReadCommonValue(stream, ref node.Values[j]); } } else { Debug.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy = null; for (int j = 0; j < valuesCnt; j++) { ReadCommonValue(stream, ref dummy); } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); uint type = stream.ReadUInt32(); ushort connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = FindNode(targetNodeID); if (hint.NodeA == null) { // Error Debug.LogWarning("Invalid connected node id."); } else { hint.BoxA = targetBoxID; tmpHints.Add(hint); } } } // Meta node.Meta.Load(engineBuild, stream); OnNodeLoaded(node); } // Visject Meta Meta.Load(engineBuild, stream); // Setup connections for (int i = 0; i < tmpHints.Count; i++) { var c = tmpHints[i]; var boxA = c.NodeA.GetBox(c.BoxA); var boxB = c.NodeB.GetBox(c.BoxB); if (boxA != null && boxB != null) { boxA.Connections.Add(boxB); } } // Ending char byte end = stream.ReadByte(); if (end != '\t') { // Error Debug.LogWarning("Invalid data."); return(true); } } return(false); }
private void LoadGraph(BinaryReader stream) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error throw new Exception("Invalid Graph format version"); } // Engine Build uint engineBuild = stream.ReadUInt32(); // Load1 { // Time saved (not used anymore to prevent binary diffs after saving unmodified surface) stream.ReadInt64(); byte[] guidBytes = new byte[16]; // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } List <ConnectionHint> tmpHints = _cachedConnections.Value; tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { // ID uint id = stream.ReadUInt32(); // Type ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node var node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); if (node == null) { // Error throw new Exception("Cannot create graph node."); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); // Properties param.Type = (ParameterType)stream.ReadByte(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = Utils.ReadStr(stream, 97); param.IsPublic = stream.ReadByte() != 0; param.IsStatic = stream.ReadByte() != 0; param.IsUIVisible = stream.ReadByte() != 0; param.IsUIEditable = stream.ReadByte() != 0; // References int refsCount = stream.ReadInt32(); param.ReferencedBy.Capacity = refsCount; for (int j = 0; j < refsCount; j++) { uint refID = stream.ReadUInt32(); var node = FindNode(refID); if (node == null) { // Error Editor.LogWarning($"Invalid node reference id (param: {param.Name}, node ref: {refID})"); } else { param.ReferencedBy.Add(node); } } // Value Utils.ReadCommonValue(stream, ref param.Value); // Meta param.Meta.Load(engineBuild, stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; // Values int valuesCnt = stream.ReadInt32(); int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = 0; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException Utils.ReadCommonValue(stream, ref node.Values[j]); } } else { Editor.LogWarning(String.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy = null; for (int j = 0; j < valuesCnt; j++) { Utils.ReadCommonValue(stream, ref dummy); } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); uint type = stream.ReadUInt32(); ushort connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = FindNode(targetNodeID); if (hint.NodeA == null) { // Error Editor.LogWarning("Invalid connected node id."); } else { hint.BoxA = targetBoxID; tmpHints.Add(hint); } } } // Meta node.Meta.Load(engineBuild, stream); OnControlLoaded(node); } // Visject Meta _meta.Load(engineBuild, stream); // Setup connections for (int i = 0; i < tmpHints.Count; i++) { var c = tmpHints[i]; var boxA = c.NodeA.GetBox(c.BoxA); var boxB = c.NodeB.GetBox(c.BoxB); if (boxA != null && boxB != null) { boxA.Connections.Add(boxB); } } // Ending char byte end = stream.ReadByte(); if (end != '\t') { // Error throw new Exception("Invalid data."); } } }
private void LoadGraph(BinaryReader stream) { // IMPORTANT! This must match C++ Graph format // Magic Code int tmp = stream.ReadInt32(); if (tmp != 1963542358) { // Error throw new Exception("Invalid Graph format version"); } // Version var version = stream.ReadUInt32(); var tmpHints = _cachedConnections.Value; var guidBytes = new byte[16]; if (version < 7000) { // Time saved (not used anymore to prevent binary diffs after saving unmodified surface) stream.ReadInt64(); // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { // ID uint id = stream.ReadUInt32(); // Type ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node SurfaceNode node; if (groupId == Archetypes.Custom.GroupID) { node = new DummyCustomNode(id, this); } else { node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); } if (node == null) { node = new MissingNode(id, this, groupId, typeId); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); // Properties param.Type = new ScriptType(GetGraphParameterValueType((GraphParamType_Deprecated)stream.ReadByte())); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; bool isStatic = stream.ReadByte() != 0; bool isUIVisible = stream.ReadByte() != 0; bool isUIEditable = stream.ReadByte() != 0; // References [Deprecated] int refsCount = stream.ReadInt32(); for (int j = 0; j < refsCount; j++) { uint refID = stream.ReadUInt32(); } // Value stream.ReadCommonValue(ref param.Value); // Meta param.Meta.Load(stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; int valuesCnt = stream.ReadInt32(); int firstValueReadIdx = 0; // Special case for missing nodes if (node is DummyCustomNode customNode) { node = null; // Values check if (valuesCnt < 2) { throw new Exception("Missing custom nodes data."); } // Node typename check object typeNameValue = null; stream.ReadCommonValue(ref typeNameValue); firstValueReadIdx = 1; string typeName = typeNameValue as string ?? string.Empty; // Find custom node archetype that matches this node type (it must be unique) var customNodes = _surface.GetCustomNodes(); if (customNodes?.Archetypes != null && typeName.Length != 0) { NodeArchetype arch = null; foreach (var nodeArchetype in customNodes.Archetypes) { if (string.Equals(Archetypes.Custom.GetNodeTypeName(nodeArchetype), typeName, StringComparison.OrdinalIgnoreCase)) { arch = nodeArchetype; break; } } if (arch != null) { node = NodeFactory.CreateNode(customNode.ID, this, customNodes, arch); } } // Fallback to the if (node == null) { Editor.LogWarning(string.Format("Cannot find custom node archetype for {0}", typeName)); node = new MissingNode(customNode.ID, this, Archetypes.Custom.GroupID, customNode.Archetype.TypeID); } Nodes[i] = node; // Store node typename in values container node.Values[0] = typeName; } if (node is MissingNode) { // Read all values Array.Resize(ref node.Values, valuesCnt); for (int j = firstValueReadIdx; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException stream.ReadCommonValue(ref node.Values[j]); } firstValueReadIdx = valuesCnt = node.Values.Length; } // Values int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = firstValueReadIdx; j < valuesCnt; j++) { // ReSharper disable once PossibleNullReferenceException stream.ReadCommonValue(ref node.Values[j]); } } else { Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy = null; for (int j = firstValueReadIdx; j < valuesCnt; j++) { stream.ReadCommonValue(ref dummy); if (j < nodeValuesCnt && dummy != null && node.Values[j] != null && node.Values[j].GetType() == dummy.GetType()) { node.Values[j] = dummy; } } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); stream.ReadUInt32(); // Skip type ushort connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node.ID; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = targetNodeID; hint.BoxA = targetBoxID; tmpHints.Add(hint); } } // Meta node.Meta.Load(stream); OnControlLoaded(node); } } else if (version == 7000) { // Nodes count int nodesCount = stream.ReadInt32(); if (Nodes.Capacity < nodesCount) { Nodes.Capacity = nodesCount; } tmpHints.Clear(); tmpHints.Capacity = Mathf.Max(tmpHints.Capacity, nodesCount * 4); // Parameters count int parametersCount = stream.ReadInt32(); if (Parameters.Capacity < parametersCount) { Parameters.Capacity = parametersCount; } // For each node for (int i = 0; i < nodesCount; i++) { uint id = stream.ReadUInt32(); ushort typeId = stream.ReadUInt16(); ushort groupId = stream.ReadUInt16(); // Create node SurfaceNode node; if (groupId == Archetypes.Custom.GroupID) { node = new DummyCustomNode(id, this); } else { node = NodeFactory.CreateNode(_surface.NodeArchetypes, id, this, groupId, typeId); } if (node == null) { node = new MissingNode(id, this, groupId, typeId); } Nodes.Add(node); } // For each param for (int i = 0; i < parametersCount; i++) { // Create param var param = new SurfaceParameter(); Parameters.Add(param); param.Type = stream.ReadVariantScriptType(); stream.Read(guidBytes, 0, 16); param.ID = new Guid(guidBytes); param.Name = stream.ReadStr(97); param.IsPublic = stream.ReadByte() != 0; // Value param.Value = stream.ReadVariant(); // Meta param.Meta.Load(stream); } // For each node for (int i = 0; i < nodesCount; i++) { var node = Nodes[i]; int valuesCnt = stream.ReadInt32(); int firstValueReadIdx = 0; // Special case for missing nodes if (node is DummyCustomNode customNode) { node = null; // Values check if (valuesCnt < 2) { throw new Exception("Missing custom nodes data."); } // Node typename check object typeNameValue = stream.ReadVariant(); firstValueReadIdx = 1; string typeName = typeNameValue as string ?? string.Empty; // Find custom node archetype that matches this node type (it must be unique) var customNodes = _surface.GetCustomNodes(); if (customNodes?.Archetypes != null && typeName.Length != 0) { NodeArchetype arch = null; foreach (var nodeArchetype in customNodes.Archetypes) { if (string.Equals(Archetypes.Custom.GetNodeTypeName(nodeArchetype), typeName, StringComparison.OrdinalIgnoreCase)) { arch = nodeArchetype; break; } } if (arch != null) { node = NodeFactory.CreateNode(customNode.ID, this, customNodes, arch); } } // Fallback to the if (node == null) { Editor.LogWarning(string.Format("Cannot find custom node archetype for {0}", typeName)); node = new MissingNode(customNode.ID, this, Archetypes.Custom.GroupID, customNode.Archetype.TypeID); } Nodes[i] = node; // Store node typename in values container node.Values[0] = typeName; } if (node is MissingNode) { // Read all values Array.Resize(ref node.Values, valuesCnt); for (int j = firstValueReadIdx; j < valuesCnt; j++) { node.Values[j] = stream.ReadVariant(); } firstValueReadIdx = valuesCnt = node.Values.Length; } // Values int nodeValuesCnt = node.Values?.Length ?? 0; if (valuesCnt == nodeValuesCnt) { for (int j = firstValueReadIdx; j < valuesCnt; j++) { node.Values[j] = stream.ReadVariant(); } } else { Editor.LogWarning(string.Format("Invalid node values. Loaded: {0}, expected: {1}. Type: {2}, {3}", valuesCnt, nodeValuesCnt, node.Archetype.Title, node.Archetype.TypeID)); object dummy; for (int j = firstValueReadIdx; j < valuesCnt; j++) { dummy = stream.ReadVariant(); if (j < nodeValuesCnt && dummy != null && node.Values[j] != null && node.Values[j].GetType() == dummy.GetType()) { node.Values[j] = dummy; } } } // Boxes ushort boxesCount = stream.ReadUInt16(); for (int j = 0; j < boxesCount; j++) { var id = stream.ReadByte(); stream.ReadVariantType(); // Skip type var connectionsCnt = stream.ReadUInt16(); ConnectionHint hint; hint.NodeB = node.ID; hint.BoxB = id; for (int k = 0; k < connectionsCnt; k++) { uint targetNodeID = stream.ReadUInt32(); byte targetBoxID = stream.ReadByte(); hint.NodeA = targetNodeID; hint.BoxA = targetBoxID; tmpHints.Add(hint); } } // Meta node.Meta.Load(stream); OnControlLoaded(node); } } else { throw new Exception($"Unsupported graph version {version}."); } // Visject Meta _meta.Load(stream); // Setup connections for (int i = 0; i < tmpHints.Count; i++) { var c = tmpHints[i]; var nodeA = FindNode(c.NodeA); var nodeB = FindNode(c.NodeB); if (nodeA == null || nodeB == null) { // Error Editor.LogWarning("Invalid connected node id."); continue; } var boxA = nodeA.GetBox(c.BoxA); var boxB = nodeB.GetBox(c.BoxB); if (boxA != null && boxB != null) { boxA.Connections.Add(boxB); } } // Ending char byte end = stream.ReadByte(); if (end != '\t') { throw new Exception("Invalid data."); } }