@zappar/zappar-cv 3.9.2 → 3.11.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.
Files changed (47) hide show
  1. package/README.md +2 -2
  2. package/lib/bridged-camera-source.d.ts +1 -0
  3. package/lib/bridged-camera-source.js +8 -0
  4. package/lib/bridged-d3-tracker.js +2 -26
  5. package/lib/camera-source.d.ts +3 -0
  6. package/lib/camera-source.js +8 -2
  7. package/lib/drawpoints.js +30 -38
  8. package/lib/gen/zappar-bridge.d.ts +12 -0
  9. package/lib/gen/zappar-client.js +173 -5
  10. package/lib/gen/zappar-cwrap.js +115 -0
  11. package/lib/gen/zappar-native.d.ts +14 -1
  12. package/lib/gen/zappar-native.js +1 -0
  13. package/lib/gen/zappar-server.js +75 -0
  14. package/lib/gen/zappar.d.ts +9 -8
  15. package/lib/html-element-source.d.ts +1 -0
  16. package/lib/html-element-source.js +4 -3
  17. package/lib/image-process-gl.d.ts +4 -5
  18. package/lib/image-process-gl.js +14 -25
  19. package/lib/imagebitmap-camera-source.d.ts +3 -0
  20. package/lib/imagebitmap-camera-source.js +12 -5
  21. package/lib/mstp-camera-source.d.ts +3 -0
  22. package/lib/mstp-camera-source.js +8 -2
  23. package/lib/native.js +39 -19
  24. package/lib/profile.d.ts +2 -1
  25. package/lib/profile.js +33 -2
  26. package/lib/sequencesource.js +2 -2
  27. package/lib/src/bridged-camera-source.d.ts +1 -0
  28. package/lib/src/camera-source.d.ts +3 -0
  29. package/lib/src/gen/zappar-bridge.d.ts +12 -0
  30. package/lib/src/gen/zappar-native.d.ts +14 -1
  31. package/lib/src/gen/zappar.d.ts +9 -8
  32. package/lib/src/html-element-source.d.ts +1 -0
  33. package/lib/src/image-process-gl.d.ts +4 -5
  34. package/lib/src/imagebitmap-camera-source.d.ts +3 -0
  35. package/lib/src/mstp-camera-source.d.ts +3 -0
  36. package/lib/src/profile.d.ts +2 -1
  37. package/lib/src/version.d.ts +1 -1
  38. package/lib/src/webxr-camera-source.d.ts +5 -0
  39. package/lib/tests/common.d.ts +3 -1
  40. package/lib/version.d.ts +1 -1
  41. package/lib/version.js +1 -1
  42. package/lib/webxr-camera-source.d.ts +5 -0
  43. package/lib/webxr-camera-source.js +67 -35
  44. package/lib/worker-imagebitmap.js +2 -14
  45. package/lib/zappar-cv.js +1 -1
  46. package/lib/zappar-cv.wasm +0 -0
  47. package/package.json +1 -1
@@ -85,7 +85,8 @@ export declare enum plane_orientation_t {
85
85
  }
86
86
  export declare enum camera_profile_t {
87
87
  DEFAULT = 0,
88
- HIGH = 1
88
+ HIGH = 1,
89
+ FULL = 2
89
90
  }
