@luma.gl/engine 9.0.0-alpha.5 → 9.0.0-alpha.50

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 (171) 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 +9 -9
  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/{lib → animation-loop}/animation-loop.d.ts +30 -31
  11. package/dist/animation-loop/animation-loop.d.ts.map +1 -0
  12. package/dist/{lib → animation-loop}/animation-loop.js +115 -199
  13. package/dist/animation-loop/animation-loop.js.map +1 -0
  14. package/dist/{lib → animation-loop}/animation-props.d.ts +6 -7
  15. package/dist/animation-loop/animation-props.d.ts.map +1 -0
  16. package/dist/animation-loop/animation-props.js.map +1 -0
  17. package/dist/animation-loop/make-animation-loop.d.ts +6 -0
  18. package/dist/animation-loop/make-animation-loop.d.ts.map +1 -0
  19. package/dist/animation-loop/make-animation-loop.js +28 -0
  20. package/dist/animation-loop/make-animation-loop.js.map +1 -0
  21. package/dist/animation-loop/render-loop.d.ts +23 -0
  22. package/dist/animation-loop/render-loop.d.ts.map +1 -0
  23. package/dist/animation-loop/render-loop.js +7 -0
  24. package/dist/animation-loop/render-loop.js.map +1 -0
  25. package/dist/dist.dev.js +7064 -0
  26. package/dist/geometries/cone-geometry.d.ts +1 -1
  27. package/dist/geometries/cone-geometry.d.ts.map +1 -1
  28. package/dist/geometries/cone-geometry.js +6 -5
  29. package/dist/geometries/cone-geometry.js.map +1 -1
  30. package/dist/geometries/cube-geometry.d.ts +2 -2
  31. package/dist/geometries/cube-geometry.d.ts.map +1 -1
  32. package/dist/geometries/cube-geometry.js +15 -8
  33. package/dist/geometries/cube-geometry.js.map +1 -1
  34. package/dist/geometries/cylinder-geometry.d.ts +1 -1
  35. package/dist/geometries/cylinder-geometry.d.ts.map +1 -1
  36. package/dist/geometries/cylinder-geometry.js +6 -5
  37. package/dist/geometries/cylinder-geometry.js.map +1 -1
  38. package/dist/geometries/ico-sphere-geometry.d.ts +2 -2
  39. package/dist/geometries/ico-sphere-geometry.d.ts.map +1 -1
  40. package/dist/geometries/ico-sphere-geometry.js +10 -19
  41. package/dist/geometries/ico-sphere-geometry.js.map +1 -1
  42. package/dist/geometries/plane-geometry.d.ts +2 -2
  43. package/dist/geometries/plane-geometry.d.ts.map +1 -1
  44. package/dist/geometries/plane-geometry.js +14 -23
  45. package/dist/geometries/plane-geometry.js.map +1 -1
  46. package/dist/geometries/sphere-geometry.d.ts +2 -2
  47. package/dist/geometries/sphere-geometry.d.ts.map +1 -1
  48. package/dist/geometries/sphere-geometry.js +9 -13
  49. package/dist/geometries/sphere-geometry.js.map +1 -1
  50. package/dist/geometries/truncated-cone-geometry.d.ts +2 -4
  51. package/dist/geometries/truncated-cone-geometry.d.ts.map +1 -1
  52. package/dist/geometries/truncated-cone-geometry.js +9 -25
  53. package/dist/geometries/truncated-cone-geometry.js.map +1 -1
  54. package/dist/geometry/geometry-table.d.ts +2 -2
  55. package/dist/geometry/geometry-table.d.ts.map +1 -1
  56. package/dist/geometry/geometry-table.js.map +1 -1
  57. package/dist/geometry/geometry-utils.d.ts.map +1 -1
  58. package/dist/geometry/geometry-utils.js +0 -9
  59. package/dist/geometry/geometry-utils.js.map +1 -1
  60. package/dist/geometry/geometry.d.ts +50 -59
  61. package/dist/geometry/geometry.d.ts.map +1 -1
  62. package/dist/geometry/geometry.js +32 -97
  63. package/dist/geometry/geometry.js.map +1 -1
  64. package/dist/geometry/gpu-geometry.d.ts +37 -0
  65. package/dist/geometry/gpu-geometry.d.ts.map +1 -0
  66. package/dist/geometry/gpu-geometry.js +107 -0
  67. package/dist/geometry/gpu-geometry.js.map +1 -0
  68. package/dist/geometry/gpu-table.d.ts +1 -0
  69. package/dist/geometry/gpu-table.d.ts.map +1 -0
  70. package/dist/geometry/gpu-table.js +2 -0
  71. package/dist/geometry/gpu-table.js.map +1 -0
  72. package/dist/index.cjs +2959 -0
  73. package/dist/index.d.ts +26 -9
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +23 -13
  76. package/dist/index.js.map +1 -1
  77. package/dist/lib/clip-space.d.ts +8 -0
  78. package/dist/lib/clip-space.d.ts.map +1 -1
  79. package/dist/lib/clip-space.js +47 -0
  80. package/dist/lib/clip-space.js.map +1 -1
  81. package/dist/lib/pipeline-factory.d.ts +12 -40
  82. package/dist/lib/pipeline-factory.d.ts.map +1 -1
  83. package/dist/lib/pipeline-factory.js +50 -148
  84. package/dist/lib/pipeline-factory.js.map +1 -1
  85. package/dist/model/model.d.ts +192 -0
  86. package/dist/model/model.d.ts.map +1 -0
  87. package/dist/model/model.js +312 -0
  88. package/dist/model/model.js.map +1 -0
  89. package/dist/scenegraph/group-node.d.ts +21 -0
  90. package/dist/scenegraph/group-node.d.ts.map +1 -0
  91. package/dist/scenegraph/group-node.js +94 -0
  92. package/dist/scenegraph/group-node.js.map +1 -0
  93. package/dist/scenegraph/model-node.d.ts +18 -0
  94. package/dist/scenegraph/model-node.d.ts.map +1 -0
  95. package/dist/scenegraph/model-node.js +28 -0
  96. package/dist/scenegraph/model-node.js.map +1 -0
  97. package/dist/scenegraph/scenegraph-node.d.ts +56 -0
  98. package/dist/scenegraph/scenegraph-node.d.ts.map +1 -0
  99. package/dist/scenegraph/scenegraph-node.js +141 -0
  100. package/dist/scenegraph/scenegraph-node.js.map +1 -0
  101. package/dist/shader-inputs.d.ts +62 -0
  102. package/dist/shader-inputs.d.ts.map +1 -0
  103. package/dist/shader-inputs.js +49 -0
  104. package/dist/shader-inputs.js.map +1 -0
  105. package/dist/transform/buffer-transform.d.ts +35 -0
  106. package/dist/transform/buffer-transform.d.ts.map +1 -0
  107. package/dist/transform/buffer-transform.js +62 -0
  108. package/dist/transform/buffer-transform.js.map +1 -0
  109. package/dist/transform/texture-transform.d.ts +57 -0
  110. package/dist/transform/texture-transform.d.ts.map +1 -0
  111. package/dist/transform/texture-transform.js +122 -0
  112. package/dist/transform/texture-transform.js.map +1 -0
  113. package/dist.min.js +286 -0
  114. package/package.json +21 -12
  115. package/src/animation/timeline.ts +16 -15
  116. package/src/{lib → animation-loop}/animation-loop.ts +120 -107
  117. package/src/{lib → animation-loop}/animation-props.ts +5 -5
  118. package/src/animation-loop/make-animation-loop.ts +44 -0
  119. package/src/animation-loop/render-loop.ts +23 -0
  120. package/src/geometries/cone-geometry.ts +1 -1
  121. package/src/geometries/cube-geometry.ts +6 -3
  122. package/src/geometries/cylinder-geometry.ts +2 -2
  123. package/src/geometries/ico-sphere-geometry.ts +7 -6
  124. package/src/geometries/plane-geometry.ts +5 -4
  125. package/src/geometries/sphere-geometry.ts +4 -3
  126. package/src/geometries/truncated-cone-geometry.ts +4 -13
  127. package/src/geometry/geometry-table.ts +1 -1
  128. package/src/geometry/geometry-utils.ts +3 -3
  129. package/src/geometry/geometry.ts +79 -119
  130. package/src/geometry/gpu-geometry.ts +124 -0
  131. package/src/geometry/gpu-table.ts +41 -0
  132. package/src/index.ts +38 -12
  133. package/src/lib/clip-space.ts +22 -21
  134. package/src/lib/pipeline-factory.ts +60 -168
  135. package/src/model/model.ts +549 -0
  136. package/src/scenegraph/group-node.ts +103 -0
  137. package/src/scenegraph/model-node.ts +50 -0
  138. package/src/scenegraph/scenegraph-node.ts +204 -0
  139. package/src/shader-inputs.ts +132 -0
  140. package/src/transform/buffer-transform.ts +94 -0
  141. package/src/transform/texture-transform.ts +169 -0
  142. package/dist/bundle.d.ts +0 -2
  143. package/dist/bundle.d.ts.map +0 -1
  144. package/dist/bundle.js +0 -5
  145. package/dist/bundle.js.map +0 -1
  146. package/dist/geometry/primitive-utils.d.ts +0 -1
  147. package/dist/geometry/primitive-utils.d.ts.map +0 -1
  148. package/dist/geometry/primitive-utils.js +0 -2
  149. package/dist/geometry/primitive-utils.js.map +0 -1
  150. package/dist/lib/animation-loop.d.ts.map +0 -1
  151. package/dist/lib/animation-loop.js.map +0 -1
  152. package/dist/lib/animation-props.d.ts.map +0 -1
  153. package/dist/lib/animation-props.js.map +0 -1
  154. package/dist/lib/model-utils.d.ts +0 -5
  155. package/dist/lib/model-utils.d.ts.map +0 -1
  156. package/dist/lib/model-utils.js +0 -45
  157. package/dist/lib/model-utils.js.map +0 -1
  158. package/dist/lib/model.d.ts +0 -41
  159. package/dist/lib/model.d.ts.map +0 -1
  160. package/dist/lib/model.js +0 -176
  161. package/dist/lib/model.js.map +0 -1
  162. package/dist/lib/render-loop.d.ts +0 -14
  163. package/dist/lib/render-loop.d.ts.map +0 -1
  164. package/dist/lib/render-loop.js +0 -49
  165. package/dist/lib/render-loop.js.map +0 -1
  166. package/src/bundle.ts +0 -4
  167. package/src/geometry/primitive-utils.ts +0 -30
  168. package/src/lib/model-utils.ts +0 -124
  169. package/src/lib/model.ts +0 -179
  170. package/src/lib/render-loop.ts +0 -58
  171. /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.5",
