@luma.gl/engine 9.0.0-alpha.9 → 9.0.0-beta.2

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 (191) hide show
  1. package/LICENSE +3 -1
  2. package/dist/animation/key-frames.d.ts +1 -1
  3. package/dist/animation/key-frames.d.ts.map +1 -1
  4. package/dist/animation/key-frames.js +6 -27
  5. package/dist/animation/key-frames.js.map +1 -1
  6. package/dist/animation/timeline.d.ts +8 -8
  7. package/dist/animation/timeline.d.ts.map +1 -1
  8. package/dist/animation/timeline.js +18 -49
  9. package/dist/animation/timeline.js.map +1 -1
  10. package/dist/animation-loop/animation-loop-template.d.ts +23 -0
  11. package/dist/animation-loop/animation-loop-template.d.ts.map +1 -0
  12. package/dist/animation-loop/animation-loop-template.js +7 -0
  13. package/dist/animation-loop/animation-loop-template.js.map +1 -0
  14. package/dist/{lib → animation-loop}/animation-loop.d.ts +30 -22
  15. package/dist/animation-loop/animation-loop.d.ts.map +1 -0
  16. package/dist/{lib → animation-loop}/animation-loop.js +77 -192
  17. package/dist/animation-loop/animation-loop.js.map +1 -0
  18. package/dist/{lib → animation-loop}/animation-props.d.ts +2 -3
  19. package/dist/animation-loop/animation-props.d.ts.map +1 -0
  20. package/dist/animation-loop/animation-props.js.map +1 -0
  21. package/dist/animation-loop/make-animation-loop.d.ts +6 -0
  22. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
  23. package/dist/animation-loop/make-animation-loop.js +28 -0
  24. package/dist/animation-loop/make-animation-loop.js.map +1 -0
  25. package/dist/debug/copy-texture-to-image.d.ts +26 -0
  26. package/dist/debug/copy-texture-to-image.d.ts.map +1 -0
  27. package/dist/debug/copy-texture-to-image.js +46 -0
  28. package/dist/debug/copy-texture-to-image.js.map +1 -0
  29. package/dist/debug/debug-framebuffer.d.ts +11 -0
  30. package/dist/debug/debug-framebuffer.d.ts.map +1 -0
  31. package/dist/debug/debug-framebuffer.js +43 -0
  32. package/dist/debug/debug-framebuffer.js.map +1 -0
  33. package/dist/debug/debug-shader-layout.d.ts +9 -0
  34. package/dist/debug/debug-shader-layout.d.ts.map +1 -0
  35. package/dist/debug/debug-shader-layout.js +28 -0
  36. package/dist/debug/debug-shader-layout.js.map +1 -0
  37. package/dist/debug/pixel-data-utils.d.ts +24 -0
  38. package/dist/debug/pixel-data-utils.d.ts.map +1 -0
  39. package/dist/debug/pixel-data-utils.js +41 -0
  40. package/dist/debug/pixel-data-utils.js.map +1 -0
  41. package/dist/dist.dev.js +10073 -0
  42. package/dist/geometries/cone-geometry.d.ts +1 -1
  43. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  44. package/dist/geometries/cone-geometry.js +6 -5
  45. package/dist/geometries/cone-geometry.js.map +1 -1
  46. package/dist/geometries/cube-geometry.d.ts +2 -2
  47. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  48. package/dist/geometries/cube-geometry.js +16 -10
  49. package/dist/geometries/cube-geometry.js.map +1 -1
  50. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  51. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  52. package/dist/geometries/cylinder-geometry.js +6 -5
  53. package/dist/geometries/cylinder-geometry.js.map +1 -1
  54. package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
  55. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  56. package/dist/geometries/ico-sphere-geometry.js +10 -19
  57. package/dist/geometries/ico-sphere-geometry.js.map +1 -1
  58. package/dist/geometries/plane-geometry.d.ts +2 -2
  59. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  60. package/dist/geometries/plane-geometry.js +14 -23
  61. package/dist/geometries/plane-geometry.js.map +1 -1
  62. package/dist/geometries/sphere-geometry.d.ts +2 -2
  63. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  64. package/dist/geometries/sphere-geometry.js +9 -13
  65. package/dist/geometries/sphere-geometry.js.map +1 -1
  66. package/dist/geometries/truncated-cone-geometry.d.ts +2 -4
  67. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  68. package/dist/geometries/truncated-cone-geometry.js +9 -25
  69. package/dist/geometries/truncated-cone-geometry.js.map +1 -1
  70. package/dist/geometry/geometry-table.d.ts +2 -2
  71. package/dist/geometry/geometry-table.d.ts.map +1 -1
  72. package/dist/geometry/geometry-table.js.map +1 -1
  73. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  74. package/dist/geometry/geometry-utils.js +0 -9
  75. package/dist/geometry/geometry-utils.js.map +1 -1
  76. package/dist/geometry/geometry.d.ts +43 -43
  77. package/dist/geometry/geometry.d.ts.map +1 -1
  78. package/dist/geometry/geometry.js +20 -86
  79. package/dist/geometry/geometry.js.map +1 -1
  80. package/dist/geometry/gpu-geometry.d.ts +37 -0
  81. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  82. package/dist/geometry/gpu-geometry.js +110 -0
  83. package/dist/geometry/gpu-geometry.js.map +1 -0
  84. package/dist/geometry/gpu-table.d.ts +1 -0
  85. package/dist/geometry/gpu-table.d.ts.map +1 -0
  86. package/dist/geometry/gpu-table.js +2 -0
  87. package/dist/geometry/gpu-table.js.map +1 -0
  88. package/dist/index.cjs +3120 -0
  89. package/dist/index.d.ts +24 -8
  90. package/dist/index.d.ts.map +1 -1
  91. package/dist/index.js +23 -14
  92. package/dist/index.js.map +1 -1
  93. package/dist/lib/clip-space.d.ts +8 -0
  94. package/dist/lib/clip-space.d.ts.map +1 -1
  95. package/dist/lib/clip-space.js +47 -0
  96. package/dist/lib/clip-space.js.map +1 -1
  97. package/dist/lib/pipeline-factory.d.ts +12 -46
  98. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  99. package/dist/lib/pipeline-factory.js +36 -179
  100. package/dist/lib/pipeline-factory.js.map +1 -1
  101. package/dist/model/model.d.ts +206 -0
  102. package/dist/model/model.d.ts.map +1 -0
  103. package/dist/model/model.js +440 -0
  104. package/dist/model/model.js.map +1 -0
  105. package/dist/scenegraph/group-node.d.ts +21 -0
  106. package/dist/scenegraph/group-node.d.ts.map +1 -0
  107. package/dist/scenegraph/group-node.js +94 -0
  108. package/dist/scenegraph/group-node.js.map +1 -0
  109. package/dist/scenegraph/model-node.d.ts +18 -0
  110. package/dist/scenegraph/model-node.d.ts.map +1 -0
  111. package/dist/scenegraph/model-node.js +28 -0
  112. package/dist/scenegraph/model-node.js.map +1 -0
  113. package/dist/scenegraph/scenegraph-node.d.ts +56 -0
  114. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
  115. package/dist/scenegraph/scenegraph-node.js +141 -0
  116. package/dist/scenegraph/scenegraph-node.js.map +1 -0
  117. package/dist/shader-inputs.d.ts +63 -0
  118. package/dist/shader-inputs.d.ts.map +1 -0
  119. package/dist/shader-inputs.js +66 -0
  120. package/dist/shader-inputs.js.map +1 -0
  121. package/dist/transform/buffer-transform.d.ts +35 -0
  122. package/dist/transform/buffer-transform.d.ts.map +1 -0
  123. package/dist/transform/buffer-transform.js +62 -0
  124. package/dist/transform/buffer-transform.js.map +1 -0
  125. package/dist/transform/texture-transform.d.ts +57 -0
  126. package/dist/transform/texture-transform.d.ts.map +1 -0
  127. package/dist/transform/texture-transform.js +122 -0
  128. package/dist/transform/texture-transform.js.map +1 -0
  129. package/dist.min.js +293 -0
  130. package/package.json +21 -12
  131. package/src/animation/timeline.ts +15 -14
  132. package/src/animation-loop/animation-loop-template.ts +23 -0
  133. package/src/{lib → animation-loop}/animation-loop.ts +99 -88
  134. package/src/{lib → animation-loop}/animation-props.ts +1 -1
  135. package/src/animation-loop/make-animation-loop.ts +44 -0
  136. package/src/debug/copy-texture-to-image.ts +72 -0
  137. package/src/debug/debug-framebuffer.ts +57 -0
  138. package/src/debug/debug-shader-layout.ts +38 -0
  139. package/src/debug/pixel-data-utils.ts +57 -0
  140. package/src/geometries/cone-geometry.ts +1 -1
  141. package/src/geometries/cube-geometry.ts +47 -45
  142. package/src/geometries/cylinder-geometry.ts +2 -2
  143. package/src/geometries/ico-sphere-geometry.ts +6 -5
  144. package/src/geometries/plane-geometry.ts +5 -4
  145. package/src/geometries/sphere-geometry.ts +4 -3
  146. package/src/geometries/truncated-cone-geometry.ts +4 -13
  147. package/src/geometry/geometry-table.ts +1 -1
  148. package/src/geometry/geometry-utils.ts +19 -3
  149. package/src/geometry/geometry.ts +65 -110
  150. package/src/geometry/gpu-geometry.ts +125 -0
  151. package/src/geometry/gpu-table.ts +41 -0
  152. package/src/index.ts +34 -10
  153. package/src/lib/clip-space.ts +22 -21
  154. package/src/lib/pipeline-factory.ts +48 -179
  155. package/src/model/model.ts +733 -0
  156. package/src/scenegraph/group-node.ts +103 -0
  157. package/src/scenegraph/model-node.ts +50 -0
  158. package/src/scenegraph/scenegraph-node.ts +204 -0
  159. package/src/shader-inputs.ts +150 -0
  160. package/src/transform/buffer-transform.ts +94 -0
  161. package/src/transform/texture-transform.ts +169 -0
  162. package/dist/bundle.d.ts +0 -2
  163. package/dist/bundle.d.ts.map +0 -1
  164. package/dist/bundle.js +0 -5
  165. package/dist/bundle.js.map +0 -1
  166. package/dist/geometry/primitive-utils.d.ts +0 -1
  167. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  168. package/dist/geometry/primitive-utils.js +0 -2
  169. package/dist/geometry/primitive-utils.js.map +0 -1
  170. package/dist/lib/animation-loop.d.ts.map +0 -1
  171. package/dist/lib/animation-loop.js.map +0 -1
  172. package/dist/lib/animation-props.d.ts.map +0 -1
  173. package/dist/lib/animation-props.js.map +0 -1
  174. package/dist/lib/model-utils.d.ts +0 -5
  175. package/dist/lib/model-utils.d.ts.map +0 -1
  176. package/dist/lib/model-utils.js +0 -45
  177. package/dist/lib/model-utils.js.map +0 -1
  178. package/dist/lib/model.d.ts +0 -41
  179. package/dist/lib/model.d.ts.map +0 -1
  180. package/dist/lib/model.js +0 -182
  181. package/dist/lib/model.js.map +0 -1
  182. package/dist/lib/render-loop.d.ts +0 -14
  183. package/dist/lib/render-loop.d.ts.map +0 -1
  184. package/dist/lib/render-loop.js +0 -49
  185. package/dist/lib/render-loop.js.map +0 -1
  186. package/src/bundle.ts +0 -4
  187. package/src/geometry/primitive-utils.ts +0 -30
  188. package/src/lib/model-utils.ts +0 -124
  189. package/src/lib/model.ts +0 -183
  190. package/src/lib/render-loop.ts +0 -58
  191. /package/dist/{lib → animation-loop}/animation-props.js +0 -0
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@luma.gl/engine",
3
- "version": "9.0.0-alpha.9",
3
+ "version": "9.0.0-beta.2",
4
4
  "description": "WebGL2 Components for High Performance Rendering and Computation",
