Tilt Five™ Unity API  1.4.1
Display.cs
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020-2023 Tilt Five, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 using System;
17 using UnityEngine;
18 
19 using TiltFive.Logging;
20 
21 namespace TiltFive
22 {
23  [Serializable]
24  public class AxesBoolean
25  {
26  public bool x = true;
27  public bool y = true;
28  public bool z = true;
29 
30  public AxesBoolean(bool setX, bool setY, bool setZ)
31  {
32  x = setX;
33  y = setY;
34  z = setZ;
35  }
36  }
37 
38  [Serializable]
39  public class AllAxesBoolean
40  {
41  public bool xyz = true;
42 
43  public AllAxesBoolean(bool setXYZ)
44  {
45  xyz = setXYZ;
46  }
47  }
48 
49  public struct ARProjectionFrustum
50  {
51  public float m_Left;
52  public float m_Right;
53  public float m_Bottom;
54  public float m_Top;
55  public float m_Near;
56  public float m_Far;
57 
58 
59  public ARProjectionFrustum(float l, float r, float b, float t, float n, float f)
60  {
61  m_Left = l; m_Right = r; m_Bottom = b; m_Top = t; m_Near = n; m_Far = f;
62  }
63  }
64 
65  public class Display : TiltFive.SingletonComponent<Display>
66  {
67  // Display Settings.
68  [NonSerialized] int[] _displaySettings = new int[2];
69 
70  // Frame sender render-thread callback.
71  [NonSerialized]
72  IntPtr _sendFrameCallback = IntPtr.Zero;
73 
74  protected override void Awake()
75  {
76  base.Awake();
77 
78  try
79  {
80  _sendFrameCallback = NativePlugin.GetSendFrameCallback();
81  }
82  catch (System.DllNotFoundException e)
83  {
84  Log.Info("Could not connect to Tilt Five plugin to get callback: {0}", e);
85  }
86  catch (Exception e)
87  {
88  Log.Error(e.Message);
89  }
90 
91  LogVersion();
92 
93  QualitySettings.vSyncCount = 0;
94  QualitySettings.maxQueuedFrames = 0;
95  }
96 
97  private void LogVersion()
98  {
99  string version = "NOT VERSIONED";
100 
101  // load version file and get the string value
102  TextAsset asset = (TextAsset)Resources.Load("pluginversion", typeof(TextAsset));
103  if (asset != null)
104  {
105  version = asset.text;
106  }
107 
108  // turn on logging if it was turned off
109  bool logEnabled = Debug.unityLogger.logEnabled;
110  if (!logEnabled)
111  {
112  Debug.unityLogger.logEnabled = true;
113  }
114 
115  // get previous setting
116  StackTraceLogType logType = Application.GetStackTraceLogType(LogType.Log);
117 
118  // turn off stacktrace logging for our messaging
119  Application.SetStackTraceLogType(LogType.Log, StackTraceLogType.None);
120 
121  Log.Info("\n********************************" +
122  "\n* Tilt Five: Unity SDK Version - " +
123  version +
124  "\n********************************");
125 
126  // reset to initial log settings
127  Application.SetStackTraceLogType(LogType.Log, logType);
128 
129  // reset logging enabled to previous
130  Debug.unityLogger.logEnabled = logEnabled;
131  }
132 
133  [Obsolete("This function has been moved into TiltFive.SystemControl")]
134  public static bool SetApplicationInfo()
135  {
136  return SystemControl.SetApplicationInfo();
137  }
138 
144  public static bool GetGlassesAvailability()
145  {
148  }
149 
150  static public bool PresentStereoImages(
151  PlayerIndex playerIndex,
152  IntPtr leftTexHandle,
153  IntPtr rightTexHandle,
154  int texWidth_PIX,
155  int texHeight_PIX,
156  bool isSrgb,
157  float fovYDegrees,
158  float widthToHeightRatio,
159  Quaternion rotToUGBD_ULVC,
160  Vector3 posOfULVC_UGBD,
161  Quaternion rotToUGBD_URVC,
162  Vector3 posOfURVC_UGBD) {
163  return Player.TryGetGlassesHandle(playerIndex, out var glassesHandle)
164  && PresentStereoImages(glassesHandle,
165  leftTexHandle,
166  rightTexHandle,
167  texWidth_PIX,
168  texHeight_PIX,
169  isSrgb,
170  fovYDegrees,
171  widthToHeightRatio,
172  rotToUGBD_ULVC,
173  posOfULVC_UGBD,
174  rotToUGBD_URVC,
175  posOfURVC_UGBD);
176  }
177 
178  static internal bool PresentStereoImages(
179  GlassesHandle glassesHandle,
180  IntPtr leftTexHandle,
181  IntPtr rightTexHandle,
182  int texWidth_PIX,
183  int texHeight_PIX,
184  bool isSrgb,
185  float fovYDegrees,
186  float widthToHeightRatio,
187  Quaternion rotToUGBD_ULVC,
188  Vector3 posOfULVC_UGBD,
189  Quaternion rotToUGBD_URVC,
190  Vector3 posOfURVC_UGBD)
191  {
192  return Instance.PresentStereoImagesImpl(glassesHandle,
193  leftTexHandle,
194  rightTexHandle,
195  texWidth_PIX,
196  texHeight_PIX,
197  isSrgb,
198  fovYDegrees,
199  widthToHeightRatio,
200  rotToUGBD_ULVC,
201  posOfULVC_UGBD,
202  rotToUGBD_URVC,
203  posOfURVC_UGBD);
204  }
205 
207  UInt64 glassesHandle,
208  IntPtr leftTexHandle,
209  IntPtr rightTexHandle,
210  int texWidth_PIX,
211  int texHeight_PIX,
212  bool isSrgb,
213  float fovYDegrees,
214  float widthToHeightRatio,
215  Quaternion rotToUGBD_ULVC,
216  Vector3 posOfULVC_UGBD,
217  Quaternion rotToUGBD_URVC,
218  Vector3 posOfURVC_UGBD)
219  {
220  // Unity reference frames:
221  //
222  // ULVC / URVC - Unity Left/Right Virtual Camera space.
223  // +x right, +y up, +z forward
224  // UGBD - Unity Gameboard space.
225  // +x right, +y up, +z forward
226  //
227  // Tilt Five reference frames:
228  //
229  // DC - Our right-handed version of Unity's default camera space
230  // (the LVC/RVC if there is no transform set on ULVC/URVC).
231  // +x right, +y up, +z backward
232  // LVC / RVC - Left/Right Virtual Camera space.
233  // +x right, +y up, +z backward
234  // GBD - Gameboard space.
235  // +x right, +y forward, +z up
236 
237  Quaternion rotToDC_GBD = Quaternion.AngleAxis(-90f, Vector3.right);
238 
239  // Calculate the VCI (the image rectangle in the normalized (z=1) image space of the virtual cameras)
240  float startY_VCI = -Mathf.Tan(fovYDegrees * (0.5f * Mathf.PI / 180.0f));
241  float startX_VCI = startY_VCI * widthToHeightRatio;
242  float width_VCI = -2f * startX_VCI;
243  float height_VCI = -2f * startY_VCI;
244  Rect vci = new Rect(startX_VCI, startY_VCI, width_VCI, height_VCI);
245 
246  // Swizzle the left-handed Unity-based coordinates into our right-handed reference frames
247  Quaternion rotToLVC_DC = new Quaternion(rotToUGBD_ULVC.x, rotToUGBD_ULVC.y, -rotToUGBD_ULVC.z, rotToUGBD_ULVC.w);
248  Quaternion rotToRVC_DC = new Quaternion(rotToUGBD_URVC.x, rotToUGBD_URVC.y, -rotToUGBD_URVC.z, rotToUGBD_URVC.w);
249 
250  Quaternion rotToLVC_GBD = rotToLVC_DC * rotToDC_GBD;
251  Quaternion rotToRVC_GBD = rotToRVC_DC * rotToDC_GBD;
252 
253  // Swap the Y and Z axes to switch from left-handed to right-handed coords
254  Vector3 posOfLVC_GBD = new Vector3(posOfULVC_UGBD.x, posOfULVC_UGBD.z, posOfULVC_UGBD.y);
255  Vector3 posOfRVC_GBD = new Vector3(posOfURVC_UGBD.x, posOfURVC_UGBD.z, posOfURVC_UGBD.y);
256 
257  // Build our frame info struct now that we're finished converting from Unity's coord space
258  T5_FrameInfo frameInfo = new T5_FrameInfo();
259 
260  frameInfo.LeftTexHandle = leftTexHandle;
261  frameInfo.RightTexHandle = rightTexHandle;
262 
263  frameInfo.TexWidth_PIX = (UInt16) texWidth_PIX;
264  frameInfo.TexHeight_PIX = (UInt16) texHeight_PIX;
265 
266  frameInfo.IsSrgb = isSrgb;
267  frameInfo.IsUpsideDown = false; // False for Unity, but possibly true for other engines
268 
269  frameInfo.VCI = vci;
270 
271  frameInfo.RotToLVC_GBD = rotToLVC_GBD;
272  frameInfo.PosOfLVC_GBD = posOfLVC_GBD;
273 
274  frameInfo.RotToRVC_GBD = rotToRVC_GBD;
275  frameInfo.PosOfRVC_GBD = posOfRVC_GBD;
276 
277  int result = NativePlugin.T5_RESULT_UNKNOWN_ERROR;
278  try
279  {
280  result = NativePlugin.QueueStereoImages(glassesHandle, frameInfo);
281  }
282  catch (Exception e)
283  {
284  Log.Error(e.Message);
285  }
286 
287  if (result != NativePlugin.T5_RESULT_SUCCESS) {
288  return false;
289  }
290 
291  if(_sendFrameCallback == IntPtr.Zero)
292  {
293  // We failed to set _sendFrameCallback during Awake() - let's try again
294  try
295  {
296  _sendFrameCallback = NativePlugin.GetSendFrameCallback();
297  }
298  catch (Exception)
299  {
300  Log.Error("Unable to send frame - the native plugin DLL may be failing to load");
301  return false;
302  }
303 
304  if (_sendFrameCallback == IntPtr.Zero)
305  {
306  // If we reach this point, the native plugin loaded, but erroneously gave us a null callback
307  Log.Error("Unable to send frame - the native plugin returned a null SendFrame callback");
308  return false;
309  }
310  }
311 
312  try
313  {
314  GL.IssuePluginEvent(_sendFrameCallback, 0);
315  GL.InvalidateState();
316  }
317  catch (Exception e)
318  {
319  Log.Error($"Failed to execute sendFrame callback: {e.Message}");
320  return false;
321  }
322 
323  return true;
324  }
325 
326  public static bool GetDisplayDimensions(ref Vector2Int displayDimensions)
327  {
328  return Instance.GetDisplayDimensionsImpl(ref displayDimensions);
329  }
330 
331  private bool GetDisplayDimensionsImpl(ref Vector2Int displayDimensions)
332  {
333  int result = NativePlugin.T5_RESULT_UNKNOWN_ERROR;
334  try
335  {
336  result = NativePlugin.GetMaxDisplayDimensions(_displaySettings);
337 
338  if(result == NativePlugin.T5_RESULT_SUCCESS)
339  {
340  displayDimensions = new Vector2Int(_displaySettings[0], _displaySettings[1]);
341  }
342  else Log.Warn("Display.cs: Failed to retrieve display settings from plugin.");
343  }
344  catch (Exception e)
345  {
346  Log.Error(e.Message);
347  }
348 
349  return result == NativePlugin.T5_RESULT_SUCCESS;
350  }
351 
352  public static bool GetGlassesIPD(UInt64 glassesHandle, ref float glassesIPD)
353  {
354  return Instance.GetGlassesIPDImpl(glassesHandle, ref glassesIPD);
355  }
356 
357  private bool GetGlassesIPDImpl(UInt64 glassesHandle, ref float glassesIPD)
358  {
359  int result = NativePlugin.T5_RESULT_UNKNOWN_ERROR;
360  try
361  {
362  result = NativePlugin.GetGlassesIPD(glassesHandle, ref glassesIPD);
363 
364  if(result != NativePlugin.T5_RESULT_SUCCESS && GetGlassesAvailability())
365  {
366  Log.Warn("Display.cs: Failed to retrieve glasses IPD");
367  }
368  }
369  catch (Exception e)
370  {
371  Log.Error(e.Message);
372  }
373 
374  return result == NativePlugin.T5_RESULT_SUCCESS;
375  }
376 
377  internal static void ApplyGraphicsSettings(GraphicsSettings graphicsSettings)
378  {
379  // If we are optimizing the framerate and a player is connected, overwrite the application's target framerate and vsync settings.
380  if (graphicsSettings.matchGlassesFramerate && Player.TryGetFirstConnectedPlayer(out var anyPlayer))
381  {
382  Application.targetFrameRate = GraphicsSettings.PREFERRED_GLASSES_FRAMERATE;
383  QualitySettings.vSyncCount = GraphicsSettings.VSYNC_DISABLED;
384  }
385  // Otherwise, restore them to the settings we observed during Awake()
386  else
387  {
388  Application.targetFrameRate = graphicsSettings.applicationTargetFramerate;
389  QualitySettings.vSyncCount = graphicsSettings.applicationVSyncCount;
390  }
391  }
392  }
393 
394  public class DisplayHelper
395  {
396  private static Matrix4x4 Frustum(ARProjectionFrustum f)
397  {
398  return Frustum(f.m_Left, f.m_Right, f.m_Bottom, f.m_Top, f.m_Near, f.m_Far);
399  }
400 
401  /***********************************************************************
402  * This is our interpretation of glFrustum. CalculateObliqueMatrix
403  * has some params that I haven't figured out yet, so I'll use this
404  * instead.
405  ***********************************************************************/
406  public static Matrix4x4 Frustum(float L, float R, float B, float T, float n, float f)
407  {
408  Matrix4x4 m = new Matrix4x4();
409 
410  m[0, 0] = (2 * n) / (R - L);
411  m[1, 1] = (2 * n) / (T - B);
412  m[0, 2] = (R + L) / (R - L);
413  m[1, 2] = (T + B) / (T - B);
414  m[2, 2] = -(f + n) / (f - n);
415  m[2, 3] = -(2 * f * n) / (f - n);
416  m[3, 2] = -1.0f;
417  m[3, 3] = 0.0f;
418 
419  return m;
420  }
421  }
422 }
AllAxesBoolean(bool setXYZ)
Definition: Display.cs:43
AxesBoolean(bool setX, bool setY, bool setZ)
Definition: Display.cs:30
static Matrix4x4 Frustum(float L, float R, float B, float T, float n, float f)
Definition: Display.cs:406
static Matrix4x4 Frustum(ARProjectionFrustum f)
Definition: Display.cs:396
void LogVersion()
Definition: Display.cs:97
bool PresentStereoImagesImpl(UInt64 glassesHandle, IntPtr leftTexHandle, IntPtr rightTexHandle, int texWidth_PIX, int texHeight_PIX, bool isSrgb, float fovYDegrees, float widthToHeightRatio, Quaternion rotToUGBD_ULVC, Vector3 posOfULVC_UGBD, Quaternion rotToUGBD_URVC, Vector3 posOfURVC_UGBD)
Definition: Display.cs:206
static bool GetDisplayDimensions(ref Vector2Int displayDimensions)
Definition: Display.cs:326
bool GetGlassesIPDImpl(UInt64 glassesHandle, ref float glassesIPD)
Definition: Display.cs:357
static bool GetGlassesIPD(UInt64 glassesHandle, ref float glassesIPD)
Definition: Display.cs:352
static bool SetApplicationInfo()
Definition: Display.cs:134
override void Awake()
Definition: Display.cs:74
IntPtr _sendFrameCallback
Definition: Display.cs:72
bool GetDisplayDimensionsImpl(ref Vector2Int displayDimensions)
Definition: Display.cs:331
static bool GetGlassesAvailability()
Get whether any glasses are available
Definition: Display.cs:144
static bool PresentStereoImages(PlayerIndex playerIndex, IntPtr leftTexHandle, IntPtr rightTexHandle, int texWidth_PIX, int texHeight_PIX, bool isSrgb, float fovYDegrees, float widthToHeightRatio, Quaternion rotToUGBD_ULVC, Vector3 posOfULVC_UGBD, Quaternion rotToUGBD_URVC, Vector3 posOfURVC_UGBD)
Definition: Display.cs:150
int[] _displaySettings
Definition: Display.cs:68
GraphicsSettings encapsulates configuration data related to the project's graphics settings,...
bool matchGlassesFramerate
Determines whether the Tilt Five SDK should optimize the project's framerate and vsync for sending fr...
The Logger.
Definition: Log.cs:42
static void Warn(string m, params object[] list)
WARN logging function call.
Definition: Log.cs:166
static void Info(string m, params object[] list)
INFO logging function call.
Definition: Log.cs:140
static void Error(string m, params object[] list)
ERROR logging function call.
Definition: Log.cs:127
Provides access to player settings and functionality.
Definition: Player.cs:31
static bool IsConnected(PlayerIndex playerIndex)
Determines whether the specified player has an associated pair of glasses connected.
Definition: Player.cs:48
Definition: Log.cs:21
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)
ARProjectionFrustum(float l, float r, float b, float t, float n, float f)
Definition: Display.cs:59