Arma Reforger Explorer  1.1.0.42
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
SCR_NearbyContextDisplay.c
Go to the documentation of this file.
1 #define DEBUG_NEARBY_CONTEXT_DISPLAY
2 
3 //------------------------------------------------------------------------------------------------
4 class SCR_NearbyContextDisplay : SCR_InfoDisplayExtended
5 {
6  [Attribute("3", UIWidgets.Slider, "Maximum distance of actions that can be presented to player. (meters)", category: "NearbyContextDisplay", params: "0 100 0.1")]
7  protected float m_fWidgetMaximumRange;
8  [Attribute("0.7", UIWidgets.Slider, "Minimum assumed distance of actions (for scaling). (meters)", category: "NearbyContextDisplay", params: "0 100 0.1")]
9  protected float m_fWidgetMinimumRange;
10 
11  [Attribute("128", UIWidgets.Slider, "Amount of widgets that are created on initialization and then re-used.", category: "NearbyContextDisplay", params: "0 256 1")]
12  protected int m_iPrecachedWidgetCount;
13 
14  [Attribute("", UIWidgets.ResourceNamePicker, "Layout", "layout", category: "NearbyContextDisplay")]
15  ResourceName m_wIconLayoutPath;
16 
17  [Attribute("1 1 1 1", UIWidgets.ColorPicker, category: "NearbyContextDisplay")]
18  protected vector m_vVisibleWidgetColor;
19  [Attribute("0.1 0.1 0.1 1", UIWidgets.ColorPicker, category: "NearbyContextDisplay")]
20  protected vector m_vNotVisibleWidgetColor;
21 
22 
26  [Attribute("0 0 1 1", UIWidgets.GraphDialog, desc: "Horizontal opacity (y) based on screen center distance (x).", category: "NearbyContextDisplay")]
27  private ref Curve m_pHorizontalOpacityCurve;
31  [Attribute("0 0 1 1", UIWidgets.GraphDialog, desc: "Vertical opacity (y) based on screen center distance (x).", category: "NearbyContextDisplay")]
32  private ref Curve m_pVerticalOpacityCurve;
33 
34  private ref Color m_pColorVisible;
35  private ref Color m_pColorNotVisible;
36 
38  private InteractionHandlerComponent m_pInteractionHandlerComponent;
39 
41  private ref array<Widget> m_aWidgets = {};
43  private int m_iVisibleWidgets;
45  private float m_fOriginalSizeX;
47  private float m_fOriginalSizeY;
48 
49  //------------------------------------------------------------------------------------------------
52  {
53  int widgetsCount = m_aWidgets.Count();
54  for (int i = widgetsCount-1; i >= 0; i--)
55  {
56  if (m_aWidgets[i])
57  m_aWidgets[i].RemoveFromHierarchy();
58  }
59 
60  m_aWidgets.Clear();
61 
62  m_pColorVisible = null;
63  m_pColorNotVisible = null;
64  }
65 
66  //------------------------------------------------------------------------------------------------
67  override void DisplayStartDraw(IEntity owner)
68  {
69  if (m_aWidgets.IsEmpty())
70  {
71  Print("Pre-cached SCR_NearbyContextDisplay widgets cannot be detected; re-rooting to m_wRoot cannot happen!", LogLevel.ERROR);
72  return;
73  }
74 
75  if (!m_wRoot)
76  {
77  Print("The SCR_NearbyContextDisplay root is NULL, the pre-cached SCR_NearbyContextDisplay widgets cannot be re-rooted!", LogLevel.ERROR);
78  return;
79  }
80 
81 
82  // Re-root the blips to the info display root
83  foreach (Widget w : m_aWidgets)
84  m_wRoot.AddChild(w);
85  }
86 
87  //------------------------------------------------------------------------------------------------
88  override void DisplayInit(IEntity owner)
89  {
90  m_pInteractionHandlerComponent = InteractionHandlerComponent.Cast(owner.FindComponent(InteractionHandlerComponent));
91  if (!m_pInteractionHandlerComponent)
92  Print("Interaction handler component could not be found! SCR_NearbyContextDisplay will not work.", LogLevel.WARNING);
93 
94 
95  m_pColorVisible = new Color(m_vVisibleWidgetColor[0], m_vVisibleWidgetColor[1], m_vVisibleWidgetColor[2], 1.0);
96  m_pColorNotVisible = new Color(m_vNotVisibleWidgetColor[0], m_vNotVisibleWidgetColor[1], m_vNotVisibleWidgetColor[2], 1.0);
97 
98  // Pre-cache widgets
99  for (int i = 0; i < m_iPrecachedWidgetCount; i++)
100  {
101  // Instantiate widgets
102  Widget iconWidget = GetGame().GetWorkspace().CreateWidgets(m_wIconLayoutPath);
103  if (!iconWidget)
104  {
105  if (m_wIconLayoutPath.IsEmpty())
106  Print("SCR_NearbyContextDisplay could not create widgets! Verify that provided Icon Layout Path is valid!", LogLevel.ERROR);
107  break;
108  }
109 
110  m_aWidgets.Insert(iconWidget);
111  // Disable their visibility by default
112  iconWidget.SetVisible(false);
113  // Prepare their transformation
114  FrameSlot.SetAnchor(iconWidget, 0, 0);
115  FrameSlot.SetAlignment(iconWidget, 0.5, 0.5);
116  FrameSlot.SetSizeToContent(iconWidget, true);
117  }
118 
119  // Store default value
120  if (m_aWidgets[0])
121  {
122  Widget icon = FindIconWidget(m_aWidgets[0]);
123  vector size = FrameSlot.GetSize(icon);
124  m_fOriginalSizeX = size[0];
125  m_fOriginalSizeY = size[1];
126  }
127  }
128 
129  //------------------------------------------------------------------------------------------------
130  override void DisplayStopDraw(IEntity owner)
131  {
132  // Were we drawing something?
133  // If yes, then disable all
134  if (m_iVisibleWidgets > 0)
135  SetVisibleWidgets(0);
136  }
137 
138 
139  //------------------------------------------------------------------------------------------------
140  override void DisplayUpdate(IEntity owner, float timeSlice)
141  {
142  bool bCameraActive = m_CameraHandler && m_CameraHandler.IsCameraActive();
143  // m_pInteractionHandlerComponent.SetNearbyCollectionEnabled(true);
144  if (!m_pInteractionHandlerComponent.GetNearbyCollectionEnabled() || !bCameraActive)
145  {
146  // Were we drawing something?
147  // If yes, then disable all
148  if (m_iVisibleWidgets > 0)
149  SetVisibleWidgets(0);
150 
151  return;
152  }
153 
154  // Fetch nearby contexts
155  array<UserActionContext> contexts = {};
156  int count = m_pInteractionHandlerComponent.GetNearbyAvailableContextList(contexts);
157 
158  // Prepare widgets
159  int actualCount = 0;
160 
161  // Get required data
162  BaseWorld world = owner.GetWorld();
163  int cameraIndex = world.GetCurrentCameraId();
164  vector mat[4];
165  world.GetCamera(cameraIndex, mat);
166  vector referencePos = mat[3];
167 
168  // Iterate through individual contexts,
169  // validate that they are visible,
170  // and update their widget representation
171  const float threshold = 0.25;
172  const float fovBase = 100; // whatever fits
173 
174  // Field of view and screen resolution is necessary to compute proper position and size of widgets
175  float zoom = 1; // world.GetCameraVerticalFOV(cameraIndex) - missing crucial getter
176  CameraManager cameraManager = GetGame().GetCameraManager();
177  if (cameraManager)
178  {
179  CameraBase camera = cameraManager.CurrentCamera();
180 
181  #ifdef DEBUG_NEARBY_CONTEXT_DISPLAY
182  if(camera.GetProjType() == CameraType.NONE)
183  Print(string.Format("%1 [DisplayUpdate] None Projection", this));
184  #endif
185 
186  if (camera && camera.GetProjType() != CameraType.NONE)
187  zoom = fovBase / Math.Max(camera.GetVerticalFOV(), 1);
188  }
189  float distanceLimit = m_fWidgetMaximumRange * zoom;
190  float distanceLimitSq = distanceLimit * distanceLimit;
191  // Screen resolution is necessary to know how far away the widget is from screen center
192  // or from cursor, if we ever allow player to use mouse cursor or eye tracking software to select the actions.
193  float resX; float resY;
194  GetGame().GetWorkspace().GetScreenSize(resX, resY);
195 
196  UserActionContext currentContext = m_pInteractionHandlerComponent.GetCurrentContext();
197  foreach (UserActionContext ctx : contexts)
198  {
199  // Do not draw currently select one
200  if (currentContext == ctx)
201  continue;
202 
203  // We already have too much
204  if (actualCount >= m_iPrecachedWidgetCount)
205  break;
206 
207  vector position = ctx.GetOrigin();
208  float distanceSq = vector.DistanceSq(position, referencePos);
209 
210  // Just ignore actions out of reach, we will fade them out anyway
211  if (distanceSq < distanceLimitSq && IsInLineOfSight(position, mat, threshold))
212  {
213  Widget widget = m_aWidgets[actualCount];
214  if (widget)
215  {
216  SetWidgetWorldPosition(world, cameraIndex, widget, position);
217 
218  // TODO@AS:
219  // First child is an image.
220  // We need more robust solution if not.
221  Widget child = FindIconWidget(widget);
222  if (child)
223  {
224  // distance^2 from context to camera origin
225  float distance = Math.Sqrt(distanceSq);
226  bool visible = ctx.IsInVisibilityAngle(referencePos);
227  SetWidgetScale(child, distance, zoom);
228  SetWidgetAlpha(child, distance, distanceLimit, resX, resY);
229  SetWidgetColor(child, distance, visible);
230  }
231  }
232  actualCount++;
233  }
234  }
235 
236  // Enable required amount of widgets
237  SetVisibleWidgets(actualCount);
238  }
239 
240  //------------------------------------------------------------------------------------------------
243  protected void SetVisibleWidgets(int count)
244  {
245  if (m_aWidgets.IsEmpty() || !m_wRoot)
246  return;
247 
248  // Enable additional widgets
249  if (count > m_iVisibleWidgets)
250  {
251  for (int i = m_iVisibleWidgets; i < count; i++)
252  m_aWidgets[i].SetVisible(true);
253 
254  m_iVisibleWidgets = count;
255  }
256  // Disable exceeding widgets
257  else if (count < m_iVisibleWidgets)
258  {
259  for (int i = count; i < m_iVisibleWidgets; i++)
260  m_aWidgets[i].SetVisible(false);
261 
262  m_iVisibleWidgets = count;
263  }
264  }
265 
266  //------------------------------------------------------------------------------------------------
267  protected void SetWidgetScale(Widget widget, float distance, float zoom)
268  {
269  // Scale is reversely proportionalto distance, but we don't want to make icons more than 2x bigger - this may depend on art resolution
270  // Scale also depends on current camera FOV, the smaller FOV the bigger the icon
271  float scale = zoom / Math.Max(distance, m_fWidgetMinimumRange);
272 
273  FrameSlot.SetSize(widget, scale * m_fOriginalSizeX, scale * m_fOriginalSizeY);
274  }
275 
276  //------------------------------------------------------------------------------------------------
277  protected void SetWidgetAlpha(Widget widget, float distance, float limit, float resX, float resY)
278  {
279  // First stage of alpha depends on distance to camera
280  float alpha = 0;
281  if (limit != 0)
282  alpha = Math.Clamp(limit - distance, 0, limit) / limit;
283 
284  // Second stage of alpha depends on distance from screen center
285  float x; float y;
286  widget.GetScreenPos(x, y);
287 
288  // Get distance from center as 0,1
289  // where 0 = center, 1 = edge
290  float xDistance = Math.AbsFloat(x - resX * 0.5) / resX;
291  float yDistance = Math.AbsFloat(y - resY * 0.5) / resY;
292 
293  // Sample curves
294  x = Math3D.Curve(ECurveType.CurveProperty2D, xDistance, m_pHorizontalOpacityCurve)[1];
295  y = Math3D.Curve(ECurveType.CurveProperty2D, yDistance, m_pVerticalOpacityCurve)[1];
296 
297  // Take the smaller value as priority,
298  // average doesn't really work well here.
299  float min = Math.Min(x, y);
300 
301  // Apply opacity
302  widget.SetOpacity(alpha * min);
303  }
304 
305  //------------------------------------------------------------------------------------------------
306  protected void SetWidgetColor(Widget widget, float distance, bool isInVisibilityRange)
307  {
308  if (isInVisibilityRange)
309  widget.SetColor(m_pColorVisible);
310  else
311  widget.SetColor(m_pColorNotVisible);
312  }
313 
314  //------------------------------------------------------------------------------------------------
320  protected void SetWidgetWorldPosition(BaseWorld world, int cameraIndex, Widget widget, vector worldPosition)
321  {
322  vector screenPosition = GetGame().GetWorkspace().ProjWorldToScreen(worldPosition, world, cameraIndex);
323  float x = screenPosition[0];
324  float y = screenPosition[1];
325  FrameSlot.SetPos(widget, x, y);
326  }
327 
328  //------------------------------------------------------------------------------------------------
333  protected bool IsInLineOfSight(vector point, vector transform[4], float val)
334  {
335  vector direction = point - transform[3];
336  direction.Normalize();
337 
338  const float threshold = 0.25;
339  if (vector.Dot(direction, transform[2]) > val)
340  return true;
341 
342  return false;
343  }
344 
345  //------------------------------------------------------------------------------------------------
349  protected Widget FindIconWidget(Widget layout)
350  {
351  return layout.GetChildren();
352  }
353 
354 };
direction
vector direction
Definition: SCR_DestructibleTreeV2.c:31
m_wRoot
protected Widget m_wRoot
Definition: SCR_ScenarioFrameworkLayerTaskDefend.c:59
SCR_NearbyContextDisplay
Definition: SCR_NearbyContextDisplay.c:4
GetGame
ArmaReforgerScripted GetGame()
Definition: game.c:1424
desc
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
Definition: SCR_RespawnBriefingComponent.c:17
SetVisible
void SetVisible(int layer)
Definition: SCR_ServicePointMapDescriptorComponent.c:95
Attribute
SCR_NearbyContextDisplay Attribute
Post-process effect of scripted camera.
distance
float distance
Definition: SCR_DestructibleTreeV2.c:29
m_CameraHandler
protected SCR_CharacterCameraHandlerComponent m_CameraHandler
Definition: SCR_InfoDisplayExtended.c:26
m_aWidgets
ref array< Widget > m_aWidgets
Definition: SCR_UITaskManagerComponent.c:25
layout
UI layouts HUD CampaignMP CampaignMainHUD layout
Definition: SCR_ScenarioFrameworkLayerTaskDefend.c:20
params
Configs ServerBrowser KickDialogs params
Definition: SCR_NotificationSenderComponent.c:24
position
vector position
Definition: SCR_DestructibleTreeV2.c:30
UserActionContext
Definition: UserActionContext.c:15
category
params category
Definition: SCR_VehicleDamageManagerComponent.c:180