File size: 14,504 Bytes
18a519f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
// ENABLE_VR is not defined on Game Core but the assembly is available with limited features when the XR module is enabled.
#if UNITY_INPUT_SYSTEM_ENABLE_XR && (ENABLE_VR || UNITY_GAMECORE) && !UNITY_FORCE_INPUTSYSTEM_XR_OFF || PACKAGE_DOCS_GENERATION
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Layouts;
using UnityEngine.InputSystem.LowLevel;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Scripting;
using TrackingState = UnityEngine.XR.InputTrackingState;

namespace UnityEngine.InputSystem.XR
{
    /// <summary>
    /// State layout for a single pose.
    /// </summary>
    /// <remarks>
    /// This is the low-level memory representation of a single pose, i.e the
    /// way poses are internally transmitted and stored in the system. PoseStates are used on devices containing <see cref="PoseControl"/>s.
    /// </remarks>
    /// <seealso cref="PoseControl"/>
    [StructLayout(LayoutKind.Explicit, Size = kSizeInBytes)]
    public struct PoseState : IInputStateTypeInfo
    {
        internal const int kSizeInBytes = 60;

        internal static readonly FourCC s_Format = new FourCC('P', 'o', 's', 'e');

        /// <summary>
        /// Memory format tag for PoseState.
        /// </summary>
        /// <value>Returns "Pose".</value>
        /// <seealso cref="InputStateBlock.format"/>
        public FourCC format => s_Format;

        /// <summary>
        /// Constructor for PoseStates.
        ///
        /// Useful for creating PoseStates locally (not from <see cref="PoseControl"/>).
        /// </summary>
        /// <param name="isTracked">Value to use for <see cref="isTracked"/></param>
        /// <param name="trackingState">Value to use for <see cref="trackingState"/></param>
        /// <param name="position">Value to use for <see cref="position"/></param>
        /// <param name="rotation">Value to use for <see cref="rotation"/></param>
        /// <param name="velocity">Value to use for <see cref="velocity"/></param>
        /// <param name="angularVelocity">Value to use for <see cref="angularVelocity"/></param>
        public PoseState(bool isTracked, TrackingState trackingState, Vector3 position, Quaternion rotation, Vector3 velocity, Vector3 angularVelocity)
        {
            this.isTracked = isTracked;
            this.trackingState = trackingState;
            this.position = position;
            this.rotation = rotation;
            this.velocity = velocity;
            this.angularVelocity = angularVelocity;
        }

        /// <summary>
        /// Whether the pose is currently being fully tracked. Otherwise, the tracking is either unavailable, or simulated.
        /// </summary>
        /// <remarks>
        /// Fully tracked means that the pose is accurate and not using any simulated or extrapolated positions, and the system tracking this pose is able to confidently track this object.
        /// </remarks>
        [FieldOffset(0), InputControl(displayName = "Is Tracked", layout = "Button", sizeInBits = 8 /* needed to ensure optimization kicks-in */)]
        public bool isTracked;

        /// <summary>
        /// A Flags Enumeration specifying which other fields in the pose state are valid.
        /// </summary>
        [FieldOffset(4), InputControl(displayName = "Tracking State", layout = "Integer")]
        public TrackingState trackingState;

        /// <summary>
        /// The position in 3D space, relative to the tracking origin where this pose represents.
        /// </summary>
        /// <remarks>
        /// Positions are represented in meters.
        /// This field is only valid if <see cref="trackingState"/> contains the <see cref="UnityEngine.XR.InputTrackingState.Position"/> value.
        /// See <seealso cref="UnityEngine.XR.TrackingOriginModeFlags"/> for information on tracking origins.
        /// </remarks>
        [FieldOffset(8), InputControl(displayName = "Position", noisy = true)]
        public Vector3 position;

        /// <summary>
        /// The rotation in 3D space, relative to the tracking origin where this pose represents.
        /// </summary>
        /// <remarks>
        /// This field is only valid if <see cref="trackingState"/> contains the <see cref="UnityEngine.XR.InputTrackingState.Rotation"/> value.
        /// See <seealso cref="UnityEngine.XR.TrackingOriginModeFlags"/> for information on tracking origins.
        /// </remarks>
        [FieldOffset(20), InputControl(displayName = "Rotation", noisy = true)]
        public Quaternion rotation;

