@zappar/zappar-cv 0.3.14 → 0.3.17

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.17] - 2022-07-21
4
+
5
+ ### Fixed
6
+
7
+ - Preserve `TextureAttribDivisor`, `VertexAttribDivisor` and `STENCIL_TEST` WebGL state.
8
+
9
+ ## [0.3.16] - 2021-02-07
10
+
11
+ ### Fixed
12
+
13
+ - External WebGL state is preserved during `process_gl` calls
14
+
15
+ ## [0.3.15] - 2021-01-25
16
+
17
+ ### Fixed
18
+
19
+ - Issues on iPad Pro
20
+
3
21
  ## [0.3.14] - 2021-10-25
4
22
 
5
23
  ### Changed
package/README.md CHANGED
@@ -18,8 +18,8 @@ npm i @zappar/zappar-cv
18
18
 
19
19
  You can use our CDN from within your HTML:
20
20
  ```
21
- <script src="https://libs.zappar.com/zappar-cv/0.3.14/zappar-cv.js"></script>
21
+ <script src="https://libs.zappar.com/zappar-cv/0.3.17/zappar-cv.js"></script>
22
22
  ```
23
23
 
24
24
  Or you can download and host our standalone JavaScript bundle:
25
- [https://libs.zappar.com/zappar-cv/0.3.14/zappar-cv.zip](https://libs.zappar.com/zappar-cv/0.3.14/zappar-cv.zip)
25
+ [https://libs.zappar.com/zappar-cv/0.3.17/zappar-cv.zip](https://libs.zappar.com/zappar-cv/0.3.17/zappar-cv.zip)
@@ -0,0 +1,9 @@
1
+ export declare class GLStateManager {
2
+ private _gl;
3
+ static get(gl: WebGLRenderingContext): GLStateManager;
4
+ private _viewports;
5
+ private _underlyingViewport;
6
+ private constructor();
7
+ push(): void;
8
+ pop(): void;
9
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GLStateManager = void 0;
4
+ const managers = new Map();
5
+ class GLStateManager {
6
+ constructor(_gl) {
7
+ this._gl = _gl;
8
+ this._viewports = [];
9
+ this._underlyingViewport = this._gl.viewport;
10
+ this._viewports.push(this._gl.getParameter(this._gl.VIEWPORT));
11
+ this._gl.viewport = (x, y, width, height) => {
12
+ this._viewports[this._viewports.length - 1] = [x, y, width, height];
13
+ this._underlyingViewport.call(this._gl, x, y, width, height);
14
+ };
15
+ }
16
+ static get(gl) {
17
+ let existing = managers.get(gl);
18
+ if (!existing) {
19
+ existing = new GLStateManager(gl);
20
+ managers.set(gl, existing);
21
+ }
22
+ return existing;
23
+ }
24
+ push() {
25
+ this._viewports.push(this._viewports[this._viewports.length - 1]);
26
+ }
27
+ pop() {
28
+ const current = this._viewports.pop();
29
+ const prev = this._viewports[this._viewports.length - 1];
30
+ if (!current || current[0] !== prev[0] || current[1] !== prev[1] || current[2] !== prev[2] || current[3] !== prev[3]) {
31
+ this._underlyingViewport.call(this._gl, prev[0], prev[1], prev[2], prev[3]);
32
+ }
33
+ }
34
+ }
35
+ exports.GLStateManager = GLStateManager;
@@ -30,6 +30,8 @@ export declare class HTMLElementSource extends Source {
30
30
  start(): void;
31
31
  getFrame(currentlyProcessing: boolean): CameraFrameInfo | undefined;
32
32
  private _processFrame;
33
+ private _instancedArraysExtension;
34
+ private _instancedArraysExtensionSet;
33
35
  private _uploadFrame;
34
36
  private _readFrame;
35
37
  private _updateTransforms;
@@ -7,6 +7,7 @@ const profile_1 = require("./profile");
7
7
  const shader_1 = require("./shader");
8
8
  const gl_matrix_1 = require("gl-matrix");
9
9
  const loglevel_1 = require("./loglevel");
10
+ const gl_state_manager_1 = require("./gl-state-manager");
10
11
  let latest = 1;
11
12
  let byId = new Map();
12
13
  class HTMLElementSource extends source_1.Source {
@@ -27,6 +28,7 @@ class HTMLElementSource extends source_1.Source {
27
28
  this._framebufferHeight = 0;
28
29
  this._framebufferId = null;
29
30
  this._renderTexture = null;
31
+ this._instancedArraysExtensionSet = false;
30
32
  let video = this._video;
31
33
  if (this._video instanceof HTMLVideoElement) {
32
34
  video.addEventListener("loadedmetadata", () => { this._hadFrames = true; });
@@ -55,6 +57,7 @@ class HTMLElementSource extends source_1.Source {
55
57
  this._vertexBuffer = undefined;
56
58
  this._indexBuffer = undefined;
57
59
  this._greyscaleShader = undefined;
60
+ this._instancedArraysExtensionSet = false;
58
61
  }
59
62
  destroy() {
60
63
  let p = pipeline_1.Pipeline.get(this._pipeline);
@@ -125,15 +128,34 @@ class HTMLElementSource extends source_1.Source {
125
128
  let pipeline = pipeline_1.Pipeline.get(this._pipeline);
126
129
  if (!pipeline)
127
130
  return;
128
- let gl = pipeline.glContext;
131
+ let { glContext: gl, isWebGL2 } = pipeline;
129
132
  if (!gl)
130
133
  return;
134
+ if (!isWebGL2 && !this._instancedArraysExtensionSet) {
135
+ this._instancedArraysExtension = gl.getExtension("ANGLE_instanced_arrays");
136
+ this._instancedArraysExtensionSet = true;
137
+ }
138
+ const glStateManager = gl_state_manager_1.GLStateManager.get(gl);
139
+ glStateManager.push();
140
+ const reenableScissorTest = gl.isEnabled(gl.SCISSOR_TEST);
141
+ const reenableDepthTest = gl.isEnabled(gl.DEPTH_TEST);
142
+ const reenableBlend = gl.isEnabled(gl.BLEND);
143
+ const reenableCullFace = gl.isEnabled(gl.CULL_FACE);
144
+ const reenableStencilTest = gl.isEnabled(gl.STENCIL_TEST);
145
+ const previousActiveTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
146
+ const previousUnpackFlip = gl.getParameter(gl.UNPACK_FLIP_Y_WEBGL);
147
+ const previousProgram = gl.getParameter(gl.CURRENT_PROGRAM);
148
+ gl.activeTexture(gl.TEXTURE0);
149
+ const previousBoundTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
150
+ const previousBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
151
+ const previousBoundArrayBuffer = gl.getParameter(gl.ARRAY_BUFFER_BINDING);
152
+ const previousBoundElementArrayBuffer = gl.getParameter(gl.ELEMENT_ARRAY_BUFFER_BINDING);
131
153
  gl.disable(gl.SCISSOR_TEST);
132
154
  gl.disable(gl.DEPTH_TEST);
133
155
  gl.disable(gl.BLEND);
134
156
  gl.disable(gl.CULL_FACE);
157
+ gl.disable(gl.STENCIL_TEST);
135
158
  gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
136
- gl.activeTexture(gl.TEXTURE0);
137
159
  gl.bindTexture(gl.TEXTURE_2D, this._currentVideoTexture);
138
160
  const level = 0;
139
161
  const internalFormat = gl.RGBA;
@@ -157,13 +179,43 @@ class HTMLElementSource extends source_1.Source {
157
179
  let vbo = this._getVertexBuffer(gl);
158
180
  let ibo = this._getIndexBuffer(gl);
159
181
  let shader = this._getGreyscaleShader(gl);
160
- // // Rendering to the greyscale conversion buffer - bind the framebuffer
182
+ const previousVertexAttribSize = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_SIZE);
183
+ const previousVertexAttribType = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_TYPE);
184
+ const previousVertexAttribNormalized = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED);
185
+ const previousVertexAttribStride = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_STRIDE);
186
+ const previousVertexAttribOffset = gl.getVertexAttribOffset(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_POINTER);
187
+ const previousVertexAttribEnabled = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
188
+ const previousVertexAttribBufferBinding = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
189
+ const previousTextureAttribSize = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_SIZE);
190
+ const previousTextureAttribType = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_TYPE);
191
+ const previousTextureAttribNormalized = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_NORMALIZED);
192
+ const previousTextureAttribStride = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_STRIDE);
193
+ const previousTextureAttribOffset = gl.getVertexAttribOffset(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_POINTER);
194
+ const previousTextureAttribEnabled = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_ENABLED);
195
+ const previousTextureAttribBufferBinding = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_BUFFER_BINDING);
196
+ let previousVertexAttribDivisor = 0;
197
+ let previousTextureAttribDivisor = 0;
198
+ if (isWebGL2) {
199
+ previousVertexAttribDivisor = gl.getVertexAttrib(shader.aVertexPositionLoc, gl.VERTEX_ATTRIB_ARRAY_DIVISOR);
200
+ previousTextureAttribDivisor = gl.getVertexAttrib(shader.aTextureCoordLoc, gl.VERTEX_ATTRIB_ARRAY_DIVISOR);
201
+ gl.vertexAttribDivisor(shader.aVertexPositionLoc, 0);
202
+ gl.vertexAttribDivisor(shader.aTextureCoordLoc, 0);
203
+ }
204
+ else if (this._instancedArraysExtension) {
205
+ previousVertexAttribDivisor = gl.getVertexAttrib(shader.aVertexPositionLoc, this._instancedArraysExtension.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
206
+ previousTextureAttribDivisor = gl.getVertexAttrib(shader.aTextureCoordLoc, this._instancedArraysExtension.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
207
+ this._instancedArraysExtension.vertexAttribDivisorANGLE(shader.aVertexPositionLoc, 0);
208
+ this._instancedArraysExtension.vertexAttribDivisorANGLE(shader.aTextureCoordLoc, 0);
209
+ }
210
+ // Rendering to the greyscale conversion buffer - bind the framebuffer
161
211
  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
212
+ // const t_before = performance.now();
213
+ // const viewport = gl.getParameter(gl.VIEWPORT);
214
+ // console.log("Viewport time", performance.now() - t_before, viewport);
162
215
  gl.viewport(0, 0, this._framebufferWidth, this._framebufferHeight);
163
- // // We'll be replacing all the content - clear is a good hint for this on mobile
164
- gl.clearColor(0.0, 0.0, 0.0, 1.0);
216
+ // We'll be replacing all the content - clear is a good hint for this on mobile
165
217
  gl.clear(gl.COLOR_BUFFER_BIT);
166
- // // Set up bindings for vertex attributes
218
+ // Set up bindings for vertex attributes
167
219
  gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
168
220
  gl.vertexAttribPointer(shader.aVertexPositionLoc, 2, gl.FLOAT, false, 4 * 4, 0);
169
221
  gl.enableVertexAttribArray(shader.aVertexPositionLoc);
@@ -183,14 +235,38 @@ class HTMLElementSource extends source_1.Source {
183
235
  gl.uniform1i(shader.uSamplerLoc, 0);
184
236
  // Do the drawing...
185
237
  gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
186
- // Disable attribute arrays
187
- gl.disableVertexAttribArray(shader.aVertexPositionLoc);
188
- gl.disableVertexAttribArray(shader.aTextureCoordLoc);
189
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
190
- gl.bindBuffer(gl.ARRAY_BUFFER, null);
191
- gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
192
- gl.useProgram(null);
193
- gl.bindTexture(gl.TEXTURE_2D, null);
238
+ gl.bindBuffer(gl.ARRAY_BUFFER, previousVertexAttribBufferBinding);
239
+ gl.vertexAttribPointer(shader.aVertexPositionLoc, previousVertexAttribSize, previousVertexAttribType, previousVertexAttribNormalized, previousVertexAttribStride, previousVertexAttribOffset);
240
+ gl.bindBuffer(gl.ARRAY_BUFFER, previousTextureAttribBufferBinding);
241
+ gl.vertexAttribPointer(shader.aTextureCoordLoc, previousTextureAttribSize, previousTextureAttribType, previousTextureAttribNormalized, previousTextureAttribStride, previousTextureAttribOffset);
242
+ gl.bindBuffer(gl.ARRAY_BUFFER, previousBoundArrayBuffer);
243
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, previousBoundElementArrayBuffer);
244
+ if (!previousVertexAttribEnabled)
245
+ gl.disableVertexAttribArray(shader.aVertexPositionLoc);
246
+ if (!previousTextureAttribEnabled)
247
+ gl.disableVertexAttribArray(shader.aTextureCoordLoc);
248
+ if (isWebGL2) {
249
+ gl.vertexAttribDivisor(shader.aVertexPositionLoc, previousVertexAttribDivisor);
250
+ gl.vertexAttribDivisor(shader.aTextureCoordLoc, previousTextureAttribDivisor);
251
+ }
252
+ else if (this._instancedArraysExtension) {
253
+ this._instancedArraysExtension.vertexAttribDivisorANGLE(shader.aVertexPositionLoc, previousVertexAttribDivisor);
254
+ this._instancedArraysExtension.vertexAttribDivisorANGLE(shader.aTextureCoordLoc, previousTextureAttribDivisor);
255
+ }
256
+ gl.bindFramebuffer(gl.FRAMEBUFFER, previousBoundFramebuffer);
257
+ gl.useProgram(previousProgram);
258
+ gl.bindTexture(gl.TEXTURE_2D, previousBoundTexture);
259
+ gl.activeTexture(previousActiveTexture);
260
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, previousUnpackFlip);
261
+ if (reenableBlend)
262
+ gl.enable(gl.BLEND);
263
+ if (reenableCullFace)
264
+ gl.enable(gl.CULL_FACE);
265
+ if (reenableDepthTest)
266
+ gl.enable(gl.DEPTH_TEST);
267
+ if (reenableScissorTest)
268
+ gl.enable(gl.SCISSOR_TEST);
269
+ glStateManager.pop();
194
270
  }
