@woosh/meep-engine 2.42.8 → 2.43.1

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 (137) hide show
  1. package/core/binary/BitSet.js +4 -4
  2. package/core/binary/ctz32.js +40 -0
  3. package/core/collection/ObservedMap.js +61 -57
  4. package/core/collection/heap/FastBinaryHeap.js +7 -1
  5. package/core/collection/heap/Uint32Heap.js +19 -0
  6. package/core/collection/map/AsyncLoadingCache.js +3 -1
  7. package/core/geom/2d/compute_polygon_area_2d.js +32 -0
  8. package/core/geom/2d/compute_polygon_area_2d.spec.js +10 -0
  9. package/core/geom/2d/compute_triangle_area_2d.js +15 -0
  10. package/core/geom/2d/compute_triangle_area_2d.spec.js +9 -0
  11. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.js +64 -0
  12. package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.spec.js +33 -0
  13. package/core/geom/2d/convex-hull/convex_hull_monotone_2d.js +82 -0
  14. package/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +135 -0
  15. package/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +282 -0
  16. package/core/geom/2d/convex-hull/orientation3.js +444 -0
  17. package/core/geom/2d/convex-hull/orientation3_array.js +22 -0
  18. package/core/geom/2d/convex-hull/orientation3_v2.js +12 -0
  19. package/core/geom/2d/intersect_ray_2d.js +56 -0
  20. package/core/geom/2d/quad-tree/QuadTreeNode.js +0 -81
  21. package/core/geom/2d/quad-tree/qt_match_data_by_circle.js +70 -0
  22. package/core/geom/3d/matrix/m4_multiply_alphatensor.js +131 -0
  23. package/core/geom/3d/plane/orient3d_fast.js +2 -6
  24. package/core/geom/3d/tetrahedra/README.md +7 -0
  25. package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +3 -1
  26. package/core/geom/3d/tetrahedra/delaunay/Cavity.js +48 -0
  27. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.js → delaunay/compute_delaunay_tetrahedral_mesh.js} +15 -7
  28. package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.spec.js → delaunay/compute_delaunay_tetrahedral_mesh.spec.js} +0 -0
  29. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +73 -0
  30. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_walk_toward_cavity.js +48 -0
  31. package/core/geom/3d/tetrahedra/hxt/a.js +524 -0
  32. package/core/geom/3d/tetrahedra/hxt/hxt.js +140 -0
  33. package/core/geom/3d/tetrahedra/hxt/hxt.wasm +0 -0
  34. package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +35 -20
  35. package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +98 -0
  36. package/core/geom/3d/tetrahedra/tetrahedra_collection.js +60 -131
  37. package/core/geom/packing/{MaxRectangles.js → max-rect/MaxRectangles.js} +28 -124
  38. package/core/geom/packing/max-rect/removeRedundantBoxes.js +69 -0
  39. package/core/geom/packing/max-rect/removeRedundantBoxesArray.js +40 -0
  40. package/core/geom/v3_distance_above_plane.js +1 -1
  41. package/core/graph/layout/BoxLayouter.js +2 -88
  42. package/core/graph/layout/CircleLayout.js +2 -1
  43. package/core/graph/layout/box/forceIntoBox.js +45 -0
  44. package/core/graph/layout/box/pullBoxTowardsPoint.js +20 -0
  45. package/core/graph/layout/box/resolveAABB2Overlap.js +22 -0
  46. package/core/math/bessel_3.js +11 -0
  47. package/core/math/bessel_i0.js +26 -0
  48. package/core/process/executor/ConcurrentExecutor.spec.js +2 -1
  49. package/core/process/task/util/actionTask.js +19 -0
  50. package/core/process/task/util/countTask.js +62 -0
  51. package/core/process/task/util/delayTask.js +45 -0
  52. package/core/process/task/util/emptyTask.js +19 -0
  53. package/core/process/task/util/failingTask.js +17 -0
  54. package/core/process/task/util/futureTask.js +48 -0
  55. package/core/process/task/util/promiseTask.js +42 -0
  56. package/core/process/task/util/randomCountTask.js +64 -0
  57. package/core/process/task/util/wrapTaskIgnoreFailure.js +47 -0
  58. package/engine/Engine.js +8 -8
  59. package/engine/EngineBootstrapper.js +1 -1
  60. package/engine/asset/AssetManager.d.ts +2 -0
  61. package/engine/asset/AssetManager.js +197 -53
  62. package/engine/asset/AssetRequest.js +32 -0
  63. package/engine/asset/loaders/ArrayBufferLoader.js +62 -50
  64. package/engine/asset/loaders/image/png/PNG.js +15 -1
  65. package/engine/asset/loaders/image/png/PNGReader.js +3 -2
  66. package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -1
  67. package/engine/ecs/storage/BinaryBufferDeSerializer.js +1 -1
  68. package/engine/ecs/storage/JSONDeSerializer.js +2 -1
  69. package/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +2 -1
  70. package/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
  71. package/engine/graphics/camera/makeScreenScissorFrustum.js +1 -1
  72. package/engine/graphics/camera/testClippingPlaneComputation.js +4 -45
  73. package/engine/graphics/ecs/camera/FrustumProjector.js +6 -0
  74. package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +5 -0
  75. package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +23 -4
  76. package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +1 -1
  77. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -0
  78. package/engine/graphics/geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js +1 -2
  79. package/engine/graphics/impostors/octahedral/ImpostorBaker.js +5 -2
  80. package/engine/graphics/impostors/octahedral/ImpostorDescription.js +18 -0
  81. package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +15 -0
  82. package/engine/graphics/impostors/octahedral/prototypeBaker.js +66 -79
  83. package/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js +134 -0
  84. package/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +128 -0
  85. package/engine/graphics/impostors/octahedral/util/build_geometry_from_cutout_shape.js +32 -0
  86. package/engine/graphics/impostors/octahedral/util/load_mesh_for_bake.js +31 -0
  87. package/engine/graphics/impostors/octahedral/util/makeImpostorAtlasPreview.js +107 -0
  88. package/engine/graphics/material/manager/ManagedMaterial.js +4 -0
  89. package/engine/graphics/material/manager/MaterialManager.js +1 -0
  90. package/engine/graphics/material/optimization/MaterialOptimizationContext.js +7 -3
  91. package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +2 -2
  92. package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
  93. package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +83 -27
  94. package/engine/graphics/shadows/ShadowMapRenderer.js +11 -4
  95. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +2 -1
  96. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +208 -38
  97. package/engine/graphics/texture/atlas/TextureAtlas.js +31 -24
  98. package/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +1 -1
  99. package/engine/graphics/texture/sampler/filter/box.js +16 -0
  100. package/engine/graphics/texture/sampler/filter/cubic2.js +32 -0
  101. package/engine/graphics/texture/sampler/filter/gaussian.js +16 -0
  102. package/engine/graphics/texture/sampler/filter/kaiser_1.js +19 -0
  103. package/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +19 -0
  104. package/engine/graphics/texture/sampler/filter/mitchell.js +55 -0
  105. package/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +109 -0
  106. package/engine/graphics/texture/sampler/filter/triangle.js +19 -0
  107. package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +187 -86
  108. package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +77 -25
  109. package/engine/graphics/texture/sampler/search/make_edge_condition_channel_threshold.js +34 -0
  110. package/engine/graphics/texture/sampler/search/sampler2d_find_pixels.js +24 -0
  111. package/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +212 -0
  112. package/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
  113. package/engine/navigation/grid/AStar.js +1 -1
  114. package/engine/scene/Scene.js +1 -1
  115. package/engine/scene/SerializedScene.js +1 -1
  116. package/engine/scene/transitionToScene.js +3 -1
  117. package/generation/example/main.js +1 -1
  118. package/generation/grid/generation/GridTaskApplyActionToCells.js +1 -1
  119. package/generation/grid/generation/GridTaskDensityMarkerDistribution.js +1 -1
  120. package/generation/grid/generation/GridTaskExecuteRuleTimes.js +1 -1
  121. package/generation/grid/generation/NoopGridTaskGenerator.js +1 -1
  122. package/generation/grid/generation/discrete/GridTaskCellularAutomata.js +2 -1
  123. package/generation/grid/generation/discrete/GridTaskConnectRooms.js +1 -1
  124. package/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +3 -2
  125. package/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +1 -1
  126. package/generation/grid/generation/grid/GridTaskAddNodesFixed.js +1 -1
  127. package/generation/grid/generation/road/GridTaskGenerateRoads.js +3 -2
  128. package/generation/grid/generation/util/buildDistanceMapToObjective.js +1 -1
  129. package/generation/markers/GridActionRuleSet.js +2 -1
  130. package/generation/placement/GridCellActionTransformNearbyMarkers.js +2 -4
  131. package/generation/theme/ThemeEngine.js +4 -1
  132. package/package.json +1 -1
  133. package/view/asset/AssetLoaderStatusView.js +5 -5
  134. package/view/minimap/gl/MinimapTerrainGL.js +1 -2
  135. package/view/renderModel.js +1 -1
  136. package/view/tooltip/TooltipView.js +5 -5
  137. package/core/process/task/TaskUtils.js +0 -352