        /// <summary>
        /// The velocity in 3D space, relative to the tracking origin where this pose represents.
        /// </summary>
        /// <remarks>
        /// Velocities are represented in meters per second.
        /// This field is only valid if <see cref="trackingState"/> contains the <see cref="UnityEngine.XR.InputTrackingState.Velocity"/> value.
        /// See <seealso cref="UnityEngine.XR.TrackingOriginModeFlags"/> for information on tracking origins.
        /// </remarks>
        [FieldOffset(36), InputControl(displayName = "Velocity", noisy = true)]
        public Vector3 velocity;

        /// <summary>
        /// The angular velocity in 3D space, relative to the tracking origin where this pose represents.
        /// </summary>
        /// <remarks>
        /// This field is only valid if <see cref="trackingState"/> contains the <see cref="UnityEngine.XR.InputTrackingState.AngularVelocity"/> value.
        /// See <seealso cref="UnityEngine.XR.TrackingOriginModeFlags"/> for information on tracking origins.
        /// </remarks>
        [FieldOffset(48), InputControl(displayName = "Angular Velocity", noisy = true)]
        public Vector3 angularVelocity;
    }

    /// <summary>
    /// A control representing a Pose in 3D space, relative to an XR tracking origin
    /// </summary>
    /// <remarks>
    /// Note that unlike most other control types, <c>PoseControls</c> do not have
    /// a flexible memory layout. They are hardwired to <see cref="PoseState"/> and
    /// will not work correctly with a different memory layouts. Additional fields may
    /// be appended to the struct but what's there in the struct has to be located
    /// at exactly those memory addresses.
    ///
    /// For more information on tracking origins see <see cref="UnityEngine.XR.TrackingOriginModeFlags"/>.
    /// </remarks>
    [Preserve, InputControlLayout(stateType = typeof(PoseState))]
    public class PoseControl : InputControl<PoseState>
    {
        /// <summary>
        /// Represents whether this pose is fully tracked or unavailable/simulated.
        /// </summary>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.isTracked"/> value.</value>
        /// <seealso cref="PoseState.isTracked"/>
        public ButtonControl isTracked { get; private set; }

        /// <summary>
        /// The other controls on this <see cref="PoseControl"/> that are currently reporting data.
        /// </summary>
        /// <remarks>
        /// This can be missing values when the device tracking this pose is restricted or not tracking properly.
        /// </remarks>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.trackingState"/> value of the pose retrieved from this control.</value>
        /// <seealso cref="PoseState.trackingState"/>
        public IntegerControl trackingState { get; private set; }

        /// <summary>
        /// The position, in meters, of this tracked pose relative to the tracking origin.
        /// </summary>
        /// <remarks>
        /// The data for this control is only valid if the value returned from <see cref="trackingState"/> contains <see cref="UnityEngine.XR.InputTrackingState.Position"/> value.
        /// </remarks>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.position"/> value of the pose retrieved from this control.</value>
        /// <seealso cref="PoseState.position"/>
        public Vector3Control position { get; private set; }

        /// <summary>
        /// The rotation of this tracked pose relative to the tracking origin.
        /// </summary>
        /// <remarks>
        /// The data for this control is only valid if the value returned from <see cref="trackingState"/> contains <see cref="UnityEngine.XR.InputTrackingState.Rotation"/> value.
        /// </remarks>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.rotation"/> value of the pose retrieved from this control.</value>
        /// <seealso cref="PoseState.rotation"/>
        public QuaternionControl rotation { get; private set; }

        /// <summary>
        /// The velocity, in meters per second, of this tracked pose relative to the tracking origin.
        /// </summary>
        /// <remarks>
        /// The data for this control is only valid if the value returned from <see cref="trackingState"/> contains <see cref="UnityEngine.XR.InputTrackingState.Velocity"/> value.
        /// </remarks>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.velocity"/> value of the pose retrieved from this control.</value>
        /// <seealso cref="PoseState.velocity"/>
        public Vector3Control velocity { get; private set; }

        /// <summary>
        /// The angular velocity of this tracked pose relative to the tracking origin.
        /// </summary>
        /// <remarks>
        /// The data for this control is only valid if the value returned from <see cref="trackingState"/> contains <see cref="UnityEngine.XR.InputTrackingState.AngularVelocity"/> value.
        /// </remarks>
        /// <value>Control representing whether the pose is being fully tracked. Maps to the <see cref="PoseState.angularVelocity"/> value of the pose retrieved from this control.</value>
        /// <seealso cref="PoseState.angularVelocity"/>
        public Vector3Control angularVelocity { get; private set; }

