@luma.gl/test-utils 9.0.0-alpha.21 → 9.0.0-alpha.23

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,714 @@
1
+ // TODO - replace createGLContext, instrumentGLContext, resizeGLContext?
2
+ // TODO - remove dependency on framebuffer (bundle size impact)
3
+ import {
4
+ luma,
5
+ Device,
6
+ DeviceProps,
7
+ log,
8
+ requestAnimationFrame,
9
+ cancelAnimationFrame
10
+ } from '@luma.gl/api';
11
+ import {Timeline, AnimationProps} from '@luma.gl/engine';
12
+ import {Stats, Stat} from '@probe.gl/stats';
13
+ import {isBrowser} from '@probe.gl/env';
14
+
15
+ import {isWebGL, resetParameters} from '@luma.gl/webgl';
16
+ // import {default as Query} from '../classic/query';
17
+ // import {ClassicFramebuffer} from '../classic/framebuffer';
18
+
19
+ type ContextProps = DeviceProps;
20
+
21
+ const isPage = isBrowser() && typeof document !== 'undefined';
22
+ function getHTMLCanvasElement(
23
+ canvas: HTMLCanvasElement | OffscreenCanvas
24
+ ): HTMLCanvasElement | null {
25
+ return typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement
26
+ ? canvas
27
+ : null;
28
+ }
29
+
30
+ let statIdCounter = 0;
31
+
32
+ /**
33
+ * Classic Animation Props.
34
+ * Contain a number of deprecated fields
35
+ * @deprecated Use new AnimationLoop in `@luma.gl/engine`
36
+ */
37
+ export type ClassicAnimationProps = AnimationProps & {
38
+ animationLoop: ClassicAnimationLoop;
39
+
40
+ /** @deprecated Use .device */
41
+ stop: () => ClassicAnimationLoop;
42
+
43
+ /** @deprecated Use .device */
44
+ gl: WebGLRenderingContext;
45
+ /** @deprecated Will be removed */
46
+ framebuffer: unknown;
47
+
48
+ /** @deprecated Use .timeline */
49
+ _timeline: Timeline;
50
+ /** @deprecated Use .animationLoop */
51
+ _loop: ClassicAnimationLoop;
52
+ /** @deprecated Use .animationLoop */
53
+ _animationLoop: ClassicAnimationLoop;
54
+ };
55
+
56
+ /** ClassicAnimationLoop properties */
57
+ export type ClassicAnimationLoopProps = {
58
+ onCreateDevice?: (props: DeviceProps) => Promise<Device>;
59
+ onCreateContext?: (props: ContextProps) => WebGLRenderingContext; // TODO: signature from createGLContext
60
+ onAddHTML?: (div: HTMLDivElement) => string; // innerHTML
61
+ onInitialize?: (animationProps: ClassicAnimationProps) => {} | void | Promise<{} | void>;
62
+ onRender?: (animationProps: ClassicAnimationProps) => void;
63
+ onFinalize?: (animationProps: ClassicAnimationProps) => void;
64
+ onError?: (reason: any) => void;
65
+
66
+ stats?: Stats;
67
+
68
+ device?: Device;
69
+ glOptions?: ContextProps; // createGLContext options
70
+ // debug?: boolean;
71
+
72
+ // view parameters
73
+ autoResizeViewport?: boolean;
74
+ autoResizeDrawingBuffer?: boolean;
75
+ useDevicePixels?: number | boolean;
76
+
77
+ /** @deprecated Use .device */
78
+ gl?: WebGLRenderingContext | null;
79
+ /** @deprecated Will be removed */
80
+ createFramebuffer?: boolean;
81
+ };
82
+
83
+ const DEFAULT_CLASSIC_ANIMATION_LOOP_PROPS: Required<ClassicAnimationLoopProps> = {
84
+ onCreateDevice: (props: DeviceProps) => luma.createDevice(props),
85
+ onCreateContext: undefined,
86
+ onAddHTML: undefined,
87
+ onInitialize: () => ({}),
88
+ onRender: () => {},
89
+ onFinalize: () => {},
90
+ onError: (error) => console.error(error), // eslint-disable-line no-console
91
+
92
+ device: null,
93
+ // debug: true,
94
+
95
+ // view parameters
96
+ useDevicePixels: true,
97
+ autoResizeViewport: true,
98
+ autoResizeDrawingBuffer: true,
99
+ stats: luma.stats.get(`animation-loop-${statIdCounter++}`),
100
+
101
+ // deprecated
102
+ // onCreateContext: (opts) => createGLContext(opts),
103
+ gl: undefined,
104
+ glOptions: {},
105
+ createFramebuffer: false
106
+ };
107
+
108
+ /**
109
+ * Convenient animation loop
110
+ * @deprecated Use `@luma.gl/engine` AnimationLoop
111
+ */
112
+ export class ClassicAnimationLoop {
113
+ device: Device;
114
+ canvas?: HTMLCanvasElement | OffscreenCanvas;
115
+
116
+ props: Required<ClassicAnimationLoopProps>;
117
+ animationProps: ClassicAnimationProps;
118
+ // framebuffer: ClassicFramebuffer = null;
119
+ timeline: Timeline = null;
120
+ stats: Stats;
121
+ cpuTime: Stat;
122
+ gpuTime: Stat;
123
+ frameRate: Stat;
124
+
125
+ display: any;
126
+
127
+ needsRedraw: string | null = 'initialized';
128
+
129
+ _initialized: boolean = false;
130
+ _running: boolean = false;
131
+ _animationFrameId: any = null;
132
+ _pageLoadPromise: Promise<{}> | null = null;
133
+ _nextFramePromise: Promise<ClassicAnimationLoop> | null = null;
134
+ _resolveNextFrame: ((loop: ClassicAnimationLoop) => void) | null = null;
135
+ _cpuStartTime: number = 0;
136
+
137
+ // _gpuTimeQuery: Query | null = null;
138
+
139
+ /** @deprecated */
140
+ gl: WebGLRenderingContext;
141
+
142
+ /*
143
+ */
144
+ constructor(props: ClassicAnimationLoopProps = {}) {
145
+ this.props = {...DEFAULT_CLASSIC_ANIMATION_LOOP_PROPS, ...props};
146
+ props = this.props;
147
+
148
+ let {useDevicePixels = true} = this.props;
149
+
150
+ if ('useDevicePixelRatio' in props) {
151
+ log.deprecated('useDevicePixelRatio', 'useDevicePixels')();
152
+ // @ts-expect-error
153
+ useDevicePixels = props.useDevicePixelRatio;
154
+ }
155
+
156
+ // state
157
+ this.device = props.device;
158
+ // @ts-expect-error
159
+ this.gl = (this.device && this.device.gl) || props.gl;
160
+
161
+ this.stats = props.stats;
162
+ this.cpuTime = this.stats.get('CPU Time');
163
+ this.gpuTime = this.stats.get('GPU Time');
164
+ this.frameRate = this.stats.get('Frame Rate');
165
+
166
+ this.setProps({
167
+ autoResizeViewport: props.autoResizeViewport,
168
+ autoResizeDrawingBuffer: props.autoResizeDrawingBuffer,
169
+ useDevicePixels
170
+ });
171
+
172
+ // Bind methods
173
+ this.start = this.start.bind(this);
174
+ this.stop = this.stop.bind(this);
175
+
176
+ this._onMousemove = this._onMousemove.bind(this);
177
+ this._onMouseleave = this._onMouseleave.bind(this);
178
+ }
179
+
180
+ destroy(): void {
181
+ this.stop();
182
+ this._setDisplay(null);
183
+ }
184
+
185
+ /** @deprecated Use .destroy() */
186
+ delete(): void {
187
+ this.destroy();
188
+ }
189
+
190
+ setNeedsRedraw(reason: string): this {
191
+ this.needsRedraw = this.needsRedraw || reason;
192
+ return this;
193
+ }
194
+
195
+ setProps(props: ClassicAnimationLoopProps): this {
196
+ if ('autoResizeViewport' in props) {
197
+ this.props.autoResizeViewport = props.autoResizeViewport;
198
+ }
199
+ if ('autoResizeDrawingBuffer' in props) {
200
+ this.props.autoResizeDrawingBuffer = props.autoResizeDrawingBuffer;
201
+ }
202
+ if ('useDevicePixels' in props) {
203
+ this.props.useDevicePixels = props.useDevicePixels;
204
+ }
205
+ return this;
206
+ }
207
+
208
+ start(opts = {}) {
209
+ this._start(opts);
210
+ return this;
211
+ }
212
+
213
+ /** Starts a render loop if not already running */
214
+ async _start(props) {
215
+ if (this._running) {
216
+ return this;
217
+ }
218
+ this._running = true;
219
+
220
+ // console.debug(`Starting ${this.constructor.name}`);
221
+ // Wait for start promise before rendering frame
222
+ try {
223
+ await this._getPageLoadPromise();
224
+
225
+ // check that we haven't been stopped
226
+ if (!this._running) {
227
+ return null;
228
+ }
229
+
230
+ let appContext;
231
+ if (!this._initialized) {
232
+ this._initialized = true;
233
+ // Create the WebGL context
234
+ await this._createDevice(props);
235
+ this._initialize(props);
236
+
237
+ // Note: onIntialize can return a promise (in case app needs to load resources)
238
+ // eslint-disable-next-line @typescript-eslint/await-thenable
239
+ appContext = await this.onInitialize(this.animationProps);
240
+ this._addCallbackData(appContext || {});
241
+ }
242
+
243
+ // check that we haven't been stopped
244
+ if (!this._running) {
245
+ return null;
246
+ }
247
+
248
+ // Start the loop
249
+ if (appContext !== false) {
250
+ // cancel any pending renders to ensure only one loop can ever run
251
+ this._cancelAnimationFrame();
252
+ this._requestAnimationFrame();
253
+ }
254
+
255
+ return this;
256
+ } catch (error) {
257
+ this.props.onError(error);
258
+ // this._running = false; // TODO
259
+ return null;
260
+ }
261
+ }
262
+
263
+ /** Explicitly draw a frame */
264
+ redraw(): this {
265
+ if (this.isContextLost()) {
266
+ return this;
267
+ }
268
+
269
+ this._beginTimers();
270
+
271
+ this._setupFrame();
272
+ this._updateCallbackData();
273
+
274
+ this._renderFrame(this.animationProps);
275
+
276
+ // clear needsRedraw flag
277
+ this._clearNeedsRedraw();
278
+
279
+ if (this._resolveNextFrame) {
280
+ this._resolveNextFrame(this);
281
+ this._nextFramePromise = null;
282
+ this._resolveNextFrame = null;
283
+ }
284
+
285
+ this._endTimers();
286
+
287
+ return this;
288
+ }
289
+
290
+ // Stops a render loop if already running, finalizing
291
+ stop() {
292
+ // console.debug(`Stopping ${this.constructor.name}`);
293
+ if (this._running) {
294
+ this._finalizeCallbackData();
295
+ this._cancelAnimationFrame();
296
+ this._nextFramePromise = null;
297
+ this._resolveNextFrame = null;
298
+ this._running = false;
299
+ }
300
+ return this;
301
+ }
302
+
303
+ attachTimeline(timeline: Timeline): Timeline {
304
+ this.timeline = timeline;
305
+ return this.timeline;
306
+ }
307
+
308
+ detachTimeline(): void {
309
+ this.timeline = null;
310
+ }
311
+
312
+ waitForRender(): Promise<ClassicAnimationLoop> {
313
+ this.setNeedsRedraw('waitForRender');
314
+
315
+ if (!this._nextFramePromise) {
316
+ this._nextFramePromise = new Promise((resolve) => {
317
+ this._resolveNextFrame = resolve;
318
+ });
319
+ }
320
+ return this._nextFramePromise;
321
+ }
322
+
323
+ async toDataURL() {
324
+ this.setNeedsRedraw('toDataURL');
325
+
326
+ await this.waitForRender();
327
+
328
+ return getHTMLCanvasElement(this.gl.canvas)?.toDataURL();
329
+ }
330
+
331
+ isContextLost(): boolean {
332
+ return this.gl.isContextLost();
333
+ }
334
+
335
+ onCreateDevice(deviceProps: DeviceProps): Promise<Device> {
336
+ const {onCreateDevice} = this.props;
337
+ return onCreateDevice(deviceProps);
338
+ }
339
+
340
+ onInitialize(animationProps: ClassicAnimationProps): {} | void {
341
+ const {onInitialize} = this.props;
342
+ return onInitialize(animationProps);
343
+ }
344
+
345
+ onRender(animationProps: ClassicAnimationProps) {
346
+ const {onRender} = this.props;
347
+ return onRender(animationProps);
348
+ }
349
+
350
+ onFinalize(animationProps: ClassicAnimationProps) {
351
+ const {onFinalize} = this.props;
352
+ return onFinalize(animationProps);
353
+ }
354
+
355
+ // DEPRECATED/REMOVED METHODS
356
+
357
+ /** @deprecated Use .onCreateDevice() */
358
+ onCreateContext(props: ContextProps) {
359
+ const {onCreateContext} = this.props;
360
+ return onCreateContext(props);
361
+ }
362
+
363
+ /** @deprecated */
364
+ getHTMLControlValue(id, defaultValue = 1) {
365
+ const element = document.getElementById(id);
366
+ // @ts-expect-error Not all html elements have value
367
+ return element ? Number(element.value) : defaultValue;
368
+ }
369
+
370
+ // PRIVATE METHODS
371
+
372
+ _initialize(props: ClassicAnimationLoopProps) {
373
+ this._createFramebuffer();
374
+ this._startEventHandling();
375
+
376
+ // Initialize the callback data
377
+ this._initializeCallbackData();
378
+ this._updateCallbackData();
379
+
380
+ // Default viewport setup, in case onInitialize wants to render
381
+ this._resizeCanvasDrawingBuffer();
382
+ this._resizeViewport();
383
+
384
+ // this._gpuTimeQuery = Query.isSupported(this.gl, ['timers']) ? new Query(this.gl) : null;
385
+ }
386
+
387
+ _getPageLoadPromise() {
388
+ if (!this._pageLoadPromise) {
389
+ this._pageLoadPromise = isPage
390
+ ? new Promise((resolve, reject) => {
391
+ if (isPage && document.readyState === 'complete') {
392
+ resolve(document);
393
+ return;
394
+ }
395
+ window.addEventListener('load', () => {
396
+ resolve(document);
397
+ });
398
+ })
399
+ : Promise.resolve({});
400
+ }
401
+ return this._pageLoadPromise;
402
+ }
403
+
404
+ _setDisplay(display: any) {
405
+ if (this.display) {
406
+ this.display.destroy();
407
+ this.display.animationLoop = null;
408
+ }
409
+
410
+ // store animation loop on the display
411
+ if (display) {
412
+ display.animationLoop = this;
413
+ }
414
+
415
+ this.display = display;
416
+ }
417
+
418
+ _requestAnimationFrame() {
419
+ if (!this._running) {
420
+ return;
421
+ }
422
+
423
+ // VR display has a separate animation frame to sync with headset
424
+ // TODO WebVR API discontinued, replaced by WebXR: https://immersive-web.github.io/webxr/
425
+ // See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/requestAnimationFrame
426
+ // if (this.display && this.display.requestAnimationFrame) {
427
+ // this._animationFrameId = this.display.requestAnimationFrame(this._animationFrame.bind(this));
428
+ // }
429
+ this._animationFrameId = requestAnimationFrame(this._animationFrame.bind(this));
430
+ }
431
+
432
+ _cancelAnimationFrame() {
433
+ if (this._animationFrameId !== null) {
434
+ return;
435
+ }
436
+
437
+ // VR display has a separate animation frame to sync with headset
438
+ // TODO WebVR API discontinued, replaced by WebXR: https://immersive-web.github.io/webxr/
439
+ // See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/requestAnimationFrame
440
+ // if (this.display && this.display.cancelAnimationFrame) {
441
+ // this.display.cancelAnimationFrame(this._animationFrameId);
442
+ // }
443
+ cancelAnimationFrame(this._animationFrameId);
444
+ this._animationFrameId = null;
445
+ }
446
+
447
+ _animationFrame() {
448
+ if (!this._running) {
449
+ return;
450
+ }
451
+ this.redraw();
452
+ this._requestAnimationFrame();
453
+ }
454
+
455
+ // Called on each frame, can be overridden to call onRender multiple times
456
+ // to support e.g. stereoscopic rendering
457
+ _renderFrame(props: ClassicAnimationProps) {
458
+ // Allow e.g. VR display to render multiple frames.
459
+ if (this.display) {
460
+ this.display._renderFrame(props);
461
+ return;
462
+ }
463
+
464
+ // call callback
465
+ this.onRender(props);
466
+ // end callback
467
+ }
468
+
469
+ _clearNeedsRedraw() {
470
+ this.needsRedraw = null;
471
+ }
472
+
473
+ _setupFrame() {
474
+ this._resizeCanvasDrawingBuffer();
475
+ this._resizeViewport();
476
+ this._resizeFramebuffer();
477
+ }
478
+
479
+ /* eslint-disable @typescript-eslint/unbound-method */
480
+
481
+ // Initialize the object that will be passed to app callbacks
482
+ _initializeCallbackData() {
483
+ this.animationProps = {
484
+ device: this.device,
485
+ gl: this.gl,
486
+
487
+ stop: this.stop,
488
+ canvas: this.gl.canvas,
489
+
490
+ // Initial values
491
+ useDevicePixels: this.props.useDevicePixels,
492
+ needsRedraw: null,
493
+
494
+ // Animation props
495
+ startTime: Date.now(),
496
+ engineTime: 0,
497
+ tick: 0,
498
+ tock: 0,
499
+
500
+ timeline: this.timeline,
501
+ // @ts-ignore
502
+ animationLoop: this,
503
+
504
+ // Timeline time for back compatibility
505
+ time: 0,
506
+
507
+ // Experimental
508
+ _mousePosition: null, // Event props
509
+
510
+ /** @deprecated */
511
+ // framebuffer: this.framebuffer,
512
+ /** @deprecated */
513
+ _timeline: this.timeline,
514
+ /** @deprecated */
515
+ _loop: this,
516
+ /** @deprecated */
517
+ _animationLoop: this
518
+ };
519
+ }
520
+
521
+ // Update the context object that will be passed to app callbacks
522
+ _updateCallbackData() {
523
+ const {width, height, aspect} = this._getSizeAndAspect();
524
+ if (width !== this.animationProps.width || height !== this.animationProps.height) {
525
+ this.setNeedsRedraw('drawing buffer resized');
526
+ }
527
+ if (aspect !== this.animationProps.aspect) {
528
+ this.setNeedsRedraw('drawing buffer aspect changed');
529
+ }
530
+
531
+ this.animationProps.width = width;
532
+ this.animationProps.height = height;
533
+ this.animationProps.aspect = aspect;
534
+
535
+ this.animationProps.needsRedraw = this.needsRedraw;
536
+
537
+ // Update time properties
538
+ this.animationProps.engineTime = Date.now() - this.animationProps.startTime;
539
+
540
+ if (this.timeline) {
541
+ this.timeline.update(this.animationProps.engineTime);
542
+ }
543
+
544
+ this.animationProps.tick = Math.floor((this.animationProps.time / 1000) * 60);
545
+ this.animationProps.tock++;
546
+
547
+ // For back compatibility
548
+ this.animationProps.time = this.timeline
549
+ ? this.timeline.getTime()
550
+ : this.animationProps.engineTime;
551
+ }
552
+
553
+ _finalizeCallbackData() {
554
+ // call callback
555
+ this.onFinalize(this.animationProps);
556
+ // end callback
557
+ }
558
+
559
+ /** Add application's data to the app context object */
560
+ _addCallbackData(appContext) {
561
+ if (typeof appContext === 'object' && appContext !== null) {
562
+ this.animationProps = Object.assign({}, this.animationProps, appContext);
563
+ }
564
+ }
565
+
566
+ /** Either uses supplied or existing context, or calls provided callback to create one */
567
+ async _createDevice(props: DeviceProps) {
568
+ const deviceProps = {...this.props, ...props, ...this.props.glOptions};
569
+
570
+ // TODO - support this.onCreateContext
571
+ // Create the WebGL context if necessary
572
+ // this.gl = this.props.gl ? instrumentGLContext(this.props.gl, deviceProps) : this.onCreateContext(deviceProps);
573
+
574
+ this.device = await this.onCreateDevice(deviceProps);
575
+ // @ts-expect-error
576
+ this.gl = this.device.gl;
577
+
578
+ if (!isWebGL(this.gl)) {
579
+ throw new Error('ClassicAnimationLoop.onCreateContext - illegal context returned');
580
+ }
581
+
582
+ // Reset the WebGL context.
583
+ resetParameters(this.gl);
584
+
585
+ this._createInfoDiv();
586
+ }
587
+
588
+ _createInfoDiv() {
589
+ const canvas = getHTMLCanvasElement(this.gl.canvas)
590
+ if (canvas && this.props.onAddHTML) {
591
+ const wrapperDiv = document.createElement('div');
592
+ document.body.appendChild(wrapperDiv);
593
+ wrapperDiv.style.position = 'relative';
594
+ const div = document.createElement('div');
595
+ div.style.position = 'absolute';
596
+ div.style.left = '10px';
597
+ div.style.bottom = '10px';
598
+ div.style.width = '300px';
599
+ div.style.background = 'white';
600
+ if (canvas) {
601
+ wrapperDiv.appendChild(canvas);
602
+ }
603
+ wrapperDiv.appendChild(div);
604
+ const html = this.props.onAddHTML(div);
605
+ if (html) {
606
+ div.innerHTML = html;
607
+ }
608
+ }
609
+ }
610
+
611
+ _getSizeAndAspect() {
612
+ // https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
613
+ const width = this.gl.drawingBufferWidth;
614
+ const height = this.gl.drawingBufferHeight;
615
+
616
+ // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
617
+ let aspect = 1;
618
+
619
+ const canvas = getHTMLCanvasElement(this.gl.canvas);
620
+ if (canvas && canvas.clientHeight) {
621
+ aspect = canvas.clientWidth / canvas.clientHeight;
622
+ } else if (width > 0 && height > 0) {
623
+ aspect = width / height;
624
+ }
625
+
626
+ return {width, height, aspect};
627
+ }
628
+
629
+ /** Default viewport setup */
630
+ _resizeViewport() {
631
+ if (this.props.autoResizeViewport) {
632
+ this.gl.viewport(0, 0, this.gl.drawingBufferWidth, this.gl.drawingBufferHeight);
633
+ }
634
+ }
635
+
636
+ /**
637
+ * Resize the render buffer of the canvas to match canvas client size
638
+ * Optionally multiplying with devicePixel ratio
639
+ */
640
+ _resizeCanvasDrawingBuffer() {
641
+ if (this.props.autoResizeDrawingBuffer) {
642
+ this.device.canvasContext.resize({useDevicePixels: this.props.useDevicePixels});
643
+ }
644
+ }
645
+
646
+ _beginTimers() {
647
+ this.frameRate.timeEnd();
648
+ this.frameRate.timeStart();
649
+
650
+ // Check if timer for last frame has completed.
651
+ // GPU timer results are never available in the same
652
+ // frame they are captured.
653
+ // if (
654
+ // this._gpuTimeQuery &&
655
+ // this._gpuTimeQuery.isResultAvailable() &&
656
+ // !this._gpuTimeQuery.isTimerDisjoint()
657
+ // ) {
658
+ // this.stats.get('GPU Time').addTime(this._gpuTimeQuery.getTimerMilliseconds());
659
+ // }
660
+
661
+ // if (this._gpuTimeQuery) {
662
+ // // GPU time query start
663
+ // this._gpuTimeQuery.beginTimeElapsedQuery();
664
+ // }
665
+
666
+ this.cpuTime.timeStart();
667
+ }
668
+
669
+ _endTimers() {
670
+ this.cpuTime.timeEnd();
671
+
672
+ // if (this._gpuTimeQuery) {
673
+ // // GPU time query end. Results will be available on next frame.
674
+ // this._gpuTimeQuery.end();
675
+ // }
676
+ }
677
+
678
+ // Event handling
679
+
680
+ _startEventHandling() {
681
+ const {canvas} = this.gl;
682
+ if (canvas) {
683
+ canvas.addEventListener('mousemove', this._onMousemove);
684
+ canvas.addEventListener('mouseleave', this._onMouseleave);
685
+ }
686
+ }
687
+
688
+ _onMousemove(e) {
689
+ this.animationProps._mousePosition = [e.offsetX, e.offsetY];
690
+ }
691
+ _onMouseleave(e) {
692
+ this.animationProps._mousePosition = null;
693
+ }
694
+
695
+ // Deprecated
696
+
697
+ /** @deprecated */
698
+ _createFramebuffer() {
699
+ // Setup default framebuffer
700
+ if (this.props.createFramebuffer) {
701
+ // this.framebuffer = new ClassicFramebuffer(this.gl);
702
+ }
703
+ }
704
+
705
+ /** @deprecated */
706
+ _resizeFramebuffer() {
707
+ // if (this.framebuffer) {
708
+ // this.framebuffer.resize({
709
+ // width: this.gl.drawingBufferWidth,
710
+ // height: this.gl.drawingBufferHeight
711
+ // });
712
+ // }
713
+ }
714
+ }
@@ -12,7 +12,8 @@ export type SnapshotTestRunnerTestCase = TestRunnerTestCase & {
12
12
  export type SnapshotTestRunnerProps = TestRunnerProps;
13
13
 
14
14
  export class SnapshotTestRunner extends TestRunner {
15
- private isDiffing: boolean = false;
15
+ // should be defined here but hack access in TestRunner
16
+ // private isDiffing: boolean = false;
16
17
 
17
18
  constructor(props: SnapshotTestRunnerProps) {
18
19
  super(props);