5
+ "type": "module",
5
6
  "license": "MIT",
6
7
  "publishConfig": {
7
8
  "access": "public"
@@ -16,27 +17,35 @@
16
17
  "animation",
17
18
  "3d"
18
19
  ],
19
- "types": "src/index.ts",
20
- "main": "dist/index.js",
20
+ "types": "dist/index.d.ts",
21
+ "main": "dist/index.cjs",
21
22
  "module": "dist/index.js",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./dist/index.d.ts",
26
+ "import": "./dist/index.js",
27
+ "require": "./dist/index.cjs"
28
+ }
29
+ },
22
30
  "files": [
23
31
  "src",
24
32
  "dist",
33
+ "dist.min.js",
25
34
  "README.md"
26
35
  ],
27
36
  "sideEffects": false,
28
37
  "scripts": {
29
- "pre-build": "npm run build-bundle",
30
- "build-bundle": "webpack --display=minimal --config ../../scripts/bundle.config.js"
38
+ "build-bundle": "ocular-bundle ./src/index.ts",
39
+ "pre-build": "npm run build-bundle && npm run build-bundle -- --env=dev"
31
40
  },
32
41
  "dependencies": {
33
42
  "@babel/runtime": "^7.0.0",
34
- "@luma.gl/constants": "9.0.0-alpha.9",
35
- "@luma.gl/shadertools": "9.0.0-alpha.9",
36
- "@luma.gl/webgl": "9.0.0-alpha.9",
37
- "@math.gl/core": "^3.5.0",
38
- "@probe.gl/log": "^3.5.0",
39
- "@probe.gl/stats": "^3.5.0"
43
+ "@luma.gl/constants": "9.0.0-beta.2",
44
+ "@luma.gl/core": "9.0.0-beta.2",
45
+ "@luma.gl/shadertools": "9.0.0-beta.2",
46
+ "@math.gl/core": "^4.0.0",
47
+ "@probe.gl/log": "^4.0.2",
48
+ "@probe.gl/stats": "^4.0.2"
40
49
  },
