Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
MaterialShaderClassNode.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.Concurrent;
5 using System.Collections.Generic;
6 using System.IO;
7 using System.Linq;
8 using SiliconStudio.Assets;
9 using SiliconStudio.Core;
10 using SiliconStudio.Core.Mathematics;
11 using SiliconStudio.Core.Serialization.Contents;
12 using SiliconStudio.Paradox.Assets.Effect;
13 using SiliconStudio.Paradox.Effects;
14 using SiliconStudio.Paradox.Effects.Data;
15 using SiliconStudio.Paradox.Graphics;
16 using SiliconStudio.Paradox.Shaders.Parser.Ast;
17 using SiliconStudio.Shaders.Ast;
18 
19 namespace SiliconStudio.Paradox.Assets.Materials.Nodes
20 {
21  [ContentSerializer(typeof(DataContentSerializer<MaterialShaderClassNode>))]
22  [DataContract("MaterialShaderClassNode")]
24  {
25  #region Public properties
26 
27  //TODO: use typed AssetReferences
28  /// <summary>
29  /// The shader.
30  /// </summary>
31  /// <userdoc>
32  /// The shader used in this node. It should be a ComputeColor.
33  /// </userdoc>
34  [DataMember(10)]
35  public AssetReference<EffectShaderAsset> MixinReference
36  {
37  get
38  {
39  return mixinReference;
40  }
41  set
42  {
43  mixinReference = value;
44  }
45  }
46 
47  /// <summary>
48  /// The generics of this class.
49  /// </summary>
50  /// <userdoc>
51  /// The generics of the shader. There is no need to edit the list, it is automatically filled when the shader is loaded.
52  /// </userdoc>
53  [DataMember(30)]
54  public GenericDictionary Generics { get; set; }
55 
56  /// <summary>
57  /// The compositions of this class.
58  /// </summary>
59  /// <userdoc>
60  /// The compositions of the shader where material nodes can be attached. There is no need to edit the list, it is automatically filled when the shader is loaded.
61  /// </userdoc>
62  [DataMember(40)]
63  public Dictionary<string, IMaterialNode> CompositionNodes { get; set; }
64 
65  /// <summary>
66  /// The members of this class.
67  /// </summary>
68  /// <userdoc>
69  /// The editables values of this shader. There is no need to edit the list, it is automatically filled when the shader is loaded.
70  /// </userdoc>
71  [DataMember(50)]
72  public Dictionary<ParameterKey, object> Members { get; set; }
73 
74  #endregion
75 
76  #region Private members
77 
78  /// <summary>
79  /// The reference to the shader.
80  /// </summary>
81  [DataMemberIgnore]
82  private AssetReference<EffectShaderAsset> mixinReference;
83 
84  #endregion
85 
86  #region Constructor & public methods
87 
89  : base()
90  {
91  Generics = new GenericDictionary();
92  CompositionNodes = new Dictionary<string, IMaterialNode>();
93  Members = new Dictionary<ParameterKey, object>();
94  }
95 
96  /// <inheritdoc/>
97  public override IEnumerable<MaterialNodeEntry> GetChildren(object context = null)
98  {
99  foreach (var composition in CompositionNodes)
100  {
101  if (composition.Value != null)
102  {
103  KeyValuePair<string, IMaterialNode> composition1 = composition;
104  yield return new MaterialNodeEntry(composition.Value, node => CompositionNodes[composition1.Key] = node);
105  }
106  }
107 
108  var materialContext = context as MaterialContext;
109  if (materialContext != null && materialContext.ExploreGenerics)
110  {
111  foreach (var gen in Generics)
112  {
113  if (gen.Value is NodeParameterTexture)
114  {
115  var foundNode = materialContext.Material.FindNode(((NodeParameterTexture)gen.Value).Reference);
116  if (foundNode != null)
117  yield return new MaterialNodeEntry(foundNode, node => { }); // TODO: change the callback
118  }
119  }
120  }
121  }
122 
123  /// <summary>
124  /// Load the shader and extract the information.
125  /// </summary>
126  public void PrepareNode(ConcurrentDictionary<string, string> projectShaders)
127  {
128  if (!MixinReference.HasLocation())
129  {
130  return;
131  }
132 
133  var newGenerics = new GenericDictionary();
134  var newCompositionNodes = new Dictionary<string, IMaterialNode>();
135  var newMembers = new Dictionary<ParameterKey, object>();
136 
137  var localMixinName = Path.GetFileNameWithoutExtension(MixinReference.Location);
138  ShaderClassType shader;
139 
140  string source;
141  if (projectShaders.TryGetValue(localMixinName, out source))
142  {
143  shader = MaterialNodeClassLoader.GetLoader().ParseShader(source);
144  }
145  else
146  {
147  shader = MaterialNodeClassLoader.GetLoader().GetShader(localMixinName);
148  }
149 
150  if (shader == null)
151  return;
152 
153  var acceptLinkedVariable = true;
154 
155  foreach (var generic in shader.ShaderGenerics)
156  {
157  if (generic.Type.Name.Text == "float4")
158  AddKey<Vector4>(generic.Name.Text, newGenerics);
159  else if (generic.Type.Name.Text == "float3")
160  AddKey<Vector3>(generic.Name.Text, newGenerics);
161  else if (generic.Type.Name.Text == "float2")
162  AddKey<Vector2>(generic.Name.Text, newGenerics);
163  else if (generic.Type.Name.Text == "float")
164  AddKey<float>(generic.Name.Text, newGenerics);
165  else if (generic.Type.Name.Text == "int")
166  AddKey<int>(generic.Name.Text, newGenerics);
167  else if (generic.Type.Name.Text == "Texture2D")
168  AddKey<Texture2D>(generic.Name.Text, newGenerics);
169  else if (generic.Type.Name.Text == "SamplerState")
170  AddKey<SamplerState>(generic.Name.Text, newGenerics);
171  else
172  AddKey<string>(generic.Name.Text, newGenerics);
173 
174  if (generic.Type is LinkType)
175  acceptLinkedVariable = false; // since the behavior is unpredictable, safely prevent addition of linked variable (= with Link annotation)
176  }
177 
178  foreach (var member in shader.Members.OfType<Variable>())
179  {
180  // TODO: enough detect compositions?
181  if (member.Type is TypeName && (member.Type.TypeInference == null || member.Type.TypeInference.TargetType == null))
182  {
183  // ComputeColor only
184  if (member.Type.Name.Text == "ComputeColor")
185  {
186  if (CompositionNodes.ContainsKey(member.Name.Text))
187  newCompositionNodes.Add(member.Name.Text, CompositionNodes[member.Name.Text]);
188  else
189  newCompositionNodes.Add(member.Name.Text, null);
190  }
191  }
192  else
193  {
194  var isColor = false;
195  string linkName = null;
196  var isStage = member.Qualifiers.Contains(ParadoxStorageQualifier.Stage);
197  var isStream = member.Qualifiers.Contains(ParadoxStorageQualifier.Stream);
198  foreach (var annotation in member.Attributes.OfType<SiliconStudio.Shaders.Ast.Hlsl.AttributeDeclaration>())
199  {
200  if (annotation.Name == "Color")
201  isColor = true;
202  if (acceptLinkedVariable && annotation.Name == "Link" && annotation.Parameters.Count > 0)
203  linkName = (string)annotation.Parameters[0].Value;
204  }
205 
206  if (!isStream && (isStage || !string.IsNullOrEmpty(linkName)))
207  {
208  if (linkName == null)
209  linkName = localMixinName + "." + member.Name.Text;
210 
211  var memberType = member.Type.ResolveType();
212  if (isColor)
213  {
214  AddMember<Color4>(linkName, newMembers);
215  }
216  else if (memberType == ScalarType.Float || memberType == ScalarType.Half)
217  {
218  AddMember<float>(linkName, newMembers);
219  }
220  else if (memberType == ScalarType.Double)
221  {
222  AddMember<double>(linkName, newMembers);
223  }
224  else if (memberType == ScalarType.Int)
225  {
226  AddMember<int>(linkName, newMembers);
227  }
228  else if (memberType == ScalarType.UInt)
229  {
230  AddMember<uint>(linkName, newMembers);
231  }
232  else if (memberType == ScalarType.Bool)
233  {
234  AddMember<bool>(linkName, newMembers);
235  }
236  else if (memberType is VectorType)
237  {
238  switch (((VectorType)memberType).Dimension)
239  {
240  case 2:
241  AddMember<Vector2>(linkName, newMembers);
242  break;
243  case 3:
244  AddMember<Vector3>(linkName, newMembers);
245  break;
246  case 4:
247  AddMember<Vector4>(linkName, newMembers);
248  break;
249  }
250  }
251  else if (member.Type.Name.Text == "Texture2D")
252  {
253  AddMember<Graphics.Texture>(linkName, newMembers);
254  }
255  else if (member.Type.Name.Text == "SamplerState")
256  {
257  AddMember<Graphics.SamplerState>(linkName, newMembers);
258  }
259  }
260  }
261  }
262 
263  Generics = newGenerics;
264  CompositionNodes = newCompositionNodes;
265  Members = newMembers;
266  }
267 
268  public ParameterCollectionData GetParameters(object context)
269  {
270  var collection = new ParameterCollectionData();
271 
272  if (MixinReference != null)
273  {
274  foreach (var keyValue in Members)
275  {
276  var expectedType = keyValue.Value.GetType();
277  if (expectedType == typeof(Color4))
278  {
279  AddToCollection<Color4>(keyValue.Key, (Color4)keyValue.Value, collection);
280  }
281  else if (expectedType == typeof(float))
282  {
283  AddToCollection<float>(keyValue.Key, (float)keyValue.Value, collection);
284  }
285  else if (expectedType == typeof(double))
286  {
287  AddToCollection<double>(keyValue.Key, (double)keyValue.Value, collection);
288  }
289  else if (expectedType == typeof(int))
290  {
291  AddToCollection<int>(keyValue.Key, (int)keyValue.Value, collection);
292  }
293  else if (expectedType == typeof(uint))
294  {
295  AddToCollection<uint>(keyValue.Key, (uint)keyValue.Value, collection);
296  }
297  else if (expectedType == typeof(bool))
298  {
299  AddToCollection<bool>(keyValue.Key, (bool)keyValue.Value, collection);
300  }
301  else if (expectedType == typeof(Vector2))
302  {
303  AddToCollection<Vector2>(keyValue.Key, (Vector2)keyValue.Value, collection);
304  }
305  else if (expectedType == typeof(Vector3))
306  {
307  AddToCollection<Vector3>(keyValue.Key, (Vector3)keyValue.Value, collection);
308  }
309  else if (expectedType == typeof(Vector4))
310  {
311  AddToCollection<Vector4>(keyValue.Key, (Vector4)keyValue.Value, collection);
312  }
313  else if (expectedType == typeof(NodeParameterTexture))
314  {
315  var matContext = context as MaterialContext;
316  if (matContext != null)
317  {
318  var textureNode = matContext.Material.FindNode(((NodeParameterTexture)keyValue.Value).Reference);
319  if (textureNode != null)
320  AddToCollection<Graphics.Texture>(keyValue.Key, textureNode, collection);
321  }
322  }
323  else if (expectedType == typeof(NodeParameterSampler))
324  {
325  AddToCollection<Graphics.SamplerState>(keyValue.Key, keyValue.Value, collection);
326  }
327  }
328  }
329  return collection;
330  }
331 
332  /// <inheritdoc/>
333  public override string ToString()
334  {
335  return "Shader";
336  }
337 
338  #endregion
339 
340  #region Private methods
341 
342  /// <summary>
343  /// Add a new member.
344  /// </summary>
345  /// <typeparam name="T">The type of the member.</typeparam>
346  /// <param name="linkName">The name of the parameter key.</param>
347  /// <param name="members">The target parameter collection.</param>
348  private void AddMember<T>(string linkName, Dictionary<ParameterKey, object> members)
349  {
350  var pk = GetTypedParameterKey<T>(linkName);
351  if (pk != null)
352  {
353  Type expectedType = null;
354  object defaultValue;
355  if (pk.PropertyType == typeof(Graphics.Texture))
356  {
357  expectedType = typeof(NodeParameterTexture);
358  defaultValue = new NodeParameterTexture();
359  }
360  else if (pk.PropertyType == typeof(Graphics.SamplerState))
361  {
362  expectedType = typeof(NodeParameterSampler);
363  defaultValue = new NodeParameterSampler();
364  }
365  else
366  {
367  expectedType = pk.PropertyType;
368  defaultValue = pk.DefaultMetadataT.DefaultValue;
369  }
370 
371  if (Members.ContainsKey(pk))
372  {
373  var value = Members[pk];
374  if (value.GetType() == expectedType)
375  members.Add(pk, value);
376  }
377  else
378  members.Add(pk, defaultValue);
379  }
380  }
381 
382  /// <summary>
383  /// Add a new generic parameter.
384  /// </summary>
385  /// <typeparam name="T">The type of the generic.</typeparam>
386  /// <param name="keyName">The name of the generic.</param>
387  /// <param name="generics">The target GenericDictionary.</param>
388  private void AddKey<T>(string keyName, GenericDictionary generics)
389  {
390  INodeParameter nodeParameter;
391  var typeT = typeof(T);
392  if (typeT == typeof(string))
393  nodeParameter = new NodeParameter();
394  else if (typeT == typeof(Texture2D))
395  nodeParameter = new NodeParameterTexture();
396  else if (typeT == typeof(float))
397  nodeParameter = new NodeParameterFloat();
398  else if (typeT == typeof(int))
399  nodeParameter = new NodeParameterInt();
400  else if (typeT == typeof(Vector2))
401  nodeParameter = new NodeParameterFloat2();
402  else if (typeT == typeof(Vector3))
403  nodeParameter = new NodeParameterFloat3();
404  else if (typeT == typeof(Vector4))
405  nodeParameter = new NodeParameterFloat4();
406  else if (typeT == typeof(SamplerState))
407  nodeParameter = new NodeParameterSampler();
408  else
409  throw new Exception("Unsupported generic format");
410 
411  if (Generics.ContainsKey(keyName))
412  {
413  var gen = Generics[keyName];
414  if (gen == null || gen.GetType() != nodeParameter.GetType())
415  generics[keyName] = nodeParameter;
416  else
417  generics[keyName] = gen;
418  }
419  else
420  generics.Add(keyName, nodeParameter);
421  }
422 
423  /// <summary>
424  /// Add the parameter to the collection.
425  /// </summary>
426  /// <typeparam name="T">The type of the parameter.</typeparam>
427  /// <param name="key">The key of the variable.</param>
428  /// <param name="value"></param>
429  /// <param name="collection"></param>
430  private void AddToCollection<T>(ParameterKey key, object value, ParameterCollectionData collection)
431  {
432  var pk = key as ParameterKey<T>;
433  if (pk != null)
434  collection.Set(pk, value);
435  }
436 
437  #endregion
438 
439  #region Private static methods
440 
441  /// <summary>
442  /// Get the correct parameter key.
443  /// </summary>
444  /// <typeparam name="T">The type of the parameter.</typeparam>
445  /// <param name="linkName">The name of the parameter key.</param>
446  /// <returns>The parameter key.</returns>
447  private static ParameterKey<T> GetTypedParameterKey<T>(string linkName)
448  {
449  var pk = ParameterKeys.FindByName(linkName);
450  if (pk != null)
451  {
452  if (pk.PropertyType == typeof(T))
453  return (ParameterKey<T>)pk;
454  }
455  //TODO: log error
456  return null;
457  }
458 
459  #endregion
460  }
461 
462 
463 }
Base class for all vector types
Definition: VectorType.cs:10
static readonly ScalarType Bool
Scalar bool.
Definition: ScalarType.cs:17
Key of an effect parameter.
Definition: ParameterKey.cs:15
SiliconStudio.Paradox.Games.Mathematics.Vector2 Vector2
static readonly ScalarType Int
Scalar int.
Definition: ScalarType.cs:37
Represents a two dimensional mathematical vector.
Definition: Vector2.cs:42
A typeless reference.
Definition: TypeName.cs:10
A custom dictionary to keep track of the order the elements were inserted.
void PrepareNode(ConcurrentDictionary< string, string > projectShaders)
Load the shader and extract the information.
An entry to a nested IMaterialNode
Key of an gereric effect parameter.
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
Data type for SiliconStudio.Paradox.Effects.ParameterCollection.
Definition: ParadoxData.cs:31
Represents a color in the form of rgba.
Definition: Color4.cs:42
static readonly ScalarType Half
Scalar half.
Definition: ScalarType.cs:32
static readonly ScalarType UInt
Scalar unsigned int.
Definition: ScalarType.cs:42
static readonly ScalarType Float
Sclar float.
Definition: ScalarType.cs:27
Represents a four dimensional mathematical vector.
Definition: Vector4.cs:42
A variable declaration.
Definition: Variable.cs:11
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
Definition: Texture2D.cs:37
static readonly ScalarType Double
Scalar double.
Definition: ScalarType.cs:22
override IEnumerable< MaterialNodeEntry > GetChildren(object context=null)
Gets the children. The context to get the children.The list of children.
SiliconStudio.Core.Mathematics.Vector3 Vector3
Base class for texture resources.
Definition: Texture.cs:38