@luma.gl/core 9.2.6 → 9.3.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/dist/adapter/canvas-context.d.ts +6 -162
  2. package/dist/adapter/canvas-context.d.ts.map +1 -1
  3. package/dist/adapter/canvas-context.js +5 -419
  4. package/dist/adapter/canvas-context.js.map +1 -1
  5. package/dist/adapter/canvas-observer.d.ts +32 -0
  6. package/dist/adapter/canvas-observer.d.ts.map +1 -0
  7. package/dist/adapter/canvas-observer.js +90 -0
  8. package/dist/adapter/canvas-observer.js.map +1 -0
  9. package/dist/adapter/canvas-surface.d.ts +150 -0
  10. package/dist/adapter/canvas-surface.d.ts.map +1 -0
  11. package/dist/adapter/canvas-surface.js +392 -0
  12. package/dist/adapter/canvas-surface.js.map +1 -0
  13. package/dist/adapter/device.d.ts +81 -16
  14. package/dist/adapter/device.d.ts.map +1 -1
  15. package/dist/adapter/device.js +191 -10
  16. package/dist/adapter/device.js.map +1 -1
  17. package/dist/adapter/luma.js +1 -1
  18. package/dist/adapter/luma.js.map +1 -1
  19. package/dist/adapter/presentation-context.d.ts +11 -0
  20. package/dist/adapter/presentation-context.d.ts.map +1 -0
  21. package/dist/adapter/presentation-context.js +12 -0
  22. package/dist/adapter/presentation-context.js.map +1 -0
  23. package/dist/adapter/resources/buffer.d.ts +1 -1
  24. package/dist/adapter/resources/buffer.d.ts.map +1 -1
  25. package/dist/adapter/resources/buffer.js +14 -6
  26. package/dist/adapter/resources/buffer.js.map +1 -1
  27. package/dist/adapter/resources/command-buffer.d.ts +3 -1
  28. package/dist/adapter/resources/command-buffer.d.ts.map +1 -1
  29. package/dist/adapter/resources/command-buffer.js +3 -1
  30. package/dist/adapter/resources/command-buffer.js.map +1 -1
  31. package/dist/adapter/resources/command-encoder.d.ts +30 -7
  32. package/dist/adapter/resources/command-encoder.d.ts.map +1 -1
  33. package/dist/adapter/resources/command-encoder.js +68 -2
  34. package/dist/adapter/resources/command-encoder.js.map +1 -1
  35. package/dist/adapter/resources/compute-pipeline.d.ts +2 -2
  36. package/dist/adapter/resources/compute-pipeline.d.ts.map +1 -1
  37. package/dist/adapter/resources/fence.d.ts +16 -0
  38. package/dist/adapter/resources/fence.d.ts.map +1 -0
  39. package/dist/adapter/resources/fence.js +17 -0
  40. package/dist/adapter/resources/fence.js.map +1 -0
  41. package/dist/adapter/resources/framebuffer.d.ts +1 -1
  42. package/dist/adapter/resources/framebuffer.d.ts.map +1 -1
  43. package/dist/adapter/resources/framebuffer.js +15 -12
  44. package/dist/adapter/resources/framebuffer.js.map +1 -1
  45. package/dist/adapter/resources/query-set.d.ts +17 -1
  46. package/dist/adapter/resources/query-set.d.ts.map +1 -1
  47. package/dist/adapter/resources/query-set.js.map +1 -1
  48. package/dist/adapter/resources/render-pipeline.d.ts +28 -10
  49. package/dist/adapter/resources/render-pipeline.d.ts.map +1 -1
  50. package/dist/adapter/resources/render-pipeline.js +21 -2
  51. package/dist/adapter/resources/render-pipeline.js.map +1 -1
  52. package/dist/adapter/resources/resource.d.ts +13 -0
  53. package/dist/adapter/resources/resource.d.ts.map +1 -1
  54. package/dist/adapter/resources/resource.js +243 -14
  55. package/dist/adapter/resources/resource.js.map +1 -1
  56. package/dist/adapter/resources/shader.js +27 -25
  57. package/dist/adapter/resources/shader.js.map +1 -1
  58. package/dist/adapter/resources/shared-render-pipeline.d.ts +22 -0
  59. package/dist/adapter/resources/shared-render-pipeline.d.ts.map +1 -0
  60. package/dist/adapter/resources/shared-render-pipeline.js +25 -0
  61. package/dist/adapter/resources/shared-render-pipeline.js.map +1 -0
  62. package/dist/adapter/resources/texture-view.d.ts +1 -1
  63. package/dist/adapter/resources/texture-view.d.ts.map +1 -1
  64. package/dist/adapter/resources/texture.d.ts +168 -28
  65. package/dist/adapter/resources/texture.d.ts.map +1 -1
  66. package/dist/adapter/resources/texture.js +284 -25
  67. package/dist/adapter/resources/texture.js.map +1 -1
  68. package/dist/adapter/types/attachments.d.ts +1 -1
  69. package/dist/adapter/types/attachments.d.ts.map +1 -1
  70. package/dist/adapter/types/buffer-layout.d.ts +1 -1
  71. package/dist/adapter/types/buffer-layout.d.ts.map +1 -1
  72. package/dist/adapter/types/parameters.d.ts +3 -1
  73. package/dist/adapter/types/parameters.d.ts.map +1 -1
  74. package/dist/adapter/types/parameters.js +1 -0
  75. package/dist/adapter/types/parameters.js.map +1 -1
  76. package/dist/adapter/types/shader-layout.d.ts +10 -6
  77. package/dist/adapter/types/shader-layout.d.ts.map +1 -1
  78. package/dist/adapter/types/uniforms.d.ts +6 -0
  79. package/dist/adapter/types/uniforms.d.ts.map +1 -1
  80. package/dist/adapter-utils/bind-groups.d.ts +9 -0
  81. package/dist/adapter-utils/bind-groups.d.ts.map +1 -0
  82. package/dist/adapter-utils/bind-groups.js +41 -0
  83. package/dist/adapter-utils/bind-groups.js.map +1 -0
  84. package/dist/adapter-utils/format-compiler-log.d.ts.map +1 -1
  85. package/dist/adapter-utils/format-compiler-log.js +23 -15
  86. package/dist/adapter-utils/format-compiler-log.js.map +1 -1
  87. package/dist/adapter-utils/get-attribute-from-layouts.d.ts +2 -2
  88. package/dist/adapter-utils/get-attribute-from-layouts.d.ts.map +1 -1
  89. package/dist/adapter-utils/get-attribute-from-layouts.js +6 -6
  90. package/dist/adapter-utils/get-attribute-from-layouts.js.map +1 -1
  91. package/dist/dist.dev.js +2686 -644
  92. package/dist/dist.min.js +10 -9
  93. package/dist/factories/bind-group-factory.d.ts +20 -0
  94. package/dist/factories/bind-group-factory.d.ts.map +1 -0
  95. package/dist/factories/bind-group-factory.js +79 -0
  96. package/dist/factories/bind-group-factory.js.map +1 -0
  97. package/dist/factories/core-module-state.d.ts +7 -0
  98. package/dist/factories/core-module-state.d.ts.map +1 -0
  99. package/dist/{shadertypes/data-types/shader-types.js → factories/core-module-state.js} +1 -1
  100. package/dist/factories/core-module-state.js.map +1 -0
  101. package/dist/factories/pipeline-factory.d.ts +54 -0
  102. package/dist/factories/pipeline-factory.d.ts.map +1 -0
  103. package/dist/factories/pipeline-factory.js +270 -0
  104. package/dist/factories/pipeline-factory.js.map +1 -0
  105. package/dist/factories/shader-factory.d.ts +20 -0
  106. package/dist/factories/shader-factory.d.ts.map +1 -0
  107. package/dist/factories/shader-factory.js +84 -0
  108. package/dist/factories/shader-factory.js.map +1 -0
  109. package/dist/index.cjs +2422 -554
  110. package/dist/index.cjs.map +4 -4
  111. package/dist/index.d.ts +30 -14
  112. package/dist/index.d.ts.map +1 -1
  113. package/dist/index.js +19 -7
  114. package/dist/index.js.map +1 -1
  115. package/dist/portable/shader-block-writer.d.ts +51 -0
  116. package/dist/portable/shader-block-writer.d.ts.map +1 -0
  117. package/dist/portable/shader-block-writer.js +185 -0
  118. package/dist/portable/shader-block-writer.js.map +1 -0
  119. package/dist/portable/uniform-block.d.ts +1 -1
  120. package/dist/portable/uniform-block.d.ts.map +1 -1
  121. package/dist/portable/uniform-store.d.ts +55 -24
  122. package/dist/portable/uniform-store.d.ts.map +1 -1
  123. package/dist/portable/uniform-store.js +73 -25
  124. package/dist/portable/uniform-store.js.map +1 -1
  125. package/dist/shadertypes/data-types/data-type-decoder.d.ts +20 -0
  126. package/dist/shadertypes/data-types/data-type-decoder.d.ts.map +1 -0
  127. package/dist/shadertypes/data-types/data-type-decoder.js +79 -0
  128. package/dist/shadertypes/data-types/data-type-decoder.js.map +1 -0
  129. package/dist/shadertypes/data-types/data-types.d.ts +31 -12
  130. package/dist/shadertypes/data-types/data-types.d.ts.map +1 -1
  131. package/dist/shadertypes/data-types/decode-data-types.d.ts.map +1 -1
  132. package/dist/shadertypes/data-types/decode-data-types.js +2 -1
  133. package/dist/shadertypes/data-types/decode-data-types.js.map +1 -1
  134. package/dist/{image-utils → shadertypes/image-types}/image-types.d.ts +0 -6
  135. package/dist/shadertypes/image-types/image-types.d.ts.map +1 -0
  136. package/dist/shadertypes/image-types/image-types.js.map +1 -0
  137. package/dist/shadertypes/shader-types/shader-block-layout.d.ts +72 -0
  138. package/dist/shadertypes/shader-types/shader-block-layout.d.ts.map +1 -0
  139. package/dist/shadertypes/shader-types/shader-block-layout.js +209 -0
  140. package/dist/shadertypes/shader-types/shader-block-layout.js.map +1 -0
  141. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts +41 -0
  142. package/dist/shadertypes/shader-types/shader-type-decoder.d.ts.map +1 -0
  143. package/dist/shadertypes/{data-types/decode-shader-types.js → shader-types/shader-type-decoder.js} +43 -4
  144. package/dist/shadertypes/shader-types/shader-type-decoder.js.map +1 -0
  145. package/dist/shadertypes/shader-types/shader-types.d.ts +101 -0
  146. package/dist/shadertypes/shader-types/shader-types.d.ts.map +1 -0
  147. package/dist/shadertypes/shader-types/shader-types.js +30 -0
  148. package/dist/shadertypes/shader-types/shader-types.js.map +1 -0
  149. package/dist/shadertypes/texture-types/pixel-utils.d.ts.map +1 -0
  150. package/dist/shadertypes/{textures → texture-types}/pixel-utils.js +4 -4
  151. package/dist/shadertypes/texture-types/pixel-utils.js.map +1 -0
  152. package/dist/shadertypes/texture-types/texture-format-decoder.d.ts +36 -0
  153. package/dist/shadertypes/texture-types/texture-format-decoder.d.ts.map +1 -0
  154. package/dist/shadertypes/{textures → texture-types}/texture-format-decoder.js +109 -37
  155. package/dist/shadertypes/texture-types/texture-format-decoder.js.map +1 -0
  156. package/dist/shadertypes/texture-types/texture-format-generics.d.ts +34 -0
  157. package/dist/shadertypes/texture-types/texture-format-generics.d.ts.map +1 -0
  158. package/dist/shadertypes/texture-types/texture-format-generics.js.map +1 -0
  159. package/dist/shadertypes/texture-types/texture-format-table.d.ts.map +1 -0
  160. package/dist/shadertypes/{textures → texture-types}/texture-format-table.js +10 -9
  161. package/dist/shadertypes/texture-types/texture-format-table.js.map +1 -0
  162. package/dist/shadertypes/{textures → texture-types}/texture-formats.d.ts +51 -17
  163. package/dist/shadertypes/texture-types/texture-formats.d.ts.map +1 -0
  164. package/dist/shadertypes/{textures → texture-types}/texture-formats.js +1 -0
  165. package/dist/shadertypes/texture-types/texture-formats.js.map +1 -0
  166. package/dist/shadertypes/texture-types/texture-layout.d.ts +5 -0
  167. package/dist/shadertypes/texture-types/texture-layout.d.ts.map +1 -0
  168. package/dist/shadertypes/texture-types/texture-layout.js +41 -0
  169. package/dist/shadertypes/texture-types/texture-layout.js.map +1 -0
  170. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts +24 -0
  171. package/dist/shadertypes/vertex-types/vertex-format-decoder.d.ts.map +1 -0
  172. package/dist/shadertypes/vertex-types/vertex-format-decoder.js +106 -0
  173. package/dist/shadertypes/vertex-types/vertex-format-decoder.js.map +1 -0
  174. package/dist/shadertypes/vertex-types/vertex-formats.d.ts +50 -0
  175. package/dist/shadertypes/vertex-types/vertex-formats.d.ts.map +1 -0
  176. package/dist/shadertypes/vertex-types/vertex-formats.js.map +1 -0
  177. package/dist/utils/array-equal.d.ts +1 -1
  178. package/dist/utils/array-equal.d.ts.map +1 -1
  179. package/dist/utils/array-equal.js +15 -9
  180. package/dist/utils/array-equal.js.map +1 -1
  181. package/dist/utils/assert.d.ts +5 -0
  182. package/dist/utils/assert.d.ts.map +1 -0
  183. package/dist/utils/assert.js +17 -0
  184. package/dist/utils/assert.js.map +1 -0
  185. package/dist/utils/stats-manager.d.ts.map +1 -1
  186. package/dist/utils/stats-manager.js +61 -1
  187. package/dist/utils/stats-manager.js.map +1 -1
  188. package/package.json +6 -6
  189. package/src/adapter/canvas-context.ts +7 -556
  190. package/src/adapter/canvas-observer.ts +130 -0
  191. package/src/adapter/canvas-surface.ts +521 -0
  192. package/src/adapter/device.ts +308 -24
  193. package/src/adapter/presentation-context.ts +16 -0
  194. package/src/adapter/resources/buffer.ts +13 -5
  195. package/src/adapter/resources/command-buffer.ts +4 -2
  196. package/src/adapter/resources/command-encoder.ts +101 -10
  197. package/src/adapter/resources/compute-pipeline.ts +2 -2
  198. package/src/adapter/resources/fence.ts +32 -0
  199. package/src/adapter/resources/framebuffer.ts +16 -13
  200. package/src/adapter/resources/query-set.ts +17 -1
  201. package/src/adapter/resources/render-pipeline.ts +52 -16
  202. package/src/adapter/resources/resource.ts +289 -14
  203. package/src/adapter/resources/shader.ts +28 -28
  204. package/src/adapter/resources/shared-render-pipeline.ts +40 -0
  205. package/src/adapter/resources/texture-view.ts +1 -1
  206. package/src/adapter/resources/texture.ts +427 -49
  207. package/src/adapter/types/attachments.ts +1 -1
  208. package/src/adapter/types/buffer-layout.ts +1 -1
  209. package/src/adapter/types/parameters.ts +4 -1
  210. package/src/adapter/types/shader-layout.ts +15 -9
  211. package/src/adapter/types/uniforms.ts +12 -0
  212. package/src/adapter-utils/bind-groups.ts +71 -0
  213. package/src/adapter-utils/format-compiler-log.ts +23 -15
  214. package/src/adapter-utils/get-attribute-from-layouts.ts +8 -11
  215. package/src/factories/bind-group-factory.ts +139 -0
  216. package/src/factories/core-module-state.ts +11 -0
  217. package/src/factories/pipeline-factory.ts +328 -0
  218. package/src/factories/shader-factory.ts +103 -0
  219. package/src/index.ts +70 -26
  220. package/src/portable/shader-block-writer.ts +254 -0
  221. package/src/portable/uniform-block.ts +1 -1
  222. package/src/portable/uniform-store.ts +98 -40
  223. package/src/shadertypes/data-types/data-type-decoder.ts +105 -0
  224. package/src/shadertypes/data-types/data-types.ts +100 -48
  225. package/src/shadertypes/data-types/decode-data-types.ts +2 -1
  226. package/src/{image-utils → shadertypes/image-types}/image-types.ts +0 -7
  227. package/src/shadertypes/shader-types/shader-block-layout.ts +340 -0
  228. package/src/shadertypes/{data-types/decode-shader-types.ts → shader-types/shader-type-decoder.ts} +88 -14
  229. package/src/shadertypes/shader-types/shader-types.ts +207 -0
  230. package/src/shadertypes/{textures → texture-types}/pixel-utils.ts +4 -4
  231. package/src/shadertypes/{textures → texture-types}/texture-format-decoder.ts +166 -45
  232. package/src/shadertypes/{textures → texture-types}/texture-format-generics.ts +42 -48
  233. package/src/shadertypes/{textures → texture-types}/texture-format-table.ts +10 -9
  234. package/src/shadertypes/{textures → texture-types}/texture-formats.ts +73 -17
  235. package/src/shadertypes/texture-types/texture-layout.ts +60 -0
  236. package/src/shadertypes/vertex-types/vertex-format-decoder.ts +131 -0
  237. package/src/shadertypes/vertex-types/vertex-formats.ts +183 -0
  238. package/src/utils/array-equal.ts +21 -9
  239. package/src/utils/assert.ts +18 -0
  240. package/src/utils/stats-manager.ts +76 -2
  241. package/dist/image-utils/image-types.d.ts.map +0 -1
  242. package/dist/image-utils/image-types.js.map +0 -1
  243. package/dist/portable/uniform-buffer-layout.d.ts +0 -28
  244. package/dist/portable/uniform-buffer-layout.d.ts.map +0 -1
  245. package/dist/portable/uniform-buffer-layout.js +0 -96
  246. package/dist/portable/uniform-buffer-layout.js.map +0 -1
  247. package/dist/shadertypes/data-types/decode-shader-types.d.ts +0 -17
  248. package/dist/shadertypes/data-types/decode-shader-types.d.ts.map +0 -1
  249. package/dist/shadertypes/data-types/decode-shader-types.js.map +0 -1
  250. package/dist/shadertypes/data-types/shader-types.d.ts +0 -45
  251. package/dist/shadertypes/data-types/shader-types.d.ts.map +0 -1
  252. package/dist/shadertypes/data-types/shader-types.js.map +0 -1
  253. package/dist/shadertypes/textures/pixel-utils.d.ts.map +0 -1
  254. package/dist/shadertypes/textures/pixel-utils.js.map +0 -1
  255. package/dist/shadertypes/textures/texture-format-decoder.d.ts +0 -18
  256. package/dist/shadertypes/textures/texture-format-decoder.d.ts.map +0 -1
  257. package/dist/shadertypes/textures/texture-format-decoder.js.map +0 -1
  258. package/dist/shadertypes/textures/texture-format-generics.d.ts +0 -33
  259. package/dist/shadertypes/textures/texture-format-generics.d.ts.map +0 -1
  260. package/dist/shadertypes/textures/texture-format-generics.js.map +0 -1
  261. package/dist/shadertypes/textures/texture-format-table.d.ts.map +0 -1
  262. package/dist/shadertypes/textures/texture-format-table.js.map +0 -1
  263. package/dist/shadertypes/textures/texture-formats.d.ts.map +0 -1
  264. package/dist/shadertypes/textures/texture-formats.js.map +0 -1
  265. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts +0 -18
  266. package/dist/shadertypes/vertex-arrays/decode-vertex-format.d.ts.map +0 -1
  267. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js +0 -100
  268. package/dist/shadertypes/vertex-arrays/decode-vertex-format.js.map +0 -1
  269. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts +0 -27
  270. package/dist/shadertypes/vertex-arrays/vertex-formats.d.ts.map +0 -1
  271. package/dist/shadertypes/vertex-arrays/vertex-formats.js.map +0 -1
  272. package/src/portable/uniform-buffer-layout.ts +0 -118
  273. package/src/shadertypes/data-types/shader-types.ts +0 -87
  274. package/src/shadertypes/vertex-arrays/decode-vertex-format.ts +0 -124
  275. package/src/shadertypes/vertex-arrays/vertex-formats.ts +0 -91
  276. /package/dist/{image-utils → shadertypes/image-types}/image-types.js +0 -0
  277. /package/dist/shadertypes/{textures → texture-types}/pixel-utils.d.ts +0 -0
  278. /package/dist/shadertypes/{textures → texture-types}/texture-format-generics.js +0 -0
  279. /package/dist/shadertypes/{textures → texture-types}/texture-format-table.d.ts +0 -0
  280. /package/dist/shadertypes/{vertex-arrays → vertex-types}/vertex-formats.js +0 -0
