Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
EntityComponentEnumerator.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Reflection;
5 using System.Threading.Tasks;
6 
7 using SiliconStudio.Paradox;
8 using SiliconStudio.Paradox.DataModel;
9 using SiliconStudio.Paradox.Effects;
10 using SiliconStudio.Paradox.Engine;
11 using SiliconStudio.Paradox.EntityModel;
12 using SiliconStudio.Paradox.Games;
13 using SiliconStudio.Paradox.Graphics;
14 using SiliconStudio.Paradox.Graphics.Data;
15 using SiliconStudio.Paradox.Games.Mathematics;
16 using SiliconStudio.Paradox.Games.MicroThreading;
17 using SiliconStudio.Paradox.Games.ViewModel;
18 using SiliconStudio.Paradox.Games.Serialization.Contents;
19 
20 namespace ScriptTest
21 {
23  {
24  public void GenerateChildren(ViewModelContext context, IViewModelNode viewModelNode, ref bool handled)
25  {
26  throw new NotImplementedException();
27  }
28  }
29 
31  {
32  private EngineContext engineContext;
33 
34  public EntityComponentEnumerator(EngineContext engineContext)
35  {
36  this.engineContext = engineContext;
37  }
38 
39  public void GenerateChildren(ViewModelContext context, IViewModelNode viewModelNode, ref bool handled)
40  {
41  bool handleValueType = false;
42 
43  if (viewModelNode.NodeValue is MicroThread)
44  {
45  var microThread = (MicroThread)viewModelNode.NodeValue;
46  var script = microThread.Get(ScriptManager.ScriptProperty);
47 
48  viewModelNode.Content = new EnumerableViewModelContent<ViewModelReference>(() => new[] { new ViewModelReference(script, true) });
49 
50  handled = true;
51  }
52  else if (viewModelNode.NodeValue is IScript)
53  {
54  var script = (IScript)viewModelNode.NodeValue;
55 
56  // Expose all variables of IScript (defined by user)
57  foreach (var property in script.GetType().GetProperties())
58  {
59  if (property.PropertyType != typeof(int) && property.PropertyType != typeof(float))
60  continue;
61 
62  viewModelNode.Children.Add(new ViewModelNode(property.Name, new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), property)));
63  }
64  handled = true;
65  }
66  else if (viewModelNode.NodeValue is Entity)
67  {
68  ViewModelNode componentsViewModelNode;
69 
70  viewModelNode.Children.Add(new ViewModelNode("Name", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(Entity).GetProperty("Name"))));
71  viewModelNode.Children.Add(new ViewModelNode("Guid", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(Entity).GetProperty("Guid"))));
72  viewModelNode.Children.Add(componentsViewModelNode = new ViewModelNode("Components", EnumerableViewModelContent.FromUnaryLambda<ViewModelReference, Entity>(new ParentNodeValueViewModelContent(),
73  (entity) => entity.Properties
74  .Select(x => x.Value)
75  .OfType<EntityComponent>()
76  .Select(x => new ViewModelReference(x, true)))));
77 
78  var availableKeysContent = new RootViewModelContent(null, typeof(string[]));
79  componentsViewModelNode.Children.Add(new ViewModelNode("AvailableKeys", availableKeysContent));
80 
81  componentsViewModelNode.Children.Add(new ViewModelNode("RequestKeys", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
82  {
83  var availableComponentKeys = new List<string>();
84 
85  // TODO: Improve component keys enumeration (maybe need a registry?)
86  // For now, scan assemblies for all types inheriting from EntityComponent
87  foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
88  {
89  foreach (var type in assembly.GetTypes())
90  {
91  if (type.IsSubclassOf(typeof(EntityComponent))
92  && type.GetField("Key", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy) != null)
93  {
94  availableComponentKeys.Add(type.AssemblyQualifiedName);
95  }
96  }
97  }
98 
99  availableKeysContent.Value = availableComponentKeys.ToArray();
100  }))));
101 
102  componentsViewModelNode.Children.Add(new ViewModelNode("Add", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
103  {
104  var entity = (Entity)viewModel2.Parent.Parent.NodeValue;
105  var componentType = Type.GetType((string)parameter);
106 
107  // For now, assume it will be stored in a PropertyKey inside the actual component named "Key"
108  var componentKeyField = componentType.GetField("Key", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
109  entity.SetObject((PropertyKey)componentKeyField.GetValue(null), Activator.CreateInstance(componentType));
110  }))));
111 
112  handled = true;
113  }
114  else if (viewModelNode.NodeValue is EntityComponent)
115  {
116  viewModelNode.PropertyName = "EntityComponent";
117  var component = (EntityComponent)viewModelNode.NodeValue;
118  // Would be better higher in the hierarchy, but it would complicate model
119  var propertyKey = component.Entity.Properties.First(x => x.Value == component).Key;
120  var propertyKeyName = propertyKey.OwnerType.Name;
121  viewModelNode.Children.Add(new ViewModelNode("PropertyKeyName", new RootViewModelContent(propertyKeyName)));
122  viewModelNode.Children.Add(new ViewModelNode("Remove", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
123  {
124  component.Entity.SetObject(propertyKey, null);
125  }))));
126 
127  var componentViewModel = new ViewModelNode("Component", component);
128  viewModelNode.Children.Add(componentViewModel);
129  if (component is TransformationComponent)
130  {
131  componentViewModel.Children.Add(new ViewModelNode("WorldMatrix", new FieldInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(TransformationComponent).GetField("WorldMatrix"))).GenerateChildren(context));
132 
133  // TODO: How to switch view model depending on TransformationComponent.Values type? Or should we always expose everything?
134  componentViewModel.Children.Add(new ViewModelNode("LocalMatrix", new FieldInfoViewModelContent(new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(TransformationComponent).GetProperty("Value")), typeof(TransformationValue).GetField("LocalMatrix"))).GenerateChildren(context));
135 
136  //if (((TransformationComponent)component).Values is TransformationTRS)
137  {
138  componentViewModel.Children.Add(new ViewModelNode("Translation", new FieldInfoViewModelContent(new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(TransformationComponent).GetProperty("Value")), typeof(TransformationTRS).GetField("Translation"))).GenerateChildren(context));
139  componentViewModel.Children.Add(new ViewModelNode("Rotation", new FieldInfoViewModelContent(new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(TransformationComponent).GetProperty("Value")), typeof(TransformationTRS).GetField("Rotation"))).GenerateChildren(context));
140  componentViewModel.Children.Add(new ViewModelNode("Scaling", new FieldInfoViewModelContent(new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(TransformationComponent).GetProperty("Value")), typeof(TransformationTRS).GetField("Scaling"))).GenerateChildren(context));
141  }
142 
143  componentViewModel.Children.Add(new ViewModelNode("Parent", LambdaViewModelContent<ViewModelReference>.FromOperand<EntityComponent>(new ParentNodeValueViewModelContent(), x => new ViewModelReference(x.Entity, false))));
144  componentViewModel.Children.Last().Children.Add(new ViewModelNode("SetAsRoot", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
145  {
146  context.ViewModelByGuid.Clear();
147  context.Root = context.GetModelView(((TransformationComponent)component).Parent.Entity).Children.First(x => x.PropertyName == "Components");
148  }))));
149  }
150  if (component is ModelComponent)
151  {
152  componentViewModel.Children.Add(new ViewModelNode("Parameters", ((ModelComponent)component).MeshParameters).GenerateChildren(context));
153  //componentViewModel.Children.Add(new ViewModelNode(
154  // "MeshParameters",
155  // EnumerableViewModelContent.FromUnaryLambda<ViewModelReference, ModelComponent>(
156  // new ParentNodeValueViewModelContent(),
157  // (ModelComponent) => ModelComponent.MeshParameters.Keys.Select(key => new ViewModelReference(Tuple.Create(ModelComponent.MeshParameters, key), true)))));
158  }
159  if (component is LightComponent)
160  {
161  componentViewModel.Children.Add(new ViewModelNode("Type", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("Type"))).GenerateChildren(context));
162  componentViewModel.Children.Add(new ViewModelNode("ShadowMap", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("ShadowMap"))).GenerateChildren(context));
163  componentViewModel.Children.Add(new ViewModelNode("Deferred", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("Deferred"))).GenerateChildren(context));
164  componentViewModel.Children.Add(new ViewModelNode("Intensity", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("Intensity"))).GenerateChildren(context));
165  componentViewModel.Children.Add(new ViewModelNode("DecayStart", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("DecayStart"))).GenerateChildren(context));
166  componentViewModel.Children.Add(new ViewModelNode("Color", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("Color"))).GenerateChildren(context));
167  componentViewModel.Children.Add(new ViewModelNode("LightDirection", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightComponent).GetProperty("LightDirection"))).GenerateChildren(context));
168  }
169  if (component is LightShaftsComponent)
170  {
171  componentViewModel.Children.Add(new ViewModelNode("Color", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightShaftsComponent).GetProperty("Color"))).GenerateChildren(context));
172  //componentViewModel.Children.Add(new ViewModelNode("LightShaftsBoundingBoxes", new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), typeof(LightShaftsComponent).GetProperty("LightShaftsBoundingBoxes"))).GenerateChildren(context));
173  }
174 
175  // Else try to display it using auto-display
176  AutoDisplayComponent(context, viewModelNode, component);
177 
178  handled = true;
179  }
180  else if (viewModelNode.NodeValue is ParameterCollection)
181  {
182  viewModelNode.Content = EnumerableViewModelContent.FromUnaryLambda<ViewModelReference, ParameterCollection>(new NodeValueViewModelContent(), (parameterCollection) =>
183  parameterCollection.Keys.Where(key => key.PropertyType.IsValueType).Select(key =>
184  {
185  if (key.PropertyType.IsValueType)
186  {
187  // For value type, generated tree won't change so make value based on key only.
188  return new ViewModelReference(Tuple.Create(parameterCollection, key), true);
189  }
190  else
191  {
192  // TODO: resources currently ignored (until fixed)
193 
194  // For reference type, make value dependent on actual value reference and source.
195  // This will trigger a regeneration for reference change (i.e. new texture bound).
196  // Useful since asset type/state might be different.
197  var value = parameterCollection.GetObject(key);
198  var valueSource = engineContext.AssetManager.Url.Get(value);
199  return new ViewModelReference(Tuple.Create(parameterCollection, key, valueSource), true);
200  }
201  }));
202 
203  var availableKeysContent = new RootViewModelContent(null, typeof(string[]));
204  viewModelNode.Children.Add(new ViewModelNode("AvailableKeys", availableKeysContent));
205 
206  viewModelNode.Children.Add(new ViewModelNode("RequestKeys", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
207  {
208  var parameterCollection = (ParameterCollection)viewModel2.Parent.NodeValue;
209  var effectMesh = viewModel2.Parent.Parent.NodeValue as EffectMesh;
210  if (effectMesh != null)
211  {
212  var availableKeys = effectMesh.Effect.Passes.SelectMany(x => x.DefaultParameters.Parameters.Select(y => y.Key)).Distinct().Where(x => !parameterCollection.IsValueOwner(x)).Select(x => x.Name).ToArray();
213  availableKeysContent.Value = availableKeys;
214  }
215  }))));
216 
217  viewModelNode.Children.Add(new ViewModelNode("Add", new RootViewModelContent((ExecuteCommand)((viewModel2, parameter) =>
218  {
219  var effectMesh = viewModel2.Parent.Parent.NodeValue as EffectMesh;
220  if (effectMesh != null)
221  {
222  var key = effectMesh.Effect.Passes.SelectMany(x => x.DefaultParameters.Parameters.Select(y => y.Key)).FirstOrDefault(x => x.Name == (string)parameter);
223  if (key != null)
224  {
225  effectMesh.Parameters.SetDefault(key);
226  }
227  }
228  }))));
229  }
230  else if (viewModelNode.NodeValue is EffectMesh)
231  {
232  viewModelNode.PropertyName = "Mesh";
233  viewModelNode.Children.Add(new ViewModelNode("Effect", LambdaViewModelContent<string>.FromParent<EffectMesh>(x => x.EffectMeshData.EffectData.Name, (x, effectName) => x.EffectMeshData.EffectData.Name = effectName)));
234  viewModelNode.Children.Add(new ViewModelNode("Parameters", ((EffectMesh)viewModelNode.NodeValue).Parameters).GenerateChildren(context));
235  //viewModelNode.Children.Add(new ViewModelNode("MeshData", LambdaViewModelContent<ViewModelReference>.FromParent<MeshData>(effectMeshData => new ViewModelReference(effectMeshData.MeshData, true))));
236  handled = true;
237  }
238  else if (viewModelNode.NodeValue is ContentData || typeof(ContentData).IsAssignableFrom(viewModelNode.Type))
239  {
240  if (viewModelNode.NodeValue is ContentData)
241  viewModelNode.Content = new NodeValueViewModelContent();
242 
243  if (viewModelNode.Value != null)
244  {
245  viewModelNode.Children.Add(new ViewModelNode("Url", new LambdaViewModelContent<string>(new ParentValueViewModelContent(),
246  x => engineContext.AssetManager.Url.Get((x.Value)),
247  (x, y) =>
248  {
249  var nodeValue = x.OwnerNode.Parent.NodeValue;
250  })));
251 
252  viewModelNode.Children.Add(new ViewModelNode("ChangeUrl", new RootViewModelContent((ExecuteCommand)(async (viewModel2, parameter) =>
253  {
254  var dropParameters = (DropCommandParameters)parameter;
255  var parameterInfo = (Tuple<ParameterCollection, ParameterKey, ContentData>)viewModel2.Parent.Parent.NodeValue;
256 
257  var parameterCollection = parameterInfo.Item1;
258 
259  var textureData = await engineContext.AssetManager.LoadAsync<Image>((string)dropParameters.Data);
260  //parameter.Item1.SetObject(parameter.Item2, );
261  //parameterCollection.Remove(parameterInfo.Item2);
262 
263  //var texture = engineContext.ContentManager.Convert<ITexture, Image>(textureData);
264  Texture texture;
265  throw new NotImplementedException();
266 
267  parameterCollection.SetObject(parameterInfo.Item2, texture);
268  }))));
269 
270  if (viewModelNode.Type == typeof(Image))
271  {
272  Image thumbnail = null;
273  Task<Image> textureData = null;
274 
275  viewModelNode.Children.Add(new ViewModelNode("Thumbnail", new LambdaViewModelContent<Image>(new ParentValueViewModelContent(), (viewModelContent) =>
276  {
277  if (textureData == null)
278  {
279  var textureDataNew = viewModelContent.Value as Image;
280  if (engineContext.AssetManager.Url.Get(textureDataNew) != null)
281  {
282  textureData = engineContext.AssetManager.LoadAsync<Image>(engineContext.AssetManager.Url.Get(textureDataNew));
283  textureData.ContinueWith(task =>
284  {
285  thumbnail = task.Result;
286  viewModelContent.OwnerNode.Content.SerializeFlags |= ViewModelContentSerializeFlags.Static;
287  });
288  }
289  }
290  return thumbnail;
291  })));
292  }
293  }
294 
295  handled = true;
296  }
297  else if (viewModelNode.NodeValue is MeshData)
298  {
299  handled = true;
300  }
301  else if (viewModelNode.NodeValue is Tuple<ParameterCollection, ParameterKey, ContentData>)
302  {
303  var value = (Tuple<ParameterCollection, ParameterKey, ContentData>)viewModelNode.NodeValue;
304 
305  // Ignore namespace and class name for key name
306  viewModelNode.PropertyName = value.Item2.Name;
307  if (viewModelNode.PropertyName.Contains('.'))
308  viewModelNode.PropertyName = viewModelNode.PropertyName.Substring(viewModelNode.PropertyName.LastIndexOf('.') + 1);
309 
310  viewModelNode.Content = new NullViewModelContent(typeof(Image));
311  if (value.Item3 != null)
312  viewModelNode.Children.Add(new ViewModelNode("ObjectRef", new RootViewModelContent(value.Item3) { SerializeFlags = ViewModelContentSerializeFlags.None }).GenerateChildren(context));
313  handled = true;
314  }
315  else if (viewModelNode.NodeValue is Tuple<ParameterCollection, ParameterKey>)
316  {
317  var value = (Tuple<ParameterCollection, ParameterKey>)viewModelNode.NodeValue;
318 
319  // Ignore namespace and class name for key name
320  viewModelNode.PropertyName = value.Item2.Name;
321  if (viewModelNode.PropertyName.Contains('.'))
322  viewModelNode.PropertyName = viewModelNode.PropertyName.Substring(viewModelNode.PropertyName.LastIndexOf('.') + 1);
323 
324  if (value.Item2.PropertyType.IsValueType)
325  {
326  viewModelNode.Content =
327  new LambdaViewModelContent<object>(() => value.Item1.GetObject(value.Item2), newValue => value.Item1.SetObject(value.Item2, newValue))
328  {
329  Type = value.Item2.PropertyType
330  };
331 
332  handleValueType = true;
333  }
334  handled = true;
335  }
336  else if (viewModelNode.Type == typeof(Matrix) || viewModelNode.Type == typeof(Vector3) || viewModelNode.Type == typeof(Color))
337  {
338  handled = true;
339  }
340  else if (viewModelNode.Type.IsValueType)
341  {
342  handleValueType = true;
343  }
344 
345  if (handleValueType)
346  {
347  if (!(viewModelNode.Type == typeof(Matrix) || viewModelNode.Type == typeof(Vector3) || viewModelNode.Type == typeof(Color) || viewModelNode.Type == typeof(Color3)))
348  {
349  if (viewModelNode.Type.IsValueType && !viewModelNode.Type.IsPrimitive && !viewModelNode.Type.IsEnum)
350  {
351  viewModelNode.Content.SerializeFlags = ViewModelContentSerializeFlags.None;
352  // Use default for those types
353  foreach (var fieldinfo in viewModelNode.Type.GetFields(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance))
354  {
355 
356  IViewModelContent viewModelContent = new FieldInfoViewModelContent(new ParentValueViewModelContent(viewModelNode.Type), fieldinfo);
357  //if (fieldinfo.FieldType.IsValueType && !fieldinfo.FieldType.IsPrimitive && !fieldinfo.FieldType.IsEnum)
358  // viewModelContent.Flags = ViewModelFlags.None;
359  // Doesn't support array
360  if (fieldinfo.FieldType.IsArray)
361  continue;
362  viewModelNode.Children.Add(new ViewModelNode(fieldinfo.Name, viewModelContent).GenerateChildren(context));
363  }
364  handled = true;
365  }
366  }
367  }
368  }
369 
370  /// <summary>
371  /// Display components that are tagged with the <see cref="DisplayAttribute"/>.
372  /// </summary>
373  /// <param name="context">Context of the view model.</param>
374  /// <param name="viewModel">The current view model</param>
375  /// <param name="component">The entity component to display</param>
376  private void AutoDisplayComponent(ViewModelContext context, IViewModelNode viewModel, EntityComponent component)
377  {
378  var displayComp = DisplayAttribute.GetDisplay(component.GetType());
379  if (displayComp == null)
380  return;
381 
382  var componentViewModel = viewModel.GetChildrenByName("Component");
383  if (componentViewModel == null)
384  return;
385 
386  // Change the name of the component being displayed
387  if (!string.IsNullOrEmpty(displayComp.Name))
388  {
389  var componentName = viewModel.GetChildrenByName("PropertyKeyName");
390  if (componentName != null)
391  {
392  componentName.Value = displayComp.Name;
393  }
394  }
395 
396  var propertyToDisplay = new List<Tuple<DisplayAttribute, ViewModelNode>>();
397  var memberInfos = new List<MemberInfo>();
398  memberInfos.AddRange(component.GetType().GetProperties());
399  memberInfos.AddRange(component.GetType().GetFields());
400 
401  // Process fields and properties
402  foreach (var property in memberInfos)
403  {
404  var display = DisplayAttribute.GetDisplay(property);
405  if (display == null) continue;
406 
407  IViewModelContent modelContent = null;
408  object modelValue = null;
409 
410  var propertyInfo = property as PropertyInfo;
411  if (propertyInfo != null)
412  {
413  if (typeof(ParameterCollection).IsAssignableFrom(propertyInfo.PropertyType))
414  {
415  modelValue = propertyInfo.GetValue(component, null);
416  }
417  else
418  {
419  modelContent = new PropertyInfoViewModelContent(new ParentNodeValueViewModelContent(), propertyInfo);
420  }
421  }
422 
423  var fieldInfo = property as FieldInfo;
424  if (fieldInfo != null)
425  {
426  if (typeof(ParameterCollection).IsAssignableFrom(fieldInfo.FieldType))
427  {
428  modelValue = fieldInfo.GetValue(component);
429  }
430  else
431  {
432  modelContent = new FieldInfoViewModelContent(new ParentNodeValueViewModelContent(), fieldInfo);
433  }
434  }
435 
436  var propertyViewModel = modelValue != null ? new ViewModelNode(display.Name ?? property.Name, modelValue) : new ViewModelNode(display.Name ?? property.Name, modelContent);
437  propertyViewModel.GenerateChildren(context);
438  propertyToDisplay.Add(new Tuple<DisplayAttribute, ViewModelNode>(display, propertyViewModel));
439  }
440 
441  foreach(var item in propertyToDisplay.OrderBy((left) => left.Item1.Order))
442  {
443  componentViewModel.Children.Add(item.Item2);
444  }
445  }
446  }
447 }
Add a light to an Entity, that will be used during rendering.
Game entity. It usually aggregates multiple EntityComponent
Definition: Entity.cs:28
Defines Position, Rotation and Scale of its Entity.
Provides method to instantiate an image 1D/2D/3D supporting TextureArray and mipmaps on the CPU or to...
Definition: Image.cs:88
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
void GenerateChildren(ViewModelContext context, IViewModelNode viewModelNode, ref bool handled)
SiliconStudio.Core.Mathematics.Color Color
Definition: ColorPicker.cs:14
void GenerateChildren(ViewModelContext context, IViewModelNode viewModelNode, ref bool handled)
Add a Model to an Entity, that will be used during rendering.
SiliconStudio.Core.Mathematics.Vector3 Vector3
A container to handle a hierarchical collection of effect variables.
EntityComponentEnumerator(EngineContext engineContext)
Base class for texture resources.
Definition: Texture.cs:38