Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
ImportModelCommand.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.Threading;
7 using System.Threading.Tasks;
8 
9 using SiliconStudio.Core.Mathematics;
10 using SiliconStudio.Paradox.DataModel;
11 using SiliconStudio.Paradox.Effects;
12 using SiliconStudio.Paradox.Effects.Data;
13 using SiliconStudio.Paradox.Extensions;
14 using SiliconStudio.Core.Serialization;
15 using SiliconStudio.Core.Serialization.Assets;
16 using SiliconStudio.Paradox.Graphics;
17 using SiliconStudio.Paradox.Graphics.Data;
18 using SiliconStudio.Paradox.Shaders;
19 
20 namespace SiliconStudio.BuildEngine
21 {
23  {
24  private delegate bool SameGroup(MeshData baseMesh, MeshData newMesh);
25 
26  /// <inheritdoc/>
27  public override IEnumerable<Tuple<string, string>> TagList { get { yield return Tuple.Create("Texture", "Value of the TextureTag property"); } }
28 
29  private static int spawnedFbxCommands;
31 
32  public string TextureTag { get; set; }
33 
34  public string ExportType { get; set; }
35  public bool TessellationAEN { get; set; }
36  public string EffectName { get; set; }
38 
39  public Dictionary<string, Tuple<Guid, string>> Materials { get; set; }
40  public Dictionary<string, Tuple<Guid, string>> Lightings { get; set; }
41  public Dictionary<string, ParameterCollectionData> Parameters;
42 
43  public bool Compact { get; set; }
44  public List<string> PreservedNodes { get; set; }
45 
46  public bool Allow32BitIndex { get; set; }
47  public bool AllowUnsignedBlendIndices { get; set; }
48  public Vector3 ViewDirectionForTransparentZSort { get; set; }
49 
50  protected ImportModelCommand()
51  {
52  // Set default values
53  ExportType = "model";
54  TextureTag = "fbx-texture";
55  TextureTagSymbol = RegisterTag("Texture", () => TextureTag);
56  AnimationRepeatMode = AnimationRepeatMode.LoopInfinite;
57  }
58 
59  private string ContextAsString
60  {
61  get
62  {
63  return string.Format("model [{0}] from import [{1}]", Location, SourcePath);
64  }
65  }
66 
67  protected override async Task<ResultStatus> DoCommandOverride(ICommandContext commandContext)
68  {
69  var assetManager = new AssetManager();
70 
71  while (Interlocked.Increment(ref spawnedFbxCommands) >= 2)
72  {
73  Interlocked.Decrement(ref spawnedFbxCommands);
74  await Task.Delay(1, CancellationToken);
75  }
76 
77  try
78  {
79  object exportedObject;
80 
81  if (ExportType == "animation")
82  {
83  // Read from model file
84  var animationClip = LoadAnimation(commandContext, assetManager);
85  exportedObject = animationClip;
86  if (animationClip == null)
87  {
88  commandContext.Logger.Info("File {0} has an empty animation.", SourcePath);
89  }
90  else if (animationClip.Duration.Ticks == 0)
91  {
92  commandContext.Logger.Warning("File {0} has a 0 tick long animation.", SourcePath);
93  }
94  else
95  {
96  animationClip.RepeatMode = AnimationRepeatMode;
97  animationClip.Optimize();
98  }
99  }
100  else if (ExportType == "model")
101  {
102  // Read from model file
103  var model = LoadModel(commandContext, assetManager);
104 
105  model.BoundingBox = BoundingBox.Empty;
106  var hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
107  hierarchyUpdater.UpdateMatrices();
108 
109  bool hasErrors = false;
110  foreach (var mesh in model.Meshes)
111  {
112  if (TessellationAEN)
113  {
114  // TODO: Generate AEN model view
115  commandContext.Logger.Error("TessellationAEN is not supported in {0}", ContextAsString);
116  hasErrors = true;
117  continue;
118  }
119 
120  if (!Materials.ContainsKey(mesh.Name))
121  {
122  commandContext.Logger.Error("Mesh material [{0}] was not found in {1}", mesh.Name, ContextAsString);
123  hasErrors = true;
124  continue;
125  }
126 
127  // set the material
128  var materialReference = Materials[mesh.Name];
129  mesh.Material = new ContentReference<MaterialData>(materialReference.Item1, materialReference.Item2);
130 
131  // set the parameters
132  if (Parameters.ContainsKey(mesh.Name) && Parameters[mesh.Name] != null)
133  {
134  if (mesh.Parameters == null)
135  mesh.Parameters = new ParameterCollectionData();
136  foreach (var keyValue in Parameters[mesh.Name])
137  mesh.Parameters.Set(keyValue.Key, keyValue.Value);
138  }
139 
140  // TODO: remove this when Lighting configuration will be behind a key in mesh parameters. This case will be handled by the code just above
141  // set the lighting configuration description
142  Tuple<Guid, string> lightingReference;
143  if (Lightings.TryGetValue(mesh.Name, out lightingReference))
144  mesh.Parameters.Set(LightingKeys.LightingConfigurations, new ContentReference<LightingConfigurationsSetData>(lightingReference.Item1, lightingReference.Item2));
145  }
146 
147  // split the meshes if necessary
148  model.Meshes = SplitExtensions.SplitMeshes(model.Meshes, Allow32BitIndex);
149 
150  // merge the meshes
151  if (Compact)
152  {
153  var indicesBlackList = new HashSet<int>();
154  if (PreservedNodes != null)
155  {
156  for (var index = 0; index < model.Hierarchy.Nodes.Length; ++index)
157  {
158  var node = model.Hierarchy.Nodes[index];
159  if (PreservedNodes.Contains(node.Name))
160  indicesBlackList.Add(index);
161  }
162  }
163 
164  // group meshes with same material and same root
165  var sameMaterialMeshes = new List<GroupList<int, MeshData>>();
166  GroupFromIndex(model, 0, indicesBlackList, model.Meshes, sameMaterialMeshes);
167 
168  // remove meshes that cannot be merged
169  var excludedMeshes = new List<MeshData>();
170  var finalMeshGroups = new List<GroupList<int, MeshData>>();
171  foreach (var meshList in sameMaterialMeshes)
172  {
173  var mergeList = new GroupList<int, MeshData> { Key = meshList.Key };
174 
175  foreach (var mesh in meshList)
176  {
177  if (mesh.Skinning != null || indicesBlackList.Contains(mesh.NodeIndex))
178  excludedMeshes.Add(mesh);
179  else
180  mergeList.Add(mesh);
181  }
182 
183  if (mergeList.Count <= 1)
184  excludedMeshes.AddRange(mergeList);
185  else
186  finalMeshGroups.Add(mergeList);
187  }
188 
189  var finalMeshes = new List<MeshData>();
190 
191  finalMeshes.AddRange(excludedMeshes);
192 
193  foreach (var meshList in finalMeshGroups)
194  {
195  // transform the buffers
196  foreach (var mesh in meshList)
197  {
198  var transformationMatrix = GetMatrixFromIndex(model.Hierarchy.Nodes, hierarchyUpdater, meshList.Key, mesh.NodeIndex);
199  mesh.Draw.VertexBuffers[0].TransformBuffer(ref transformationMatrix);
200  }
201 
202  // refine the groups base on several tests
203  var newMeshGroups = new List<GroupList<int, MeshData>> { meshList };
204  // only regroup meshes if they share the same parameters
205  newMeshGroups = RefineGroups(newMeshGroups, CompareParameters);
206  // only regroup meshes if they share the shadow options
207  newMeshGroups = RefineGroups(newMeshGroups, CompareShadowOptions);
208  //only regroup meshes if they share the same lighting configurations
209  newMeshGroups = RefineGroups(newMeshGroups, CompareLightingConfigurations);
210 
211 
212  // add to the final meshes groups
213  foreach (var sameParamsMeshes in newMeshGroups)
214  {
215  var baseMesh = sameParamsMeshes[0];
216  var newMeshList = sameParamsMeshes.Select(x => x.Draw).ToList().GroupDrawData(Allow32BitIndex);
217  foreach (var generatedMesh in newMeshList)
218  {
219  finalMeshes.Add(new MeshData {
220  Material = baseMesh.Material,
221  Parameters = baseMesh.Parameters,
222  Name = baseMesh.Name,
223  Draw = generatedMesh,
224  NodeIndex = meshList.Key,
225  Skinning = null,
226  });
227  }
228  }
229  }
230 
231  // delete empty nodes (neither mesh nor bone attached)
232  var keptNodes = new bool[model.Hierarchy.Nodes.Length];
233  for (var i = 0; i < keptNodes.Length; ++i)
234  {
235  keptNodes[i] = false;
236  }
237  foreach (var keepIndex in indicesBlackList)
238  {
239  var nodeIndex = keepIndex;
240  while (nodeIndex != -1 && !keptNodes[nodeIndex])
241  {
242  keptNodes[nodeIndex] = true;
243  nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
244  }
245  }
246  foreach (var mesh in finalMeshes)
247  {
248  var nodeIndex = mesh.NodeIndex;
249  while (nodeIndex != -1 && !keptNodes[nodeIndex])
250  {
251  keptNodes[nodeIndex] = true;
252  nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
253  }
254 
255  if (mesh.Skinning != null)
256  {
257  foreach (var bone in mesh.Skinning.Bones)
258  {
259  nodeIndex = bone.NodeIndex;
260  while (nodeIndex != -1 && !keptNodes[nodeIndex])
261  {
262  keptNodes[nodeIndex] = true;
263  nodeIndex = model.Hierarchy.Nodes[nodeIndex].ParentIndex;
264  }
265  }
266  }
267  }
268 
269  var newNodes = new List<ModelNodeDefinition>();
270  var newMapping = new int[model.Hierarchy.Nodes.Length];
271  for (var i = 0; i < keptNodes.Length; ++i)
272  {
273  if (keptNodes[i])
274  {
275  var parentIndex = model.Hierarchy.Nodes[i].ParentIndex;
276  if (parentIndex != -1)
277  model.Hierarchy.Nodes[i].ParentIndex = newMapping[parentIndex]; // assume that the nodes are well ordered
278  newMapping[i] = newNodes.Count;
279  newNodes.Add(model.Hierarchy.Nodes[i]);
280  }
281  }
282 
283  foreach (var mesh in finalMeshes)
284  {
285  mesh.NodeIndex = newMapping[mesh.NodeIndex];
286 
287  if (mesh.Skinning != null)
288  {
289  for (var i = 0; i < mesh.Skinning.Bones.Length; ++i)
290  {
291  mesh.Skinning.Bones[i].NodeIndex = newMapping[mesh.Skinning.Bones[i].NodeIndex];
292  }
293  }
294  }
295 
296  model.Meshes = finalMeshes;
297  model.Hierarchy.Nodes = newNodes.ToArray();
298 
299  hierarchyUpdater = new ModelViewHierarchyUpdater(model.Hierarchy.Nodes);
300  hierarchyUpdater.UpdateMatrices();
301  }
302 
303  // bounding boxes
304  foreach (var mesh in model.Meshes)
305  {
306  var vertexBuffers = mesh.Draw.VertexBuffers;
307  if (vertexBuffers.Length > 0)
308  {
309  // Compute local mesh bounding box (no node transformation)
310  Matrix matrix = Matrix.Identity;
311  mesh.BoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);
312 
313  // Compute model bounding box (includes node transformation)
314  hierarchyUpdater.GetWorldMatrix(mesh.NodeIndex, out matrix);
315  var meshBoundingBox = vertexBuffers[0].ComputeBoundingBox(ref matrix);
316  BoundingBox.Merge(ref model.BoundingBox, ref meshBoundingBox, out model.BoundingBox);
317  }
318 
319  // TODO: temporary Always try to compact
320  mesh.Draw.CompactIndexBuffer();
321  }
322 
323  // merges all the Draw VB and IB together to produce one final VB and IB by entity.
324  var sizeVertexBuffer = model.Meshes.SelectMany(x => x.Draw.VertexBuffers).Select(x => x.Buffer.Value.Content.Length).Sum();
325  var sizeIndexBuffer = model.Meshes.Select(x => x.Draw.IndexBuffer).Select(x => x.Buffer.Value.Content.Length).Sum();
326  var vertexBuffer = new BufferData(BufferFlags.VertexBuffer, new byte[sizeVertexBuffer]);
327  var indexBuffer = new BufferData(BufferFlags.IndexBuffer, new byte[sizeIndexBuffer]);
328  var vertexBufferNextIndex = 0;
329  var indexBufferNextIndex = 0;
330  foreach (var drawMesh in model.Meshes.Select(x => x.Draw))
331  {
332  // the index buffer
333  var oldIndexBuffer = drawMesh.IndexBuffer.Buffer.Value.Content;
334 
335  Array.Copy(oldIndexBuffer, 0, indexBuffer.Content, indexBufferNextIndex, oldIndexBuffer.Length);
336 
337  drawMesh.IndexBuffer.Offset = indexBufferNextIndex;
338  drawMesh.IndexBuffer.Buffer = indexBuffer;
339 
340  indexBufferNextIndex += oldIndexBuffer.Length;
341 
342  // the vertex buffers
343  foreach (var vertexBufferBinding in drawMesh.VertexBuffers)
344  {
345  var oldVertexBuffer = vertexBufferBinding.Buffer.Value.Content;
346 
347  Array.Copy(oldVertexBuffer, 0, vertexBuffer.Content, vertexBufferNextIndex, oldVertexBuffer.Length);
348 
349  vertexBufferBinding.Offset = vertexBufferNextIndex;
350  vertexBufferBinding.Buffer = vertexBuffer;
351 
352  vertexBufferNextIndex += oldVertexBuffer.Length;
353  }
354  }
355 
356 
357  // If there were any errors while importing models
358  if (hasErrors)
359  {
360  return ResultStatus.Failed;
361  }
362 
363  // Convert to Entity
364  exportedObject = model;
365  }
366  else
367  {
368  commandContext.Logger.Error("Unknown export type [{0}] {1}", ExportType, ContextAsString);
369  return ResultStatus.Failed;
370  }
371 
372  if (exportedObject != null)
373  assetManager.Save(Location, exportedObject);
374 
375  commandContext.Logger.Info("The {0} has been successfully imported.", ContextAsString);
376 
377  return ResultStatus.Successful;
378  }
379  catch (Exception ex)
380  {
381  commandContext.Logger.Error("Unexpected error while importing {0}", ex, ContextAsString);
382  return ResultStatus.Failed;
383  }
384  finally
385  {
386  Interlocked.Decrement(ref spawnedFbxCommands);
387  }
388  }
389 
390  /// <summary>
391  /// Refine the mesh groups based on the result of the delegate test method.
392  /// </summary>
393  /// <param name="meshList">The list of mesh groups.</param>
394  /// <param name="sameGroupDelegate">The test delegate.</param>
395  /// <returns>The new list of mesh groups.</returns>
396  private List<GroupList<int, MeshData>> RefineGroups(List<GroupList<int, MeshData>> meshList, SameGroup sameGroupDelegate)
397  {
398  var finalGroups = new List<GroupList<int, MeshData>>();
399  foreach (var meshGroup in meshList)
400  {
401  var updatedGroups = new List<GroupList<int, MeshData>>();
402  foreach (var mesh in meshGroup)
403  {
404  var createNewGroup = true;
405  foreach (var sameParamsMeshes in updatedGroups)
406  {
407  if (sameGroupDelegate(sameParamsMeshes[0], mesh))
408  {
409  sameParamsMeshes.Add(mesh);
410  createNewGroup = false;
411  break;
412  }
413  }
414 
415  if (createNewGroup)
416  {
417  var newGroup = new GroupList<int, MeshData> { Key = meshGroup.Key };
418  newGroup.Add(mesh);
419  updatedGroups.Add(newGroup);
420  }
421  }
422  finalGroups.AddRange(updatedGroups);
423  }
424  return finalGroups;
425  }
426 
427  /// <summary>
428  /// Create groups of mergeable meshes.
429  /// </summary>
430  /// <param name="model">The current model.</param>
431  /// <param name="index">The index of the currently visited node.</param>
432  /// <param name="nodeBlackList">List of the nodes that should be kept.</param>
433  /// <param name="meshes">The meshes and their node index.</param>
434  /// <param name="finalLists">List of mergeable meshes and their root node.</param>
435  /// <returns>A list of mergeable meshes in progress.</returns>
436  private Dictionary<Guid, List<MeshData>> GroupFromIndex(ModelData model, int index, HashSet<int> nodeBlackList, List<MeshData> meshes, List<GroupList<int, MeshData>> finalLists)
437  {
438  var children = GetChildren(model.Hierarchy.Nodes, index);
439 
440  var materialGroups = new Dictionary<Guid, List<MeshData>>();
441 
442  // Get the group from each child
443  foreach (var child in children)
444  {
445  var newMaterialGroups = GroupFromIndex(model, child, nodeBlackList, meshes, finalLists);
446 
447  foreach (var group in newMaterialGroups)
448  {
449  if (!materialGroups.ContainsKey(group.Key))
450  materialGroups.Add(group.Key, new List<MeshData>());
451  materialGroups[group.Key].AddRange(group.Value);
452  }
453  }
454 
455  // Add the current node if it has a mesh
456  foreach (var nodeMesh in meshes.Where(x => x.NodeIndex == index))
457  {
458  var matId = nodeMesh.Material.Id;
459  if (!materialGroups.ContainsKey(matId))
460  materialGroups.Add(matId, new List<MeshData>());
461  materialGroups[matId].Add(nodeMesh);
462  }
463 
464  // Store the generated list as final if the node should be kept
465  if (nodeBlackList.Contains(index) || index == 0)
466  {
467  foreach (var materialGroup in materialGroups)
468  {
469  var groupList = new GroupList<int, MeshData>();
470  groupList.Key = index;
471  groupList.AddRange(materialGroup.Value);
472  finalLists.Add(groupList);
473  }
474  materialGroups.Clear();
475  }
476 
477  return materialGroups;
478  }
479 
480  /// <summary>
481  /// Get the transformation matrix to go from rootIndex to index.
482  /// </summary>
483  /// <param name="hierarchy">The node hierarchy.</param>
484  /// <param name="updater">The updater containing the local matrices.</param>
485  /// <param name="rootIndex">The root index.</param>
486  /// <param name="index">The current index.</param>
487  /// <returns>The matrix at this index.</returns>
488  private Matrix GetMatrixFromIndex(ModelNodeDefinition[] hierarchy, ModelViewHierarchyUpdater updater, int rootIndex, int index)
489  {
490  if (index == -1 || index == rootIndex)
491  return Matrix.Identity;
492 
493  Matrix outMatrix;
494  updater.GetLocalMatrix(index, out outMatrix);
495 
496  if (index != rootIndex)
497  {
498  var topMatrix = GetMatrixFromIndex(hierarchy, updater, rootIndex, hierarchy[index].ParentIndex);
499  outMatrix = Matrix.Multiply(outMatrix, topMatrix);
500  }
501 
502  return outMatrix;
503  }
504 
505  /// <summary>
506  /// Get the children of the requested node.
507  /// </summary>
508  /// <param name="hierarchy">The node hierarchy.</param>
509  /// <param name="index">The current node index.</param>
510  /// <returns>A list of all the indices of the children.</returns>
511  private List<int> GetChildren(ModelNodeDefinition[] hierarchy, int index)
512  {
513  var result = new List<int>();
514  for (var i = 0; i < hierarchy.Length; ++i)
515  {
516  if (hierarchy[i].ParentIndex == index)
517  result.Add(i);
518  }
519  return result;
520  }
521 
522  protected abstract ModelData LoadModel(ICommandContext commandContext, AssetManager assetManager);
523 
524  protected abstract AnimationClip LoadAnimation(ICommandContext commandContext, AssetManager assetManager);
525 
526  protected override void ComputeParameterHash(BinarySerializationWriter writer)
527  {
528  base.ComputeParameterHash(writer);
529 
530  writer.SerializeExtended(this, ArchiveMode.Serialize);
531  }
532 
534  {
535  yield return new ObjectUrl(UrlType.File, SourcePath);
536  }
537 
538  /// <summary>
539  /// Parses a shader source definition
540  /// </summary>
541  /// <param name="shaderSource">The shader source.</param>
542  /// <returns>an instance of ShaderSource.</returns>
543  protected static ShaderSource ParseShaderSource(string shaderSource)
544  {
545  var sources = shaderSource.Split(new[] { ",", ";" }, StringSplitOptions.RemoveEmptyEntries);
546 
547  if (sources.Length == 1)
548  {
549  return new ShaderClassSource(sources[0]);
550  }
551 
552  var mixin = new ShaderMixinSource();
553  foreach (var source in sources)
554  {
555  mixin.Mixins.Add(new ShaderClassSource(source));
556  }
557 
558  return mixin;
559  }
560 
561  /// <summary>
562  /// Compares the parameters of the two meshes.
563  /// </summary>
564  /// <param name="baseMesh">The base mesh.</param>
565  /// <param name="newMesh">The mesh to compare.</param>
566  /// <param name="extra">Unused parameter.</param>
567  /// <returns>True if all the parameters are the same, false otherwise.</returns>
568  private static bool CompareParameters(MeshData baseMesh, MeshData newMesh)
569  {
570  var localParams = baseMesh.Parameters;
571  if (localParams == null && newMesh.Parameters == null)
572  return true;
573  if (localParams == null || newMesh.Parameters == null)
574  return false;
575  return AreCollectionsEqual(localParams, newMesh.Parameters);
576  }
577 
578  /// <summary>
579  /// Compares the shadow options between the two meshes.
580  /// </summary>
581  /// <param name="baseMesh">The base mesh.</param>
582  /// <param name="newMesh">The mesh to compare.</param>
583  /// <param name="extra">Unused parameter.</param>
584  /// <returns>True if the options are the same, false otherwise.</returns>
585  private static bool CompareShadowOptions(MeshData baseMesh, MeshData newMesh)
586  {
587  return CompareKeyValue(baseMesh.Parameters, newMesh.Parameters, LightingKeys.CastShadows)
588  && CompareKeyValue(baseMesh.Parameters, newMesh.Parameters, LightingKeys.ReceiveShadows);
589  }
590 
591  /// <summary>
592  /// Compares the value behind a key in two ParameterCollectionData.
593  /// </summary>
594  /// <param name="parameters0">The first ParameterCollectionData.</param>
595  /// <param name="parameters1">The second ParameterCollectionData.</param>
596  /// <param name="key">The ParameterKey.</param>
597  /// <returns>True</returns>
598  private static bool CompareKeyValue<T>(ParameterCollectionData parameters0, ParameterCollectionData parameters1, ParameterKey<T> key)
599  {
600  var value0 = parameters0.ContainsKey(key) ? parameters0[key] : key.DefaultMetadataT.DefaultValue;
601  var value1 = parameters1.ContainsKey(key) ? parameters1[key] : key.DefaultMetadataT.DefaultValue;
602  return value0 == value1;
603  }
604 
605  /// <summary>
606  /// Compares the lighting configurations of the two meshes.
607  /// </summary>
608  /// <param name="baseMesh">The base mesh.</param>
609  /// <param name="newMesh">The mesh to compare.</param>
610  /// <returns>True if all the configurations are the same, false otherwise.</returns>
611  private static bool CompareLightingConfigurations(MeshData baseMesh, MeshData newMesh)
612  {
613  var config0Content = GetLightingConfigurations(baseMesh);
614  var config1Content = GetLightingConfigurations(newMesh);
615  if (config0Content == null && config1Content == null)
616  return true;
617  if (config0Content == null || config1Content == null)
618  return false;
619  return config0Content.Id == config1Content.Id;
620  }
621 
622  /// <summary>
623  /// Retrives the lighting configurations if present.
624  /// </summary>
625  /// <param name="mesh">The mesh containing the lighting configurations.</param>
626  /// <returns>The content reference to the lighting configuration.</returns>
627  private static ContentReference GetLightingConfigurations(MeshData mesh)
628  {
629  if (mesh != null && mesh.Parameters != null && mesh.Parameters.ContainsKey(LightingKeys.LightingConfigurations))
630  {
631  var config = mesh.Parameters[LightingKeys.LightingConfigurations];
632  if (config != null)
633  return config as ContentReference;
634  }
635  return null;
636  }
637 
638  /// <summary>
639  /// Test if two ParameterCollectionData are equal
640  /// </summary>
641  /// <param name="parameters0">The first ParameterCollectionData.</param>
642  /// <param name="parameters1">The second ParameterCollectionData.</param>
643  /// <returns>True if the collections are the same, false otherwise.</returns>
644  private static bool AreCollectionsEqual(ParameterCollectionData parameters0, ParameterCollectionData parameters1)
645  {
646  bool result = true;
647  foreach (var paramKey in parameters0)
648  {
649  result &= parameters1.ContainsKey(paramKey.Key) && parameters1[paramKey.Key].Equals(paramKey.Value);
650  }
651  foreach (var paramKey in parameters1)
652  {
653  result &= parameters0.ContainsKey(paramKey.Key) && parameters0[paramKey.Key].Equals(paramKey.Value);
654  }
655  return result;
656  }
657 
658  public override string ToString()
659  {
660  return (SourcePath ?? "[File]") + (ExportType != null ? " (" + ExportType + ")" : "") + " > " + (Location ?? "[Location]");
661  }
662 
663  }
664 
665  /// <summary>
666  /// A implementation of IGrouping.
667  /// </summary>
668  /// <typeparam name="TK">Key type.</typeparam>
669  /// <typeparam name="T">Element type.</typeparam>
670  public class GroupList<TK,T> : List<T>, IGrouping<TK,T>
671  {
672  public TK Key { get; set; }
673  }
674 }
Dictionary< string, ParameterCollectionData > Parameters
override async Task< ResultStatus > DoCommandOverride(ICommandContext commandContext)
The method to override containing the actual command code. It is called by the DoCommand function ...
ModelNodeDefinition[] Nodes
The nodes in this hierarchy.
SiliconStudio.Paradox.Effects.Data.ParameterCollectionData Parameters
Data field for SiliconStudio.Paradox.Effects.Mesh.Parameters.
Definition: EngineData.cs:212
override void ComputeParameterHash(BinarySerializationWriter writer)
A mixin performing a combination of ShaderClassSource and other mixins.
Key of an gereric effect parameter.
Represents a three dimensional mathematical vector.
Definition: Vector3.cs:42
Implements SerializationStream as a binary writer.
Data type for SiliconStudio.Paradox.Effects.ParameterCollection.
Definition: ParadoxData.cs:31
An aggregation of AnimationCurve with their channel names.
AnimationRepeatMode
Enumeration describing how an animation should be repeated.
static ShaderSource ParseShaderSource(string shaderSource)
Parses a shader source definition
static readonly ParameterKey< bool > ReceiveShadows
Flag stating if the mesh receives shadows.
Definition: LightingKeys.cs:76
Data type for SiliconStudio.Paradox.Effects.Mesh.
Definition: EngineData.cs:197
static readonly ParameterKey< bool > CastShadows
Flag stating if the mesh casts shadows.
Definition: LightingKeys.cs:68
Data type for SiliconStudio.Paradox.Effects.Model.
Definition: EngineData.cs:241
Performs hierarchical updates for a given Model.
Describes a single transformation node, usually in a Model node hierarchy.
static readonly ParameterKey< LightingConfigurationsSet > LightingConfigurations
Supported lighting configurations.
Definition: LightingKeys.cs:84
Content of a GPU buffer (vertex buffer, index buffer, etc...).
Definition: BufferData.cs:10
SiliconStudio.Paradox.Effects.ModelViewHierarchyDefinition Hierarchy
Data field for SiliconStudio.Paradox.Effects.Model.Hierarchy.
Definition: EngineData.cs:256
override IEnumerable< ObjectUrl > GetInputFiles()
Gets the list of input files (that can be deduced without running the command, only from command para...
Represents a 4x4 mathematical matrix.
Definition: Matrix.cs:47