@woosh/meep-engine 2.39.39 → 2.39.42

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 (62) hide show
  1. package/core/binary/operations/ceilPowerOfTwo.spec.js +17 -0
  2. package/core/bvh2/aabb3/AABB3.js +6 -6
  3. package/core/bvh2/binary/2/BinaryUint32BVH.js +7 -1
  4. package/core/bvh2/binary/2/BinaryUint32BVH.spec.js +31 -1
  5. package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.js +5 -5
  6. package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.spec.js +70 -0
  7. package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.spec.js +2 -2
  8. package/core/cache/Cache.js +6 -0
  9. package/core/collection/IteratorUtils.js +1 -0
  10. package/core/collection/queue/Deque.js +5 -2
  11. package/core/color/Color.js +22 -4
  12. package/core/color/hsluv/HSLuv.js +187 -0
  13. package/core/geom/3d/aabb/aabb3_matrix4_project.js +1 -0
  14. package/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +1 -1
  15. package/core/primitives/strings/compareStrings.js +22 -0
  16. package/editor/Editor.js +2 -0
  17. package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +12 -6
  18. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +22 -11
  19. package/engine/EngineHarness.js +7 -0
  20. package/engine/asset/loaders/geometry/geometry/computeBufferAttributeHash.js +5 -6
  21. package/engine/asset/loaders/image/codec/Codec.js +9 -0
  22. package/engine/asset/loaders/image/codec/CodecWithFallback.js +52 -11
  23. package/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +12 -0
  24. package/engine/asset/loaders/image/png/PNGReader.js +2 -1
  25. package/engine/asset/loaders/image/png/PNG_HEADER_BYTES.js +1 -0
  26. package/engine/computeStridedIntegerArrayHash.js +19 -0
  27. package/engine/ecs/EntityBuilder.d.ts +2 -0
  28. package/engine/ecs/gui/GUIElement.d.ts +3 -1
  29. package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +5 -3
  30. package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +11 -2
  31. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -8
  32. package/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.d.ts +7 -0
  33. package/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +17 -1
  34. package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +336 -0
  35. package/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +176 -0
  36. package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +7 -3
  37. package/engine/graphics/micron/build/hierarchy/merge_patches.js +0 -1
  38. package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -3
  39. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +32 -1
  40. package/engine/graphics/render/forward_plus/LightManager.js +58 -13
  41. package/engine/graphics/render/forward_plus/debug/createScreenGrid.js +192 -9
  42. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +42 -1
  43. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +1 -0
  44. package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +5 -0
  45. package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -4
  46. package/engine/graphics/render/forward_plus/model/Decal.js +33 -5
  47. package/engine/graphics/render/forward_plus/model/PointLight.js +1 -1
  48. package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +4 -0
  49. package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +480 -12
  50. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +49 -29
  51. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +11 -0
  52. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +34 -0
  53. package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +9 -1
  54. package/engine/graphics/texture/atlas/TextureAtlas.js +29 -16
  55. package/engine/graphics/texture/atlas/TextureAtlasDebugger.js +75 -19
  56. package/engine/graphics/texture/sampler/Sampler2D.d.ts +2 -0
  57. package/engine/graphics/texture/sampler/Sampler2D.js +51 -10
  58. package/engine/sound/ecs/SoundListenerSystem.js +5 -0
  59. package/engine/sound/ecs/emitter/SoundEmitter.js +12 -1
  60. package/package.json +1 -1
  61. package/samples/terrain/from_image_2.js +8 -2
  62. package/view/tooltip/TooltipManager.js +0 -95
@@ -10,6 +10,48 @@ import { BVH_BINARY_NODE_SIZE, BVH_LEAF_NODE_SIZE } from "../../../../../core/bv
10
10
  */
11
11
  const stack = [];
12
12
 
