@tangram.gl/tangram-renderer 0.0.0-stage → 0.0.0

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 (321) hide show
  1. package/README.md +59 -2
  2. package/dist/core.js +36923 -0
  3. package/dist/core.js.map +6 -0
  4. package/dist/index.js +32 -0
  5. package/dist/loaders-gl-worker.js +82 -0
  6. package/dist/loaders-gl-worker.js.map +6 -0
  7. package/dist/map-logic.js +2 -0
  8. package/dist/map-logic.js.map +6 -0
  9. package/dist/projected-basemaps-worker.js +3 -0
  10. package/dist/projected-basemaps-worker.js.map +6 -0
  11. package/dist/shader-modules.js +141 -0
  12. package/dist/shader-modules.js.map +6 -0
  13. package/dist/style-schema.js +126 -0
  14. package/dist/style-schema.js.map +6 -0
  15. package/dist/tangram-style.schema.json +882 -0
  16. package/dist/tangram.debug.mjs +37139 -0
  17. package/dist/tangram.debug.mjs.map +6 -0
  18. package/dist/tangram.min.mjs +4950 -0
  19. package/dist/types/builders/earcut.d.ts +15 -0
  20. package/dist/types/core.d.ts +29 -0
  21. package/dist/types/gl/constants.d.ts +2 -0
  22. package/dist/types/gl/globe_mesh.d.ts +48 -0
  23. package/dist/types/gl/glsl.d.ts +17 -0
  24. package/dist/types/gl/vertex-constants.d.ts +4 -0
  25. package/dist/types/gl/vertex-types.d.ts +34 -0
  26. package/dist/types/gl/vertex_data.d.ts +32 -0
  27. package/dist/types/gl/vertex_elements.d.ts +8 -0
  28. package/dist/types/gl/vertex_layout.d.ts +32 -0
  29. package/dist/types/glsl.d.ts +14 -0
  30. package/dist/types/gpu/luma_device_renderer.d.ts +66 -0
  31. package/dist/types/gpu/resource_lifecycle.d.ts +4 -0
  32. package/dist/types/gpu/tangram_gpu_backend.d.ts +151 -0
  33. package/dist/types/index.d.ts +155 -0
  34. package/dist/types/lights/light-definitions.d.ts +121 -0
  35. package/dist/types/map-logic/draped-terrain-bounds.d.ts +41 -0
  36. package/dist/types/map-logic/globe-terrain-preparation.d.ts +85 -0
  37. package/dist/types/map-logic/globe-terrain.d.ts +54 -0
  38. package/dist/types/map-logic/index.d.ts +33 -0
  39. package/dist/types/map-logic/label-identity.d.ts +22 -0
  40. package/dist/types/map-logic/label-placement.d.ts +32 -0
  41. package/dist/types/map-logic/screen-bounds.d.ts +15 -0
  42. package/dist/types/map-logic/terrain-data.d.ts +55 -0
  43. package/dist/types/map-logic/terrain-error.d.ts +51 -0
  44. package/dist/types/map-logic/terrain-ground-topology.d.ts +26 -0
  45. package/dist/types/map-logic/terrain-height-field.d.ts +59 -0
  46. package/dist/types/map-logic/terrain-navigation.d.ts +27 -0
  47. package/dist/types/map-logic/terrain-neighborhood.d.ts +5 -0
  48. package/dist/types/map-logic/terrain-query.d.ts +33 -0
  49. package/dist/types/map-logic/terrain-resource-budget.d.ts +51 -0
  50. package/dist/types/map-logic/terrain-transition-topology.d.ts +23 -0
  51. package/dist/types/map-logic/tile-build-queue.d.ts +51 -0
  52. package/dist/types/map-logic/tile-cache-policy.d.ts +46 -0
  53. package/dist/types/map-logic/tile-residency.d.ts +17 -0
  54. package/dist/types/map-logic/triangle-query-index.d.ts +87 -0
  55. package/dist/types/procedures/js-yaml.d.ts +15 -0
  56. package/dist/types/procedures/mesh-projector.d.ts +107 -0
  57. package/dist/types/procedures/mvt-dependencies.d.ts +20 -0
  58. package/dist/types/procedures/projected-coordinate-transform.d.ts +27 -0
  59. package/dist/types/procedures/projection-batch-executor.d.ts +53 -0
  60. package/dist/types/procedures/scene-yaml-legacy.d.ts +6 -0
  61. package/dist/types/procedures/terrain-draping.d.ts +165 -0
  62. package/dist/types/procedures/terrain-globe.d.ts +6 -0
  63. package/dist/types/procedures/terrain-styled-topology.d.ts +34 -0
  64. package/dist/types/procedures/web-mercator-legacy.d.ts +4 -0
  65. package/dist/types/procedures/web-mercator-math.d.ts +4 -0
  66. package/dist/types/scene/globals.d.ts +11 -0
  67. package/dist/types/scene/ground_footprint.d.ts +16 -0
  68. package/dist/types/scene/host_frame.d.ts +54 -0
  69. package/dist/types/scene/projection_math.d.ts +52 -0
  70. package/dist/types/scene/scene-resource-types.d.ts +177 -0
  71. package/dist/types/scene/scene_bundle.d.ts +69 -0
  72. package/dist/types/scene/visibility_adapter.d.ts +106 -0
  73. package/dist/types/selection/draped-terrain-surface.d.ts +78 -0
  74. package/dist/types/selection/terrain_surface.d.ts +149 -0
  75. package/dist/types/shader-modules/globe-horizon.d.ts +15 -0
  76. package/dist/types/shader-modules/height-decode.d.ts +13 -0
  77. package/dist/types/shader-modules/hillshade.d.ts +13 -0
  78. package/dist/types/shader-modules/index.d.ts +6 -0
  79. package/dist/types/shader-modules/planar.d.ts +12 -0
  80. package/dist/types/shader-modules/sphere-map.d.ts +13 -0
  81. package/dist/types/shader-modules/triplanar.d.ts +15 -0
  82. package/dist/types/sources/decoded_tile_store.d.ts +95 -0
  83. package/dist/types/sources/tile_source_metadata.d.ts +32 -0
  84. package/dist/types/styles/text/fontfaceobserver.d.ts +10 -0
  85. package/dist/types/tile/tile_id.d.ts +37 -0
  86. package/dist/types/tile/tile_traversal_adapter.d.ts +63 -0
  87. package/dist/types/types.d.ts +293 -0
  88. package/dist/types/utils/geo.d.ts +57 -0
  89. package/dist/types/utils/hash.d.ts +1 -0
  90. package/dist/types/utils/log.d.ts +27 -0
  91. package/dist/types/utils/props.d.ts +6 -0
  92. package/dist/types/utils/subscribe.d.ts +10 -0
  93. package/dist/types/utils/thread.d.ts +6 -0
  94. package/dist/types/utils/urls.d.ts +26 -0
  95. package/dist/types/utils/utils.d.ts +26 -0
  96. package/dist/types/utils/version.d.ts +2 -0
  97. package/dist/types/utils/worker-types.d.ts +68 -0
  98. package/dist/types/utils/worker_broker.d.ts +3 -0
  99. package/package.json +103 -3
  100. package/src/builders/common.ts +41 -0
  101. package/src/builders/earcut.d.ts +15 -0
  102. package/src/builders/geometry-types.ts +60 -0
  103. package/src/builders/points.ts +115 -0
  104. package/src/builders/polygons.ts +225 -0
  105. package/src/builders/polylines.ts +682 -0
  106. package/src/builders/wireframe.ts +31 -0
  107. package/src/core.d.ts +29 -0
  108. package/src/core.ts +33 -0
  109. package/src/experimental/loaders-gl-worker.ts +19 -0
  110. package/src/experimental/projected-basemaps-worker.ts +13 -0
  111. package/src/experimental/projected-mesh-cache.ts +137 -0
  112. package/src/experimental/projected-mesh-domain.ts +110 -0
  113. package/src/experimental/projected-mesh-refinement.ts +193 -0
  114. package/src/experimental/projected-mesh.ts +399 -0
  115. package/src/experimental/projected-normal.ts +26 -0
  116. package/src/experimental/projected-symbol-mesh.ts +74 -0
  117. package/src/gl/constants.ts +18 -0
  118. package/src/gl/context.ts +103 -0
  119. package/src/gl/extensions.ts +30 -0
  120. package/src/gl/globe_mesh.ts +285 -0
  121. package/src/gl/glsl.ts +257 -0
  122. package/src/gl/mesh-types.ts +56 -0
  123. package/src/gl/render_state.ts +111 -0
  124. package/src/gl/shader_program.ts +1310 -0
  125. package/src/gl/texture.ts +814 -0
  126. package/src/gl/uniform_buffer.ts +340 -0
  127. package/src/gl/vao.ts +154 -0
  128. package/src/gl/vbo_mesh.ts +349 -0
  129. package/src/gl/vertex-constants.ts +19 -0
  130. package/src/gl/vertex-types.ts +35 -0
  131. package/src/gl/vertex_data.ts +126 -0
  132. package/src/gl/vertex_elements.ts +54 -0
  133. package/src/gl/vertex_layout.ts +241 -0
  134. package/src/glsl.d.ts +14 -0
  135. package/src/gpu/luma_device_renderer.ts +579 -0
  136. package/src/gpu/pixel_readback.ts +51 -0
  137. package/src/gpu/resource_lifecycle.ts +32 -0
  138. package/src/gpu/tangram_gpu_backend.ts +195 -0
  139. package/src/index.d.ts +155 -0
  140. package/src/index.ts +105 -0
  141. package/src/labels/collision-types.ts +94 -0
  142. package/src/labels/collision.ts +273 -0
  143. package/src/labels/collision_grid.ts +61 -0
  144. package/src/labels/intersect.ts +30 -0
  145. package/src/labels/label-types.ts +91 -0
  146. package/src/labels/label.ts +207 -0
  147. package/src/labels/label_line.ts +801 -0
  148. package/src/labels/label_point.ts +131 -0
  149. package/src/labels/main-pass-types.ts +73 -0
  150. package/src/labels/main_pass.ts +221 -0
  151. package/src/labels/point_anchor.ts +100 -0
  152. package/src/labels/point_placement.ts +150 -0
  153. package/src/labels/projected-pass.ts +259 -0
  154. package/src/labels/repeat_group.ts +72 -0
  155. package/src/lights/ambient_light.glsl +18 -0
  156. package/src/lights/directional_light.glsl +39 -0
  157. package/src/lights/geographic-lights.ts +21 -0
  158. package/src/lights/light-definitions.ts +285 -0
  159. package/src/lights/light.ts +590 -0
  160. package/src/lights/lighting-uniforms.ts +80 -0
  161. package/src/lights/lighting-wgsl.ts +116 -0
  162. package/src/lights/material.glsl +237 -0
  163. package/src/lights/material.ts +145 -0
  164. package/src/lights/native-falloff.ts +37 -0
  165. package/src/lights/point_light.glsl +96 -0
  166. package/src/lights/spot_light.glsl +111 -0
  167. package/src/map-logic/draped-terrain-bounds.ts +71 -0
  168. package/src/map-logic/globe-terrain-preparation.ts +217 -0
  169. package/src/map-logic/globe-terrain.ts +296 -0
  170. package/src/map-logic/index.ts +37 -0
  171. package/src/map-logic/label-identity.ts +36 -0
  172. package/src/map-logic/label-placement.ts +117 -0
  173. package/src/map-logic/screen-bounds.ts +34 -0
  174. package/src/map-logic/terrain-data.ts +107 -0
  175. package/src/map-logic/terrain-error.ts +134 -0
  176. package/src/map-logic/terrain-ground-topology.ts +164 -0
  177. package/src/map-logic/terrain-height-field.ts +254 -0
  178. package/src/map-logic/terrain-navigation.ts +50 -0
  179. package/src/map-logic/terrain-neighborhood.ts +43 -0
  180. package/src/map-logic/terrain-query.ts +51 -0
  181. package/src/map-logic/terrain-resource-budget.ts +124 -0
  182. package/src/map-logic/terrain-transition-topology.ts +164 -0
  183. package/src/map-logic/tile-build-queue.ts +110 -0
  184. package/src/map-logic/tile-cache-policy.ts +89 -0
  185. package/src/map-logic/tile-residency.ts +50 -0
  186. package/src/map-logic/triangle-query-index.ts +265 -0
  187. package/src/procedures/js-yaml.d.ts +15 -0
  188. package/src/procedures/mesh-projector.ts +191 -0
  189. package/src/procedures/mlt-loaders.ts +55 -0
  190. package/src/procedures/mvt-dependencies.d.ts +20 -0
  191. package/src/procedures/mvt-legacy.ts +150 -0
  192. package/src/procedures/mvt-loaders.ts +53 -0
  193. package/src/procedures/mvt-parser.ts +48 -0
  194. package/src/procedures/mvt-properties.ts +36 -0
  195. package/src/procedures/mvt-tile-provider.ts +72 -0
  196. package/src/procedures/pmtiles-loader.ts +75 -0
  197. package/src/procedures/projected-coordinate-transform.ts +79 -0
  198. package/src/procedures/projection-batch-executor.ts +140 -0
  199. package/src/procedures/scene-yaml-legacy.ts +16 -0
  200. package/src/procedures/scene-yaml-loaders.ts +10 -0
  201. package/src/procedures/terrain-draping.ts +713 -0
  202. package/src/procedures/terrain-globe.ts +32 -0
  203. package/src/procedures/terrain-styled-topology.ts +184 -0
  204. package/src/procedures/web-mercator-legacy.ts +24 -0
  205. package/src/procedures/web-mercator-math.ts +50 -0
  206. package/src/scene/camera.ts +298 -0
  207. package/src/scene/camera_base.ts +116 -0
  208. package/src/scene/classic_scene.ts +20 -0
  209. package/src/scene/external_camera.ts +101 -0
  210. package/src/scene/globals.ts +120 -0
  211. package/src/scene/ground_footprint.ts +139 -0
  212. package/src/scene/host_frame.ts +326 -0
  213. package/src/scene/projected_tile_lod.ts +125 -0
  214. package/src/scene/projection_math.ts +142 -0
  215. package/src/scene/projection_shaders.ts +183 -0
  216. package/src/scene/renderer.ts +516 -0
  217. package/src/scene/scene-resource-types.ts +174 -0
  218. package/src/scene/scene.ts +2378 -0
  219. package/src/scene/scene_bundle.ts +304 -0
  220. package/src/scene/scene_debug.ts +129 -0
  221. package/src/scene/scene_loader.ts +402 -0
  222. package/src/scene/scene_worker.ts +528 -0
  223. package/src/scene/view.ts +683 -0
  224. package/src/scene/visibility_adapter.ts +319 -0
  225. package/src/scene/worker_url.ts +15 -0
  226. package/src/selection/draped-terrain-surface.ts +377 -0
  227. package/src/selection/selection-types.ts +79 -0
  228. package/src/selection/selection.ts +542 -0
  229. package/src/selection/selection_fragment.glsl +18 -0
  230. package/src/selection/selection_globals.glsl +9 -0
  231. package/src/selection/selection_pixels.ts +59 -0
  232. package/src/selection/selection_vertex.glsl +15 -0
  233. package/src/selection/terrain_surface.ts +298 -0
  234. package/src/shader-modules/globe-horizon.ts +52 -0
  235. package/src/shader-modules/height-decode.ts +41 -0
  236. package/src/shader-modules/hillshade.ts +70 -0
  237. package/src/shader-modules/index.ts +10 -0
  238. package/src/shader-modules/planar.ts +24 -0
  239. package/src/shader-modules/sphere-map.ts +38 -0
  240. package/src/shader-modules/triplanar.ts +45 -0
  241. package/src/sources/aligned_tile_source.ts +122 -0
  242. package/src/sources/data_source.ts +655 -0
  243. package/src/sources/decoded_tile_store.ts +245 -0
  244. package/src/sources/geojson.ts +300 -0
  245. package/src/sources/mvt.ts +247 -0
  246. package/src/sources/raster.ts +341 -0
  247. package/src/sources/shared_tile_source_adapter.ts +117 -0
  248. package/src/sources/sources.ts +10 -0
  249. package/src/sources/tile_source_adapter.ts +84 -0
  250. package/src/sources/tile_source_metadata.ts +65 -0
  251. package/src/sources/tile_source_state.ts +112 -0
  252. package/src/sources/topojson.ts +90 -0
  253. package/src/styles/feature_annotations.ts +16 -0
  254. package/src/styles/filter.ts +190 -0
  255. package/src/styles/geometry-style-types.ts +209 -0
  256. package/src/styles/globe_visibility_wgsl.ts +22 -0
  257. package/src/styles/layer-types.ts +45 -0
  258. package/src/styles/layer.ts +586 -0
  259. package/src/styles/lines/dasharray.ts +49 -0
  260. package/src/styles/lines/lines.ts +707 -0
  261. package/src/styles/lines/lines_wgsl.ts +224 -0
  262. package/src/styles/points/point-runtime-types.ts +125 -0
  263. package/src/styles/points/points.ts +1079 -0
  264. package/src/styles/points/points_fragment.glsl +126 -0
  265. package/src/styles/points/points_vertex.glsl +230 -0
  266. package/src/styles/points/points_wgsl.ts +189 -0
  267. package/src/styles/polygons/polygons.ts +268 -0
  268. package/src/styles/polygons/polygons_fragment.glsl +173 -0
  269. package/src/styles/polygons/polygons_vertex.glsl +213 -0
  270. package/src/styles/polygons/polygons_wgsl.ts +127 -0
  271. package/src/styles/property-types.ts +125 -0
  272. package/src/styles/raster/raster.ts +33 -0
  273. package/src/styles/raster/raster_globals.glsl +46 -0
  274. package/src/styles/style-mixing-types.ts +101 -0
  275. package/src/styles/style-runtime-types.ts +220 -0
  276. package/src/styles/style-schema.ts +133 -0
  277. package/src/styles/style.ts +1033 -0
  278. package/src/styles/style_globals.glsl +69 -0
  279. package/src/styles/style_manager.ts +464 -0
  280. package/src/styles/style_parser.ts +620 -0
  281. package/src/styles/text/font_manager.ts +180 -0
  282. package/src/styles/text/fontfaceobserver.d.ts +10 -0
  283. package/src/styles/text/text-types.ts +220 -0
  284. package/src/styles/text/text.ts +378 -0
  285. package/src/styles/text/text_canvas.ts +773 -0
  286. package/src/styles/text/text_labels.ts +436 -0
  287. package/src/styles/text/text_segments.ts +142 -0
  288. package/src/styles/text/text_settings.ts +228 -0
  289. package/src/styles/text/text_wgsl.ts +159 -0
  290. package/src/styles/text/text_wrap.ts +194 -0
  291. package/src/tile/globe_tile_preload.ts +40 -0
  292. package/src/tile/tangram_tileset_2d.ts +108 -0
  293. package/src/tile/tile-build-types.ts +155 -0
  294. package/src/tile/tile.ts +807 -0
  295. package/src/tile/tile_id.ts +172 -0
  296. package/src/tile/tile_manager.ts +889 -0
  297. package/src/tile/tile_pyramid.ts +119 -0
  298. package/src/tile/tile_resource_cache.ts +91 -0
  299. package/src/tile/tile_traversal_adapter.ts +132 -0
  300. package/src/types.ts +332 -0
  301. package/src/utils/debounce.ts +17 -0
  302. package/src/utils/debug_settings.ts +43 -0
  303. package/src/utils/errors.ts +12 -0
  304. package/src/utils/functions.ts +95 -0
  305. package/src/utils/geo.ts +364 -0
  306. package/src/utils/hash.ts +14 -0
  307. package/src/utils/log.ts +108 -0
  308. package/src/utils/media_capture.ts +193 -0
  309. package/src/utils/merge.ts +44 -0
  310. package/src/utils/obb.ts +134 -0
  311. package/src/utils/props.ts +43 -0
  312. package/src/utils/slice.ts +14 -0
  313. package/src/utils/subscribe.ts +58 -0
  314. package/src/utils/task.ts +154 -0
  315. package/src/utils/thread.ts +26 -0
  316. package/src/utils/urls.ts +223 -0
  317. package/src/utils/utils.ts +310 -0
  318. package/src/utils/vector.ts +197 -0
  319. package/src/utils/version.ts +8 -0
  320. package/src/utils/worker-types.ts +79 -0
  321. package/src/utils/worker_broker.ts +523 -0
