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