13
+ /**
14
+ *
15
+ * @param {DataView} data_view
16
+ * @param {number} address
17
+ * @param {ArrayLike<number>|number[]} planes
18
+ * @return {boolean}
19
+ */
20
+ function frustum_check(data_view, address, planes) {
21
+ const n_x0 = data_view.getFloat32(address);
22
+ const n_y0 = data_view.getFloat32(address + 4);
23
+ const n_z0 = data_view.getFloat32(address + 8);
24
+ const n_x1 = data_view.getFloat32(address + 12);
25
+ const n_y1 = data_view.getFloat32(address + 16);
26
+ const n_z1 = data_view.getFloat32(address + 20);
27
+
28
+ for (let plane_address = 0; plane_address < 24; plane_address += 4) {
29
+
30
+ const plane_normal_x = planes[plane_address];
31
+ const plane_normal_y = planes[plane_address + 1];
32
+ const plane_normal_z = planes[plane_address + 2];
33
+ const plane_constant = planes[plane_address + 3];
34
+
35
+ const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
36
+ plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
37
+ n_x0, n_y0, n_z0,
38
+ n_x1, n_y1, n_z1
39
+ );
40
+
41
+ if (distanceAbovePlane <= 0) {
42
+ // node is below the plane
43
+
44
+ // query_bvh_frustum_from_objects.rejection_count++;
45
+
46
+ return false;
47
+ }
48
+
49
+ // TODO under current scheme we can reserve 6 bit in what we push onto the stack for plane mask (allows us to skip some planar tests)
50
+ }
51
+
52
+ return true;
53
+ }
54
+
13
55
  /**
14
56
  * Most of the data is in flat continuous array for cache coherence
15
57
  * @param {number[]} destination
@@ -57,35 +99,8 @@ export function query_bvh_frustum_from_texture(
57
99
  // is intermediate node
58
100
  const node_address = node_index * BVH_BINARY_NODE_SIZE;
59
101
 
60
- const n_x0 = data_view.getFloat32(node_address);
61
- const n_y0 = data_view.getFloat32(node_address + 4);
62
- const n_z0 = data_view.getFloat32(node_address + 8);
63
- const n_x1 = data_view.getFloat32(node_address + 12);
64
- const n_y1 = data_view.getFloat32(node_address + 16);
65
- const n_z1 = data_view.getFloat32(node_address + 20);
66
-
67
- for (plane_address = 0; plane_address < 24; plane_address += 4) {
68
-
69
- const plane_normal_x = planes[plane_address];
70
- const plane_normal_y = planes[plane_address + 1];
71
- const plane_normal_z = planes[plane_address + 2];
72
- const plane_constant = planes[plane_address + 3];
73
-
74
- const distanceAbovePlane = aabb3_computeDistanceAbovePlane_max(
75
- plane_normal_x, plane_normal_y, plane_normal_z, plane_constant,
76
- n_x0, n_y0, n_z0,
77
- n_x1, n_y1, n_z1
78
- );
79
-
80
- if (distanceAbovePlane < 0) {
81
- // node is below the plane
82
-
83
- // query_bvh_frustum_from_objects.rejection_count++;
84
-
85
- continue stack_loop;
86
- }
87
-
88
- // TODO under current scheme we can reserve 6 bit in what we push onto the stack for plane mask (allows us to skip some planar tests)
102
+ if (!frustum_check(data_view, node_address, planes)) {
103
+ continue;
89
104
  }
90
105
 
91
106
  const left_index = (node_index << 1) + 1;
@@ -130,6 +145,11 @@ export function query_bvh_frustum_from_texture(
130
145
 
131
146
  } else if (light_type === 3) {
132
147
  // decal
148
+
149
+ if (!frustum_check(data_view, node_address, planes)) {
150
+ continue;
151
+ }
152
+
133
153
  } else {
134
154
  throw new Error(`Unsupported light type ${light_type}`);
135
155
  }
@@ -16,4 +16,15 @@ export class AbstractTextureAtlas {
16
16
  remove(patch) {
17
17
  throw new Error('Not Implemented')
18
18
  }
19
+
20
+ get sampler() {
21
+ throw new Error('Not Implemented')
22
+ }
23
+
24
+ /**
25
+ * @throws {Error} if update fails
26
+ */
27
+ update() {
28
+ throw new Error('Not Implemented')
29
+ }
19
30
  }
@@ -1,5 +1,6 @@
1
1
  import { Cache } from "../../../../core/cache/Cache.js";
2
2
  import { AbstractTextureAtlas } from "./AbstractTextureAtlas.js";
3
+ import { invokeObjectHash } from "../../../../core/model/object/invokeObjectHash.js";
3
4
 
4
5
  /**
5
6
  * 4Mb
@@ -26,6 +27,7 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
26
27
  */
