@zappar/zappar-cv 3.6.0 → 3.7.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,19 @@
1
+ import { Zappar } from ".";
2
+ import { Pipeline } from "./pipeline";
3
+ import { WebXRWTOptions } from "./webxr-camera-source";
4
+ export declare class WebXRWorldTracker {
5
+ private static _sharedInstance;
6
+ static SharedInstance(): WebXRWorldTracker;
7
+ private _latestId;
8
+ private _wtStateById;
9
+ private _anchorStateById;
10
+ private _identityPose;
11
+ private _emptyArray;
12
+ private _getWtState;
13
+ private _getAnchorState;
14
+ private _getWtDataFromPipeline;
15
+ private _getWtData;
16
+ private _notifyOptionsUpdated;
17
+ getCombinedOptionsForPipeline(p: Pipeline): WebXRWTOptions;
18
+ impl: Partial<Zappar>;
19
+ }
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.6.0";
1
+ export declare const VERSION = "3.7.0-beta.0";
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "3.6.0";
1
+ export const VERSION = "3.7.0-beta.0";
@@ -0,0 +1,79 @@
1
+ import { anchor_status_t, world_tracker_quality_t, camera_profile_t, zappar_camera_source_t, zappar_pipeline_t, zappar_custom_anchor_t } from "./gen/zappar";
2
+ import { CameraFrameInfo, Source } from "./source";
3
+ export interface WebXRPlaneAnchorData {
4
+ id: string;
5
+ horizontal: boolean;
6
+ status: anchor_status_t;
7
+ pose: Float32Array;
8
+ boundary: Float32Array;
9
+ boundaryVersion: number;
10
+ }
11
+ export interface WebXRCustomAnchorData {
12
+ id: number;
13
+ status: anchor_status_t;
14
+ pose: Float32Array;
15
+ poseVersion: number;
16
+ }
17
+ export interface WebXRWTData {
18
+ world_anchor_status: anchor_status_t;
19
+ world_anchor_pose: Float32Array;
20
+ ground_anchor_status: anchor_status_t;
21
+ ground_anchor_pose: Float32Array;
22
+ plane_anchors: WebXRPlaneAnchorData[];
23
+ custom_anchors: WebXRCustomAnchorData[];
24
+ quality: world_tracker_quality_t;
25
+ }
26
+ export interface WebXRWTOptions {
27
+ horizontalPlaneDetection: boolean;
28
+ verticalPlaneDetection: boolean;
29
+ }
30
+ export declare class WebXRCameraSource extends Source {
31
+ private _impl;
32
+ private _pipeline;
33
+ sessionNumber: number;
34
+ private _isPaused;
35
+ private _xrSession;
36
+ private _xrLocalSpace;
37
+ private _xrViewerSpace;
38
+ private _xrGlBinding;
39
+ private _xrWebGLLayer;
40
+ private _offscreenCanvas;
41
+ private _offscreenContext;
42
+ private _imageBlitGl;
43
+ private _latestFrame;
44
+ private _latestWtData;
45
+ private _wtOptions;
46
+ private _lastFrameTime;
47
+ private _cameraToDeviceTransform;
48
+ private _cameraModel;
49
+ private _rawCameraModel;
50
+ private _profile;
51
+ private _permissionRequestShown;
52
+ private _planeHitTestSource;
53
+ private _customAnchorSetRequests;
54
+ private _customAnchors;
55
+ static IsSupported(): boolean;
56
+ constructor(_impl: zappar_camera_source_t, _pipeline: zappar_pipeline_t);
57
+ destroy(): void;
58
+ setProfile(p: camera_profile_t): void;
59
+ private _stop;
60
+ pause(): void;
61
+ start(): void;
62
+ optionsUpdated(options: WebXRWTOptions): void;
63
+ resetTracking(): void;
64
+ getFrame(currentlyProcessing: boolean): void;
65
+ private _syncCamera;
66
+ private _onXRFrame;
67
+ private _onXREnd;
68
+ private _hasStartedOrientation;
69
+ private _lastTimestamp;
70
+ private _deviceMotionListener;
71
+ private _startDeviceOrientation;
72
+ private _startDeviceMotion;
73
+ private _stopDeviceMotion;
74
+ uploadGL(info: CameraFrameInfo): void;
75
+ setCustomAnchorPose(o: zappar_custom_anchor_t, version: number, pose: Float32Array): Promise<void>;
76
+ deleteCustomAnchor(o: zappar_custom_anchor_t): Promise<void>;
77
+ private _updateCameraModel;
78
+ private _isPlaneVertical;
79
+ }
@@ -0,0 +1,537 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { anchor_status_t, world_tracker_quality_t, camera_profile_t } from "./gen/zappar";
11
+ import { profile } from "./profile";
12
+ import { Pipeline } from "./pipeline";
13
+ import { Source } from "./source";
14
+ import { cameraRotationForScreenOrientation } from "./cameramodel";
15
+ import { zcout } from "./loglevel";
16
+ import { deleteCameraSource } from "./camera-source-map";
17
+ import { mat4, vec3, quat } from "gl-matrix";
18
+ import { ImageBlitGl } from "./image-blit-gl";
19
+ import { permissionRequestUI } from "./permission";
20
+ const _circleBoundary = new Float32Array(32 * 2);
21
+ for (let i = 0; i < 32; i++) {
22
+ const angle = (i / 32) * 2 * Math.PI;
23
+ _circleBoundary[i * 2] = Math.cos(angle) * 0.5;
24
+ _circleBoundary[i * 2 + 1] = Math.sin(angle) * 0.5;
25
+ }
26
+ const _quat = quat.create();
27
+ const _trans = vec3.create();
28
+ const _up = vec3.fromValues(0, 1, 0);
29
+ export class WebXRCameraSource extends Source {
30
+ constructor(_impl, _pipeline) {
31
+ super();
32
+ this._impl = _impl;
33
+ this._pipeline = _pipeline;
34
+ this.sessionNumber = 0;
35
+ this._isPaused = true;
36
+ this._xrSession = null;
37
+ this._xrLocalSpace = null;
38
+ this._xrViewerSpace = null;
39
+ this._xrGlBinding = null;
40
+ this._xrWebGLLayer = null;
41
+ this._offscreenCanvas = new OffscreenCanvas(640, 480);
42
+ this._latestFrame = null;
43
+ this._latestWtData = null;
44
+ this._wtOptions = {
45
+ horizontalPlaneDetection: true,
46
+ verticalPlaneDetection: false
47
+ };
48
+ this._lastFrameTime = -1;
49
+ this._cameraToDeviceTransform = mat4.create();
50
+ this._cameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
51
+ this._rawCameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
52
+ this._profile = camera_profile_t.DEFAULT;
53
+ this._permissionRequestShown = false;
54
+ this._planeHitTestSource = null;
55
+ this._customAnchorSetRequests = new Map();
56
+ this._customAnchors = new Map();
57
+ this._onXRFrame = (time, frame) => {
58
+ var _a, _b, _c, _d, _e;
59
+ if (this._isPaused)
60
+ return;
61
+ (_a = this._xrSession) === null || _a === void 0 ? void 0 : _a.requestAnimationFrame(this._onXRFrame);
62
+ if (!this._xrLocalSpace || !this._xrGlBinding || !this._xrViewerSpace)
63
+ return;
64
+ let viewerPose = frame.getViewerPose(this._xrViewerSpace);
65
+ if (!viewerPose)
66
+ return;
67
+ let camView;
68
+ let camera;
69
+ let texture;
70
+ for (const view of viewerPose.views) {
71
+ camera = view.camera;
72
+ if (camera) {
73
+ texture = this._xrGlBinding.getCameraImage(camera);
74
+ if (texture) {
75
+ camView = view;
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ if (!texture)
81
+ return;
82
+ const viewport = (_b = this._xrWebGLLayer) === null || _b === void 0 ? void 0 : _b.getViewport(camView);
83
+ this._updateCameraModel(camView, viewport);
84
+ const localPose = frame.getViewerPose(this._xrLocalSpace);
85
+ const gl = this._offscreenContext;
86
+ let blitWidth = camera.width;
87
+ let blitHeight = camera.height;
88
+ let blitMax = Math.max(blitWidth, blitHeight);
89
+ if (blitMax > 1280) {
90
+ blitWidth = Math.round(1280 * blitWidth / blitMax);
91
+ blitHeight = Math.round(1280 * blitHeight / blitMax);
92
+ }
93
+ if (blitWidth != this._offscreenCanvas.width || blitHeight != this._offscreenCanvas.height) {
94
+ this._offscreenCanvas.width = blitWidth;
95
+ this._offscreenCanvas.height = blitHeight;
96
+ gl.viewport(0, 0, this._offscreenCanvas.width, this._offscreenCanvas.height);
97
+ }
98
+ // Blit the texture to the framebuffer
99
+ gl.bindTexture(gl.TEXTURE_2D, texture);
100
+ this._imageBlitGl.doBlit();
101
+ gl.bindTexture(gl.TEXTURE_2D, null);
102
+ if (this._latestFrame)
103
+ this._latestFrame.close();
104
+ this._latestFrame = this._offscreenCanvas.transferToImageBitmap();
105
+ let rot = cameraRotationForScreenOrientation(false);
106
+ const rotateMatrix = (m, rot) => {
107
+ let ret = m.slice();
108
+ if (rot === 90) {
109
+ ret[0] = m[1];
110
+ ret[4] = m[5];
111
+ ret[8] = m[9];
112
+ ret[12] = m[13];
113
+ ret[1] = -m[0];
114
+ ret[5] = -m[4];
115
+ ret[9] = -m[8];
116
+ ret[13] = -m[12];
117
+ }
118
+ if (rot === 180) {
119
+ ret[0] = -m[0];
120
+ ret[4] = -m[4];
121
+ ret[8] = -m[8];
122
+ ret[12] = -m[12];
123
+ ret[1] = -m[1];
124
+ ret[5] = -m[5];
125
+ ret[9] = -m[9];
126
+ ret[13] = -m[13];
127
+ }
128
+ if (rot === 270) {
129
+ ret[0] = -m[1];
130
+ ret[4] = -m[5];
131
+ ret[8] = -m[9];
132
+ ret[12] = -m[13];
133
+ ret[1] = m[0];
134
+ ret[5] = m[4];
135
+ ret[9] = m[8];
136
+ ret[13] = m[12];
137
+ }
138
+ return ret;
139
+ };
140
+ for (const [customAnchor, req] of this._customAnchorSetRequests.entries()) {
141
+ if (req.delay > 0) {
142
+ req.delay--;
143
+ continue;
144
+ }
145
+ this._customAnchorSetRequests.delete(customAnchor);
146
+ mat4.getRotation(_quat, req.pose);
147
+ mat4.getTranslation(_trans, req.pose);
148
+ const rigid = new XRRigidTransform({ x: _trans[0], y: _trans[1], z: _trans[2], w: 1 }, { x: _quat[0], y: _quat[1], z: _quat[2], w: _quat[3] });
149
+ (_d = (_c = frame.createAnchor) === null || _c === void 0 ? void 0 : _c.call(frame, rigid, this._xrLocalSpace)) === null || _d === void 0 ? void 0 : _d.then(anchor => {
150
+ const existing = this._customAnchors.get(customAnchor);
151
+ if (existing)
152
+ existing.anchor.delete();
153
+ this._customAnchors.set(customAnchor, { anchor, version: req.version });
154
+ });
155
+ }
156
+ const plane_anchors = [];
157
+ if (this._planeHitTestSource && this._wtOptions.horizontalPlaneDetection && this._xrViewerSpace) {
158
+ const hitTestResults = frame.getHitTestResults(this._planeHitTestSource);
159
+ for (const hitTestResult of hitTestResults) {
160
+ const worldPose = hitTestResult.getPose(this._xrLocalSpace);
161
+ const poseInCamera = hitTestResult.getPose(this._xrViewerSpace);
162
+ if (!worldPose || !poseInCamera)
163
+ continue;
164
+ if (this._isPlaneVertical(worldPose)) {
165
+ if (this._wtOptions.verticalPlaneDetection) {
166
+ const xzRotation = [1, 0];
167
+ // Looking to compute a 2D rotation matrix to rotate the X and Z coordinates
168
+ // of the WebXR plane such that the Z coordinate points down (ie aligned
169
+ // with -Y in the world).
170
+ // [a -b]
171
+ // [b a]
172
+ // Dot product of X and Z axis directions with world up direction
173
+ const xDp = worldPose.transform.matrix[1];
174
+ const zDp = worldPose.transform.matrix[9];
175
+ const normScale = 1.0 / Math.sqrt(xDp * xDp + zDp * zDp);
176
+ xzRotation[0] = -zDp * normScale;
177
+ xzRotation[1] = -xDp * normScale;
178
+ const cp = poseInCamera.transform.matrix.slice();
179
+ const m0 = cp[0];
180
+ const m1 = cp[1];
181
+ const m2 = cp[2];
182
+ const m8 = cp[8];
183
+ const m9 = cp[9];
184
+ const m10 = cp[10];
185
+ const a = xzRotation[0];
186
+ const b = -xzRotation[1]; // -b gives us the inverse
187
+ cp[0] = a * m0 + b * m8;
188
+ cp[1] = a * m1 + b * m9;
189
+ cp[2] = a * m2 + b * m10;
190
+ cp[8] = -b * m0 + a * m8;
191
+ cp[9] = -b * m1 + a * m9;
192
+ cp[10] = -b * m2 + a * m10;
193
+ plane_anchors.push({
194
+ id: "plane-" + plane_anchors.length,
195
+ horizontal: false,
196
+ status: anchor_status_t.ANCHOR_STATUS_TRACKING,
197
+ pose: rotateMatrix(cp, rot),
198
+ boundary: _circleBoundary,
199
+ boundaryVersion: 0
200
+ });
201
+ break;
202
+ }
203
+ continue; // skip vertical planes if not requested
204
+ }
205
+ if (poseInCamera) {
206
+ plane_anchors.push({
207
+ id: "plane-" + plane_anchors.length,
208
+ horizontal: true,
209
+ status: anchor_status_t.ANCHOR_STATUS_TRACKING,
210
+ pose: rotateMatrix(poseInCamera.transform.matrix, rot),
211
+ boundary: _circleBoundary,
212
+ boundaryVersion: 0
213
+ });
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ const custom_anchors = [];
219
+ if (this._xrViewerSpace && frame.trackedAnchors) {
220
+ for (const [o, anchor] of this._customAnchors.entries()) {
221
+ const pose = frame.getPose(anchor.anchor.anchorSpace, this._xrViewerSpace);
222
+ if (!pose)
223
+ continue;
224
+ custom_anchors.push({
225
+ id: o,
226
+ status: frame.trackedAnchors.has(anchor.anchor) ? anchor_status_t.ANCHOR_STATUS_TRACKING : anchor_status_t.ANCHOR_STATUS_PAUSED,
227
+ pose: rotateMatrix((_e = pose === null || pose === void 0 ? void 0 : pose.transform) === null || _e === void 0 ? void 0 : _e.matrix, rot),
228
+ poseVersion: anchor.version
229
+ });
230
+ }
231
+ }
232
+ if (!localPose) {
233
+ if (!this._latestWtData)
234
+ return;
235
+ this._latestWtData = Object.assign(Object.assign({}, this._latestWtData), { world_anchor_status: anchor_status_t.ANCHOR_STATUS_PAUSED, ground_anchor_status: anchor_status_t.ANCHOR_STATUS_PAUSED, quality: world_tracker_quality_t.WORLD_TRACKER_QUALITY_LIMITED });
236
+ }
237
+ else {
238
+ const world_pose = rotateMatrix(localPose.transform.inverse.matrix, rot);
239
+ this._latestWtData = {
240
+ world_anchor_status: anchor_status_t.ANCHOR_STATUS_TRACKING,
241
+ world_anchor_pose: world_pose,
242
+ ground_anchor_pose: mat4.create(),
243
+ ground_anchor_status: anchor_status_t.ANCHOR_STATUS_INITIALIZING,
244
+ plane_anchors,
245
+ custom_anchors,
246
+ quality: world_tracker_quality_t.WORLD_TRACKER_QUALITY_GOOD,
247
+ };
248
+ }
249
+ };
250
+ this._onXREnd = (ev) => {
251
+ this._xrLocalSpace = null;
252
+ this._xrSession = null;
253
+ this._latestFrame = null;
254
+ this._latestWtData = null;
255
+ this._customAnchorSetRequests.clear();
256
+ this._customAnchors.clear();
257
+ this._planeHitTestSource = null;
258
+ if (this._isPaused)
259
+ return;
260
+ if (this._permissionRequestShown)
261
+ return;
262
+ this._permissionRequestShown = true;
263
+ permissionRequestUI({ ignoreUserActivation: true }).then(() => {
264
+ this._permissionRequestShown = false;
265
+ this._syncCamera();
266
+ });
267
+ };
268
+ this._hasStartedOrientation = false;
269
+ this._lastTimestamp = -1;
270
+ this._deviceMotionListener = (ev) => {
271
+ let pipeline = Pipeline.get(this._pipeline);
272
+ if (!pipeline)
273
+ return;
274
+ let timeStamp = (ev.timeStamp !== undefined && ev.timeStamp !== null) ? ev.timeStamp : performance.now();
275
+ let interval = ev.interval;
276
+ if (this._lastTimestamp > -1 && !profile.trustSensorIntervals) {
277
+ interval = Math.max(timeStamp - this._lastTimestamp, interval);
278
+ }
279
+ this._lastTimestamp = timeStamp;
280
+ interval *= profile.intervalMultiplier;
281
+ if (ev.acceleration !== null &&
282
+ ev.acceleration.x !== null &&
283
+ ev.acceleration.y !== null &&
284
+ ev.acceleration.z !== null) {
285
+ pipeline.motionAccelerometerWithoutGravitySubmitInt(timeStamp, interval, ev.acceleration.x * profile.deviceMotionMutliplier, ev.acceleration.y * profile.deviceMotionMutliplier, ev.acceleration.z * profile.deviceMotionMutliplier);
286
+ }
287
+ if (ev.accelerationIncludingGravity !== null &&
288
+ ev.accelerationIncludingGravity.x !== null &&
289
+ ev.accelerationIncludingGravity.y !== null &&
290
+ ev.accelerationIncludingGravity.z !== null) {
291
+ pipeline.motionAccelerometerSubmit(timeStamp, ev.accelerationIncludingGravity.x * profile.deviceMotionMutliplier, ev.accelerationIncludingGravity.y * profile.deviceMotionMutliplier, ev.accelerationIncludingGravity.z * profile.deviceMotionMutliplier);
292
+ pipeline.motionAccelerometerWithGravitySubmitInt(timeStamp, interval, ev.accelerationIncludingGravity.x * profile.deviceMotionMutliplier, ev.accelerationIncludingGravity.y * profile.deviceMotionMutliplier, ev.accelerationIncludingGravity.z * profile.deviceMotionMutliplier);
293
+ }
294
+ if (ev.rotationRate !== null &&
295
+ ev.rotationRate.alpha !== null &&
296
+ ev.rotationRate.beta !== null &&
297
+ ev.rotationRate.gamma !== null && this._hasStartedOrientation) {
298
+ pipeline.motionRotationRateSubmit(timeStamp, ev.rotationRate.alpha * Math.PI / -180.0, ev.rotationRate.beta * Math.PI / -180.0, ev.rotationRate.gamma * Math.PI / -180.0);
299
+ pipeline.motionRotationRateSubmitInt(timeStamp, interval, ev.rotationRate.alpha, ev.rotationRate.beta, ev.rotationRate.gamma);
300
+ }
301
+ else if (!this._hasStartedOrientation) {
302
+ this._startDeviceOrientation();
303
+ }
304
+ };
305
+ zcout("Using WebXR camera source");
306
+ let gl = this._offscreenCanvas.getContext('webgl', { xrCompatible: true });
307
+ if (!gl)
308
+ throw new Error("Couldn't get a webgl context from OffscreenCanvas");
309
+ this._offscreenContext = gl;
310
+ this._imageBlitGl = new ImageBlitGl(gl, false);
311
+ }
312
+ static IsSupported() {
313
+ // Core spec objects
314
+ if (!(navigator.xr && (XRSession === null || XRSession === void 0 ? void 0 : XRSession.prototype) && (XRFrame === null || XRFrame === void 0 ? void 0 : XRFrame.prototype)))
315
+ return false;
316
+ // Check required WebXR features
317
+ if (!(XRCamera === null || XRCamera === void 0 ? void 0 : XRCamera.prototype))
318
+ return false; // raw-camera-access
319
+ if (!('domOverlayState' in XRSession.prototype))
320
+ return false; // dom-overlay
321
+ if (!('requestHitTestSource' in XRSession.prototype))
322
+ return false; // hit-test
323
+ if (!('createAnchor' in XRFrame.prototype))
324
+ return false; // anchors
325
+ return true;
326
+ }
327
+ destroy() {
328
+ this.pause();
329
+ deleteCameraSource(this._impl);
330
+ }
331
+ setProfile(p) {
332
+ this._profile = p;
333
+ }
334
+ _stop() {
335
+ if (!this._xrSession)
336
+ return;
337
+ this._xrSession.end();
338
+ }
339
+ pause() {
340
+ this._isPaused = true;
341
+ let p = Pipeline.get(this._pipeline);
342
+ if (p && p.currentCameraSource === this)
343
+ p.currentCameraSource = undefined;
344
+ this._stopDeviceMotion();
345
+ this._syncCamera();
346
+ }
347
+ start() {
348
+ var _a;
349
+ let p = Pipeline.get(this._pipeline);
350
+ if (p && p.currentCameraSource !== this) {
351
+ (_a = p.currentCameraSource) === null || _a === void 0 ? void 0 : _a.pause();
352
+ p.currentCameraSource = this;
353
+ }
354
+ this._isPaused = false;
355
+ this._startDeviceMotion();
356
+ this._syncCamera();
357
+ }
358
+ optionsUpdated(options) {
359
+ this._wtOptions = options;
360
+ }
361
+ resetTracking() {
362
+ var _a;
363
+ (_a = this._xrSession) === null || _a === void 0 ? void 0 : _a.end();
364
+ // TODO (remove anchors, reset local space)
365
+ }
366
+ getFrame(currentlyProcessing) {
367
+ var _a, _b;
368
+ if (!this._latestFrame)
369
+ return;
370
+ if (currentlyProcessing)
371
+ return;
372
+ let currentTime = performance.now();
373
+ if (currentTime < (this._lastFrameTime + 25))
374
+ return;
375
+ this._lastFrameTime = currentTime;
376
+ const imageBitmap = this._latestFrame;
377
+ this._latestFrame = null;
378
+ let rotation = cameraRotationForScreenOrientation(false);
379
+ let pipeline = Pipeline.get(this._pipeline);
380
+ if (!pipeline)
381
+ return;
382
+ let isPortrait = (rotation == 90) || (rotation == 270);
383
+ let [dataWidth, dataHeight] = profile.getDataSize(this._profile);
384
+ let ibWidth = isPortrait ? imageBitmap.height : imageBitmap.width;
385
+ let ibHeight = isPortrait ? imageBitmap.width : imageBitmap.height;
386
+ let cropHeight = Math.round(dataWidth * ibHeight / ibWidth);
387
+ if (cropHeight < dataHeight) {
388
+ dataHeight = cropHeight;
389
+ }
390
+ else {
391
+ dataWidth = Math.round(dataHeight * ibWidth / ibHeight);
392
+ }
393
+ const rawX = isPortrait ? this._rawCameraModel[1] : this._rawCameraModel[0];
394
+ const rawY = isPortrait ? this._rawCameraModel[0] : this._rawCameraModel[1];
395
+ const rawU = isPortrait ? this._rawCameraModel[3] : this._rawCameraModel[2];
396
+ const rawV = isPortrait ? this._rawCameraModel[2] : this._rawCameraModel[3];
397
+ this._cameraModel[0] = 0.5 * rawX * dataWidth / rawU;
398
+ this._cameraModel[1] = 0.5 * rawY * dataHeight / rawV;
399
+ this._cameraModel[2] = dataWidth * 0.5;
400
+ this._cameraModel[3] = dataHeight * 0.5;
401
+ let token = pipeline.registerToken({
402
+ dataWidth: imageBitmap.width,
403
+ dataHeight: imageBitmap.height,
404
+ texture: undefined,
405
+ userFacing: false,
406
+ cameraSource: this,
407
+ cameraSourceData: { wtData: this._latestWtData },
408
+ cameraModel: this._cameraModel.slice(),
409
+ cameraToDevice: this._cameraToDeviceTransform
410
+ });
411
+ (_b = (_a = Pipeline.get(this._pipeline)) === null || _a === void 0 ? void 0 : _a.sendImageBitmapToWorker) === null || _b === void 0 ? void 0 : _b.call(_a, imageBitmap, rotation, false, token, this._cameraModel, this._cameraToDeviceTransform, this._profile);
412
+ return;
413
+ }
414
+ _syncCamera() {
415
+ var _a, _b, _c;
416
+ return __awaiter(this, void 0, void 0, function* () {
417
+ if (this._isPaused) {
418
+ if (this._xrSession)
419
+ this._stop();
420
+ return;
421
+ }
422
+ if (this._xrSession)
423
+ return;
424
+ let hasActivation = (_a = navigator.userActivation) === null || _a === void 0 ? void 0 : _a.isActive;
425
+ if (!hasActivation) {
426
+ if (this._permissionRequestShown)
427
+ return;
428
+ this._permissionRequestShown = true;
429
+ permissionRequestUI().then(() => {
430
+ this._permissionRequestShown = false;
431
+ this._syncCamera();
432
+ });
433
+ return;
434
+ }
435
+ if (navigator.xr) {
436
+ try {
437
+ const session = yield navigator.xr.requestSession('immersive-ar', { requiredFeatures: ['dom-overlay', 'camera-access', 'hit-test', 'anchors'], domOverlay: { root: document.documentElement } });
438
+ const refSpace = yield session.requestReferenceSpace('local');
439
+ this._xrViewerSpace = yield session.requestReferenceSpace('viewer');
440
+ this._xrWebGLLayer = new XRWebGLLayer(session, this._offscreenContext);
441
+ session.updateRenderState({ baseLayer: this._xrWebGLLayer });
442
+ session.addEventListener('end', this._onXREnd);
443
+ session.requestAnimationFrame(this._onXRFrame);
444
+ this.sessionNumber++;
445
+ this._xrSession = session;
446
+ this._xrLocalSpace = refSpace;
447
+ this._xrGlBinding = new XRWebGLBinding(session, this._offscreenContext);
448
+ (_c = (_b = session.requestHitTestSource) === null || _b === void 0 ? void 0 : _b.call(session, {
449
+ space: this._xrViewerSpace,
450
+ entityTypes: ['plane']
451
+ })) === null || _c === void 0 ? void 0 : _c.then((hitTestSource) => {
452
+ this._planeHitTestSource = hitTestSource;
453
+ });
454
+ }
455
+ catch (ex) {
456
+ console.log('Exception starting immersive-ar session');
457
+ }
458
+ }
459
+ });
460
+ }
461
+ _startDeviceOrientation() {
462
+ if (this._hasStartedOrientation)
463
+ return;
464
+ this._hasStartedOrientation = true;
465
+ window.addEventListener("deviceorientation", (ev) => {
466
+ let pipeline = Pipeline.get(this._pipeline);
467
+ if (!pipeline)
468
+ return;
469
+ let timeStamp = (ev.timeStamp !== undefined && ev.timeStamp !== null) ? ev.timeStamp : performance.now();
470
+ if (ev.alpha === null || ev.beta === null || ev.gamma === null)
471
+ return;
472
+ // pipeline.motionAttitudeSubmit(timeStamp, ev.alpha, ev.beta, ev.gamma);
473
+ pipeline.motionAttitudeSubmitInt(timeStamp, 0, ev.alpha, ev.beta, ev.gamma);
474
+ });
475
+ }
476
+ _startDeviceMotion() {
477
+ window.addEventListener("devicemotion", this._deviceMotionListener, false);
478
+ }
479
+ _stopDeviceMotion() {
480
+ window.removeEventListener("devicemotion", this._deviceMotionListener);
481
+ }
482
+ uploadGL(info) {
483
+ const pipeline = Pipeline.get(this._pipeline);
484
+ const gl = pipeline === null || pipeline === void 0 ? void 0 : pipeline.glContext;
485
+ if (!info ||
486
+ info.texture ||
487
+ !info.frame ||
488
+ !pipeline ||
489
+ !gl)
490
+ return;
491
+ let texture = pipeline.getVideoTexture();
492
+ if (!texture)
493
+ return;
494
+ gl.bindTexture(gl.TEXTURE_2D, texture);
495
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
496
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, info.frame);
497
+ gl.bindTexture(gl.TEXTURE_2D, null);
498
+ info.texture = texture;
499
+ }
500
+ setCustomAnchorPose(o, version, pose) {
501
+ return __awaiter(this, void 0, void 0, function* () {
502
+ this._customAnchorSetRequests.set(o, { version, pose: pose.slice(), delay: 3 });
503
+ });
504
+ }
505
+ deleteCustomAnchor(o) {
506
+ var _a;
507
+ return __awaiter(this, void 0, void 0, function* () {
508
+ (_a = this._customAnchors.get(o)) === null || _a === void 0 ? void 0 : _a.anchor.delete();
509
+ });
510
+ }
511
+ _updateCameraModel(camView, viewport) {
512
+ const p = camView.projectionMatrix;
513
+ const u0 = (1 - p[8]) * viewport.width / 2 + viewport.x;
514
+ const v0 = (1 - p[9]) * viewport.height / 2 + viewport.y;
515
+ // Focal lengths in pixels (these are equal for square pixels)
516
+ const ax = viewport.width / 2 * p[0];
517
+ const ay = viewport.height / 2 * p[5];
518
+ this._rawCameraModel[0] = ax;
519
+ this._rawCameraModel[1] = ay;
520
+ // Principal point in pixels
521
+ this._rawCameraModel[2] = u0;
522
+ this._rawCameraModel[3] = v0;
523
+ }
524
+ _isPlaneVertical(pose) {
525
+ _quat[0] = pose.transform.orientation.x;
526
+ _quat[1] = pose.transform.orientation.y;
527
+ _quat[2] = pose.transform.orientation.z;
528
+ _quat[3] = pose.transform.orientation.w;
529
+ _up[0] = 0;
530
+ _up[1] = 1;
531
+ _up[2] = 0;
532
+ vec3.transformQuat(_up, _up, _quat);
533
+ if (Math.abs(_up[1]) < 0.5)
534
+ return true;
535
+ return false;
536
+ }
537
+ }
@@ -0,0 +1,19 @@
1
+ import { Zappar } from ".";
2
+ import { Pipeline } from "./pipeline";
3
+ import { WebXRWTOptions } from "./webxr-camera-source";
4
+ export declare class WebXRWorldTracker {
5
+ private static _sharedInstance;
6
+ static SharedInstance(): WebXRWorldTracker;
7
+ private _latestId;
8
+ private _wtStateById;
9
+ private _anchorStateById;
10
+ private _identityPose;
11
+ private _emptyArray;
12
+ private _getWtState;
13
+ private _getAnchorState;
14
+ private _getWtDataFromPipeline;
15
+ private _getWtData;
16
+ private _notifyOptionsUpdated;
17
+ getCombinedOptionsForPipeline(p: Pipeline): WebXRWTOptions;
18
+ impl: Partial<Zappar>;
19
+ }