41
- "gitHead": "b84aae16edcdee2be84d2861c81cc6584e336b28"
50
+ "gitHead": "d90ddd6231c3d405d88dfb9e8c232c4dfefcc056"
42
51
  }
@@ -1,4 +1,5 @@
1
1
  // luma.gl, MIT license
2
+ // Copyright (c) vis.gl contributors
2
3
 
3
4
  /**
4
5
  * Timeline channel properties
@@ -7,7 +8,7 @@
7
8
  * @param rate = 1
8
9
  * @param repeat = 1
9
10
  */
10
- export type ChannelOptions = {
11
+ export type ChannelOptions = {
11
12
  delay?: number
12
13
  duration?: number
13
14
  rate?: number
@@ -49,7 +50,7 @@ export class Timeline {
49
50
  addChannel(props: ChannelOptions): number {
50
51
  const {delay = 0, duration = Number.POSITIVE_INFINITY, rate = 1, repeat = 1} = props;
51
52
 
52
- const handle = channelHandles++;
53
+ const channelId = channelHandles++;
53
54
  const channel: Channel = {
54
55
  time: 0,
55
56
  delay,
@@ -58,23 +59,23 @@ export class Timeline {
58
59
  repeat
59
60
  };
60
61
  this._setChannelTime(channel, this.time);
61
- this.channels.set(handle, channel);
62
+ this.channels.set(channelId, channel);
62
63
 
63
- return handle;
64
+ return channelId;
64
65
  }
65
66
 
66
- removeChannel(handle: number): void {
67
- this.channels.delete(handle);
67
+ removeChannel(channelId: number): void {
68
+ this.channels.delete(channelId);
68
69
 
69
70
  for (const [animationHandle, animation] of this.animations) {
70
- if (animation.channel === handle) {
71
+ if (animation.channel === channelId) {
71
72
  this.detachAnimation(animationHandle);
72
73
  }
73
74
  }
74
75
  }
75
76
 
76
- isFinished(handle: number): boolean {
77
- const channel = this.channels.get(handle);
77
+ isFinished(channelId: number): boolean {
78
+ const channel = this.channels.get(channelId);
78
79
  if (channel === undefined) {
79
80
  return false;
80
81
  }
@@ -82,12 +83,12 @@ export class Timeline {
82
83
  return this.time >= channel.delay + channel.duration * channel.repeat;
83
84
  }
84
85
 
85
- getTime(handle?: number): number {
86
- if (handle === undefined) {
86
+ getTime(channelId?: number): number {
87
+ if (channelId === undefined) {
87
88
  return this.time;
88
89
  }
89
90
 
90
- const channel = this.channels.get(handle);
91
+ const channel = this.channels.get(channelId);
91
92
 
92
93
  if (channel === undefined) {
93
94
  return -1;
@@ -137,8 +138,8 @@ export class Timeline {
137
138
  return animationHandle;
138
139
  }
139
140
 
140
- detachAnimation(handle: number): void {
141
- this.animations.delete(handle);
141
+ detachAnimation(channelId: number): void {
142
+ this.animations.delete(channelId);
142
143
  }
143
144
 
144
145
  update(engineTime: number): void {
@@ -0,0 +1,23 @@
1
+ import type {AnimationProps} from './animation-props';
2
+
3
+ /**
4
+ * Minimal class that represents a "componentized" rendering life cycle
5
+ * (resource construction, repeated rendering, resource destruction)
6
+ *
7
+ * @note A motivation for this class compared to the raw animation loop is
8
+ * that it simplifies TypeScript code by allowing resources to be typed unconditionally
9
+ * since they are allocated in the constructor rather than in onInitialized
10
+ *
11
+ * @note Introduced in luma.gl v9
12
+ *
13
+ * @example AnimationLoopTemplate is intended to be subclassed,
14
+ * but the subclass should not be instantiated directly. Instead the subclass
15
+ * (i.e. the constructor of the subclass) should be used
16
+ * as an argument to create an AnimationLoop.
17
+ */
18
+ export abstract class AnimationLoopTemplate {
19
+ constructor(animationProps?: AnimationProps) {}
20
+ async onInitialize(animationProps: AnimationProps): Promise<unknown> { return null; }
21
+ abstract onRender(animationProps: AnimationProps): unknown;
22
+ abstract onFinalize(animationProps: AnimationProps): void;
23
+ }
@@ -1,53 +1,54 @@
1
- import {luma, Device, DeviceProps} from '@luma.gl/api';
2
- import {requestAnimationFrame, cancelAnimationFrame} from '@luma.gl/api';
1
+ // luma.gl, MIT license
2
+ // Copyright (c) vis.gl contributors
3
+
4
+ import {luma, Device} from '@luma.gl/core';
5
+ import {requestAnimationFrame, cancelAnimationFrame} from '@luma.gl/core';
3
6
  import {Timeline} from '../animation/timeline';
4
- import {AnimationProps} from '../lib/animation-props';
7
+ import {AnimationProps} from './animation-props';
5
8
  import {Stats, Stat} from '@probe.gl/stats';
6
- import {isBrowser} from '@probe.gl/env';
7
-
8
- const isPage = isBrowser() && typeof document !== 'undefined';
9
9
 
10
10
  let statIdCounter = 0;
11
11
 
12
- type ContextProps = DeviceProps;
13
-
14
12
  /** AnimationLoop properties */
15
13
  export type AnimationLoopProps = {
16
- onCreateDevice?: (props: DeviceProps) => Promise<Device>;
14
+ device: Device | Promise<Device>;
15
+
17
16
  onAddHTML?: (div: HTMLDivElement) => string; // innerHTML
18
- onInitialize?: (animationProps: AnimationProps) => void;
19
- onRender?: (animationProps: AnimationProps) => void;
17
+ onInitialize?: (animationProps: AnimationProps) => Promise<unknown>;
18
+ onRender?: (animationProps: AnimationProps) => unknown;
20
19
  onFinalize?: (animationProps: AnimationProps) => void;
21
20
  onError?: (reason: Error) => void;
22
21
 
23
- device?: Device | null;
24
- deviceProps?: DeviceProps;
25
22
  stats?: Stats;
26
23
 
27
- // view parameters
28
- debug?: boolean;
24
+ // view parameters - TODO move to CanvasContext?
29
25
  autoResizeViewport?: boolean;
30
26
  autoResizeDrawingBuffer?: boolean;
31
27
  useDevicePixels?: number | boolean;
32
28
  };
33
29
 
30
+ export type MutableAnimationLoopProps = {
31
+ // view parameters
32
+ autoResizeViewport?: boolean;
33
+ autoResizeDrawingBuffer?: boolean;
34
+ useDevicePixels?: number | boolean;
35
+ }
36
+
34
37
  const DEFAULT_ANIMATION_LOOP_PROPS: Required<AnimationLoopProps> = {
35
- onCreateDevice: (props: DeviceProps): Promise<Device> => luma.createDevice(props),
38
+ device: null!,
39
+
36
40
  onAddHTML: () => '',
37
- onInitialize: () => ({}),
41
+ onInitialize: async () => { return null; },
38
42
  onRender: () => {},
39
43
  onFinalize: () => {},
40
44
  onError: (error) => console.error(error), // eslint-disable-line no-console
41
45
 
42
- device: null,
43
- deviceProps: {},
44
- debug: false,
45
46
  stats: luma.stats.get(`animation-loop-${statIdCounter++}`),
46
47
 
47
48
  // view parameters
48
49
  useDevicePixels: true,
49
- autoResizeViewport: true,
50
- autoResizeDrawingBuffer: true,
50
+ autoResizeViewport: false,
51
+ autoResizeDrawingBuffer: false,
51
52
  };
52
53
 
53
54
  /** Convenient animation loop */
@@ -71,7 +72,7 @@ export class AnimationLoop {
71
72
  _running: boolean = false;
72
73
  _animationFrameId: any = null;
73
74
  _nextFramePromise: Promise<AnimationLoop> | null = null;
74
- _resolveNextFrame: ((AnimationLoop) => void) | null = null;
75
+ _resolveNextFrame: ((animationLoop: AnimationLoop) => void) | null = null;
75
76
  _cpuStartTime: number = 0;
76
77
 
77
78
  // _gpuTimeQuery: Query | null = null;
@@ -79,17 +80,17 @@ export class AnimationLoop {
79
80
  /*
80
81
  * @param {HTMLCanvasElement} canvas - if provided, width and height will be passed to context
81
82
  */
82
- constructor(props: AnimationLoopProps = {}) {
83
+ constructor(props: AnimationLoopProps) {
83
84
  this.props = {...DEFAULT_ANIMATION_LOOP_PROPS, ...props};
84
85
  props = this.props;
85
86
 
86
- let {useDevicePixels = true} = this.props;
87
+ if (!props.device) {
88
+ throw new Error('No device provided');
89
+ }
87
90
 
88
- // state
89
- this.device = props.device || null;
90
- // @ts-expect-error
91
- this.gl = (this.device && this.device.gl) || props.gl;
91
+ const {useDevicePixels = true} = this.props;
92
92
 
93
+ // state
93
94
  this.stats = props.stats || new Stats({id: 'animation-loop-stats'});
94
95
  this.cpuTime = this.stats.get('CPU Time');
95
96
  this.gpuTime = this.stats.get('GPU Time');
@@ -119,13 +120,14 @@ export class AnimationLoop {
119
120
  this.destroy();
120
121
  }
121
122
 
123
+ /** Flags this animation loop as needing redraw */
122
124
  setNeedsRedraw(reason: string): this {
123
125
  this.needsRedraw = this.needsRedraw || reason;
124
126
  return this;
125
127
  }
126
128
 
127
- // TODO - move to CanvasContext
128
- setProps(props: AnimationLoopProps): this {
129
+ /** TODO - move these props to CanvasContext? */
130
+ setProps(props: MutableAnimationLoopProps): this {
129
131
  if ('autoResizeViewport' in props) {
130
132
  this.props.autoResizeViewport = props.autoResizeViewport || false;
131
133
  }
@@ -146,16 +148,12 @@ export class AnimationLoop {
146
148
  this._running = true;
147
149
 
148
150
  try {
149
- // check that we haven't been stopped
150
- if (!this._running) {
151
- return null;
152
- }
153
151
 
154
152
  let appContext;
155
153
  if (!this._initialized) {
156
154
  this._initialized = true;
157
155
  // Create the WebGL context
158
- await this._createDevice();
156
+ await this._initDevice();
159
157
  this._initialize();
160
158
 
161
159
  // Note: onIntialize can return a promise (e.g. in case app needs to load resources)
@@ -183,13 +181,31 @@ export class AnimationLoop {
183
181
  }
184
182
  }
185
183
 
184
+ /** Stops a render loop if already running, finalizing */
185
+ stop() {
186
+ // console.debug(`Stopping ${this.constructor.name}`);
187
+ if (this._running) {
188
+ // call callback
189
+ // If stop is called immediately, we can end up in a state where props haven't been initialized...
190
+ if (this.animationProps) {
191
+ this.props.onFinalize(this.animationProps);
192
+ }
193
+
194
+ this._cancelAnimationFrame();
195
+ this._nextFramePromise = null;
196
+ this._resolveNextFrame = null;
197
+ this._running = false;
198
+ }
199
+ return this;
200
+ }
201
+
186
202
  /** Explicitly draw a frame */
187
203
  redraw(): this {
188
204
  if (this.device?.isLost) {
189
205
  return this;
190
206
  }
191
207
 
192
- this._beginTimers();
208
+ this._beginFrameTimers();
193
209
 
194
210
  this._setupFrame();
195
211
  this._updateAnimationProps();
@@ -205,38 +221,23 @@ export class AnimationLoop {
205
221
  this._resolveNextFrame = null;
206
222
  }
207
223
 
208
- this._endTimers();
224
+ this._endFrameTimers();
209
225
 
210
226
  return this;
211
227
  }
212
228
 
213
- // Stops a render loop if already running, finalizing
214
- stop() {
215
- // console.debug(`Stopping ${this.constructor.name}`);
216
- if (this._running) {
217
- // call callback
218
- // If stop is called immediately, we can end up in a state where props haven't been initialized...
219
- if (this.animationProps) {
220
- this.props.onFinalize(this.animationProps);
221
- }
222
-
223
- this._cancelAnimationFrame();
224
- this._nextFramePromise = null;
225
- this._resolveNextFrame = null;
226
- this._running = false;
227
- }
228
- return this;
229
- }
230
-
229
+ /** Add a timeline, it will be automatically updated by the animation loop. */
231
230
  attachTimeline(timeline: Timeline): Timeline {
232
231
  this.timeline = timeline;
233
232
  return this.timeline;
234
233
  }
235
234
 
235
+ /** Remove a timeline */
236
236
  detachTimeline(): void {
237
237
  this.timeline = null;
238
238
  }
239
239
 
240
+ /** Wait until a render completes */
240
241
  waitForRender(): Promise<AnimationLoop> {
241
242
  this.setNeedsRedraw('waitForRender');
242
243
 
@@ -248,6 +249,7 @@ export class AnimationLoop {
248
249
  return this._nextFramePromise;
249
250
  }
250
251
 
252
+ /** TODO - should use device.deviceContext */
251
253
  async toDataURL(): Promise<string> {
252
254
  this.setNeedsRedraw('toDataURL');
253
255
  await this.waitForRender();
@@ -259,7 +261,7 @@ export class AnimationLoop {
259
261
 
260
262
  // PRIVATE METHODS
261
263
 
262
- _initialize() {
264
+ _initialize(): void {
263
265
  this._startEventHandling();
264
266
 
265
267
  // Initialize the callback data
@@ -273,9 +275,9 @@ export class AnimationLoop {
273
275
  // this._gpuTimeQuery = Query.isSupported(this.gl, ['timers']) ? new Query(this.gl) : null;
274
276
  }
275
277
 
276
- _setDisplay(display) {
278
+ _setDisplay(display: any): void {
277
279
  if (this.display) {
278
- this.display.delete();
280
+ this.display.destroy();
279
281
  this.display.animationLoop = null;
280
282
  }
281
283
 
@@ -287,7 +289,7 @@ export class AnimationLoop {
287
289
  this.display = display;
288
290
  }
289
291
 
290
- _requestAnimationFrame() {
292
+ _requestAnimationFrame(): void {
291
293
  if (!this._running) {
292
294
  return;
293
295
  }
@@ -301,8 +303,8 @@ export class AnimationLoop {
301
303
  this._animationFrameId = requestAnimationFrame(this._animationFrame.bind(this));
302
304
  }
303
305
 
304
- _cancelAnimationFrame() {
305
- if (this._animationFrameId !== null) {
306
+ _cancelAnimationFrame(): void {
307
+ if (this._animationFrameId === null) {
306
308
  return;
307
309
  }
308
310
 
@@ -312,11 +314,11 @@ export class AnimationLoop {
312
314
  // if (this.display && this.display.cancelAnimationFrame) {
313
315
  // this.display.cancelAnimationFrame(this._animationFrameId);
314
316
  // }
315
- cancelAnimationFrame(this._animationFrameId);
317
+ cancelAnimationFrame(this._animationFrameId);
316
318
  this._animationFrameId = null;
317
319
  }
318
320
 
319
- _animationFrame() {
321
+ _animationFrame(): void {
320
322
  if (!this._running) {
321
323
  return;
322
324
  }
@@ -326,36 +328,40 @@ export class AnimationLoop {
326
328
 
327
329
  // Called on each frame, can be overridden to call onRender multiple times
328
330
  // to support e.g. stereoscopic rendering
329
- _renderFrame(props: AnimationProps) {
331
+ _renderFrame(animationProps: AnimationProps): void {
330
332
  // Allow e.g. VR display to render multiple frames.
331
333
  if (this.display) {
332
- this.display._renderFrame(props);
334
+ this.display._renderFrame(animationProps);
333
335
  return;
334
336
  }
335
337
 
336
338
  // call callback
337
- this.props.onRender(props);
339
+ this.props.onRender(this._getAnimationProps());
338
340
  // end callback
341
+
342
+ // Submit commands (necessary on WebGPU)
343
+ this.device.submit();
339
344
  }
340
345
 
341
- _clearNeedsRedraw() {
346
+ _clearNeedsRedraw(): void {
342
347
  this.needsRedraw = false;
343
348
  }
344
349
 
345
- _setupFrame() {
350
+ _setupFrame(): void {
346
351
  this._resizeCanvasDrawingBuffer();
347
352
  this._resizeViewport();
348
353
  }
349
354
 
350
355
  // Initialize the object that will be passed to app callbacks
351
- _initializeAnimationProps() {
356
+ _initializeAnimationProps(): void {
352
357
  if (!this.device) {
353
358
  throw new Error('loop');
354
359
  }
355
360
  this.animationProps = {
356
361
  animationLoop: this,
362
+
357
363
  device: this.device,
358
- canvas: this.device?.canvasContext?.canvas!,
364
+ canvas: this.device?.canvasContext?.canvas,
359
365
  timeline: this.timeline,
360
366
 
361
367
  // Initial values
@@ -392,6 +398,7 @@ export class AnimationLoop {
392
398
  return;
393
399
  }
394
400
 
401
+ // Can this be replaced with canvas context?
395
402
  const {width, height, aspect} = this._getSizeAndAspect();
396
403
  if (width !== this.animationProps.width || height !== this.animationProps.height) {
397
404
  this.setNeedsRedraw('drawing buffer resized');
@@ -422,15 +429,17 @@ export class AnimationLoop {
422
429
  : this.animationProps.engineTime;
423
430
  }
424
431
 
425
- /** Either uses supplied or existing context, or calls provided callback to create one */
426
- async _createDevice() {
427
- const deviceProps = {...this.props, ...this.props.deviceProps};
428
- this.device = await this.props.onCreateDevice(deviceProps);
429
- this.canvas = this.device.canvasContext?.canvas!;
430
- this._createInfoDiv();
432
+ /** Wait for supplied device */
433
+ async _initDevice() {
434
+ this.device = await this.props.device;
435
+ if (!this.device) {
436
+ throw new Error('No device provided');
437
+ }
438
+ this.canvas = this.device.canvasContext?.canvas || null;
439
+ // this._createInfoDiv();
431
440
  }
432
441
 
433
- _createInfoDiv() {
442
+ _createInfoDiv(): void {
434
443
  if (this.canvas && this.props.onAddHTML) {
435
444
  const wrapperDiv = document.createElement('div');
436
445
  document.body.appendChild(wrapperDiv);
@@ -475,7 +484,7 @@ export class AnimationLoop {
475
484
  }
476
485
 
477
486
  /** Default viewport setup */
478
- _resizeViewport() {
487
+ _resizeViewport(): void {
479
488
  // @ts-expect-error Expose on canvasContext
480
489
  if (this.props.autoResizeViewport && this.device.gl) {
481
490
  // @ts-expect-error Expose canvasContext
@@ -487,13 +496,13 @@ export class AnimationLoop {
487
496
  * Resize the render buffer of the canvas to match canvas client size
488
497
  * Optionally multiplying with devicePixel ratio
489
498
  */
490
- _resizeCanvasDrawingBuffer() {
499
+ _resizeCanvasDrawingBuffer(): void {
491
500
  if (this.props.autoResizeDrawingBuffer) {
492
501
  this.device?.canvasContext?.resize({useDevicePixels: this.props.useDevicePixels});
493
502
  }
494
503
  }
495
504
 
496
- _beginTimers() {
505
+ _beginFrameTimers() {
497
506
  this.frameRate.timeEnd();
498
507
  this.frameRate.timeStart();
499
508
 
@@ -513,10 +522,10 @@ export class AnimationLoop {
513
522
  // this._gpuTimeQuery.beginTimeElapsedQuery();
514
523
  // }
515
524
 
516
- // this.cpuTime.timeStart();
525
+ this.cpuTime.timeStart();
517
526
  }
518
527
 
519
- _endTimers() {
528
+ _endFrameTimers() {
520
529
  this.cpuTime.timeEnd();
521
530
 
522
531
  // if (this._gpuTimeQuery) {
@@ -529,16 +538,18 @@ export class AnimationLoop {
529
538
 
530
539
  _startEventHandling() {
531
540
  if (this.canvas) {
532
- this.canvas.addEventListener('mousemove', this._onMousemove);
533
- this.canvas.addEventListener('mouseleave', this._onMouseleave);
541
+ this.canvas.addEventListener('mousemove', this._onMousemove.bind(this));
542
+ this.canvas.addEventListener('mouseleave', this._onMouseleave.bind(this));
534
543
  }
535
544
  }
536
545
 
537
- _onMousemove(e) {
538
- this._getAnimationProps()._mousePosition = [e.offsetX, e.offsetY];
546
+ _onMousemove(event: Event) {
547
+ if (event instanceof MouseEvent) {
548
+ this._getAnimationProps()._mousePosition = [event.offsetX, event.offsetY];
549
+ }
539
550
  }
540
551
 
541
- _onMouseleave(e) {
552
+ _onMouseleave(event: Event) {
542
553
  this._getAnimationProps()._mousePosition = null;
543
554
  }
544
555
  }
@@ -1,4 +1,4 @@
1
- import {Device} from '@luma.gl/api';
1
+ import {Device} from '@luma.gl/core';
2
2
  import {Timeline} from '../animation/timeline'
3
3
  import type {AnimationLoop} from './animation-loop';
4
4
 
@@ -0,0 +1,44 @@
1
+ // luma.gl, MIT license
2
+ import {luma} from '@luma.gl/core';
3
+ import {AnimationLoopTemplate} from './animation-loop-template'
4
+ import {AnimationLoop, AnimationLoopProps} from './animation-loop'
5
+ import type {AnimationProps} from './animation-props';
6
+
7
+ export type MakeAnimationLoopProps = Omit<AnimationLoopProps, 'onCreateDevice' | 'onInitialize' | 'onRedraw' | 'onFinalize'>;
8
+
9
+ /** Instantiates and runs the render loop */
10
+ export function makeAnimationLoop(AnimationLoopTemplateCtor: typeof AnimationLoopTemplate, props?: MakeAnimationLoopProps): AnimationLoop {
11
+ let renderLoop: AnimationLoopTemplate | null = null;
12
+
13
+ const device = props?.device || luma.createDevice();
14
+
15
+ // Create an animation loop;
16
+ const animationLoop = new AnimationLoop({
17
+ ... props,
18
+
19
+ device,
20
+
21
+ async onInitialize(animationProps: AnimationProps): Promise<unknown> {
22
+ // @ts-expect-error abstract to prevent instantiation
23
+ renderLoop = new AnimationLoopTemplateCtor(animationProps);
24
+ // Any async loading can be handled here
25
+ return await renderLoop?.onInitialize(animationProps);
26
+ },
27
+
28
+ onRender: (animationProps: AnimationProps) => renderLoop?.onRender(animationProps),
29
+
30
+ onFinalize: (animationProps: AnimationProps) => renderLoop?.onFinalize(animationProps)
31
+ });
32
+
33
+ // @ts-expect-error Hack: adds info for the website to find
34
+ animationLoop.getInfo = () => {
35
+ // @ts-ignore
36
+ // eslint-disable-next-line no-invalid-this
37
+ return this.AnimationLoopTemplateCtor.info;
38
+ }
39
+
40
+ // Start the loop automatically
41
+ // animationLoop.start();
42
+
43
+ return animationLoop;
44
+ }