Unity SDK Docs 1.5.0-beta.6
Loading...
Searching...
No Matches
NativePlugin.cs
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 */
16using System;
17using System.Runtime.InteropServices;
18using UnityEngine;
19
20namespace TiltFive
21{
22 public class NativePlugin
23 {
24
25#if (UNITY_IPHONE || UNITY_WEBGL) && !UNITY_EDITOR
26 public const string PLUGIN_LIBRARY = @"__Internal";
27#else
28 public const string PLUGIN_LIBRARY = @"TiltFiveUnity";
29#endif
30
31 internal const int T5_RESULT_SUCCESS = 0;
32 internal const int T5_RESULT_UNKNOWN_ERROR = 1;
33
34 #region Native Functions
35
36 // Init
37 [DllImport(PLUGIN_LIBRARY)]
38 internal static extern int SetApplicationInfo(
39 T5_StringUTF8 appName,
40 T5_StringUTF8 appId,
41 T5_StringUTF8 appVersion);
42
43 [DllImport(PLUGIN_LIBRARY)]
44 internal static extern int SetPlatformContext(
45 IntPtr platformContext);
46
47 [DllImport(PLUGIN_LIBRARY)]
48 [return: MarshalAs(UnmanagedType.I4)]
49 internal static extern ServiceCompatibility GetServiceCompatibility();
50
51 [DllImport(PLUGIN_LIBRARY)]
52 internal static extern int IsTiltFiveUIRequestingAttention(ref T5_Bool attentionRequested);
53
54 // Glasses Acquisition
55 [DllImport(PLUGIN_LIBRARY)]
56 internal static extern int RefreshGlassesAvailable();
57
58 // Set Maximum Desired Glasses. Count starts at 0.
59 //
60 // Note that using this to reduce the count will result in glasses being released back to
61 // the set of available glasses, which can invalidate handles currently in use. Generally,
62 // this should only be called once on load to indicate how many glasses your application
63 // wants.
64 [DllImport(PLUGIN_LIBRARY)]
65 internal static extern void SetMaxDesiredGlasses(byte maxCount);
66
67 // Glasses Availability
68 [DllImport(PLUGIN_LIBRARY)]
69 internal static extern int GetGlassesHandles(
70 ref byte handleCount,
71 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] UInt64[] glassesHandle);
72
73 // Glasses Friendly Name
74 [DllImport(PLUGIN_LIBRARY)]
75 internal static extern int GetGlassesFriendlyName(UInt64 glassesHandle, ref T5_StringUTF8 glassesFriendlyName);
76
77 // Head Pose
78 [DllImport(PLUGIN_LIBRARY)]
79 internal static extern int GetGlassesPose(
80 UInt64 glassesHandle,
81 ref T5_GlassesPose glassesPose,
82 [MarshalAs(UnmanagedType.I4)] T5_GlassesPoseUsage glassesPoseUsage);
83
84 // Gameboard Poses
85 [DllImport(PLUGIN_LIBRARY)]
86 internal static extern int GetGameboardPoses(UInt64 glassesHandle,
87 [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] T5_GameboardPose[] gameboardPoses,
88 ref UInt16 count);
89
90 [DllImport(PLUGIN_LIBRARY)]
91 internal static extern int ConfigureCameraStream(UInt64 glassesHandle, T5_CameraStreamConfig cameraConfig);
92
93 [DllImport(PLUGIN_LIBRARY)]
94 internal static extern int GetFilledCamImageBuffer(UInt64 glassesHandle, ref T5_CamImage camImageBuffer);
95
96 [DllImport(PLUGIN_LIBRARY)]
97 internal static extern int SubmitEmptyCamImageBuffer(UInt64 glassesHandle, IntPtr camImageBuffer, UInt32 bufferSize);
98
99 [DllImport(PLUGIN_LIBRARY)]
100 internal static extern int CancelCamImageBuffer(UInt64 glassesHandle, IntPtr buffer);
101
102 [DllImport(PLUGIN_LIBRARY)]
103 internal static extern int GetDewarpedPixelCoordinate(UInt64 glassesHandle, ref T5_PixelDewarp pixelDewarp);
104
105#if TILT_FIVE_ENABLE_PROJECTOR_EXTRINSICS_ADJUSTMENTS
106 [DllImport(PLUGIN_LIBRARY)]
107 internal static extern int SetProjectorExtrinsicsAdjustment(UInt64 glassesHandle,
108 [MarshalAs(UnmanagedType.LPArray, SizeConst = 14)] float[] args);
109#endif
110
111 // Gameboard dimensions
112 [DllImport(PLUGIN_LIBRARY)]
113 internal static extern int GetGameboardDimensions(
114 [MarshalAs(UnmanagedType.I4)] GameboardType gameboardType,
115 ref T5_GameboardSize playableSpaceInMeters);
116
117 // Wand Availability
118 [DllImport(PLUGIN_LIBRARY)]
119 internal static extern int GetWandAvailability(
120 UInt64 glassesHandle,
121 ref T5_Bool wandAvailable,
122 [MarshalAs(UnmanagedType.I4)] ControllerIndex wandTarget);
123
124 // Scan for Wands
125 [DllImport(PLUGIN_LIBRARY)]
126 internal static extern int ScanForWands();
127
128 // Wand Controls State
129 [DllImport(PLUGIN_LIBRARY)]
130 internal static extern int GetControllerState(
131 UInt64 glassesHandle,
132 [MarshalAs(UnmanagedType.I4)] ControllerIndex controllerIndex,
133 ref T5_ControllerState controllerState);
134
135 [DllImport(PLUGIN_LIBRARY)]
136 internal static extern int SendImpulse(UInt64 glassesHandle,
137 [MarshalAs(UnmanagedType.I4)] ControllerIndex controllerIndex, float amplitude, ushort duration);
138
139 // Submit Render Textures
140 [DllImport(PLUGIN_LIBRARY)]
141 internal static extern int QueueStereoImages(UInt64 glassesHandle, T5_FrameInfo frameInfo);
142
143 [DllImport(PLUGIN_LIBRARY)]
144 internal static extern IntPtr GetSendFrameCallback();
145
146 [DllImport(PLUGIN_LIBRARY)]
147 internal static extern int GetMaxDisplayDimensions(
148 UInt64 glassesHandle,
149 out UInt16 framebufferWidth,
150 out UInt16 framebufferHeight);
151
152 [DllImport(PLUGIN_LIBRARY)]
153 internal static extern int GetGlassesIPD(UInt64 glassesHandle, ref float glassesIPD);
154
155 [DllImport(PLUGIN_LIBRARY)]
156 internal static extern void UnloadWorkaround();
157
158#if UNITY_WEBGL && !UNITY_EDITOR
159 [DllImport ("__Internal")]
160 internal static extern void RegisterPlugin();
161#endif
162
163 #endregion Native Functions
164 }
165
171 internal struct T5_Bool
172 {
173 private readonly byte booleanByte;
174
175 public T5_Bool(bool boolean)
176 {
177 booleanByte = Convert.ToByte(boolean);
178 }
179
180 public static implicit operator bool(T5_Bool t5_boolean)
181 => Convert.ToBoolean(t5_boolean.booleanByte);
182 public static implicit operator T5_Bool(bool boolean) => new T5_Bool(boolean);
183 }
184
190 [StructLayout(LayoutKind.Sequential)]
191 internal struct T5_Position
192 {
193 public float X, Y, Z;
194
195 public T5_Position(Vector3 position)
196 {
197 X = position.x;
198 Y = position.y;
199 Z = position.z;
200 }
201
202 public static implicit operator Vector3(T5_Position t5_position)
203 => new Vector3(t5_position.X, t5_position.Y, t5_position.Z);
204 public static implicit operator T5_Position(Vector3 position) => new T5_Position(position);
205 }
206
212 [StructLayout(LayoutKind.Sequential)]
213 internal struct T5_Rotation
214 {
215 public float W, X, Y, Z;
216
217 public T5_Rotation(Quaternion rotation)
218 {
219 W = rotation.w;
220 X = rotation.x;
221 Y = rotation.y;
222 Z = rotation.z;
223 }
224
225 public static implicit operator Quaternion(T5_Rotation t5_rotation)
226 => new Quaternion(t5_rotation.X, t5_rotation.Y, t5_rotation.Z, t5_rotation.W);
227 public static implicit operator T5_Rotation(Quaternion rotation) => new T5_Rotation(rotation);
228 }
229
230 internal struct GlassesHandle : IEquatable<GlassesHandle>
231 {
232 private UInt64 glassesHandle;
233 public static implicit operator UInt64(GlassesHandle handle) => handle.glassesHandle;
234 public static implicit operator GlassesHandle(UInt64 handle) => new GlassesHandle() { glassesHandle = handle };
235 public override int GetHashCode() => glassesHandle.GetHashCode();
236 public bool Equals(GlassesHandle other) => glassesHandle == other.glassesHandle;
237 public override string ToString()
238 {
239 return glassesHandle.ToString();
240 }
241 }
242
246 [StructLayout(LayoutKind.Sequential)]
247 internal struct T5_GlassesPose
248 {
249 public UInt64 TimestampNanos;
250
251 private T5_Position posOfGLS_STAGE;
252 private T5_Rotation rotationToGLS_STAGE;
253
254 public GameboardType GameboardType;
255
256 public Vector3 PosOfGLS_STAGE { get => posOfGLS_STAGE; set => posOfGLS_STAGE = value; }
257 public Quaternion RotationToGLS_STAGE { get => rotationToGLS_STAGE; set => rotationToGLS_STAGE = value; }
258 }
259
263 [StructLayout(LayoutKind.Sequential)]
264 internal struct T5_GameboardPose
265 {
266 public UInt64 TimestampNanos;
267
268 private T5_Position posOfBOARD_STAGE;
269 private T5_Rotation rotationToBOARD_STAGE;
270
271 public GameboardType GameboardType;
272 public UInt64 id;
273
274 public Vector3 PosOfBOARD_STAGE { get => posOfBOARD_STAGE; set => posOfBOARD_STAGE = value; }
275 public Quaternion RotationToBOARD_STAGE { get => rotationToBOARD_STAGE; set => rotationToBOARD_STAGE = value; }
276 }
277
285 [StructLayout(LayoutKind.Sequential)]
286 public struct T5_CamImage
287 {
288 public UInt16 ImageBufferWidth_PIX;
289 public UInt16 ImageBufferHeight_PIX;
290 public UInt16 ImageBufferStride_PIX;
291 public UInt32 ImageBufferSize_PIX;
292 public IntPtr ImageBuffer;
293 private T5_Position posOfCAM_STAGE;
294 private T5_Rotation rotToCAM_STAGE;
295 public Vector3 PosOfCAM_STAGE { get => posOfCAM_STAGE; set => posOfCAM_STAGE = value; }
296 public Quaternion RotToCAM_STAGE { get => rotToCAM_STAGE; set => rotToCAM_STAGE = value; }
297
298 [Obsolete("T5_CamImage.PosOfCAM_GBD is deprecated. Please use T5_CamImage.PosOfCAM_STAGE instead.")]
299 public Vector3 PosOfCAM_GBD => PosOfCAM_STAGE;
300 [Obsolete("T5_CamImage.RotToCAM_GBD is deprecated. Please use T5_CamImage.RotToCAM_STAGE instead.")]
301 public Quaternion RotToCAM_GBD => RotToCAM_STAGE;
302
303 public T5_CamImage(UInt16 bufferWidth, UInt16 bufferHeight, UInt16 bufferStride, UInt32 bufferSize)
304 {
305 ImageBuffer = IntPtr.Zero;
306 ImageBufferWidth_PIX = bufferWidth;
307 ImageBufferHeight_PIX = bufferHeight;
308 ImageBufferStride_PIX = bufferStride;
309 ImageBufferSize_PIX = bufferSize;
310 posOfCAM_STAGE = Vector3.zero;
311 rotToCAM_STAGE = Quaternion.identity;
312 }
313 }
314
318 [StructLayout(LayoutKind.Sequential)]
320 {
321 public byte cameraIndex;
322 private T5_Bool streamEnabled;
323 public bool enabled { get => streamEnabled; set => streamEnabled = value; }
324 }
325
329 [StructLayout(LayoutKind.Sequential)]
330 public struct T5_PixelDewarp
331 {
332 public Vector2 pixelCoord_PIX { get => pixelCoord_PIX; set => pixelCoord_PIX = value; }
333 public Vector2 pixelCoord_IMG { get => pixelCoord_IMG; set => pixelCoord_IMG = value; }
334 public byte cameraIndex;
335 }
336
340 [StructLayout(LayoutKind.Sequential)]
341 internal struct T5_ControllerState
342 {
343 [StructLayout(LayoutKind.Sequential)]
344 public struct Joystick
345 {
346 public float X, Y;
347
348 public static implicit operator Vector2(Joystick joystick) => new Vector2(joystick.X, joystick.Y);
349 }
350
351 [StructLayout(LayoutKind.Sequential)]
352 public struct Buttons
353 {
354 private T5_Bool t5,
355 one,
356 two,
357 three,
358 a,
359 b,
360 x,
361 y;
362
363 public bool T5 { get => t5; set => t5 = value; }
364 public bool One { get => one; set => one = value; }
365 public bool Two { get => two; set => two = value; }
366 public bool Three { get => three; set => three = value; }
367 public bool A { get => a; set => a = value; }
368 public bool B { get => b; set => b = value; }
369 public bool X { get => x; set => x = value; }
370 public bool Y { get => y; set => y = value; }
371 [Obsolete("Buttons.System is deprecated, please use Wandbutton.T5 instead.", true)]
372 public bool System => T5;
373 [Obsolete("Buttons.Z is deprecated, please use Wandbutton.Three instead.", true)]
374 public bool Z => Three;
375 }
376
377 public UInt64 TimestampNanos;
378
379 private T5_Bool analogValid;
380 private T5_Bool batteryValid;
381 private T5_Bool buttonsValid;
382 private T5_Bool poseValid;
383
384 public float Trigger;
385 public Joystick Stick;
386 public byte Battery;
387 public Buttons ButtonsState;
388
389 private T5_Rotation rotToWND_STAGE;
390 private T5_Position aimPos_STAGE;
391 private T5_Position fingertipsPos_STAGE;
392 private T5_Position gripPos_STAGE;
393
394 public T5_Hand Hand;
395
396 public bool AnalogValid { get => analogValid; set => analogValid = value; }
397 public bool BatteryValid { get => batteryValid; set => batteryValid = value; }
398 public bool ButtonsValid { get => buttonsValid; set => buttonsValid = value; }
399 public bool PoseValid { get => poseValid; set => poseValid = value; }
400
401 public Quaternion RotToWND_STAGE { get => rotToWND_STAGE; set => rotToWND_STAGE = value; }
402 public Vector3 AimPos_STAGE { get => aimPos_STAGE; set => aimPos_STAGE = value; }
403 public Vector3 FingertipsPos_STAGE { get => fingertipsPos_STAGE; set => fingertipsPos_STAGE = value; }
404 public Vector3 GripPos_STAGE { get => gripPos_STAGE; set => gripPos_STAGE = value; }
405 }
406
412 [StructLayout(LayoutKind.Sequential)]
413 internal struct T5_VCI
414 {
415 public float StartX_VCI;
416 public float StartY_VCI;
417 public float Width_VCI;
418 public float Height_VCI;
419
420 public T5_VCI(Rect rect)
421 {
422 StartX_VCI = rect.x;
423 StartY_VCI = rect.y;
424 Width_VCI = rect.width;
425 Height_VCI = rect.height;
426 }
427
428 public static implicit operator Rect(T5_VCI vci)
429 => new Rect(vci.StartX_VCI, vci.StartY_VCI, vci.Width_VCI, vci.Height_VCI);
430 public static implicit operator T5_VCI(Rect rect) => new T5_VCI(rect);
431 }
432
436 [StructLayout(LayoutKind.Sequential)]
437 internal struct T5_FrameInfo
438 {
439 public IntPtr LeftTexHandle;
440 public IntPtr RightTexHandle;
441 public UInt16 TexWidth_PIX;
442 public UInt16 TexHeight_PIX;
443
444 private T5_Bool isSrgb;
445 private T5_Bool isUpsideDown;
446
447 private T5_VCI vci;
448
449 private T5_Rotation rotToLVC_STAGE;
450 private T5_Position posOfLVC_STAGE;
451
452 private T5_Rotation rotToRVC_STAGE;
453 private T5_Position posOfRVC_STAGE;
454
455 public bool IsSrgb { get => isSrgb; set => isSrgb = value; }
456 public bool IsUpsideDown { get => isUpsideDown; set => isUpsideDown = value; }
457 public Rect VCI { get => vci; set => vci = value; }
458 public Quaternion RotToLVC_STAGE { get => rotToLVC_STAGE; set => rotToLVC_STAGE = value; }
459 public Vector3 PosOfLVC_STAGE { get => posOfLVC_STAGE; set => posOfLVC_STAGE = value; }
460 public Quaternion RotToRVC_STAGE { get => rotToRVC_STAGE; set => rotToRVC_STAGE = value; }
461 public Vector3 PosOfRVC_STAGE { get => posOfRVC_STAGE; set => posOfRVC_STAGE = value; }
462 }
463
471 [StructLayout(LayoutKind.Explicit, Pack = 4)]
472 internal struct T5_StringUTF8 : IDisposable
473 {
474 [FieldOffset(0)] private UInt32 maxBufferSize;
475 [FieldOffset(4)] private UInt32 length;
476 [FieldOffset(8)] private IntPtr pStringBytesUTF8;
477
478 public T5_StringUTF8(string text)
479 {
480 pStringBytesUTF8 = IntPtr.Zero;
481 length = 0;
482 maxBufferSize = 16 * 1024;
483
484 if (text != null)
485 {
486 // Allocate enough unmanaged memory to store the string
487 byte[] textBytesUTF8 = System.Text.Encoding.UTF8.GetBytes(text);
488
489 // If the string is too long to fit in the unmanaged buffer, truncate it.
490 length = (UInt32)Math.Min(textBytesUTF8.Length, maxBufferSize);
491 pStringBytesUTF8 = Marshal.AllocHGlobal((int)maxBufferSize);
492
493 // Store the string data
494 Marshal.Copy(textBytesUTF8, 0, pStringBytesUTF8, (int)length);
495 }
496 }
497
498 public static implicit operator string(T5_StringUTF8 t5_StringUTF8)
499 => ToString(t5_StringUTF8);
500
501 public static implicit operator T5_StringUTF8(string text) => new T5_StringUTF8(text);
502
503 private static string ToString(T5_StringUTF8 t5_StringUTF8)
504 {
505 if (t5_StringUTF8.pStringBytesUTF8 == IntPtr.Zero)
506 {
507 return null;
508 }
509
510 var managedBytes = new byte[t5_StringUTF8.length];
511 try
512 {
513 Marshal.Copy(t5_StringUTF8.pStringBytesUTF8, managedBytes, 0, (int)t5_StringUTF8.length);
514 return System.Text.Encoding.UTF8.GetString(managedBytes);
515 }
516 catch (Exception e)
517 {
518 Debug.LogError($"Failed to copy string from unmanaged memory: {e}");
519 return null;
520 }
521 }
522
526 public void Dispose()
527 {
528 // Don't forget to free that unmanaged memory we allocated.
529 // Marshal.FreeHGlobal() will safely do nothing if IntPtr.Zero is passed in.
530 Marshal.FreeHGlobal(pStringBytesUTF8);
531 pStringBytesUTF8 = IntPtr.Zero;
532 }
533 }
534
538 public enum ServiceCompatibility : Int32
539 {
540 // <summary>
541 // The running service is incompatible with this client.
542 // </summary>
543 Incompatible = 0,
544
545 // <summary>
546 // The running service is compatible with this client.
547 // </summary>
548 Compatible = 1,
549
550 // <summary>
551 // Don't know yet whether the running service is compatible with this client.
552 // </summary>
553 Unknown = 2,
554 }
555
559 public enum PlayerIndex
560 {
561 [HideInInspector]
562 None = 0,
563 One = 1,
564 Two = 2,
565 Three = 3,
566 Four = 4
567 }
568
573 public enum ControllerIndex : Int32
574 {
578 Right = 0,
579
584 }
585
614
618 [StructLayout(LayoutKind.Sequential)]
619 public struct T5_GameboardSize
620 {
625
630
635
640
645
646 public T5_GameboardSize(float viewableExtentPositiveX, float viewableExtentNegativeX,
647 float viewableExtentPositiveZ, float viewableExtentNegativeZ,
648 float viewableExtentPositiveY)
649 {
650 ViewableExtentPositiveX = viewableExtentPositiveX;
651 ViewableExtentNegativeX = viewableExtentNegativeX;
652 ViewableExtentPositiveZ = viewableExtentPositiveZ;
653 ViewableExtentNegativeZ = viewableExtentNegativeZ;
654 ViewableExtentPositiveY = viewableExtentPositiveY;
655 }
656
657 [Obsolete("This version of the T5_GameboardSize constructor is obsolete. " +
658 "Please use T5_GameboardSize(float viewableExtentPositiveX, float viewableExtentNegativeX, " +
659 "float viewableExtentPositiveZ, float viewableExtentNegativeZ, float viewableExtentPositiveY) instead.", true)]
660 public T5_GameboardSize(float playableSpaceX, float playableSpaceZ, float borderWidth)
661 {
662 ViewableExtentPositiveX = playableSpaceX / 2f;
663 ViewableExtentNegativeX = playableSpaceX / 2f;
664 ViewableExtentPositiveZ = playableSpaceZ / 2f;
665 ViewableExtentNegativeZ = playableSpaceZ / 2f;
667 }
668 }
669
673 public enum ControllerPosition : Int32
674 {
678 Grip = 0,
679
684
688 Aim = 2
689 }
690
694 public enum T5_Hand : byte
695 {
699 Unknown = 0,
700
704 Left = 1,
705
709 Right = 2,
710 }
711
715 internal enum T5_GlassesPoseUsage : Int32
716 {
727 GlassesPresentation = 1,
728
737 SpectatorPresentation = 2,
738 }
739}
ServiceCompatibility
Whether the running service is compatible.
ControllerPosition
Points of interest along the wand controller, such as the handle position or wand tip.
@ Fingertips
The typical resting position of the player's fingertips, near the wand joystick and trigger.
@ Aim
The tip of the wand.
@ Grip
The center of the wand handle.
ControllerIndex
Since wands are all physically identical (they have no "handedness"), it doesn't make sense to addres...
@ Right
The wand held in the player's right hand.
@ Left
The wand held in the player's left hand.
GameboardType
The type of Gameboard being tracked by the glasses.
@ GameboardType_None
No Gameboard at all.
@ GameboardType_LE
The LE Gameboard.
@ GameboardType_XE
The XE Gameboard, laid out flat.
@ GameboardType_XE_Raised
The XE Gameboard, folded upward using its kickstand.
T5_Hand
Reported wand hand.
PlayerIndex
The Player index (e.g. Player One, Player Two, etc)
Represents a wrapper on a buffer comtaining a camera image.
Camera Stream Configuration.
Physical dimensions of a gameboard, in meters.
float ViewableExtentNegativeX
The distance in meters from the gameboard origin to the edge of the viewable area in the negative X d...
float ViewableExtentPositiveY
The distance in meters above the gameboard origin that the viewable area extends in the positive Y di...
float ViewableExtentPositiveX
The distance in meters from the gameboard origin to the edge of the viewable area in the positive X d...
float ViewableExtentPositiveZ
The distance in meters from the gameboard origin to the edge of the viewable area in the positive Z d...
float ViewableExtentNegativeZ
The distance in meters from the gameboard origin to the edge of the viewable area in the negative Z d...
Pixel Coordinate Dewarp Wrapper.