@luma.gl/engine 9.0.0-beta.1 → 9.0.0-beta.10
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/dist/animation/key-frames.js +54 -54
- package/dist/animation/timeline.d.ts.map +1 -1
- package/dist/animation/timeline.js +95 -100
- package/dist/animation-loop/animation-loop-template.d.ts +1 -1
- package/dist/animation-loop/animation-loop-template.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop-template.js +19 -5
- package/dist/animation-loop/animation-loop.d.ts +2 -2
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +433 -356
- package/dist/animation-loop/animation-props.d.ts +2 -2
- package/dist/animation-loop/animation-props.d.ts.map +1 -1
- package/dist/animation-loop/animation-props.js +0 -1
- package/dist/animation-loop/make-animation-loop.d.ts +2 -2
- package/dist/animation-loop/make-animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/make-animation-loop.js +28 -24
- package/dist/computation.d.ts +95 -0
- package/dist/computation.d.ts.map +1 -0
- package/dist/computation.js +248 -0
- package/dist/debug/copy-texture-to-image.d.ts.map +1 -1
- package/dist/debug/copy-texture-to-image.js +39 -42
- package/dist/debug/debug-framebuffer.d.ts.map +1 -1
- package/dist/debug/debug-framebuffer.js +43 -40
- package/dist/debug/debug-shader-layout.js +24 -25
- package/dist/debug/pixel-data-utils.d.ts.map +1 -1
- package/dist/debug/pixel-data-utils.js +34 -36
- package/dist/dist.dev.js +2538 -3027
- package/dist/dist.min.js +102 -0
- package/dist/geometries/cone-geometry.d.ts +1 -1
- package/dist/geometries/cone-geometry.d.ts.map +1 -1
- package/dist/geometries/cone-geometry.js +11 -17
- package/dist/geometries/cube-geometry.d.ts +1 -1
- package/dist/geometries/cube-geometry.d.ts.map +1 -1
- package/dist/geometries/cube-geometry.js +190 -61
- package/dist/geometries/cylinder-geometry.d.ts +1 -1
- package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
- package/dist/geometries/cylinder-geometry.js +9 -14
- package/dist/geometries/ico-sphere-geometry.d.ts +1 -1
- package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/ico-sphere-geometry.js +141 -160
- package/dist/geometries/plane-geometry.d.ts +1 -1
- package/dist/geometries/plane-geometry.d.ts.map +1 -1
- package/dist/geometries/plane-geometry.js +92 -110
- package/dist/geometries/sphere-geometry.d.ts +1 -1
- package/dist/geometries/sphere-geometry.d.ts.map +1 -1
- package/dist/geometries/sphere-geometry.js +76 -95
- package/dist/geometries/truncated-cone-geometry.d.ts +1 -1
- package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
- package/dist/geometries/truncated-cone-geometry.js +99 -117
- package/dist/geometry/geometry-table.d.ts.map +1 -1
- package/dist/geometry/geometry-table.js +3 -1
- package/dist/geometry/geometry-utils.js +35 -32
- package/dist/geometry/geometry.d.ts.map +1 -1
- package/dist/geometry/geometry.js +80 -71
- package/dist/geometry/gpu-geometry.d.ts +1 -1
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +79 -99
- package/dist/geometry/gpu-table.js +41 -1
- package/dist/index.cjs +725 -409
- package/dist/index.cjs.map +7 -0
- package/dist/index.d.ts +43 -40
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/lib/clip-space.d.ts +2 -2
- package/dist/lib/clip-space.d.ts.map +1 -1
- package/dist/lib/clip-space.js +28 -34
- package/dist/lib/pipeline-factory.d.ts +13 -14
- package/dist/lib/pipeline-factory.d.ts.map +1 -1
- package/dist/lib/pipeline-factory.js +86 -85
- package/dist/lib/shader-factory.d.ts +17 -0
- package/dist/lib/shader-factory.d.ts.map +1 -0
- package/dist/lib/shader-factory.js +46 -0
- package/dist/model/model.d.ts +59 -46
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +635 -411
- package/dist/scenegraph/group-node.d.ts +1 -1
- package/dist/scenegraph/group-node.d.ts.map +1 -1
- package/dist/scenegraph/group-node.js +73 -83
- package/dist/scenegraph/model-node.d.ts +3 -3
- package/dist/scenegraph/model-node.d.ts.map +1 -1
- package/dist/scenegraph/model-node.js +31 -24
- package/dist/scenegraph/scenegraph-node.d.ts.map +1 -1
- package/dist/scenegraph/scenegraph-node.js +136 -124
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +99 -58
- package/dist/transform/buffer-transform.d.ts +1 -1
- package/dist/transform/buffer-transform.d.ts.map +1 -1
- package/dist/transform/buffer-transform.js +65 -57
- package/dist/transform/texture-transform.d.ts +1 -1
- package/dist/transform/texture-transform.d.ts.map +1 -1
- package/dist/transform/texture-transform.js +109 -114
- package/dist.min.js +3 -271
- package/package.json +10 -9
- package/src/animation/timeline.ts +20 -20
- package/src/animation-loop/animation-loop-template.ts +10 -8
- package/src/animation-loop/animation-loop.ts +20 -10
- package/src/animation-loop/animation-props.ts +1 -1
- package/src/animation-loop/make-animation-loop.ts +17 -8
- package/src/computation.ts +346 -0
- package/src/debug/copy-texture-to-image.ts +9 -11
- package/src/debug/debug-framebuffer.ts +16 -3
- package/src/debug/debug-shader-layout.ts +1 -1
- package/src/debug/pixel-data-utils.ts +3 -6
- package/src/geometries/cube-geometry.ts +17 -13
- package/src/geometries/ico-sphere-geometry.ts +1 -1
- package/src/geometries/plane-geometry.ts +1 -1
- package/src/geometries/sphere-geometry.ts +1 -1
- package/src/geometries/truncated-cone-geometry.ts +2 -1
- package/src/geometry/geometry-table.ts +9 -6
- package/src/geometry/geometry-utils.ts +16 -0
- package/src/geometry/geometry.ts +9 -6
- package/src/geometry/gpu-geometry.ts +18 -11
- package/src/index.ts +4 -1
- package/src/lib/clip-space.ts +16 -19
- package/src/lib/pipeline-factory.ts +71 -64
- package/src/lib/shader-factory.ts +57 -0
- package/src/model/model.ts +255 -146
- package/src/scenegraph/group-node.ts +14 -10
- package/src/scenegraph/model-node.ts +2 -2
- package/src/scenegraph/scenegraph-node.ts +2 -2
- package/src/shader-inputs.ts +19 -12
- package/src/transform/buffer-transform.ts +16 -8
- package/src/transform/texture-transform.ts +14 -15
- package/dist/animation/key-frames.js.map +0 -1
- package/dist/animation/timeline.js.map +0 -1
- package/dist/animation-loop/animation-loop-template.js.map +0 -1
- package/dist/animation-loop/animation-loop.js.map +0 -1
- package/dist/animation-loop/animation-props.js.map +0 -1
- package/dist/animation-loop/make-animation-loop.js.map +0 -1
- package/dist/debug/copy-texture-to-image.js.map +0 -1
- package/dist/debug/debug-framebuffer.js.map +0 -1
- package/dist/debug/debug-shader-layout.js.map +0 -1
- package/dist/debug/pixel-data-utils.js.map +0 -1
- package/dist/geometries/cone-geometry.js.map +0 -1
- package/dist/geometries/cube-geometry.js.map +0 -1
- package/dist/geometries/cylinder-geometry.js.map +0 -1
- package/dist/geometries/ico-sphere-geometry.js.map +0 -1
- package/dist/geometries/plane-geometry.js.map +0 -1
- package/dist/geometries/sphere-geometry.js.map +0 -1
- package/dist/geometries/truncated-cone-geometry.js.map +0 -1
- package/dist/geometry/geometry-table.js.map +0 -1
- package/dist/geometry/geometry-utils.js.map +0 -1
- package/dist/geometry/geometry.js.map +0 -1
- package/dist/geometry/gpu-geometry.js.map +0 -1
- package/dist/geometry/gpu-table.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/clip-space.js.map +0 -1
- package/dist/lib/pipeline-factory.js.map +0 -1
- package/dist/model/model.js.map +0 -1
- package/dist/scenegraph/group-node.js.map +0 -1
- package/dist/scenegraph/model-node.js.map +0 -1
- package/dist/scenegraph/scenegraph-node.js.map +0 -1
- package/dist/shader-inputs.js.map +0 -1
- package/dist/transform/buffer-transform.js.map +0 -1
- package/dist/transform/texture-transform.js.map +0 -1
|
@@ -1,365 +1,442 @@
|
|
|
1
|
+
// luma.gl
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
// Copyright (c) vis.gl contributors
|
|
1
4
|
import { luma } from '@luma.gl/core';
|
|
2
5
|
import { requestAnimationFrame, cancelAnimationFrame } from '@luma.gl/core';
|
|
3
6
|
import { Stats } from '@probe.gl/stats';
|
|
4
7
|
let statIdCounter = 0;
|
|
5
8
|
const DEFAULT_ANIMATION_LOOP_PROPS = {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
device: null,
|
|
10
|
+
onAddHTML: () => '',
|
|
11
|
+
onInitialize: async () => {
|
|
12
|
+
return null;
|
|
13
|
+
},
|
|
14
|
+
onRender: () => { },
|
|
15
|
+
onFinalize: () => { },
|
|
16
|
+
onError: error => console.error(error), // eslint-disable-line no-console
|
|
17
|
+
stats: luma.stats.get(`animation-loop-${statIdCounter++}`),
|
|
18
|
+
// view parameters
|
|
19
|
+
useDevicePixels: true,
|
|
20
|
+
autoResizeViewport: false,
|
|
21
|
+
autoResizeDrawingBuffer: false
|
|
18
22
|
};
|
|
23
|
+
/** Convenient animation loop */
|
|
19
24
|
export class AnimationLoop {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
25
|
+
device = null;
|
|
26
|
+
canvas = null;
|
|
27
|
+
props;
|
|
28
|
+
animationProps = null;
|
|
29
|
+
timeline = null;
|
|
30
|
+
stats;
|
|
31
|
+
cpuTime;
|
|
32
|
+
gpuTime;
|
|
33
|
+
frameRate;
|
|
34
|
+
display;
|
|
35
|
+
needsRedraw = 'initialized';
|
|
36
|
+
_initialized = false;
|
|
37
|
+
_running = false;
|
|
38
|
+
_animationFrameId = null;
|
|
39
|
+
_nextFramePromise = null;
|
|
40
|
+
_resolveNextFrame = null;
|
|
41
|
+
_cpuStartTime = 0;
|
|
42
|
+
// _gpuTimeQuery: Query | null = null;
|
|
43
|
+
/*
|
|
44
|
+
* @param {HTMLCanvasElement} canvas - if provided, width and height will be passed to context
|
|
45
|
+
*/
|
|
46
|
+
constructor(props) {
|
|
47
|
+
this.props = { ...DEFAULT_ANIMATION_LOOP_PROPS, ...props };
|
|
48
|
+
props = this.props;
|
|
49
|
+
if (!props.device) {
|
|
50
|
+
throw new Error('No device provided');
|
|
51
|
+
}
|
|
52
|
+
const { useDevicePixels = true } = this.props;
|
|
53
|
+
// state
|
|
54
|
+
this.stats = props.stats || new Stats({ id: 'animation-loop-stats' });
|
|
55
|
+
this.cpuTime = this.stats.get('CPU Time');
|
|
56
|
+
this.gpuTime = this.stats.get('GPU Time');
|
|
57
|
+
this.frameRate = this.stats.get('Frame Rate');
|
|
58
|
+
this.setProps({
|
|
59
|
+
autoResizeViewport: props.autoResizeViewport,
|
|
60
|
+
autoResizeDrawingBuffer: props.autoResizeDrawingBuffer,
|
|
61
|
+
useDevicePixels
|
|
62
|
+
});
|
|
63
|
+
// Bind methods
|
|
64
|
+
this.start = this.start.bind(this);
|
|
65
|
+
this.stop = this.stop.bind(this);
|
|
66
|
+
this._onMousemove = this._onMousemove.bind(this);
|
|
67
|
+
this._onMouseleave = this._onMouseleave.bind(this);
|
|
68
|
+
}
|
|
69
|
+
destroy() {
|
|
70
|
+
this.stop();
|
|
71
|
+
this._setDisplay(null);
|
|
72
|
+
}
|
|
73
|
+
/** @deprecated Use .destroy() */
|
|
74
|
+
delete() {
|
|
75
|
+
this.destroy();
|
|
76
|
+
}
|
|
77
|
+
/** Flags this animation loop as needing redraw */
|
|
78
|
+
setNeedsRedraw(reason) {
|
|
79
|
+
this.needsRedraw = this.needsRedraw || reason;
|
|
80
|
+
return this;
|
|
81
|
+
}
|
|
82
|
+
/** TODO - move these props to CanvasContext? */
|
|
83
|
+
setProps(props) {
|
|
84
|
+
if ('autoResizeViewport' in props) {
|
|
85
|
+
this.props.autoResizeViewport = props.autoResizeViewport || false;
|
|
86
|
+
}
|
|
87
|
+
if ('autoResizeDrawingBuffer' in props) {
|
|
88
|
+
this.props.autoResizeDrawingBuffer = props.autoResizeDrawingBuffer || false;
|
|
89
|
+
}
|
|
90
|
+
if ('useDevicePixels' in props) {
|
|
91
|
+
this.props.useDevicePixels = props.useDevicePixels || false;
|
|
92
|
+
}
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/** Starts a render loop if not already running */
|
|
96
|
+
async start() {
|
|
97
|
+
if (this._running) {
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
this._running = true;
|
|
101
|
+
try {
|
|
102
|
+
let appContext;
|
|
103
|
+
if (!this._initialized) {
|
|
104
|
+
this._initialized = true;
|
|
105
|
+
// Create the WebGL context
|
|
106
|
+
await this._initDevice();
|
|
107
|
+
this._initialize();
|
|
108
|
+
// Note: onIntialize can return a promise (e.g. in case app needs to load resources)
|
|
109
|
+
await this.props.onInitialize(this._getAnimationProps());
|
|
110
|
+
}
|
|
111
|
+
// check that we haven't been stopped
|
|
112
|
+
if (!this._running) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
// Start the loop
|
|
116
|
+
if (appContext !== false) {
|
|
117
|
+
// cancel any pending renders to ensure only one loop can ever run
|
|
118
|
+
this._cancelAnimationFrame();
|
|
119
|
+
this._requestAnimationFrame();
|
|
120
|
+
}
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const error = err instanceof Error ? err : new Error('Unknown error');
|
|
125
|
+
this.props.onError(error);
|
|
126
|
+
// this._running = false; // TODO
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** Stops a render loop if already running, finalizing */
|
|
131
|
+
stop() {
|
|
132
|
+
// console.debug(`Stopping ${this.constructor.name}`);
|
|
133
|
+
if (this._running) {
|
|
134
|
+
// call callback
|
|
135
|
+
// If stop is called immediately, we can end up in a state where props haven't been initialized...
|
|
136
|
+
if (this.animationProps) {
|
|
137
|
+
this.props.onFinalize(this.animationProps);
|
|
138
|
+
}
|
|
139
|
+
this._cancelAnimationFrame();
|
|
140
|
+
this._nextFramePromise = null;
|
|
141
|
+
this._resolveNextFrame = null;
|
|
142
|
+
this._running = false;
|
|
143
|
+
}
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
/** Explicitly draw a frame */
|
|
147
|
+
redraw() {
|
|
148
|
+
if (this.device?.isLost) {
|
|
149
|
+
return this;
|
|
150
|
+
}
|
|
151
|
+
this._beginFrameTimers();
|
|
152
|
+
this._setupFrame();
|
|
153
|
+
this._updateAnimationProps();
|
|
154
|
+
this._renderFrame(this._getAnimationProps());
|
|
155
|
+
// clear needsRedraw flag
|
|
156
|
+
this._clearNeedsRedraw();
|
|
157
|
+
if (this._resolveNextFrame) {
|
|
158
|
+
this._resolveNextFrame(this);
|
|
159
|
+
this._nextFramePromise = null;
|
|
160
|
+
this._resolveNextFrame = null;
|
|
161
|
+
}
|
|
162
|
+
this._endFrameTimers();
|
|
163
|
+
return this;
|
|
164
|
+
}
|
|
165
|
+
/** Add a timeline, it will be automatically updated by the animation loop. */
|
|
166
|
+
attachTimeline(timeline) {
|
|
167
|
+
this.timeline = timeline;
|
|
168
|
+
return this.timeline;
|
|
169
|
+
}
|
|
170
|
+
/** Remove a timeline */
|
|
171
|
+
detachTimeline() {
|
|
172
|
+
this.timeline = null;
|
|
173
|
+
}
|
|
174
|
+
/** Wait until a render completes */
|
|
175
|
+
waitForRender() {
|
|
176
|
+
this.setNeedsRedraw('waitForRender');
|
|
177
|
+
if (!this._nextFramePromise) {
|
|
178
|
+
this._nextFramePromise = new Promise(resolve => {
|
|
179
|
+
this._resolveNextFrame = resolve;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
return this._nextFramePromise;
|
|
183
|
+
}
|
|
184
|
+
/** TODO - should use device.deviceContext */
|
|
185
|
+
async toDataURL() {
|
|
186
|
+
this.setNeedsRedraw('toDataURL');
|
|
187
|
+
await this.waitForRender();
|
|
188
|
+
if (this.canvas instanceof HTMLCanvasElement) {
|
|
189
|
+
return this.canvas.toDataURL();
|
|
190
|
+
}
|
|
191
|
+
throw new Error('OffscreenCanvas');
|
|
192
|
+
}
|
|
193
|
+
// PRIVATE METHODS
|
|
194
|
+
_initialize() {
|
|
195
|
+
this._startEventHandling();
|
|
196
|
+
// Initialize the callback data
|
|
197
|
+
this._initializeAnimationProps();
|
|
198
|
+
this._updateAnimationProps();
|
|
199
|
+
// Default viewport setup, in case onInitialize wants to render
|
|
200
|
+
this._resizeCanvasDrawingBuffer();
|
|
201
|
+
this._resizeViewport();
|
|
202
|
+
// this._gpuTimeQuery = Query.isSupported(this.gl, ['timers']) ? new Query(this.gl) : null;
|
|
203
|
+
}
|
|
204
|
+
_setDisplay(display) {
|
|
205
|
+
if (this.display) {
|
|
206
|
+
this.display.destroy();
|
|
207
|
+
this.display.animationLoop = null;
|
|
208
|
+
}
|
|
209
|
+
// store animation loop on the display
|
|
210
|
+
if (display) {
|
|
211
|
+
display.animationLoop = this;
|
|
212
|
+
}
|
|
213
|
+
this.display = display;
|
|
214
|
+
}
|
|
215
|
+
_requestAnimationFrame() {
|
|
216
|
+
if (!this._running) {
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
// VR display has a separate animation frame to sync with headset
|
|
220
|
+
// TODO WebVR API discontinued, replaced by WebXR: https://immersive-web.github.io/webxr/
|
|
221
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/requestAnimationFrame
|
|
222
|
+
// if (this.display && this.display.requestAnimationFrame) {
|
|
223
|
+
// this._animationFrameId = this.display.requestAnimationFrame(this._animationFrame.bind(this));
|
|
224
|
+
// }
|
|
225
|
+
this._animationFrameId = requestAnimationFrame(this._animationFrame.bind(this));
|
|
226
|
+
}
|
|
227
|
+
_cancelAnimationFrame() {
|
|
228
|
+
if (this._animationFrameId === null) {
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
// VR display has a separate animation frame to sync with headset
|
|
232
|
+
// TODO WebVR API discontinued, replaced by WebXR: https://immersive-web.github.io/webxr/
|
|
233
|
+
// See https://developer.mozilla.org/en-US/docs/Web/API/VRDisplay/requestAnimationFrame
|
|
234
|
+
// if (this.display && this.display.cancelAnimationFrame) {
|
|
235
|
+
// this.display.cancelAnimationFrame(this._animationFrameId);
|
|
236
|
+
// }
|
|
237
|
+
cancelAnimationFrame(this._animationFrameId);
|
|
238
|
+
this._animationFrameId = null;
|
|
239
|
+
}
|
|
240
|
+
_animationFrame() {
|
|
241
|
+
if (!this._running) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
this.redraw();
|
|
106
245
|
this._requestAnimationFrame();
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
_getSizeAndAspect() {
|
|
307
|
-
var _this$device3, _this$device4;
|
|
308
|
-
if (!this.device) {
|
|
309
|
-
return {
|
|
310
|
-
width: 1,
|
|
311
|
-
height: 1,
|
|
312
|
-
aspect: 1
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
const [width, height] = ((_this$device3 = this.device) === null || _this$device3 === void 0 || (_this$device3 = _this$device3.canvasContext) === null || _this$device3 === void 0 ? void 0 : _this$device3.getPixelSize()) || [1, 1];
|
|
316
|
-
let aspect = 1;
|
|
317
|
-
const canvas = (_this$device4 = this.device) === null || _this$device4 === void 0 || (_this$device4 = _this$device4.canvasContext) === null || _this$device4 === void 0 ? void 0 : _this$device4.canvas;
|
|
318
|
-
if (canvas && canvas.clientHeight) {
|
|
319
|
-
aspect = canvas.clientWidth / canvas.clientHeight;
|
|
320
|
-
} else if (width > 0 && height > 0) {
|
|
321
|
-
aspect = width / height;
|
|
322
|
-
}
|
|
323
|
-
return {
|
|
324
|
-
width,
|
|
325
|
-
height,
|
|
326
|
-
aspect
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
_resizeViewport() {
|
|
330
|
-
if (this.props.autoResizeViewport && this.device.gl) {
|
|
331
|
-
this.device.gl.viewport(0, 0, this.device.gl.drawingBufferWidth, this.device.gl.drawingBufferHeight);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
_resizeCanvasDrawingBuffer() {
|
|
335
|
-
if (this.props.autoResizeDrawingBuffer) {
|
|
336
|
-
var _this$device5;
|
|
337
|
-
(_this$device5 = this.device) === null || _this$device5 === void 0 || (_this$device5 = _this$device5.canvasContext) === null || _this$device5 === void 0 ? void 0 : _this$device5.resize({
|
|
338
|
-
useDevicePixels: this.props.useDevicePixels
|
|
339
|
-
});
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
_beginFrameTimers() {
|
|
343
|
-
this.frameRate.timeEnd();
|
|
344
|
-
this.frameRate.timeStart();
|
|
345
|
-
this.cpuTime.timeStart();
|
|
346
|
-
}
|
|
347
|
-
_endFrameTimers() {
|
|
348
|
-
this.cpuTime.timeEnd();
|
|
349
|
-
}
|
|
350
|
-
_startEventHandling() {
|
|
351
|
-
if (this.canvas) {
|
|
352
|
-
this.canvas.addEventListener('mousemove', this._onMousemove.bind(this));
|
|
353
|
-
this.canvas.addEventListener('mouseleave', this._onMouseleave.bind(this));
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
_onMousemove(event) {
|
|
357
|
-
if (event instanceof MouseEvent) {
|
|
358
|
-
this._getAnimationProps()._mousePosition = [event.offsetX, event.offsetY];
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
_onMouseleave(event) {
|
|
362
|
-
this._getAnimationProps()._mousePosition = null;
|
|
363
|
-
}
|
|
246
|
+
}
|
|
247
|
+
// Called on each frame, can be overridden to call onRender multiple times
|
|
248
|
+
// to support e.g. stereoscopic rendering
|
|
249
|
+
_renderFrame(animationProps) {
|
|
250
|
+
// Allow e.g. VR display to render multiple frames.
|
|
251
|
+
if (this.display) {
|
|
252
|
+
this.display._renderFrame(animationProps);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// call callback
|
|
256
|
+
this.props.onRender(this._getAnimationProps());
|
|
257
|
+
// end callback
|
|
258
|
+
// Submit commands (necessary on WebGPU)
|
|
259
|
+
this.device.submit();
|
|
260
|
+
}
|
|
261
|
+
_clearNeedsRedraw() {
|
|
262
|
+
this.needsRedraw = false;
|
|
263
|
+
}
|
|
264
|
+
_setupFrame() {
|
|
265
|
+
this._resizeCanvasDrawingBuffer();
|
|
266
|
+
this._resizeViewport();
|
|
267
|
+
}
|
|
268
|
+
// Initialize the object that will be passed to app callbacks
|
|
269
|
+
_initializeAnimationProps() {
|
|
270
|
+
if (!this.device) {
|
|
271
|
+
throw new Error('loop');
|
|
272
|
+
}
|
|
273
|
+
this.animationProps = {
|
|
274
|
+
animationLoop: this,
|
|
275
|
+
device: this.device,
|
|
276
|
+
canvas: this.device?.canvasContext?.canvas,
|
|
277
|
+
timeline: this.timeline,
|
|
278
|
+
// Initial values
|
|
279
|
+
useDevicePixels: this.props.useDevicePixels,
|
|
280
|
+
needsRedraw: false,
|
|
281
|
+
// Placeholders
|
|
282
|
+
width: 1,
|
|
283
|
+
height: 1,
|
|
284
|
+
aspect: 1,
|
|
285
|
+
// Animation props
|
|
286
|
+
time: 0,
|
|
287
|
+
startTime: Date.now(),
|
|
288
|
+
engineTime: 0,
|
|
289
|
+
tick: 0,
|
|
290
|
+
tock: 0,
|
|
291
|
+
// Experimental
|
|
292
|
+
_mousePosition: null // Event props
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
_getAnimationProps() {
|
|
296
|
+
if (!this.animationProps) {
|
|
297
|
+
throw new Error('animationProps');
|
|
298
|
+
}
|
|
299
|
+
return this.animationProps;
|
|
300
|
+
}
|
|
301
|
+
// Update the context object that will be passed to app callbacks
|
|
302
|
+
_updateAnimationProps() {
|
|
303
|
+
if (!this.animationProps) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
// Can this be replaced with canvas context?
|
|
307
|
+
const { width, height, aspect } = this._getSizeAndAspect();
|
|
308
|
+
if (width !== this.animationProps.width || height !== this.animationProps.height) {
|
|
309
|
+
this.setNeedsRedraw('drawing buffer resized');
|
|
310
|
+
}
|
|
311
|
+
if (aspect !== this.animationProps.aspect) {
|
|
312
|
+
this.setNeedsRedraw('drawing buffer aspect changed');
|
|
313
|
+
}
|
|
314
|
+
this.animationProps.width = width;
|
|
315
|
+
this.animationProps.height = height;
|
|
316
|
+
this.animationProps.aspect = aspect;
|
|
317
|
+
this.animationProps.needsRedraw = this.needsRedraw;
|
|
318
|
+
// Update time properties
|
|
319
|
+
this.animationProps.engineTime = Date.now() - this.animationProps.startTime;
|
|
320
|
+
if (this.timeline) {
|
|
321
|
+
this.timeline.update(this.animationProps.engineTime);
|
|
322
|
+
}
|
|
323
|
+
this.animationProps.tick = Math.floor((this.animationProps.time / 1000) * 60);
|
|
324
|
+
this.animationProps.tock++;
|
|
325
|
+
// For back compatibility
|
|
326
|
+
this.animationProps.time = this.timeline
|
|
327
|
+
? this.timeline.getTime()
|
|
328
|
+
: this.animationProps.engineTime;
|
|
329
|
+
}
|
|
330
|
+
/** Wait for supplied device */
|
|
331
|
+
async _initDevice() {
|
|
332
|
+
this.device = await this.props.device;
|
|
333
|
+
if (!this.device) {
|
|
334
|
+
throw new Error('No device provided');
|
|
335
|
+
}
|
|
336
|
+
this.canvas = this.device.canvasContext?.canvas || null;
|
|
337
|
+
// this._createInfoDiv();
|
|
338
|
+
}
|
|
339
|
+
_createInfoDiv() {
|
|
340
|
+
if (this.canvas && this.props.onAddHTML) {
|
|
341
|
+
const wrapperDiv = document.createElement('div');
|
|
342
|
+
document.body.appendChild(wrapperDiv);
|
|
343
|
+
wrapperDiv.style.position = 'relative';
|
|
344
|
+
const div = document.createElement('div');
|
|
345
|
+
div.style.position = 'absolute';
|
|
346
|
+
div.style.left = '10px';
|
|
347
|
+
div.style.bottom = '10px';
|
|
348
|
+
div.style.width = '300px';
|
|
349
|
+
div.style.background = 'white';
|
|
350
|
+
if (this.canvas instanceof HTMLCanvasElement) {
|
|
351
|
+
wrapperDiv.appendChild(this.canvas);
|
|
352
|
+
}
|
|
353
|
+
wrapperDiv.appendChild(div);
|
|
354
|
+
const html = this.props.onAddHTML(div);
|
|
355
|
+
if (html) {
|
|
356
|
+
div.innerHTML = html;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
_getSizeAndAspect() {
|
|
361
|
+
if (!this.device) {
|
|
362
|
+
return { width: 1, height: 1, aspect: 1 };
|
|
363
|
+
}
|
|
364
|
+
// https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
|
|
365
|
+
const [width, height] = this.device?.canvasContext?.getPixelSize() || [1, 1];
|
|
366
|
+
// https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
|
|
367
|
+
let aspect = 1;
|
|
368
|
+
const canvas = this.device?.canvasContext?.canvas;
|
|
369
|
+
// @ts-expect-error
|
|
370
|
+
if (canvas && canvas.clientHeight) {
|
|
371
|
+
// @ts-expect-error
|
|
372
|
+
aspect = canvas.clientWidth / canvas.clientHeight;
|
|
373
|
+
}
|
|
374
|
+
else if (width > 0 && height > 0) {
|
|
375
|
+
aspect = width / height;
|
|
376
|
+
}
|
|
377
|
+
return { width, height, aspect };
|
|
378
|
+
}
|
|
379
|
+
/** Default viewport setup */
|
|
380
|
+
_resizeViewport() {
|
|
381
|
+
// TODO can we use canvas context to code this in a portable way?
|
|
382
|
+
// @ts-expect-error Expose on canvasContext
|
|
383
|
+
if (this.props.autoResizeViewport && this.device.gl) {
|
|
384
|
+
// @ts-expect-error Expose canvasContext
|
|
385
|
+
this.device.gl.viewport(0, 0,
|
|
386
|
+
// @ts-expect-error Expose canvasContext
|
|
387
|
+
this.device.gl.drawingBufferWidth,
|
|
388
|
+
// @ts-expect-error Expose canvasContext
|
|
389
|
+
this.device.gl.drawingBufferHeight);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Resize the render buffer of the canvas to match canvas client size
|
|
394
|
+
* Optionally multiplying with devicePixel ratio
|
|
395
|
+
*/
|
|
396
|
+
_resizeCanvasDrawingBuffer() {
|
|
397
|
+
if (this.props.autoResizeDrawingBuffer) {
|
|
398
|
+
this.device?.canvasContext?.resize({ useDevicePixels: this.props.useDevicePixels });
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
_beginFrameTimers() {
|
|
402
|
+
this.frameRate.timeEnd();
|
|
403
|
+
this.frameRate.timeStart();
|
|
404
|
+
// Check if timer for last frame has completed.
|
|
405
|
+
// GPU timer results are never available in the same
|
|
406
|
+
// frame they are captured.
|
|
407
|
+
// if (
|
|
408
|
+
// this._gpuTimeQuery &&
|
|
409
|
+
// this._gpuTimeQuery.isResultAvailable() &&
|
|
410
|
+
// !this._gpuTimeQuery.isTimerDisjoint()
|
|
411
|
+
// ) {
|
|
412
|
+
// this.stats.get('GPU Time').addTime(this._gpuTimeQuery.getTimerMilliseconds());
|
|
413
|
+
// }
|
|
414
|
+
// if (this._gpuTimeQuery) {
|
|
415
|
+
// // GPU time query start
|
|
416
|
+
// this._gpuTimeQuery.beginTimeElapsedQuery();
|
|
417
|
+
// }
|
|
418
|
+
this.cpuTime.timeStart();
|
|
419
|
+
}
|
|
420
|
+
_endFrameTimers() {
|
|
421
|
+
this.cpuTime.timeEnd();
|
|
422
|
+
// if (this._gpuTimeQuery) {
|
|
423
|
+
// // GPU time query end. Results will be available on next frame.
|
|
424
|
+
// this._gpuTimeQuery.end();
|
|
425
|
+
// }
|
|
426
|
+
}
|
|
427
|
+
// Event handling
|
|
428
|
+
_startEventHandling() {
|
|
429
|
+
if (this.canvas) {
|
|
430
|
+
this.canvas.addEventListener('mousemove', this._onMousemove.bind(this));
|
|
431
|
+
this.canvas.addEventListener('mouseleave', this._onMouseleave.bind(this));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
_onMousemove(event) {
|
|
435
|
+
if (event instanceof MouseEvent) {
|
|
436
|
+
this._getAnimationProps()._mousePosition = [event.offsetX, event.offsetY];
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
_onMouseleave(event) {
|
|
440
|
+
this._getAnimationProps()._mousePosition = null;
|
|
441
|
+
}
|
|
364
442
|
}
|
|
365
|
-
//# sourceMappingURL=animation-loop.js.map
|