Tilt Five™ Unity API  1.3.0
 
Loading...
Searching...
No Matches
NativePlugin.cs
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-2022 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 #region Native Functions
32
33 // Init
34 [DllImport(PLUGIN_LIBRARY)]
35 public static extern int SetApplicationInfo(
36 T5_StringUTF8 appName,
37 T5_StringUTF8 appId,
38 T5_StringUTF8 appVersion);
39
40 [DllImport(PLUGIN_LIBRARY)]
41 [return: MarshalAs(UnmanagedType.I4)]
43
44 // Glasses Acquisition
45 [DllImport(PLUGIN_LIBRARY)]
46 public static extern int RefreshGlassesAvailable();
47
48 // Set Maximum Desired Glasses. Count starts at 0.
49 //
50 // Note that using this to reduce the count will result in glasses being released back to
51 // the set of available glasses, which can invalidate handles currently in use. Generally,
52 // this should only be called once on load to indicate how many glasses your application
53 // wants.
54 [DllImport(PLUGIN_LIBRARY)]
55 public static extern void SetMaxDesiredGlasses(byte maxCount);
56
57 // Glasses Availability
58 [DllImport(PLUGIN_LIBRARY)]
59 public static extern int GetGlassesHandles(
60 ref byte handleCount,
61 [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] UInt64[] glassesHandle);
62
63 // Glasses Friendly Name
64 [DllImport(PLUGIN_LIBRARY)]
65 public static extern int GetGlassesFriendlyName(UInt64 glassesHandle, ref T5_StringUTF8 glassesFriendlyName);
66
67 // Head Pose
68 [DllImport(PLUGIN_LIBRARY)]
69 public static extern int GetGlassesPose(
70 UInt64 glassesHandle,
71 ref T5_GlassesPose glassesPose,
72 [MarshalAs(UnmanagedType.I4)] T5_GlassesPoseUsage glassesPoseUsage);
73
74 [DllImport(PLUGIN_LIBRARY)]
75 public static extern int ConfigureCameraStream(UInt64 glassesHandle, T5_CameraStreamConfig cameraConfig);
76
77 [DllImport(PLUGIN_LIBRARY)]
78 public static extern int GetFilledCamImageBuffer(UInt64 glassesHandle, ref T5_CamImage camImageBuffer);
79
80 [DllImport(PLUGIN_LIBRARY)]
81 public static extern int SubmitEmptyCamImageBuffer(UInt64 glassesHandle, IntPtr camImageBuffer, UInt32 bufferSize);
82
83 [DllImport(PLUGIN_LIBRARY)]
84 public static extern int CancelCamImageBuffer(UInt64 glassesHandle, IntPtr buffer);
85
86 // Gameboard dimensions
87 [DllImport(PLUGIN_LIBRARY)]
88 public static extern int GetGameboardDimensions(
89 [MarshalAs(UnmanagedType.I4)] GameboardType gameboardType,
90 ref T5_GameboardSize playableSpaceInMeters);
91
92 // Wand Availability
93 [DllImport(PLUGIN_LIBRARY)]
94 public static extern int GetWandAvailability(
95 UInt64 glassesHandle,
96 ref T5_Bool wandAvailable,
97 [MarshalAs(UnmanagedType.I4)] ControllerIndex wandTarget);
98
99 // Scan for Wands
100 [DllImport(PLUGIN_LIBRARY)]
101 public static extern int ScanForWands();
102
103 // Wand Controls State
104 [DllImport(PLUGIN_LIBRARY)]
105 public static extern int GetControllerState(
106 UInt64 glassesHandle,
107 [MarshalAs(UnmanagedType.I4)] ControllerIndex controllerIndex,
108 ref T5_ControllerState controllerState);
109
110 [DllImport(PLUGIN_LIBRARY)]
111 public static extern int SetRumbleMotor(uint motor, float intensity);
112
113 // Submit Render Textures
114 [DllImport(PLUGIN_LIBRARY)]
115 public static extern int QueueStereoImages(UInt64 glassesHandle, T5_FrameInfo frameInfo);
116
117 [DllImport(PLUGIN_LIBRARY)]
118 public static extern IntPtr GetSendFrameCallback();
119
120 [DllImport(PLUGIN_LIBRARY)]
121 public static extern int GetMaxDisplayDimensions(
122 [MarshalAs(UnmanagedType.LPArray, SizeConst = 2)] int[] displayDimensions);
123
124 [DllImport(PLUGIN_LIBRARY)]
125 public static extern int GetGlassesIPD(UInt64 glassesHandle, ref float glassesIPD);
126
127 [DllImport(PLUGIN_LIBRARY)]
128 public static extern void UnloadWorkaround();
129
130#if UNITY_WEBGL && !UNITY_EDITOR
131 [DllImport ("__Internal")]
132 public static extern void RegisterPlugin();
133#endif
134
135 #endregion Native Functions
136 }
137
143 public struct T5_Bool
144 {
145 private readonly byte booleanByte;
146
147 public T5_Bool(bool boolean)
148 {
149 booleanByte = Convert.ToByte(boolean);
150 }
151
152 public static implicit operator bool(T5_Bool t5_boolean)
153 => Convert.ToBoolean(t5_boolean.booleanByte);
154 public static implicit operator T5_Bool(bool boolean) => new T5_Bool(boolean);
155 }
156
162 [StructLayout(LayoutKind.Sequential)]
163 internal struct T5_Position
164 {
165 public float X, Y, Z;
166
167 public T5_Position(Vector3 position)
168 {
169 X = position.x;
170 Y = position.y;
171 Z = position.z;
172 }
173
174 public static implicit operator Vector3(T5_Position t5_position)
175 => new Vector3(t5_position.X, t5_position.Y, t5_position.Z);
176 public static implicit operator T5_Position(Vector3 position) => new T5_Position(position);
177 }
178
184 [StructLayout(LayoutKind.Sequential)]
185 internal struct T5_Rotation
186 {
187 public float W, X, Y, Z;
188
189 public T5_Rotation(Quaternion rotation)
190 {
191 W = rotation.w;
192 X = rotation.x;
193 Y = rotation.y;
194 Z = rotation.z;
195 }
196
197 public static implicit operator Quaternion(T5_Rotation t5_rotation)
198 => new Quaternion(t5_rotation.X, t5_rotation.Y, t5_rotation.Z, t5_rotation.W);
199 public static implicit operator T5_Rotation(Quaternion rotation) => new T5_Rotation(rotation);
200 }
201
202 internal struct GlassesHandle : IEquatable<GlassesHandle>
203 {
204 private UInt64 glassesHandle;
205 public static implicit operator UInt64(GlassesHandle handle) => handle.glassesHandle;
206 public static implicit operator GlassesHandle(UInt64 handle) => new GlassesHandle() { glassesHandle = handle };
207 public override int GetHashCode() => glassesHandle.GetHashCode();
208 public bool Equals(GlassesHandle other) => glassesHandle == other.glassesHandle;
209 public override string ToString()
210 {
211 return glassesHandle.ToString();
212 }
213 }
214
218 [StructLayout(LayoutKind.Sequential)]
219 public struct T5_GlassesPose
220 {
221 public UInt64 TimestampNanos;
222
223 private T5_Position posOfGLS_GBD;
224 private T5_Rotation rotationToGLS_GBD;
225
227
228 public Vector3 PosOfGLS_GBD { get => posOfGLS_GBD; set => posOfGLS_GBD = value; }
229 public Quaternion RotationToGLS_GBD { get => rotationToGLS_GBD; set => rotationToGLS_GBD = value; }
230 }
231
239 [StructLayout(LayoutKind.Sequential)]
240 public struct T5_CamImage
241 {
242 public UInt16 ImageBufferWidth_PIX;
245 public UInt32 ImageBufferSize_PIX;
246 public IntPtr ImageBuffer;
247 private T5_Position posOfCAM_GBD;
248 private T5_Rotation rotToCAM_GBD;
249 public Vector3 PosOfCAM_GBD { get => posOfCAM_GBD; set => posOfCAM_GBD = value; }
250 public Quaternion RotToCAM_GBD { get => rotToCAM_GBD; set => rotToCAM_GBD = value; }
251
252 public T5_CamImage(UInt16 bufferWidth, UInt16 bufferHeight, UInt16 bufferStride, UInt32 bufferSize)
253 {
254 ImageBuffer = IntPtr.Zero;
255 ImageBufferWidth_PIX = bufferWidth;
256 ImageBufferHeight_PIX = bufferHeight;
257 ImageBufferStride_PIX = bufferStride;
258 ImageBufferSize_PIX = bufferSize;
259 posOfCAM_GBD = Vector3.zero;
260 rotToCAM_GBD = Quaternion.identity;
261 }
262 }
263
267 [StructLayout(LayoutKind.Sequential)]
269 {
270 public byte cameraIndex;
272 public bool enabled { get => streamEnabled; set => streamEnabled = value; }
273 }
274
278 [StructLayout(LayoutKind.Sequential)]
279 public struct T5_ControllerState
280 {
281 [StructLayout(LayoutKind.Sequential)]
282 public struct Joystick
283 {
284 public float X, Y;
285
286 public static implicit operator Vector2(Joystick joystick) => new Vector2(joystick.X, joystick.Y);
287 }
288
289 [StructLayout(LayoutKind.Sequential)]
290 public struct Buttons
291 {
292 private T5_Bool t5,
300
301 public bool T5 { get => t5; set => t5 = value; }
302 public bool One { get => one; set => one = value; }
303 public bool Two { get => two; set => two = value; }
304 public bool Three { get => three; set => three = value; }
305 public bool A { get => a; set => a = value; }
306 public bool B { get => b; set => b = value; }
307 public bool X { get => x; set => x = value; }
308 public bool Y { get => y; set => y = value; }
309 [Obsolete("Buttons.System is deprecated, please use Wandbutton.T5 instead.")]
310 public bool System => T5;
311 [Obsolete("Buttons.Z is deprecated, please use Wandbutton.Three instead.")]
312 public bool Z => Three;
313 }
314
315 public UInt64 TimestampNanos;
316
321
322 public float Trigger;
324 public byte Battery;
326
327 private T5_Rotation rotToWND_GBD;
328 private T5_Position aimPos_GBD;
329 private T5_Position fingertipsPos_GBD;
330 private T5_Position gripPos_GBD;
331
332 public T5_Hand Hand;
333
334 public bool AnalogValid { get => analogValid; set => analogValid = value; }
335 public bool BatteryValid { get => batteryValid; set => batteryValid = value; }
336 public bool ButtonsValid { get => buttonsValid; set => buttonsValid = value; }
337 public bool PoseValid { get => poseValid; set => poseValid = value; }
338
339 public Quaternion RotToWND_GBD { get => rotToWND_GBD; set => rotToWND_GBD = value; }
340 public Vector3 AimPos_GBD { get => aimPos_GBD; set => aimPos_GBD = value; }
341 public Vector3 FingertipsPos_GBD { get => fingertipsPos_GBD; set => fingertipsPos_GBD = value; }
342 public Vector3 GripPos_GBD { get => gripPos_GBD; set => gripPos_GBD = value; }
343 }
344
350 [StructLayout(LayoutKind.Sequential)]
351 internal struct T5_VCI
352 {
353 public float StartX_VCI;
354 public float StartY_VCI;
355 public float Width_VCI;
356 public float Height_VCI;
357
358 public T5_VCI(Rect rect)
359 {
360 StartX_VCI = rect.x;
361 StartY_VCI = rect.y;
362 Width_VCI = rect.width;
363 Height_VCI = rect.height;
364 }
365
366 public static implicit operator Rect(T5_VCI vci)
367 => new Rect(vci.StartX_VCI, vci.StartY_VCI, vci.Width_VCI, vci.Height_VCI);
368 public static implicit operator T5_VCI(Rect rect) => new T5_VCI(rect);
369 }
370
374 [StructLayout(LayoutKind.Sequential)]
375 public struct T5_FrameInfo
376 {
377 public IntPtr LeftTexHandle;
378 public IntPtr RightTexHandle;
379 public UInt16 TexWidth_PIX;
380 public UInt16 TexHeight_PIX;
381
384
385 private T5_VCI vci;
386
387 private T5_Rotation rotToLVC_GBD;
388 private T5_Position posOfLVC_GBD;
389
390 private T5_Rotation rotToRVC_GBD;
391 private T5_Position posOfRVC_GBD;
392
393 public bool IsSrgb { get => isSrgb; set => isSrgb = value; }
394 public bool IsUpsideDown { get => isUpsideDown; set => isUpsideDown = value; }
395 public Rect VCI { get => vci; set => vci = value; }
396 public Quaternion RotToLVC_GBD { get => rotToLVC_GBD; set => rotToLVC_GBD = value; }
397 public Vector3 PosOfLVC_GBD { get => posOfLVC_GBD; set => posOfLVC_GBD = value; }
398 public Quaternion RotToRVC_GBD { get => rotToRVC_GBD; set => rotToRVC_GBD = value; }
399 public Vector3 PosOfRVC_GBD { get => posOfRVC_GBD; set => posOfRVC_GBD = value; }
400 }
401
409 [StructLayout(LayoutKind.Explicit, Pack = 4)]
410 public struct T5_StringUTF8 : IDisposable
411 {
412 [FieldOffset(0)] private UInt32 maxBufferSize;
413 [FieldOffset(4)] private UInt32 length;
414 [FieldOffset(8)] private IntPtr pStringBytesUTF8;
415
416 public T5_StringUTF8(string text)
417 {
418 pStringBytesUTF8 = IntPtr.Zero;
419 length = 0;
420 maxBufferSize = 16 * 1024;
421
422 if (text != null)
423 {
424 // Allocate enough unmanaged memory to store the string
425 byte[] textBytesUTF8 = System.Text.Encoding.UTF8.GetBytes(text);
426
427 // If the string is too long to fit in the unmanaged buffer, truncate it.
428 length = (UInt32)Math.Min(textBytesUTF8.Length, maxBufferSize);
429 pStringBytesUTF8 = Marshal.AllocHGlobal((int)maxBufferSize);
430
431 // Store the string data
432 Marshal.Copy(textBytesUTF8, 0, pStringBytesUTF8, (int)length);
433 }
434 }
435
436 public static implicit operator string(T5_StringUTF8 t5_StringUTF8)
437 => ToString(t5_StringUTF8);
438
439 public static implicit operator T5_StringUTF8(string text) => new T5_StringUTF8(text);
440
441 private static string ToString(T5_StringUTF8 t5_StringUTF8)
442 {
443 if (t5_StringUTF8.pStringBytesUTF8 == IntPtr.Zero)
444 {
445 return null;
446 }
447
448 var managedBytes = new byte[t5_StringUTF8.length];
449 try
450 {
451 Marshal.Copy(t5_StringUTF8.pStringBytesUTF8, managedBytes, 0, (int)t5_StringUTF8.length);
452 return System.Text.Encoding.UTF8.GetString(managedBytes);
453 }
454 catch (Exception e)
455 {
456 Debug.LogError($"Failed to copy string from unmanaged memory: {e}");
457 return null;
458 }
459 }
460
464 public void Dispose()
465 {
466 // Don't forget to free that unmanaged memory we allocated.
467 // Marshal.FreeHGlobal() will safely do nothing if IntPtr.Zero is passed in.
468 Marshal.FreeHGlobal(pStringBytesUTF8);
469 pStringBytesUTF8 = IntPtr.Zero;
470 }
471 }
472
476 public enum ServiceCompatibility : Int32
477 {
478 // <summary>
479 // The running service is incompatible with this client.
480 // </summary>
481 Incompatible = 0,
482
483 // <summary>
484 // The running service is compatible with this client.
485 // </summary>
486 Compatible = 1,
487
488 // <summary>
489 // Don't know yet whether the running service is compatible with this client.
490 // </summary>
491 Unknown = 2,
492 }
493
497 public enum PlayerIndex
498 {
499 [HideInInspector]
500 None = 0,
501 One = 1,
502 Two = 2,
503 Three = 3,
504 Four = 4
505 }
506
511 public enum ControllerIndex : Int32
512 {
516 Right = 0,
517
521 Left = 1,
522
523 [Obsolete("ControllerIndex.Primary is deprecated, please update to use left/right based on user preference instead.")]
524 Primary = Right,
525
526 [Obsolete("ControllerIndex.Secondary is deprecated, please update to use left/right based on user preference instead.")]
527 Secondary = Left,
528 }
529
533 public enum GameboardType : Int32
534 {
542
547
552
557 }
558
562 [StructLayout(LayoutKind.Sequential)]
563 public struct T5_GameboardSize
564 {
566 public float BorderWidth;
567
568 public T5_GameboardSize(float playableSpaceX, float playableSpaceY, float borderWidth)
569 {
570 PlayableSpaceX = playableSpaceX;
571 PlayableSpaceY = playableSpaceY;
572 BorderWidth = borderWidth;
573 }
574 }
575
579 public enum ControllerPosition : Int32
580 {
584 Grip = 0,
585
589 Fingertips = 1,
590
594 Aim = 2
595 }
596
600 public enum T5_Hand : byte
601 {
605 Unknown = 0,
606
610 Left = 1,
611
615 Right = 2,
616 }
617
621 public enum T5_GlassesPoseUsage : Int32
622 {
634
644 }
645}
static void UnloadWorkaround()
static int GetWandAvailability(UInt64 glassesHandle, ref T5_Bool wandAvailable, [MarshalAs(UnmanagedType.I4)] ControllerIndex wandTarget)
static int GetGlassesPose(UInt64 glassesHandle, ref T5_GlassesPose glassesPose, [MarshalAs(UnmanagedType.I4)] T5_GlassesPoseUsage glassesPoseUsage)
static int CancelCamImageBuffer(UInt64 glassesHandle, IntPtr buffer)
static ServiceCompatibility GetServiceCompatibility()
static int GetGlassesIPD(UInt64 glassesHandle, ref float glassesIPD)
static int GetGameboardDimensions([MarshalAs(UnmanagedType.I4)] GameboardType gameboardType, ref T5_GameboardSize playableSpaceInMeters)
static int GetGlassesFriendlyName(UInt64 glassesHandle, ref T5_StringUTF8 glassesFriendlyName)
static int SetRumbleMotor(uint motor, float intensity)
static void SetMaxDesiredGlasses(byte maxCount)
static int QueueStereoImages(UInt64 glassesHandle, T5_FrameInfo frameInfo)
const string PLUGIN_LIBRARY
Definition: NativePlugin.cs:28
static IntPtr GetSendFrameCallback()
static int RefreshGlassesAvailable()
static int GetControllerState(UInt64 glassesHandle, [MarshalAs(UnmanagedType.I4)] ControllerIndex controllerIndex, ref T5_ControllerState controllerState)
static int ScanForWands()
static int GetGlassesHandles(ref byte handleCount, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] UInt64[] glassesHandle)
static int SubmitEmptyCamImageBuffer(UInt64 glassesHandle, IntPtr camImageBuffer, UInt32 bufferSize)
static int ConfigureCameraStream(UInt64 glassesHandle, T5_CameraStreamConfig cameraConfig)
static int GetMaxDisplayDimensions([MarshalAs(UnmanagedType.LPArray, SizeConst=2)] int[] displayDimensions)
static int GetFilledCamImageBuffer(UInt64 glassesHandle, ref T5_CamImage camImageBuffer)
static int SetApplicationInfo(T5_StringUTF8 appName, T5_StringUTF8 appId, T5_StringUTF8 appVersion)
Definition: Log.cs:21
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.
T5_GlassesPoseUsage
Glasses pose usage indicator.
@ SpectatorPresentation
The pose will be used to render images to be presented on a device other than the glasses,...
@ GlassesPresentation
The pose will be used to render images to be presented on the glasses.
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 boolean value.
readonly byte booleanByte
T5_Bool(bool boolean)
Represents a wrapper on a buffer comtaining a camera image.
T5_Position posOfCAM_GBD
T5_CamImage(UInt16 bufferWidth, UInt16 bufferHeight, UInt16 bufferStride, UInt32 bufferSize)
T5_Rotation rotToCAM_GBD
Quaternion RotToCAM_GBD
Camera Stream Configuration.
Contains wand related information (Pose, Buttons, Trigger, Stick, Battery)
Render information to be used with NativePlugin.QueueStereoImages(T5_FrameInfo)
T5_Position posOfRVC_GBD
T5_Position posOfLVC_GBD
T5_Rotation rotToRVC_GBD
T5_Rotation rotToLVC_GBD
Physical dimensions of a gameboard, in meters.
T5_GameboardSize(float playableSpaceX, float playableSpaceY, float borderWidth)
Headset pose information to be retrieved with NativePlugin.GetGlassesPose(ref T5_GlassesPose)
T5_Rotation rotationToGLS_GBD
GameboardType GameboardType
Quaternion RotationToGLS_GBD
Represents a string value.
static string ToString(T5_StringUTF8 t5_StringUTF8)
T5_StringUTF8(string text)
void Dispose()
Safely disposes of this T5_StringUTF8 and any unmanaged memory allocated during its construction.