27
28
  this.__cached_patches = new Cache({
28
29
  maxWeight: cache_size,
30
+ keyHashFunction: invokeObjectHash,
29
31
  keyWeigher(sampler) {
30
32
  return sampler.computeByteSize();
31
33
  }
@@ -41,6 +43,25 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
41
43
  this.__cached_patches.onEvicted.add(this.__handle_cache_eviction, this);
42
44
  }
43
45
 
46
+ update() {
47
+ try {
48
+ this.__atals.update();
49
+ } catch (e) {
50
+ if (this.__cached_patches.size() > 0) {
51
+
52
+ // has some caches patches, lets drop them
53
+ this.__cached_patches.clear();
54
+
55
+ // try to update again
56
+ this.__atals.update();
57
+
58
+ } else {
59
+ // just re-throw
60
+ throw e;
61
+ }
62
+ }
63
+ }
64
+
44
65
  /**
45
66
  *
46
67
  * @returns {AbstractTextureAtlas}
@@ -49,6 +70,14 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
49
70
  return this.__atals;
50
71
  }
51
72
 
73
+ /**
74
+ *
75
+ * @return {Sampler2D}
76
+ */
77
+ get sampler() {
78
+ return this.__atals.sampler;
79
+ }
80
+
52
81
  /**
53
82
  *
54
83
  * @param {Sampler2D} sampler
@@ -74,6 +103,11 @@ export class CachingTextureAtlas extends AbstractTextureAtlas {
74
103
 
75
104
  if (existing_patch !== null) {
76
105
  // cache hit
106
+
107
+ // remove from cache
108
+ this.__cached_patches.remove(sampler);
109
+
110
+ // return patch
77
111
  return existing_patch;
78
112
  }
79
113
 
@@ -26,6 +26,10 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
26
26
 
27
27
  }
28
28
 
29
+ update() {
30
+ this.__atlas.update();
31
+ }
32
+
29
33
  /**
30
34
  *
31
35
  * @param {Reference} ref
@@ -39,8 +43,10 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
39
43
  ref_counts.set(patch, ref_count - 1);
40
44
 
41
45
  if (ref_count === 1) {
42
- // clear patch
46
+ // last reference removed, clear patch
43
47
  this.__atlas.remove(patch);
48
+ ref_counts.delete(patch);
49
+ this.__patches.delete(patch.sampler);
44
50
  }
45
51
  }
46
52
 
@@ -61,6 +67,8 @@ export class ReferencedTextureAtlas extends AbstractTextureAtlas {
61
67
  if (patch === undefined) {
62
68
  patch = atlas.add(sampler);
63
69
  ref_counts.set(patch, 1)
70
+
71
+ this.__patches.set(sampler, patch);
64
72
  } else {
65
73
  ref_counts.set(patch, ref_counts.get(patch) + 1);
66
74
  }
@@ -9,7 +9,9 @@ import { AtlasPatchFlag } from "./AtlasPatchFlag.js";
9
9
  import Signal from "../../../../core/events/signal/Signal.js";
10
10
  import { assert } from "../../../../core/assert.js";
11
11
  import { DataType } from "../../../../core/collection/table/DataType.js";
12
- import { DataType2TypedArrayConstructorMapping } from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
12
+ import {
13
+ DataType2TypedArrayConstructorMapping
14
+ } from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
13
15
  import { AbstractTextureAtlas } from "./AbstractTextureAtlas.js";
14
16
  import { invokeObjectClone } from "../../../../core/model/object/invokeObjectClone.js";
15
17
 
@@ -47,10 +49,11 @@ export class TextureAtlas extends AbstractTextureAtlas {
47
49
  const channel_count = 4;
48
50
 
49
51
  /**
52
+ * @private
50
53
  * @readonly
51
54
  * @type {Sampler2D}
52
55
  */
53
- this.sampler = new Sampler2D(new TypeArrayConstructor(size * size * channel_count), channel_count, size, size);
56
+ this.__sampler = new Sampler2D(new TypeArrayConstructor(size * size * channel_count), channel_count, size, size);
54
57
 
55
58
 
56
59
  /**
@@ -71,6 +74,14 @@ export class TextureAtlas extends AbstractTextureAtlas {
71
74
  this.__needsUpdate = false;
72
75
  }
73
76
 
77
+ /**
78
+ *
79
+ * @return {Sampler2D}
80
+ */
81
+ get sampler() {
82
+ return this.__sampler;
83
+ }
84
+
74
85
  /**
75
86
  *
76
87
  * @param {Sampler2D} sampler
@@ -127,7 +138,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
127
138
 
128
139
 
129
140
  //erase data
130
- this.sampler.data.fill(0);
141
+ this.__sampler.data.fill(0);
131
142
 
132
143
  this.__needsUpdate = true;
133
144
  }
@@ -175,7 +186,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
175
186
 
176
187
  this.size.set(x, y);
177
188
  this.packer.resize(x, y);
178
- this.sampler.resize(x, y);
189
+ this.__sampler.resize(x, y);
179
190
 
180
191
  return true;
181
192
  }
@@ -188,17 +199,17 @@ export class TextureAtlas extends AbstractTextureAtlas {
188
199
  paintPatch(patch) {
189
200
  // console.time('TextureAtlas.paintPatch');
190
201
 
191
- const target = this.sampler;
202
+ const target = this.__sampler;
192
203
 
193
204
  const source = patch.sampler;
194
205
 
195
- const patchPosition = patch.position;
196
- const patchSize = patch.size;
206
+ const patch_position = patch.position;
207
+ const patch_size = patch.size;
197
208
 
198
209
  target.copy_sameItemSize(
199
210
  source,
200
211
  0, 0,
201
- patchPosition.x, patchPosition.y, patchSize.x, patchSize.y
212
+ patch_position.x, patch_position.y, patch_size.x, patch_size.y
202
213
  );
203
214
 
204
215
  patch.setFlag(AtlasPatchFlag.Painted);
@@ -222,7 +233,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
222
233
 
223
234
  this.eraseArea(x0, y0, x1, y1);
224
235
 
225
-
236
+ // mark as non-painted
226
237
  patch.clearFlag(AtlasPatchFlag.Painted);
227
238
  }
228
239
 
@@ -234,9 +245,9 @@ export class TextureAtlas extends AbstractTextureAtlas {
234
245
  * @param {number} y1
235
246
  */
236
247
  eraseArea(x0, y0, x1, y1) {
237
- const sampler = this.sampler;
248
+ const sampler = this.__sampler;
238
249
 
239
- sampler.zeroFill(x0, y0, x1, y1);
250
+ sampler.zeroFill(x0, y0, x1 - x0, y1 - y0);
240
251
  }
241
252
 
242
253
  /**
@@ -246,6 +257,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
246
257
  * @return {AtlasPatch}
247
258
  */
248
259
  add(sampler, padding = 4) {
260
+ // console.log('#add');
249
261
 
250
262
  const patch = new AtlasPatch();
251
263
 
@@ -272,6 +284,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
272
284
  * @return {boolean}
273
285
  */
274
286
  remove(patch) {
287
+ // console.log('#remove');
275
288
  const patchIndex = this.patches.indexOf(patch);
276
289
 
277
290
  if (patchIndex === -1) {
@@ -282,15 +295,15 @@ export class TextureAtlas extends AbstractTextureAtlas {
282
295
  this.patches.splice(patchIndex, 1);
283
296
  this.idPool.release(patch.id);
284
297
 
285
- if (patch.getFlag(AtlasPatchFlag.Packed)) {
286
- this.packer.remove(patch.packing);
287
- }
288
-
289
298
  if (patch.getFlag(AtlasPatchFlag.Painted)) {
290
299
  //erase the patch
291
300
  this.erasePatch(patch);
292
301
  }
293
302
 
303
+ if (patch.getFlag(AtlasPatchFlag.Packed)) {
304
+ this.packer.remove(patch.packing);
305
+ }
306
+
294
307
  return true;
295
308
  }
296
309
 
@@ -513,7 +526,7 @@ export class TextureAtlas extends AbstractTextureAtlas {
513
526
  * Drops all the data
514
527
  */
515
528
  reset() {
516
- this.sampler.data.fill(0);
529
+ this.__sampler.data.fill(0);
517
530
 
518
531
  this.patches = [];
519
532
 
@@ -1,5 +1,6 @@
1
- import EmptyView from "../../../../view/elements/EmptyView.js";
2
1
  import Vector2 from "../../../../core/geom/Vector2.js";
2
+ import { CanvasView } from "../../../../view/elements/CanvasView.js";
3
+ import { FrameRunner } from "../../FrameRunner.js";
3
4
 
4
5
  /**
5
6
  * Visualizer for TextureAtlas, to help understand current state of the atlas
@@ -9,13 +10,19 @@ export class TextureAtlasDebugger {
9
10
  *
10
11
  * @param {TextureAtlas} atlas
11
12
  * @param {Vector2} [scale]
13
+ * @param {boolean} [draw_padding]
14
+ * @param {boolean} [draw_borders]
12
15
  */
13
- constructor(atlas, { scale = new Vector2(1, 1) } = {}) {
16
+ constructor(atlas, {
17
+ scale = new Vector2(1, 1),
18
+ draw_padding = true,
19
+ draw_borders = true
20
+ } = {}) {
14
21
  window.atlas = atlas;
15
22
 
16
- this.vAtlasContent = new EmptyView({ tag: 'canvas' });
23
+ const vCanvas = new CanvasView();
17
24
 
18
- this.vAtlasContent.css({
25
+ vCanvas.css({
19
26
  position: "absolute",
20
27
  top: "0",
21
28
  left: "0",
@@ -25,49 +32,98 @@ export class TextureAtlasDebugger {
25
32
  background: 'rgba(0,0,0,0.8)'
26
33
  });
27
34
 
28
- const ctx = this.vAtlasContent.el.getContext('2d');
35
+ const ctx = vCanvas.context2d;
36
+
37
+ let last_drawn_version = -1;
29
38
 
30
39
  function draw() {
31
40
 
32
41
  const size = atlas.size;
42
+
43
+
33
44
  if (size.x !== 0 && size.y !== 0) {
34
45
  ctx.clearRect(0, 0, size.x, size.y);
35
46
 
36
47
  const imageData = ctx.createImageData(size.x, size.y);
48
+
37
49
  imageData.data.set(atlas.sampler.data);
38
50
 
39
51
  ctx.putImageData(imageData, 0, 0);
40
52
 
41
- ctx.strokeStyle = 'red';
42
53
 
43
54
  //draw patch boundaries
44
- atlas.patches.forEach(patch => {
45
- const aabb2 = patch.packing;
55
+ for (let i = 0; i < atlas.patches.length; i++) {
56
+ const patch = atlas.patches[i];
46
57
 
47
- ctx.strokeRect(aabb2.x0, aabb2.y0, aabb2.getWidth(), aabb2.getHeight());
58
+ if (draw_padding) {
59
+ // draw padding area
60
+ ctx.strokeStyle = 'rgba(0,166,255,0.5)';
61
+ ctx.lineWidth = patch.padding;
48
62
 
49
- });
63
+ ctx.strokeRect(
64
+ patch.position.x - patch.padding * 0.5,
65
+ patch.position.y - patch.padding * 0.5,
66
+ patch.size.x + patch.padding,
67
+ patch.size.y + patch.padding,
68
+ );
69
+ }
70
+
71
+ if (draw_borders) {
72
+ const aabb2 = patch.packing;
73
+
74
+ // draw patch borders
75
+ ctx.strokeStyle = 'red';
76
+ ctx.lineWidth = 1;
77
+
78
+ ctx.strokeRect(aabb2.x0, aabb2.y0, aabb2.getWidth(), aabb2.getHeight());
79
+ }
80
+ }
50
81
 
51
82
  } else {
52
83
  ctx.clearRect(0, 0, 1, 1);
53
84
  }
85
+
86
+ // remember last drawn version
87
+ last_drawn_version = atlas.sampler.version;
88
+ }
89
+
90
+ vCanvas.size.set(0, 0);
91
+
92
+ function try_draw() {
93
+ if (last_drawn_version !== atlas.sampler.version) {
94
+ draw();
95
+ }
54
96
  }
55
97
 
56
- this.vAtlasContent.size.set(0, 0);
98
+ const write_dimensions = () => {
99
+ const x = atlas.size.x;
100
+ const y = atlas.size.y;
57
101
 
58
- atlas.size.onChanged.add((x, y) => {
59
- const v = this.vAtlasContent;
102
+ vCanvas.size.set(x, y);
103
+ vCanvas.scale.copy(scale);
104
+ vCanvas.transformOrigin.set(0, 0);
105
+ };
60
106
 
61
- const w = x * scale.x;
62
- const h = y * scale.y;
107
+ function full_update() {
108
+ write_dimensions();
109
+ draw();
110
+ }
111
+
112
+ const fr = new FrameRunner(try_draw);
63
113
 
64
- v.size.set(w, h);
65
- v.el.setAttribute('width', x);
66
- v.el.setAttribute('height', y);
114
+ atlas.size.onChanged.add(full_update);
67
115
 
116
+ vCanvas.on.linked.add(() => {
117
+ full_update();
118
+ fr.startup();
68
119
  });
69
120
 
70
- this.vAtlasContent.on.linked.add(draw);
121
+ vCanvas.on.unlinked.add(() => {
122
+ fr.shutdown();
123
+ })
124
+
71
125
  atlas.on.painted.add(draw);
126
+
127
+ this.vAtlasContent = vCanvas;
72
128
  }
73
129
  }
@@ -1,4 +1,6 @@
1
1
  export class Sampler2D {
2
+ constructor(data: ArrayLike<number>, itemSize?: number, width?: number, height?: number)
3
+
2
4
  readonly height: number
3
5
  readonly width: number
4
6
 
@@ -15,6 +15,8 @@ import {
15
15
  compute_typed_array_constructor_from_data_type
16
16
  } from "../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
17
17
  import { Base64 } from "../../../../core/binary/Base64.js";
18
+ import { computeStridedIntegerArrayHash } from "../../../computeStridedIntegerArrayHash.js";
19
+ import { is_typed_array_equals } from "../../../../core/collection/array/typed/is_typed_array_equals.js";
18
20
 
19
21
  /**
20
22
  * @class
@@ -23,20 +25,20 @@ export class Sampler2D {
23
25
  /**
24
26
  *
25
27
  * @param {ArrayLike<number>|number[]|Uint8ClampedArray|Uint8Array|Uint16Array|Uint32Array|Int8Array|Int16Array|Int32Array|Float32Array|Float64Array} data
26
- * @param {int} itemSize
27
- * @param {int} width
28
- * @param {int} height
28
+ * @param {number} itemSize
29
+ * @param {number} width
30
+ * @param {number} height
29
31
  * @constructor
30
32
  */
31
33
  constructor(data = [], itemSize = 1, width = 0, height = 0) {
32
- if (!Number.isInteger(itemSize)) {
33
- throw new Error(`itemSize must be integer, instead was ${itemSize}`);
34
+ if (!Number.isInteger(itemSize) || itemSize < 0) {
35
+ throw new Error(`itemSize must be a non-negative integer, instead was ${itemSize}`);
34
36
  }
35
- if (!Number.isInteger(width)) {
36
- throw new Error(`width must be integer, instead was ${width}`);
37
+ if (!Number.isInteger(width) || itemSize < 0) {
38
+ throw new Error(`width must be a non-negative integer, instead was ${width}`);
37
39
  }
38
- if (!Number.isInteger(height)) {
39
- throw new Error(`height must be integer, instead was ${height}`);
40
+ if (!Number.isInteger(height) || itemSize < 0) {
41
+ throw new Error(`height must be a non-negative integer, instead was ${height}`);
40
42
  }
41
43
 
42
44
  if (data === undefined) {
@@ -523,6 +525,7 @@ export class Sampler2D {
523
525
  * @returns {number}
524
526
  */
525
527
  sampleChannelBilinear(x, y, channel) {
528
+ assert.isNonNegativeInteger(channel, 'channel');
526
529
 
527
530
  const itemSize = this.itemSize;
528
531
 
@@ -1099,12 +1102,16 @@ export class Sampler2D {
1099
1102
  * @param {Number} height
1100
1103
  */
1101
1104
  zeroFill(x, y, width, height) {
1105
+ assert.isNonNegativeInteger(width, 'width');
1106
+ assert.isNonNegativeInteger(height, 'height');
1102
1107
 
1103
1108
  const x0 = clamp(x, 0, this.width);
1104
1109
  const y0 = clamp(y, 0, this.height);
1105
1110
  const x1 = clamp(x + width, 0, this.width);
1106
1111
  const y1 = clamp(y + height, 0, this.height);
1107
1112
 
1113
+ // console.log(`#zerofill x:${x}, y:${y}, width:${width}, height:${height} \t -> \t x0:${x0}, y0:${y0}, x1:${x1}, y1:${y1}`); // DEBUG
1114
+
1108
1115
  const data = this.data;
1109
1116
  const itemSize = this.itemSize;
1110
1117
 
@@ -1432,6 +1439,40 @@ export class Sampler2D {
1432
1439
  }
1433
1440
  }
1434
1441
 
1442
+ /**
1443
+ *
1444
+ * @param {Sampler2D} other
1445
+ * @return {boolean}
1446
+ */
1447
+ equals(other) {
1448
+ if (
1449
+ this.width !== other.width
1450
+ || this.height !== other.height
1451
+ || this.itemSize !== other.itemSize
1452
+ ) {
1453
+ return false;
1454
+ }
1455
+
1456
+ return is_typed_array_equals(this.data, other.data);
1457
+ }
1458
+
1459
+ /**
1460
+ *
1461
+ * @return {number}
1462
+ */
1463
+ hash() {
1464
+ let hash = (((this.width & 0xFFFF) << 16) | (this.height & 0xFFFF)) ^ this.itemSize;
1465
+
1466
+ const length = this.data.length;
1467
+
1468
+ const stride = Math.max(1, Math.ceil(length / 509));
1469
+
1470
+ hash ^= computeStridedIntegerArrayHash(this.data, 0, length, stride);
1471
+
1472
+ return hash;
1473
+ }
1474
+
1475
+
1435
1476
  /**
1436
1477
  * @returns {Sampler2D}
1437
1478
  */
@@ -1477,7 +1518,7 @@ export class Sampler2D {
1477
1518
 
1478
1519
  this.data = new CTOR(data);
1479
1520
 
1480
- }else{
1521
+ } else {
1481
1522
 
1482
1523
  throw new Error('Unsupported data format');
1483
1524
 
@@ -9,6 +9,7 @@ import { Transform } from '../../ecs/transform/Transform.js';
9
9
  import { browserInfo } from "../../Platform.js";
10
10
  import Vector3 from "../../../core/geom/Vector3.js";
11
11
  import { noop } from "../../../core/function/Functions.js";
12
+ import { assert } from "../../../core/assert.js";
12
13
 
13
14
  const v3 = new Vector3();
14
15
  const v3_up = new Vector3();
@@ -86,6 +87,10 @@ class SoundListenerSystem extends System {
86
87
  */
87
88
  constructor(context) {
88
89
  super();
90
+
91
+ assert.defined(context, 'context');
92
+ assert.isInstanceOf(context, AudioContext, 'context', 'AudioContext');
93
+
89
94
  this.dependencies = [SoundListener, Transform];
90
95
  //
91
96
  this.webAudioContext = context;
@@ -41,6 +41,11 @@ function volume2dB(volume) {
41
41
  return 20 * Math.log10(volume);
42
42
  }
43
43
 
44
+ const DEFAULT_DISTANCE_MIN = 1;
45
+ const DEFAULT_DISTANCE_MAX = 10000;
46
+
47
+ const DEFAULT_CHANNEL = null;
48
+
44
49
  /**
45
50
  * @class
46
51
  */
@@ -61,7 +66,7 @@ export class SoundEmitter {
61
66
  *
62
67
  * @type {String|SoundEmitterChannels|null}
63
68
  */
64
- this.channel = null;
69
+ this.channel = DEFAULT_CHANNEL;
65
70
 
66
71
  /**
67
72
  *
@@ -483,6 +488,8 @@ export class SoundEmitter {
483
488
 
484
489
  if (json.channel !== undefined) {
485
490
  this.channel = json.channel;
491
+ } else {
492
+ this.channel = DEFAULT_CHANNEL;
486
493
  }
487
494
 
488
495
  if (json.volume !== undefined) {
@@ -491,10 +498,14 @@ export class SoundEmitter {
491
498
 
492
499
  if (typeof json.distanceMin === "number") {
493
500
  this.distanceMin = json.distanceMin;
501
+ } else {
502
+ this.distanceMin = DEFAULT_DISTANCE_MIN;
494
503
  }
495
504
 
496
505
  if (typeof json.distanceMax === "number") {
497
506
  this.distanceMax = json.distanceMax;
507
+ } else {
508
+ this.distanceMax = DEFAULT_DISTANCE_MAX;
498
509
  }
499
510
 
500
511
  if (typeof json.isAttenuated === "boolean") {
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "productName": "Meep",
6
6
  "description": "production-ready JavaScript game engine based on Entity Component System Architecture",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.39.39",
8
+ "version": "2.39.42",
9
9
  "dependencies": {
10
10
  "gl-matrix": "3.4.3",
11
11
  "fast-levenshtein": "2.0.6",