@@ -0,0 +1,523 @@
1
+ // Tangram
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) 2013-2016 Brett Camper and Mapzen
4
+ // Copyright (c) 2026 vis.gl contributors
5
+
6
+ /*jshint worker: true*/
7
+
8
+ // WorkerBroker routes messages between web workers and the main thread, allowing for simpler
9
+ // async code via promises. Example usage:
10
+ //
11
+ // In web worker, register self as a callable "target", and define a method:
12
+ //
13
+ // WorkerBroker.addTarget('self', self);
14
+ //
15
+ // self.square = function (x) {
16
+ // return x * x;
17
+ // };
18
+ //
19
+ // In main thread, invoke that method and receive the result (if any) as a promise.
20
+ //
21
+ // worker = new Worker(...);
22
+ // WorkerBroker.addWorker(worker);
23
+ //
24
+ // WorkerBroker.postMessage(worker, 'self.square', 5).then(function(y) {
25
+ // console.log(y);
26
+ // });
27
+ //
28
+ // -> prints 25
29
+ //
30
+ // Async code:
31
+ //
32
+ // For synchronous code that must pass a return value to the main thread, the function can simply
33
+ // return an immediate value (see example above). For cases where the worker method needs to run
34
+ // asynchronous code, the function can return a promise, and the resolved or rejected value will
35
+ // be sent back to the main thread when the promise is fulfilled.
36
+ //
37
+ // Error handling:
38
+ //
39
+ // If the worker method either throws an error, or returns a promise that is rejected, it will be
40
+ // sent back to the main thread as a promise rejection. These two examples are equivalent:
41
+ //
42
+ // In worker, throwing an error:
43
+ //
44
+ // self.broken = function () {
45
+ // throw new Error('error in worker!');
46
+ // };
47
+ //
48
+ // In worker, returning a rejected promise:
49
+ //
50
+ // self.broken = function () {
51
+ // return Promise.reject(new Error('error in worker!'));
52
+ // };
53
+ //
54
+ // In main thread, both errors are received as a promise rejection:
55
+ //
56
+ // WorkerBroker.postMessage(worker, 'self.broken').then(
57
+ // // Promise resolved
58
+ // function() {
59
+ // console.log('success!');
60
+ // },
61
+ // // Promise rejected
62
+ // function(error) {
63
+ // console.log('error!', error);
64
+ // });
65
+ //
66
+ // -> prints 'error! error in worker'
67
+ //
68
+ // Calling from worker to main thread:
69
+ //
70
+ // The same style of calls can be made *from* a web worker, to the main thread. The API is the same
71
+ // with the exception that the first argument, 'worker', is not needed for WorkerBroker.postMessage(),
72
+ // since the main thread is the implicit target.
73
+ //
74
+ // In main thread, define a method and register it:
75
+ //
76
+ // var geometry = {
77
+ // length: function(x, y) {
78
+ // return Math.sqrt(x * x + y * y);
79
+ // }
80
+ // };
81
+ //
82
+ // WorkerBroker.addTarget('geometry', geometry);
83
+ //
84
+ // In worker thread):
85
+ //
86
+ // WorkerBroker.postMessage('geometry.length', 3, 4).then(function(d) {
87
+ // console.log(d);
88
+ // });
89
+ //
90
+ // -> prints 5
91
+ //
92
+
93
+ import Thread from './thread';
94
+ import log from './log';
95
+ import type {BrokerMethod, BrokerPacket, BrokerPostMessage, BrokerTransferable, BrokerWorker,
96
+ PendingBrokerMessage, TransferEnvelope, TransferEnvelopeFactory, WorkerBrokerApi} from './worker-types';
97
+
98
+ // The object is populated below; keeping staged construction preserves logger/broker initialization.
99
+ export const WorkerBroker = {} as WorkerBrokerApi;
100
+ export default WorkerBroker;
101
+
102
+ // Global list of all worker messages
103
+ // Uniquely tracks every call made between main thread and a worker
104
+ var message_id = 0;
105
+ var messages: Record<number, PendingBrokerMessage> = {};
106
+
107
+ // Register an object to receive calls from other thread
108
+ WorkerBroker.targets = {};
109
+ WorkerBroker.addTarget = function (name, target) {
110
+ WorkerBroker.targets[name] = target;
111
+ };
112
+
113
+ WorkerBroker.removeTarget = function (name) {
114
+ if (name) {
115
+ delete WorkerBroker.targets[name];
116
+ }
117
+ };
118
+
119
+ // Given a dot-notation-style method name, e.g. 'Object.object.method',
120
+ // find the object to call the method on from the list of registered targets
121
+ function findTarget (method: string | undefined): [] | [string | undefined, Record<string, unknown>] {
122
+ var chain: string[] = [];
123
+ if (typeof method === 'string') {
124
+ chain = method.split('.');
125
+ method = chain.pop();
126
+ }
127
+
128
+ var target = WorkerBroker.targets;
129
+
130
+ for (let m=0; m < chain.length; m++) {
131
+ if (target[chain[m]]) {
132
+ target = target[chain[m]] as Record<string, unknown>;
133
+ }
134
+ else {
135
+ return [];
136
+ }
137
+ }
138
+
139
+ return [method, target];
140
+ }
141
+
142
+ // Main thread:
143
+ // - Send messages to workers, and optionally receive an async response as a promise
144
+ // - Receive messages from workers, and optionally send an async response back as a promise
145
+ function setupMainThread (): void {
146
+
147
+ // Send a message to a worker, and optionally get an async response
148
+ // Arguments:
149
+ // - worker: one or more web worker instances to send the message to (single value or array)
150
+ // - method: the method with this name, specified with dot-notation, will be invoked in the worker
151
+ // - message: spread of arguments to call the method with
152
+ // Returns:
153
+ // - a promise that will be fulfilled if the worker method returns a value (could be immediately, or async)
154
+ //
155
+ WorkerBroker.postMessage = function (worker: BrokerWorker | BrokerWorker[], method: BrokerMethod, ...message: unknown[]) {
156
+ // If more than one worker specified, post to multiple
157
+ if (Array.isArray(worker)) {
158
+ return Promise.all(
159
+ worker.map(w => WorkerBroker.postMessage(w, method, ...message))
160
+ );
161
+ }
162
+
163
+ // Parse options
164
+ let options: {stringify?: boolean} = {};
165
+ if (typeof method === 'object') {
166
+ options = method;
167
+ method = method.method;
168
+ }
169
+
170
+ // Track state of this message
171
+ var promise = new Promise<unknown>((resolve, reject) => {
172
+ messages[message_id] = { method, message, resolve, reject };
173
+ });
174
+
175
+
176
+ let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
177
+
178
+ if (message && message.length === 1 && message[0] instanceof WorkerBroker.withTransferables) {
179
+ transferables = message[0].transferables;
180
+ message = message[0].value;
181
+ }
182
+
183
+ payload = {
184
+ type: 'main_send', // mark message as method invocation from main thread
185
+ message_id, // unique id for this message, for life of program
186
+ method, // will dispatch to a function of this name within the worker
187
+ message // message payload
188
+ };
189
+
190
+ if (options.stringify) {
191
+ payload = JSON.stringify(payload);
192
+ }
193
+
194
+ worker.postMessage(payload, transferables.map(t => t.object));
195
+ freeTransferables(transferables);
196
+ if (transferables.length > 0) {
197
+ log('trace', `'${method}' transferred ${transferables.length} objects to worker thread`);
198
+ }
199
+
200
+ message_id++;
201
+ return promise;
202
+ } as BrokerPostMessage;
203
+
204
+ // Add a worker to communicate with - each worker must be registered from the main thread
205
+ WorkerBroker.addWorker = function (worker) {
206
+ if (!(worker instanceof Worker)) {
207
+ throw Error('Worker broker could not add non-Worker object', worker as unknown as ErrorOptions);
208
+ }
209
+
210
+ worker.addEventListener('message', function WorkerBrokerMainThreadHandler(event) {
211
+ let data = ((typeof event.data === 'string') ? JSON.parse(event.data) : event.data) as BrokerPacket;
212
+ let id = data.message_id;
213
+
214
+ // Listen for messages coming back from the worker, and fulfill that message's promise
215
+ if (data.type === 'worker_reply') {
216
+ // Pass the result to the promise
217
+ if (messages[id]) {
218
+ if (data.error) {
219
+ messages[id].reject(data.error);
220
+ }
221
+ else {
222
+ messages[id].resolve(data.message);
223
+ }
224
+ delete messages[id];
225
+ }
226
+ }
227
+ // Listen for messages initiating a call from the worker, dispatch them,
228
+ // and send any return value back to the worker
229
+ // Unique id for this message & return call to main thread
230
+ else if (data.type === 'worker_send' && id != null) {
231
+ // Call the requested method and save the return value
232
+ let result: unknown, error: unknown, target: Record<string, unknown> | undefined, method_name: string | undefined, method;
233
+ try {
234
+ [method_name, target] = findTarget(data.method);
235
+ if (!target) {
236
+ throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because no object with that name is registered on main thread`);
237
+ }
238
+
239
+ method = (typeof target[method_name!] === 'function') && target[method_name!] as ((...arguments_: unknown[]) => unknown);
240
+ if (!method) {
241
+ throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because object has no method with that name`);
242
+ }
243
+
244
+ result = method.apply(target, data.message);
245
+ }
246
+ catch(e) {
247
+ // Thrown errors will be passed back (in string form) to worker
248
+ error = e;
249
+
250
+ }
251
+ // Send return value to worker
252
+ let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
253
+
254
+ // Async result
255
+ if (result instanceof Promise) {
256
+ result.then((value) => {
257
+ if (value instanceof WorkerBroker.withTransferables) {
258
+ transferables = value.transferables;
259
+ value = value.value[0];
260
+ }
261
+
262
+ payload = {
263
+ type: 'main_reply',
264
+ message_id: id,
265
+ message: value
266
+ };
267
+ worker.postMessage(payload, transferables.map(t => t.object));
268
+ freeTransferables(transferables);
269
+ if (transferables.length > 0) {
270
+ log('trace', `'${method_name}' transferred ${transferables.length} objects to worker thread`);
271
+ }
272
+
273
+ }, (error) => {
274
+ worker.postMessage({
275
+ type: 'main_reply',
276
+ message_id: id,
277
+ error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
278
+ });
279
+ });
280
+ }
281
+ // Immediate result
282
+ else {
283
+ if (result instanceof WorkerBroker.withTransferables) {
284
+ transferables = result.transferables;
285
+ result = result.value[0];
286
+ }
287
+
288
+ payload = {
289
+ type: 'main_reply',
290
+ message_id: id,
291
+ message: result,
292
+ error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
293
+ };
294
+ worker.postMessage(payload, transferables.map(t => t.object));
295
+ freeTransferables(transferables);
296
+ if (transferables.length > 0) {
297
+ log('trace', `'${method_name}' transferred ${transferables.length} objects to worker thread`);
298
+ }
299
+ }
300
+ }
301
+ });
302
+
303
+ };
304
+
305
+ // Expose for debugging
306
+ WorkerBroker.getMessages = function () {
307
+ return messages;
308
+ };
309
+
310
+ WorkerBroker.getMessageId = function () {
311
+ return message_id;
312
+ };
313
+
314
+ }
315
+
316
+ // Worker threads:
317
+ // - Receive messages from main thread, and optionally send an async response back as a promise
318
+ // - Send messages to main thread, and optionally receive an async response as a promise
319
+ function setupWorkerThread (): void {
320
+
321
+ // Send a message to the main thread, and optionally get an async response as a promise
322
+ // Arguments:
323
+ // - method: the method with this name, specified with dot-notation, will be invoked on the main thread
324
+ // - message: array of arguments to call the method with
325
+ // Returns:
326
+ // - a promise that will be fulfilled if the main thread method returns a value (could be immediately, or async)
327
+ //
328
+ WorkerBroker.postMessage = function (method: BrokerMethod, ...message: unknown[]) {
329
+ // Parse options
330
+ let options: {stringify?: boolean} = {};
331
+ if (typeof method === 'object') {
332
+ options = method;
333
+ method = method.method;
334
+ }
335
+
336
+ // Track state of this message
337
+ var promise = new Promise<unknown>((resolve, reject) => {
338
+ messages[message_id] = { method, message, resolve, reject };
339
+ });
340
+
341
+ let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
342
+
343
+ if (message && message.length === 1 && message[0] instanceof WorkerBroker.withTransferables) {
344
+ transferables = message[0].transferables;
345
+ message = message[0].value;
346
+ }
347
+
348
+ payload = {
349
+ type: 'worker_send', // mark message as method invocation from worker
350
+ message_id, // unique id for this message, for life of program
351
+ method, // will dispatch to a method of this name on the main thread
352
+ message // message payload
353
+ };
354
+
355
+ if (options.stringify) {
356
+ payload = JSON.stringify(payload);
357
+ }
358
+
359
+ (self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
360
+ freeTransferables(transferables);
361
+ if (transferables.length > 0) {
362
+ log('trace', `'${method}' transferred ${transferables.length} objects to main thread`);
363
+ }
364
+
365
+ message_id++;
366
+ return promise;
367
+ } as BrokerPostMessage;
368
+
369
+ self.addEventListener('message', function WorkerBrokerWorkerThreadHandler(event: MessageEvent<unknown>) {
370
+ let data = ((typeof event.data === 'string') ? JSON.parse(event.data) : event.data) as BrokerPacket;
371
+ let id = data.message_id;
372
+
373
+ // Listen for messages coming back from the main thread, and fulfill that message's promise
374
+ if (data.type === 'main_reply') {
375
+ // Pass the result to the promise
376
+ if (messages[id]) {
377
+ if (data.error) {
378
+ messages[id].reject(data.error);
379
+ }
380
+ else {
381
+ messages[id].resolve(data.message);
382
+ }
383
+ delete messages[id];
384
+ }
385
+ }
386
+ // Receive messages from main thread, dispatch them, and send back a reply
387
+ // Unique id for this message & return call to main thread
388
+ else if (data.type === 'main_send' && id != null) {
389
+ // Call the requested worker method and save the return value
390
+ let result: unknown, error: unknown, target: Record<string, unknown> | undefined, method_name: string | undefined, method;
391
+ try {
392
+ [method_name, target] = findTarget(data.method);
393
+ if (!target) {
394
+ throw Error(`Worker broker could not dispatch message type ${data.method} on target ${data.target} because no object with that name is registered on main thread`);
395
+ }
396
+
397
+ method = (typeof target[method_name!] === 'function') && target[method_name!] as ((...arguments_: unknown[]) => unknown);
398
+
399
+ if (!method) {
400
+ throw Error(`Worker broker could not dispatch message type ${data.method} because worker has no method with that name`);
401
+ }
402
+
403
+ result = method.apply(target, data.message);
404
+ }
405
+ catch(e) {
406
+ // Thrown errors will be passed back (in string form) to main thread
407
+ error = e;
408
+ }
409
+
410
+ // Send return value to main thread
411
+ let payload: BrokerPacket | string, transferables: BrokerTransferable[] = [];
412
+
413
+ // Async result
414
+ if (result instanceof Promise) {
415
+ result.then((value) => {
416
+ if (value instanceof WorkerBroker.withTransferables) {
417
+ transferables = value.transferables;
418
+ value = value.value[0];
419
+ }
420
+
421
+ payload = {
422
+ type: 'worker_reply',
423
+ message_id: id,
424
+ message: value
425
+ };
426
+ (self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
427
+ freeTransferables(transferables);
428
+ if (transferables.length > 0) {
429
+ log('trace', `'${method_name}' transferred ${transferables.length} objects to main thread`);
430
+ }
431
+ }, (error) => {
432
+ (self as DedicatedWorkerGlobalScope).postMessage({
433
+ type: 'worker_reply',
434
+ message_id: id,
435
+ error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
436
+ });
437
+ });
438
+ }
439
+ // Immediate result
440
+ else {
441
+ if (result instanceof WorkerBroker.withTransferables) {
442
+ transferables = result.transferables;
443
+ result = result.value[0];
444
+ }
445
+
446
+ payload = {
447
+ type: 'worker_reply',
448
+ message_id: id,
449
+ message: result,
450
+ error: (error instanceof Error ? `${error.message}: ${error.stack}` : error)
451
+ };
452
+ (self as DedicatedWorkerGlobalScope).postMessage(payload, transferables.map(t => t.object));
453
+ freeTransferables(transferables);
454
+ if (transferables.length > 0) {
455
+ log('trace', `'${method_name}' transferred ${transferables.length} objects to main thread`);
456
+ }
457
+ }
458
+ }
459
+ });
460
+
461
+ }
462
+
463
+ // Special value wrapper, to indicate that we want to find and include transferable objects in the message
464
+ WorkerBroker.withTransferables = function (this: TransferEnvelope | undefined, ...value: unknown[]) {
465
+ if (!(this instanceof WorkerBroker.withTransferables)) {
466
+ return new WorkerBroker.withTransferables(...value);
467
+ }
468
+
469
+ this.value = value;
470
+ this.transferables = findTransferables(this.value);
471
+ } as TransferEnvelopeFactory;
472
+
473
+ // Build a list of transferable objects from a source object
474
+ // Returns a list of info about each transferable:
475
+ // - object: the actual transferable object
476
+ // - parent: the parent object that the transferable is a property of (if any)
477
+ // - property: the property name of the transferable on the parent object (if any)
478
+ // TODO: add option in case you DON'T want to transfer objects
479
+ function findTransferables(source: unknown, parent: object | null = null, property: string | number | null = null,
480
+ list: BrokerTransferable[] = []): BrokerTransferable[] {
481
+ if (!source) {
482
+ return list;
483
+ }
484
+
485
+ if (Array.isArray(source)) {
486
+ // Check each array element
487
+ source.forEach((x, i) => findTransferables(x, source, i, list));
488
+ }
489
+ else if (typeof source === 'object') {
490
+ // Is the object a transferable array buffer?
491
+ if (source instanceof ArrayBuffer) {
492
+ list.push({ object: source, parent, property });
493
+ }
494
+ // Or looks like a typed array (has an array buffer property)?
495
+ else if ((source as {buffer?: unknown}).buffer instanceof ArrayBuffer) {
496
+ list.push({ object: (source as {buffer: ArrayBuffer}).buffer, parent, property });
497
+ }
498
+ // Otherwise check each property
499
+ else {
500
+ for (let prop in source) {
501
+ findTransferables((source as Record<string, unknown>)[prop], source, prop, list);
502
+ }
503
+ }
504
+ }
505
+ return list;
506
+ }
507
+
508
+ // Remove neutered transferables from parent objects, as they should no longer be accessed after transfer
509
+ function freeTransferables(transferables: BrokerTransferable[]): void {
510
+ if (!Array.isArray(transferables)) {
511
+ return;
512
+ }
513
+ transferables.filter(t => t.parent && t.property).forEach(t => delete (t.parent as Record<string | number, unknown>)[t.property!]);
514
+ }
515
+
516
+ // Setup this thread as appropriate
517
+ if (Thread.is_main) {
518
+ setupMainThread();
519
+ }
520
+
521
+ if (Thread.is_worker) {
522
+ setupWorkerThread();
523
+ }