Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
MaterialTextureVisitor.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 SiliconStudio.Paradox.Assets.Materials.Nodes;
7 using SiliconStudio.Paradox.Effects;
8 using SiliconStudio.Paradox.Effects.Modules;
9 using SiliconStudio.Paradox.Graphics;
10 
11 namespace SiliconStudio.Paradox.Assets.Materials.Processor.Visitors
12 {
14  {
15  #region Private static members
16 
17  /// <summary>
18  /// Available default texture keys.
19  /// </summary>
20  private static readonly List<ParameterKey<Graphics.Texture>> DefaultTextureKeys = new List<ParameterKey<Graphics.Texture>>()
21  {
22  TexturingKeys.Texture0,
23  TexturingKeys.Texture1,
24  TexturingKeys.Texture2,
25  TexturingKeys.Texture3,
26  TexturingKeys.Texture4,
27  TexturingKeys.Texture5,
28  TexturingKeys.Texture6,
29  TexturingKeys.Texture7,
30  TexturingKeys.Texture8,
31  TexturingKeys.Texture9
32  };
33 
34  /// <summary>
35  /// Available diffuse texture keys.
36  /// </summary>
37  private static readonly List<ParameterKey<Graphics.Texture>> DiffuseTextureKeys = new List<ParameterKey<Graphics.Texture>>()
38  {
39  MaterialTexturingKeys.DiffuseTexture0,
40  MaterialTexturingKeys.DiffuseTexture1,
41  MaterialTexturingKeys.DiffuseTexture2,
42  MaterialTexturingKeys.DiffuseTexture3
43  };
44 
45  /// <summary>
46  /// Available specular texture keys.
47  /// </summary>
48  private static readonly List<ParameterKey<Graphics.Texture>> SpecularTextureKeys = new List<ParameterKey<Graphics.Texture>>()
49  {
50  MaterialTexturingKeys.SpecularTexture0,
51  MaterialTexturingKeys.SpecularTexture1,
52  MaterialTexturingKeys.SpecularTexture2
53  };
54 
55  /// <summary>
56  /// Available normal map texture keys.
57  /// </summary>
58  private static readonly List<ParameterKey<Graphics.Texture>> NormalMapTextureKeys = new List<ParameterKey<Graphics.Texture>>()
59  {
60  MaterialTexturingKeys.NormalMapTexture0,
61  MaterialTexturingKeys.NormalMapTexture1
62  };
63 
64  /// <summary>
65  /// Available displacement texture keys.
66  /// </summary>
67  private static readonly List<ParameterKey<Graphics.Texture>> DisplacementTextureKeys = new List<ParameterKey<Graphics.Texture>>()
68  {
69  MaterialTexturingKeys.DisplacementTexture0
70  };
71 
72  #endregion
73 
74  #region Private members
75 
76  /// <summary>
77  /// Generic method to get a texture key
78  /// </summary>
79  private delegate ParameterKey<Graphics.Texture> TextureKeyGetter(MaterialTextureVisitor textureVisitor);
80 
81  /// <summary>
82  /// Index of the next candidate in the default texture key pool.
83  /// </summary>
84  private int nextDefaultIndex = 0;
85 
86  /// <summary>
87  /// Index of the next candidate in the diffuse texture key pool.
88  /// </summary>
89  private int nextDiffuseIndex = 0;
90 
91  /// <summary>
92  /// Index of the next candidate in the specular texture key pool.
93  /// </summary>
94  private int nextSpecularIndex = 0;
95 
96  /// <summary>
97  /// Index of the next candidate in the normal map texture key pool.
98  /// </summary>
99  private int nextNormalMapIndex = 0;
100 
101  /// <summary>
102  /// Index of the next candidate in the displacement texture key pool.
103  /// </summary>
104  private int nextDisplacementIndex = 0;
105 
106  /// <summary>
107  /// List of already used texture keys.
108  /// </summary>
109  private List<ParameterKey<Graphics.Texture>> usedTextureKeys = new List<ParameterKey<Graphics.Texture>>();
110 
111  #endregion
112 
113  #region Public methods
114 
116  {
117  }
118 
119  /// <summary>
120  /// Reset the indices.
121  /// </summary>
122  public void ResetTextureIndices()
123  {
124  nextDefaultIndex = 0;
125  nextDiffuseIndex = 0;
126  nextSpecularIndex = 0;
127  nextNormalMapIndex = 0;
128  nextDisplacementIndex = 0;
129  }
130 
131  /// <summary>
132  /// Assign the default texture keys to the texture slots.
133  /// </summary>
134  /// <param name="nodes">List of nodes.</param>
136  {
137  AssignParameterKeys(nodes, samplers, GetNextDefaultTextureKey);
138  }
139 
140  /// <summary>
141  /// Assign the default texture keys to the texture slots.
142  /// </summary>
143  /// <param name="node">The node to look into.</param>
145  {
146  AssignParameterKeys(node, GetNextDefaultTextureKey);
147  }
148 
149  /// <summary>
150  /// Assign the diffuse texture keys to the texture slots.
151  /// </summary>
152  /// <param name="node">The node to look into.</param>
154  {
155  AssignParameterKeys(node, GetNextDiffuseTextureKey);
156  }
157 
158  /// <summary>
159  /// Assign the specular texture keys to the texture slots.
160  /// </summary>
161  /// <param name="node">The node to look into.</param>
163  {
164  AssignParameterKeys(node, GetNextSpecularTextureKey);
165  }
166 
167  /// <summary>
168  /// Assign the normal map texture keys to the texture slots.
169  /// </summary>
170  /// <param name="node">The node to look into.</param>
172  {
173  AssignParameterKeys(node, GetNextNormalMapTextureKey);
174  }
175 
176  /// <summary>
177  /// Assign the displacement texture keys to the texture slots.
178  /// </summary>
179  /// <param name="node">The node to look into.</param>
181  {
182  AssignParameterKeys(node, GetNextDisplacementTextureKey);
183  }
184 
185  /// <summary>
186  /// Test if the tree can be reduced to a single texture or color.
187  /// </summary>
188  /// <param name="node">The node to explore.</param>
189  /// <param name="texcoord">The unique texcoord if applicable.</param>
190  /// <returns>A boolean stating this test.</returns>
191  public bool HasUniqueTexcoord(IMaterialNode node, out TextureCoordinate texcoord)
192  {
193  var allTextures = GatherTextureValues(node).Distinct().ToList();
194  texcoord = TextureCoordinate.TexcoordNone;
195 
196  foreach (var texSlot in allTextures)
197  {
198  if (texcoord == TextureCoordinate.TexcoordNone)
199  texcoord = texSlot.TexcoordIndex;
200 
201  if (texcoord != texSlot.TexcoordIndex)
202  return false;
203  }
204  return true;
205  }
206 
207  /// <summary>
208  /// Get all the textures needed for this node.
209  /// </summary>
210  /// <param name="node">The node to explore.</param>
211  /// <returns>The list containing all the textures.</returns>
212  public List<MaterialTextureNode> GetAllTextureValues(IMaterialNode node)
213  {
214  return GatherTextureValues(node).Distinct().ToList();
215  }
216 
217  /// <summary>
218  /// Get all the textures needed for this node with the potential generic parameters.
219  /// </summary>
220  /// <param name="node">The node to explore.</param>
221  /// <returns>The list containing all the textures.</returns>
222  public List<MaterialTextureNode> GetAllTextureValuesWithGenerics(IMaterialNode node)
223  {
224  return GatherTextureValuesWithGenerics(node).Distinct().ToList();
225  }
226 
227  /// <summary>
228  /// Get all the textures needed for this node.
229  /// </summary>
230  /// <param name="node">The node to explore.</param>
231  /// <returns>The list containing all the textures.</returns>
232  public List<NodeParameterSampler> GetAllSamplerValues(IMaterialNode node)
233  {
234  return GatherSamplerValues(node).Distinct().ToList();
235  }
236 
237  /// <summary>
238  /// Get all the textures for this model.
239  /// </summary>
240  /// <returns>The list containing all the textures.</returns>
241  public List<MaterialTextureNode> GetAllModelTextureValues()
242  {
243  var returnList = new List<MaterialTextureNode>();
244  foreach (var reference in Material.ColorNodes)
245  {
246  returnList.AddRange(GatherTextureValues(Material.FindNode(reference.Value)));
247  }
248  return returnList.Distinct().ToList();
249  }
250 
251  /// <summary>
252  /// Get all the textures for this model.
253  /// </summary>
254  /// <returns>The list containing all the textures even the ones in the generics.</returns>
255  public List<MaterialTextureNode> GetAllModelTextureValuesWithGenerics()
256  {
257  var returnList = new List<MaterialTextureNode>();
258  foreach (var reference in Material.ColorNodes)
259  {
260  returnList.AddRange(GatherTextureValuesWithGenerics(Material.FindNode(reference.Value)));
261  }
262  return returnList.Distinct().ToList();
263  }
264 
265  /// <summary>
266  /// Get all the Sampler from the generics for this model.
267  /// </summary>
268  /// <returns>The list containing all the textures.</returns>
269  public List<NodeParameterSampler> GetAllSamplerValues()
270  {
271  var returnList = new List<NodeParameterSampler>();
272  foreach (var reference in Material.ColorNodes)
273  {
274  returnList.AddRange(GatherSamplerValues(Material.FindNode(reference.Value)));
275  }
276  return returnList.Distinct().ToList();
277  }
278 
279  /// <summary>
280  /// Get all the texture from this material.
281  /// </summary>
282  /// <returns>The list containing all the textures</returns>
283  public List<MaterialTextureNode> GetAllTextureValues()
284  {
285  var returnList = new List<MaterialTextureNode>();
286  foreach (var tree in Material.Nodes)
287  returnList.AddRange(GatherTextureValues(tree.Value));
288  return returnList.Distinct().ToList();
289  }
290 
291  #endregion
292 
293  #region Private methods
294 
295  /// <summary>
296  /// Assign the Keys to the textures in the tree.
297  /// </summary>
298  /// <param name="node">The node to look into.</param>
299  /// <param name="getTextureKey">The delegate function to get the correct key.</param>
300  private void AssignParameterKeys(IMaterialNode node, TextureKeyGetter getTextureKey)
301  {
302  var allTextures = GatherTextureValues(node).Distinct().ToList();
303  var textureKeys = new Dictionary<string, ParameterKey<Graphics.Texture>>();
304 
305  foreach (var texSlot in allTextures)
306  {
307  //TODO: compare texture sampling method
309  var textureName = texSlot.TextureName;
310  if (textureName == null || !textureKeys.TryGetValue(textureName, out pk))
311  {
312  pk = getTextureKey(this);
313  if (textureName != null)
314  textureKeys.Add(textureName, pk);
315  }
316 
317  texSlot.UsedParameterKey = pk;
318  texSlot.Sampler.SamplerParameterKey = TexturingKeys.Sampler;
319  }
320  }
321 
322  /// <summary>
323  /// Assign the Keys to the textures and the samplers in the list.
324  /// </summary>
325  /// <param name="nodes">List of nodes.</param>
326  /// <param name="samplers">The list of sampler existing outside of MaterialTextureNode</param>
327  /// <param name="getTextureKey">The delegate function to get the correct key.</param>
328  private void AssignParameterKeys(IEnumerable<MaterialTextureNode> nodes, IEnumerable<NodeParameterSampler> samplers, TextureKeyGetter getTextureKey)
329  {
330  var textureKeys = new Dictionary<IMaterialNode, ParameterKey<Graphics.Texture>>();
331  var samplerKeys = new Dictionary<SamplerDescription, ParameterKey<SamplerState>>();
332  int samplerIndex = 0;
333 
334  // assign the predefined keys
335  foreach (var texSlot in nodes.Distinct())
336  {
337  if (!texSlot.AutoAssignKey && texSlot.Key != null)
338  {
339  texSlot.UsedParameterKey = (ParameterKey<Graphics.Texture>)texSlot.Key;
340  textureKeys.Add(texSlot, texSlot.UsedParameterKey);
341  usedTextureKeys.Add(texSlot.UsedParameterKey);
342  }
343  }
344 
345  // assign/generate all the keys
346  foreach (var texSlot in nodes.Distinct())
347  {
348  ParameterKey<Graphics.Texture> textureParameterKey;
349  if (!textureKeys.TryGetValue(texSlot, out textureParameterKey))
350  {
351  textureParameterKey = getTextureKey(this);
352  textureKeys.Add(texSlot, textureParameterKey);
353  }
354  texSlot.UsedParameterKey = textureParameterKey;
355 
356  SetSamplerKey(texSlot.Sampler, samplerKeys, ref samplerIndex);
357  }
358 
359  if (samplers != null)
360  {
361  foreach (var gen in samplers)
362  SetSamplerKey(gen, samplerKeys, ref samplerIndex);
363  }
364  }
365 
366  /// <summary>
367  /// Get the sampler key, a new one or an existing one.
368  /// </summary>
369  /// <param name="sampler">The sampler.</param>
370  /// <param name="samplerKeys">The already defined keys.</param>
371  /// <param name="samplerIndex">The current index of the sampler.</param>
372  /// <returns>The ParameterKey.</returns>
373  private void SetSamplerKey(NodeParameterSampler sampler, Dictionary<SamplerDescription, ParameterKey<SamplerState>> samplerKeys, ref int samplerIndex)
374  {
375  var state = new SamplerDescription { Filtering = sampler.Filtering, AddressModeU = sampler.AddressModeU, AddressModeV = sampler.AddressModeV, AddressModeW = TextureAddressMode.Wrap };
376  ParameterKey<SamplerState> samplerParameterKey;
377  if (!samplerKeys.TryGetValue(state, out samplerParameterKey))
378  {
379  samplerParameterKey = GetDefaultSamplerKey(samplerIndex);
380  ++samplerIndex;
381  samplerKeys.Add(state, samplerParameterKey);
382  }
383  sampler.SamplerParameterKey = samplerParameterKey;
384  }
385 
386  /// <summary>
387  /// Generic function to get the next texture key.
388  /// </summary>
389  /// <param name="textureKeysList">The list of available texture keys.</param>
390  /// <param name="nextIndex">the index of the next parameter key.</param>
391  /// <returns>The parameter key.</returns>
392  private ParameterKey<Graphics.Texture> GetNextTextureKey(List<ParameterKey<Graphics.Texture>> textureKeysList, ref int nextIndex)
393  {
394  while (usedTextureKeys.Contains(textureKeysList[nextIndex]) && nextIndex < textureKeysList.Count)
395  {
396  ++nextIndex;
397  }
398 
399  if (nextIndex == textureKeysList.Count)
400  throw new IndexOutOfRangeException("There is no more available texture key.");
401 
402  return textureKeysList[nextIndex++];
403  }
404 
405  /// <summary>
406  /// Gather all the textures in the node hierarchy.
407  /// </summary>
408  /// <param name="node">The node to look into.</param>
409  /// <returns>A collection of MaterialTextureNode.</returns>
410  private IEnumerable<MaterialTextureNode> GatherTextureValues(IMaterialNode node)
411  {
412  var materialContext = new MaterialContext { Material = Material, ExploreGenerics = false };
413  return GatherTextures(node, materialContext);
414  }
415 
416  /// <summary>
417  /// Gather all the textures in the node hierarchy, even the ones behind the generics.
418  /// </summary>
419  /// <param name="node">The node to look into.</param>
420  /// <returns>A collection of MaterialTextureNode.</returns>
421  private IEnumerable<MaterialTextureNode> GatherTextureValuesWithGenerics(IMaterialNode node)
422  {
423  var materialContext = new MaterialContext { Material = Material, ExploreGenerics = true };
424  return GatherTextures(node, materialContext);
425  }
426 
427  /// <summary>
428  /// Common gather texture function.
429  /// </summary>
430  /// <param name="node">The node to look into.</param>
431  /// <param name="materialContext">The visitor context.</param>
432  /// <returns>A collection of MaterialTextureNode.</returns>
433  private IEnumerable<MaterialTextureNode> GatherTextures(IMaterialNode node, MaterialContext materialContext)
434  {
435  var textureValues = new List<MaterialTextureNode>();
436  node.VisitNodes((context, nodeEntry) =>
437  {
438  var textureValue = nodeEntry.Node as MaterialTextureNode;
439  if (textureValue != null)
440  {
441  textureValues.Add(textureValue);
442  }
443  }, materialContext);
444  return textureValues;
445  }
446 
447  /// <summary>
448  /// Gather all the sampler generics in the node hierarchy.
449  /// </summary>
450  /// <param name="node">The node to look into.</param>
451  /// <returns>A collection of NodeParameterSampler.</returns>
452  private IEnumerable<NodeParameterSampler> GatherSamplerValues(IMaterialNode node)
453  {
454  var samplerValues = new List<NodeParameterSampler>();
455  node.VisitNodes((context, nodeEntry) =>
456  {
457  var shaderClassNode = nodeEntry.Node as MaterialShaderClassNode;
458  if (shaderClassNode != null)
459  {
460  foreach (var gen in shaderClassNode.Generics)
461  {
462  var genSampler = gen.Value as NodeParameterSampler;
463  if (genSampler != null)
464  {
465  samplerValues.Add(genSampler);
466  }
467  }
468  }
469  }, new MaterialContext { Material = Material, ExploreGenerics = false });
470  return samplerValues;
471  }
472 
473  #endregion
474 
475  #region Private static methods
476 
477  /// <summary>
478  /// Get the next texture parameter key from the default pool.
479  /// </summary>
480  /// <returns>A parameter key.</returns>
481  private static ParameterKey<Graphics.Texture> GetNextDefaultTextureKey(MaterialTextureVisitor textureVisitor)
482  {
483  return textureVisitor.GetNextTextureKey(DefaultTextureKeys, ref textureVisitor.nextDefaultIndex);
484  }
485 
486  /// <summary>
487  /// Get the next texture parameter key from the diffuse pool.
488  /// </summary>
489  /// <returns>A parameter key.</returns>
490  private static ParameterKey<Graphics.Texture> GetNextDiffuseTextureKey(MaterialTextureVisitor textureVisitor)
491  {
492  return textureVisitor.GetNextTextureKey(DiffuseTextureKeys, ref textureVisitor.nextDiffuseIndex);
493  }
494 
495  /// <summary>
496  /// Get the next texture parameter key from the specular pool.
497  /// </summary>
498  /// <returns>A parameter key.</returns>
499  private static ParameterKey<Graphics.Texture> GetNextSpecularTextureKey(MaterialTextureVisitor textureVisitor)
500  {
501  return textureVisitor.GetNextTextureKey(SpecularTextureKeys, ref textureVisitor.nextSpecularIndex);
502  }
503 
504  /// <summary>
505  /// Get the next texture parameter key from the normal map pool.
506  /// </summary>
507  /// <returns>A parameter key.</returns>
508  private static ParameterKey<Graphics.Texture> GetNextNormalMapTextureKey(MaterialTextureVisitor textureVisitor)
509  {
510  return textureVisitor.GetNextTextureKey(NormalMapTextureKeys, ref textureVisitor.nextNormalMapIndex);
511  }
512 
513  /// <summary>
514  /// Get the next texture parameter key from the displacement pool.
515  /// </summary>
516  /// <returns>A parameter key.</returns>
517  private static ParameterKey<Graphics.Texture> GetNextDisplacementTextureKey(MaterialTextureVisitor textureVisitor)
518  {
519  return textureVisitor.GetNextTextureKey(DisplacementTextureKeys, ref textureVisitor.nextDisplacementIndex);
520  }
521 
522  /// <summary>
523  /// Get the ParameterKey of generic sampler.
524  /// </summary>
525  /// <param name="i">The id of the texture.</param>
526  /// <returns>The corresponding ParameterKey.</returns>
527  private static ParameterKey<SamplerState> GetDefaultSamplerKey(int i)
528  {
529  switch (i)
530  {
531  case 0:
532  return TexturingKeys.Sampler0;
533  case 1:
534  return TexturingKeys.Sampler1;
535  case 2:
536  return TexturingKeys.Sampler2;
537  case 3:
538  return TexturingKeys.Sampler3;
539  case 4:
540  return TexturingKeys.Sampler4;
541  case 5:
542  return TexturingKeys.Sampler5;
543  case 6:
544  return TexturingKeys.Sampler6;
545  case 7:
546  return TexturingKeys.Sampler7;
547  case 8:
548  return TexturingKeys.Sampler8;
549  case 9:
550  return TexturingKeys.Sampler9;
551  default:
552  throw new ArgumentOutOfRangeException("Asked for " + i + " but no more than 10 default textures are currently supported");
553  }
554  }
555 
556  #endregion
557 
558  private struct SamplerDescription
559  {
560  public TextureFilter Filtering;
561  public TextureAddressMode AddressModeU;
562  public TextureAddressMode AddressModeV;
563  public TextureAddressMode AddressModeW;
564  }
565  }
566 }
List< NodeParameterSampler > GetAllSamplerValues(IMaterialNode node)
Get all the textures needed for this node.
Key of an effect parameter.
Definition: ParameterKey.cs:15
bool HasUniqueTexcoord(IMaterialNode node, out TextureCoordinate texcoord)
Test if the tree can be reduced to a single texture or color.
void AssignDiffuseTextureKeys(IMaterialNode node)
Assign the diffuse texture keys to the texture slots.
List< MaterialTextureNode > GetAllModelTextureValuesWithGenerics()
Get all the textures for this model.
TextureAddressMode
Identify a technique for resolving texture coordinates that are outside of the boundaries of a textur...
void AssignDisplacementTextureKeys(IMaterialNode node)
Assign the displacement texture keys to the texture slots.
TextureCoordinate
The texture coordinate.
TextureFilter
Filtering options during texture sampling.
List< MaterialTextureNode > GetAllTextureValues()
Get all the texture from this material.
List< MaterialTextureNode > GetAllTextureValues(IMaterialNode node)
Get all the textures needed for this node.
void AssignSpecularTextureKeys(IMaterialNode node)
Assign the specular texture keys to the texture slots.
void AssignDefaultTextureKeys(IMaterialNode node)
Assign the default texture keys to the texture slots.
void AssignDefaultTextureKeys(IEnumerable< MaterialTextureNode > nodes, IEnumerable< NodeParameterSampler > samplers)
Assign the default texture keys to the texture slots.
List< MaterialTextureNode > GetAllTextureValuesWithGenerics(IMaterialNode node)
Get all the textures needed for this node with the potential generic parameters.
void AssignNormalMapTextureKeys(IMaterialNode node)
Assign the normal map texture keys to the texture slots.
List< NodeParameterSampler > GetAllSamplerValues()
Get all the Sampler from the generics for this model.
Base interface for all nodes in the material tree
List< MaterialTextureNode > GetAllModelTextureValues()
Get all the textures for this model.
Base class for texture resources.
Definition: Texture.cs:38