@luma.gl/engine 9.0.0-alpha.14 → 9.0.0-alpha.16

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