        /// <summary>
        /// Default-initialize the pose control.
        /// </summary>
        /// <remarks>
        /// Sets the <see cref="InputStateBlock.format"/> to <c>"Pose"</c>.
        /// </remarks>
        public PoseControl()
        {
            m_StateBlock.format = PoseState.s_Format;
        }

        /// <inheritdoc />
        protected override void FinishSetup()
        {
            isTracked = GetChildControl<ButtonControl>("isTracked");
            trackingState = GetChildControl<IntegerControl>("trackingState");
            position = GetChildControl<Vector3Control>("position");
            rotation = GetChildControl<QuaternionControl>("rotation");
            velocity = GetChildControl<Vector3Control>("velocity");
            angularVelocity = GetChildControl<Vector3Control>("angularVelocity");

            base.FinishSetup();
        }

        /// <inheritdoc />
        public override unsafe PoseState ReadUnprocessedValueFromState(void* statePtr)
        {
            switch (m_OptimizedControlDataType)
            {
                case InputStateBlock.kFormatPose:
                    return *(PoseState*)((byte*)statePtr + (int)m_StateBlock.byteOffset);
                default:
                    return new PoseState()
                    {
                        isTracked = isTracked.ReadUnprocessedValueFromStateWithCaching(statePtr) > 0.5f,
                        trackingState = (TrackingState)trackingState.ReadUnprocessedValueFromStateWithCaching(statePtr),
                        position = position.ReadUnprocessedValueFromStateWithCaching(statePtr),
                        rotation = rotation.ReadUnprocessedValueFromStateWithCaching(statePtr),
                        velocity = velocity.ReadUnprocessedValueFromStateWithCaching(statePtr),
                        angularVelocity = angularVelocity.ReadUnprocessedValueFromStateWithCaching(statePtr),
                    };
            }
        }

        /// <inheritdoc />
        public override unsafe void WriteValueIntoState(PoseState value, void* statePtr)
        {
            switch (m_OptimizedControlDataType)
            {
                case InputStateBlock.kFormatPose:
                    *(PoseState*)((byte*)statePtr + (int)m_StateBlock.byteOffset) = value;
                    break;
                default:
                    isTracked.WriteValueIntoState(value.isTracked, statePtr);
                    trackingState.WriteValueIntoState((uint)value.trackingState, statePtr);
                    position.WriteValueIntoState(value.position, statePtr);
                    rotation.WriteValueIntoState(value.rotation, statePtr);
                    velocity.WriteValueIntoState(value.velocity, statePtr);
                    angularVelocity.WriteValueIntoState(value.angularVelocity, statePtr);
                    break;
            }
        }

        protected override FourCC CalculateOptimizedControlDataType()
        {
            if (
                m_StateBlock.sizeInBits == PoseState.kSizeInBytes * 8 &&
                m_StateBlock.bitOffset == 0 &&
                isTracked.optimizedControlDataType == InputStateBlock.kFormatByte &&
                trackingState.optimizedControlDataType == InputStateBlock.kFormatInt &&
                position.optimizedControlDataType == InputStateBlock.kFormatVector3 &&
                rotation.optimizedControlDataType == InputStateBlock.kFormatQuaternion &&
                velocity.optimizedControlDataType == InputStateBlock.kFormatVector3 &&
                angularVelocity.optimizedControlDataType == InputStateBlock.kFormatVector3 &&
                trackingState.m_StateBlock.byteOffset == isTracked.m_StateBlock.byteOffset + 4 &&
                position.m_StateBlock.byteOffset == isTracked.m_StateBlock.byteOffset + 8 &&
                rotation.m_StateBlock.byteOffset == isTracked.m_StateBlock.byteOffset + 20 &&
                velocity.m_StateBlock.byteOffset == isTracked.m_StateBlock.byteOffset + 36 &&
                angularVelocity.m_StateBlock.byteOffset == isTracked.m_StateBlock.byteOffset + 48
            )
                return InputStateBlock.kFormatPose;

            return InputStateBlock.kFormatInvalid;
        }
    }
}
#endif