@woosh/meep-engine 2.49.7 → 2.49.9

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 (108) hide show
  1. package/editor/enableEditor.js +1 -8
  2. package/package.json +1 -1
  3. package/samples/terrain/editor.js +2 -2
  4. package/src/core/cache/Cache.js +1 -1
  5. package/src/core/collection/HashSet.js +1 -1
  6. package/src/core/collection/table/RowFirstTableSpec.js +110 -92
  7. package/src/core/collection/table/RowFirstTableSpec.spec.js +49 -0
  8. package/src/core/color/Color.d.ts +4 -2
  9. package/src/core/color/Color.js +7 -8
  10. package/src/core/color/Color.spec.js +93 -0
  11. package/src/core/color/hex2rgb.spec.js +10 -0
  12. package/src/core/color/rgb2hex.js +1 -1
  13. package/src/core/color/rgb2hex.spec.js +13 -0
  14. package/src/core/fsm/simple/SimpleStateMachine.spec.js +75 -0
  15. package/src/core/fsm/simple/SimpleStateMachineDescription.js +1 -1
  16. package/src/core/fsm/simple/SimpleStateMachineDescription.spec.js +32 -0
  17. package/src/core/geom/2d/Rectangle.spec.js +51 -0
  18. package/src/core/geom/3d/aabb/aabb3_intersects_ray.spec.js +90 -0
  19. package/src/core/geom/3d/line/line3_compute_nearest_point_to_point.spec.js +61 -0
  20. package/src/core/geom/3d/morton/mortonEncode_magicbits.js +1 -34
  21. package/src/core/geom/3d/morton/split_by_2.js +17 -0
  22. package/src/core/geom/3d/morton/split_by_3.js +16 -0
  23. package/src/core/geom/3d/plane/computePlaneLineIntersection.js +6 -1
  24. package/src/core/geom/3d/sphere/sphere_intersects_ray.spec.js +11 -0
  25. package/src/core/geom/3d/sphere/sphere_radius_sqr_from_v3_array_transformed.spec.js +8 -0
  26. package/src/core/geom/3d/topology/samples/sampleFloodFill.js +3 -3
  27. package/src/core/geom/3d/topology/struct/binary/io/OrderedEdge.js +1 -1
  28. package/src/core/geom/random/randomPointOnBox.spec.js +57 -0
  29. package/src/core/math/bessel_i0.spec.js +43 -0
  30. package/src/core/math/bessel_j0.js +30 -0
  31. package/src/core/math/hash/murmur3_32.spec.js +8 -0
  32. package/src/core/math/hash/squirrel3.spec.js +16 -0
  33. package/src/core/math/interval/NumericInterval.js +1 -0
  34. package/src/core/math/{bessel_i0.js → modified_bessel_i0.js} +5 -2
  35. package/src/core/math/noise/{create_noise_2d.js → create_simplex_noise_2d.js} +2 -2
  36. package/src/core/math/noise/create_simplex_noise_2d.spec.js +21 -0
  37. package/src/core/math/normalizeArrayVector.spec.js +15 -0
  38. package/src/core/math/physics/irradiance/interpolate_irradiance_linear.spec.js +20 -0
  39. package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.js +4 -4
  40. package/src/core/math/physics/irradiance/interpolate_irradiance_lograrithmic.spec.js +18 -0
  41. package/src/core/math/physics/irradiance/interpolate_irradiance_smith.js +1 -1
  42. package/src/core/math/physics/irradiance/interpolate_irradiance_smith.spec.js +20 -0
  43. package/src/core/math/random/seededRandomMersenneTwister.spec.js +10 -0
  44. package/src/core/math/spline/spline_bezier3.js +1 -1
  45. package/src/core/math/spline/spline_bezier3_bounds.js +2 -1
  46. package/src/core/math/spline/spline_bezier3_bounds.spec.js +37 -0
  47. package/src/core/math/statistics/computeSampleSize_Cochran.spec.js +12 -0
  48. package/src/core/math/statistics/computeStatisticalPartialMedian.js +4 -0
  49. package/src/core/math/statistics/computeStatisticalPartialMedian.spec.js +13 -0
  50. package/src/engine/Engine.d.ts +4 -2
  51. package/src/engine/Engine.js +62 -41
  52. package/src/engine/Engine.spec.js +11 -0
  53. package/src/engine/InputEngine.js +12 -0
  54. package/src/engine/achievements/Achievement.spec.js +21 -0
  55. package/src/engine/animation/curve/compression/prototypeCurveCompression.js +2 -2
  56. package/src/engine/animation/curve/compression/{animation_curve_to_float_array.js → sample_animation_curve_to_float_array.js} +10 -3
  57. package/src/engine/animation/curve/compression/sample_animation_curve_to_float_array.spec.js +29 -0
  58. package/src/engine/animation/curve/draw/build_curve_editor.js +3 -3
  59. package/src/engine/development/performance/RingBufferMetric.js +1 -1
  60. package/src/engine/ecs/animation/Animation.js +2 -180
  61. package/src/engine/ecs/animation/AnimationClip.js +132 -0
  62. package/src/engine/ecs/animation/AnimationClip.spec.js +5 -0
  63. package/src/engine/ecs/animation/AnimationClipFlag.js +7 -0
  64. package/src/engine/ecs/animation/AnimationFlags.js +8 -0
  65. package/src/engine/ecs/animation/AnimationSerializationAdapter.js +32 -0
  66. package/src/engine/ecs/systems/AnimationSystem.js +3 -1
  67. package/src/engine/graphics/GraphicsEngine.js +2 -13
  68. package/src/engine/graphics/camera/testClippingPlaneComputation.js +1 -1
  69. package/src/engine/graphics/ecs/animation/AnimationControllerSystem.js +2 -1
  70. package/src/engine/graphics/ecs/compileAllMaterials.js +1 -1
  71. package/src/engine/graphics/ecs/mesh/createTaskWaitForMeshesToLoad.js +1 -1
  72. package/src/engine/graphics/ecs/path/testPathDisplaySystem.js +1 -1
  73. package/src/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +1 -1
  74. package/src/engine/graphics/impostors/octahedral/ImpostorBaker.js +1 -1
  75. package/src/engine/graphics/load_and_set_cubemap_v0.js +21 -0
  76. package/src/engine/graphics/material/optimization/MaterialOptimizationContext.js +1 -1
  77. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +3 -5
  78. package/src/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +3 -5
  79. package/src/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +2 -2
  80. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +1 -1
  81. package/src/engine/graphics/render/visibility/hiz/prototypeHiZ.js +3 -5
  82. package/src/engine/graphics/sh3/prototypeSH3Probe.js +4 -4
  83. package/src/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.js +4 -3
  84. package/src/engine/graphics/texture/sampler/filter/kaiser_1.js +8 -4
  85. package/src/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +2 -0
  86. package/src/engine/graphics/texture/virtual/VirtualTexture.js +9 -0
  87. package/src/engine/graphics/texture/virtual/VirtualTexture.spec.js +5 -4
  88. package/src/engine/graphics/texture/virtual/tile/TileLoader.js +5 -0
  89. package/src/engine/input/devices/PointerDevice.spec.js +7 -0
  90. package/src/engine/platform/InMemoryEnginePlatform.js +20 -0
  91. package/src/engine/save/Storage.d.ts +7 -7
  92. package/src/engine/save/storage/InMemoryStorage.js +34 -0
  93. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +11 -4
  94. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.spec.js +30 -0
  95. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +18 -2
  96. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.spec.js +17 -0
  97. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -2
  98. package/src/generation/grid/GridData.js +0 -60
  99. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +2 -2
  100. /package/src/core/collection/{IteratorUtils.js → collectIteratorValueToArray.js} +0 -0
  101. /package/src/core/color/{ColorUtils.js → parseColor.js} +0 -0
  102. /package/src/engine/ecs/{animation → ik}/IKMath.js +0 -0
  103. /package/src/engine/ecs/{animation → ik}/IKProblem.js +0 -0
  104. /package/src/engine/ecs/{animation → ik}/IKSolver.js +0 -0
  105. /package/src/engine/ecs/{animation → ik}/InverseKinematics.js +0 -0
  106. /package/src/engine/ecs/{animation → ik}/InverseKinematicsSystem.js +0 -0
  107. /package/src/engine/ecs/{animation → ik}/OneBoneSurfaceAlignmentSolver.js +0 -0
  108. /package/src/engine/ecs/{animation → ik}/TwoBoneInverseKinematicsSolver.js +0 -0