195
271
  _readFrame(p, gl) {
196
272
  if (!this._currentVideoTexture)
@@ -208,10 +284,11 @@ class HTMLElementSource extends source_1.Source {
208
284
  pixels = new ArrayBuffer(greySize);
209
285
  }
210
286
  let pixelsView = new Uint8Array(pixels);
287
+ const previousBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
211
288
  let framebuffer = this._getFramebuffer(gl, profile_1.profile.dataWidth / 4, profile_1.profile.dataHeight);
212
289
  gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
213
290
  gl.readPixels(0, 0, this._framebufferWidth, this._framebufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixelsView);
214
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
291
+ gl.bindFramebuffer(gl.FRAMEBUFFER, previousBoundFramebuffer);
215
292
  return {
216
293
  uvTransform: this._cameraUvTransform,
217
294
  data: pixels,
package/lib/pipeline.d.ts CHANGED
@@ -15,15 +15,17 @@ export declare class Pipeline {
15
15
  private cameraTokens;
16
16
  private nextCameraToken;
17
17
  private tokensInFlight;
18
- glContext: WebGLRenderingContext | undefined;
18
+ glContext: WebGLRenderingContext | WebGL2RenderingContext | undefined;
19
19
  private videoTextures;
20
20
  cameraPixelArrays: ArrayBuffer[];
21
21
  private _cameraDraw;
22
22
  private _faceDraw;
23
23
  private _faceProjectDraw;
24
+ private _isWebGL2;
24
25
  onGLContextReset: Event;
25
26
  static create(client: zappar_cwrap, mgr: MsgManager): zappar_pipeline_t;
26
27
  static get(p: zappar_pipeline_t): Pipeline | undefined;
28
+ get isWebGL2(): boolean;
27
29
  private constructor();
28
30
  frameUpdate(client: zappar_client): void;
29
31
  cameraTokenReturn(tokenId: number, pixelArray: ArrayBuffer): void;
package/lib/pipeline.js CHANGED
@@ -21,6 +21,7 @@ class Pipeline {
21
21
  this.tokensInFlight = 0;
22
22
  this.videoTextures = [];
23
23
  this.cameraPixelArrays = [];
24
+ this._isWebGL2 = false;
24
25
  this.onGLContextReset = new event_1.Event();
25
26
  }
26
27
  static create(client, mgr) {
@@ -31,6 +32,9 @@ class Pipeline {
31
32
  static get(p) {
32
33
  return byId.get(p);
33
34
  }
35
+ get isWebGL2() {
36
+ return this._isWebGL2;
37
+ }
34
38
  frameUpdate(client) {
35
39
  for (let msg of this.pendingMessages) {
36
40
  client.processMessages(msg);
@@ -106,6 +110,7 @@ class Pipeline {
106
110
  glContextSet(gl, texturePool) {
107
111
  this.glContextLost();
108
112
  this.glContext = gl;
113
+ this._isWebGL2 = gl.getParameter(gl.VERSION).indexOf("WebGL 2") >= 0;
109
114
  texturePool = texturePool || [];
110
115
  for (let i = 0; i < 4; i++) {
111
116
  let tex = texturePool[i] || gl.createTexture();
package/lib/profile.js CHANGED
@@ -26,43 +26,41 @@ let engine = (agent.getEngine().name || "unknown").toLowerCase();
26
26
  if (engine === "webkit" && os !== "ios") {
27
27
  exports.profile.deviceMotionMutliplier = 1.0;
28
28
  if (window.orientation !== undefined) {
29
- // iPad
30
- iDevice();
29
+ // iPad. The version number isn't reliable as it masquerades as MacOS
30
+ iDevice("15.0");
31
31
  }
32
32
  }
33
33
  if (engine === "webkit" && os === "ios") {
34
34
  exports.profile.deviceMotionMutliplier = 1.0;
35
- iDevice();
35
+ const version = agent.getOS().version || "15.0";
36
+ iDevice(version);
36
37
  }
37
- function iDevice() {
38
- let version = agent.getOS().version;
39
- if (version) {
40
- let versionParts = version.split(".");
41
- if (versionParts.length >= 2) {
42
- const majorVersion = parseInt(versionParts[0]);
43
- const minorVersion = parseInt(versionParts[1]);
44
- if (majorVersion < 11 ||
45
- (majorVersion === 11 && minorVersion < 3)) {
46
- exports.profile.blacklisted = true;
47
- }
48
- if (majorVersion < 12 ||
49
- (majorVersion === 12 && minorVersion < 2)) {
50
- exports.profile.videoElementInDOM = true;
51
- }
52
- if ((majorVersion === 12 && minorVersion >= 2) || (majorVersion >= 13))
53
- exports.profile.showGyroPermissionsWarningIfNecessary = true;
54
- if (majorVersion >= 13) {
55
- exports.profile.showSafariPermissionsResetIfNecessary = true;
56
- }
57
- if (((majorVersion >= 12 && minorVersion > 1) || (majorVersion >= 13)) &&
58
- navigator.mediaDevices &&
59
- navigator.mediaDevices.getSupportedConstraints &&
60
- navigator.mediaDevices.getSupportedConstraints().frameRate) {
61
- exports.profile.requestHighFrameRate = true;
62
- // Avoid bug where iOS letterboxes 16:9 into 4:3 for high fps
63
- exports.profile.videoHeight = 360;
64
- exports.profile.dataHeight = 180;
65
- }
38
+ function iDevice(version) {
39
+ let versionParts = version.split(".");
40
+ if (versionParts.length >= 2) {
41
+ const majorVersion = parseInt(versionParts[0]);
42
+ const minorVersion = parseInt(versionParts[1]);
43
+ if (majorVersion < 11 ||
44
+ (majorVersion === 11 && minorVersion < 3)) {
45
+ exports.profile.blacklisted = true;
46
+ }
47
+ if (majorVersion < 12 ||
48
+ (majorVersion === 12 && minorVersion < 2)) {
49
+ exports.profile.videoElementInDOM = true;
50
+ }
51
+ if ((majorVersion === 12 && minorVersion >= 2) || (majorVersion >= 13))
52
+ exports.profile.showGyroPermissionsWarningIfNecessary = true;
53
+ if (majorVersion >= 13) {
54
+ exports.profile.showSafariPermissionsResetIfNecessary = true;
55
+ }
56
+ if (((majorVersion >= 12 && minorVersion > 1) || (majorVersion >= 13)) &&
57
+ navigator.mediaDevices &&
58
+ navigator.mediaDevices.getSupportedConstraints &&
59
+ navigator.mediaDevices.getSupportedConstraints().frameRate) {
60
+ exports.profile.requestHighFrameRate = true;
61
+ // Avoid bug where iOS letterboxes 16:9 into 4:3 for high fps
62
+ exports.profile.videoHeight = 360;
63
+ exports.profile.dataHeight = 180;
66
64
  }
67
65
  }
68
66
  }
package/lib/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.3.14";
1
+ export declare const VERSION = "0.3.17";
package/lib/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = void 0;
4
- exports.VERSION = "0.3.14";
4
+ exports.VERSION = "0.3.17";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zappar/zappar-cv",
3
- "version": "0.3.14",
3
+ "version": "0.3.17",
4
4
  "description": "Zappar's core computer vision library, supporting image, face and world tracking.",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",