@@ -16,21 +16,8 @@ import { noop } from "../../core/function/Functions.js";
16
16
  import { Deque } from "../../core/collection/queue/Deque.js";
17
17
  import Task from "../../core/process/task/Task.js";
18
18
  import { TaskSignal } from "../../core/process/task/TaskSignal.js";
19
-
20
- class AssetRequest {
21
- /**
22
- *
23
- * @param {function(asset:Asset)} successCallback
24
- * @param {function(error:*)} failureCallback
25
- * @param {function(loaded:number, total:number):void} progressCallback
26
- * @constructor
27
- */
28
- constructor(successCallback, failureCallback, progressCallback) {
29
- this.successCallback = successCallback;
30
- this.failureCallback = failureCallback;
31
- this.pogressCallback = progressCallback;
32
- }
33
- }
19
+ import { AssetRequest } from "./AssetRequest.js";
20
+ import FastBinaryHeap from "../../core/collection/heap/FastBinaryHeap.js";
34
21
 
35
22
  /**
36
23
  * @enum {number}
@@ -69,6 +56,32 @@ class PendingAsset {
69
56
  */
70
57
  this.state = AssetLoadState.Initial;
71
58
  }
59
+
60
+ /**
61
+ * Returns aggregated priority of the pending asset based on highest priority of associated requests
62
+ * @return {number}
63
+ */
64
+ get priority() {
65
+ let max_priority = 0;
66
+
67
+ const requests = this.requests;
68
+ const n = requests.length;
69
+
70
+ if (n > 0) {
71
+ max_priority = requests[0].priority;
72
+ }
73
+
74
+ for (let i = 1; i < n; i++) {
75
+ const request = requests[i];
76
+ const priority = request.priority;
77
+
78
+ if (priority > max_priority) {
79
+ max_priority = request;
80
+ }
81
+ }
82
+
83
+ return max_priority;
84
+ }
72
85
  }