90
91
  export declare enum world_scale_mode_t {
91
92
  DEFAULT = 0,
@@ -263,4 +264,16 @@ export interface zappar_cwrap {
263
264
  custom_anchor_pose_set_with_parent(o: zappar_custom_anchor_t, pose: Float32Array, anchor_id: string): void;
264
265
  d3_tracker_create(pipeline: zappar_pipeline_t): zappar_d3_tracker_t;
265
266
  d3_tracker_destroy(o: zappar_d3_tracker_t): void;
267
+ d3_tracker_enabled(o: zappar_d3_tracker_t): boolean;
268
+ d3_tracker_enabled_set(o: zappar_d3_tracker_t, enabled: boolean): void;
269
+ d3_tracker_count(o: zappar_d3_tracker_t): number;
270
+ d3_tracker_id(o: zappar_d3_tracker_t, indx: number): string;
271
+ d3_tracker_pose0_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
272
+ d3_tracker_pose1_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
273
+ d3_tracker_type(o: zappar_d3_tracker_t, indx: number): number;
274
+ d3_tracker_category(o: zappar_d3_tracker_t, indx: number): number;
275
+ d3_tracker_qr(o: zappar_d3_tracker_t, indx: number): string;
276
+ d3_tracker_dense(o: zappar_d3_tracker_t, indx: number): number;
277
+ d3_tracker_landmarks_data(o: zappar_d3_tracker_t, indx: number): Float32Array;
278
+ d3_tracker_landmarks_data_size(o: zappar_d3_tracker_t, indx: number): number;
266
279
  }
@@ -125,6 +125,7 @@ export interface zappar {
125
125
  camera_source_start(o: zappar_camera_source_t): void;
126
126
  camera_source_pause(o: zappar_camera_source_t): void;
127
127
  camera_source_profile_set(o: zappar_camera_source_t, profile: camera_profile_t): void;
128
+ camera_source_preferred_resolution_set(o: zappar_camera_source_t, width: number, height: number): void;
128
129
  sequence_source_create(pipeline: zappar_pipeline_t): zappar_sequence_source_t;
129
130
  sequence_source_destroy(o: zappar_sequence_source_t): void;
130
131
  sequence_source_start(o: zappar_sequence_source_t): void;
@@ -295,25 +296,25 @@ export interface zappar {
295
296
  custom_anchor_pose_set_with_parent(o: zappar_custom_anchor_t, pose: Float32Array, anchor_id: string): void;
296
297
  d3_tracker_create(pipeline: zappar_pipeline_t): zappar_d3_tracker_t;
297
298
  d3_tracker_destroy(o: zappar_d3_tracker_t): void;
298
- d3_tracker_id(o: zappar_d3_tracker_t, indx: number): string;
299
299
  d3_tracker_enabled(o: zappar_d3_tracker_t): boolean;
300
300
  d3_tracker_enabled_set(o: zappar_d3_tracker_t, enabled: boolean): void;
301
301
  d3_tracker_process_max_resolution_set(o: zappar_d3_tracker_t, v: boolean): void;
302
302
  d3_tracker_count(o: zappar_d3_tracker_t): number;
303
- d3_tracker_qr(o: zappar_d3_tracker_t, indx: number): string;
304
- d3_tracker_pose_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
305
- d3_tracker_pose_camera_relative(o: zappar_d3_tracker_t, indx: number, mirror: boolean): Float32Array;
306
- d3_tracker_pose(o: zappar_d3_tracker_t, indx: number, camera_pose: Float32Array, mirror: boolean): Float32Array;
303
+ d3_tracker_id(o: zappar_d3_tracker_t, indx: number): string;
307
304
  d3_tracker_pose0_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
308
305
  d3_tracker_pose0_camera_relative(o: zappar_d3_tracker_t, indx: number, mirror: boolean): Float32Array;
309
306
  d3_tracker_pose0(o: zappar_d3_tracker_t, indx: number, camera_pose: Float32Array, mirror: boolean): Float32Array;
310
307
  d3_tracker_pose1_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
311
308
  d3_tracker_pose1_camera_relative(o: zappar_d3_tracker_t, indx: number, mirror: boolean): Float32Array;
312
309
  d3_tracker_pose1(o: zappar_d3_tracker_t, indx: number, camera_pose: Float32Array, mirror: boolean): Float32Array;
313
- d3_tracker_landmarks_data(o: zappar_d3_tracker_t, indx: number): Float32Array;
314
- d3_tracker_landmarks_data_size(o: zappar_d3_tracker_t, indx: number): number;
315
310
  d3_tracker_type(o: zappar_d3_tracker_t, indx: number): number;
316
- d3_tracker_dense(o: zappar_d3_tracker_t, indx: number): number;
317
311
  d3_tracker_category(o: zappar_d3_tracker_t, indx: number): number;
312
+ d3_tracker_qr(o: zappar_d3_tracker_t, indx: number): string;
313
+ d3_tracker_dense(o: zappar_d3_tracker_t, indx: number): number;
314
+ d3_tracker_landmarks_data(o: zappar_d3_tracker_t, indx: number): Float32Array;
315
+ d3_tracker_landmarks_data_size(o: zappar_d3_tracker_t, indx: number): number;
316
+ d3_tracker_pose_raw(o: zappar_d3_tracker_t, indx: number): Float32Array;
317
+ d3_tracker_pose_camera_relative(o: zappar_d3_tracker_t, indx: number, mirror: boolean): Float32Array;
318
+ d3_tracker_pose(o: zappar_d3_tracker_t, indx: number, camera_pose: Float32Array, mirror: boolean): Float32Array;
318
319
  d3_tracker_size_for_id_set(o: zappar_d3_tracker_t, id: string, size: number): void;
319
320
  }
@@ -10,6 +10,7 @@ export declare class HTMLElementSource extends Source {
10
10
  protected _cameraToScreenRotation: number;
11
11
  private _isUploadFrame;
12
12
  private _currentVideoTexture;
13
+ private _currentDataSize;
13
14
  private _imageProcessor;
14
15
  private _cameraToDeviceTransform;
15
16
  private _cameraToDeviceTransformUserFacing;
@@ -1,7 +1,6 @@
1
1
  import { camera_profile_t } from "./gen/zappar-native";
2
2
  export interface ProcessedFrame {
3
3
  data?: ArrayBuffer;
4
- texture: WebGLTexture | undefined;
5
4
  dataWidth: number;
6
5
  dataHeight: number;
7
6
  uvTransform?: Float32Array;
@@ -17,6 +16,7 @@ export declare class ImageProcessGL {
17
16
  private _computedTransformRotation;
18
17
  private _computedFrontCameraRotation;
19
18
  private _cameraUvTransform;
19
+ private _dataSize;
20
20
  private _framebufferWidth;
21
21
  private _framebufferHeight;
22
22
  private _framebufferId;
@@ -29,10 +29,9 @@ export declare class ImageProcessGL {
29
29
  constructor(_gl: WebGL2RenderingContext | WebGLRenderingContext);
30
30
  resetGLContext(): void;
31
31
  destroy(): void;
32
- uploadFrame(texture: WebGLTexture, img: HTMLVideoElement | HTMLImageElement | ImageBitmap, rotation: number, fc: boolean, cp: camera_profile_t): void;
33
- uploadFrameForSize(texture: WebGLTexture, img: HTMLVideoElement | HTMLImageElement | ImageBitmap, rotation: number, fc: boolean, dataWidth: number, dataHeight: number): void;
34
- readFrame(texture: WebGLTexture, pixels: ArrayBuffer, cp: camera_profile_t): ProcessedFrame;
35
- readFrameForSize(texture: WebGLTexture, pixels: ArrayBuffer, dataWidth: number, dataHeight: number): ProcessedFrame;
32
+ uploadFrame(texture: WebGLTexture, img: HTMLVideoElement | HTMLImageElement | ImageBitmap, rotation: number, fc: boolean, cp: camera_profile_t): [number, number];
33
+ uploadFrameForSize(texture: WebGLTexture, img: HTMLVideoElement | HTMLImageElement | ImageBitmap | null, rotation: number, fc: boolean, dataWidth: number, dataHeight: number): void;
34
+ readFrame(pixels: ArrayBuffer): ProcessedFrame;
36
35
  private _updateTransforms;
37
36
  private _getCameraUvTransform;
38
37
  private _getFramebuffer;
@@ -8,6 +8,8 @@ export declare class ImageBitmapCameraSource extends Source {
8
8
  static DEFAULT_DEVICE_ID: string;
9
9
  private _currentStream;
10
10
  private _activeDeviceId;
11
+ private _preferredWidth;
12
+ private _preferredHeight;
11
13
  private _isPaused;
12
14
  private _isUserFacing;
13
15
  private _hadFrames;
@@ -22,6 +24,7 @@ export declare class ImageBitmapCameraSource extends Source {
22
24
  constructor(_impl: zappar_camera_source_t, _pipeline: zappar_pipeline_t, _deviceId: string);
23
25
  destroy(): void;
24
26
  setProfile(p: camera_profile_t): void;
27
+ setPreferredResolution(w: number, h: number): void;
25
28
  private _stop;
26
29
  pause(): void;
27
30
  start(): void;
@@ -8,6 +8,8 @@ export declare class MSTPCameraSource extends Source {
8
8
  static DEFAULT_DEVICE_ID: string;
9
9
  private _currentStream;
10
10
  private _activeDeviceId;
11
+ private _preferredWidth;
12
+ private _preferredHeight;
11
13
  private _isPaused;
12
14
  private _isUserFacing;
13
15
  private _cameraToScreenRotation;
@@ -20,6 +22,7 @@ export declare class MSTPCameraSource extends Source {
20
22
  private _stop;
21
23
  pause(): void;
22
24
  start(): void;
25
+ setPreferredResolution(w: number, h: number): void;
23
26
  private _getConstraints;
24
27
  getFrame(allowRead: boolean): void;
25
28
  private _getUserMedia;
@@ -11,7 +11,6 @@ export declare let profile: {
11
11
  requestHighFrameRate: boolean;
12
12
  videoWidth: number;
13
13
  videoHeight: number;
14
- getDataSize: (p: camera_profile_t) => number[];
15
14
  videoElementInDOM: boolean;
16
15
  preferMediaStreamTrackProcessorCamera: boolean;
17
16
  preferImageBitmapCamera: boolean;
@@ -22,3 +21,5 @@ export declare let profile: {
22
21
  trustSensorIntervals: boolean;
23
22
  offscreenCanvasSupported: boolean;
24
23
  };
24
+ export declare function getDataSize(p: camera_profile_t, fullWidth: number, fullHeight: number): [number, number];
25
+ export declare function getDataSizeForSource(p: camera_profile_t, source: HTMLVideoElement | HTMLImageElement | ImageBitmap, rotation?: number): [number, number];
@@ -1 +1 @@
1
- export declare const VERSION = "3.9.2";
1
+ export declare const VERSION = "3.11.0";
@@ -47,7 +47,11 @@ export declare class WebXRCameraSource extends Source {
47
47
  private _cameraToDeviceTransform;
48
48
  private _cameraModel;
49
49
  private _rawCameraModel;
50
+ private _rawCameraWidth;
51
+ private _rawCameraHeight;
50
52
  private _profile;
53
+ private _preferredWidth;
54
+ private _preferredHeight;
51
55
  private _permissionRequestShown;
52
56
  private _planeHitTestSource;
53
57
  private _customAnchorSetRequests;
@@ -57,6 +61,7 @@ export declare class WebXRCameraSource extends Source {
57
61
  constructor(_impl: zappar_camera_source_t, _pipeline: zappar_pipeline_t);
58
62
  destroy(): void;
59
63
  setProfile(p: camera_profile_t): void;
64
+ setPreferredResolution(w: number, h: number): void;
60
65
  private _stop;
61
66
  pause(): void;
62
67
  start(): void;
@@ -1,9 +1,11 @@
1
- import { Zappar, zappar_pipeline_t } from "../src";
1
+ import { Zappar, zappar_pipeline_t, zappar_camera_source_t } from "../src";
2
2
  import { zappar_sequence_source_t } from "../src/gen/zappar";
3
3
  import { Event1 } from "../src/event";
4
4
  export declare let canvas: HTMLCanvasElement;
5
5
  export declare let mirrorPoses: boolean;
6
6
  export declare let pipeline: zappar_pipeline_t;
7
+ export declare let rearSource: zappar_camera_source_t;
8
+ export declare let frontSource: zappar_camera_source_t;
7
9
  export declare let onSequenceLoaded: Event1<zappar_sequence_source_t>;
8
10
  export declare function setup(webgl2?: boolean): Zappar;
9
11
  export declare function currentPoseSetting(): PoseSetting;
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "3.9.2";
1
+ export declare const VERSION = "3.11.0";
package/lib/version.js CHANGED
@@ -1 +1 @@
1
- export const VERSION = "3.9.2";
1
+ export const VERSION = "3.11.0";
@@ -47,7 +47,11 @@ export declare class WebXRCameraSource extends Source {
47
47
  private _cameraToDeviceTransform;
48
48
  private _cameraModel;
49
49
  private _rawCameraModel;
50
+ private _rawCameraWidth;
51
+ private _rawCameraHeight;
50
52
  private _profile;
53
+ private _preferredWidth;
54
+ private _preferredHeight;
51
55
  private _permissionRequestShown;
52
56
  private _planeHitTestSource;
53
57
  private _customAnchorSetRequests;
@@ -57,6 +61,7 @@ export declare class WebXRCameraSource extends Source {
57
61
  constructor(_impl: zappar_camera_source_t, _pipeline: zappar_pipeline_t);
58
62
  destroy(): void;
59
63
  setProfile(p: camera_profile_t): void;
64
+ setPreferredResolution(w: number, h: number): void;
60
65
  private _stop;
61
66
  pause(): void;
62
67
  start(): void;
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { anchor_status_t, world_tracker_quality_t, camera_profile_t } from "./gen/zappar";
11
- import { profile } from "./profile";
11
+ import { profile, getDataSizeForSource } from "./profile";
12
12
  import { Pipeline } from "./pipeline";
13
13
  import { Source } from "./source";
14
14
  import { cameraRotationForScreenOrientation } from "./cameramodel";
@@ -50,13 +50,17 @@ export class WebXRCameraSource extends Source {
50
50
  this._cameraToDeviceTransform = mat4.create();
51
51
  this._cameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
52
52
  this._rawCameraModel = new Float32Array([300, 300, 160, 120, 0, 0]);
53
+ this._rawCameraWidth = 320;
54
+ this._rawCameraHeight = 240;
53
55
  this._profile = camera_profile_t.DEFAULT;
56
+ this._preferredWidth = profile.videoWidth;
57
+ this._preferredHeight = profile.videoHeight;
54
58
  this._permissionRequestShown = false;
55
59
  this._planeHitTestSource = null;
56
60
  this._customAnchorSetRequests = new Map();
57
61
  this._customAnchors = new Map();
58
62
  this._onXRFrame = (time, frame) => {
59
- var _a, _b, _c, _d, _e, _f;
63
+ var _a, _b, _c, _d, _e;
60
64
  if (this._isPaused)
61
65
  return;
62
66
  (_a = this._xrSession) === null || _a === void 0 ? void 0 : _a.requestAnimationFrame(this._onXRFrame);
@@ -80,16 +84,19 @@ export class WebXRCameraSource extends Source {
80
84
  }
81
85
  if (!texture)
82
86
  return;
83
- const viewport = (_b = this._xrWebGLLayer) === null || _b === void 0 ? void 0 : _b.getViewport(camView);
84
- this._updateCameraModel(camView, viewport);
87
+ this._updateCameraModel(camView, camera);
85
88
  const localPose = frame.getViewerPose(this._xrLocalSpace);
89
+ let rot = cameraRotationForScreenOrientation(false);
90
+ let isPortrait = (rot == 90) || (rot == 270);
86
91
  const gl = this._offscreenContext;
87
92
  let blitWidth = camera.width;
88
93
  let blitHeight = camera.height;
89
- let blitMax = Math.max(blitWidth, blitHeight);
90
- if (blitMax > 1280) {
91
- blitWidth = Math.round(1280 * blitWidth / blitMax);
92
- blitHeight = Math.round(1280 * blitHeight / blitMax);
94
+ let prefWidth = isPortrait ? this._preferredHeight : this._preferredWidth;
95
+ let prefHeight = isPortrait ? this._preferredWidth : this._preferredHeight;
96
+ let scale = Math.min(prefWidth / blitWidth, prefHeight / blitHeight);
97
+ if (scale < 1) {
98
+ blitWidth = Math.round(scale * blitWidth);
99
+ blitHeight = Math.round(scale * blitHeight);
93
100
  }
94
101
  if (blitWidth != this._offscreenCanvas.width || blitHeight != this._offscreenCanvas.height) {
95
102
  this._offscreenCanvas.width = blitWidth;
@@ -103,7 +110,6 @@ export class WebXRCameraSource extends Source {
103
110
  if (this._latestFrame)
104
111
  this._latestFrame.close();
105
112
  this._latestFrame = this._offscreenCanvas.transferToImageBitmap();
106
- let rot = cameraRotationForScreenOrientation(false);
107
113
  const rotateMatrix = (m, rot) => {
108
114
  let ret = m.slice();
109
115
  if (rot === 90) {
@@ -147,7 +153,7 @@ export class WebXRCameraSource extends Source {
147
153
  mat4.getRotation(_quat, req.pose);
148
154
  mat4.getTranslation(_trans, req.pose);
149
155
  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] });
150
- (_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 => {
156
+ (_c = (_b = frame.createAnchor) === null || _b === void 0 ? void 0 : _b.call(frame, rigid, this._xrLocalSpace)) === null || _c === void 0 ? void 0 : _c.then(anchor => {
151
157
  const existing = this._customAnchors.get(customAnchor);
152
158
  if (existing)
153
159
  existing.anchor.delete();
@@ -235,7 +241,7 @@ export class WebXRCameraSource extends Source {
235
241
  custom_anchors.push({
236
242
  id: o,
237
243
  status: frame.trackedAnchors.has(anchor.anchor) ? anchor_status_t.ANCHOR_STATUS_TRACKING : anchor_status_t.ANCHOR_STATUS_PAUSED,
238
- pose: rotateMatrix((_e = pose === null || pose === void 0 ? void 0 : pose.transform) === null || _e === void 0 ? void 0 : _e.matrix, rot),
244
+ pose: rotateMatrix((_d = pose === null || pose === void 0 ? void 0 : pose.transform) === null || _d === void 0 ? void 0 : _d.matrix, rot),
239
245
  poseVersion: anchor.version
240
246
  });
241
247
  }
@@ -248,7 +254,7 @@ export class WebXRCameraSource extends Source {
248
254
  else {
249
255
  const world_pose = rotateMatrix(localPose.transform.inverse.matrix, rot);
250
256
  let ground_pose = mat4.create();
251
- mat4.fromTranslation(_ground, [0, (_f = this._groundH) !== null && _f !== void 0 ? _f : -1.5, 0]);
257
+ mat4.fromTranslation(_ground, [0, (_e = this._groundH) !== null && _e !== void 0 ? _e : -1.5, 0]);
252
258
  mat4.multiply(ground_pose, localPose.transform.inverse.matrix, _ground);
253
259
  ground_pose = rotateMatrix(ground_pose, rot);
254
260
  this._latestWtData = {
@@ -353,6 +359,10 @@ export class WebXRCameraSource extends Source {
353
359
  setProfile(p) {
354
360
  this._profile = p;
355
361
  }
362
+ setPreferredResolution(w, h) {
363
+ this._preferredWidth = w;
364
+ this._preferredHeight = h;
365
+ }
356
366
  _stop() {
357
367
  if (!this._xrSession)
358
368
  return;
@@ -401,25 +411,37 @@ export class WebXRCameraSource extends Source {
401
411
  let pipeline = Pipeline.get(this._pipeline);
402
412
  if (!pipeline)
403
413
  return;
404
- let isPortrait = (rotation == 90) || (rotation == 270);
405
- let [dataWidth, dataHeight] = profile.getDataSize(this._profile);
406
- let ibWidth = isPortrait ? imageBitmap.height : imageBitmap.width;
407
- let ibHeight = isPortrait ? imageBitmap.width : imageBitmap.height;
408
- let cropHeight = Math.round(dataWidth * ibHeight / ibWidth);
409
- if (cropHeight < dataHeight) {
410
- dataHeight = cropHeight;
414
+ let [dataWidth, dataHeight] = getDataSizeForSource(this._profile, imageBitmap, rotation);
415
+ // Calculate the raw camera model after rotation to primary landscape for zcv
416
+ const isPortrait = (rotation == 90) || (rotation == 270);
417
+ const rawWidth = isPortrait ? this._rawCameraHeight : this._rawCameraWidth;
418
+ const rawHeight = isPortrait ? this._rawCameraWidth : this._rawCameraHeight;
419
+ this._cameraModel[0] = isPortrait ? this._rawCameraModel[1] : this._rawCameraModel[0];
420
+ this._cameraModel[1] = isPortrait ? this._rawCameraModel[0] : this._rawCameraModel[1];
421
+ if (rotation === 90) {
422
+ this._cameraModel[2] = rawWidth - this._rawCameraModel[3];
423
+ this._cameraModel[3] = this._rawCameraModel[2];
424
+ }
425
+ else if (rotation === 180) {
426
+ this._cameraModel[2] = rawWidth - this._rawCameraModel[2];
427
+ this._cameraModel[3] = rawHeight - this._rawCameraModel[3];
428
+ }
429
+ else if (rotation === 270) {
430
+ this._cameraModel[2] = this._rawCameraModel[3];
431
+ this._cameraModel[3] = rawHeight - this._rawCameraModel[2];
411
432
  }
412
433
  else {
413
- dataWidth = Math.round(dataHeight * ibWidth / ibHeight);
434
+ this._cameraModel[2] = this._rawCameraModel[2];
435
+ this._cameraModel[3] = this._rawCameraModel[3];
414
436
  }
415
- const rawX = isPortrait ? this._rawCameraModel[1] : this._rawCameraModel[0];
416
- const rawY = isPortrait ? this._rawCameraModel[0] : this._rawCameraModel[1];
417
- const rawU = isPortrait ? this._rawCameraModel[3] : this._rawCameraModel[2];
418
- const rawV = isPortrait ? this._rawCameraModel[2] : this._rawCameraModel[3];
419
- this._cameraModel[0] = 0.5 * rawX * dataWidth / rawU;
420
- this._cameraModel[1] = 0.5 * rawY * dataHeight / rawV;
421
- this._cameraModel[2] = dataWidth * 0.5;
422
- this._cameraModel[3] = dataHeight * 0.5;
437
+ // Apply the scaling to "data" pixels rather than "raw" pixels
438
+ this._cameraModel[0] *= (dataWidth / rawWidth);
439
+ this._cameraModel[1] *= (dataHeight / rawHeight);
440
+ this._cameraModel[2] *= (dataWidth / rawWidth);
441
+ this._cameraModel[3] *= (dataHeight / rawHeight);
442
+ // Offset for pixel-centered coords assumption in zcv
443
+ this._cameraModel[2] -= 0.5;
444
+ this._cameraModel[3] -= 0.5;
423
445
  let token = pipeline.registerToken({
424
446
  dataWidth: imageBitmap.width,
425
447
  dataHeight: imageBitmap.height,
@@ -516,10 +538,11 @@ export class WebXRCameraSource extends Source {
516
538
  let texture = pipeline.getVideoTexture();
517
539
  if (!texture)
518
540
  return;
541
+ const previousBoundTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
519
542
  gl.bindTexture(gl.TEXTURE_2D, texture);
520
543
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
521
544
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, info.frame);
522
- gl.bindTexture(gl.TEXTURE_2D, null);
545
+ gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture);
523
546
  info.texture = texture;
524
547
  }
525
548
  setCustomAnchorPose(o, version, pose) {
@@ -533,18 +556,27 @@ export class WebXRCameraSource extends Source {
533
556
  (_a = this._customAnchors.get(o)) === null || _a === void 0 ? void 0 : _a.anchor.delete();
534
557
  });
535
558
  }
536
- _updateCameraModel(camView, viewport) {
559
+ _updateCameraModel(camView, camera) {
537
560
  const p = camView.projectionMatrix;
538
- const u0 = (1 - p[8]) * viewport.width / 2 + viewport.x;
539
- const v0 = (1 - p[9]) * viewport.height / 2 + viewport.y;
561
+ // Principal points
562
+ // NB: The v0 expression is different from that given (as of 2026-01-16) in
563
+ // https://github.com/immersive-web/raw-camera-access/blob/main/explainer.md
564
+ // Simon re-derived the expressions considering v0 was measured from the top
565
+ // of the image. So the sign change vs the expression for u0 is expected.
566
+ // Chrome incorrectly always returns projection matrices centered on the
567
+ // viewport, with p[8] and p[9] zero, but this will make a difference if that
568
+ // gets fixed.
569
+ const u0 = (1 - p[8]) * camera.width / 2;
570
+ const v0 = (1 + p[9]) * camera.height / 2;
540
571
  // Focal lengths in pixels (these are equal for square pixels)
541
- const ax = viewport.width / 2 * p[0];
542
- const ay = viewport.height / 2 * p[5];
572
+ const ax = camera.width / 2 * p[0];
573
+ const ay = camera.height / 2 * p[5];
543
574
  this._rawCameraModel[0] = ax;
544
575
  this._rawCameraModel[1] = ay;
545
- // Principal point in pixels
546
576
  this._rawCameraModel[2] = u0;
547
577
  this._rawCameraModel[3] = v0;
578
+ this._rawCameraWidth = camera.width;
579
+ this._rawCameraHeight = camera.height;
548
580
  }
549
581
  _isPlaneVertical(pose) {
550
582
  _quat[0] = pose.transform.orientation.x;
@@ -1,5 +1,4 @@
1
1
  import { ImageProcessGL } from "./image-process-gl";
2
- import { profile } from "./profile";
3
2
  import { mat4 } from "gl-matrix";
4
3
  let pixels;
5
4
  let texture;
@@ -34,23 +33,12 @@ export function handleImageBitmap(m, r, server, mgr) {
34
33
  }
35
34
  if (!texture)
36
35
  return;
37
- let [dataWidth, dataHeight] = profile.getDataSize(m.cp);
38
- let isPortrait = (m.r == 90) || (m.r == 270);
39
- let ibWidth = isPortrait ? m.i.height : m.i.width;
40
- let ibHeight = isPortrait ? m.i.width : m.i.height;
41
- let cropHeight = Math.round(dataWidth * ibHeight / ibWidth);
42
- if (cropHeight < dataHeight) {
43
- dataHeight = cropHeight;
44
- }
45
- else {
46
- dataWidth = Math.round(dataHeight * ibWidth / ibHeight);
47
- }
36
+ let [dataWidth, dataHeight] = imageProcessor.uploadFrame(texture, m.i, m.r, m.userFacing, m.cp);
48
37
  if (!pixels || pixels.byteLength < dataWidth * dataHeight) {
49
38
  // console.log("Generating pixel buffer", profile.dataWidth * profile.dataHeight);
50
39
  pixels = new ArrayBuffer(dataWidth * dataHeight);
51
40
  }
52
- imageProcessor.uploadFrameForSize(texture, m.i, m.r, m.userFacing, dataWidth, dataHeight);
53
- let info = imageProcessor.readFrameForSize(texture, pixels, dataWidth, dataHeight);
41
+ let info = imageProcessor.readFrame(pixels);
54
42
  let msg = {
55
43
  t: "imageBitmapS2C",
56
44
  dataWidth: info.dataWidth,