3
+ "version": "9.0.0-alpha.50",
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
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs",
27
+ "types": "./dist/index.d.ts"
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.5",
35
- "@luma.gl/shadertools": "9.0.0-alpha.5",
36
- "@luma.gl/webgl": "9.0.0-alpha.5",
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-alpha.50",
44
+ "@luma.gl/core": "9.0.0-alpha.50",
45
+ "@luma.gl/shadertools": "9.0.0-alpha.50",
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": "729cfdd272836270d0f59793b8a36a2a3aea47ca"
50
+ "gitHead": "83899806fcfab67f97cc8b308f81e4844a05ca05"
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
@@ -27,7 +28,7 @@ export type AnimationOptions = {
27
28
  }
28
29
 
29
30
  type Animation = {
30
- channel: number;
31
+ channel?: number;
31
32
  animation: {
32
33
  setTime: (time: number) => void
33
34
  }
@@ -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 {
@@ -1,63 +1,65 @@
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;
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
+
37
+
34
38
  const DEFAULT_ANIMATION_LOOP_PROPS: Required<AnimationLoopProps> = {
35
- onCreateDevice: (props: DeviceProps): Promise<Device> => luma.createDevice(props),
36
- onAddHTML: undefined,
37
- onInitialize: () => ({}),
39
+ device: null!,
40
+
41
+ onAddHTML: () => '',
42
+ onInitialize: async () => { return null; },
38
43
  onRender: () => {},
39
44
  onFinalize: () => {},
40
45
  onError: (error) => console.error(error), // eslint-disable-line no-console
41
46
 
42
- device: undefined,
43
- deviceProps: {},
44
- debug: false,
45
47
  stats: luma.stats.get(`animation-loop-${statIdCounter++}`),
46
48
 
47
49
  // view parameters
48
50
  useDevicePixels: true,
49
- autoResizeViewport: true,
50
- autoResizeDrawingBuffer: true,
51
+ autoResizeViewport: false,
52
+ autoResizeDrawingBuffer: false,
51
53
  };
52
54
 
53
55
  /** Convenient animation loop */
54
- export default class AnimationLoop {
55
- device: Device;
56
- canvas: HTMLCanvasElement; // | OffscreenCanvas;
56
+ export class AnimationLoop {
57
+ device: Device | null = null;
58
+ canvas: HTMLCanvasElement | OffscreenCanvas | null = null;
57
59
 
58
60
  props: Required<AnimationLoopProps>;
59
- animationProps: AnimationProps;
60
- timeline: Timeline = null;
61
+ animationProps: AnimationProps | null = null;
62
+ timeline: Timeline | null = null;
61
63
  stats: Stats;
62
64
  cpuTime: Stat;
63
65
  gpuTime: Stat;
@@ -65,13 +67,13 @@ export default class AnimationLoop {
65
67
 
66
68
  display: any;
67
69
 
68
- needsRedraw: string | null = 'initialized';
70
+ needsRedraw: string | false = 'initialized';
69
71
 
70
72
  _initialized: boolean = false;
71
73
  _running: boolean = false;
72
- _animationFrameId = null;
74
+ _animationFrameId: any = null;
73
75
  _nextFramePromise: Promise<AnimationLoop> | null = null;
74
- _resolveNextFrame: ((AnimationLoop) => void) | null = null;
76
+ _resolveNextFrame: ((animationLoop: AnimationLoop) => void) | null = null;
75
77
  _cpuStartTime: number = 0;
76
78
 
77
79
  // _gpuTimeQuery: Query | null = null;
@@ -79,18 +81,18 @@ export default class AnimationLoop {
79
81
  /*
80
82
  * @param {HTMLCanvasElement} canvas - if provided, width and height will be passed to context
81
83
  */
82
- constructor(props: AnimationLoopProps = {}) {
84
+ constructor(props: AnimationLoopProps) {
83
85
  this.props = {...DEFAULT_ANIMATION_LOOP_PROPS, ...props};
84
86
  props = this.props;
85
87
 
86
- let {useDevicePixels = true} = this.props;
88
+ if (!props.device) {
89
+ throw new Error('No device provided');
90
+ }
87
91
 
88
- // state
89
- this.device = props.device;
90
- // @ts-expect-error
91
- this.gl = (this.device && this.device.gl) || props.gl;
92
+ const {useDevicePixels = true} = this.props;
92
93
 
93
- this.stats = props.stats;
94
+ // state
95
+ this.stats = props.stats || new Stats({id: 'animation-loop-stats'});
94
96
  this.cpuTime = this.stats.get('CPU Time');
95
97
  this.gpuTime = this.stats.get('GPU Time');
96
98
  this.frameRate = this.stats.get('Frame Rate');
@@ -125,15 +127,15 @@ export default class AnimationLoop {
125
127
  }
126
128
 
127
129
  // TODO - move to CanvasContext
128
- setProps(props: AnimationLoopProps): this {
130
+ setProps(props: MutableAnimationLoopProps): this {
129
131
  if ('autoResizeViewport' in props) {
130
- this.props.autoResizeViewport = props.autoResizeViewport;
132
+ this.props.autoResizeViewport = props.autoResizeViewport || false;
131
133
  }
132
134
  if ('autoResizeDrawingBuffer' in props) {
133
- this.props.autoResizeDrawingBuffer = props.autoResizeDrawingBuffer;
135
+ this.props.autoResizeDrawingBuffer = props.autoResizeDrawingBuffer || false;
134
136
  }
135
137
  if ('useDevicePixels' in props) {
136
- this.props.useDevicePixels = props.useDevicePixels;
138
+ this.props.useDevicePixels = props.useDevicePixels || false;
137
139
  }
138
140
  return this;
139
141
  }
@@ -146,20 +148,16 @@ export default 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)
162
- await this.onInitialize(this.animationProps);
160
+ await this.props.onInitialize(this._getAnimationProps());
163
161
  }
164
162
 
165
163
  // check that we haven't been stopped
@@ -185,16 +183,16 @@ export default class AnimationLoop {
185
183
 
186
184
  /** Explicitly draw a frame */
187
185
  redraw(): this {
188
- if (this.device.isLost) {
186
+ if (this.device?.isLost) {
189
187
  return this;
190
188
  }
191
189
 
192
- this._beginTimers();
190
+ this._beginFrameTimers();
193
191
 
194
192
  this._setupFrame();
195
- this._updateCallbackData();
193
+ this._updateAnimationProps();
196
194
 
197
- this._renderFrame(this.animationProps);
195
+ this._renderFrame(this._getAnimationProps());
198
196
 
199
197
  // clear needsRedraw flag
200
198
  this._clearNeedsRedraw();
@@ -205,7 +203,7 @@ export default class AnimationLoop {
205
203
  this._resolveNextFrame = null;
206
204
  }
207
205
 
208
- this._endTimers();
206
+ this._endFrameTimers();
209
207
 
210
208
  return this;
211
209
  }
@@ -215,7 +213,10 @@ export default class AnimationLoop {
215
213
  // console.debug(`Stopping ${this.constructor.name}`);
216
214
  if (this._running) {
217
215
  // call callback
218
- this.onFinalize(this.animationProps);
216
+ // If stop is called immediately, we can end up in a state where props haven't been initialized...
217
+ if (this.animationProps) {
218
+ this.props.onFinalize(this.animationProps);
219
+ }
219
220
 
220
221
  this._cancelAnimationFrame();
221
222
  this._nextFramePromise = null;
@@ -245,26 +246,13 @@ export default class AnimationLoop {
245
246
  return this._nextFramePromise;
246
247
  }
247
248
 
248
- async toDataURL() {
249
+ async toDataURL(): Promise<string> {
249
250
  this.setNeedsRedraw('toDataURL');
250
251
  await this.waitForRender();
251
- return this.canvas.toDataURL();
252
- }
253
-
254
- onCreateDevice(deviceProps: DeviceProps): Promise<Device> {
255
- return this.props.onCreateDevice(deviceProps);
256
- }
257
-
258
- onInitialize(animationProps: AnimationProps): {} | void {
259
- return this.props.onInitialize(animationProps);
260
- }
261
-
262
- onRender(animationProps: AnimationProps) {
263
- return this.props.onRender(animationProps);
264
- }
265
-
266
- onFinalize(animationProps: AnimationProps) {
267
- return this.props.onFinalize(animationProps);
252
+ if (this.canvas instanceof HTMLCanvasElement) {
253
+ return this.canvas.toDataURL();
254
+ }
255
+ throw new Error('OffscreenCanvas');
268
256
  }
269
257
 
270
258
  // PRIVATE METHODS
@@ -273,8 +261,8 @@ export default class AnimationLoop {
273
261
  this._startEventHandling();
274
262
 
275
263
  // Initialize the callback data
276
- this._initializeCallbackData();
277
- this._updateCallbackData();
264
+ this._initializeAnimationProps();
265
+ this._updateAnimationProps();
278
266
 
279
267
  // Default viewport setup, in case onInitialize wants to render
280
268
  this._resizeCanvasDrawingBuffer();
@@ -283,9 +271,9 @@ export default class AnimationLoop {
283
271
  // this._gpuTimeQuery = Query.isSupported(this.gl, ['timers']) ? new Query(this.gl) : null;
284
272
  }
285
273
 
286
- _setDisplay(display) {
274
+ _setDisplay(display: any) {
287
275
  if (this.display) {
288
- this.display.delete();
276
+ this.display.destroy();
289
277
  this.display.animationLoop = null;
290
278
  }
291
279
 
@@ -312,7 +300,7 @@ export default class AnimationLoop {
312
300
  }
313
301
 
314
302
  _cancelAnimationFrame() {
315
- if (this._animationFrameId !== null) {
303
+ if (this._animationFrameId === null) {
316
304
  return;
317
305
  }
318
306
 
@@ -322,7 +310,7 @@ export default class AnimationLoop {
322
310
  // if (this.display && this.display.cancelAnimationFrame) {
323
311
  // this.display.cancelAnimationFrame(this._animationFrameId);
324
312
  // }
325
- cancelAnimationFrame(this._animationFrameId);
313
+ cancelAnimationFrame(this._animationFrameId);
326
314
  this._animationFrameId = null;
327
315
  }
328
316
 
@@ -336,20 +324,20 @@ export default class AnimationLoop {
336
324
 
337
325
  // Called on each frame, can be overridden to call onRender multiple times
338
326
  // to support e.g. stereoscopic rendering
339
- _renderFrame(props: AnimationProps) {
327
+ _renderFrame(animationProps: AnimationProps) {
340
328
  // Allow e.g. VR display to render multiple frames.
341
329
  if (this.display) {
342
- this.display._renderFrame(props);
330
+ this.display._renderFrame(animationProps);
343
331
  return;
344
332
  }
345
333
 
346
334
  // call callback
347
- this.onRender(props);
335
+ this.props.onRender(this._getAnimationProps());
348
336
  // end callback
349
337
  }
350
338
 
351
339
  _clearNeedsRedraw() {
352
- this.needsRedraw = null;
340
+ this.needsRedraw = false;
353
341
  }
354
342
 
355
343
  _setupFrame() {
@@ -358,16 +346,20 @@ export default class AnimationLoop {
358
346
  }
359
347
 
360
348
  // Initialize the object that will be passed to app callbacks
361
- _initializeCallbackData() {
349
+ _initializeAnimationProps() {
350
+ if (!this.device) {
351
+ throw new Error('loop');
352
+ }
362
353
  this.animationProps = {
363
354
  animationLoop: this,
355
+
364
356
  device: this.device,
365
- canvas: this.device.canvasContext.canvas,
357
+ canvas: this.device?.canvasContext?.canvas,
366
358
  timeline: this.timeline,
367
359
 
368
360
  // Initial values
369
361
  useDevicePixels: this.props.useDevicePixels,
370
- needsRedraw: null,
362
+ needsRedraw: false,
371
363
 
372
364
  // Placeholders
373
365
  width: 1,
@@ -386,8 +378,20 @@ export default class AnimationLoop {
386
378
  };
387
379
  }
388
380
 
381
+ _getAnimationProps(): AnimationProps {
382
+ if (!this.animationProps) {
383
+ throw new Error('animationProps');
384
+ }
385
+ return this.animationProps;
386
+ }
387
+
389
388
  // Update the context object that will be passed to app callbacks
390
- _updateCallbackData() {
389
+ _updateAnimationProps(): void {
390
+ if (!this.animationProps) {
391
+ return;
392
+ }
393
+
394
+ // Can this be replaced with canvas context?
391
395
  const {width, height, aspect} = this._getSizeAndAspect();
392
396
  if (width !== this.animationProps.width || height !== this.animationProps.height) {
393
397
  this.setNeedsRedraw('drawing buffer resized');
@@ -418,13 +422,14 @@ export default class AnimationLoop {
418
422
  : this.animationProps.engineTime;
419
423
  }
420
424
 
421
- /** Either uses supplied or existing context, or calls provided callback to create one */
422
- async _createDevice() {
423
- const deviceProps = {...this.props, ...this.props.deviceProps};
424
- this.device = await this.onCreateDevice(deviceProps);
425
- // @ts-expect-error
426
- this.canvas = this.device.canvasContext.canvas;
427
- this._createInfoDiv();
425
+ /** Wait for supplied device */
426
+ async _initDevice() {
427
+ this.device = await this.props.device;
428
+ if (!this.device) {
429
+ throw new Error('No device provided');
430
+ }
431
+ this.canvas = this.device.canvasContext?.canvas || null;
432
+ // this._createInfoDiv();
428
433
  }
429
434
 
430
435
  _createInfoDiv() {
@@ -438,7 +443,9 @@ export default class AnimationLoop {
438
443
  div.style.bottom = '10px';
439
444
  div.style.width = '300px';
440
445
  div.style.background = 'white';
441
- wrapperDiv.appendChild(this.canvas);
446
+ if (this.canvas instanceof HTMLCanvasElement) {
447
+ wrapperDiv.appendChild(this.canvas);
448
+ }
442
449
  wrapperDiv.appendChild(div);
443
450
  const html = this.props.onAddHTML(div);
444
451
  if (html) {
@@ -447,13 +454,16 @@ export default class AnimationLoop {
447
454
  }
448
455
  }
449
456
 
450
- _getSizeAndAspect() {
457
+ _getSizeAndAspect(): {width: number; height: number; aspect: number} {
458
+ if (!this.device) {
459
+ return {width: 1, height: 1, aspect: 1};
460
+ }
451
461
  // https://webglfundamentals.org/webgl/lessons/webgl-resizing-the-canvas.html
452
- const [width, height] = this.device.canvasContext.getPixelSize();
462
+ const [width, height] = this.device?.canvasContext?.getPixelSize() || [1, 1];
453
463
 
454
464
  // https://webglfundamentals.org/webgl/lessons/webgl-anti-patterns.html
455
465
  let aspect = 1;
456
- const canvas = this.device.canvasContext.canvas;
466
+ const canvas = this.device?.canvasContext?.canvas;
457
467
 
458
468
  // @ts-expect-error
459
469
  if (canvas && canvas.clientHeight) {
@@ -481,11 +491,11 @@ export default class AnimationLoop {
481
491
  */
482
492
  _resizeCanvasDrawingBuffer() {
483
493
  if (this.props.autoResizeDrawingBuffer) {
484
- this.device.canvasContext.resize({useDevicePixels: this.props.useDevicePixels});
494
+ this.device?.canvasContext?.resize({useDevicePixels: this.props.useDevicePixels});
485
495
  }
486
496
  }
487
497
 
488
- _beginTimers() {
498
+ _beginFrameTimers() {
489
499
  this.frameRate.timeEnd();
490
500
  this.frameRate.timeStart();
491
501
 
@@ -505,10 +515,10 @@ export default class AnimationLoop {
505
515
  // this._gpuTimeQuery.beginTimeElapsedQuery();
506
516
  // }
507
517
 
508
- // this.cpuTime.timeStart();
518
+ this.cpuTime.timeStart();
509
519
  }
510
520
 
511
- _endTimers() {
521
+ _endFrameTimers() {
512
522
  this.cpuTime.timeEnd();
513
523
 
514
524
  // if (this._gpuTimeQuery) {
@@ -521,15 +531,18 @@ export default class AnimationLoop {
521
531
 
522
532
  _startEventHandling() {
523
533
  if (this.canvas) {
524
- this.canvas.addEventListener('mousemove', this._onMousemove);
525
- this.canvas.addEventListener('mouseleave', this._onMouseleave);
534
+ this.canvas.addEventListener('mousemove', this._onMousemove.bind(this));
535
+ this.canvas.addEventListener('mouseleave', this._onMouseleave.bind(this));
526
536
  }
527
537
  }
528
538
 
529
- _onMousemove(e) {
530
- this.animationProps._mousePosition = [e.offsetX, e.offsetY];
539
+ _onMousemove(event: Event) {
540
+ if (event instanceof MouseEvent) {
541
+ this._getAnimationProps()._mousePosition = [event.offsetX, event.offsetY];
542
+ }
531
543
  }
532
- _onMouseleave(e) {
533
- this.animationProps._mousePosition = null;
544
+
545
+ _onMouseleave(event: Event) {
546
+ this._getAnimationProps()._mousePosition = null;
534
547
  }
535
548
  }
@@ -1,6 +1,6 @@
1
- import {Device} from '@luma.gl/api';
1
+ import {Device} from '@luma.gl/core';
2
2
  import {Timeline} from '../animation/timeline'
3
- import type AnimationLoop from './animation-loop';
3
+ import type {AnimationLoop} from './animation-loop';
4
4
 
5
5
  /** Properties passed to every render frame */
6
6
  export type AnimationProps = {
@@ -22,10 +22,10 @@ export type AnimationProps = {
22
22
  tock: number;
23
23
 
24
24
  // Initial values
25
- needsRedraw?: string;
25
+ needsRedraw?: string | false;
26
26
 
27
- timeline: Timeline;
27
+ timeline: Timeline | null;
28
28
 
29
29
  // Experimental
30
- _mousePosition?: [number, number]; // [offsetX, offsetY],
30
+ _mousePosition?: [number, number] | null; // [offsetX, offsetY],
31
31
  };
@@ -0,0 +1,44 @@
1
+ // luma.gl, MIT license
2
+ import {luma} from '@luma.gl/core';
3
+ import {AnimationLoopTemplate} from './render-loop'
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
+ }