// // Convert from the "ViewModel" to the "Model" // // We don't maintain the ShaderPatcherLayer.NodeGraph representation // permanently... But we need this for serialization and shader // generation operations // // So, let's just build it from the graph control object. // public ShaderPatcherLayer.NodeGraph ToShaderPatcherLayer(HyperGraph.IGraphModel graph) { ShaderPatcherLayer.NodeGraph nodeGraph = new ShaderPatcherLayer.NodeGraph(); Dictionary <Node, int> nodeToVisualNodeId = new Dictionary <Node, int>(); foreach (Node n in graph.Nodes) { var nTag = n.Tag as ShaderFragmentNodeTag; if (nTag == null) { continue; } // Create a "visual node" (unless it already exists) // -- this contains information that only affects the rendered // graphs, not the output shader int visualNodeId; if (nodeToVisualNodeId.ContainsKey(n)) { visualNodeId = nodeToVisualNodeId[n]; } else { visualNodeId = nodeGraph.VisualNodes.Count(); nodeToVisualNodeId.Add(n, visualNodeId); nodeGraph.VisualNodes.Add( new ShaderPatcherLayer.VisualNode() { Location = n.Location, State = (n.Collapsed) ? ShaderPatcherLayer.VisualNode.StateType.Collapsed : ShaderPatcherLayer.VisualNode.StateType.Normal }); } // Potentially build a "node" in the patcher layer. This is only required // if we're referencing some object in the shader fragments archive if (!string.IsNullOrEmpty(nTag.ArchiveName)) { ShaderPatcherLayer.Node resultNode = new ShaderPatcherLayer.Node() { FragmentArchiveName = nTag.ArchiveName, NodeId = nTag.Id, VisualNodeId = visualNodeId }; if (n.Tag is ShaderParameterNodeTag) { // This is a hack... But there should be a drop down list that // can tell us the type of this parameter struct box. foreach (var i in n.Items) { if (i is HyperGraph.Items.NodeDropDownItem) { var dropDown = (HyperGraph.Items.NodeDropDownItem)i; var stringForm = dropDown.Items[dropDown.SelectedIndex]; var parameterSource = ShaderFragmentNodeCreator.AsEnumValue <ShaderFragmentArchive.Parameter.SourceType>(stringForm, ShaderFragmentNodeCreator.ParamSourceTypeNames); resultNode.NodeType = AsNodeType(parameterSource); } } } else { resultNode.NodeType = ShaderPatcherLayer.Node.Type.Procedure; } nodeGraph.Nodes.Add(resultNode); } // Build connections... foreach (NodeConnection connection in n.Connections) { if (connection.To != null) { var dstNode = connection.To.Node.Tag as ShaderFragmentNodeTag; if (dstNode == null) { continue; } var dstItem = connection.To.Item as ShaderFragmentNodeItem; if (dstItem == null) { continue; } if (connection.From == null && connection.To.Node == n) { // this is a direct constant connection. It connects the value either to a constant value, or some named variable nodeGraph.ConstantConnections.Add( new ShaderPatcherLayer.ConstantConnection() { Value = connection.Name, OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name }); } else if (connection.To.Node == n && connection.To.Item is ShaderFragmentInterfaceParameterItem) { // this is an output parameter. This is the only case where we creating the connection // while processing the node on the "out" side var outputParam = (ShaderFragmentInterfaceParameterItem)connection.To.Item; var resultConnection = new ShaderPatcherLayer.OutputParameterConnection { VisualNodeId = visualNodeId, // (visual node for the output box) Type = outputParam.Type, Name = outputParam.Name, Semantic = outputParam.Semantic }; if (connection.From.Item is ShaderFragmentNodeItem) { var tag = connection.From.Item.Node.Tag as ShaderFragmentNodeTag; if (tag != null) { resultConnection.InputNodeID = tag.Id; } resultConnection.InputParameterName = ((ShaderFragmentNodeItem)connection.From.Item).Name; } nodeGraph.OutputParameterConnections.Add(resultConnection); } else if (connection.From.Node == n) { if (connection.From.Item is ShaderFragmentInterfaceParameterItem) { // it's an input parameter... we just need type, name, semantic var inputParam = (ShaderFragmentInterfaceParameterItem)connection.From.Item; nodeGraph.InputParameterConnections.Add( new ShaderPatcherLayer.InputParameterConnection { OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name, VisualNodeId = visualNodeId, Type = inputParam.Type, Name = inputParam.Name, Semantic = inputParam.Semantic, Default = inputParam.Default }); } else if (connection.To.Item is ShaderFragmentInterfaceParameterItem) { // it's an output parameter... // this will be handled when processing the node on the out side } else { // This is an output to the next node var resultConnection = new ShaderPatcherLayer.NodeConnection() { InputNodeID = nTag.Id, OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name, OutputType = TypeFromNodeItem(dstItem) }; if (connection.From.Item is ShaderFragmentNodeItem) { var sourceItem = (ShaderFragmentNodeItem)connection.From.Item; resultConnection.InputParameterName = sourceItem.Name; resultConnection.InputType = TypeFromNodeItem(sourceItem); } nodeGraph.NodeConnections.Add(resultConnection); } } } else if (connection.From != null && connection.From.Node == n) { // when connection.To is null, it could be an attached output connection var resultConnection = new ShaderPatcherLayer.OutputParameterConnection() { Name = connection.Name, InputNodeID = nTag.Id }; if (connection.From.Item is ShaderFragmentNodeItem) { var sourceItem = (ShaderFragmentNodeItem)connection.From.Item; resultConnection.InputParameterName = sourceItem.Name; resultConnection.Type = TypeFromNodeItem(sourceItem); } nodeGraph.OutputParameterConnections.Add(resultConnection); } } // build the preview settings objects foreach (var i in n.Items) { var preview = i as ShaderFragmentPreviewItem; if (preview == null) { continue; } var settings = preview.PreviewSettings; settings.VisualNodeId = visualNodeId; nodeGraph.PreviewSettingsObjects.Add(settings); } } return(nodeGraph); }
// // Convert from the "ViewModel" to the "Model" // // We don't maintain the ShaderPatcherLayer.NodeGraph representation // permanently... But we need this for serialization and shader // generation operations // // So, let's just build it from the graph control object. // public ShaderPatcherLayer.NodeGraph ToShaderPatcherLayer(HyperGraph.IGraphModel graph) { ShaderPatcherLayer.NodeGraph nodeGraph = new ShaderPatcherLayer.NodeGraph(); Dictionary<Node, int> nodeToVisualNodeId = new Dictionary<Node, int>(); foreach (Node n in graph.Nodes) { var nTag = n.Tag as ShaderFragmentNodeTag; if (nTag == null) continue; // Create a "visual node" (unless it already exists) // -- this contains information that only affects the rendered // graphs, not the output shader int visualNodeId; if (nodeToVisualNodeId.ContainsKey(n)) { visualNodeId = nodeToVisualNodeId[n]; } else { visualNodeId = nodeGraph.VisualNodes.Count(); nodeToVisualNodeId.Add(n, visualNodeId); nodeGraph.VisualNodes.Add( new ShaderPatcherLayer.VisualNode() { Location = n.Location, State = (n.Collapsed) ? ShaderPatcherLayer.VisualNode.StateType.Collapsed : ShaderPatcherLayer.VisualNode.StateType.Normal }); } // Potentially build a "node" in the patcher layer. This is only required // if we're referencing some object in the shader fragments archive if (!string.IsNullOrEmpty(nTag.ArchiveName)) { ShaderPatcherLayer.Node resultNode = new ShaderPatcherLayer.Node() { FragmentArchiveName = nTag.ArchiveName, NodeId = nTag.Id, VisualNodeId = visualNodeId }; if (n.Tag is ShaderParameterNodeTag) { // This is a hack... But there should be a drop down list that // can tell us the type of this parameter struct box. foreach (var i in n.Items) { if (i is HyperGraph.Items.NodeDropDownItem) { var dropDown = (HyperGraph.Items.NodeDropDownItem)i; var stringForm = dropDown.Items[dropDown.SelectedIndex]; var parameterSource = ShaderFragmentNodeCreator.AsEnumValue<ShaderFragmentArchive.Parameter.SourceType>(stringForm, ShaderFragmentNodeCreator.ParamSourceTypeNames); resultNode.NodeType = AsNodeType(parameterSource); } } } else { resultNode.NodeType = ShaderPatcherLayer.Node.Type.Procedure; } nodeGraph.Nodes.Add(resultNode); } // Build connections... foreach (NodeConnection connection in n.Connections) { if (connection.To != null) { var dstNode = connection.To.Node.Tag as ShaderFragmentNodeTag; if (dstNode == null) continue; var dstItem = connection.To.Item as ShaderFragmentNodeItem; if (dstItem == null) continue; if (connection.From == null && connection.To.Node == n) { // this is a direct constant connection. It connects the value either to a constant value, or some named variable nodeGraph.ConstantConnections.Add( new ShaderPatcherLayer.ConstantConnection() { Value = connection.Name, OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name }); } else if (connection.To.Node == n && connection.To.Item is ShaderFragmentInterfaceParameterItem) { // this is an output parameter. This is the only case where we creating the connection // while processing the node on the "out" side var outputParam = (ShaderFragmentInterfaceParameterItem)connection.To.Item; var resultConnection = new ShaderPatcherLayer.OutputParameterConnection { VisualNodeId = visualNodeId, // (visual node for the output box) Type = outputParam.Type, Name = outputParam.Name, Semantic = outputParam.Semantic }; if (connection.From.Item is ShaderFragmentNodeItem) { var tag = connection.From.Item.Node.Tag as ShaderFragmentNodeTag; if (tag != null) resultConnection.InputNodeID = tag.Id; resultConnection.InputParameterName = ((ShaderFragmentNodeItem)connection.From.Item).Name; } nodeGraph.OutputParameterConnections.Add(resultConnection); } else if (connection.From.Node == n) { if (connection.From.Item is ShaderFragmentInterfaceParameterItem) { // it's an input parameter... we just need type, name, semantic var inputParam = (ShaderFragmentInterfaceParameterItem)connection.From.Item; nodeGraph.InputParameterConnections.Add( new ShaderPatcherLayer.InputParameterConnection { OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name, VisualNodeId = visualNodeId, Type = inputParam.Type, Name = inputParam.Name, Semantic = inputParam.Semantic, Default = inputParam.Default }); } else if (connection.To.Item is ShaderFragmentInterfaceParameterItem) { // it's an output parameter... // this will be handled when processing the node on the out side } else { // This is an output to the next node var resultConnection = new ShaderPatcherLayer.NodeConnection() { InputNodeID = nTag.Id, OutputNodeID = dstNode.Id, OutputParameterName = dstItem.Name, OutputType = TypeFromNodeItem(dstItem) }; if (connection.From.Item is ShaderFragmentNodeItem) { var sourceItem = (ShaderFragmentNodeItem)connection.From.Item; resultConnection.InputParameterName = sourceItem.Name; resultConnection.InputType = TypeFromNodeItem(sourceItem); } nodeGraph.NodeConnections.Add(resultConnection); } } } else if (connection.From != null && connection.From.Node == n) { // when connection.To is null, it could be an attached output connection var resultConnection = new ShaderPatcherLayer.OutputParameterConnection() { Name = connection.Name, InputNodeID = nTag.Id }; if (connection.From.Item is ShaderFragmentNodeItem) { var sourceItem = (ShaderFragmentNodeItem)connection.From.Item; resultConnection.InputParameterName = sourceItem.Name; resultConnection.Type = TypeFromNodeItem(sourceItem); } nodeGraph.OutputParameterConnections.Add(resultConnection); } } // build the preview settings objects foreach (var i in n.Items) { var preview = i as ShaderFragmentPreviewItem; if (preview == null) continue; var settings = preview.PreviewSettings; settings.VisualNodeId = visualNodeId; nodeGraph.PreviewSettingsObjects.Add(settings); } } return nodeGraph; }