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); } }