@woosh/meep-engine 2.48.12 → 2.48.14

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 (68) hide show
  1. package/package.json +1 -1
  2. package/src/core/collection/queue/Deque.d.ts +9 -0
  3. package/src/core/collection/queue/Deque.js +3 -0
  4. package/src/core/collection/queue/Deque.spec.js +51 -0
  5. package/src/core/font/FontAssetLoader.js +2 -2
  6. package/src/core/math/bessel_3.js +3 -1
  7. package/src/core/math/noise/create_noise_2d.js +193 -0
  8. package/src/core/path/computeFileExtension.js +3 -2
  9. package/src/engine/Engine.js +14 -8
  10. package/src/engine/achievements/AchievementManager.js +16 -16
  11. package/src/engine/asset/AssetManager.d.ts +10 -5
  12. package/src/engine/asset/AssetManager.js +79 -24
  13. package/src/engine/asset/AssetManager.spec.js +1 -1
  14. package/src/engine/asset/AssetRequest.js +19 -1
  15. package/src/engine/asset/AssetRequestScope.d.ts +3 -0
  16. package/src/engine/asset/AssetRequestScope.js +64 -0
  17. package/src/engine/asset/PendingAsset.js +7 -7
  18. package/src/engine/asset/loaders/ArrayBufferLoader.js +1 -1
  19. package/src/engine/asset/loaders/AssetLoader.d.ts +9 -2
  20. package/src/engine/asset/loaders/AssetLoader.js +19 -16
  21. package/src/engine/asset/loaders/GLTFAssetLoader.d.ts +1 -1
  22. package/src/engine/asset/loaders/GLTFAssetLoader.js +2 -2
  23. package/src/engine/asset/loaders/JavascriptAssetLoader.js +17 -12
  24. package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
  25. package/src/engine/asset/loaders/LegacyThreeJSONAssetLoader.js +4 -1
  26. package/src/engine/asset/loaders/SVGAssetLoader.js +1 -1
  27. package/src/engine/asset/loaders/SoundAssetLoader.js +4 -6
  28. package/src/engine/asset/loaders/TextAssetLoader.js +1 -1
  29. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +24 -17
  30. package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts +1 -1
  31. package/src/engine/asset/loaders/texture/TextureAssetLoader.js +1 -1
  32. package/src/engine/asset/preloader/Preloader.js +1 -1
  33. package/src/engine/development/performance/MetricStatistics.js +7 -5
  34. package/src/engine/development/performance/RingBufferMetric.js +2 -2
  35. package/src/engine/ecs/foliage/ecs/Foliage2System.js +7 -5
  36. package/src/engine/ecs/foliage/ecs/InstancedMeshUtils.js +14 -1
  37. package/src/engine/ecs/gui/GUIElementSystem.d.ts +1 -1
  38. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +2 -2
  39. package/src/engine/ecs/terrain/ecs/PromiseSamplerHeight.js +16 -9
  40. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +3 -21
  41. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +16 -11
  42. package/src/engine/ecs/terrain/serialization/TerrainSerializationAdapter.js +1 -1
  43. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +18 -15
  44. package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +4 -2
  45. package/src/engine/graphics/ecs/mesh/MeshSystem.js +1 -1
  46. package/src/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +6 -4
  47. package/src/engine/graphics/material/getTextureImmediate.js +5 -3
  48. package/src/engine/graphics/texture/3d/SingleChannelSampler3D.js +146 -0
  49. package/src/engine/graphics/texture/3d/scs3d_read_2d_slice.js +26 -0
  50. package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +1 -1
  51. package/src/engine/graphics/texture/sampler/Sampler2D.js +22 -13
  52. package/src/engine/graphics/texture/sampler/filter/box.js +3 -3
  53. package/src/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +2 -1
  54. package/src/engine/graphics/texture/sampler/genericResampleSampler2D.js +9 -8
  55. package/src/engine/graphics/texture/sampler/loadSampler2D.js +18 -16
  56. package/src/engine/graphics/texture/sampler/sampler2d_scale_down_linear.js +8 -11
  57. package/src/engine/graphics/texture/virtual/tile/TileLoader.js +1 -1
  58. package/src/engine/graphics/trail/x/RibbonXPlugin.js +5 -3
  59. package/src/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
  60. package/src/engine/physics/fluid/FluidField.js +153 -1
  61. package/src/engine/physics/fluid/prototype.js +201 -0
  62. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +67 -0
  63. package/src/engine/sound/ecs/emitter/loadSoundTrackAsset.js +1 -1
  64. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +17 -12
  65. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +14 -10
  66. package/src/view/elements/MeshPreview.js +66 -64
  67. package/src/view/elements/image/SvgImageView.js +8 -6
  68. package/src/view/renderModel.js +1 -1
