@woosh/meep-engine 2.34.20 → 2.34.25
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.
- package/core/binary/BitSet.js +20 -0
- package/core/bvh2/aabb3/aabb3_nearest_point_on_surface.js +65 -0
- package/core/collection/list/List.js +30 -0
- package/core/geom/3d/shape/UnitCubeShape3D.js +7 -37
- package/core/geom/3d/{sphereIntersectsPoint.js → sphere/sphereIntersectsPoint.js} +0 -0
- package/core/geom/3d/sphere/sphere_array_intersects_ray.js +25 -0
- package/core/geom/3d/sphere/sphere_intersects_ray.js +51 -0
- package/core/model/object/invokeObjectClone.js +2 -0
- package/core/model/object/invokeObjectCompare.js +9 -0
- package/engine/graphics/micron/build/PatchRepresentation.js +1 -5
- package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +7 -1
- package/engine/graphics/micron/build/hierarchy/merge_patches.js +0 -4
- package/engine/graphics/micron/format/MicronGeometry.js +28 -9
- package/engine/graphics/micron/format/serialization/deserialize_patch.js +40 -11
- package/engine/graphics/render/forward_plus/LightManager.js +23 -6
- package/engine/graphics/render/forward_plus/PointLightData.js +9 -0
- package/engine/graphics/render/forward_plus/model/AbstractLight.js +16 -0
- package/engine/graphics/render/layers/RenderLayer.js +3 -2
- package/engine/graphics/render/view/CameraView.js +2 -1
- package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -2
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +95 -20
- package/engine/graphics/render/visibility/IncrementalDeltaSet.spec.js +46 -0
- package/engine/graphics/three/compare_three_objects.js +8 -0
- package/engine/sound/ecs/emitter/SoundEmitter.js +59 -0
- package/engine/sound/ecs/emitter/SoundEmitterComponentContext.js +8 -0
- package/engine/sound/ecs/emitter/SoundEmitterSystem.js +2 -1
- package/engine/sound/ecs/emitter/SoundTrack.js +41 -0
- package/package.json +1 -1
package/core/binary/BitSet.js
CHANGED
|
@@ -509,6 +509,26 @@ BitSet.prototype.getAndClear = function (index) {
|
|
|
509
509
|
return v;
|
|
510
510
|
};
|
|
511
511
|
|
|
512
|
+
/**
|
|
513
|
+
*
|
|
514
|
+
* @param {number} distance
|
|
515
|
+
* @param {number} start_index
|
|
516
|
+
* @param {number} end_index
|
|
517
|
+
*/
|
|
518
|
+
BitSet.prototype.shift = function (distance, start_index, end_index) {
|
|
519
|
+
if (distance > 0) {
|
|
520
|
+
for (let i = end_index; i >= start_index; i--) {
|
|
521
|
+
const v = this.get(i);
|
|
522
|
+
this.set(i + distance, v);
|
|
523
|
+
}
|
|
524
|
+
} else {
|
|
525
|
+
for (let i = start_index; i <= end_index; i++) {
|
|
526
|
+
const v = this.get(i);
|
|
527
|
+
this.set(i + distance, v);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
512
532
|
/**
|
|
513
533
|
* Sets all of the bits in this BitSet to false.
|
|
514
534
|
*/
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { clamp } from "../../math/clamp.js";
|
|
2
|
+
import { min2 } from "../../math/min2.js";
|
|
3
|
+
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {number[]|ArrayLike<number>} result
|
|
9
|
+
* @param {number} x0
|
|
10
|
+
* @param {number} y0
|
|
11
|
+
* @param {number} z0
|
|
12
|
+
* @param {number} x1
|
|
13
|
+
* @param {number} y1
|
|
14
|
+
* @param {number} z1
|
|
15
|
+
* @param {number} r_x
|
|
16
|
+
* @param {number} r_y
|
|
17
|
+
* @param {number} r_z
|
|
18
|
+
*/
|
|
19
|
+
export function aabb3_nearest_point_on_surface(result, x0, y0, z0, x1, y1, z1, r_x, r_y, r_z) {
|
|
20
|
+
const ar_x0 = Math.abs(r_x - x0);
|
|
21
|
+
const ar_x1 = Math.abs(r_x - x1);
|
|
22
|
+
const ar_x_min = min2(ar_x0, ar_x1);
|
|
23
|
+
|
|
24
|
+
const ar_y0 = Math.abs(r_y - y0);
|
|
25
|
+
const ar_y1 = Math.abs(r_y - y1);
|
|
26
|
+
const ar_y_min = min2(ar_y0, ar_y1);
|
|
27
|
+
|
|
28
|
+
const ar_z0 = Math.abs(r_z - z0);
|
|
29
|
+
const ar_z1 = Math.abs(r_z - z1);
|
|
30
|
+
const ar_z_min = min2(ar_z0, ar_z1);
|
|
31
|
+
|
|
32
|
+
// figure out closest face to the reference point
|
|
33
|
+
if (ar_x_min > ar_y_min && ar_x_min > ar_z_min) {
|
|
34
|
+
// X is smallest, project onto X axis
|
|
35
|
+
if (ar_x0 <= ar_x1) {
|
|
36
|
+
result[0] = x0;
|
|
37
|
+
} else {
|
|
38
|
+
result[0] = x1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
result[1] = clamp(r_y, y0, y1);
|
|
42
|
+
result[2] = clamp(r_z, z0, z1);
|
|
43
|
+
} else if (ar_y_min > ar_x_min && ar_y_min > ar_z_min) {
|
|
44
|
+
// Y is smallest, project onto X axis
|
|
45
|
+
if (ar_y0 <= ar_y1) {
|
|
46
|
+
result[1] = y0;
|
|
47
|
+
} else {
|
|
48
|
+
result[1] = y1;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
result[0] = clamp(r_x, x0, x1);
|
|
52
|
+
result[2] = clamp(r_z, z0, z1);
|
|
53
|
+
} else {
|
|
54
|
+
// project onto Z axis
|
|
55
|
+
|
|
56
|
+
if (ar_z0 <= ar_z1) {
|
|
57
|
+
result[2] = z0;
|
|
58
|
+
} else {
|
|
59
|
+
result[2] = z1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
result[0] = clamp(r_x, x0, x1);
|
|
63
|
+
result[1] = clamp(r_y, y0, y1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -919,4 +919,34 @@ List.prototype.equals = function (other) {
|
|
|
919
919
|
return true;
|
|
920
920
|
};
|
|
921
921
|
|
|
922
|
+
/**
|
|
923
|
+
*
|
|
924
|
+
* @param {List<T>} other
|
|
925
|
+
* @returns {number}
|
|
926
|
+
*/
|
|
927
|
+
List.prototype.compare = function (other) {
|
|
928
|
+
const l = this.length;
|
|
929
|
+
|
|
930
|
+
const other_length = other.length;
|
|
931
|
+
if (l !== other_length) {
|
|
932
|
+
return l - other_length;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
for (let i = 0; i < l; i++) {
|
|
936
|
+
const a = this.get(i);
|
|
937
|
+
|
|
938
|
+
const b = other.get(i);
|
|
939
|
+
|
|
940
|
+
const delta = a.compare(b);
|
|
941
|
+
|
|
942
|
+
if (delta !== 0) {
|
|
943
|
+
return delta;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// same
|
|
949
|
+
return 0;
|
|
950
|
+
};
|
|
951
|
+
|
|
922
952
|
export default List;
|
|
@@ -4,8 +4,8 @@ import { v3_length } from "../../v3_length.js";
|
|
|
4
4
|
import { max2 } from "../../../math/max2.js";
|
|
5
5
|
import { max3 } from "../../../math/max3.js";
|
|
6
6
|
import { min2 } from "../../../math/min2.js";
|
|
7
|
-
import { clamp } from "../../../math/clamp.js";
|
|
8
7
|
import { compute_signed_distance_gradient_by_sampling } from "./util/compute_signed_distance_gradient_by_sampling.js";
|
|
8
|
+
import { aabb3_nearest_point_on_surface } from "../../../bvh2/aabb3/aabb3_nearest_point_on_surface.js";
|
|
9
9
|
|
|
10
10
|
export class UnitCubeShape3D extends AbstractShape3D {
|
|
11
11
|
|
|
@@ -18,43 +18,13 @@ export class UnitCubeShape3D extends AbstractShape3D {
|
|
|
18
18
|
const r_y = reference[1];
|
|
19
19
|
const r_z = reference[2];
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
aabb3_nearest_point_on_surface(
|
|
22
|
+
result,
|
|
23
|
+
-0.5, -0.5, -0.5,
|
|
24
|
+
0.5, 0.5, 0.5,
|
|
25
|
+
r_x, r_y, r_z
|
|
26
|
+
);
|
|
25
27
|
|
|
26
|
-
if (ar_x > ar_y && ar_x > ar_z) {
|
|
27
|
-
// X is smallest, project onto X axis
|
|
28
|
-
if (r_x <= 0) {
|
|
29
|
-
result[0] = -0.5;
|
|
30
|
-
} else {
|
|
31
|
-
result[0] = 0.5;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
result[1] = clamp(r_y, -0.5, 0.5);
|
|
35
|
-
result[2] = clamp(r_z, -0.5, 0.5);
|
|
36
|
-
} else if (ar_y > ar_x && ar_y > ar_z) {
|
|
37
|
-
// Y is smallest, project onto X axis
|
|
38
|
-
if (r_y <= 0) {
|
|
39
|
-
result[1] = -0.5;
|
|
40
|
-
} else {
|
|
41
|
-
result[1] = 0.5;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
result[0] = clamp(r_x, -0.5, 0.5);
|
|
45
|
-
result[2] = clamp(r_z, -0.5, 0.5);
|
|
46
|
-
} else {
|
|
47
|
-
// project onto Z axis
|
|
48
|
-
|
|
49
|
-
if (r_z <= 0) {
|
|
50
|
-
result[2] = -0.5;
|
|
51
|
-
} else {
|
|
52
|
-
result[2] = 0.5;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
result[0] = clamp(r_x, -0.5, 0.5);
|
|
56
|
-
result[1] = clamp(r_y, -0.5, 0.5);
|
|
57
|
-
}
|
|
58
28
|
}
|
|
59
29
|
|
|
60
30
|
signed_distance_gradient_at_point(result, point) {
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import { sphere_intersects_ray } from "./sphere_intersects_ray.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {number[]|ArrayLike<number>} sphere
|
|
8
|
+
* @param {number} origin_x
|
|
9
|
+
* @param {number} origin_y
|
|
10
|
+
* @param {number} origin_z
|
|
11
|
+
* @param {number} direction_x
|
|
12
|
+
* @param {number} direction_y
|
|
13
|
+
* @param {number} direction_z
|
|
14
|
+
* @returns {boolean}
|
|
15
|
+
*/
|
|
16
|
+
export function sphere_array_intersects_ray(
|
|
17
|
+
sphere,
|
|
18
|
+
origin_x, origin_y, origin_z,
|
|
19
|
+
direction_x, direction_y, direction_z
|
|
20
|
+
) {
|
|
21
|
+
return sphere_intersects_ray(sphere[0], sphere[1], sphere[2], sphere[3],
|
|
22
|
+
origin_x, origin_y, origin_z,
|
|
23
|
+
direction_x, direction_y, direction_z
|
|
24
|
+
);
|
|
25
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import { v3_dot } from "../../v3_dot.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {number} center_x
|
|
8
|
+
* @param {number} center_y
|
|
9
|
+
* @param {number} center_z
|
|
10
|
+
* @param {number} radius
|
|
11
|
+
* @param {number} origin_x
|
|
12
|
+
* @param {number} origin_y
|
|
13
|
+
* @param {number} origin_z
|
|
14
|
+
* @param {number} direction_x
|
|
15
|
+
* @param {number} direction_y
|
|
16
|
+
* @param {number} direction_z
|
|
17
|
+
* @returns {boolean}
|
|
18
|
+
*/
|
|
19
|
+
export function sphere_intersects_ray(
|
|
20
|
+
center_x, center_y, center_z, radius,
|
|
21
|
+
origin_x, origin_y, origin_z,
|
|
22
|
+
direction_x, direction_y, direction_z
|
|
23
|
+
) {
|
|
24
|
+
const delta_x = center_x - origin_x;
|
|
25
|
+
const delta_y = center_y - origin_y;
|
|
26
|
+
const delta_z = center_z - origin_z;
|
|
27
|
+
|
|
28
|
+
const tca = v3_dot(delta_x, delta_y, delta_z, direction_x, direction_y, direction_z);
|
|
29
|
+
const d2 = v3_dot(delta_x, delta_y, delta_z, delta_x, delta_y, delta_z) - tca * tca;
|
|
30
|
+
|
|
31
|
+
const radius2 = radius * radius;
|
|
32
|
+
|
|
33
|
+
if (d2 > radius2) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const thc = Math.sqrt(radius2 - d2);
|
|
38
|
+
|
|
39
|
+
// t0 = first intersect point - entrance on front of sphere
|
|
40
|
+
const t0 = tca - thc;
|
|
41
|
+
|
|
42
|
+
// t1 = second intersect point - exit point on back of sphere
|
|
43
|
+
const t1 = tca + thc;
|
|
44
|
+
|
|
45
|
+
// test to see if both t0 and t1 are behind the ray - if so, no intersection
|
|
46
|
+
if (t0 < 0 && t1 < 0) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
@@ -190,15 +190,11 @@ export class PatchRepresentation {
|
|
|
190
190
|
return result;
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
|
|
193
|
+
computeBounds() {
|
|
194
194
|
computeTopoMeshBoundiningBox(this.bounding_box, this.topology_snapshot);
|
|
195
195
|
computeTopoMeshBoundingSphere(this.bounding_sphere, this.topology_snapshot);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
computeBounds() {
|
|
199
|
-
this.computeBoundingBox();
|
|
200
|
-
}
|
|
201
|
-
|
|
202
198
|
/**
|
|
203
199
|
* @returns {number}
|
|
204
200
|
*/
|
|
@@ -134,7 +134,13 @@ async function assemble_graph(nodes) {
|
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
// return root
|
|
137
|
-
|
|
137
|
+
const root = __nodes[0];
|
|
138
|
+
|
|
139
|
+
//set group bounds to produce a valid root
|
|
140
|
+
root.group_aabb.copy(root.bounding_box);
|
|
141
|
+
root.group_bounding_sphere.set(root.bounding_sphere);
|
|
142
|
+
|
|
143
|
+
return root;
|
|
138
144
|
}
|
|
139
145
|
|
|
140
146
|
|
|
@@ -515,10 +515,6 @@ export async function merge_patches(
|
|
|
515
515
|
// only 1 patch, no merge opportunity, forward it to output directly
|
|
516
516
|
const node = nodes[0];
|
|
517
517
|
|
|
518
|
-
//set group bounds to produce a valid root
|
|
519
|
-
node.group_aabb.copy(node.bounding_box);
|
|
520
|
-
node.group_bounding_sphere.set(node.bounding_sphere);
|
|
521
|
-
|
|
522
518
|
output[output_offset.value++] = node;
|
|
523
519
|
return 1;
|
|
524
520
|
} else {
|
|
@@ -3,6 +3,7 @@ import { assert } from "../../../../core/assert.js";
|
|
|
3
3
|
import { computeTriangleRayIntersection } from "../../../../core/geom/3d/triangle/computeTriangleRayIntersection.js";
|
|
4
4
|
import { SurfacePoint3 } from "../../../../core/geom/3d/SurfacePoint3.js";
|
|
5
5
|
import { aabb3_array_intersects_ray } from "../../../../core/bvh2/aabb3/aabb3_array_intersects_ray.js";
|
|
6
|
+
import { sphere_array_intersects_ray } from "../../../../core/geom/3d/sphere/sphere_array_intersects_ray.js";
|
|
6
7
|
|
|
7
8
|
let id_counter = 0;
|
|
8
9
|
|
|
@@ -78,6 +79,8 @@ export class MicronGeometry {
|
|
|
78
79
|
origin_x, origin_y, origin_z,
|
|
79
80
|
direction_x, direction_y, direction_z
|
|
80
81
|
) {
|
|
82
|
+
let i;
|
|
83
|
+
let stack_cursor = 1;
|
|
81
84
|
|
|
82
85
|
/**
|
|
83
86
|
*
|
|
@@ -86,7 +89,6 @@ export class MicronGeometry {
|
|
|
86
89
|
const hits = [];
|
|
87
90
|
|
|
88
91
|
// initialize stack
|
|
89
|
-
let stack_cursor = 1;
|
|
90
92
|
const stack = scratch_traversal_stack;
|
|
91
93
|
stack[0] = this.root;
|
|
92
94
|
|
|
@@ -104,16 +106,23 @@ export class MicronGeometry {
|
|
|
104
106
|
|
|
105
107
|
const patch = stack[stack_cursor];
|
|
106
108
|
|
|
107
|
-
// using group
|
|
108
|
-
const bb = patch.group_bounding_box;
|
|
109
|
+
// using group bounds because it's conservative, as we want to be able to hit LOD_0
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
// sphere test
|
|
112
|
+
if (!sphere_array_intersects_ray(patch.group_bounding_sphere,
|
|
112
113
|
origin_x, origin_y, origin_z,
|
|
113
114
|
direction_x, direction_y, direction_z
|
|
114
|
-
)
|
|
115
|
+
)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
115
118
|
|
|
116
|
-
|
|
119
|
+
|
|
120
|
+
// box test (more expensive, different volume)
|
|
121
|
+
if (!aabb3_array_intersects_ray(
|
|
122
|
+
patch.group_bounding_box,
|
|
123
|
+
origin_x, origin_y, origin_z,
|
|
124
|
+
direction_x, direction_y, direction_z
|
|
125
|
+
)) {
|
|
117
126
|
// no intersection
|
|
118
127
|
continue;
|
|
119
128
|
}
|
|
@@ -122,6 +131,16 @@ export class MicronGeometry {
|
|
|
122
131
|
// LOD 0 - source geometry
|
|
123
132
|
|
|
124
133
|
// cast against bounds
|
|
134
|
+
|
|
135
|
+
// sphere test
|
|
136
|
+
if (!sphere_array_intersects_ray(patch.bounding_sphere,
|
|
137
|
+
origin_x, origin_y, origin_z,
|
|
138
|
+
direction_x, direction_y, direction_z
|
|
139
|
+
)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// box test
|
|
125
144
|
if (!aabb3_array_intersects_ray(
|
|
126
145
|
patch.bounding_box,
|
|
127
146
|
origin_x, origin_y, origin_z,
|
|
@@ -136,7 +155,7 @@ export class MicronGeometry {
|
|
|
136
155
|
|
|
137
156
|
const vertices = patch.vertex_attribute_arrays[position_attribute_index];
|
|
138
157
|
|
|
139
|
-
for (
|
|
158
|
+
for ( i = 0; i < index_count;) {
|
|
140
159
|
const a = indices[i++];
|
|
141
160
|
const b = indices[i++];
|
|
142
161
|
const c = indices[i++];
|
|
@@ -183,7 +202,7 @@ export class MicronGeometry {
|
|
|
183
202
|
|
|
184
203
|
const child_count = children.length;
|
|
185
204
|
|
|
186
|
-
for (
|
|
205
|
+
for ( i = 0; i < child_count; i++) {
|
|
187
206
|
const child = children[i];
|
|
188
207
|
|
|
189
208
|
// push to stack
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { aabb3_build_corners } from "../../../../../core/geom/3d/aabb/aabb3_build_corners.js";
|
|
2
2
|
import { DataTypeByteSizes } from "../../../../../core/collection/table/DataTypeByteSizes.js";
|
|
3
3
|
import { DataType2TypedArrayConstructorMapping } from "../../../../../core/collection/table/DataType2TypedArrayConstructorMapping.js";
|
|
4
|
+
import { v3_distance } from "../../../../../core/geom/v3_distance.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
*
|
|
@@ -18,17 +19,6 @@ export function deserialize_patch(buffer, patch, vertex_spec, patch_array) {
|
|
|
18
19
|
buffer.readFloat32Array(gbb, 0, 6);
|
|
19
20
|
buffer.readFloat32Array(patch.group_bounding_sphere, 0, 4);
|
|
20
21
|
|
|
21
|
-
// reconstruct corners
|
|
22
|
-
aabb3_build_corners(
|
|
23
|
-
patch.group_bounding_box_corners,
|
|
24
|
-
0,
|
|
25
|
-
gbb[0],
|
|
26
|
-
gbb[1],
|
|
27
|
-
gbb[2],
|
|
28
|
-
gbb[3],
|
|
29
|
-
gbb[4],
|
|
30
|
-
gbb[5]
|
|
31
|
-
);
|
|
32
22
|
|
|
33
23
|
patch.group_error = buffer.readFloat32();
|
|
34
24
|
patch.lod = buffer.readUintVar();
|
|
@@ -101,4 +91,43 @@ export function deserialize_patch(buffer, patch, vertex_spec, patch_array) {
|
|
|
101
91
|
|
|
102
92
|
patch.vertex_attribute_arrays[i] = array;
|
|
103
93
|
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
// validate and fix group bounds as necessary
|
|
97
|
+
if (
|
|
98
|
+
patch.group_bounding_box[0] > patch.bounding_box[0] // x0
|
|
99
|
+
|| patch.group_bounding_box[1] > patch.bounding_box[1] // y0
|
|
100
|
+
|| patch.group_bounding_box[2] > patch.bounding_box[2] // x0
|
|
101
|
+
|| patch.group_bounding_box[3] < patch.bounding_box[3] // x1
|
|
102
|
+
|| patch.group_bounding_box[4] < patch.bounding_box[4] // y1
|
|
103
|
+
|| patch.group_bounding_box[5] < patch.bounding_box[5] // z1
|
|
104
|
+
) {
|
|
105
|
+
// bounds are violated, fix
|
|
106
|
+
patch.group_bounding_box.set(patch.bounding_box);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (v3_distance(
|
|
110
|
+
patch.group_bounding_sphere[0],
|
|
111
|
+
patch.group_bounding_sphere[1],
|
|
112
|
+
patch.group_bounding_sphere[2],
|
|
113
|
+
patch.bounding_sphere[0],
|
|
114
|
+
patch.bounding_sphere[1],
|
|
115
|
+
patch.bounding_sphere[2]
|
|
116
|
+
) + patch.bounding_sphere[3] > patch.group_bounding_sphere[3]) {
|
|
117
|
+
// group's sphere bounds are violated, fix
|
|
118
|
+
patch.group_bounding_sphere.set(patch.bounding_sphere);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
// reconstruct corners
|
|
123
|
+
aabb3_build_corners(
|
|
124
|
+
patch.group_bounding_box_corners,
|
|
125
|
+
0,
|
|
126
|
+
gbb[0],
|
|
127
|
+
gbb[1],
|
|
128
|
+
gbb[2],
|
|
129
|
+
gbb[3],
|
|
130
|
+
gbb[4],
|
|
131
|
+
gbb[5]
|
|
132
|
+
);
|
|
104
133
|
}
|
|
@@ -42,6 +42,9 @@ import { Decal } from "./model/Decal.js";
|
|
|
42
42
|
import { ReferencedTextureAtlas } from "../../texture/atlas/ReferencedTextureAtlas.js";
|
|
43
43
|
import { v3_morton_encode_transformed } from "../../../../core/geom/3d/morton/v3_morton_encode_transformed.js";
|
|
44
44
|
import { v3_distance } from "../../../../core/geom/v3_distance.js";
|
|
45
|
+
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
46
|
+
import { arrayQuickSort } from "../../../../core/collection/array/arrayQuickSort.js";
|
|
47
|
+
import { invokeObjectCompare } from "../../../../core/model/object/invokeObjectCompare.js";
|
|
45
48
|
|
|
46
49
|
const LOOKUP_CACHE_SIZE = 1024; // must be power of two
|
|
47
50
|
|
|
@@ -227,7 +230,13 @@ export class LightManager {
|
|
|
227
230
|
* @readonly
|
|
228
231
|
* @private
|
|
229
232
|
*/
|
|
230
|
-
this.__visible_lights = new IncrementalDeltaSet();
|
|
233
|
+
this.__visible_lights = new IncrementalDeltaSet(invokeObjectCompare);
|
|
234
|
+
/**
|
|
235
|
+
*
|
|
236
|
+
* @type {PointLightData[]}
|
|
237
|
+
* @private
|
|
238
|
+
*/
|
|
239
|
+
this.__sorted_visible_lights = [];
|
|
231
240
|
|
|
232
241
|
/**
|
|
233
242
|
*
|
|
@@ -520,10 +529,18 @@ export class LightManager {
|
|
|
520
529
|
* @private
|
|
521
530
|
*/
|
|
522
531
|
__sort_visible_light() {
|
|
523
|
-
this.
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
532
|
+
const sorted_lights = this.__sorted_visible_lights;
|
|
533
|
+
const visible_light_set = this.__visible_lights;
|
|
534
|
+
const visible_light_count = visible_light_set.size;
|
|
535
|
+
|
|
536
|
+
if (sorted_lights.length > visible_light_count) {
|
|
537
|
+
// crop array if it's too big
|
|
538
|
+
sorted_lights.splice(visible_light_count, sorted_lights.length - visible_light_count)
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
array_copy(visible_light_set.elements, 0, sorted_lights, 0, visible_light_count);
|
|
542
|
+
|
|
543
|
+
arrayQuickSort(sorted_lights, this.__sort_visible_light_score, this, 0, visible_light_count - 1);
|
|
527
544
|
}
|
|
528
545
|
|
|
529
546
|
__update_visible_bvh() {
|
|
@@ -615,7 +632,7 @@ export class LightManager {
|
|
|
615
632
|
*
|
|
616
633
|
* @type {PointLightData[]}
|
|
617
634
|
*/
|
|
618
|
-
const visible_lights = this.
|
|
635
|
+
const visible_lights = this.__sorted_visible_lights;
|
|
619
636
|
|
|
620
637
|
// write light data into texture
|
|
621
638
|
const visible_light_count = visible_lights.length;
|
|
@@ -21,6 +21,15 @@ export class PointLightData {
|
|
|
21
21
|
this.bvh_leaf_main = new LeafNode(this, 0, 0, 0, 0, 0, 0);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {PointLightData} other
|
|
27
|
+
* @returns {number}
|
|
28
|
+
*/
|
|
29
|
+
compare(other) {
|
|
30
|
+
return this.light.compare(other.light);
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
update() {
|
|
25
34
|
|
|
26
35
|
const leaf = this.bvh_leaf_main;
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
let id_counter = 0;
|
|
2
|
+
|
|
1
3
|
export class AbstractLight {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.id = id_counter++;
|
|
6
|
+
}
|
|
2
7
|
|
|
3
8
|
/**
|
|
4
9
|
*
|
|
@@ -47,4 +52,15 @@ export class AbstractLight {
|
|
|
47
52
|
toArray(destination, address) {
|
|
48
53
|
throw new Error('Not Implemented');
|
|
49
54
|
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {AbstractLight} other
|
|
59
|
+
* @returns {number}
|
|
60
|
+
*/
|
|
61
|
+
compare(other) {
|
|
62
|
+
return this.id - other.id;
|
|
63
|
+
}
|
|
50
64
|
}
|
|
65
|
+
|
|
66
|
+
AbstractLight.prototype.type = 'Abstract';
|
|
@@ -12,6 +12,7 @@ import { ThreeFrustumsIntersectionBVHVisitor } from "../../../../core/bvh2/trave
|
|
|
12
12
|
import { traverseBinaryNodeUsingVisitor } from "../../../../core/bvh2/traversal/traverseBinaryNodeUsingVisitor.js";
|
|
13
13
|
import { ThreeClippingPlaneComputingBVHVisitor } from "../../../../core/bvh2/traversal/ThreeClippingPlaneComputingBVHVisitor.js";
|
|
14
14
|
import { RenderLayerState } from "./RenderLayerState.js";
|
|
15
|
+
import { compare_three_objects } from "../../three/compare_three_objects.js";
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
class VisibleLeafCollector extends BVHVisitor {
|
|
@@ -109,9 +110,9 @@ export class RenderLayer {
|
|
|
109
110
|
|
|
110
111
|
/**
|
|
111
112
|
* Contains visible elements across all views, if element is in at least one view - it will be here
|
|
112
|
-
* @type {IncrementalDeltaSet<Object3D>}
|
|
113
|
+
* @type {IncrementalDeltaSet<THREE.Object3D>}
|
|
113
114
|
*/
|
|
114
|
-
this.visibleSet = new IncrementalDeltaSet();
|
|
115
|
+
this.visibleSet = new IncrementalDeltaSet(compare_three_objects);
|
|
115
116
|
|
|
116
117
|
/**
|
|
117
118
|
*
|
|
@@ -5,6 +5,7 @@ import { frustumFromCamera } from "../../ecs/camera/CameraSystem.js";
|
|
|
5
5
|
import { Frustum } from "three";
|
|
6
6
|
import { read_frustum_planes_to_array } from "../forward_plus/cluster/read_frustum_planes_to_array.js";
|
|
7
7
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
8
|
+
import { compare_three_objects } from "../../three/compare_three_objects.js";
|
|
8
9
|
|
|
9
10
|
const DEFAULT_FLAGS = CameraViewFlags.Active
|
|
10
11
|
| CameraViewFlags.AdaptivePlaneNear
|
|
@@ -52,7 +53,7 @@ export class CameraView {
|
|
|
52
53
|
*
|
|
53
54
|
* @type {IncrementalDeltaSet<THREE.Object3D>}
|
|
54
55
|
*/
|
|
55
|
-
this.visible_objects = new IncrementalDeltaSet();
|
|
56
|
+
this.visible_objects = new IncrementalDeltaSet(compare_three_objects);
|
|
56
57
|
|
|
57
58
|
/**
|
|
58
59
|
*
|
|
@@ -3,6 +3,8 @@ export class IncrementalDeltaSet<T> {
|
|
|
3
3
|
version: number
|
|
4
4
|
size: number
|
|
5
5
|
|
|
6
|
+
constructor(compare: (a: T, b: T) => number)
|
|
7
|
+
|
|
6
8
|
contains(element: T): boolean
|
|
7
9
|
|
|
8
10
|
push(element: T): void
|
|
@@ -14,6 +16,4 @@ export class IncrementalDeltaSet<T> {
|
|
|
14
16
|
initializeUpdate(): void
|
|
15
17
|
|
|
16
18
|
finalizeUpdate(): void
|
|
17
|
-
|
|
18
|
-
sort(f: (T) => number, ctx?: any): void
|
|
19
19
|
}
|
|
@@ -2,7 +2,7 @@ import { BitSet } from "../../../../core/binary/BitSet.js";
|
|
|
2
2
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
3
3
|
import { assert } from "../../../../core/assert.js";
|
|
4
4
|
import { IllegalStateException } from "../../../../core/fsm/exceptions/IllegalStateException.js";
|
|
5
|
-
import {
|
|
5
|
+
import { binarySearchHighIndex } from "../../../../core/collection/array/binarySearchHighIndex.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @readonly
|
|
@@ -16,15 +16,30 @@ const IncrementalDeltaSetState = {
|
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* accelerated Set data structure optimized for incremental re-building
|
|
19
|
+
* Always sorted
|
|
19
20
|
* @template V
|
|
20
21
|
*/
|
|
21
22
|
export class IncrementalDeltaSet {
|
|
22
|
-
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param {function(V,V):number} compare stable comparator
|
|
26
|
+
*/
|
|
27
|
+
constructor(compare) {
|
|
28
|
+
assert.isFunction(compare, 'compare');
|
|
29
|
+
|
|
23
30
|
/**
|
|
24
31
|
*
|
|
25
32
|
* @type {V[]}
|
|
33
|
+
* @private
|
|
26
34
|
*/
|
|
27
|
-
this.
|
|
35
|
+
this.__elements = [];
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
* @type {function(V, V): number}
|
|
40
|
+
* @private
|
|
41
|
+
*/
|
|
42
|
+
this.__compare = compare;
|
|
28
43
|
|
|
29
44
|
/**
|
|
30
45
|
* Current version of the state, each time the set is updated - version changes
|
|
@@ -69,15 +84,39 @@ export class IncrementalDeltaSet {
|
|
|
69
84
|
this.state = IncrementalDeltaSetState.Clear;
|
|
70
85
|
}
|
|
71
86
|
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
* @return {V[]}
|
|
90
|
+
*/
|
|
91
|
+
get elements() {
|
|
92
|
+
return this.__elements;
|
|
93
|
+
}
|
|
72
94
|
|
|
73
95
|
/**
|
|
74
96
|
*
|
|
97
|
+
* @param {(V)=>any} visitor
|
|
98
|
+
* @param {*} [visitorContext]
|
|
99
|
+
*/
|
|
100
|
+
forEach(visitor, visitorContext) {
|
|
101
|
+
const n = this.size;
|
|
102
|
+
const elements = this.__elements;
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < n; i++) {
|
|
105
|
+
const el = elements[i];
|
|
106
|
+
|
|
107
|
+
visitor.call(visitorContext, el);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* @deprecated
|
|
75
114
|
* @param {function(T):number} score_function
|
|
76
115
|
* @param {*} [score_context]
|
|
77
116
|
* @returns {void}
|
|
78
117
|
*/
|
|
79
118
|
sort(score_function, score_context) {
|
|
80
|
-
|
|
119
|
+
throw new Error('Deprecated, the set is always sorted');
|
|
81
120
|
}
|
|
82
121
|
|
|
83
122
|
/**
|
|
@@ -86,7 +125,33 @@ export class IncrementalDeltaSet {
|
|
|
86
125
|
* @returns {boolean}
|
|
87
126
|
*/
|
|
88
127
|
contains(element) {
|
|
89
|
-
return this.
|
|
128
|
+
return this.__indexOf(element) !== -1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
*
|
|
133
|
+
* @param {V} element
|
|
134
|
+
* @return {number}
|
|
135
|
+
* @private
|
|
136
|
+
*/
|
|
137
|
+
__indexOf(element) {
|
|
138
|
+
const i = this.__indexExpected(element);
|
|
139
|
+
|
|
140
|
+
if (this.__elements[i] === element) {
|
|
141
|
+
return i;
|
|
142
|
+
} else {
|
|
143
|
+
return -1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* @param {V} element
|
|
150
|
+
* @return {number}
|
|
151
|
+
* @private
|
|
152
|
+
*/
|
|
153
|
+
__indexExpected(element) {
|
|
154
|
+
return binarySearchHighIndex(this.__elements, element, this.__compare, 0, this.size - 1);
|
|
90
155
|
}
|
|
91
156
|
|
|
92
157
|
/**
|
|
@@ -99,10 +164,10 @@ export class IncrementalDeltaSet {
|
|
|
99
164
|
throw new IllegalStateException("Cannot remove during build");
|
|
100
165
|
}
|
|
101
166
|
|
|
102
|
-
const i = this.
|
|
167
|
+
const i = this.__indexOf(element);
|
|
103
168
|
|
|
104
169
|
if (i !== -1) {
|
|
105
|
-
this.
|
|
170
|
+
this.__elements.splice(i, 1);
|
|
106
171
|
this.size--;
|
|
107
172
|
|
|
108
173
|
this.version++;
|
|
@@ -119,7 +184,7 @@ export class IncrementalDeltaSet {
|
|
|
119
184
|
return;
|
|
120
185
|
}
|
|
121
186
|
|
|
122
|
-
this.
|
|
187
|
+
this.__elements.splice(0, this.size);
|
|
123
188
|
this.size = 0;
|
|
124
189
|
this.flags.reset();
|
|
125
190
|
|
|
@@ -153,14 +218,17 @@ export class IncrementalDeltaSet {
|
|
|
153
218
|
let deletions = 0;
|
|
154
219
|
|
|
155
220
|
//go through all dirty flags and remove corresponding elements
|
|
221
|
+
const flags = this.flags;
|
|
222
|
+
const elements = this.__elements;
|
|
223
|
+
|
|
156
224
|
for (
|
|
157
|
-
let i =
|
|
225
|
+
let i = flags.nextSetBit(0);
|
|
158
226
|
i !== -1;
|
|
159
|
-
i =
|
|
227
|
+
i = flags.nextSetBit(i + 1)
|
|
160
228
|
) {
|
|
161
229
|
const index = i - deletions;
|
|
162
230
|
|
|
163
|
-
const removed =
|
|
231
|
+
const removed = elements.splice(index, 1);
|
|
164
232
|
|
|
165
233
|
this.onRemoved.send1(removed[0]);
|
|
166
234
|
|
|
@@ -170,7 +238,7 @@ export class IncrementalDeltaSet {
|
|
|
170
238
|
//update size
|
|
171
239
|
this.size -= deletions;
|
|
172
240
|
|
|
173
|
-
|
|
241
|
+
flags.reset();
|
|
174
242
|
|
|
175
243
|
this.state = IncrementalDeltaSetState.Ready;
|
|
176
244
|
|
|
@@ -184,19 +252,26 @@ export class IncrementalDeltaSet {
|
|
|
184
252
|
*/
|
|
185
253
|
push(element) {
|
|
186
254
|
//check if element is already in the set
|
|
187
|
-
const
|
|
188
|
-
const i = elements.indexOf(element); //TODO this can probably be done faster. Maybe use a bloom filter? or some kind of a hash
|
|
255
|
+
const index = this.__indexExpected(element);
|
|
189
256
|
|
|
190
|
-
|
|
191
|
-
|
|
257
|
+
const elements = this.__elements;
|
|
258
|
+
|
|
259
|
+
if (elements[index] !== element) {
|
|
260
|
+
// element is not in the set
|
|
261
|
+
|
|
262
|
+
// shift flags to make space for it
|
|
263
|
+
this.flags.shift(1, index, this.size);
|
|
264
|
+
|
|
265
|
+
// insert
|
|
266
|
+
elements.splice(index, 0, element);
|
|
192
267
|
this.size++;
|
|
193
268
|
|
|
194
269
|
this.onAdded.send1(element);
|
|
195
|
-
} else {
|
|
196
|
-
//Existing element. We're keeping it. clear dirty flag
|
|
197
|
-
this.flags.clear(i);
|
|
198
270
|
}
|
|
199
271
|
|
|
272
|
+
// clear flag for inserted element
|
|
273
|
+
this.flags.clear(index);
|
|
274
|
+
|
|
200
275
|
}
|
|
201
276
|
|
|
202
277
|
/**
|
|
@@ -204,7 +279,7 @@ export class IncrementalDeltaSet {
|
|
|
204
279
|
* @param {IncrementalDeltaSet<V>} other
|
|
205
280
|
*/
|
|
206
281
|
pushOther(other) {
|
|
207
|
-
const elements = other.
|
|
282
|
+
const elements = other.__elements;
|
|
208
283
|
const n = other.size;
|
|
209
284
|
for (let i = 0; i < n; i++) {
|
|
210
285
|
const el = elements[i];
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { IncrementalDeltaSet } from "./IncrementalDeltaSet.js";
|
|
2
|
+
import { compareNumbersAscending } from "../../../../core/function/Functions.js";
|
|
3
|
+
|
|
4
|
+
test('set is sorted after insert, push 1,2', () => {
|
|
5
|
+
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
6
|
+
|
|
7
|
+
set.push(1);
|
|
8
|
+
set.push(2);
|
|
9
|
+
|
|
10
|
+
expect(set.elements[0]).toBe(1);
|
|
11
|
+
expect(set.elements[1]).toBe(2);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('set is sorted after insert, push 2,1', () => {
|
|
15
|
+
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
16
|
+
|
|
17
|
+
set.push(2);
|
|
18
|
+
set.push(1);
|
|
19
|
+
|
|
20
|
+
expect(set.elements[0]).toBe(1);
|
|
21
|
+
expect(set.elements[1]).toBe(2);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('set is sorted after insert, push 1,2,3', () => {
|
|
25
|
+
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
26
|
+
|
|
27
|
+
set.push(1);
|
|
28
|
+
set.push(2);
|
|
29
|
+
set.push(3);
|
|
30
|
+
|
|
31
|
+
expect(set.elements[0]).toBe(1);
|
|
32
|
+
expect(set.elements[1]).toBe(2);
|
|
33
|
+
expect(set.elements[2]).toBe(3);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('set is sorted after insert, push 3,2,1', () => {
|
|
37
|
+
const set = new IncrementalDeltaSet(compareNumbersAscending);
|
|
38
|
+
|
|
39
|
+
set.push(3);
|
|
40
|
+
set.push(2);
|
|
41
|
+
set.push(1);
|
|
42
|
+
|
|
43
|
+
expect(set.elements[0]).toBe(1);
|
|
44
|
+
expect(set.elements[1]).toBe(2);
|
|
45
|
+
expect(set.elements[2]).toBe(3);
|
|
46
|
+
});
|
|
@@ -16,6 +16,8 @@ import { objectKeyByValue } from "../../../../core/model/object/objectKeyByValue
|
|
|
16
16
|
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
|
|
17
17
|
import { computeHashIntegerArray } from "../../../../core/collection/array/computeHashIntegerArray.js";
|
|
18
18
|
import { computeHashFloat } from "../../../../core/math/hash/computeHashFloat.js";
|
|
19
|
+
import { compareStrings } from "../../../../core/primitives/strings/compareStrings.js";
|
|
20
|
+
import { compareNumbers } from "../../../../core/primitives/numbers/compareNumbers.js";
|
|
19
21
|
|
|
20
22
|
/**
|
|
21
23
|
* Convert decibel to percentage volume
|
|
@@ -127,6 +129,63 @@ export class SoundEmitter {
|
|
|
127
129
|
|
|
128
130
|
}
|
|
129
131
|
|
|
132
|
+
/**
|
|
133
|
+
*
|
|
134
|
+
* @param {SoundEmitter} other
|
|
135
|
+
* @returns number
|
|
136
|
+
*/
|
|
137
|
+
compare(other) {
|
|
138
|
+
const tracks = this.tracks.compare(other.tracks);
|
|
139
|
+
|
|
140
|
+
if (tracks !== 0) {
|
|
141
|
+
return tracks;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const channel = compareStrings(this.channel, other.channel);
|
|
145
|
+
|
|
146
|
+
if (channel !== 0) {
|
|
147
|
+
return channel;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const distanceMin = compareNumbers(this.__distanceMin, other.__distanceMin);
|
|
151
|
+
|
|
152
|
+
if (distanceMin !== 0) {
|
|
153
|
+
return distanceMin;
|
|
154
|
+
}
|
|
155
|
+
const distanceMax = compareNumbers(this.__distanceMax, other.__distanceMax);
|
|
156
|
+
|
|
157
|
+
if (distanceMax !== 0) {
|
|
158
|
+
return distanceMax;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const panningModel = compareNumbers(this.panningModel, other.panningModel);
|
|
162
|
+
|
|
163
|
+
if (panningModel !== 0) {
|
|
164
|
+
return panningModel;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const attenuation = compareNumbers(this.attenuation, other.attenuation);
|
|
168
|
+
|
|
169
|
+
if (attenuation !== 0) {
|
|
170
|
+
return attenuation;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
const flags = compareNumbers(this.flags, other.flags);
|
|
174
|
+
|
|
175
|
+
if (flags !== 0) {
|
|
176
|
+
return flags;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const volume = compareNumbers(this.volume.getValue(), other.volume.getValue());
|
|
180
|
+
|
|
181
|
+
if (volume !== 0) {
|
|
182
|
+
return volume;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
130
189
|
|
|
131
190
|
/**
|
|
132
191
|
*
|
|
@@ -45,6 +45,14 @@ export class SoundEmitterComponentContext {
|
|
|
45
45
|
this.__isConnected = false;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
*
|
|
50
|
+
* @param {SoundEmitterComponentContext} other
|
|
51
|
+
*/
|
|
52
|
+
compare(other) {
|
|
53
|
+
return this.emitter.compare(other.emitter);
|
|
54
|
+
}
|
|
55
|
+
|
|
48
56
|
update() {
|
|
49
57
|
|
|
50
58
|
const position = this.transform.position;
|
|
@@ -18,6 +18,7 @@ import { tryRotateSingleNode } from "../../../../core/bvh2/transform/RotationOpt
|
|
|
18
18
|
import { SoundEmitterComponentContext } from "./SoundEmitterComponentContext.js";
|
|
19
19
|
import { SoundEmitterFlags } from "./SoundEmitterFlags.js";
|
|
20
20
|
import { SoundEmitterChannel } from "./SoundEmitterChannel.js";
|
|
21
|
+
import { invokeObjectCompare } from "../../../../core/model/object/invokeObjectCompare.js";
|
|
21
22
|
|
|
22
23
|
/**
|
|
23
24
|
* @readonly
|
|
@@ -96,7 +97,7 @@ export class SoundEmitterSystem extends System {
|
|
|
96
97
|
*
|
|
97
98
|
* @type {IncrementalDeltaSet<SoundEmitterComponentContext>}
|
|
98
99
|
*/
|
|
99
|
-
this.activeSet = new IncrementalDeltaSet();
|
|
100
|
+
this.activeSet = new IncrementalDeltaSet(invokeObjectCompare);
|
|
100
101
|
|
|
101
102
|
/**
|
|
102
103
|
* Spatial index
|
|
@@ -4,6 +4,8 @@ import { assert } from "../../../../core/assert.js";
|
|
|
4
4
|
import { computeStringHash } from "../../../../core/primitives/strings/computeStringHash.js";
|
|
5
5
|
import { computeHashIntegerArray } from "../../../../core/collection/array/computeHashIntegerArray.js";
|
|
6
6
|
import { computeHashFloat } from "../../../../core/math/hash/computeHashFloat.js";
|
|
7
|
+
import { compareStrings } from "../../../../core/primitives/strings/compareStrings.js";
|
|
8
|
+
import { compareNumbers } from "../../../../core/primitives/numbers/compareNumbers.js";
|
|
7
9
|
|
|
8
10
|
const DEFAULT_FLAGS = SoundTrackFlags.StartWhenReady;
|
|
9
11
|
|
|
@@ -55,6 +57,45 @@ export class SoundTrack {
|
|
|
55
57
|
this.nodes = null;
|
|
56
58
|
}
|
|
57
59
|
|
|
60
|
+
/**
|
|
61
|
+
*
|
|
62
|
+
* @param {SoundTrack} other
|
|
63
|
+
* @returns number
|
|
64
|
+
*/
|
|
65
|
+
compare(other) {
|
|
66
|
+
const url = compareStrings(this.url, other.url);
|
|
67
|
+
|
|
68
|
+
if (url !== 0) {
|
|
69
|
+
return url;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const time = compareNumbers(this.time, other.time);
|
|
73
|
+
|
|
74
|
+
if (time !== 0) {
|
|
75
|
+
return time;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const channel = compareStrings(this.channel, other.channel);
|
|
79
|
+
|
|
80
|
+
if (channel !== 0) {
|
|
81
|
+
return channel;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const volume = compareNumbers(this.__volume, other.__volume);
|
|
85
|
+
|
|
86
|
+
if (volume !== 0) {
|
|
87
|
+
return volume;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const flags = compareNumbers(this.flags, other.flags);
|
|
91
|
+
|
|
92
|
+
if (flags !== 0) {
|
|
93
|
+
return flags;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
58
99
|
/**
|
|
59
100
|
*
|
|
60
101
|
* @param {number|SoundEmitterFlags} flag
|
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.34.
|
|
8
|
+
"version": "2.34.25",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|