Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ShaderMixinCodeGen.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Text;
7 using SiliconStudio.Paradox.Shaders.Parser.Ast;
8 using SiliconStudio.Shaders.Ast;
9 using SiliconStudio.Shaders.Ast.Hlsl;
10 using SiliconStudio.Shaders.Utility;
11 using SiliconStudio.Shaders.Visitor;
12 using SiliconStudio.Shaders.Writer;
13 
14 namespace SiliconStudio.Paradox.Shaders.Parser.Mixins
15 {
16  /// <summary>
17  /// This class is responsible to generate associated C# code from an effect file (extension: pdxfx).
18  /// </summary>
19  public class ShaderMixinCodeGen : ShaderKeyGeneratorBase//ShaderWriter
20  {
21  private const string DefaultNameSpace = "SiliconStudio.Paradox.Effects.Modules";
22 
23  private const string BlockContextTag = "BlockContextTag";
24  private readonly LoggerResult logging;
25  private readonly Shader shader;
26  private ShaderBlock currentBlock;
27  private int localVariableCount;
28 
29  /// <summary>
30  /// Initializes a new instance of the <see cref="ShaderMixinCodeGen" /> class.
31  /// </summary>
32  /// <param name="shader">The shader.</param>
33  /// <param name="logging">The logging.</param>
34  /// <exception cref="System.ArgumentNullException">shader or logging</exception>
35  /// <exception cref="System.InvalidOperationException">Cannot process shaders having already parsing errors</exception>
36  public ShaderMixinCodeGen(Shader shader, LoggerResult logging)
37  {
38  if (shader == null)
39  throw new ArgumentNullException("shader");
40 
41  if (logging == null)
42  throw new ArgumentNullException("logging");
43 
44  this.shader = shader;
45  this.logging = logging;
46  EnablePreprocessorLine = true;
47  }
48 
49  /// <summary>
50  /// Generates the csharp code from a pdxfx file.
51  /// </summary>
52  /// <param name="pdxfxShaderCode">The PDXFX shader code.</param>
53  /// <param name="filePath">The file path.</param>
54  /// <returns>System.String.</returns>
55  /// <exception cref="System.InvalidOperationException"></exception>
56  public static string GenerateCsharp(string pdxfxShaderCode, string filePath)
57  {
58  // Compile
59  var shader = ParadoxShaderParser.PreProcessAndParse(pdxfxShaderCode, filePath);
60 
61  // Try to generate a mixin code.
62  var loggerResult = new LoggerResult();
63  var shaderKeyGenerator = new ShaderMixinCodeGen(shader, loggerResult);
64 
65  if (shaderKeyGenerator.Run())
66  {
67  return shaderKeyGenerator.Text;
68  }
69  throw new InvalidOperationException(loggerResult.ToString());
70  }
71 
72  /// <summary>
73  /// Runs the code generation. Results is accessible from <see cref="ShaderWriter.Text"/> property.
74  /// </summary>
75  public override bool Run()
76  {
77  // If there are any errors, report them in the file as well
78  // but return immediately as we can't really process the shader object
79  if (logging.HasErrors)
80  {
81  LogErrors();
82  return false;
83  }
84 
85  // Add namespace for shader class type
86  FixShaderClassTypeWithNoNameSpace();
87 
88  var blockVisitor = new ShaderBlockVisitor(this, logging);
89  blockVisitor.Run(shader);
90 
91  // If there are any errors, generated by the visitor report them immediately
92  if (logging.HasErrors)
93  {
94  LogErrors();
95  return false;
96  }
97 
98  WriteLine("// <auto-generated>");
99  WriteLine("// Do not edit this file yourself!");
100  WriteLine("//");
101  WriteLine("// This code was generated by Paradox Shader Mixin Code Generator.");
102  WriteLine("// To generate it yourself, please install SiliconStudio.Paradox.VisualStudio.Package .vsix");
103  WriteLine("// and re-save the associated .pdxfx.");
104  WriteLine("// </auto-generated>");
105  WriteLine();
106 
107  // No mixin found, just return
108  if (!blockVisitor.HasMixin && !blockVisitor.HasShaderClassType)
109  {
110  WriteLine("// Nothing to generate");
111  return true;
112  }
113 
114  // Header of usings declaration
115  // TODO: Should probably be better to use fully qualified name of types to avoid conflicts.
116 
117  WriteLine("using System;");
118  WriteLine("using SiliconStudio.Core;");
119  WriteLine("using SiliconStudio.Paradox.Effects;");
120  WriteLine("using SiliconStudio.Paradox.Graphics;");
121  WriteLine("using SiliconStudio.Paradox.Shaders;");
122  WriteLine("using SiliconStudio.Core.Mathematics;");
123  WriteLine("using Buffer = SiliconStudio.Paradox.Graphics.Buffer;");
124  WriteLine();
125 
126  // Visit the shader and generate the code
127  VisitDynamic(shader);
128 
129  // If there are any errors log them into the shader
130  if (logging.HasErrors)
131  {
132  LogErrors();
133  return false;
134  }
135 
136  return true;
137  }
138 
139  public override void Visit(AssignmentExpression assignmentExpression)
140  {
141  Identifier typeTarget;
142  Identifier typeMember;
143  if (TryParameters(assignmentExpression.Target, out typeTarget, out typeMember))
144  {
145  Write("context.SetParam(").Write(typeTarget).Write(".").Write(typeMember).Write(", ");
146  VisitDynamic(assignmentExpression.Value);
147  Write(")");
148  }
149  else
150  {
151  base.Visit(assignmentExpression);
152  }
153  }
154 
155  public override void Visit(MemberReferenceExpression memberReferenceExpression)
156  {
157  Identifier typeTarget;
158  Identifier typeMember;
159  if (TryParameters(memberReferenceExpression, out typeTarget, out typeMember))
160  {
161  Write("context.GetParam(").Write(typeTarget).Write(".").Write(typeMember).Write(")");
162  }
163  else
164  {
165  base.Visit(memberReferenceExpression);
166  }
167  }
168 
169  /// <summary>
170  /// Visits the specified enum type.
171  /// </summary>
172  /// <param name="enumType">Type of the enum.</param>
173  [Visit]
174  protected virtual void Visit(EnumType enumType)
175  {
176  Write("[DataContract]");
177  WriteLinkLine(enumType);
178  Write("public enum");
179  Write(" ");
180  Write(enumType.Name);
181  WriteSpace();
182  {
183  OpenBrace();
184  foreach (Expression fieldDeclaration in enumType.Values)
185  {
186  WriteLinkLine(fieldDeclaration);
187  VisitDynamic(fieldDeclaration);
188  WriteLine(",");
189  }
190  CloseBrace(false).Write(";").WriteLine();
191  }
192  }
193 
194  /// <summary>
195  /// Visits the specified params block.
196  /// </summary>
197  /// <param name="paramsBlock">The params block.</param>
198  [Visit]
199  protected virtual void Visit(ParametersBlock paramsBlock)
200  {
201  Write("[DataContract]");
202  WriteLinkLine(paramsBlock);
203  Write("public partial class");
204  Write(" ");
205  Write(paramsBlock.Name);
206  WriteSpace();
207  Write(": ShaderMixinParameters");
208  {
209  OpenBrace();
210 
211  foreach (DeclarationStatement parameter in paramsBlock.Body.Statements.OfType<DeclarationStatement>())
212  {
213  var variable = parameter.Content as Variable;
214  if (variable == null)
215  continue;
216 
217  WriteLinkLine(parameter);
218  VisitDynamic(variable);
219  }
220 
221  CloseBrace(false).Write(";").WriteLine();
222  }
223  }
224 
225  /// <summary>
226  /// Visits the specified keyword expression.
227  /// </summary>
228  /// <param name="keywordExpression">The keyword expression.</param>
229  [Visit]
230  protected virtual void Visit(KeywordExpression keywordExpression)
231  {
232  // A discard will be transformed to 'return'
233  if (keywordExpression.Name.Text == "discard")
234  {
235  Write("return");
236  }
237  else
238  {
239  base.Visit(keywordExpression);
240  }
241  }
242 
243  [Visit]
244  protected virtual void Visit(ShaderClassType shader)
245  {
246  Write("public static partial class ");
247  Write(shader.Name);
248  Write("Keys");
249  {
250  OpenBrace();
251  foreach (var decl in shader.Members.OfType<Variable>())
252  {
253  VisitDynamic(decl);
254  }
255  CloseBrace();
256  }
257  }
258 
259  [Visit]
260  protected virtual void Visit(GenericType<ObjectType> type)
261  {
262  if (IsStringInList(type.Name, "StructuredBuffer", "RWStructuredBuffer", "ConsumeStructuredBuffer", "AppendStructuredBuffer"))
263  {
264  Write("Buffer");
265  }
266  ProcessInitialValueStatus = false;
267  }
268 
269  /// <summary>
270  /// Visits the specified for each statement.
271  /// </summary>
272  /// <param name="forEachStatement">For each statement.</param>
273  [Visit]
274  protected virtual void Visit(ForEachStatement forEachStatement)
275  {
276  WriteLinkLine(forEachStatement);
277 
278  if (forEachStatement.Variable == null)
279  {
280  localVariableCount++;
281 
282  Identifier parameterType;
283  Identifier parameterMember;
284  if (!TryParameters(forEachStatement.Collection, out parameterType, out parameterMember))
285  {
286  Write(@"#error ""Unexpected parameter for 'foreach params' [");
287  VisitDynamic(forEachStatement.Collection);
288  WriteLine(@"]. Expecting single property access""");
289  return;
290  }
291 
292  string variable = "____" + localVariableCount;
293  Write("foreach(").Write("var ").Write(variable).Write(" in ");
294  VisitDynamic(forEachStatement.Collection);
295  WriteLine(")");
296 
297  var statement = forEachStatement.Body as BlockStatement;
298  if (statement == null)
299  {
300  statement = new BlockStatement {Span = forEachStatement.Body.Span};
301  statement.Statements.Add(forEachStatement.Body);
302  }
303  AddPushPopParameters(statement, parameterType, parameterMember, new VariableReferenceExpression(variable), forEachStatement.Span);
304 
305  VisitDynamic(statement);
306 
307  localVariableCount--;
308  }
309  else
310  {
311  Write("foreach(");
312  VisitDynamic(forEachStatement.Variable);
313  Write(" in ");
314  VisitDynamic(forEachStatement.Collection);
315  Write(")");
316  WriteLine();
317  VisitDynamic(forEachStatement.Body);
318  }
319  }
320 
321  /// <summary>
322  /// Visits the specified shader block.
323  /// </summary>
324  /// <param name="shaderBlock">The shader block.</param>
325  [Visit]
326  protected virtual void Visit(ShaderBlock shaderBlock)
327  {
328  WriteLinkLine(shaderBlock);
329  currentBlock = shaderBlock;
330 
331  VariableAsParameterKey = false;
332 
333  // Use a single internal class for all shader mixins
334  Write("internal static partial class ShaderMixins");
335  {
336  OpenBrace();
337  Write("internal partial class");
338  Write(" ");
339  Write(shaderBlock.Name);
340  WriteSpace();
341  Write(" : IShaderMixinBuilder");
342  {
343  OpenBrace();
344  // Generate the main generate method for each shader block
345  Write("public void Generate(ShaderMixinSourceTree mixin, ShaderMixinContext context)");
346  {
347  OpenBrace();
348  // Create a context associated with ShaderBlock
349  foreach (Statement statement in shaderBlock.Body.Statements)
350  {
351  VisitDynamic(statement);
352  }
353  CloseBrace();
354  }
355 
356  WriteLine();
357  WriteLine("[ModuleInitializer]");
358  WriteLine("internal static void __Initialize__()");
359  {
360  OpenBrace();
361  Write("ShaderMixinManager.Register(\"").Write(shaderBlock.Name).Write("\", new ").Write(shaderBlock.Name).WriteLine("());");
362  CloseBrace();
363  }
364  CloseBrace();
365  }
366  CloseBrace();
367  }
368 
369  VariableAsParameterKey = true;
370  currentBlock = null;
371  }
372 
373  /// <summary>
374  /// Visits the specified mixin statement.
375  /// </summary>
376  /// <param name="mixinStatement">The mixin statement.</param>
377  [Visit]
378  protected virtual void Visit(MixinStatement mixinStatement)
379  {
380  Expression mixinName;
381  AssignmentExpression assignExpression;
382  var genericParameters = new List<Expression>();
383 
384  switch (mixinStatement.Type)
385  {
386  case MixinStatementType.Default:
387  ExtractGenericParameters(mixinStatement.Value, out mixinName, genericParameters);
388 
389  WriteLinkLine(mixinStatement);
390  Write("context.Mixin(mixin, ");
391  WriteMixinName(mixinName);
392  WriteGenericParameters(genericParameters);
393  WriteLine(");");
394  break;
395 
396  case MixinStatementType.Child:
397 
398  // mixin child can come in 2 flavour:
399  // 1) mixin child MyEffect => equivalent to mixin child MyEffect = MyEffect
400  // 2) mixin child MyGenericEffectName = MyEffect
401  var targetExpression = mixinStatement.Value;
402  assignExpression = mixinStatement.Value as AssignmentExpression;
403  if (assignExpression != null)
404  {
405  targetExpression = assignExpression.Value;
406  }
407 
408  ExtractGenericParameters(targetExpression, out mixinName, genericParameters);
409  var childName = assignExpression != null ? assignExpression.Target : mixinName;
410  {
411  OpenBrace();
412  WriteLinkLine(mixinStatement);
413  Write("var __subMixin = new ShaderMixinSourceTree() { Name = ");
414  WriteMixinName(childName);
415  WriteLine(", Parent = mixin };");
416  WriteLine("mixin.Children.Add(__subMixin);");
417 
418  WriteLinkLine(mixinStatement);
419  WriteLine("context.BeginChild(__subMixin);");
420 
421  WriteLinkLine(mixinStatement);
422  Write("context.Mixin(__subMixin, ");
423  WriteMixinName(mixinName);
424  WriteGenericParameters(genericParameters);
425  WriteLine(");");
426 
427  WriteLinkLine(mixinStatement);
428  WriteLine("context.EndChild();");
429 
430  CloseBrace();
431  }
432  break;
433 
434  case MixinStatementType.Remove:
435  ExtractGenericParameters(mixinStatement.Value, out mixinName, genericParameters);
436 
437  WriteLinkLine(mixinStatement);
438  Write("context.RemoveMixin(mixin, ");
439  WriteMixinName(mixinName);
440  if (genericParameters.Count > 0)
441  {
442  logging.Error("Removing with generic parameters is not supported", mixinStatement.Span);
443  }
444  WriteLine(");");
445  break;
446 
447  case MixinStatementType.Clone:
448  WriteLinkLine(mixinStatement);
449  WriteLine("context.CloneProperties();");
450 
451  WriteLinkLine(mixinStatement);
452  WriteLine("mixin.Mixin.CloneFrom(mixin.Parent.Mixin);");
453  break;
454 
455  case MixinStatementType.Macro:
456  WriteLinkLine(mixinStatement);
457  var context = (ShaderBlockContext)currentBlock.GetTag(BlockContextTag);
458  assignExpression = mixinStatement.Value as AssignmentExpression;
459  Expression macroName;
460  Expression macroValue;
461 
462  if (assignExpression != null)
463  {
464  macroName = assignExpression.Target;
465  if (macroName is VariableReferenceExpression)
466  {
467  macroName = new LiteralExpression(macroName.ToString());
468  }
469  macroValue = assignExpression.Value;
470  }
471  else
472  {
473  var variableReference = mixinStatement.Value as MemberReferenceExpression;
474  if (variableReference == null || !(variableReference.Target is VariableReferenceExpression) || !context.DeclaredParameters.Contains((((VariableReferenceExpression)variableReference.Target).Name.Text)))
475  {
476  logging.Error("Invalid syntax. Expecting: mixin macro Parameters.NameOfProperty or mixin macro nameOfProperty = value", mixinStatement.Span);
477  macroName = new LiteralExpression("#INVALID_MACRO_NAME");
478  macroValue = mixinStatement.Value;
479  }
480  else
481  {
482  macroName = new LiteralExpression(variableReference.Member.Text);
483  macroValue = mixinStatement.Value;
484  }
485  }
486 
487  Write("mixin.Mixin.AddMacro(");
488  VisitDynamic(macroName);
489  Write(", ");
490  VisitDynamic(macroValue);
491  WriteLine(");");
492  break;
493 
494  case MixinStatementType.Compose:
495  assignExpression = mixinStatement.Value as AssignmentExpression;
496  if (assignExpression == null)
497  {
498  logging.Error("Expecting assign expression for composition", mixinStatement.Value.Span);
499  return;
500  }
501 
502  var addCompositionFunction = "AddComposition";
503 
504  // If it's a +=, let's create or complete a ShaderArraySource
505  if (assignExpression.Operator == AssignmentOperator.Addition)
506  {
507  addCompositionFunction = "AddCompositionToArray";
508  }
509 
510  ExtractGenericParameters(assignExpression.Value, out mixinName, genericParameters);
511 
512  {
513  OpenBrace();
514  WriteLinkLine(mixinStatement);
515  WriteLine("var __subMixin = new ShaderMixinSourceTree() { Parent = mixin };");
516 
517  WriteLinkLine(mixinStatement);
518  Write("context.Mixin(__subMixin, ");
519  WriteMixinName(mixinName);
520  WriteGenericParameters(genericParameters);
521  WriteLine(");");
522 
523  Write("mixin.Mixin.");
524  Write(addCompositionFunction);
525  Write("(");
526  WriteMixinName(assignExpression.Target);
527  Write(", __subMixin.Mixin");
528  WriteLine(");");
529  CloseBrace();
530  }
531  break;
532  }
533  }
534 
535  /// <summary>
536  /// Visits the specified using statement.
537  /// </summary>
538  /// <param name="usingStatement">The using statement.</param>
539  [Visit]
540  protected virtual void Visit(UsingStatement usingStatement)
541  {
542  WriteLinkLine(usingStatement);
543  Write("using ").Write(usingStatement.Name).WriteLine(";");
544  }
545 
546  /// <summary>
547  /// Visits the specified using parameters statement.
548  /// </summary>
549  /// <param name="usingParametersStatement">The using parameters statement.</param>
550  [Visit]
551  protected virtual void Visit(UsingParametersStatement usingParametersStatement)
552  {
553  if (usingParametersStatement.Body == null)
554  return;
555 
556  Identifier parameterType;
557  Identifier parameterMember;
558  if (!TryParameters(usingParametersStatement.Name, out parameterType, out parameterMember))
559  {
560  Write(@"#error ""Unexpected parameter for 'using params' [");
561  VisitDynamic(usingParametersStatement.Name);
562  WriteLine(@"]. Expecting single property access""");
563  return;
564  }
565 
566  AddPushPopParameters(usingParametersStatement.Body, parameterType, parameterMember, usingParametersStatement.Name, usingParametersStatement.Span);
567 
568  Visit(usingParametersStatement.Body);
569  }
570 
571  private void AddPushPopParameters(BlockStatement blockStatement, Identifier parameterType, Identifier parameterMember, Expression paramValue, SourceSpan span)
572  {
573  var pushStatement = new ExpressionStatement(new MethodInvocationExpression(new MemberReferenceExpression(new VariableReferenceExpression("context"), "PushParameters"), paramValue)) {Span = span};
574  var popStatement = new ExpressionStatement(new MethodInvocationExpression(new MemberReferenceExpression(new VariableReferenceExpression("context"), "PopParameters"))) {Span = span};
575  blockStatement.Statements.Insert(0, pushStatement);
576  ;
577  blockStatement.Statements.Add(popStatement);
578  }
579 
580  private bool TryParameters(Expression expression, out Identifier type, out Identifier member)
581  {
582  type = null;
583  member = null;
584  var memberReferenceExpression = expression as MemberReferenceExpression;
585  if (memberReferenceExpression == null)
586  return false;
587 
588  var name = memberReferenceExpression.Target as VariableReferenceExpression;
589 
590  bool foundDeclaredParameters = false;
591  if (currentBlock != null)
592  {
593  var context = (ShaderBlockContext)currentBlock.GetTag(BlockContextTag);
594  HashSet<string> usings = context.DeclaredParameters;
595 
596  if (name != null && usings.Contains(name.Name))
597  {
598  type = name.Name;
599  member = memberReferenceExpression.Member;
600  foundDeclaredParameters = true;
601  }
602  }
603 
604  return foundDeclaredParameters;
605  }
606 
607  private void ExtractGenericParameters(Expression expression, out Expression mixinName, List<Expression> genericParametersOut)
608  {
609  if (genericParametersOut == null)
610  {
611  throw new ArgumentNullException("genericParametersOut");
612  }
613 
614  mixinName = expression;
615  genericParametersOut.Clear();
616 
617  var varExp = expression as VariableReferenceExpression;
618  if (varExp != null)
619  {
620  Identifier identifier = varExp.Name;
621  var identifierGeneric = identifier as IdentifierGeneric;
622  if (identifierGeneric != null)
623  {
624  mixinName = new VariableReferenceExpression(identifierGeneric.Text);
625 
626  foreach (Identifier subIdentifier in identifierGeneric.Identifiers)
627  {
628  var identifierDot = subIdentifier as IdentifierDot;
629  if (identifierDot != null)
630  {
631  if (identifierDot.Identifiers.Count == 2)
632  {
633  genericParametersOut.Add(new MemberReferenceExpression(new VariableReferenceExpression(identifierDot.Identifiers[0]), identifierDot.Identifiers[1]));
634  }
635  else
636  {
637  logging.Error("Unsupported identifier in generic used for mixin", identifierDot.Span);
638  }
639  }
640  else if (subIdentifier is LiteralIdentifier)
641  {
642  var literalIdentifier = (LiteralIdentifier)subIdentifier;
643 
644  genericParametersOut.Add(new LiteralExpression(literalIdentifier.Value));
645  }
646  else if (subIdentifier.GetType() == typeof(Identifier))
647  {
648  genericParametersOut.Add(new VariableReferenceExpression(subIdentifier));
649  }
650  else
651  {
652  logging.Error("Unsupported identifier in generic used for mixin", subIdentifier.Span);
653  }
654  }
655  }
656  }
657  }
658 
659  private void WriteGenericParameters(IEnumerable<Expression> genericParameters)
660  {
661  foreach (Expression genericParameter in genericParameters)
662  {
663  Write(", ");
664  VisitDynamic(genericParameter);
665  }
666  }
667 
668  private void WriteMixinName(Expression mixinName)
669  {
670  // Output between "" only if the mixin name is only a variable
671  if (mixinName is VariableReferenceExpression)
672  {
673  Write("\"");
674  }
675  VisitDynamic(mixinName);
676  if (mixinName is VariableReferenceExpression)
677  {
678  Write("\"");
679  }
680  }
681 
682  private void LogErrors()
683  {
684  foreach (var reportMessage in logging.Messages)
685  {
686  if (reportMessage.Level == ReportMessageLevel.Error)
687  {
688  Write("#error ").WriteLine(reportMessage.ToString());
689  }
690  }
691  }
692 
693  private class ShaderBlockContext
694  {
695  public readonly HashSet<string> DeclaredParameters = new HashSet<string>();
696  }
697 
698  private void FixShaderClassTypeWithNoNameSpace()
699  {
700  for (int i = 0; i < shader.Declarations.Count; i++)
701  {
702  var node = shader.Declarations[i];
703  if (node is ShaderClassType)
704  {
705  var nameSpaceBlock = new NamespaceBlock(DefaultNameSpace);
706  nameSpaceBlock.Body.Add(node);
707  shader.Declarations[i] = nameSpaceBlock;
708  }
709  }
710  }
711 
712  /// <summary>
713  /// Internal visitor to precalculate all available Parameters in the context
714  /// </summary>
715  private sealed class ShaderBlockVisitor : ShaderVisitor
716  {
717  private readonly LoggerResult logging;
718  private ShaderBlockContext currentContext;
719 
720  private readonly ShaderKeyGeneratorBase parent;
721 
722  private bool isVisitingShaderClassType;
723 
724  public ShaderBlockVisitor(ShaderKeyGeneratorBase parent, LoggerResult logging)
725  : base(false, false)
726  {
727  this.parent = parent;
728  this.logging = logging;
729  }
730 
731  public bool HasMixin { get; private set; }
732 
733  public bool HasShaderClassType { get; private set; }
734 
735  public void Run(Shader shader)
736  {
737  VisitDynamic(shader);
738  }
739 
740  [Visit]
741  private void Visit(ParametersBlock paramsBlock)
742  {
743  HasMixin = true;
744  }
745 
746  [Visit]
747  private void Visit(ShaderClassType shaderClassType)
748  {
749  isVisitingShaderClassType = true;
750  foreach (var variable in shaderClassType.Members.OfType<Variable>())
751  {
752  if (isVisitingShaderClassType && !HasShaderClassType)
753  {
754  if (parent.IsParameterKey(variable))
755  {
756  HasShaderClassType = true;
757  }
758  }
759  }
760  isVisitingShaderClassType = false;
761  }
762 
763  [Visit]
764  private void Visit(ShaderBlock shaderBlock)
765  {
766  HasMixin = true;
767 
768  // Create a context associated with ShaderBlock
769  currentContext = new ShaderBlockContext();
770  shaderBlock.SetTag(BlockContextTag, currentContext);
771 
772  foreach (Statement statement in shaderBlock.Body.Statements)
773  {
774  VisitDynamic(statement);
775  }
776  currentContext = null;
777  }
778 
779  [Visit]
780  private void Visit(UsingParametersStatement usingParametersStatement)
781  {
782  if (currentContext == null)
783  {
784  logging.Error("Unexpected 'using params' outside of shader block declaration", usingParametersStatement.Span);
785  return;
786  }
787 
788  HashSet<string> usings = currentContext.DeclaredParameters;
789 
790  // If this is a using params without a body, it is a simple reference of a ParameterBlock
791  if (usingParametersStatement.Body == null)
792  {
793  var simpleName = usingParametersStatement.Name as VariableReferenceExpression;
794  if (simpleName != null)
795  {
796  string typeName = simpleName.Name.Text;
797 
798  if (usings.Contains(typeName))
799  {
800  logging.Error("Unexpected declaration of using params. This variable is already declared in this scope", usingParametersStatement.Span);
801  return;
802  }
803 
804  usings.Add(typeName);
805  }
806  }
807  else
808  {
809  // using params with a body is to enter the context of the parameters passed to the using statements
810  VisitDynamic(usingParametersStatement.Body);
811  }
812  }
813  }
814  }
815 }
virtual void Visit(EnumType enumType)
Visits the specified enum type.
virtual void Visit(ForEachStatement forEachStatement)
Visits the specified for each statement.
ShaderMixinCodeGen(Shader shader, LoggerResult logging)
Initializes a new instance of the ShaderMixinCodeGen class.
virtual void Visit(ShaderBlock shaderBlock)
Visits the specified shader block.
BlockStatement Body
Gets or sets the body.
Definition: ShaderBlock.cs:26
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
List< Expression > Values
Gets or sets the fields.
Definition: EnumType.cs:34
SourceSpan Span
Gets or sets the source span.
Definition: Node.cs:37
Keyword expression statement like continue; break; discard;
string Text
Gets or sets the name.
Definition: Identifier.cs:77
Expression Collection
Gets or sets the condition.
Identifier Name
Gets or sets the name of this declaration
Definition: IDeclaration.cs:16
A class to collect parsing/expression messages.
Definition: LoggerResult.cs:13
Expression Target
Gets or sets the target receving the assigment.
AssignmentOperator
Assignment operator used in assignment expression (a = b) or statements (a = b;)
override void Visit(MemberReferenceExpression memberReferenceExpression)
virtual void Visit(UsingStatement usingStatement)
Visits the specified using statement.
Expression Value
Gets or sets the value of the assigment..
override bool Run()
Runs the code generation. Results is accessible from ShaderWriter.Text property.
A variable declaration.
Definition: Variable.cs:11
Base root class for all statements.
Definition: Statement.cs:11
virtual void Visit(MixinStatement mixinStatement)
Visits the specified mixin statement.
Variable Variable
Gets or sets the initializer.
Expression Value
Gets or sets the target of this mixin.
A member reference in the form {this}.{Name}
StatementList Statements
Gets or sets the statements.
ReportMessageLevel
Level of a ReportMessage.
Identifier Name
Gets or sets the name.
virtual void Visit(UsingParametersStatement usingParametersStatement)
Visits the specified using parameters statement.
virtual void Visit(ParametersBlock paramsBlock)
Visits the specified params block.
Base class for all generic types.
Definition: GenericType.cs:14
static string GenerateCsharp(string pdxfxShaderCode, string filePath)
Generates the csharp code from a pdxfx file.
List< Node > Members
Gets or sets the members.
Definition: ClassType.cs:64
Toplevel container of a shader parsing result.
Definition: Shader.cs:12
A generic identifier in the form Typename
document false
MixinStatementType Type
Gets or sets the type.
AssignmentOperator Operator
Gets or sets the operator.
Identifier Name
Gets or sets the type name.
Definition: TypeBase.cs:77
This class is responsible to generate associated C# code from an effect file (extension: pdxfx)...
virtual void Visit(GenericType< ObjectType > type)
override void Visit(AssignmentExpression assignmentExpression)
object GetTag(object tagKey)
Gets a tag value associated to this node..
Definition: Node.cs:78
virtual void Visit(KeywordExpression keywordExpression)
Visits the specified keyword expression.