@@ -147,7 +147,7 @@ export class TileLoader {
147
147
  }
148
148
 
149
149
  //do load
150
- this.assetManager.get('image', url, success, failure);
150
+ this.assetManager.get({ path: 'image', type: url, callback: success, failure: failure });
151
151
  }
152
152
 
153
153
  /**
@@ -115,9 +115,11 @@ export class RibbonXPlugin extends EnginePlugin {
115
115
  if (spec.diffuse !== null) {
116
116
  const am = this.engine.assetManager;
117
117
 
118
- am.get(spec.diffuse, GameAssetType.Texture, (asset) => {
119
- material.uniforms.uDiffuse.value = asset.create();
120
- }, console.warn);
118
+ am.get({
119
+ path: spec.diffuse, type: GameAssetType.Texture, callback: (asset) => {
120
+ material.uniforms.uDiffuse.value = asset.create();
121
+ }, failure: console.warn
122
+ });
121
123
 
122
124
  material.defines.USE_TEXTURE = true;
123
125
  }
@@ -116,7 +116,7 @@ export class StaticKnowledgeDataTable {
116
116
  * @returns {T|null}
117
117
  */
118
118
  get(id) {
119
- assert.typeOf(id, 'string', 'id');
119
+ assert.isString(id, 'id');
120
120
 
121
121
  const element = this.elements[id];
122
122
 
@@ -1,9 +1,161 @@
1
+ import { clamp } from "../../../core/math/clamp.js";
2
+ import { lerp } from "../../../core/math/lerp.js";
3
+
4
+ /**
5
+ *
6
+ * @param {Float32Array} data
7
+ * @param {number[]} resolution
8
+ */
9
+ function v3_grid_apply_advection_forward(data, resolution) {
10
+
11
+ }
12
+
13
+ /**
14
+ *
15
+ * @param {Float32Array} data
16
+ * @param {number[]} resolution
17
+ */
18
+ function v3_grid_apply_advection_reverse(data, resolution) {
19
+
20
+ }
21
+
1
22
  /**
2
23
  * Represents a space where fluid simulation happens
3
24
  *
4
25
  * @see 2019 GDC talk by Runard Rupert "Wind Simulation in God of War" https://www.youtube.com/watch?v=dDgyBKkSf7A
5
26
  * @see Inspired by GDC talk "Interactive Wind and Vegetation in 'God of War'" - https://www.youtube.com/watch?v=MKX45_riWQA
6
27
  */
7
- export class FluidField{
28
+ export class FluidField {
29
+ data = new Float32Array(0)
30
+ #size = [0, 0, 0]
31
+ #resolution = [0, 0, 0]
32
+
33
+
34
+ build() {
35
+ this.data = new Float32Array(
36
+ this.#resolution[0] * this.#resolution[1] * this.#resolution[2] * 3
37
+ );
38
+ }
39
+
40
+ /**
41
+ *
42
+ * @param {number[]} out
43
+ * @param {number} u
44
+ * @param {number} v
45
+ * @param {number} w
46
+ */
47
+ sample_linear_uv(out, u, v, w) {
48
+ const max_x = this.#resolution[0] - 1;
49
+ const max_y = this.#resolution[1] - 1;
50
+ const max_z = this.#resolution[2] - 1;
51
+
52
+ this.sample_linear(out, u * max_x, v * max_y, w * max_z);
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param {number[]} out
58
+ * @param {number} x
59
+ * @param {number} y
60
+ * @param {number} z
61
+ */
62
+ sample_linear(out, x, y, z) {
63
+ out[0] = this.sample_channel_linear(x, y, z, 0);
64
+ out[1] = this.sample_channel_linear(x, y, z, 1);
65
+ out[2] = this.sample_channel_linear(x, y, z, 2);
66
+ }
67
+
68
+ /**
69
+ *
70
+ * @param {number} x
71
+ * @param {number} y
72
+ * @param {number} z
73
+ * @param {number} channel
74
+ * @returns {number}
75
+ */
76
+ sample_channel_linear(x, y, z, channel) {
77
+ const resolution = this.#resolution;
78
+
79
+ const res_x = resolution[0];
80
+ const res_y = resolution[1];
81
+ const res_z = resolution[2];
82
+
83
+ const x_max = res_x - 1;
84
+ const y_max = res_y - 1;
85
+ const z_max = res_z - 1;
86
+
87
+ const x_clamped = clamp(x, 0, x_max);
88
+ const y_clamped = clamp(y, 0, y_max);
89
+ const z_clamped = clamp(z, 0, z_max);
90
+
91
+ const x0 = x_clamped | 0;
92
+ const y0 = y_clamped | 0;
93
+ const z0 = z_clamped | 0;
94
+
95
+ const f_x = x_clamped - x0;
96
+ const f_y = y_clamped - y0;
97
+ const f_z = z_clamped - z0;
98
+
99
+ const x1 = x_clamped === x0 ? x0 : x0 + 1;
100
+ const y1 = y_clamped === y0 ? y0 : y0 + 1;
101
+ const z1 = z_clamped === z0 ? z0 : z0 + 1;
102
+
103
+ // get 8 points
104
+ const data = this.data;
105
+
106
+ const z0_offset = z0 * (res_x * res_y) * 3;
107
+
108
+ const y0_offset = y0 * res_x * 3;
109
+
110
+ const x0_offset = x0 * 3 + channel;
111
+ const x1_offset = x1 * 3 + channel;
112
+
113
+ const x0y0z0 = data[z0_offset + y0_offset + x0_offset];
114
+ const x1y0z0 = data[z0_offset + y0_offset + x1_offset];
115
+
116
+ const y1_offset = y1 * res_x * 3;
117
+
118
+ const x0y1z0 = data[z0_offset + y1_offset + x0_offset];
119
+ const x1y1z0 = data[z0_offset + y1_offset + x1_offset];
120
+
121
+ const z1_offset = z1 * (res_x * res_y) * 3;
122
+
123
+ const x0y0z1 = data[z1_offset + y0_offset + x0_offset];
124
+ const x1y0z1 = data[z1_offset + y0_offset + x1_offset];
125
+
126
+ const x0y1z1 = data[z1_offset + y1_offset + x0_offset];
127
+ const x1y1z1 = data[z1_offset + y1_offset + x1_offset];
128
+
129
+ // filter on z0
130
+ const lerp_z0_y0 = lerp(x0y0z0, x1y0z0, f_x);
131
+ const lerp_z0_y1 = lerp(x0y1z0, x1y1z0, f_x);
132
+ const lerp_z0 = lerp(lerp_z0_y0, lerp_z0_y1, f_y);
133
+
134
+ // filter on z1
135
+ const lerp_z1_y0 = lerp(x0y0z1, x1y0z1, f_x);
136
+ const lerp_z1_y1 = lerp(x0y1z1, x1y1z1, f_x);
137
+ const lerp_z1 = lerp(lerp_z1_y0, lerp_z1_y1, f_y);
138
+
139
+ return lerp(lerp_z0, lerp_z1, f_z);
140
+ }
141
+
142
+ set size(v) {
143
+ const width = v[0];
144
+ const height = v[1];
145
+ const depth = v[2];
146
+
147
+ this.#size[0] = width;
148
+ this.#size[1] = height;
149
+ this.#size[2] = depth
150
+ }
151
+
152
+ set resolution(v) {
153
+ const width = v[0];
154
+ const height = v[1];
155
+ const depth = v[2];
8
156
 
157
+ this.#resolution[0] = width;
158
+ this.#resolution[1] = height;
159
+ this.#resolution[2] = depth
160
+ }
9
161
  }
@@ -0,0 +1,201 @@
1
+ import { EngineHarness } from "../../EngineHarness.js";
2
+ import { SingleChannelSampler3D } from "../../graphics/texture/3d/SingleChannelSampler3D.js";
3
+ import GUIElementSystem from "../../ecs/gui/GUIElementSystem.js";
4
+ import EntityBuilder from "../../ecs/EntityBuilder.js";
5
+ import GUIElement from "../../ecs/gui/GUIElement.js";
6
+ import EmptyView from "../../../view/elements/EmptyView.js";
7
+ import { Sampler2D } from "../../graphics/texture/sampler/Sampler2D.js";
8
+ import { CanvasView } from "../../../view/elements/CanvasView.js";
9
+ import { float2uint8 } from "../../../core/binary/float2uint8.js";
10
+ import { clamp } from "../../../core/math/clamp.js";
11
+ import { randomIntegerBetween } from "../../../core/math/random/randomIntegerBetween.js";
12
+ import { seededRandom } from "../../../core/math/random/seededRandom.js";
13
+ import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorComponent.js";
14
+ import { BehaviorSystem } from "../../intelligence/behavior/ecs/BehaviorSystem.js";
15
+ import { v3_grid_apply_diffusion } from "./solver/v3_grid_apply_diffusion.js";
16
+ import { max2 } from "../../../core/math/max2.js";
17
+ import { MetricCollection } from "../../development/performance/MetricCollection.js";
18
+ import { PeriodicConsolePrinter } from "../../development/performance/monitor/PeriodicConsolePrinter.js";
19
+ import { MetricStatistics } from "../../development/performance/MetricStatistics.js";
20
+
21
+ const harness = new EngineHarness();
22
+
23
+ class SliceVisualiser extends EmptyView {
24
+
25
+ /**
26
+ *
27
+ * @param {SingleChannelSampler3D} source
28
+ */
29
+ constructor(source) {
30
+ super({ classList: ['slice-visualizer'] });
31
+
32
+ this.source = source;
33
+
34
+ const slices = [];
35
+ const views = [];
36
+
37
+ const resolution = source.resolution;
38
+ const resolution_x = resolution[0];
39
+ const resolution_y = resolution[1];
40
+ const resolution_z = resolution[2];
41
+
42
+ const slice_size = resolution_x * resolution_y;
43
+
44
+ /**
45
+ *
46
+ * @type {ImageData|null}
47
+ */
48
+ let imageData = null;
49
+
50
+ for (let i = 0; i < resolution_z; i++) {
51
+ slices[i] = new Sampler2D(new Float32Array(source.data.buffer, i * slice_size * 4, slice_size), 1, resolution_x, resolution_y);
52
+
53
+ const child = new CanvasView();
54
+ child.size.set(resolution_x, resolution_y);
55
+
56
+ if (imageData === null) {
57
+ imageData = child.context2d.getImageData(0, 0, resolution_x, resolution_y);
58
+ }
59
+
60
+ child.css({
61
+ position: "absolute",
62
+ left: 0,
63
+ top: 0
64
+ });
65
+
66
+ views[i] = child;
67
+
68
+ this.addChild(child);
69
+ }
70
+
71
+ this.draw = () => {
72
+
73
+ for (let i = 0; i < resolution_z; i++) {
74
+ const view = views[i];
75
+ const slice = slices[i];
76
+
77
+ for (let j = 0; j < slice_size; j++) {
78
+ const j4 = j * 4;
79
+
80
+
81
+ const uint8_value = float2uint8(slice.data[j]);
82
+
83
+ imageData.data[j4] = clamp(uint8_value, 0, 255);
84
+ imageData.data[j4 + 3] = 255;
85
+ }
86
+
87
+ view.context2d.putImageData(imageData, 0, 0);
88
+ }
89
+
90
+ };
91
+
92
+ const layout = () => {
93
+ const width = this.size.x;
94
+
95
+ const grid_width = max2(1, Math.floor(width / resolution_x));
96
+
97
+ for (let i = 0; i < resolution_z; i++) {
98
+ const view = views[i];
99
+
100
+ const grid_x = i % grid_width;
101
+ const grid_y = Math.floor(i / grid_width);
102
+
103
+ view.position.set(grid_x * resolution_x, grid_y * resolution_y);
104
+ }
105
+ }
106
+
107
+ this.on.linked.add(layout);
108
+ this.size.onChanged.add(layout);
109
+ }
110
+
111
+
112
+ }
113
+
114
+ const metrics = new MetricCollection();
115
+
116
+ metrics.create({ name: 'sim' })
117
+
118
+ /**
119
+ *
120
+ * @param {Engine} engine
121
+ */
122
+ function main(engine) {
123
+
124
+ const ecd = engine.entityManager.dataset;
125
+
126
+ const sampler = new SingleChannelSampler3D();
127
+
128
+ sampler.resolution = [32, 32, 16];
129
+
130
+ const random = seededRandom();
131
+
132
+ sampler.data.fill(1000, 20, 40);
133
+
134
+ for (let i = 0; i < 100; i++) {
135
+
136
+ sampler.write(
137
+ randomIntegerBetween(random, 0, 16),
138
+ randomIntegerBetween(random, 0, 16),
139
+ randomIntegerBetween(random, 0, 4),
140
+ random()
141
+ );
142
+
143
+ }
144
+
145
+
146
+ const slice_view = new SliceVisualiser(sampler);
147
+
148
+ slice_view.size.set(432, 1000);
149
+ slice_view.scale.setScalar(2);
150
+ slice_view.transformOrigin.set(0, 0);
151
+
152
+ const sampler_0 = sampler.clone();
153
+ const sampler_1 = sampler.clone();
154
+
155
+ const ping_pong = [sampler_0, sampler_1];
156
+ let ping_pong_index = 0;
157
+
158
+
159
+ new EntityBuilder()
160
+ .add(BehaviorComponent.looping_function(time_delta => {
161
+
162
+ const source = ping_pong[ping_pong_index % 2];
163
+ const target = ping_pong[(ping_pong_index + 1) % 2];
164
+
165
+ ping_pong_index++;
166
+
167
+ const t0 = performance.now();
168
+
169
+ for (let i = 0; i < 5; i++) {
170
+ v3_grid_apply_diffusion(target.data, source.data, source.resolution);
171
+ }
172
+
173
+ metrics.get('sim').record(performance.now() - t0);
174
+
175
+ sampler.copy(target);
176
+
177
+ slice_view.draw();
178
+
179
+ }))
180
+ .build(ecd);
181
+
182
+ const metric_stats = new MetricStatistics();
183
+
184
+ new PeriodicConsolePrinter(3, () => metrics.list().map(m => {
185
+ metrics.get(m).computeStats(metric_stats);
186
+
187
+ return `${m}: ${metric_stats}`;
188
+ }).join('\n')).start()
189
+
190
+ new EntityBuilder()
191
+ .add(GUIElement.fromView(slice_view))
192
+ .build(ecd);
193
+
194
+ }
195
+
196
+ harness.initialize({
197
+ configuration(config, engine) {
198
+ config.addSystem(new GUIElementSystem(engine.gameView, engine))
199
+ config.addSystem(new BehaviorSystem(engine))
200
+ }
201
+ }).then(main)
@@ -0,0 +1,67 @@
1
+ /**
2
+ *
3
+ * @param {Float32Array} output
4
+ * @param {Float32Array} input
5
+ * @param {number[]} resolution
6
+ */
7
+ export function v3_grid_apply_diffusion(output, input, resolution) {
8
+ const res_x = resolution[0];
9
+ const res_y = resolution[1];
10
+ const res_z = resolution[2];
11
+
12
+ const factor = 1 / 7;
13
+
14
+ let sum = 0;
15
+
16
+ const slice_size = res_y * res_x;
17
+
18
+ for (let z = 0; z < res_z; z++) {
19
+ for (let y = 0; y < res_y; y++) {
20
+ for (let x = 0; x < res_x; x++) {
21
+
22
+ let sample_count = 1;
23
+
24
+ sum = 0;
25
+
26
+ // sample cells around
27
+ if (z > 0) {
28
+ sample_count++;
29
+ sum += input[(z - 1) * slice_size + y * res_x + x]
30
+ }
31
+
32
+ if (y > 0) {
33
+ sample_count++;
34
+ sum += input[z * slice_size + (y - 1) * res_x + x]
35
+ }
36
+
37
+ if (x > 0) {
38
+ sample_count++;
39
+ sum += input[z * slice_size + y * res_x + (x - 1)]
40
+ }
41
+
42
+
43
+ const current = z * slice_size + y * res_x + x;
44
+
45
+ sum += input[current];
46
+
47
+ if (x < res_x - 1) {
48
+ sample_count++;
49
+ sum += input[z * slice_size + y * res_x + (x + 1)]
50
+ }
51
+
52
+ if (y < res_y - 1) {
53
+ sample_count++;
54
+ sum += input[z * slice_size + (y + 1) * res_x + x]
55
+ }
56
+
57
+ if (z < res_z - 1) {
58
+ sample_count++;
59
+ sum += input[(z + 1) * slice_size + y * res_x + x]
60
+ }
61
+
62
+ output[current] = sum / sample_count;
63
+
64
+ }
65
+ }
66
+ }
67
+ }
@@ -37,5 +37,5 @@ export function loadSoundTrackAsset(track, assetManager, resolve = noop, reject
37
37
  asset_path = track_url;
38
38
  }
39
39
 
40
- assetManager.get(asset_path, GameAssetType.Sound, resolve, reject);
40
+ assetManager.get({ path: asset_path, type: GameAssetType.Sound, callback: resolve, failure: reject });
41
41
  }
@@ -72,12 +72,20 @@ export class CellFilterGaussianBlur extends CellFilter {
72
72
  * @private
73
73
  */
74
74
  this.__kernel = [];
75
+
75
76
  /**
76
77
  *
77
78
  * @type {number}
78
79
  * @private
79
80
  */
80
81
  this.__kernel_total_power = 0;
82
+
83
+ /**
84
+ *
85
+ * @type {number}
86
+ * @private
87
+ */
88
+ this.__inv_kernel_total_power = 0;
81
89
  }
82
90
 
83
91
  initialize(grid, seed) {
@@ -94,6 +102,9 @@ export class CellFilterGaussianBlur extends CellFilter {
94
102
  // initialize kernel
95
103
  this.__kernel_total_power = buildKernel(this.__kernel, this.samples_x, this.samples_y, this.sigma_x, this.sigma_y);
96
104
 
105
+ // store inverse, to be able to use multiply instead of division in execution
106
+ this.__inv_kernel_total_power = 1 / this.__kernel_total_power;
107
+
97
108
  super.initialize(grid, seed);
98
109
  }
99
110
 
@@ -132,8 +143,8 @@ export class CellFilterGaussianBlur extends CellFilter {
132
143
  const sizeX = this.size_x;
133
144
  const sizeY = this.size_y;
134
145
 
135
- const local_u_scale = 1 / (samplesX - 1);
136
- const local_v_scale = 1 / (samplesY - 1);
146
+ const local_u_scale = sizeX / (samplesX - 1);
147
+ const local_v_scale = sizeY / (samplesY - 1);
137
148
 
138
149
  let sum = 0;
139
150
  let ix, iy = 0;
@@ -146,9 +157,7 @@ export class CellFilterGaussianBlur extends CellFilter {
146
157
  for (; iy < samplesY; iy++) {
147
158
  const local_y = iy - half_samples_y;
148
159
 
149
- const ny = local_y * local_v_scale;
150
-
151
- const offset_y = sizeY * ny;
160
+ const offset_y = y + local_y * local_v_scale;
152
161
 
153
162
  const row_address = iy * i_samples_x;
154
163
 
@@ -156,13 +165,11 @@ export class CellFilterGaussianBlur extends CellFilter {
156
165
 
157
166
  const local_x = ix - half_samples_x;
158
167
 
159
- const nx = local_x * local_u_scale;
160
-
161
- const offset_x = sizeX * nx;
168
+ const offset_x = local_x * local_u_scale;
162
169
 
163
170
  const power = kernel[row_address + ix];
164
171
 
165
- const sourceValue = source.execute(grid, x + offset_x, y + offset_y, 0);
172
+ const sourceValue = source.execute(grid, x + offset_x, offset_y, 0);
166
173
 
167
174
  const sample_contribution = sourceValue * power;
168
175
 
@@ -171,8 +178,6 @@ export class CellFilterGaussianBlur extends CellFilter {
171
178
  }
172
179
  }
173
180
 
174
- const result = sum / this.__kernel_total_power;
175
-
176
- return result;
181
+ return sum * this.__inv_kernel_total_power;
177
182
  }
178
183
  }
@@ -1,10 +1,10 @@
1
1
  import { seededRandom } from "../../../../core/math/random/seededRandom.js";
2
2
  import { CellFilter } from "../../CellFilter.js";
3
- import SimplexNoise from "simplex-noise";
4
3
  import { CellFilterAdd } from "../math/algebra/CellFilterAdd.js";
5
4
  import { CellFilterMultiply } from "../math/algebra/CellFilterMultiply.js";
6
5
  import { CellFilterLiteralFloat } from "../CellFilterLiteralFloat.js";
7
6
  import { CellFilterDivide } from "../math/algebra/CellFilterDivide.js";
7
+ import { createNoise2D } from "../../../../core/math/noise/create_noise_2d.js";
8
8
 
9
9
  export class CellFilterSimplexNoise extends CellFilter {
10
10
  constructor() {
@@ -12,7 +12,7 @@ export class CellFilterSimplexNoise extends CellFilter {
12
12
 
13
13
  /**
14
14
  * @private
15
- * @type {SimplexNoise}
15
+ * @type {function(x:number,y:number):number}
16
16
  */
17
17
  this.noise = null;
18
18
 
@@ -25,6 +25,9 @@ export class CellFilterSimplexNoise extends CellFilter {
25
25
  this.scale_x = 1;
26
26
  this.scale_y = 1;
27
27
 
28
+ this.inv_scale_x = 1;
29
+ this.inv_scale_y = 1;
30
+
28
31
  /**
29
32
  * RNG Seed offset
30
33
  * @type {number}
@@ -50,6 +53,8 @@ export class CellFilterSimplexNoise extends CellFilter {
50
53
  let amplitude = 1;
51
54
  let totalAmplitude = 0;
52
55
 
56
+ const G = Math.pow(2, -persistence);
57
+
53
58
  for (let i = 0; i < octaves; i++) {
54
59
  const noise = CellFilterSimplexNoise.from(scale * frequency, scale * frequency, s);
55
60
 
@@ -63,7 +68,7 @@ export class CellFilterSimplexNoise extends CellFilter {
63
68
  }
64
69
 
65
70
  totalAmplitude += amplitude;
66
- amplitude *= persistence;
71
+ amplitude *= G;
67
72
  frequency *= lacunarity;
68
73
 
69
74
  s = (s + 1) * 31;
@@ -95,25 +100,24 @@ export class CellFilterSimplexNoise extends CellFilter {
95
100
  r.scale_y = scale_y;
96
101
  r.__seed = seed;
97
102
 
103
+ r.inv_scale_x = 1 / scale_x;
104
+ r.inv_scale_y = 1 / scale_y;
105
+
98
106
  return r;
99
107
  }
100
108
 
101
109
  initialize(grid, seed) {
102
110
  this.random.setCurrentSeed(seed + this.__seed);
103
111
 
104
- const noise = new SimplexNoise(this.random);
105
-
106
- this.noise = noise;
112
+ this.noise = createNoise2D(this.random);
107
113
 
108
114
  super.initialize(grid, seed);
109
115
  }
110
116
 
111
117
  execute(grid, x, y, rotation) {
112
- const noiseValue = this.noise.noise2D(x / this.scale_x, y / this.scale_y);
118
+ const noiseValue = this.noise(x * this.inv_scale_x, y * this.inv_scale_y);
113
119
 
114
120
  //noise function returns values in range [-1,1] we need to scale that to [0,1] range
115
- const normalizedValue = (noiseValue + 1) / 2;
116
-
117
- return normalizedValue;
121
+ return (noiseValue + 1) * 0.5;
118
122
  }
119
123
  }