@@ -0,0 +1,521 @@
1
+ // luma.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {isBrowser} from '@probe.gl/env';
6
+ import type {Device} from './device';
7
+ import type {CanvasContext} from './canvas-context';
8
+ import {CanvasObserver} from './canvas-observer';
9
+ import type {PresentationContext} from './presentation-context';
10
+ import type {Framebuffer} from './resources/framebuffer';
11
+ import type {TextureFormatDepthStencil} from '../shadertypes/texture-types/texture-formats';
12
+ import {uid} from '../utils/uid';
13
+ import {withResolvers} from '../utils/promise-utils';
14
+ import {assertDefined} from '../utils/assert';
15
+
16
+ /** Properties for a CanvasContext */
17
+ export type CanvasContextProps = {
18
+ /** Identifier, for debugging */
19
+ id?: string;
20
+ /** If a canvas not supplied, one will be created and added to the DOM. If a string, a canvas with that id will be looked up in the DOM */
21
+ canvas?: HTMLCanvasElement | OffscreenCanvas | string | null;
22
+ /** If new canvas is created, it will be created in the specified container, otherwise is appended as a child of document.body */
23
+ container?: HTMLElement | string | null;
24
+ /** Width in pixels of the canvas - used when creating a new canvas */
25
+ width?: number;
26
+ /** Height in pixels of the canvas - used when creating a new canvas */
27
+ height?: number;
28
+ /** Visibility (only used if new canvas is created). */
29
+ visible?: boolean;
30
+ /** Whether to size the drawing buffer to the pixel size during auto resize. If a number is provided it is used as a static pixel ratio */
31
+ useDevicePixels?: boolean | number;
32
+ /** Whether to track window resizes. */
33
+ autoResize?: boolean;
34
+ /** @see https://developer.mozilla.org/en-US/docs/Web/API/GPUCanvasContext/configure#alphamode */
35
+ alphaMode?: 'opaque' | 'premultiplied';
36
+ /** @see https://developer.mozilla.org/en-US/docs/Web/API/GPUCanvasContext/configure#colorspace */
37
+ colorSpace?: 'srgb'; // GPUPredefinedColorSpace
38
+ /** Whether to track position changes. Calls this.device.onPositionChange */
39
+ trackPosition?: boolean;
40
+ };
41
+
42
+ export type MutableCanvasContextProps = {
43
+ /** Whether to size the drawing buffer to the pixel size during auto resize. If a number is provided it is used as a static pixel ratio */
44
+ useDevicePixels?: boolean | number;
45
+ };
46
+
47
+ /**
48
+ * Shared tracked-canvas lifecycle used by both renderable and presentation contexts.
49
+ * - Creates a new canvas or looks up a canvas from the DOM
50
+ * - Provides check for DOM loaded
51
+ * @todo commit() @see https://github.com/w3ctag/design-reviews/issues/288
52
+ * @todo transferControlToOffscreen: @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/transferControlToOffscreen
53
+ */
54
+ export abstract class CanvasSurface {
55
+ static isHTMLCanvas(canvas: unknown): canvas is HTMLCanvasElement {
56
+ return typeof HTMLCanvasElement !== 'undefined' && canvas instanceof HTMLCanvasElement;
57
+ }
58
+
59
+ static isOffscreenCanvas(canvas: unknown): canvas is OffscreenCanvas {
60
+ return typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas;
61
+ }
62
+
63
+ static defaultProps: Required<CanvasContextProps> = {
64
+ id: undefined!,
65
+ canvas: null,
66
+ width: 800,
67
+ height: 600,
68
+ useDevicePixels: true,
69
+ autoResize: true,
70
+ container: null,
71
+ visible: true,
72
+ alphaMode: 'opaque',
73
+ colorSpace: 'srgb',
74
+ trackPosition: false
75
+ };
76
+
77
+ abstract readonly device: Device;
78
+ abstract readonly handle: unknown;
79
+ readonly id: string;
80
+
81
+ readonly props: Required<CanvasContextProps>;
82
+ readonly canvas: HTMLCanvasElement | OffscreenCanvas;
83
+ /** Handle to HTML canvas */
84
+ readonly htmlCanvas?: HTMLCanvasElement;
85
+ /** Handle to wrapped OffScreenCanvas */
86
+ readonly offscreenCanvas?: OffscreenCanvas;
87
+ readonly type: 'html-canvas' | 'offscreen-canvas' | 'node';
88
+
89
+ /** Promise that resolved once the resize observer has updated the pixel size */
90
+ initialized: Promise<void>;
91
+ isInitialized: boolean = false;
92
+
93
+ /** Visibility is automatically updated (via an IntersectionObserver) */
94
+ isVisible: boolean = true;
95
+
96
+ /** Width of canvas in CSS units (tracked by a ResizeObserver) */
97
+ cssWidth: number;
98
+ /** Height of canvas in CSS units (tracked by a ResizeObserver) */
99
+ cssHeight: number;
100
+
101
+ /** Device pixel ratio. Automatically updated via media queries */
102
+ devicePixelRatio: number;
103
+ /** Exact width of canvas in physical pixels (tracked by a ResizeObserver) */
104
+ devicePixelWidth: number;
105
+ /** Exact height of canvas in physical pixels (tracked by a ResizeObserver) */
106
+ devicePixelHeight: number;
107
+
108
+ /** Width of drawing buffer: automatically tracks this.pixelWidth if props.autoResize is true */
109
+ drawingBufferWidth: number;
110
+ /** Height of drawing buffer: automatically tracks this.pixelHeight if props.autoResize is true */
111
+ drawingBufferHeight: number;
112
+
113
+ /** Resolves when the canvas is initialized, i.e. when the ResizeObserver has updated the pixel size */
114
+ protected _initializedResolvers = withResolvers<void>();
115
+ protected _canvasObserver: CanvasObserver;
116
+ /** Position of the canvas in the document, updated by a timer */
117
+ protected _position: [number, number] = [0, 0];
118
+ /** Whether this canvas context has been destroyed */
119
+ protected destroyed = false;
120
+ /** Whether the drawing buffer size needs to be resized (deferred resizing to avoid flicker) */
121
+ protected _needsDrawingBufferResize: boolean = true;
122
+
123
+ abstract get [Symbol.toStringTag](): string;
124
+
125
+ toString(): string {
126
+ return `${this[Symbol.toStringTag]}(${this.id})`;
127
+ }
128
+
129
+ constructor(props?: CanvasContextProps) {
130
+ this.props = {...CanvasSurface.defaultProps, ...props};
131
+ props = this.props;
132
+
133
+ this.initialized = this._initializedResolvers.promise;
134
+
135
+ if (!isBrowser()) {
136
+ this.canvas = {width: props.width || 1, height: props.height || 1} as OffscreenCanvas;
137
+ } else if (!props.canvas) {
138
+ this.canvas = createCanvasElement(props);
139
+ } else if (typeof props.canvas === 'string') {
140
+ this.canvas = getCanvasFromDOM(props.canvas);
141
+ } else {
142
+ this.canvas = props.canvas;
143
+ }
144
+
145
+ if (CanvasSurface.isHTMLCanvas(this.canvas)) {
146
+ this.id = props.id || this.canvas.id;
147
+ this.type = 'html-canvas';
148
+ this.htmlCanvas = this.canvas;
149
+ } else if (CanvasSurface.isOffscreenCanvas(this.canvas)) {
150
+ this.id = props.id || 'offscreen-canvas';
151
+ this.type = 'offscreen-canvas';
152
+ this.offscreenCanvas = this.canvas;
153
+ } else {
154
+ this.id = props.id || 'node-canvas-context';
155
+ this.type = 'node';
156
+ }
157
+
158
+ this.cssWidth = this.htmlCanvas?.clientWidth || this.canvas.width;
159
+ this.cssHeight = this.htmlCanvas?.clientHeight || this.canvas.height;
160
+ this.devicePixelWidth = this.canvas.width;
161
+ this.devicePixelHeight = this.canvas.height;
162
+ this.drawingBufferWidth = this.canvas.width;
163
+ this.drawingBufferHeight = this.canvas.height;
164
+ this.devicePixelRatio = globalThis.devicePixelRatio || 1;
165
+ this._position = [0, 0];
166
+ this._canvasObserver = new CanvasObserver({
167
+ canvas: this.htmlCanvas,
168
+ trackPosition: this.props.trackPosition,
169
+ onResize: entries => this._handleResize(entries),
170
+ onIntersection: entries => this._handleIntersection(entries),
171
+ onDevicePixelRatioChange: () => this._observeDevicePixelRatio(),
172
+ onPositionChange: () => this.updatePosition()
173
+ });
174
+ }
175
+
176
+ destroy() {
177
+ if (!this.destroyed) {
178
+ this.destroyed = true;
179
+ this._stopObservers();
180
+ // @ts-expect-error Clear the device to make sure we don't access it after destruction.
181
+ this.device = null;
182
+ }
183
+ }
184
+
185
+ setProps(props: MutableCanvasContextProps): this {
186
+ if ('useDevicePixels' in props) {
187
+ this.props.useDevicePixels = props.useDevicePixels || false;
188
+ this._updateDrawingBufferSize();
189
+ }
190
+ return this;
191
+ }
192
+
193
+ /** Returns a framebuffer with properly resized current 'swap chain' textures */
194
+ getCurrentFramebuffer(options?: {
195
+ depthStencilFormat?: TextureFormatDepthStencil | false;
196
+ }): Framebuffer {
197
+ this._resizeDrawingBufferIfNeeded();
198
+ return this._getCurrentFramebuffer(options);
199
+ }
200
+
201
+ getCSSSize(): [number, number] {
202
+ return [this.cssWidth, this.cssHeight];
203
+ }
204
+
205
+ getPosition() {
206
+ return this._position;
207
+ }
208
+
209
+ getDevicePixelSize(): [number, number] {
210
+ return [this.devicePixelWidth, this.devicePixelHeight];
211
+ }
212
+
213
+ getDrawingBufferSize(): [number, number] {
214
+ return [this.drawingBufferWidth, this.drawingBufferHeight];
215
+ }
216
+
217
+ getMaxDrawingBufferSize(): [number, number] {
218
+ const maxTextureDimension = this.device.limits.maxTextureDimension2D;
219
+ return [maxTextureDimension, maxTextureDimension];
220
+ }
221
+
222
+ setDrawingBufferSize(width: number, height: number) {
223
+ width = Math.floor(width);
224
+ height = Math.floor(height);
225
+ if (this.drawingBufferWidth === width && this.drawingBufferHeight === height) {
226
+ return;
227
+ }
228
+ this.drawingBufferWidth = width;
229
+ this.drawingBufferHeight = height;
230
+ this._needsDrawingBufferResize = true;
231
+ }
232
+
233
+ getDevicePixelRatio(): number {
234
+ const devicePixelRatio = typeof window !== 'undefined' && window.devicePixelRatio;
235
+ return devicePixelRatio || 1;
236
+ }
237
+
238
+ cssToDevicePixels(
239
+ cssPixel: [number, number],
240
+ yInvert: boolean = true
241
+ ): {
242
+ x: number;
243
+ y: number;
244
+ width: number;
245
+ height: number;
246
+ } {
247
+ const ratio = this.cssToDeviceRatio();
248
+ const [width, height] = this.getDrawingBufferSize();
249
+ return scalePixels(cssPixel, ratio, width, height, yInvert);
250
+ }
251
+
252
+ /** @deprecated - use .getDevicePixelSize() */
253
+ getPixelSize() {
254
+ return this.getDevicePixelSize();
255
+ }
256
+
257
+ /** @deprecated Use the current drawing buffer size for projection setup. */
258
+ getAspect(): number {
259
+ const [width, height] = this.getDrawingBufferSize();
260
+ return width > 0 && height > 0 ? width / height : 1;
261
+ }
262
+
263
+ /** @deprecated Returns multiplier need to convert CSS size to Device size */
264
+ cssToDeviceRatio(): number {
265
+ try {
266
+ const [drawingBufferWidth] = this.getDrawingBufferSize();
267
+ const [cssWidth] = this.getCSSSize();
268
+ return cssWidth ? drawingBufferWidth / cssWidth : 1;
269
+ } catch {
270
+ return 1;
271
+ }
272
+ }
273
+
274
+ /** @deprecated Use canvasContext.setDrawingBufferSize() */
275
+ resize(size: {width: number; height: number}): void {
276
+ this.setDrawingBufferSize(size.width, size.height);
277
+ }
278
+
279
+ protected abstract _configureDevice(): void;
280
+
281
+ protected abstract _getCurrentFramebuffer(options?: {
282
+ depthStencilFormat?: TextureFormatDepthStencil | false;
283
+ }): Framebuffer;
284
+
285
+ protected _setAutoCreatedCanvasId(id: string) {
286
+ if (this.htmlCanvas?.id === 'lumagl-auto-created-canvas') {
287
+ this.htmlCanvas.id = id;
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Starts DOM observation after the derived context and its device are fully initialized.
293
+ *
294
+ * `CanvasSurface` construction runs before subclasses can assign `this.device`, and the
295
+ * default WebGL canvas context is created before `WebGLDevice` has initialized `limits`,
296
+ * `features`, and the rest of its runtime state. Deferring observer startup avoids early
297
+ * `ResizeObserver` and DPR callbacks running against a partially initialized device.
298
+ */
299
+ _startObservers(): void {
300
+ if (this.destroyed) {
301
+ return;
302
+ }
303
+ this._canvasObserver.start();
304
+ }
305
+
306
+ /**
307
+ * Stops all DOM observation and timers associated with a canvas surface.
308
+ *
309
+ * This pairs with `_startObservers()` so teardown uses the same lifecycle whether a context is
310
+ * explicitly destroyed, abandoned during device reuse, or temporarily has not started observing
311
+ * yet. Centralizing shutdown here keeps resize/DPR/position watchers from surviving past the
312
+ * lifetime of the owning device.
313
+ */
314
+ _stopObservers(): void {
315
+ this._canvasObserver.stop();
316
+ }
317
+
318
+ protected _handleIntersection(entries: IntersectionObserverEntry[]) {
319
+ if (this.destroyed) {
320
+ return;
321
+ }
322
+
323
+ const entry = entries.find(entry_ => entry_.target === this.canvas);
324
+ if (!entry) {
325
+ return;
326
+ }
327
+ const isVisible = entry.isIntersecting;
328
+ if (this.isVisible !== isVisible) {
329
+ this.isVisible = isVisible;
330
+ this.device.props.onVisibilityChange(this as CanvasContext | PresentationContext);
331
+ }
332
+ }
333
+
334
+ protected _handleResize(entries: ResizeObserverEntry[]) {
335
+ if (this.destroyed) {
336
+ return;
337
+ }
338
+
339
+ const entry = entries.find(entry_ => entry_.target === this.canvas);
340
+ if (!entry) {
341
+ return;
342
+ }
343
+
344
+ const contentBoxSize = assertDefined(entry.contentBoxSize?.[0]);
345
+ this.cssWidth = contentBoxSize.inlineSize;
346
+ this.cssHeight = contentBoxSize.blockSize;
347
+
348
+ const oldPixelSize = this.getDevicePixelSize();
349
+
350
+ const devicePixelWidth =
351
+ entry.devicePixelContentBoxSize?.[0]?.inlineSize ||
352
+ contentBoxSize.inlineSize * devicePixelRatio;
353
+
354
+ const devicePixelHeight =
355
+ entry.devicePixelContentBoxSize?.[0]?.blockSize ||
356
+ contentBoxSize.blockSize * devicePixelRatio;
357
+
358
+ const [maxDevicePixelWidth, maxDevicePixelHeight] = this.getMaxDrawingBufferSize();
359
+ this.devicePixelWidth = Math.max(1, Math.min(devicePixelWidth, maxDevicePixelWidth));
360
+ this.devicePixelHeight = Math.max(1, Math.min(devicePixelHeight, maxDevicePixelHeight));
361
+
362
+ this._updateDrawingBufferSize();
363
+
364
+ this.device.props.onResize(this as CanvasContext | PresentationContext, {oldPixelSize});
365
+ }
366
+
367
+ protected _updateDrawingBufferSize() {
368
+ if (this.props.autoResize) {
369
+ if (typeof this.props.useDevicePixels === 'number') {
370
+ const devicePixelRatio = this.props.useDevicePixels;
371
+ this.setDrawingBufferSize(
372
+ this.cssWidth * devicePixelRatio,
373
+ this.cssHeight * devicePixelRatio
374
+ );
375
+ } else if (this.props.useDevicePixels) {
376
+ this.setDrawingBufferSize(this.devicePixelWidth, this.devicePixelHeight);
377
+ } else {
378
+ this.setDrawingBufferSize(this.cssWidth, this.cssHeight);
379
+ }
380
+ }
381
+
382
+ this._initializedResolvers.resolve();
383
+ this.isInitialized = true;
384
+
385
+ this.updatePosition();
386
+ }
387
+
388
+ _resizeDrawingBufferIfNeeded() {
389
+ if (this._needsDrawingBufferResize) {
390
+ this._needsDrawingBufferResize = false;
391
+ const sizeChanged =
392
+ this.drawingBufferWidth !== this.canvas.width ||
393
+ this.drawingBufferHeight !== this.canvas.height;
394
+ if (sizeChanged) {
395
+ this.canvas.width = this.drawingBufferWidth;
396
+ this.canvas.height = this.drawingBufferHeight;
397
+ this._configureDevice();
398
+ }
399
+ }
400
+ }
401
+
402
+ _observeDevicePixelRatio() {
403
+ if (this.destroyed || !this._canvasObserver.started) {
404
+ return;
405
+ }
406
+ const oldRatio = this.devicePixelRatio;
407
+ this.devicePixelRatio = window.devicePixelRatio;
408
+
409
+ this.updatePosition();
410
+
411
+ this.device.props.onDevicePixelRatioChange?.(this as CanvasContext | PresentationContext, {
412
+ oldRatio
413
+ });
414
+ }
415
+
416
+ updatePosition() {
417
+ if (this.destroyed) {
418
+ return;
419
+ }
420
+ const newRect = this.htmlCanvas?.getBoundingClientRect();
421
+ if (newRect) {
422
+ const position: [number, number] = [newRect.left, newRect.top];
423
+ this._position ??= position;
424
+ const positionChanged =
425
+ position[0] !== this._position[0] || position[1] !== this._position[1];
426
+ if (positionChanged) {
427
+ const oldPosition = this._position;
428
+ this._position = position;
429
+ this.device.props.onPositionChange?.(this as CanvasContext | PresentationContext, {
430
+ oldPosition
431
+ });
432
+ }
433
+ }
434
+ }
435
+ }
436
+
437
+ function getContainer(container: HTMLElement | string | null): HTMLElement {
438
+ if (typeof container === 'string') {
439
+ const element = document.getElementById(container);
440
+ if (!element) {
441
+ throw new Error(`${container} is not an HTML element`);
442
+ }
443
+ return element;
444
+ }
445
+ if (container) {
446
+ return container;
447
+ }
448
+ return document.body;
449
+ }
450
+
451
+ function getCanvasFromDOM(canvasId: string): HTMLCanvasElement {
452
+ const canvas = document.getElementById(canvasId);
453
+ if (!CanvasSurface.isHTMLCanvas(canvas)) {
454
+ throw new Error('Object is not a canvas element');
455
+ }
456
+ return canvas;
457
+ }
458
+
459
+ function createCanvasElement(props: CanvasContextProps) {
460
+ const {width, height} = props;
461
+ const newCanvas = document.createElement('canvas');
462
+ newCanvas.id = uid('lumagl-auto-created-canvas');
463
+ newCanvas.width = width || 1;
464
+ newCanvas.height = height || 1;
465
+ newCanvas.style.width = Number.isFinite(width) ? `${width}px` : '100%';
466
+ newCanvas.style.height = Number.isFinite(height) ? `${height}px` : '100%';
467
+ if (!props?.visible) {
468
+ newCanvas.style.visibility = 'hidden';
469
+ }
470
+ const container = getContainer(props?.container || null);
471
+ container.insertBefore(newCanvas, container.firstChild);
472
+
473
+ return newCanvas;
474
+ }
475
+
476
+ function scalePixels(
477
+ pixel: [number, number],
478
+ ratio: number,
479
+ width: number,
480
+ height: number,
481
+ yInvert: boolean
482
+ ): {
483
+ x: number;
484
+ y: number;
485
+ width: number;
486
+ height: number;
487
+ } {
488
+ const point = pixel;
489
+
490
+ const x = scaleX(point[0], ratio, width);
491
+ let y = scaleY(point[1], ratio, height, yInvert);
492
+
493
+ let temporary = scaleX(point[0] + 1, ratio, width);
494
+ const xHigh = temporary === width - 1 ? temporary : temporary - 1;
495
+
496
+ temporary = scaleY(point[1] + 1, ratio, height, yInvert);
497
+ let yHigh;
498
+ if (yInvert) {
499
+ temporary = temporary === 0 ? temporary : temporary + 1;
500
+ yHigh = y;
501
+ y = temporary;
502
+ } else {
503
+ yHigh = temporary === height - 1 ? temporary : temporary - 1;
504
+ }
505
+ return {
506
+ x,
507
+ y,
508
+ width: Math.max(xHigh - x + 1, 1),
509
+ height: Math.max(yHigh - y + 1, 1)
510
+ };
511
+ }
512
+
513
+ function scaleX(x: number, ratio: number, width: number): number {
514
+ return Math.min(Math.round(x * ratio), width - 1);
515
+ }
516
+
517
+ function scaleY(y: number, ratio: number, height: number, yInvert: boolean): number {
518
+ return yInvert
519
+ ? Math.max(0, height - 1 - Math.round(y * ratio))
520
+ : Math.min(Math.round(y * ratio), height - 1);
521
+ }