@@ -1,4 +1,19 @@
1
1
  import Rectangle from "./Rectangle.js";
2
+ import Vector2 from "../Vector2.js";
3
+
4
+ test("constructor", () => {
5
+ expect(() => new Rectangle()).not.toThrow();
6
+ });
7
+
8
+ test("default constructor produces 0 size rectangle with valid position", () => {
9
+ const r = new Rectangle();
10
+
11
+ expect(r.size.x).toBe(0);
12
+ expect(r.size.y).toBe(0);
13
+
14
+ expect(r.position.x).not.toBeNaN();
15
+ expect(r.position.y).not.toBeNaN();
16
+ });
2
17
 
3
18
  test("toArray works correctly", () => {
4
19
  const v = new Rectangle(1, 2, 3, 4);
@@ -9,3 +24,39 @@ test("toArray works correctly", () => {
9
24
 
10
25
  expect(actual).toEqual([1, 2, 3, 4]);
11
26
  });
27
+
28
+ test("toJSON", () => {
29
+ const r = new Rectangle(1, 3, 7, 11);
30
+
31
+ expect(r.toJSON()).toEqual({
32
+ position: { x: 1, y: 3 },
33
+ size: { x: 7, y: 11 }
34
+ });
35
+ });
36
+
37
+ test("fromJSON", () => {
38
+
39
+ const r = new Rectangle();
40
+
41
+ r.fromJSON({
42
+ position: { x: 1, y: 3 },
43
+ size: { x: 7, y: 11 }
44
+ });
45
+
46
+ expect(r.position.x).toBe(1);
47
+ expect(r.position.y).toBe(3);
48
+
49
+ expect(r.size.x).toBe(7);
50
+ expect(r.size.y).toBe(11);
51
+ });
52
+
53
+ test("computeCenter", () => {
54
+ const r = new Rectangle(1, 3, 7, 11);
55
+
56
+ const center = new Vector2();
57
+
58
+ r.computeCenter(center);
59
+
60
+ expect(center.x).toBe(4.5);
61
+ expect(center.y).toBe(8.5);
62
+ });
@@ -1,6 +1,96 @@
1
1
  import { seededRandom } from "../../../math/random/seededRandom.js";
2
2
  import { aabb3_intersects_ray } from "./aabb3_intersects_ray.js";
3
3
 
4
+ test("axis aligned ray on X", () => {
5
+ expect(aabb3_intersects_ray(
6
+ -0.5, -0.5, -0.5,
7
+ +0.5, +0.5, +0.5,
8
+ -1, 0, 0,
9
+ 1, 0, 0
10
+ )).toBe(true);
11
+
12
+ expect(aabb3_intersects_ray(
13
+ -0.5, -0.5, -0.5,
14
+ +0.5, +0.5, +0.5,
15
+ -1, 0, 0,
16
+ -1, 0, 0
17
+ )).toBe(false);
18
+
19
+ expect(aabb3_intersects_ray(
20
+ -0.5, -0.5, -0.5,
21
+ +0.5, +0.5, +0.5,
22
+ 1, 0, 0,
23
+ -1, 0, 0
24
+ )).toBe(true);
25
+
26
+ expect(aabb3_intersects_ray(
27
+ -0.5, -0.5, -0.5,
28
+ +0.5, +0.5, +0.5,
29
+ 1, 0, 0,
30
+ 1, 0, 0
31
+ )).toBe(false);
32
+ });
33
+
34
+ test("axis aligned ray on Y", () => {
35
+ expect(aabb3_intersects_ray(
36
+ -0.5, -0.5, -0.5,
37
+ +0.5, +0.5, +0.5,
38
+ 0, -1, 0,
39
+ 0, 1, 0
40
+ )).toBe(true);
41
+
42
+ expect(aabb3_intersects_ray(
43
+ -0.5, -0.5, -0.5,
44
+ +0.5, +0.5, +0.5,
45
+ 0, -1, 0,
46
+ 0, -1, 0
47
+ )).toBe(false);
48
+
49
+ expect(aabb3_intersects_ray(
50
+ -0.5, -0.5, -0.5,
51
+ +0.5, +0.5, +0.5,
52
+ 0, 1, 0,
53
+ 0, -1, 0
54
+ )).toBe(true);
55
+
56
+ expect(aabb3_intersects_ray(
57
+ -0.5, -0.5, -0.5,
58
+ +0.5, +0.5, +0.5,
59
+ 0, 1, 0,
60
+ 0, 1, 0
61
+ )).toBe(false);
62
+ });
63
+
64
+ test("axis aligned ray on Z", () => {
65
+ expect(aabb3_intersects_ray(
66
+ -0.5, -0.5, -0.5,
67
+ +0.5, +0.5, +0.5,
68
+ 0, 0, -1,
69
+ 0, 0, 1
70
+ )).toBe(true);
71
+
72
+ expect(aabb3_intersects_ray(
73
+ -0.5, -0.5, -0.5,
74
+ +0.5, +0.5, +0.5,
75
+ 0, 0, -1,
76
+ 0, 0, -1
77
+ )).toBe(false);
78
+
79
+ expect(aabb3_intersects_ray(
80
+ -0.5, -0.5, -0.5,
81
+ +0.5, +0.5, +0.5,
82
+ 0, 0, 1,
83
+ 0, 0, -1
84
+ )).toBe(true);
85
+
86
+ expect(aabb3_intersects_ray(
87
+ -0.5, -0.5, -0.5,
88
+ +0.5, +0.5, +0.5,
89
+ 0, 0, 1,
90
+ 0, 0, 1
91
+ )).toBe(false);
92
+ });
93
+
4
94
  test.skip("performance raycast", () => {
5
95
  const rng = seededRandom(42);
6
96
 
@@ -0,0 +1,61 @@
1
+ import { line3_compute_nearest_point_to_point } from "./line3_compute_nearest_point_to_point.js";
2
+
3
+ test("aligned with the start of the line", () => {
4
+ const result = [];
5
+
6
+ line3_compute_nearest_point_to_point(result, 0,
7
+ 1, 3, 7, 11, 13, 17,
8
+ 1, 3, 7
9
+ );
10
+
11
+ expect(result).toEqual([1, 3, 7])
12
+ });
13
+
14
+ test("aligned with the end of the line", () => {
15
+ const result = [];
16
+
17
+ line3_compute_nearest_point_to_point(result, 0,
18
+ 1, 3, 7, 11, 13, 17,
19
+ 11, 13, 17
20
+ );
21
+
22
+ expect(result).toEqual([11, 13, 17])
23
+ });
24
+
25
+ test("ref point is on line past line ends", () => {
26
+
27
+ const result = [];
28
+
29
+ line3_compute_nearest_point_to_point(result, 0,
30
+ -1, 0, 0, 3, 0, 0,
31
+ -2, 0, 0
32
+ );
33
+
34
+ expect(result).toEqual([-1, 0, 0])
35
+
36
+ line3_compute_nearest_point_to_point(result, 0,
37
+ -1, 0, 0, 3, 0, 0,
38
+ 7, 0, 0
39
+ );
40
+
41
+ expect(result).toEqual([3, 0, 0])
42
+ });
43
+
44
+ test("ref point is on the line", () => {
45
+
46
+ const result = [];
47
+
48
+ line3_compute_nearest_point_to_point(result, 0,
49
+ -1, 0, 0, 3, 0, 0,
50
+ 1, 0, 0
51
+ );
52
+
53
+ expect(result).toEqual([1, 0, 0])
54
+
55
+ line3_compute_nearest_point_to_point(result, 0,
56
+ -1, 0, 0, 3, 0, 0,
57
+ 2, 0, 0
58
+ );
59
+
60
+ expect(result).toEqual([2, 0, 0])
61
+ });
@@ -1,37 +1,4 @@
1
- /**
2
- * method to separate bits from a given integer 3 positions apart
3
- * we only look at the first 10 bits
4
- *
5
- * @example when input is ABC, output bits are A00B00C
6
- * @param {number} a
7
- * @returns {number}
8
- */
9
- function split_by_3(a) {
10
- let x = a;
11
- x = (x | x << 16) & 0x30000ff;
12
- x = (x | x << 8) & 0x0300f00f;
13
- x = (x | x << 4) & 0x30c30c3;
14
- x = (x | x << 2) & 0x9249249;
15
- return x;
16
- }
17
-
18
- /**
19
- * method to separate bits from a given integer 2 positions apart
20
- *
21
- * @example when input is ABC, output bits are A00B00C
22
- * @see https://github.com/Forceflow/libmorton/blob/234a443ca8e2c64f6385f1a9d6ee10a70d08a3fa/include/libmorton/morton2D.h#L99
23
- * @param {number} a
24
- * @returns {number}
25
- */
26
- export function split_by_2(a) {
27
- let x = a;
28
- x = (x | x << 16) & 0x0000FFFF;
29
- x = (x | x << 8) & 0x00FF00FF;
30
- x = (x | x << 4) & 0x0F0F0F0F;
31
- x = (x | x << 2) & 0x33333333;
32
- x = (x | x << 1) & 0x55555555;
33
- return x;
34
- }
1
+ import { split_by_3 } from "./split_by_3.js";
35
2
 
36
3
  /**
37
4
  * Based on article and C++ source code:
@@ -0,0 +1,17 @@
1
+ /**
2
+ * method to separate bits from a given integer 2 positions apart
3
+ *
4
+ * @example when input is ABC, output bits are A00B00C
5
+ * @see https://github.com/Forceflow/libmorton/blob/234a443ca8e2c64f6385f1a9d6ee10a70d08a3fa/include/libmorton/morton2D.h#L99
6
+ * @param {number} a
7
+ * @returns {number}
8
+ */
9
+ export function split_by_2(a) {
10
+ let x = a;
11
+ x = (x | x << 16) & 0x0000FFFF;
12
+ x = (x | x << 8) & 0x00FF00FF;
13
+ x = (x | x << 4) & 0x0F0F0F0F;
14
+ x = (x | x << 2) & 0x33333333;
15
+ x = (x | x << 1) & 0x55555555;
16
+ return x;
17
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * method to separate bits from a given integer 3 positions apart
3
+ * we only look at the first 10 bits
4
+ *
5
+ * @example when input is ABC, output bits are A00B00C
6
+ * @param {number} a
7
+ * @returns {number}
8
+ */
9
+ export function split_by_3(a) {
10
+ let x = a;
11
+ x = (x | x << 16) & 0x30000ff;
12
+ x = (x | x << 8) & 0x0300f00f;
13
+ x = (x | x << 4) & 0x30c30c3;
14
+ x = (x | x << 2) & 0x9249249;
15
+ return x;
16
+ }
@@ -15,7 +15,12 @@ import { v3_dot } from "../../v3_dot.js";
15
15
  * @param {number} dist Plane distance
16
16
  * @returns {boolean} true if intersection is found, false otherwise
17
17
  */
18
- export function computePlaneLineIntersection(out, originX, originY, originZ, directionX, directionY, directionZ, normalX, normalY, normalZ, dist) {
18
+ export function computePlaneLineIntersection(
19
+ out,
20
+ originX, originY, originZ,
21
+ directionX, directionY, directionZ,
22
+ normalX, normalY, normalZ, dist
23
+ ) {
19
24
  const denom = v3_dot(directionX, directionY, directionZ, normalX, normalY, normalZ);
20
25
 
21
26
  const p = v3_dot(normalX, normalY, normalZ, originX, originY, originZ) + dist;
@@ -47,3 +47,14 @@ test("ray from +Z to -Z intersects sphere", () => {
47
47
  0, 0, -1
48
48
  )).toBe(true);
49
49
  });
50
+
51
+
52
+ // negative cases
53
+
54
+ test("ray from -X to -X", () => {
55
+ expect(sphere_intersects_ray(
56
+ 0, 0, 0, 1,
57
+ -2, 0, 0,
58
+ -1, 0, 0
59
+ )).toBe(false);
60
+ });
@@ -0,0 +1,8 @@
1
+ import { sphere_radius_sqr_from_v3_array_transformed } from "./sphere_radius_sqr_from_v3_array_transformed.js";
2
+ import { MATRIX_4_IDENTITY } from "../matrix/MATRIX_4_IDENTITY.js";
3
+
4
+ test("base case", () => {
5
+ expect(sphere_radius_sqr_from_v3_array_transformed([0, 0, 0], 3, MATRIX_4_IDENTITY)).toBe(0);
6
+ expect(sphere_radius_sqr_from_v3_array_transformed([1, 0, 0], 3, MATRIX_4_IDENTITY)).toBe(1);
7
+ expect(sphere_radius_sqr_from_v3_array_transformed([-1, 0, 0], 3, MATRIX_4_IDENTITY)).toBe(1);
8
+ });
@@ -9,7 +9,7 @@ import { topo_mesh_to_three_buffer_geometry } from "../topo_mesh_to_three_buffer
9
9
  import { three_buffer_geometry_to_topo_mesh } from "../three_buffer_geometry_to_topo_mesh.js";
10
10
  import { mesh_flood_fill } from "../util/mesh_flood_fill.js";
11
11
  import { compute_aabb_from_points } from "../../aabb/compute_aabb_from_points.js";
12
- import { AABB3 } from "../../../../bvh2/aabb3/AABB3.js";
12
+ import { AABB3 } from "../../../../geom/3d/aabb/AABB3.js";
13
13
  import { mergeVertices } from "three/examples/jsm/utils/BufferGeometryUtils.js";
14
14
  import { makeGeometryIndexed } from "../../../../../engine/graphics/geometry/buffered/makeGeometryIndexed.js";
15
15
  import { v3_dot } from "../../../v3_dot.js";
@@ -23,10 +23,10 @@ import { SGMeshEvents } from "../../../../../engine/graphics/ecs/mesh-v2/aggrega
23
23
  import { Color } from "../../../../color/Color.js";
24
24
  import { seededRandom } from "../../../../math/random/seededRandom.js";
25
25
  import { expandConnectivityByLocality } from "../expandConnectivityByLocality.js";
26
- import { buildCubeURLs } from "../../../../../engine/graphics/texture/cubemap/buildCubeURLs.js";
27
26
  import { EntityNode } from "../../../../../engine/ecs/parent/EntityNode.js";
28
27
  import { TransformAttachmentSystem } from "../../../../../engine/ecs/transform-attachment/TransformAttachmentSystem.js";
29
28
  import { make_ray_from_viewport_position } from "../../../../../engine/graphics/make_ray_from_viewport_position.js";
29
+ import { load_and_set_cubemap_v0 } from "../../../../../engine/graphics/load_and_set_cubemap_v0.js";
30
30
 
31
31
  const harness = new EngineHarness();
32
32
 
@@ -98,7 +98,7 @@ async function main(engine) {
98
98
  enableTerrain: false
99
99
  });
100
100
 
101
- engine.graphics.loadEnvironmentMap(buildCubeURLs('data/textures/cubemaps/hip_miramar/32/', '.png'));
101
+ load_and_set_cubemap_v0(engine.graphics,'data/textures/cubemaps/hip_miramar/32/', '.png')
102
102
 
103
103
  const path = 'data/models/sponza-pbr/gltf/sponza.glb';
104
104
 
@@ -1,4 +1,4 @@
1
- import { split_by_2 } from "../../../../morton/mortonEncode_magicbits.js";
1
+ import { split_by_2 } from "../../../../morton/split_by_2.js";
2
2
 
3
3
  export class OrderedEdge {
4
4
  /**
@@ -0,0 +1,57 @@
1
+ import { randomPointOnBox } from "./randomPointOnBox.js";
2
+
3
+ function assert_point_on_box(sample) {
4
+
5
+ const x = sample[0];
6
+ const y = sample[1];
7
+ const z = sample[2];
8
+
9
+ function assert_range(v) {
10
+ expect(v).toBeGreaterThanOrEqual(-0.5);
11
+ expect(v).toBeLessThanOrEqual(0.5);
12
+ }
13
+
14
+ if (Math.abs(x) === 0.5 && Math.abs(y) === 0.5) {
15
+ assert_range(z);
16
+ } else if (Math.abs(x) === 0.5 && Math.abs(z) === 0.5) {
17
+ assert_range(y);
18
+ } else if (Math.abs(y) === 0.5 && Math.abs(z) === 0.5) {
19
+ assert_range(x);
20
+ } else if (Math.abs(x) === 0.5) {
21
+ assert_range(y);
22
+ assert_range(z);
23
+ } else if (Math.abs(y) === 0.5) {
24
+ assert_range(x);
25
+ assert_range(z);
26
+ } else if (Math.abs(z) === 0.5) {
27
+ assert_range(y);
28
+ assert_range(x);
29
+ } else {
30
+ throw new Error(`Unexpected ${sample}`);
31
+ }
32
+
33
+ }
34
+
35
+ test("samples are on box shell", () => {
36
+ function validate(sample_value) {
37
+
38
+ const sample = [];
39
+
40
+ randomPointOnBox(() => sample_value, sample, 0);
41
+
42
+ assert_point_on_box(sample);
43
+ }
44
+
45
+ validate(0);
46
+ validate(1);
47
+
48
+ validate(0.1);
49
+ validate(0.2);
50
+ validate(0.3);
51
+ validate(0.4);
52
+ validate(0.5);
53
+ validate(0.6);
54
+ validate(0.7);
55
+ validate(0.8);
56
+ validate(0.9);
57
+ });
@@ -0,0 +1,43 @@
1
+ import { bessel_j0 } from "./bessel_j0.js";
2
+
3
+ test("sanity", () => {
4
+ const v = bessel_j0(0);
5
+
6
+ expect(typeof v).toBe("number");
7
+ expect(v).not.toBeNaN();
8
+
9
+ });
10
+
11
+ test("sweep through low positive values", () => {
12
+ // https://www.wolframalpha.com/input?i=besselj%5B0%2Cx%5D
13
+
14
+ expect(bessel_j0(0)).toBeCloseTo(1, 1);
15
+ expect(bessel_j0(0.1)).toBeCloseTo(0.997, 1);
16
+ expect(bessel_j0(0.2)).toBeCloseTo(0.990, 1);
17
+ expect(bessel_j0(0.3)).toBeCloseTo(0.977, 1);
18
+ expect(bessel_j0(0.4)).toBeCloseTo(0.960, 1);
19
+ expect(bessel_j0(0.5)).toBeCloseTo(0.938, 1);
20
+ expect(bessel_j0(0.6)).toBeCloseTo(0.912, 1);
21
+ expect(bessel_j0(0.7)).toBeCloseTo(0.881, 1);
22
+ expect(bessel_j0(0.8)).toBeCloseTo(0.846, 1);
23
+ expect(bessel_j0(0.9)).toBeCloseTo(0.807, 1);
24
+ expect(bessel_j0(1)).toBeCloseTo(0.765, 1);
25
+ expect(bessel_j0(2)).toBeCloseTo(0.223, 1);
26
+
27
+ });
28
+
29
+ test("roots", () => {
30
+
31
+ expect(bessel_j0(2.40482555769577)).toBeCloseTo(0, 1);
32
+ expect(bessel_j0(-2.40482555769577)).toBeCloseTo(0, 1);
33
+
34
+ expect(bessel_j0(5.52007811028631)).toBeCloseTo(0, 1);
35
+ expect(bessel_j0(-5.52007811028631)).toBeCloseTo(0, 1);
36
+
37
+ expect(bessel_j0(8.65372791291101)).toBeCloseTo(0, 1);
38
+ expect(bessel_j0(-8.65372791291101)).toBeCloseTo(0, 1);
39
+
40
+ expect(bessel_j0(11.7915344390143)).toBeCloseTo(0, 1);
41
+ expect(bessel_j0(-11.7915344390143)).toBeCloseTo(0, 1);
42
+
43
+ });
@@ -0,0 +1,30 @@
1
+ import { assert } from "../assert.js";
2
+
3
+ const q = 0.7172491568;
4
+ const p0 = 0.6312725339;
5
+ const ps0 = 0.4308049446;
6
+ const p1 = 0.3500347951;
7
+ const ps1 = 0.4678202347;
8
+ const p2 = -0.06207747907;
9
+ const ps2 = 0.04253832927;
10
+ // const lamb4 = (lamb * lamb) * (lamb * lamb);
11
+ const lamb4 = 0.559840650625;
12
+
13
+ /**
14
+ * Bessel first order function of zeroth order
15
+ * @see https://link.springer.com/article/10.1007/s40314-020-01238-z
16
+ * @see https://www.shadertoy.com/view/Wt3czM
17
+ * @param {number} x
18
+ * @return {number}
19
+ */
20
+ export function bessel_j0(x) {
21
+ assert.notNaN(x, 'x');
22
+
23
+ const xx = x * x;
24
+
25
+ const t0 = Math.sqrt(1.0 + lamb4 * xx);
26
+ const t1 = Math.sqrt(t0);
27
+
28
+ return xx === 0.0 ? 1.0 : 1.0 / (t1 * (1.0 + q * xx)) * ((p0 + p1 * xx + p2 * t0) * Math.cos(x) + ((ps0 + ps1 * xx) * t0 + ps2 * xx) * (Math.sin(x) / x));
29
+
30
+ }
@@ -0,0 +1,8 @@
1
+ import { murmur3_32 } from "./murmur3_32.js";
2
+
3
+ test("hashing [0] with 0 seed", () => {
4
+ const hash = murmur3_32(new Uint32Array([0]), 0);
5
+ expect(typeof hash).toBe("number");
6
+ expect(Number.isInteger(hash)).toBe(true);
7
+ expect(hash).not.toBeNaN();
8
+ });
@@ -0,0 +1,16 @@
1
+ import { squirrel3 } from "./squirrel3.js";
2
+
3
+ function expect_integer(v) {
4
+
5
+ expect(typeof v).toBe("number");
6
+ expect(Number.isInteger(v)).toBe(true);
7
+ expect(v).not.toBeNaN();
8
+ }
9
+
10
+ test("sanity check", () => {
11
+ expect_integer(squirrel3(0));
12
+ expect_integer(squirrel3(1));
13
+ expect_integer(squirrel3(-1));
14
+
15
+ expect(squirrel3(0)).not.toEqual(squirrel3(1));
16
+ });
@@ -111,6 +111,7 @@ export class NumericInterval {
111
111
 
112
112
  /**
113
113
  * Whether min and max are the same
114
+ * In other words if span is 0
114
115
  * @returns {boolean}
115
116
  */
116
117
  isExact() {
@@ -1,14 +1,16 @@
1
1
  import { assert } from "../assert.js";
2
2
 
3
+ // const lamb = 0.865;
4
+
3
5
  /**
4
- * Modified bessel function of the first kind
6
+ * Modified bessel function of the first kind zeroth order
5
7
  * @see https://mathworld.wolfram.com/ModifiedBesselFunctionoftheFirstKind.html
6
8
  * @see https://computergraphics.stackexchange.com/questions/6393/kaiser-windowed-sinc-filter-for-mip-mapping
7
9
  * @see https://github.com/terifan/ImageResampler/blob/dbc212ce6aaa769bf3c9623cb6ead58ffd51d76c/src/org/terifan/image_resampler/FilterFactory.java
8
10
  * @param {number} x
9
11
  * @returns {number}
10
12
  */
11
- export function bessel_i0(x) {
13
+ export function modified_bessel_i0(x) {
12
14
  assert.notNaN(x, 'x');
13
15
 
14
16
  let sum = 1.0;
@@ -24,3 +26,4 @@ export function bessel_i0(x) {
24
26
 
25
27
  return sum;
26
28
  }
29
+
@@ -58,9 +58,9 @@ const grad4 = /*#__PURE__*/ new Float64Array([0, 1, 1, 1, 0, 1, 1, -1, 0, 1, -1,
58
58
  /**
59
59
  * Creates a 2D noise function
60
60
  * @param random the random function that will be used to build the permutation table
61
- * @returns {function(x:number, y:number):number}
61
+ * @returns {function(x:number, y:number):number} producing values in range -1 .. 1
62
62
  */
63
- export function createNoise2D(random = Math.random) {
63
+ export function create_simplex_noise_2d(random = Math.random) {
64
64
  // allocate continuous chunk of memory
65
65
  const buffer = new ArrayBuffer(512 * 2);
66
66
 
@@ -0,0 +1,21 @@
1
+ import { create_simplex_noise_2d } from "./create_simplex_noise_2d.js";
2
+
3
+ test("sample 10 points in 0..1 range", () => {
4
+ const noise2d = create_simplex_noise_2d(() => 0);
5
+
6
+ const COUNT = 10;
7
+ for (let i = 0; i < COUNT; i++) {
8
+ const u = i / (COUNT - 1);
9
+ for (let j = 0; j < COUNT; j++) {
10
+ const v = j / (COUNT - 1);
11
+
12
+ const value = noise2d(u, v);
13
+
14
+ expect(typeof value).toBe('number');
15
+ expect(value).not.toBeNaN();
16
+
17
+ expect(value).toBeGreaterThanOrEqual(-1);
18
+ expect(value).toBeLessThanOrEqual(1);
19
+ }
20
+ }
21
+ });
@@ -0,0 +1,15 @@
1
+ import { normalizeArrayVector } from "./normalizeArrayVector.js";
2
+
3
+ test("1d vector normalization", () => {
4
+ const v = [7];
5
+
6
+ normalizeArrayVector(v, v, 1);
7
+
8
+ expect(v[0]).toBeCloseTo(1);
9
+
10
+ v[0] = -13;
11
+
12
+ normalizeArrayVector(v, v, 1);
13
+
14
+ expect(v[0]).toBeCloseTo(-1);
15
+ });
@@ -0,0 +1,20 @@
1
+ import { interpolate_irradiance_linear } from "./interpolate_irradiance_linear.js";
2
+
3
+ test("sanity check", () => {
4
+
5
+ expect(interpolate_irradiance_linear(3, 3, 3)).toBe(1);
6
+
7
+ expect(interpolate_irradiance_linear(3, 3, 7)).toBe(1);
8
+
9
+ expect(interpolate_irradiance_linear(7, 3, 7)).toBe(0);
10
+
11
+ expect(interpolate_irradiance_linear(0, 3, 7)).toBe(1);
12
+
13
+ expect(interpolate_irradiance_linear(11, 3, 7)).toBe(0);
14
+
15
+ const mid = interpolate_irradiance_linear(5, 3, 7);
16
+
17
+ expect(mid).toBeGreaterThan(0);
18
+ expect(mid).toBeLessThan(1);
19
+
20
+ });
@@ -1,19 +1,19 @@
1
1
  import { inverseLerp } from "../../inverseLerp.js";
2
2
 
3
3
  /**
4
- *
4
+ * Approximates logarithmic decay, except it goes to 0 at max
5
+ * Estimation is done using a 5th degree polynomial
5
6
  * @param {number} distance
6
7
  * @param {number} min
7
8
  * @param {number} max
8
9
  * @return {number}
9
10
  */
10
11
  export function interpolate_irradiance_lograrithmic(distance, min, max) {
11
- if (distance >= max) {
12
- return 0;
13
- }
14
12
 
15
13
  if (distance <= min) {
16
14
  return 1;
15
+ } else if (distance >= max) {
16
+ return 0;
17
17
  }
18
18
 
19
19
  const x = inverseLerp(min, max, distance);
@@ -0,0 +1,18 @@
1
+ import { interpolate_irradiance_lograrithmic } from "./interpolate_irradiance_lograrithmic.js";
2
+
3
+ test("sanity check", () => {
4
+ expect(interpolate_irradiance_lograrithmic(3, 3, 3)).toBe(1);
5
+
6
+ expect(interpolate_irradiance_lograrithmic(3, 3, 7)).toBe(1);
7
+
8
+ expect(interpolate_irradiance_lograrithmic(7, 3, 7)).toBe(0);
9
+
10
+ expect(interpolate_irradiance_lograrithmic(0, 3, 7)).toBe(1);
11
+
12
+ expect(interpolate_irradiance_lograrithmic(11, 3, 7)).toBe(0);
13
+
14
+ const mid = interpolate_irradiance_lograrithmic(5, 3, 7);
15
+
16
+ expect(mid).toBeGreaterThan(0);
17
+ expect(mid).toBeLessThan(1);
18
+ });