1 | 'use strict';
|
2 | import { useEffect, useMemo, useRef } from 'react';
|
3 | import { initializeSensor, registerSensor, unregisterSensor } from '../core';
|
4 | import type {
|
5 | SensorConfig,
|
6 | AnimatedSensor,
|
7 | Value3D,
|
8 | ValueRotation,
|
9 | } from '../commonTypes';
|
10 | import {
|
11 | SensorType,
|
12 | IOSReferenceFrame,
|
13 | InterfaceOrientation,
|
14 | } from '../commonTypes';
|
15 | import { callMicrotasks } from '../threads';
|
16 |
|
17 |
|
18 |
|
19 | function eulerToQuaternion(pitch: number, roll: number, yaw: number) {
|
20 | 'worklet';
|
21 | const c1 = Math.cos(pitch / 2);
|
22 | const s1 = Math.sin(pitch / 2);
|
23 | const c2 = Math.cos(roll / 2);
|
24 | const s2 = Math.sin(roll / 2);
|
25 | const c3 = Math.cos(yaw / 2);
|
26 | const s3 = Math.sin(yaw / 2);
|
27 |
|
28 | return [
|
29 | s1 * c2 * c3 - c1 * s2 * s3,
|
30 | c1 * s2 * c3 + s1 * c2 * s3,
|
31 | c1 * c2 * s3 + s1 * s2 * c3,
|
32 | c1 * c2 * c3 - s1 * s2 * s3,
|
33 | ];
|
34 | }
|
35 |
|
36 | function adjustRotationToInterfaceOrientation(data: ValueRotation) {
|
37 | 'worklet';
|
38 | const { interfaceOrientation, pitch, roll, yaw } = data;
|
39 | if (interfaceOrientation === InterfaceOrientation.ROTATION_90) {
|
40 | data.pitch = roll;
|
41 | data.roll = -pitch;
|
42 | data.yaw = yaw - Math.PI / 2;
|
43 | } else if (interfaceOrientation === InterfaceOrientation.ROTATION_270) {
|
44 | data.pitch = -roll;
|
45 | data.roll = pitch;
|
46 | data.yaw = yaw + Math.PI / 2;
|
47 | } else if (interfaceOrientation === InterfaceOrientation.ROTATION_180) {
|
48 | data.pitch *= -1;
|
49 | data.roll *= -1;
|
50 | data.yaw *= -1;
|
51 | }
|
52 |
|
53 | const q = eulerToQuaternion(data.pitch, data.roll, data.yaw);
|
54 | data.qx = q[0];
|
55 | data.qy = q[1];
|
56 | data.qz = q[2];
|
57 | data.qw = q[3];
|
58 | return data;
|
59 | }
|
60 |
|
61 | function adjustVectorToInterfaceOrientation(data: Value3D) {
|
62 | 'worklet';
|
63 | const { interfaceOrientation, x, y } = data;
|
64 | if (interfaceOrientation === InterfaceOrientation.ROTATION_90) {
|
65 | data.x = -y;
|
66 | data.y = x;
|
67 | } else if (interfaceOrientation === InterfaceOrientation.ROTATION_270) {
|
68 | data.x = y;
|
69 | data.y = -x;
|
70 | } else if (interfaceOrientation === InterfaceOrientation.ROTATION_180) {
|
71 | data.x *= -1;
|
72 | data.y *= -1;
|
73 | }
|
74 | return data;
|
75 | }
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | export function useAnimatedSensor(
|
86 | sensorType: SensorType.ROTATION,
|
87 | userConfig?: Partial<SensorConfig>
|
88 | ): AnimatedSensor<ValueRotation>;
|
89 | export function useAnimatedSensor(
|
90 | sensorType: Exclude<SensorType, SensorType.ROTATION>,
|
91 | userConfig?: Partial<SensorConfig>
|
92 | ): AnimatedSensor<Value3D>;
|
93 | export function useAnimatedSensor(
|
94 | sensorType: SensorType,
|
95 | userConfig?: Partial<SensorConfig>
|
96 | ): AnimatedSensor<ValueRotation> | AnimatedSensor<Value3D> {
|
97 | const userConfigRef = useRef(userConfig);
|
98 |
|
99 | const hasConfigChanged =
|
100 | userConfigRef.current?.adjustToInterfaceOrientation !==
|
101 | userConfig?.adjustToInterfaceOrientation ||
|
102 | userConfigRef.current?.interval !== userConfig?.interval ||
|
103 | userConfigRef.current?.iosReferenceFrame !== userConfig?.iosReferenceFrame;
|
104 |
|
105 | if (hasConfigChanged) {
|
106 | userConfigRef.current = { ...userConfig };
|
107 | }
|
108 |
|
109 | const config: SensorConfig = useMemo(
|
110 | () => ({
|
111 | interval: 'auto',
|
112 | adjustToInterfaceOrientation: true,
|
113 | iosReferenceFrame: IOSReferenceFrame.Auto,
|
114 | ...userConfigRef.current,
|
115 | }),
|
116 | [userConfigRef.current]
|
117 | );
|
118 |
|
119 | const ref = useRef<AnimatedSensor<Value3D | ValueRotation>>({
|
120 | sensor: initializeSensor(sensorType, config),
|
121 | unregister: () => {
|
122 |
|
123 | },
|
124 | isAvailable: false,
|
125 | config,
|
126 | });
|
127 |
|
128 | useEffect(() => {
|
129 | ref.current = {
|
130 | sensor: initializeSensor(sensorType, config),
|
131 | unregister: () => {
|
132 |
|
133 | },
|
134 | isAvailable: false,
|
135 | config,
|
136 | };
|
137 |
|
138 | const sensorData = ref.current.sensor;
|
139 | const adjustToInterfaceOrientation =
|
140 | ref.current.config.adjustToInterfaceOrientation;
|
141 |
|
142 | const id = registerSensor(sensorType, config, (data) => {
|
143 | 'worklet';
|
144 | if (adjustToInterfaceOrientation) {
|
145 | if (sensorType === SensorType.ROTATION) {
|
146 | data = adjustRotationToInterfaceOrientation(data as ValueRotation);
|
147 | } else {
|
148 | data = adjustVectorToInterfaceOrientation(data as Value3D);
|
149 | }
|
150 | }
|
151 | sensorData.value = data;
|
152 | callMicrotasks();
|
153 | });
|
154 |
|
155 | if (id !== -1) {
|
156 |
|
157 | ref.current.unregister = () => unregisterSensor(id);
|
158 | ref.current.isAvailable = true;
|
159 | } else {
|
160 |
|
161 | ref.current.unregister = () => {
|
162 |
|
163 | };
|
164 | ref.current.isAvailable = false;
|
165 | }
|
166 |
|
167 | return () => {
|
168 | ref.current.unregister();
|
169 | };
|
170 | }, [sensorType, config]);
|
171 |
|
172 | return ref.current as AnimatedSensor<ValueRotation> | AnimatedSensor<Value3D>;
|
173 | }
|