73
86
 
74
87
  class Response {
@@ -83,8 +96,18 @@ class Response {
83
96
  }
84
97
  }
85
98
 
99
+ /**
100
+ * Used by the priority queue, so the priority is inverted as the BinaryHeap returns elements in ascending score order (from lowest)
101
+ * @param {PendingAsset} pending_asset
102
+ * @returns {number}
103
+ */
104
+ function get_pending_asset_priority_score(pending_asset) {
105
+ return -pending_asset.priority;
106
+ }
107
+
86
108
 
87
109
  /**
110
+ * Handles loading/generating assets
88
111
  * @class
89
112
  */
90
113
  export class AssetManager {
@@ -97,17 +120,44 @@ export class AssetManager {
97
120
  /**
98
121
  *
99
122
  * @type {HashMap<AssetDescription, Asset>}
123
+ * @private
100
124
  */
101
- this.assets = new HashMap();
125
+ this.assets = new HashMap({
126
+ capacity: 1024
127
+ });
102
128
 
103
129
  /**
104
130
  *
105
131
  * @type {ObservedMap<AssetDescription, PendingAsset>}
132
+ * @private
106
133
  */
107
- this.requestMap = new ObservedMap(new HashMap());
134
+ this.request_map = new ObservedMap(new HashMap());
135
+
136
+ /**
137
+ * Waiting queue for assets that haven't yet been scheduled (passed to relevant loader)
138
+ * @type {BinaryHeap<PendingAsset>}
139
+ * @private
140
+ */
141
+ this.__pending_asset_wait_queue = new FastBinaryHeap(get_pending_asset_priority_score);
142
+ /**
143
+ * Assets currently being processed by loaders
144
+ * @type {Set<PendingAsset>}
145
+ * @private
146
+ */
147
+ this.__pending_asset_active_load_set = new Set();
148
+
149
+ /**
150
+ * Maximum number of requests that can be handled at the same time
151
+ * Since most of the requests are handled over the network, this can help you control network concurrency,
152
+ * this can be useful to keep some network slots available for high-priority requests such as UI related ones
153
+ * TODO currently nested asset requests are not recognized, so if nesting level exceeds concurrency - it will lead to a deadlock
154
+ * @type {number}
155
+ */
156
+ this.load_concurrency = Infinity;
108
157
 
109
158
  /**
110
159
  * Registered loaders
160
+ * @private
111
161
  * @type {Object<AssetLoader>}
112
162
  */
113
163
  this.loaders = {};
@@ -115,19 +165,23 @@ export class AssetManager {
115
165
  /**
116
166
  * After asset is loaded, a chain of transforms can be applied to it, these are registered here
117
167
  * Transformers are executed in the order in which they are added
168
+ * Identified by asset "type" string
118
169
  * @type {Object<AssetTransformer[]>}
170
+ * @private
119
171
  */
120
172
  this.transformers = {};
121
173
 
122
174
  /**
123
175
  * Named links to specific assets. Useful to later re-mapping assets and having meaningful names for them
124
176
  * @type {Map<string, AssetDescription>}
177
+ * @private
125
178
  */
126
179
  this.aliases = new Map();
127
180
 
128
181
  /**
129
182
  * This will be added to asset path for actual network resolution
130
183
  * @type {string}
184
+ * @private
131
185
  */
132
186
  this.rootPath = '';
133
187
 
@@ -147,16 +201,12 @@ export class AssetManager {
147
201
  /**
148
202
  *
149
203
  * @type {HashSet<AssetDescription>}
204
+ * @private
150
205
  */
151
206
  this.failures = new HashSet();
152
- /**
153
- * @readonly
154
- * @type {boolean}
155
- */
156
- this.isAssetManager = true;
157
207
 
158
208
  /**
159
- *
209
+ * Queue of responses that are waiting to be dispatched
160
210
  * @type {Deque<Response>}
161
211
  * @private
162
212
  */
@@ -182,6 +232,11 @@ export class AssetManager {
182
232
  }
183
233
  });
184
234
 
235
+ /**
236
+ *
237
+ * @type {boolean}
238
+ * @private
239
+ */
185
240
  this.__is_running = false;
186
241
  }
187
242
 
@@ -195,6 +250,11 @@ export class AssetManager {
195
250
  this.__is_running = true;
196
251
  }
197
252
 
253
+ /**
254
+ *
255
+ * @param {number} [immediate] should be let pending work finish, or abort it and shut down immediately? Defaults to false (wait)
256
+ * @return {Promise<void>}
257
+ */
198
258
  async shutdown(immediate = false) {
199
259
  if (!this.__is_running) {
200
260
  return;
@@ -268,12 +328,12 @@ export class AssetManager {
268
328
  //create request object
269
329
  const assetRequest = new AssetRequest(callback, failure, progress);
270
330
  //submit request
271
- this.submitRequest(path, type, assetRequest);
331
+ this.submitRequest(assetDescription, assetRequest);
272
332
  }
273
333
  }
274
334
 
275
335
  /**
276
- *
336
+ * Manually add a fully resolved resource
277
337
  * @param {string} path
278
338
  * @param {string} type
279
339
  * @param {Asset} asset
@@ -281,6 +341,12 @@ export class AssetManager {
281
341
  insert(path, type, asset) {
282
342
  const assetDescription = new AssetDescription(path, type);
283
343
 
344
+ const existing_resource = this.assets.get(assetDescription);
345
+
346
+ if (existing_resource !== undefined && existing_resource !== asset) {
347
+ console.warn(`Another asset under ${assetDescription} already exists and will be replaced`);
348
+ }
349
+
284
350
  this.assets.set(assetDescription, asset);
285
351
  }
286
352
 
@@ -310,45 +376,84 @@ export class AssetManager {
310
376
 
311
377
  /**
312
378
  *
313
- * @param {string} path
314
- * @param {string} type
315
- * @param {AssetRequest} request
379
+ * @param {PendingAsset} asset
380
+ * @private
381
+ */
382
+ __schedule_load(asset) {
383
+ if (this.__pending_asset_active_load_set.size < this.load_concurrency) {
384
+ this.__dispatch_pending_asset(asset);
385
+ } else {
386
+ this.__pending_asset_wait_queue.push(asset);
387
+ }
388
+ }
389
+
390
+ /**
391
+ * Asset has been loaded successfully, failed, or aborted
392
+ * @param {PendingAsset} pending_asset
316
393
  * @private
317
394
  */
318
- submitRequest(path, type, request) {
319
- const requestMap = this.requestMap;
395
+ __handle_asset_resolved(pending_asset) {
396
+ // console.log(`Asset resolved ${pending_asset.description}`); // DEBUG
320
397
 
321
- const assetDescription = new AssetDescription(path, type);
398
+ const active_set = this.__pending_asset_active_load_set;
322
399
 
323
- let pendingAsset = requestMap.get(assetDescription);
324
- if (pendingAsset !== undefined) {
325
- //already loading
326
- pendingAsset.requests.push(request);
327
- return;
328
- }
400
+ this.request_map.delete(pending_asset.description);
401
+ active_set.delete(pending_asset);
329
402
 
330
- pendingAsset = new PendingAsset(assetDescription);
403
+ const queue = this.__pending_asset_wait_queue;
331
404
 
332
- requestMap.set(assetDescription, pendingAsset);
405
+ // schedule more if possible
406
+ while (!queue.isEmpty() && active_set.size < this.load_concurrency) {
407
+ const load = queue.pop();
408
+
409
+ this.__dispatch_pending_asset(load);
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Dispatch load request to relevant loader
415
+ * @param {PendingAsset} pendingAsset
416
+ * @private
417
+ */
418
+ __dispatch_pending_asset(pendingAsset) {
419
+ // console.log(`Asset load dispatched ${pendingAsset.description}`); // DEBUG
333
420
 
334
421
  const requests = pendingAsset.requests;
335
- requests.push(request);
422
+ const assetDescription = pendingAsset.description;
423
+ const type = assetDescription.type;
424
+ const path = assetDescription.path;
336
425
 
337
426
  const loader = this.loaders[type];
338
427
 
339
- if (loader === void 0) {
340
- if (typeof request.failureCallback === "function") {
341
- request.failureCallback(`no loader exists for asset type '${type}', valid types are: ${Object.keys(this.loaders).join(', ')}`);
342
- } else {
343
- //uncaught
344
- console.error("Uncaught asset load failure: No loader for asset type", type);
428
+ if (loader === undefined) {
429
+ let reported_error = false;
430
+ // no loader
431
+ for (let i = 0; i < requests.length; i++) {
432
+ const assetRequest = requests[i];
433
+
434
+ if (typeof assetRequest.failureCallback === "function") {
435
+ assetRequest.failureCallback(`no loader exists for asset type '${type}', valid types are: ${Object.keys(this.loaders).join(', ')}`);
436
+ } else {
437
+ //uncaught
438
+ if (!reported_error) {
439
+ console.error("Uncaught asset load failure: No loader for asset type", type);
440
+ reported_error = true;
441
+ }
442
+ }
345
443
  }
444
+
445
+ this.__handle_asset_resolved(pendingAsset);
446
+
346
447
  return;
347
448
  }
348
449
 
450
+ // mark as being loaded
451
+ this.__pending_asset_active_load_set.add(pendingAsset);
452
+
349
453
  const assets = this.assets;
350
454
  const failures = this.failures;
351
455
 
456
+
352
457
  /**
353
458
  *
354
459
  * @param {Asset} loaded_asset
@@ -392,8 +497,9 @@ export class AssetManager {
392
497
  //register asset
393
498
  assets.set(assetDescription, asset);
394
499
 
395
- //clear callbacks
396
- requestMap.delete(assetDescription);
500
+ //clear callbacks etc.
501
+ this.__handle_asset_resolved(pendingAsset);
502
+
397
503
 
398
504
  // process callbacks
399
505
  for (let i = 0; i < requests.length; i++) {
@@ -403,7 +509,7 @@ export class AssetManager {
403
509
 
404
510
  }
405
511
 
406
- function failure(error) {
512
+ const failure = (error) => {
407
513
  if (pendingAsset.state === AssetLoadState.Failed) {
408
514
  console.warn(`Asset already failed, this is a redundant invocation. AD: ${assetDescription}`);
409
515
  return;
@@ -424,8 +530,9 @@ export class AssetManager {
424
530
  console.error("Failed to execute asset failure callback", e);
425
531
  }
426
532
  }
427
- //clear callbacks
428
- requestMap.delete(assetDescription);
533
+
534
+ //clear callbacks etc.
535
+ this.__handle_asset_resolved(pendingAsset);
429
536
 
430
537
  // record failure
431
538
  failures.add(assetDescription);
@@ -463,11 +570,42 @@ export class AssetManager {
463
570
  }
464
571
 
465
572
  } catch (e) {
466
- console.error(`Loader failed on invocation. path=${path}, type=${type}`, request, 'Loader exception: ', e);
573
+ console.error(`Loader failed on invocation. path=${path}, type=${type}`, 'Loader exception: ', e);
467
574
  failure(e);
468
575
  }
469
576
  }
470
577
 
578
+ /**
579
+ *
580
+ * @param {AssetDescription} assetDescription
581
+ * @param {AssetRequest} request
582
+ * @private
583
+ */
584
+ submitRequest(assetDescription, request) {
585
+ const requestMap = this.request_map;
586
+
587
+ let pendingAsset = requestMap.get(assetDescription);
588
+ if (pendingAsset !== undefined) {
589
+ //already loading
590
+ pendingAsset.requests.push(request);
591
+
592
+ // update priority queue if necessary
593
+ this.__pending_asset_wait_queue.updateElementScore(pendingAsset);
594
+
595
+ return;
596
+ }
597
+
598
+ // not loading yet, lets create a load container and schedule it
599
+ pendingAsset = new PendingAsset(assetDescription);
600
+
601
+ requestMap.set(assetDescription, pendingAsset);
602
+
603
+ const requests = pendingAsset.requests;
604
+ requests.push(request);
605
+
606
+ this.__schedule_load(pendingAsset);
607
+ }
608
+
471
609
  /**
472
610
  *
473
611
  * @param {string} type
@@ -666,7 +804,7 @@ export class AssetManager {
666
804
  /**
667
805
  *
668
806
  * @param {string} alias
669
- * @return {AssetDescription}
807
+ * @return {AssetDescription|undefined}
670
808
  */
671
809
  resolveAlias(alias) {
672
810
 
@@ -692,3 +830,9 @@ export class AssetManager {
692
830
  this.aliases.set(alias, assetDescription);
693
831
  }
694
832
  }
833
+
834
+ /**
835
+ * @readonly
836
+ * @type {boolean}
837
+ */
838
+ AssetManager.prototype.isAssetManager = true;
@@ -0,0 +1,32 @@
1
+ export class AssetRequest {
2
+ /**
3
+ *
4
+ * @param {function(asset:Asset)} successCallback
5
+ * @param {function(error:*)} failureCallback
6
+ * @param {function(loaded:number, total:number):void} progressCallback
7
+ * @constructor
8
+ */
9
+ constructor(successCallback, failureCallback, progressCallback) {
10
+ /**
11
+ *
12
+ * @type {function(Asset)}
13
+ */
14
+ this.successCallback = successCallback;
15
+ /**
16
+ *
17
+ * @type {function(*)}
18
+ */
19
+ this.failureCallback = failureCallback;
20
+ /**
21
+ *
22
+ * @type {function(number, number): void}
23
+ */
24
+ this.pogressCallback = progressCallback;
25
+
26
+ /**
27
+ * Higher priority requests should be handled first
28
+ * @type {number}
29
+ */
30
+ this.priority = 0;
31
+ }
32
+ }
@@ -14,84 +14,96 @@ export class ArrayBufferLoader extends AssetLoader {
14
14
  });
15
15
 
16
16
  fetch(request)
17
- .then(response => {
18
- if (response.status === 200 || response.status === 0) {
17
+ .then(handle_response)
18
+ .then(response_to_asset)
19
+ .catch(failure);
19
20
 
20
- // Some browsers return HTTP Status 0 when using non-http protocol
21
- // e.g. 'file://' or 'data://'. Handle as success.
21
+ /**
22
+ *
23
+ * @param {Response} response
24
+ * @return {Promise<void>}
25
+ */
26
+ async function response_to_asset(response) {
27
+ const arrayBuffer = await response.arrayBuffer();
22
28
 
23
- if (response.status === 0) {
29
+ const asset = new Asset(
30
+ function () {
31
+ return arrayBuffer;
32
+ },
33
+ arrayBuffer.byteSize
34
+ );
24
35
 
25
- console.warn('HTTP Status 0 received.');
36
+ success(asset);
37
+ }
26
38
 
27
- }
39
+ /**
40
+ *
41
+ * @param {Response} response
42
+ * @return {Response}
43
+ */
44
+ function handle_response(response) {
45
+ if (!(response.status === 200 || response.status === 0)) {
28
46
 
29
- if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) {
47
+ throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`);
30
48
 
31
- return response;
49
+ }
32
50
 
33
- }
51
+ // Some browsers return HTTP Status 0 when using non-http protocol
52
+ // e.g. 'file://' or 'data://'. Handle as success.
34
53
 
35
- const reader = response.body.getReader();
36
- const contentLength = response.headers.get('Content-Length');
37
- const total = contentLength ? parseInt(contentLength) : 0;
38
- const lengthComputable = total !== 0;
39
- let loaded = 0;
54
+ if (response.status === 0) {
40
55
 
41
- // periodically read data into the new stream tracking while download progress
42
- const stream = new ReadableStream({
43
- start(controller) {
56
+ console.warn('HTTP Status 0 received.');
44
57
 
45
- readData();
58
+ }
46
59
 
47
- function readData() {
60
+ if (typeof ReadableStream === 'undefined' || response.body.getReader === undefined) {
48
61
 
49
- reader.read().then(({ done, value }) => {
62
+ return response;
50
63
 
51
- if (done) {
64
+ }
52
65
 
53
- controller.close();
66
+ const reader = response.body.getReader();
67
+ const contentLength = response.headers.get('Content-Length');
68
+ const total = contentLength ? parseInt(contentLength) : 0;
69
+ const lengthComputable = total !== 0;
70
+ let loaded = 0;
54
71
 
55
- } else {
72
+ // periodically read data into the new stream tracking while download progress
73
+ const stream = new ReadableStream({
74
+ start(controller) {
56
75
 
57
- loaded += value.byteLength;
76
+ readData();
58
77
 
59
- progress(loaded, length);
78
+ function readData() {
60
79
 
61
- controller.enqueue(value);
62
- readData();
80
+ reader.read().then(({ done, value }) => {
63
81
 
64
- }
82
+ if (done) {
65
83
 
66
- });
84
+ controller.close();
67
85
 
68
- }
86
+ } else {
87
+
88
+ loaded += value.byteLength;
69
89
 
70
- }
90
+ progress(loaded, length);
71
91
 
72
- });
92
+ controller.enqueue(value);
93
+ readData();
73
94
 
74
- return new Response(stream);
95
+ }
75
96
 
76
- } else {
97
+ });
77
98
 
78
- throw Error(`fetch for "${response.url}" responded with ${response.status}: ${response.statusText}`);
99
+ }
79
100
 
80
101
  }
81
- })
82
- .then(async response => {
83
- const arrayBuffer = await response.arrayBuffer();
84
-
85
- const asset = new Asset(
86
- function () {
87
- return arrayBuffer;
88
- },
89
- arrayBuffer.byteSize
90
- );
91
-
92
- success(asset);
93
- })
94
- .catch(failure);
102
+
103
+ });
104
+
105
+ return new Response(stream);
106
+ }
95
107
 
96
108
 
97
109
  }
@@ -360,8 +360,22 @@ PNG.prototype.getUint8Data_case3 = function () {
360
360
 
361
361
  //transparency
362
362
  if (transparency_lookup !== null) {
363
+ const transparency_lookup_size = transparency_lookup.length;
364
+
363
365
  for (let i = 0; i < pixel_count; i++) {
364
- result_data[i * 4 + 3] = transparency_lookup[pixels[i * d]];
366
+ const pixel_index = pixels[i * d];
367
+
368
+ const result_address = i * 4 + 3;
369
+
370
+ if (pixel_index >= transparency_lookup_size) {
371
+ /*
372
+ when sampling outside of lookup, value defaults to 255
373
+ @see "tRNS" chunk in PNG 1.2 spec
374
+ */
375
+ result_data[result_address] = 255;
376
+ } else {
377
+ result_data[result_address] = transparency_lookup[pixel_index];
378
+ }
365
379
  }
366
380
  }
367
381
 
@@ -267,10 +267,11 @@ PNGReader.prototype.decodePixels = function () {
267
267
 
268
268
  const inflator = new zlib.Inflate();
269
269
 
270
- const chunk_count = this.dataChunks.length;
270
+ const chunks = this.dataChunks;
271
+ const chunk_count = chunks.length;
271
272
 
272
273
  for (let i = 0; i < chunk_count; i++) {
273
- inflator.push(this.dataChunks[i]);
274
+ inflator.push(chunks[i]);
274
275
 
275
276
  if (inflator.err) {
276
277
  throw new Error(inflator.err);
@@ -7,9 +7,10 @@ import { InstancedFoliage } from "../InstancedFoliage.js";
7
7
  import { buildTreeOptimizationTask } from "../../../../core/bvh2/BVHTasks.js";
8
8
  import Task from "../../../../core/process/task/Task.js";
9
9
  import { TaskSignal } from "../../../../core/process/task/TaskSignal.js";
10
- import { countTask, promiseTask } from "../../../../core/process/task/TaskUtils.js";
11
10
  import { assert } from "../../../../core/assert.js";
12
11
  import { InstancedMeshLayer } from "./InstancedMeshLayer.js";
12
+ import { countTask } from "../../../../core/process/task/util/countTask.js";
13
+ import { promiseTask } from "../../../../core/process/task/util/promiseTask.js";
13
14
 
14
15
  /**
15
16
  * Convert all existing instanced mesh components to individual Transform+Mesh pairs
@@ -1,9 +1,9 @@
1
- import { emptyTask } from "../../../core/process/task/TaskUtils.js";
2
1
  import Task from "../../../core/process/task/Task.js";
3
2
  import { TaskSignal } from "../../../core/process/task/TaskSignal.js";
4
3
  import { assert } from "../../../core/assert.js";
5
4
  import { BinaryCollectionDeSerializer } from "./binary/collection/BinaryCollectionDeSerializer.js";
6
5
  import { BinaryObjectSerializationAdapter } from "./binary/object/BinaryObjectSerializationAdapter.js";
6
+ import { emptyTask } from "../../../core/process/task/util/emptyTask.js";
7
7
 
8
8
  class BinaryBufferDeSerializer {
9
9
  constructor() {
@@ -4,8 +4,9 @@
4
4
 
5
5
 
6
6
  import Blueprint from '../Blueprint.js';
7
- import { countTask, emptyTask } from '../../../core/process/task/TaskUtils.js';
8
7
  import { assert } from "../../../core/assert.js";
8
+ import { countTask } from "../../../core/process/task/util/countTask.js";
9
+ import { emptyTask } from "../../../core/process/task/util/emptyTask.js";
9
10
 
10
11
  /**
11
12
  *
@@ -6,8 +6,9 @@ import { colorizeGraphGreedyWeight } from "../../../../../core/graph/coloring/co
6
6
  import { validateGraphColoring } from "../../../../../core/graph/coloring/validateGraphColoring.js";
7
7
  import ConcurrentExecutor from "../../../../../core/process/executor/ConcurrentExecutor.js";
8
8
  import Task from "../../../../../core/process/task/Task.js";
9
- import { actionTask, countTask } from "../../../../../core/process/task/TaskUtils.js";
10
9
  import { TaskSignal } from "../../../../../core/process/task/TaskSignal.js";
10
+ import { actionTask } from "../../../../../core/process/task/util/actionTask.js";
11
+ import { countTask } from "../../../../../core/process/task/util/countTask.js";
11
12
 
12
13
  /**
13
14
  * We convert splat mapping into a graph of connecting material patches and solve the overlaps as a "Graph Coloring" problem