public InlineFunctionNodeFactory(string name, Script script) { var segments = name.Split('.'); Category = segments.Take(segments.Length - 2).Select(_ => FilterName(_)).ToArray(); Type = Name = FilterName(segments[segments.Length - 2]); _script = script.Clone(); _script.ClearGroups(); var nodesUsedInGraph = new HashSet <int>(_script.Nodes.SelectMany(_ => _.InputPins).Select(_ => _.Connection).Where(_ => _ != null).Select(_ => _.NodeId)); foreach (var scriptNode in _script.Nodes) { if (NodeTypes.IsConnectorType(scriptNode.Type)) { if (scriptNode.InputPins[0].Connection == null) { _inputPins.Add(new PinWithConnection(scriptNode.Name, scriptNode.InputPins[0].Type)); } else if (!nodesUsedInGraph.Contains(scriptNode.Id)) { _outputPins.Add(new Pin(scriptNode.Name, scriptNode.OutputPins[0].Type)); } } } InputTypes = _inputPins.Select(_ => _.Type).Distinct().ToList(); OutputTypes = _outputPins.Select(_ => _.Type).Distinct().ToList(); }
private void ElimitateConnectors() { foreach (var nodeHelper in Script.Nodes.ToArray()) { if (NodeTypes.IsConnectorType(nodeHelper.Type)) { ElimitateConnector(nodeHelper); } } }
public void Inline(ScriptHelper <TranslatedMaterialGraph.NodeInfo> script, NodeHelper <TranslatedMaterialGraph.NodeInfo> scriptNode) { var nodes = script.Merge(_script).ToList(); foreach (var node in nodes) { node.Id = scriptNode.Id; if (NodeTypes.IsConnectorType(node.Type)) { var hasInputConnections = node.InputPins[0].Links.Any(); var hasOutputConnections = node.OutputPins[0].Links.Any(); if (!hasOutputConnections && hasInputConnections) { var pin = scriptNode.OutputPins[node.Name]; if (pin == null) { throw new MaterialCompilationException("Output pin " + node.Name + " not found", scriptNode.Id); } if (pin.Type != node.OutputPins[0].Type) { throw new MaterialCompilationException( "Output pin " + node.Name + " mismatch: expected " + node.InputPins[0].Type + " but found " + pin.Type); } script.CopyConnections(pin, node.OutputPins[0]); } else if (hasOutputConnections && !hasInputConnections) { var pin = scriptNode.InputPins[node.Name]; if (pin == null) { throw new MaterialCompilationException("Input pin " + node.Name + " not found", scriptNode.Id); } if (pin.Type != node.InputPins[0].Type) { throw new MaterialCompilationException( "Input pin " + node.Name + " mismatch: expected " + node.InputPins[0].Type + " but found " + pin.Type); } script.CopyConnections(pin, node.InputPins[0]); } } } script.Nodes.Remove(scriptNode); }
public string GenerateCode(NodeHelper <TranslatedMaterialGraph.NodeInfo> node) { if (node.Type == NodeTypes.Special.Variable) { return(GenerateVarCode(node)); } if (node.Extra.Define.IsIfDef) { return(GenerateIfDef(node)); } //if (node.Type == NodeTypes.Texture2DSampler2DVec2 // || node.Type == NodeTypes.Texture2DSampler2DVec2Float // || node.Type == NodeTypes.TextureCubeSamplerCubeVec3 // || node.Type == NodeTypes.TextureCubeSamplerCubeVec3Float // ) //{ // if (node.InputPins["sampler"].Links.Count == 0) // { // return "vec4(0.0,0.0,0.0,0.0)"; // } //} var args = node.InputPins.Select(_ => GenerateCode(_)).ToList(); if (NodeTypes.IsConnectorType(node.Type)) { return(args[0]); } if (NodeTypes.IsIfDefType(node.Type)) { throw new InvalidOperationException("ifdef should be handeled at var code path"); } if (node.Type == NodeTypes.VertexData) { return("i" + node.OutputPins[0].Id); } if (NodeTypes.IsAttribute(node.Type)) { if (node.Name == "BlendIndices") { return("ivec4(i" + node.Name + ")"); } return("i" + node.Name); } if (NodeTypes.IsUniform(node.Type)) { return("c" + node.Name); } if (NodeTypes.IsParameter(node.Type)) { return("c" + node.Name); } string constType; if (NodeTypes._constants.TryGetValue(node.Type, out constType)) { return(GetConstantValue(node.Value, constType)); } switch (node.Type) { case NodeTypes.Function: return(node.Name + "(" + string.Join(",", args) + ")"); case NodeTypes.Special.Default: return(GenerateDefaultValue(node.OutputPins[0].Type)); case NodeTypes.Special.ShadowMapOutput: _writer.WriteLine(null, " #ifdef VSM_SHADOW"); _writer.WriteLine(null, " float depth = " + args[0] + ".x / " + args[0] + ".y * 0.5 + 0.5;"); _writer.WriteLine(null, " gl_FragColor = vec4(depth, depth * depth, 1.0, 1.0);"); _writer.WriteLine(null, " #else"); _writer.WriteLine(null, " gl_FragColor = vec4(1.0);"); _writer.WriteLine(null, " #endif"); return(null); case NodeTypes.Special.FinalColor: _writer.WriteLine(null, "gl_FragColor = " + args[0] + ";"); return(null); case NodeTypes.Special.FragData0: _writer.WriteLine(null, "gl_FragData[0] = " + args[0] + ";"); return(null); case NodeTypes.Special.FragData1: _writer.WriteLine(null, "gl_FragData[1] = " + args[0] + ";"); return(null); case NodeTypes.Special.FragData2: _writer.WriteLine(null, "gl_FragData[2] = " + args[0] + ";"); return(null); case NodeTypes.Special.FragData3: _writer.WriteLine(null, "gl_FragData[3] = " + args[0] + ";"); return(null); case NodeTypes.FragCoord: return("gl_FragCoord"); case NodeTypes.FrontFacing: return("gl_FrontFacing"); case NodeTypes.LightColor: case NodeTypes.Opacity: case NodeTypes.AmbientColor: case NodeTypes.RefractionColor: case NodeTypes.PerPixelFloat: case NodeTypes.PerPixelVec2: case NodeTypes.PerPixelVec3: case NodeTypes.PerPixelVec4: return(args[0]); case NodeTypes.ObjectData: case NodeTypes.LightData: case NodeTypes.CameraData: case NodeTypes.ZoneData: throw new InvalidOperationException( "This code shouldn't be executed. All uniforms must be split into individual nodes on preprocessing."); case NodeTypes.Special.SetVarying: { var arg = args[0]; var actualType = GetType(node.InputPins[0].Type); var varyingType = GetVaryingType(node.InputPins[0].Type); if (actualType != varyingType) { arg = varyingType + "(" + arg + ")"; } var connectedNode = node.InputPins[0].ConnectedPins.FirstOrDefault()?.Node; if (connectedNode != null && addComments) { _writer.WriteLine(null, "// based on node " + connectedNode.Name + " " + connectedNode.Value + " (type:" + connectedNode.Type + ", id:" + connectedNode.Id + "), cost estimation: " + connectedNode.Extra.EstimatedCost); } _writer.WriteLine(node.Extra.Define.Expression, "v" + node.Value + " = " + arg + ";"); } return(null); case NodeTypes.Discard: _writer.WriteLine(null, "if (" + args[0] + ") discard;"); return(null); case NodeTypes.Special.GetVarying: { var arg = "v" + node.Value; var actualType = GetType(node.OutputPins[0].Type); var varyingType = GetVaryingType(node.OutputPins[0].Type); if (actualType != varyingType) { arg = actualType + "(" + arg + ")"; } return(arg); } case NodeTypes.Sampler2D: case NodeTypes.Sampler3D: case NodeTypes.SamplerCube: return(GetSamplerName(node)); //_writer.WriteLine("uniform "+node.OutputPins.First().Type+" s" + GetSamplerName(node) + ";"); case NodeTypes.BreakVec4ToVec3AndFloat: case NodeTypes.BreakVec3ToVec2AndFloat: case NodeTypes.BreakVec4ToVec2AndVec2: case NodeTypes.BreakVec4ToVec2AndFloats: case NodeTypes.BreakVec2: case NodeTypes.BreakVec3: case NodeTypes.BreakVec4: if (node.OutputPins.Count != 1) { throw new InvalidOperationException(node + " expected to have a single output."); } return(args[0] + "." + node.OutputPins[0].Id.ToLower()); case NodeTypes.MultiplyFloatFloat: case NodeTypes.MultiplyVec2Float: case NodeTypes.MultiplyVec3Float: case NodeTypes.MultiplyVec4Float: case NodeTypes.MultiplyVec2Vec2: case NodeTypes.MultiplyVec3Vec3: case NodeTypes.MultiplyVec4Vec4: case NodeTypes.MultiplyVec4Mat4: case NodeTypes.MultiplyVec3Mat3: case NodeTypes.MultiplyMat3Vec3: case NodeTypes.MultiplyMat4x3Float: case NodeTypes.MultiplyMat4Float: return(GenBinaryOperator("*", args)); case NodeTypes.MultiplyVec4Mat4x3: return("(" + GenBinaryOperator("*", args) + ").xyz"); //case NodeTypes.MultiplyVec3Mat4: //case NodeTypes.MultiplyVec3Mat4x3: // return GenBinaryOperator("*", new []{ "vec4("+args[0]+", 1.0)", args[1] }); case NodeTypes.AddFloatFloat: case NodeTypes.AddVec2Vec2: case NodeTypes.AddVec3Vec3: case NodeTypes.AddVec4Vec4: case NodeTypes.AddMat4Mat4: case NodeTypes.AddMat4x3Mat4x3: return(GenBinaryOperator("+", args)); case NodeTypes.SubtractFloatFloat: case NodeTypes.SubtractVec2Vec2: case NodeTypes.SubtractVec3Vec3: case NodeTypes.SubtractVec4Vec4: return(GenBinaryOperator("-", args)); case NodeTypes.MinusFloat: case NodeTypes.MinusVec2: case NodeTypes.MinusVec3: case NodeTypes.MinusVec4: return(GenUnaryOperator("-", args)); case NodeTypes.SaturateFloat: return("clamp(" + args[0] + ", 0.0, 1.0)"); case NodeTypes.SaturateVec2: return("clamp(" + args[0] + ", vec2(0.0, 0.0), vec2(1.0, 1.0))"); case NodeTypes.SaturateVec3: return("clamp(" + args[0] + ", vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0))"); case NodeTypes.SaturateVec4: return("clamp(" + args[0] + ", vec4(0.0, 0.0, 0.0, 0.0), vec4(1.0, 1.0, 1.0, 1.0))"); case NodeTypes.DivideFloatFloat: case NodeTypes.DivideVec2Float: case NodeTypes.DivideVec3Float: case NodeTypes.DivideVec4Float: case NodeTypes.DivideVec2Vec2: case NodeTypes.DivideVec3Vec3: case NodeTypes.DivideVec4Vec4: return(GenBinaryOperator("/", args)); case NodeTypes.TernaryFloat: case NodeTypes.TernaryVec2: case NodeTypes.TernaryVec3: case NodeTypes.TernaryVec4: return("((" + args[0] + ")?(" + args[1] + "):(" + args[2] + "))"); case NodeTypes.MakeVec4FromVec3: return(node.OutputPins[0].Type + "(" + string.Join(", ", args) + ", 1.0)"); case NodeTypes.MakeMat4x3FromVec4Vec4Vec4: return("mat4(" + string.Join(", ", args) + ", vec4(0.0, 0.0, 0.0, 1.0))"); case NodeTypes.MakeVec4FromVec3AndFloat: case NodeTypes.MakeVec4FromVec2AndVec2: case NodeTypes.MakeVec3FromVec2AndFloat: case NodeTypes.MakeVec2: case NodeTypes.MakeVec3: case NodeTypes.MakeVec4: case NodeTypes.MakeMat3FromVec3Vec3Vec3: return(node.OutputPins[0].Type + "(" + string.Join(", ", args) + ")"); case NodeTypes.MakeMat3FromMat4: case NodeTypes.MakeMat3FromMat4x3: return("GetNormalMatrix(" + string.Join(", ", args) + ")"); case NodeTypes.SampleVSMShadow: return("texture2D(" + string.Join(", ", args) + ").rg"); case NodeTypes.SkinMatrixIndex: return("mat4(" + args[0] + "[" + args[1] + "*3], " + args[0] + "[" + args[1] + "*3+1]," + args[0] + "[" + args[1] + "*3+2], vec4(0.0, 0.0, 0.0, 1.0))"); case NodeTypes.LightMatricesIndex: case NodeTypes.VertexLightsIndex: return(args[0] + "[" + args[1] + "]"); case NodeTypes.PositionOutput: return(args[0]); case NodeTypes.LessThanFloatFloat: return(GenBinaryOperator("<", args)); case NodeTypes.NotBool: return("!(" + args[0] + ")"); case NodeTypes.EqualFloatFloat: return(GenBinaryOperator("==", args)); case NodeTypes.NotEqualFloatFloat: return(GenBinaryOperator("!=", args)); case NodeTypes.GreaterThanFloatFloat: return(GenBinaryOperator(">", args)); case NodeTypes.LessThanEqualFloatFloat: return(GenBinaryOperator("<=", args)); case NodeTypes.GreaterThanEqualFloatFloat: return(GenBinaryOperator(">=", args)); case NodeTypes.AndAlso: return(GenBinaryOperator("&&", args)); case NodeTypes.OrElse: return(GenBinaryOperator("||", args)); default: var bracketIndex = node.Type.IndexOf("("); if (bracketIndex > 0) { return(node.Type.Substring(0, bracketIndex) + "(" + string.Join(", ", args) + ")"); } throw new MaterialCompilationException("Node " + node.Type + " isn't implemented yet.", node.Id); } }
public void Inline(ScriptViewModel script, NodeViewModel node) { var newScript = script.Script.Clone(); var group = new NodeGroup { Name = node.Name }; newScript.Groups.Add(group); var externalPins = new List <PinWithConnection>(); foreach (var scriptNode in newScript.Nodes) { foreach (var pinWithConnection in scriptNode.InputPins) { if (pinWithConnection.Connection != null && pinWithConnection.Connection.NodeId == node.Id) { externalPins.Add(pinWithConnection); } } } var newNodes = newScript.MergeWith(_script, (float)node.Position.X, (float)node.Position.Y); var inputConnectors = new Dictionary <string, ScriptNode>(); var outputConnectors = new Dictionary <string, ScriptNode>(); foreach (var scriptNode in newNodes) { scriptNode.GroupId = group.Id; if (NodeTypes.IsConnectorType(scriptNode.Type)) { if (scriptNode.InputPins[0].Connection == null) { inputConnectors.Add(scriptNode.Name, scriptNode); } else { outputConnectors.Add(scriptNode.Name, scriptNode); } } } foreach (var nodeInputPin in node.Node.InputPins) { if (nodeInputPin.Connection != null) { ScriptNode connector; if (inputConnectors.TryGetValue(nodeInputPin.Id, out connector)) { connector.InputPins[0].Connection = nodeInputPin.Connection; } } } foreach (var externalConnection in externalPins) { ScriptNode connector; if (outputConnectors.TryGetValue(externalConnection.Connection.PinId, out connector)) { externalConnection.Connection = new Connection(connector.Id, connector.OutputPins[0].Id); } else { externalConnection.Connection = null; } } newScript.Nodes.RemoveAt(node.Node.Id); script.Script = newScript; }