/// <summary> /// Combines the parameters of a given method into a single string. /// </summary> /// <param name="method">The method whose parameters needs to be joined.</param> /// <returns>The combined parameters as a <see cref="StringBuilder" />.</returns> protected virtual StringBuilder JoinParams(MethodDefinition method) { var result = new StringBuilder(); foreach (var param in method.Parameters) { var paramType = param.ParameterType.ToType(); if (!ShaderMapping.Types.ContainsKey(paramType)) { var strAdd = (paramType != typeof(Object)) ? " '" + paramType.Name + "'" : String.Empty; var instr = method.Body.Instructions[0]; DebugLog.Error("Method has a parameter of the unsupported type" + strAdd, instr); return(null); } var isRef = (param.ParameterType is ByReferenceType); var refStr = (isRef) ? "out " : String.Empty; var typeMapped = ShaderMapping.Types[paramType]; var paramName = param.Name; result.Append(refStr).Append(typeMapped).Space(); result.Append(paramName).Append(", "); } if (result.Length > 0) { result.Length -= 2; } return(result); }
/// <summary> /// Translates a while loop, e.g. "while (val) { ... }". /// </summary> /// <remarks> /// GLSLES does not support while loops. /// </remarks> public override StringBuilder VisitWhileStatement(WhileStatement whileStmt) { var instr = GetInstructionFromStmt(whileStmt.GetParent <Statement>()); DebugLog.Error("While loops are not supported in GLSLES", instr); return(new StringBuilder()); }
protected string MapDataTypeIfValid(AstType node, Type type) { if (type != null && ShaderMapping.Types.ContainsKey(type)) { return(ShaderMapping.Types[type]); } var instr = GetInstructionFromStmt(node.GetParent <Statement>()); DebugLog.Error("Type '" + type + "' is not supported", instr); return(null); }
/// <summary> /// Checks member variables before translating the shader. /// </summary> protected internal virtual void PreVariableCheck() { foreach (var memberVar in ShaderDesc.Variables) { var varName = memberVar.Definition.Name; var varType = memberVar.DataType; // resolve data type of variable if (!ShaderMapping.Types.ContainsKey(varType)) { var strAdd = (varType != typeof(Object)) ? " type '" + varType.Name + "' " : " a type "; DebugLog.Error(varType + varName + "' is of" + strAdd + "which is not supported."); } } }
/// <summary> /// Translates a type reference, e.g. "OtherClass.". /// </summary> public override StringBuilder VisitTypeReferenceExpression(TypeReferenceExpression typeRefExpr) { var memberRef = typeRefExpr.GetParent <MemberReferenceExpression>(); if (memberRef == null) { return(new StringBuilder()); } var instr = GetInstructionFromStmt(typeRefExpr.GetParent <Statement>()); var name = memberRef.MemberName; DebugLog.Error("Static member '" + name + "' of class '" + typeRefExpr.Type + "' cannot be used", instr); return(null); }
/// <summary> /// Maps the return type to the targeted shader language. /// </summary> /// <param name="method">The method whose return type needs to be mapped.</param> /// <returns></returns> protected virtual StringBuilder MapReturnType(MethodDefinition method) { var retType = method.ReturnType.ToType(); if (!ShaderMapping.Types.ContainsKey(retType)) { var strAdd = (retType != typeof(Object)) ? " '" + retType.Name + "'" : String.Empty; var instr = method.Body.Instructions[0]; DebugLog.Error("Method has an unsupported return type" + strAdd, instr); return(null); } return(new StringBuilder(ShaderMapping.Types[retType])); }
private static bool MethodExists(TypeDefinition asmType, string methodName, out MethodDefinition method) { var methodCount = asmType.Methods.Count(asmMethod => asmMethod.Name == methodName); method = asmType.Methods.FirstOrDefault(asmMethod => asmMethod.Name == methodName); if (methodCount <= 1 && method != null && method.IsVirtual) { return(true); } var instr = (method != null) ? method.Body.Instructions[0] : null; DebugLog.Error("You did not override method '" + methodName + "' properly", instr); return(false); }
/// <summary> /// Translates an unary expression, e.g. "value++". /// </summary> public override StringBuilder VisitUnaryOperatorExpression(UnaryOperatorExpression unaryOpExpr) { var result = new StringBuilder(); var expr = unaryOpExpr.Expression.AcceptVisitor(this); // unary operator type mapping var opPreAsngmt = new Dictionary <UnaryOperatorType, string> { { UnaryOperatorType.Decrement, "--" }, { UnaryOperatorType.Increment, "++" }, { UnaryOperatorType.Minus, "-" }, { UnaryOperatorType.Plus, "+" }, { UnaryOperatorType.BitNot, "~" }, { UnaryOperatorType.Not, "!" }, { UnaryOperatorType.PostDecrement, "--" }, { UnaryOperatorType.PostIncrement, "++" }, }; var opPostAsngmt = new Dictionary <UnaryOperatorType, string> { { UnaryOperatorType.PostDecrement, "--" }, { UnaryOperatorType.PostIncrement, "++" }, }; if (opPreAsngmt.ContainsKey(unaryOpExpr.Operator)) { result.Append(opPreAsngmt[unaryOpExpr.Operator]).Append(expr); } else if (opPostAsngmt.ContainsKey(unaryOpExpr.Operator)) { result.Append(expr).Append(opPostAsngmt[unaryOpExpr.Operator]); } else { var dInstr = GetInstructionFromStmt(unaryOpExpr.GetParent <Statement>()); DebugLog.Error("Unary operator '" + unaryOpExpr.Operator + "' is not supported", dInstr); } return(result); }
/// <summary> /// Tests the given shaders by passing them to the GLSL/HLSL compiler. /// </summary> /// <param name="vertexShader">The vertex shader.</param> /// <param name="fragmentShader">The fragment shader.</param> internal override void PreCompile(StringBuilder vertexShader, StringBuilder fragmentShader) { if (GLSLCompiler.CanCheck(ShaderDesc.Target.Version)) { if (ShaderDesc.Target.Envr == SLEnvironment.OpenGLES) { DebugLog.Warning("Shader will be tested on OpenGL but target is OpenGL ES"); } if (ShaderDesc.Target.Envr == SLEnvironment.OpenGLMix) { DebugLog.Warning("Shader will be tested on OpenGL but target is OpenGL and OpenGL ES"); } var vertTest = GLSLCompiler.CreateShader(vertexShader, SLShaderType.VertexShader); vertTest.Length = Math.Max(0, vertTest.Length - 3); vertTest = vertTest.Replace("0(", " => 0("); var fragTest = GLSLCompiler.CreateShader(fragmentShader, SLShaderType.FragmentShader); fragTest.Length = Math.Max(0, fragTest.Length - 3); fragTest = fragTest.Replace("0(", " => 0("); if (vertTest.Length > 0) { DebugLog.Error("OpenGL found problems while compiling vertex shader:\n" + vertTest); } else if (fragTest.Length > 0) { DebugLog.Error("OpenGL found problems while compiling fragment shader:\n" + fragTest); } else { Console.WriteLine(" => Test was successful. OpenGL did not find any problems."); } } else { DebugLog.Warning("Cannot test shader as your graphics card does not support the targeted version."); } }
/// <summary> /// Checks member variables before translating the shader. /// </summary> /// <remarks> /// GLSL 1.1 does not support data type 'double'. /// GLSL 1.1 does not support const arrays. /// </remarks> protected internal override void PreVariableCheck() { base.PreVariableCheck(); // no support for type 'double' var doubleVars = ShaderDesc.Variables.Where(var => var.DataType == typeof(double)); foreach (var doubleVar in doubleVars) { DebugLog.Warning("'" + doubleVar.Definition.Name + "' is of type 'double' which" + " is not supported in GLSL 1.1. Type will be changed to 'float'"); } // no support for const arrays var arrays = ShaderDesc.Variables.Where(var => var.IsArray); var constArrays = arrays.Where(var => var.Attribute == SLVariableType.xSLConstAttribute); foreach (var constArray in constArrays) { DebugLog.Error("'" + constArray.Definition.Name + "' is a const array. This" + " is not supported in GLSL 1.1"); } }
private static int Main(string[] args) { Console.WriteLine("---------------------- CrossSL V1.0 ----------------------"); if (args.Length == 0 || String.IsNullOrEmpty(args[0])) { DebugLog.UsageError("Start CrossSL with a .NET assemly as argument to translate\n" + "shaders from .NET to GLSL, e.g. 'CrossSL.exe Assembly.exe'"); return(-1); } string inputPath = args[0]; var asmName = Path.GetFileName(inputPath); var asmDir = Path.GetDirectoryName(inputPath); if (!File.Exists(inputPath)) { DebugLog.UsageError("Could not find assembly '" + asmName + "' in path:\n\n" + asmDir); return(-1); } // ReSharper disable once AssignNullToNotNullAttribute var metaPath = Path.Combine(asmDir, "CrossSL.Meta.dll"); if (!File.Exists(inputPath) || !File.Exists(metaPath)) { DebugLog.UsageError("Found assembly '" + asmName + "' but meta assembly 'CrossSL.Meta.dll'" + "\nis missing. It needs to be in the same directory:\n\n" + asmDir); return(-1); } Console.WriteLine("\n\nFound assembly '" + asmName + "' and meta assembly 'CrossSL.Meta.dll'."); // check if there is a .pdb file along with the .exe var debugFile = Path.ChangeExtension(inputPath, "pdb"); var debugName = Path.GetFileName(debugFile); DebugLog.Verbose = File.Exists(debugFile); Console.WriteLine(DebugLog.Verbose ? "Found also .pdb file '" + debugName + "'. This allows for better debugging." : "Found no .pdb file '" + debugName + "'. Extended debugging has been disabled."); // read assembly (and symbols) with Mono.Cecil var resolver = new DefaultAssemblyResolver(); resolver.AddSearchDirectory(asmDir); var readParams = new ReaderParameters { ReadSymbols = DebugLog.Verbose, AssemblyResolver = resolver }; var asm = AssemblyDefinition.ReadAssembly(inputPath, readParams); // read meta assembly (without symbols) with Mono.Cecil var metaParams = new ReaderParameters { ReadSymbols = false }; var metaAsm = AssemblyDefinition.ReadAssembly(metaPath, metaParams); // find all types with xSLShader as base type var shaderDescs = new List <ShaderDesc>(); var asmTypes = asm.Modules.SelectMany( asmMod => asmMod.Types.Where(asmType => asmType.BaseType != null)); var asmShaderTypes = asmTypes.Where(asmType => asmType.BaseType.IsType <xSLShader>()); foreach (var asmType in asmShaderTypes) { DebugLog.Reset(); if (DebugLog.Verbose) { // load symbols from pdb file var asmModule = asmType.Module; using (var symbReader = new PdbReaderProvider().GetSymbolReader(asmModule, debugFile)) asmModule.ReadSymbols(symbReader); } var asmTypeName = asmType.Name; Console.WriteLine("\n\nFound a shader called '" + asmTypeName + "':"); var shaderDesc = new ShaderDesc { Name = asmTypeName, Type = asmType }; // check for [xSLDebug] first in case the shader should be ignored var debugAttr = asmType.CustomAttributes.FirstOrDefault( attrType => attrType.AttributeType.IsType <xSLShader.xSLDebugAttribute>()); if (debugAttr != null) { shaderDesc.DebugFlags = (xSLShader.xSLDebug)debugAttr.ConstructorArguments[0].Value; if ((shaderDesc.DebugFlags & xSLShader.xSLDebug.IgnoreShader) != 0) { Console.WriteLine(" => Found [xSLDebug] with 'IgnoreShader' flag. Shader skipped."); continue; } } // check for [xSLTarget] and save settings var targetAttr = asmType.CustomAttributes.FirstOrDefault( attr => attr.AttributeType.IsType <xSLShader.xSLTargetAttribute>()); if (targetAttr == null) { shaderDesc.Target = new ShaderTarget { Envr = SLEnvironment.OpenGL, Version = 110, VersionID = 0 }; DebugLog.Error("Could not find [xSLTarget]. Please specify the targeted shading language"); } else { var typeName = targetAttr.ConstructorArguments[0].Type.Name; var versionID = (int)targetAttr.ConstructorArguments[0].Value; var shaderTarget = new ShaderTarget { VersionID = versionID }; switch (typeName) { case "GLSL": shaderTarget.Envr = SLEnvironment.OpenGL; break; case "GLSLES": shaderTarget.Envr = SLEnvironment.OpenGLES; break; case "GLSLMix": shaderTarget.Envr = SLEnvironment.OpenGLMix; break; } var vStr = SLVersion.VIDs[(int)shaderTarget.Envr][versionID]; shaderTarget.Version = Int32.Parse(vStr); shaderDesc.Target = shaderTarget; if (shaderTarget.Envr == SLEnvironment.OpenGLMix) { typeName = "GLSL 1.10 & GLSLES"; vStr = "100"; } vStr = vStr.Insert(1, "."); Console.WriteLine(" => Found [xSLTarget]. Compiling shader as " + typeName + " " + vStr + "."); } var shaderTranslator = ShaderTranslator.GetTranslator(shaderDesc.Target); shaderTranslator.ShaderDesc = shaderDesc; // save debug settings if (debugAttr == null) { shaderDesc.DebugFlags = xSLShader.xSLDebug.None; Console.WriteLine(" => Could not find [xSLDebug]. Debugging has been disabled."); DebugLog.Disabled = true; } else { if ((shaderDesc.DebugFlags & xSLShader.xSLDebug.None) != 0) { Console.WriteLine(" => Found [xSLDebug] with 'None' flag. Debugging has been disabled."); } else { Console.WriteLine(" => Found [xSLDebug]. Debugging with flags: " + shaderDesc.DebugFlags); } } // check for common mistakes Console.WriteLine("\n 1. Checking shader for obvious mistakes."); // check if vertex or fragment method is missing MethodDefinition vertexMain; if (!MethodExists(asmType, "VertexShader", out vertexMain)) { continue; } MethodDefinition fragmentMain; if (!MethodExists(asmType, "FragmentShader", out fragmentMain)) { continue; } // get their precission attributes var vertPrecAttr = vertexMain.CustomAttributes.FirstOrDefault( attrType => attrType.AttributeType.IsType <xSLShader.xSLPrecisionAttribute>()); var fragPrecAttr = fragmentMain.CustomAttributes.FirstOrDefault( attrType => attrType.AttributeType.IsType <xSLShader.xSLPrecisionAttribute>()); shaderDesc.Precision = new CustomAttribute[2]; shaderDesc.Precision[(int)SLShaderType.VertexShader] = vertPrecAttr; shaderDesc.Precision[(int)SLShaderType.FragmentShader] = fragPrecAttr; // get default file for this shader in case no instructions are available var defaultSeq = vertexMain.Body.Instructions[0].SequencePoint; DebugLog.DefaultFile = defaultSeq != null?Path.GetFileName(defaultSeq.Document.Url) : asmTypeName; // check if there are additional constructors for field/property initialization var ctorMethods = asmType.Methods.Where(asmMethod => asmMethod.IsConstructor); var customCtors = new Collection <MethodDefinition>(); foreach (var ctorMethod in ctorMethods.Where(ctor => ctor.Body.CodeSize > 7)) { // see if there are field initializations (as for "constants") var varInits = ctorMethod.Body.Instructions.Any(instr => instr.OpCode == OpCodes.Stfld); // or property setter calls (as for "constants") var funcCalls = ctorMethod.Body.Instructions.Where(instr => instr.OpCode == OpCodes.Call); var propInits = funcCalls.Any(instr => ((MethodReference)instr.Operand).Resolve().IsSetter); if (varInits || propInits) { customCtors.Add(ctorMethod); } else { var instr = ctorMethod.Body.Instructions[0]; DebugLog.Warning("Found a constructor with no valid content", instr); } } // analyze variables used in shader Console.WriteLine("\n 2. Collecting information about fields and properties."); var variables = new Collection <VariableDesc>(); var varTypes = Enum.GetNames(typeof(SLVariableType)); // read and gather fields and backing fields foreach (var asmField in asmType.Fields) { var varDesc = new VariableDesc { Definition = asmField }; var fdName = asmField.Name; var fdType = asmField.FieldType.ToType(); var fdArray = asmField.FieldType.IsArray; var attrs = asmField.CustomAttributes; var isProp = fdName.Contains("<"); if (isProp) { // ReSharper disable once StringIndexOfIsCultureSpecific.1 fdName = fdName.Remove(0, 1).Remove(fdName.IndexOf('>') - 1); var asmProp = asmType.Properties.First(prop => prop.Name == fdName); varDesc.Definition = asmProp; attrs = asmProp.CustomAttributes; fdType = asmProp.PropertyType.ToType(); fdArray = asmProp.PropertyType.IsArray; } var attrCt = attrs.Count(attr => varTypes.Contains(attr.AttributeType.Name)); var validFd = (asmField.HasConstant || attrCt == 1); var varType = (isProp) ? "Property '" : "Field '"; if (asmField.IsStatic && !asmField.HasConstant) { DebugLog.Error(varType + fdName + "' cannot be static"); } else if (validFd) { var fdAttrName = attrs.First(attr => varTypes.Contains(attr.AttributeType.Name)); var fdAttr = (SLVariableType)Array.IndexOf(varTypes, fdAttrName.AttributeType.Name); if (asmField.HasConstant) { if (fdAttr != SLVariableType.xSLConstAttribute) { DebugLog.Error(varType + "constant " + fdName + "' has an invalid attribute"); } varDesc.Value = asmField.Constant; } varDesc.DataType = fdType; varDesc.Attribute = fdAttr; varDesc.IsArray = fdArray; variables.Add(varDesc); } else { DebugLog.Error(varType + fdName + "' is neither a constant nor has valid attributes"); } } shaderDesc.Variables = variables; shaderTranslator.PreVariableCheck(); // translate main, depending methods and constructors if (shaderDesc.Target.Envr == SLEnvironment.OpenGLMix) { Console.WriteLine("\n 3. Translating shader from C# to GLSL/GLSLES."); } else { Console.WriteLine("\n 3. Translating shader from C# to " + shaderDesc.Target.Envr + "."); } shaderDesc.Funcs = new IEnumerable <FunctionDesc> [2]; var vertexFuncs = shaderTranslator.Translate(shaderDesc.Target, vertexMain); shaderDesc.Funcs[(int)SLShaderType.VertexShader] = vertexFuncs; var fragmentFuncs = shaderTranslator.Translate(shaderDesc.Target, fragmentMain); shaderDesc.Funcs[(int)SLShaderType.FragmentShader] = fragmentFuncs; // check correct use of constants foreach (var ctor in customCtors) { var funcs = shaderTranslator.Translate(shaderDesc.Target, ctor); var allVars = funcs.SelectMany(func => func.Variables).ToList(); var allGlobVars = allVars.Where(variables.Contains).ToList(); var illegalVars = allVars.Except(allGlobVars).ToList(); foreach (var illegalVar in illegalVars) { var name = illegalVar.Definition.Name; var instr = illegalVar.Instruction; DebugLog.Error("Illegal use of '" + name + "' in a constructor", instr); } foreach (var constVar in allGlobVars) { var globVar = shaderDesc.Variables.First(var => var.Equals(constVar)); var index = shaderDesc.Variables.IndexOf(globVar); var name = constVar.Definition.Name; var instr = constVar.Instruction; if (globVar.Attribute != SLVariableType.xSLConstAttribute) { DebugLog.Error("Variable '" + name + "' is used as a constant but not marked as such'", instr); } else if (globVar.Value != null && constVar.Value != null) { DebugLog.Error("Constant '" + name + "' cannot be set more than once", instr); } else if (constVar.Value is String) { DebugLog.Error("Constant '" + name + "' was initialized with an invalid value", instr); } else { shaderDesc.Variables[index].Value = constVar.Value; } } } // build both shaders var vertexResult = shaderTranslator.BuildShader(SLShaderType.VertexShader); var fragmentResult = shaderTranslator.BuildShader(SLShaderType.FragmentShader); shaderDesc = shaderTranslator.ShaderDesc; // see if there are unused fields/properties var unusedVars = shaderDesc.Variables.Where(var => !var.IsReferenced); unusedVars = unusedVars.Where(var => var.Attribute != SLVariableType.xSLConstAttribute); foreach (var unsedVar in unusedVars) { DebugLog.Warning("Variable '" + unsedVar.Definition.Name + "' was declared but not used"); } if (!DebugLog.Abort) { Console.WriteLine("\n 4. Building vertex and fragment shader."); // debugging: save to file first, then precompile Console.WriteLine("\n 5. Applying debugging flags if any."); if (!DebugLog.Abort && (xSLShader.xSLDebug.SaveToFile & shaderDesc.DebugFlags) != 0) { var directory = Path.GetDirectoryName(inputPath); if (directory != null) { var combined = new StringBuilder("---- VertexShader ----").NewLine(2); combined.Append(vertexResult).NewLine(3).Append("---- FragmentShader ----"); combined.NewLine(2).Append(fragmentResult); var filePath = Path.Combine(directory, shaderDesc.Name + ".txt"); File.WriteAllText(filePath, combined.ToString()); Console.WriteLine(" => Saved shader to: '" + filePath + "'"); } } if (!DebugLog.Abort && (xSLShader.xSLDebug.PreCompile & shaderDesc.DebugFlags) != 0) { shaderTranslator.PreCompile(vertexResult, fragmentResult); } } else { Console.WriteLine("\n 4. Shader will not be built due to critical errors."); Console.WriteLine("\n 5. Applying debugging flags if any."); } if (DebugLog.Abort) { if ((xSLShader.xSLDebug.ThrowException & shaderDesc.DebugFlags) != 0) { Console.WriteLine(" => Errors will be thrown when using the shader."); Console.WriteLine("\n 6. Preparing to update meta assembly for this shader."); } } // save shaders or errors into the assembly var genShader = metaAsm.MainModule.Types.First(type => type.ToType() == typeof(xSL <>)); var instShader = new GenericInstanceType(genShader); var asmTypeImport = metaAsm.MainModule.Import(asmType); instShader.GenericArguments.Add(asmTypeImport); var instrList = new List <Instruction>(); if (!DebugLog.Abort) { Console.WriteLine("\n 6. Preparing to update meta assembly for this shader."); var vertField = GenericFieldReference(genShader, instShader, "_vertex"); var fragField = GenericFieldReference(genShader, instShader, "_fragment"); var transField = GenericFieldReference(genShader, instShader, "_translated"); metaAsm.MainModule.Import(vertField); metaAsm.MainModule.Import(fragField); metaAsm.MainModule.Import(transField); instrList.Add(Instruction.Create(OpCodes.Ldstr, vertexResult.ToString())); instrList.Add(Instruction.Create(OpCodes.Stsfld, vertField)); instrList.Add(Instruction.Create(OpCodes.Ldstr, fragmentResult.ToString())); instrList.Add(Instruction.Create(OpCodes.Stsfld, fragField)); instrList.Add(Instruction.Create(OpCodes.Ldc_I4_1)); instrList.Add(Instruction.Create(OpCodes.Stsfld, transField)); } // apply debug mode ThrowException if (DebugLog.Abort && (xSLShader.xSLDebug.ThrowException & shaderDesc.DebugFlags) != 0) { var errors = DebugLog.Errors.ToString().Replace(" =>", "=>"); var errField = GenericFieldReference(genShader, instShader, "_error"); instrList.Add(Instruction.Create(OpCodes.Ldstr, errors)); instrList.Add(Instruction.Create(OpCodes.Stsfld, errField)); } shaderDesc.Instructions = instrList; Console.WriteLine(DebugLog.Abort ? "\n ---- Translation failed ----" : "\n ---- Translation succeeded ----"); shaderDescs.Add(shaderDesc); } // write shaders into assembly var invalidCt = shaderDescs.Count(shader => !shader.Instructions.Any()); if (invalidCt == shaderDescs.Count) { Console.WriteLine("\n\nAssembly will not be updated as no shader was translated successfully."); } else { Console.WriteLine("\n\nUpdating CrossSL meta assembly:"); var asmModule = metaAsm.MainModule; var genShader = asmModule.Types.First(type => type.ToType() == typeof(xSL <>)); var xSLInit = genShader.Methods.First(method => method.Name == "Init"); var ilProc = xSLInit.Body.GetILProcessor(); xSLInit.Body.Instructions.Clear(); foreach (var shaderDesc in shaderDescs) { foreach (var instr in shaderDesc.Instructions) { ilProc.Append(instr); } } var ret = Instruction.Create(OpCodes.Ret); ilProc.Append(ret); try { var writeParams = new WriterParameters { WriteSymbols = false }; asmModule.Write(metaPath, writeParams); foreach (var shaderDesc in shaderDescs) { if (shaderDesc.Instructions.Count() > 2) { Console.WriteLine(" => Added shader '" + shaderDesc.Name + "' to assembly."); } else if (shaderDesc.Instructions.Any()) { Console.WriteLine(" => [ThrowException] mode was applied for shader '" + shaderDesc.Name + "'."); } } Console.WriteLine("\n => Saved assembly as '" + metaPath + "'"); } catch (IOException) { Console.WriteLine(" => Cannot update assembly. File might be missing, read-only or in use."); } } DebugLog.UsageError("\nDone."); return(0); }
private StringBuilder InvalidNode(AstNode invalidNode, string msg) { DebugLog.Error(msg, GetInstructionFromStmt(invalidNode.GetParent <Statement>())); return(new StringBuilder()); }
/// <summary> /// Checks member and referenced variables after translating the shader. /// </summary> /// <param name="shaderType">Type of the shader.</param> /// <param name="varDescs">The variable descs.</param> /// <param name="refVars">The referenced variables.</param> private void PostVariableCheck(SLShaderType shaderType, Collection <VariableDesc> varDescs, List <VariableDesc> refVars) { // check if varyings and attributes are used properly var varVars = varDescs.Where(var => var.Attribute == SLVariableType.xSLVaryingAttribute); if (shaderType == SLShaderType.FragmentShader) { foreach (var invalidVar in varVars.Where(var => !var.IsReferenced)) { DebugLog.Error("Varying '" + invalidVar.Definition.Name + "' is used in 'FragmentShader()'" + " but was not set in 'VertexShader()'", invalidVar.Instruction); } var attrVars = varDescs.Where(var => var.Attribute == SLVariableType.xSLAttributeAttribute).ToList(); foreach (var invalidVar in attrVars) { DebugLog.Error("Attribute '" + invalidVar.Definition.Name + "' cannot be " + "used in in 'FragmentShader()'" + invalidVar.Instruction); } } else { var fragFunc = ShaderDesc.Funcs[(int)SLShaderType.FragmentShader]; var mergedVars = fragFunc.SelectMany(func => func.Variables).ToList(); foreach (var invalidVar in varVars.Where(var => !mergedVars.Contains(var))) { DebugLog.Warning("Varying '" + invalidVar.Definition.Name + "' was set in 'VertexShader()'" + " but is not used in 'FragmentShader()'", invalidVar.Instruction); } } // check if constants have been set var constVars = varDescs.Where(var => var.Attribute == SLVariableType.xSLConstAttribute).ToList(); foreach (var constVar in refVars.Where(constVars.Contains).Where(con => con.Value != null)) { DebugLog.Error("Constant '" + constVar.Definition.Name + "' cannot be initialized " + "in 'VertexShader()'", constVar.Instruction); } foreach (var constVar in constVars.Where(var => var.Value == null)) { constVar.Value = ShaderDesc.Variables.First(var => var.Definition == constVar.Definition).Value; if (constVar.Value != null) { continue; } DebugLog.Error("Constant '" + constVar.Definition.Name + "' was not initialized", constVar.Instruction); } // check if invalid variables are set var nestedTypes = typeof(xSLShader).GetNestedTypes(BindingFlags.NonPublic); var attrType = nestedTypes.FirstOrDefault(type => type.Name == shaderType + "Attribute"); var mandType = nestedTypes.FirstOrDefault(type => type == typeof(xSLShader.MandatoryAttribute)); var allProps = typeof(xSLShader).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic); var validProps = allProps.Where(prop => prop.CustomAttributes.Any(attr => attr.AttributeType == attrType)); var validNames = validProps.Select(prop => prop.Name).ToList(); var globalVars = refVars.Where(def => def.Definition.DeclaringType.IsType <xSLShader>()).ToList(); var globalNames = globalVars.Select(var => var.Definition.Name).ToList(); foreach (var memberVar in globalNames.Where(var => !validNames.Contains(var))) { var instr = globalVars.First(var => var.Definition.Name == memberVar).Instruction; DebugLog.Error("'" + memberVar + "' cannot be used in '" + shaderType + "()'", instr); } // check if necessary variables are set var mandVars = allProps.Where(prop => prop.CustomAttributes.Any(attr => attr.AttributeType == mandType)); foreach (var mandVar in mandVars) { var mandVarName = mandVar.Name; if (validNames.Contains(mandVarName) && !globalNames.Contains(mandVarName)) { DebugLog.Error("'" + mandVarName + "' has to be set in '" + shaderType + "()'"); } if (globalNames.Count(var => var == mandVarName) > 1) { var instr = globalVars.Last(var => var.Definition.Name == mandVarName).Instruction; DebugLog.Warning("'" + mandVarName + "' has been set more than" + " once in '" + shaderType + "()'", instr); } } }