Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_BasePreviewEntity.c
Go to the documentation of this file.
1 [EntityEditorProps(category: "GameScripted/Preview", description: "", color: "0 0 0 0", dynamicBox: true)]
2 class SCR_BasePreviewEntityClass: GenericEntityClass
3 {
4 };
10 {
11  [Attribute(uiwidget: UIWidgets.Flags, category: "Preview Entity", enums: ParamEnumArray.FromEnum(EPreviewEntityFlag))]
12  protected EPreviewEntityFlag m_Flags;
13 
14  protected IEntity m_Entity;
15  protected IEntitySource m_EntitySource;
16  protected float m_fHeightTerrain = -1;
17  protected bool m_bIsOnOrigTransform = true;
18  protected vector m_vLocalTransform[4];
19  protected vector m_vTerrainTransform[4];
20  protected ref array<SCR_BasePreviewEntity> m_aChildren;
21  protected vector m_vBounds[2];
22  protected bool m_bHasMultipleEditableEntities;
23 
34  static SCR_BasePreviewEntity SpawnPreview(notnull array<ref SCR_BasePreviewEntry> entries, ResourceName previewPrefab, BaseWorld world = null, EntitySpawnParams spawnParams = null, ResourceName material = ResourceName.Empty, EPreviewEntityFlag flags = 0)
35  {
36  if (entries.IsEmpty())
37  {
38  Print("No entries defined!", LogLevel.WARNING);
39  return null;
40  }
41 
42  if (!world)
43  world = GetGame().GetWorld();
44 
45  EntitySpawnParams spawnParamsLocal = spawnParams;
46  if (!spawnParamsLocal)
47  {
48  spawnParamsLocal = new EntitySpawnParams();
49  spawnParamsLocal.Transform[3] = entries[0].m_vPosition;
50  }
51 
52  bool applyMesh = !material.IsEmpty();
53 
54  //--- Create root entity
55  string ext;
56  FilePath.StripExtension(previewPrefab, ext);
57  Resource previewResource;
58  typename previewType;
59  bool spawnFromResource;
60  if (!ext.IsEmpty())
61  {
62  previewResource = Resource.Load(previewPrefab);
63  spawnFromResource = previewResource.IsValid();
64  }
65 
66  SCR_BasePreviewEntity rootEntity;
67  if (spawnFromResource)
68  {
69  //--- From prefab
70  rootEntity = SCR_BasePreviewEntity.Cast(GetGame().SpawnEntityPrefab(previewResource, world, spawnParamsLocal));
71  }
72  else
73  {
74  //--- From class name
75  previewType = previewPrefab.ToType();
76  if (!previewType)
77  previewType = SCR_BasePreviewEntity;
78  rootEntity = SCR_BasePreviewEntity.Cast(GetGame().SpawnEntity(previewType, world, spawnParamsLocal));
79  }
80 
81  if (!rootEntity)
82  {
83  Debug.Error2("SCR_BasePreviewEntity", string.Format("Unable to create preview entity from prefab/type '%1'!", previewPrefab));
84  return null;
85  }
86 
87  vector rootTransform[4];
88  Math3D.MatrixCopy(spawnParamsLocal.Transform, rootTransform);
89 
90  rootEntity.m_Flags = flags;
91 
92  vector rootBoundMin = vector.One * float.MAX;
93  vector rootBoundMax = -rootBoundMin;
94 
95  int editableEntityCount;
96 
97  array<SCR_BasePreviewEntity> children = {};
98  SCR_BasePreviewEntity entity, parent;
99  foreach (int i, SCR_BasePreviewEntry entry: entries)
100  {
101  //entry.Log(i);
102 
103  //--- Get local transformation matrix
104  spawnParamsLocal = new EntitySpawnParams();
105  entry.LoadTransform(spawnParamsLocal.Transform);
106 
107  if (entry.m_Shape != EPreviewEntityShape.ELLIPSE && entry.m_Shape != EPreviewEntityShape.RECTANGLE) //--- Don't scale area meshes; instead, the scale is applied on the actual area
108  Math3D.MatrixScale(spawnParamsLocal.Transform, entry.GetScale()); //--- Apply scale on matrix, SetScale() doesn't work reliably
109 
110  //--- Get parent (don't apply it to spawn params, it doesn't create true hierarchy link)
111  if (entry.m_iParentID == -1)
112  parent = rootEntity;
113  else
114  parent = children[entry.m_iParentID];
115 
116  //--- Count how manuy editable entities are inside. When more than 1, editing along geometry is disabled.
117  if (entry.m_Flags & EPreviewEntityFlag.EDITABLE)
118  editableEntityCount++;
119 
120  if (applyMesh && entry.m_Shape == EPreviewEntityShape.PREFAB && entry.m_Mesh)
121  {
122  //--- Use preview prefab
123  entity = SCR_BasePreviewEntity.Cast(GetGame().SpawnEntityPrefabLocal(Resource.Load(entry.m_Mesh), world, spawnParamsLocal));
124  }
125  else
126  {
127  //--- Create entity
128  if (spawnFromResource)
129  entity = SCR_BasePreviewEntity.Cast(GetGame().SpawnEntityPrefabLocal(previewResource, world, spawnParamsLocal));
130  else
131  entity = SCR_BasePreviewEntity.Cast(GetGame().SpawnEntity(previewType, world, spawnParamsLocal));
132 
133  if (entity && applyMesh)
134  {
135  switch (entry.m_Shape)
136  {
137  case EPreviewEntityShape.MESH:
138  {
139  //--- Set mesh from a file
140  if (entry.m_Mesh)
141  {
142  Resource meshResource = Resource.Load(entry.m_Mesh);
143  if (meshResource)
144  {
145  BaseResourceObject res = meshResource.GetResource();
146 
147  if (res)
148  entity.SetPreviewObject(res.ToVObject(), material);
149  }
150  }
151  break;
152  }
153  case EPreviewEntityShape.ELLIPSE:
154  case EPreviewEntityShape.RECTANGLE:
155  {
156  int resolution = SCR_BaseAreaMeshComponent.PREVIEW_RESOLUTION;
157  vector dimensions = entry.m_vScale;
158 
159  if (resolution <= 0 || dimensions[0] <= 0 || dimensions[1] <= 0 || dimensions[2] <= 0)
160  {
161  break;
162  }
163 
164  array<vector> positions = {};
165 
166  if (entry.m_Shape == EPreviewEntityShape.ELLIPSE)
167  {
168  float dirStep = Math.PI2 / resolution;
169 
170  //--- Get positions
171  for (int v = 0; v < resolution; v++)
172  {
173  float dir = dirStep * v;
174  vector pos = Vector(Math.Sin(dir) * dimensions[0], -dimensions[1], Math.Cos(dir) * dimensions[2]);
175  positions.Insert(pos);
176  }
177  }
178  else if (entry.m_Shape == EPreviewEntityShape.RECTANGLE)
179  {
180  //~ Resulution is always 4 for Rectangles
181  resolution = 4;
182 
183  //~ Make sure it uses half of the width and lenght
184  float width = dimensions[0] / 2;
185  float lenght = dimensions[2] / 2;
186 
187  array<vector> corners = {
188  Vector(-width, -dimensions[1], -lenght),
189  Vector(width, -dimensions[1], -lenght),
190  Vector(width, -dimensions[1], lenght),
191  Vector(-width, -dimensions[1], lenght)
192  };
193 
194  //~ Set positions
195  for (int p = 0; p < resolution; p++)
196  {
197  vector start = corners[p];
198  vector end = corners[(p + 1) % resolution];
199 
200  for (float s = 0; s < 4; s++)
201  {
202  vector pos = vector.Lerp(start, end, s / resolution);
203  positions.Insert(pos);
204  }
205  }
206  }
207 
208  Resource res = SCR_Shape.CreateAreaMesh(positions, dimensions[1] * 2, material, true);
209  MeshObject meshObject = res.GetResource().ToMeshObject();
210  if (meshObject)
211  entity.SetObject(meshObject, "");
212  }
213 
214  }
215  }
216  }
217  children.Insert(entity);
218 
219  //--- Update root bounding box
220  vector boundMin, boundMax;
221  entity.GetBounds(boundMin, boundMax);
222  boundMin += entry.m_vPosition;
223  boundMax += entry.m_vPosition;
224 
225  rootBoundMin[0] = Math.Min(rootBoundMin[0], boundMin[0]);
226  rootBoundMin[1] = Math.Min(rootBoundMin[1], boundMin[1]);
227  rootBoundMin[2] = Math.Min(rootBoundMin[2], boundMin[2]);
228 
229  rootBoundMax[0] = Math.Max(rootBoundMax[0], boundMax[0]);
230  rootBoundMax[1] = Math.Max(rootBoundMax[1], boundMax[1]);
231  rootBoundMax[2] = Math.Max(rootBoundMax[2], boundMax[2]);
232 
233  //--- Add to parent (spawn params won't do that on their own)
234  int pivot = -1;
235  if (!entry.m_iPivotID.IsEmpty() && parent.GetAnimation())
236  pivot = parent.GetAnimation().GetBoneIndex(entry.m_iPivotID);
237  parent.AddChild(entity, pivot, EAddChildFlags.AUTO_TRANSFORM);
238 
239  //--- Cache the child in parent's array
240  if (!parent.m_aChildren)
241  parent.m_aChildren = {};
242  parent.m_aChildren.Insert(entity);
243 
244  //--- Set coordinates local to terrain
245  Math3D.AnglesToMatrix(entry.m_vAnglesTerrain, entity.m_vTerrainTransform);
246  entity.m_fHeightTerrain = entry.m_vHeightTerrain;
247 
248  //--- Make a copy of local transform for use in SetPreviewTransform()
249  Math3D.MatrixCopy(spawnParamsLocal.Transform, entity.m_vLocalTransform);
250 
251  //--- Initialize
252  entity.m_Flags |= entry.m_Flags;
253  entity.m_Entity = entry.m_Entity;
254 
255  entity.EOnPreviewInit(entry, rootEntity);
256  }
257  rootEntity.m_vBounds[0] = rootBoundMin;
258  rootEntity.m_vBounds[1] = rootBoundMax;
259 
260  //--- When there is more than one editable entity, mark it. Editing along geometry is disallowed in such case.
261  rootEntity.m_bHasMultipleEditableEntities = editableEntityCount > 1;
262 
263  rootEntity.EOnRootPreviewInit(entries);
264 
265  Print(string.Format("Preview entity created from %1 entries, at %2, using '%3' with material '%4'", entries.Count(), rootTransform, previewPrefab, material), LogLevel.VERBOSE);
266 
267  return rootEntity;
268  }
269 
278  void SetPreviewTransform(vector worldTransform[4], EEditorTransformVertical verticalMode, float heightTerrain = 0, bool isUnderwater = false, TraceParam trace = null)
279  {
280  //--- Get height difference
281  if (m_fHeightTerrain == -1)
282  m_fHeightTerrain = heightTerrain;
283  heightTerrain -= m_fHeightTerrain;
284 
285  SetWorldTransform(worldTransform);
286  SetChildTransform(verticalMode, heightTerrain, isUnderwater, trace);
287  Update();
288 
289  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_SHOW_DEBUG))
290  {
291  DbgUI.Begin(this.ToString(), 0, 0);
292  SCR_DbgUI.Matrix("worldTransform", worldTransform);
293  SCR_Global.DrawMatrix(worldTransform, 1);
294  DbgUI.End();
295  }
296  }
297  protected void SetChildTransform(EEditorTransformVertical verticalMode, float heightTerrain, bool isUnderwater = false, TraceParam trace = null)
298  {
299  if (GetParent())
300  {
301  //--- Actual preview entity, not root
302  switch (verticalMode)
303  {
304  case EEditorTransformVertical.GEOMETRY:
305  case EEditorTransformVertical.TERRAIN:
306  {
307  //--- Restore local transformation and convert it to world transformation
308  vector transform[4], surfaceBasis[4];
309  GetParent().GetWorldTransform(transform);
310  Math3D.MatrixMultiply4(transform, m_vLocalTransform, transform);
311 
312  float scale = transform[0].Length();
313 
314  //--- Get surface basis
315  if (!SCR_TerrainHelper.GetTerrainBasis(transform[3], surfaceBasis, GetWorld(), !isUnderwater, trace))
316  return;
317 
318  vector angles = Math3D.MatrixToAngles(transform);
319  if (SCR_Enum.HasFlag(m_Flags, EPreviewEntityFlag.HORIZONTAL))
320  {
321  //--- Orient to horizontal normal
322  angles[1] = 0;
323  angles[2] = 0;
324  Math3D.AnglesToMatrix(angles, transform);
325  }
326  else
327  {
328  //--- Orient to terrain normal
329  //--- Get identity matrix rotated according to the entity
330  Math3D.AnglesToMatrix(Vector(angles[0], 0, 0), transform);
331 
332  //--- Rotate surface basis
333  Math3D.MatrixMultiply3(surfaceBasis, transform, surfaceBasis);
334 
335  //--- Apply local transformation relative to terrain
336  Math3D.MatrixMultiply3(surfaceBasis, m_vTerrainTransform, transform);
337  }
338 
339  //--- Apply height
340  transform[3][1] = surfaceBasis[3][1] + m_fHeightTerrain + heightTerrain;
341 
342  //--- Preserve scale
343  if (scale != 1)
344  Math3D.MatrixScale(transform, scale);
345 
346  //--- Apply
347  SetWorldTransform(transform);
348  Update();
349 
350  m_bIsOnOrigTransform = false;
351  break;
352  }
353  default:
354  {
355  //--- Reset transformation
356  if (!m_bIsOnOrigTransform)
357  {
358  SetLocalTransform(m_vLocalTransform);
359  m_bIsOnOrigTransform = true;
360  }
361  break;
362  }
363  }
364  }
365  if (m_aChildren && (!GetParent() || SCR_Enum.HasFlag(m_Flags, EPreviewEntityFlag.ORIENT_CHILDREN)))
366  {
367  //--- Is root, or has children and is allowed to orient them
368  for (int i = 0, count = m_aChildren.Count(); i < count; i++)
369  {
370  m_aChildren[i].SetChildTransform(verticalMode, heightTerrain, isUnderwater, trace);
371  }
372  }
373 
374  if (DiagMenu.GetBool(SCR_DebugMenuID.DEBUGUI_EDITOR_SHOW_DEBUG))
375  {
376  vector matrix[4];
377  GetWorldTransform(matrix);
378  SCR_Global.DrawMatrix(matrix, 1, colorX: Color.CYAN, colorY: Color.MAGENTA, colorZ: 0xffffff00);
379  }
380  }
381  protected void SetPreviewObject(VObject mesh, ResourceName material)
382  {
383  if (!mesh)
384  return;
385 
386  string remap = string.Empty;
387  string materials[256];
388  int numMats = mesh.GetMaterials(materials);
389  for (int i = 0; i < numMats; i++)
390  {
391  remap += string.Format("$remap '%1' '%2';", materials[i], material);
392  }
393  SetObject(mesh, remap);
394  }
395 
400  array<SCR_BasePreviewEntity> GetPreviewChildren()
401  {
402  return m_aChildren;
403  }
408  IEntity GetSourceEntity()
409  {
410  return m_Entity;
411  }
417  void GetPreviewBounds(out vector outBoundMin, out vector outBoundMax)
418  {
419  outBoundMin = m_vBounds[0];
420  outBoundMax = m_vBounds[1]
421  }
425  bool HasMultipleEditableEntities()
426  {
427  return m_bHasMultipleEditableEntities;
428  }
433  protected void EOnPreviewInit(SCR_BasePreviewEntry entry, SCR_BasePreviewEntity root);
438  protected void EOnRootPreviewInit(array<ref SCR_BasePreviewEntry> entries);
439 
440  void SCR_BasePreviewEntity(IEntitySource src, IEntity parent)
441  {
442  }
443  void ~SCR_BasePreviewEntity()
444  {
445  while (GetChildren())
446  {
447  delete GetChildren();
448  }
449  }
450 
451 #ifdef WORKBENCH
452  override void _WB_GetBoundBox(inout vector min, inout vector max, IEntitySource src)
453  {
454  GetBounds(min, max);
455  }
456  override void _WB_AfterWorldUpdate(float timeSlice)
457  {
458  //--- Show mesh name for easier World Editor debugging
459  if (_WB_GetEditorAPI() && _WB_GetEditorAPI().IsEntitySelectedAsMain(_WB_GetEditorAPI().EntityToSource(this)))
460  {
461  string text = "<No Mesh>";
462  if (GetVObject())
463  text = FilePath.StripPath(GetVObject().GetResourceName());
464 
465  vector pos = GetOrigin();
466  DebugTextWorldSpace.Create(GetWorld(), text, DebugTextFlags.ONCE | DebugTextFlags.CENTER, pos[0], pos[1], pos[2], 12, Color.WHITE, Color.BLACK);
467  }
468  }
469 #endif
470 };
SCR_TerrainHelper
Definition: SCR_TerrainHelper.c:1
SpawnEntity
protected IEntity SpawnEntity(ResourceName entityResourceName, notnull IEntity slotOwner)
Definition: SCR_CatalogEntitySpawnerComponent.c:1008
SCR_DbgUI
Definition: SCR_DbgUI.c:1
SCR_Enum
Definition: SCR_Enum.c:1
EntityEditorProps
enum EQueryType EntityEditorProps(category:"GameScripted/Sound", description:"THIS IS THE SCRIPT DESCRIPTION.", color:"0 0 255 255")
Definition: SCR_AmbientSoundsComponent.c:12
SCR_BasePreviewEntry
Definition: SCR_BasePreviewEntry.c:2
SCR_BasePreviewEntityClass
Definition: SCR_BasePreviewEntity.c:2
EPreviewEntityShape
EPreviewEntityShape
Definition: EPreviewEntityMesh.c:1
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
SCR_BasePreviewEntity
Definition: SCR_BasePreviewEntity.c:9
m_Entity
enum EAITargetInfoCategory m_Entity
GenericEntity
SCR_GenericBoxEntityClass GenericEntity
EPreviewEntityFlag
EPreviewEntityFlag
Definition: EPreviewEntityFlag.c:1
EEditorTransformVertical
EEditorTransformVertical
Vertical transformation mode.
Definition: EEditorTransformVertical.c:5
GetOrigin
vector GetOrigin()
Definition: SCR_AIUtilityComponent.c:279
Attribute
typedef Attribute
Post-process effect of scripted camera.
m_aChildren
protected ref array< SCR_ScenarioFrameworkLayerBase > m_aChildren
Definition: SCR_ScenarioFrameworkLayerBase.c:57
Update
override void Update(float timeSlice)
Definition: SCR_CampaignBuildingGadgetToolComponent.c:28
SCR_Shape
Definition: SCR_Shape.c:1
SCR_Global
Definition: Functions.c:6
GetChildren
void GetChildren(out array< SCR_ScenarioFrameworkLayerBase > children)
Definition: SCR_ScenarioFrameworkLayerBase.c:359
SCR_DebugMenuID
SCR_DebugMenuID
This enum contains all IDs for DiagMenu entries added in script.
Definition: DebugMenuID.c:3
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180