@woosh/meep-engine 2.75.9 → 2.76.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/build/meep.cjs +4 -2
  2. package/build/meep.module.js +4 -2
  3. package/package.json +1 -1
  4. package/src/core/binary/BitSet.js +4 -2
  5. package/src/core/collection/heap/Uin32Heap.spec.js +14 -1
  6. package/src/core/collection/heap/Uint32Heap.js +31 -16
  7. package/src/{engine/graphics → core/math/random}/generate_halton_jitter.js +2 -2
  8. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +1 -1
  9. package/src/engine/graphics/texture/virtual/VirtualTextureUsageUpdater.js +1 -1
  10. package/src/engine/navigation/grid/find_path_on_grid_astar.js +193 -124
  11. package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +75 -15
  12. package/src/engine/graphics/CanvasBlur.js +0 -599
  13. package/src/engine/graphics/material/LoadMaterial.js +0 -199
  14. package/src/engine/graphics/material/getTextureImmediate.js +0 -21
  15. package/src/engine/graphics/render/buffer/RenderGraph.js +0 -177
  16. package/src/engine/graphics/render/buffer/RenderGraphUtils.js +0 -32
  17. package/src/engine/graphics/render/buffer/buffers/DepthFrameBuffer.js +0 -101
  18. package/src/engine/graphics/render/buffer/conection/ProgramValueSlotConnection.js +0 -43
  19. package/src/engine/graphics/render/buffer/conection/ProgramValueSlotConnectionEndpoint.js +0 -39
  20. package/src/engine/graphics/render/buffer/conection/ProgramValueSlotConnectionValidator.js +0 -30
  21. package/src/engine/graphics/render/buffer/executor/FrameBufferPool.js +0 -127
  22. package/src/engine/graphics/render/buffer/executor/RenderGraphExecutor.js +0 -261
  23. package/src/engine/graphics/render/buffer/executor/RenderProgramCommandType.js +0 -5
  24. package/src/engine/graphics/render/buffer/node/DeferredRenderProgramDefinition.js +0 -142
  25. package/src/engine/graphics/render/buffer/node/RenderProgramDefinition.js +0 -21
  26. package/src/engine/graphics/render/buffer/node/RenderProgramInstance.js +0 -30
  27. package/src/engine/graphics/render/buffer/node/ScreenSpaceRenderProgramDefinition.js +0 -118
  28. package/src/engine/graphics/render/staged/PostProcessingEffect.js +0 -32
  29. package/src/engine/graphics/render/staged/PostProcessingEffectInputCoupling.js +0 -41
  30. package/src/engine/graphics/render/staged/PostProcessingStack.js +0 -29
  31. package/src/engine/graphics/render/staged/StagedRenderer.js +0 -161
  32. package/src/engine/graphics/render/staged/StandardRenderOutputs.js +0 -20
  33. package/src/engine/graphics/texture/CanvasClone.js +0 -28
  34. package/src/engine/graphics/texture/sampler/differenceSampler.js +0 -36
  35. package/src/engine/graphics/texture/sampler/loadSampler2D.js +0 -41
  36. package/src/engine/graphics/texture/sampler/mergeSampler2D.js +0 -96
  37. package/src/engine/graphics/texture/sampler/rgbaData2valueSampler2D.js +0 -38
  38. /package/src/{engine/graphics/texture → core/math/noise}/noise_octaves.js +0 -0
package/build/meep.cjs CHANGED
@@ -71805,7 +71805,7 @@ BitSet.prototype.shift = function (distance, start_index, end_index) {
71805
71805
  };
71806
71806
 
71807
71807
  /**
71808
- * Sets all of the bits in this BitSet to false.
71808
+ * Sets all the bits in this BitSet to false.
71809
71809
  */
71810
71810
  BitSet.prototype.reset = function () {
71811
71811
  const current_length = this.__length;
@@ -71813,7 +71813,9 @@ BitSet.prototype.reset = function () {
71813
71813
  if (current_length <= 0) {
71814
71814
  // no action required
71815
71815
  return;
71816
- } else if (current_length <= 32) {
71816
+ }
71817
+
71818
+ if (current_length <= 32) {
71817
71819
  // one word, set first word to 0 manually
71818
71820
  this.__data_uint32[0] = 0;
71819
71821
  } else {
@@ -71803,7 +71803,7 @@ BitSet.prototype.shift = function (distance, start_index, end_index) {
71803
71803
  };
71804
71804
 
71805
71805
  /**
71806
- * Sets all of the bits in this BitSet to false.
71806
+ * Sets all the bits in this BitSet to false.
71807
71807
  */
71808
71808
  BitSet.prototype.reset = function () {
71809
71809
  const current_length = this.__length;
@@ -71811,7 +71811,9 @@ BitSet.prototype.reset = function () {
71811
71811
  if (current_length <= 0) {
71812
71812
  // no action required
71813
71813
  return;
71814
- } else if (current_length <= 32) {
71814
+ }
71815
+
71816
+ if (current_length <= 32) {
71815
71817
  // one word, set first word to 0 manually
71816
71818
  this.__data_uint32[0] = 0;
71817
71819
  } else {
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.75.9",
8
+ "version": "2.76.1",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -546,7 +546,7 @@ BitSet.prototype.shift = function (distance, start_index, end_index) {
546
546
  };
547
547
 
548
548
  /**
549
- * Sets all of the bits in this BitSet to false.
549
+ * Sets all the bits in this BitSet to false.
550
550
  */
551
551
  BitSet.prototype.reset = function () {
552
552
  const current_length = this.__length;
@@ -554,7 +554,9 @@ BitSet.prototype.reset = function () {
554
554
  if (current_length <= 0) {
555
555
  // no action required
556
556
  return;
557
- } else if (current_length <= 32) {
557
+ }
558
+
559
+ if (current_length <= 32) {
558
560
  // one word, set first word to 0 manually
559
561
  this.__data_uint32[0] = 0;
560
562
  } else {
@@ -1,5 +1,5 @@
1
- import { Uint32Heap } from "./Uint32Heap.js";
2
1
  import { seededRandom } from "../../math/random/seededRandom.js";
2
+ import { Uint32Heap } from "./Uint32Heap.js";
3
3
 
4
4
  test('initial capacity setting via constructor', () => {
5
5
  const heap = new Uint32Heap(3);
@@ -126,6 +126,19 @@ test("insert_or_update", () => {
126
126
 
127
127
  });
128
128
 
129
+ test("clear should make heap empty", () => {
130
+ const heap = new Uint32Heap();
131
+
132
+ heap.clear();
133
+
134
+ expect(heap.is_empty()).toBe(true);
135
+
136
+ heap.insert(1, 7);
137
+
138
+ heap.clear();
139
+
140
+ expect(heap.is_empty()).toBe(true);
141
+ });
129
142
 
130
143
  test.skip("performance 1,000,000 random element fill / drain", () => {
131
144
 
@@ -55,12 +55,12 @@ function HEAP_RIGHT(i) {
55
55
  export class Uint32Heap {
56
56
  /**
57
57
  *
58
- * @param {number} [capacity] Can supply initial capacity, heap will still grow when necessary. This allows to prevent needless re-allocations when max heap size is known in advance
58
+ * @param {number} [initial_capacity] Can supply initial capacity, heap will still grow when necessary. This allows to prevent needless re-allocations when max heap size is known in advance
59
59
  */
60
- constructor(capacity = DEFAULT_CAPACITY) {
61
- assert.isNonNegativeInteger(capacity, 'capacity');
60
+ constructor(initial_capacity = DEFAULT_CAPACITY) {
61
+ assert.isNonNegativeInteger(initial_capacity, 'capacity');
62
62
 
63
- this.__data_buffer = new ArrayBuffer(capacity * ELEMENT_BYTE_SIZE);
63
+ this.__data_buffer = new ArrayBuffer(initial_capacity * ELEMENT_BYTE_SIZE);
64
64
 
65
65
  /**
66
66
  * Used to access stored IDs
@@ -76,7 +76,7 @@ export class Uint32Heap {
76
76
  */
77
77
  this.__data_float32 = new Float32Array(this.__data_buffer);
78
78
 
79
- this.__capacity = capacity;
79
+ this.__capacity = initial_capacity;
80
80
  this.__size = 0;
81
81
  }
82
82
 
@@ -140,9 +140,12 @@ export class Uint32Heap {
140
140
  uint32[i2] = uint32[j2];
141
141
  uint32[j2] = mem_0;
142
142
 
143
- const mem_1 = uint32[i2 + 1];
144
- uint32[i2 + 1] = uint32[j2 + 1];
145
- uint32[j2 + 1] = mem_1;
143
+ const i21 = i2 + 1;
144
+ const j21 = j2 + 1;
145
+
146
+ const mem_1 = uint32[i21];
147
+ uint32[i21] = uint32[j21];
148
+ uint32[j21] = mem_1;
146
149
  }
147
150
 
148
151
  /**
@@ -263,7 +266,7 @@ export class Uint32Heap {
263
266
  */
264
267
  find_index_by_id(id) {
265
268
  const n = this.__size
266
- const n2 = n * 2;
269
+ const n2 = n << 1; // fast *2 multiplication
267
270
 
268
271
  const uint32 = this.__data_uint32;
269
272
 
@@ -279,6 +282,12 @@ export class Uint32Heap {
279
282
  return -1;
280
283
  }
281
284
 
285
+ /**
286
+ * Clear out all the data, heap will be made empty
287
+ */
288
+ clear() {
289
+ this.__size = 0;
290
+ }
282
291
 
283
292
  /**
284
293
  *
@@ -331,14 +340,16 @@ export class Uint32Heap {
331
340
  }
332
341
 
333
342
  /**
334
- *
343
+ * Update score of an element referenced directly by index, this is a fast method, but you're generally not going to know the index so in most cases it's best to use "update_score" instead
335
344
  * @param {number} index
336
345
  * @param {number} score
337
346
  */
338
347
  __update_score_by_index(index, score) {
339
348
 
340
349
  const float32 = this.__data_float32;
341
- const index2 = index * 2;
350
+
351
+ const index2 = index << 1; // fast *2 multiplication
352
+
342
353
  const existing_score = float32[index2];
343
354
 
344
355
  if (score < existing_score) {
@@ -362,7 +373,9 @@ export class Uint32Heap {
362
373
  return Number.NaN;
363
374
  }
364
375
 
365
- return this.__data_float32[index * 2];
376
+ const index2 = index << 1; // fast *2 multiplication
377
+
378
+ return this.__data_float32[index2];
366
379
  }
367
380
 
368
381
 
@@ -391,21 +404,23 @@ export class Uint32Heap {
391
404
  assert.lessThanOrEqual(id, UINT32_MAX - 1, 'must be less than or equal to (2^32 - 2)');
392
405
  assert.isNumber(score, 'score');
393
406
 
394
- if (this.__size >= this.__capacity) {
407
+ const current_size = this.__size;
408
+
409
+ if (current_size >= this.__capacity) {
395
410
  // need to re-allocate
396
411
  this.__capacity_grow();
397
412
  }
398
413
 
399
414
  // insert at the end
400
- const index = this.__size;
401
- const address = index * 2;
415
+ const index = current_size;
416
+ const address = index << 1;
402
417
 
403
418
  // write data
404
419
  this.__data_float32[address] = score;
405
420
  this.__data_uint32[address + 1] = id;
406
421
 
407
422
  // record increased size
408
- this.__size++;
423
+ this.__size = current_size + 1;
409
424
 
410
425
  this.heap_up(index);
411
426
  }
@@ -1,5 +1,5 @@
1
- import { assert } from "../../core/assert.js";
2
- import { halton_sequence } from "../../core/math/statistics/halton_sequence.js";
1
+ import { assert } from "../../assert.js";
2
+ import { halton_sequence } from "../statistics/halton_sequence.js";
3
3
 
4
4
  /**
5
5
  * Generates a number of 2d jitter offsets in range -1...1
@@ -1,6 +1,6 @@
1
1
  import { array_copy } from "../../../../../../core/collection/array/array_copy.js";
2
+ import { generate_halton_jitter } from "../../../../../../core/math/random/generate_halton_jitter.js";
2
3
  import { EnginePlugin } from "../../../../../plugin/EnginePlugin.js";
3
- import { generate_halton_jitter } from "../../../../generate_halton_jitter.js";
4
4
 
5
5
  export class TemporalSupersamplingRenderPlugin extends EnginePlugin {
6
6
  constructor() {
@@ -16,7 +16,7 @@ import { assert } from "../../../../core/assert.js";
16
16
  import { array_copy } from "../../../../core/collection/array/array_copy.js";
17
17
  import { clamp } from "../../../../core/math/clamp.js";
18
18
  import { max2 } from "../../../../core/math/max2.js";
19
- import { generate_halton_jitter } from "../../generate_halton_jitter.js";
19
+ import { generate_halton_jitter } from "../../../../core/math/random/generate_halton_jitter.js";
20
20
  import { renderScreenSpace } from "../../render/utils/renderScreenSpace.js";
21
21
  import { Sampler2D } from "../sampler/Sampler2D.js";
22
22
  import { VirtualTextureUsage } from "./VirtualTextureUsage.js";
@@ -1,7 +1,9 @@
1
- import BinaryHeap from '../../../core/collection/heap/FastBinaryHeap.js';
2
- import Vector2 from '../../../core/geom/Vector2.js';
3
1
  import { assert } from "../../../core/assert.js";
2
+ import { BitSet } from "../../../core/binary/BitSet.js";
3
+ import { Uint32Heap } from "../../../core/collection/heap/Uint32Heap.js";
4
+ import Vector2 from '../../../core/geom/Vector2.js';
4
5
 
6
+ const neighbors = new Uint32Array(4);
5
7
 
6
8
  /**
7
9
  *
@@ -18,28 +20,169 @@ function index2point(result, index, width) {
18
20
 
19
21
  /**
20
22
  *
21
- * @param {number[]} result
23
+ * @param {number[]|Uint32Array} result
22
24
  * @param {number} index
23
25
  * @param {number} width
24
26
  * @param {number} height
27
+ * @returns {number}
25
28
  */
26
- function computeOrthogonalNeighbors(result, index, width, height) {
29
+ function computeNeighbors(result, index, width, height) {
27
30
  const x = index % width;
28
31
  const y = (index / width) | 0;
32
+
33
+ let neighbour_count = 0;
34
+
35
+ if (y > 0) {
36
+ result[neighbour_count] = index - width;
37
+ neighbour_count++
38
+ }
29
39
  if (x > 0) {
30
- result.push(index - 1);
40
+ result[neighbour_count] = index - 1;
41
+ neighbour_count++;
31
42
  }
32
43
  if (x < width - 1) {
33
- result.push(index + 1);
34
- }
35
- if (y > 0) {
36
- result.push(index - width);
44
+ result[neighbour_count] = index + 1;
45
+ neighbour_count++;
37
46
  }
38
47
  if (y < height - 1) {
39
- result.push(index + width);
48
+ result[neighbour_count] = index + width;
49
+ neighbour_count++
50
+ }
51
+
52
+ return neighbour_count;
53
+ }
54
+
55
+ /**
56
+ *
57
+ * @param {number} node
58
+ * @param {number[]} g_score
59
+ * @param {number} width
60
+ * @param {number} height
61
+ * @returns {number[]}
62
+ */
63
+ function pathTo(node, g_score, width, height) {
64
+ let v_previous = new Vector2(-1, -1);
65
+ let v_current = new Vector2();
66
+
67
+ let dx = 1,
68
+ dy = 1,
69
+ _dx = 0,
70
+ _dy = 0;
71
+
72
+ const result = [];
73
+
74
+ let current = node;
75
+ let prev = current;
76
+
77
+ let last_value = g_score[current];
78
+
79
+ while (current !== -1) {
80
+ index2point(v_current, current, width);
81
+
82
+ _dx = v_current.x - v_previous.x;
83
+ _dy = v_current.y - v_previous.y;
84
+
85
+ // normalize
86
+ if (_dx !== 0) {
87
+ _dx /= Math.abs(_dx);
88
+ }
89
+
90
+ if (_dy !== 0) {
91
+ _dy /= Math.abs(_dy);
92
+ }
93
+
94
+ const direction_change = dx !== _dx || dy !== _dy;
95
+
96
+ if (direction_change) {
97
+ // direction changed
98
+ dx = _dx;
99
+ dy = _dy;
100
+
101
+ //only record points where connection bends to save space
102
+ result.push(prev);
103
+ }
104
+
105
+ prev = current;
106
+
107
+
108
+ //swap vectors
109
+ const t = v_previous;
110
+ v_previous = v_current;
111
+ v_current = t;
112
+
113
+ // find next point
114
+ const neighbour_count = computeNeighbors(neighbors, current, width, height);
115
+
116
+ current = -1;
117
+
118
+ for (let i = 0; i < neighbour_count; i++) {
119
+ const neighbor = neighbors[i];
120
+
121
+ const score = g_score[neighbor];
122
+
123
+ if (score < last_value) {
124
+ current = neighbor;
125
+ last_value = score;
126
+ } else if (score === last_value) {
127
+ // same score, prefer non-bending neighbours
128
+
129
+ index2point(v_current, neighbor, width);
130
+
131
+ _dx = v_current.x - v_previous.x;
132
+ _dy = v_current.y - v_previous.y;
133
+
134
+ if (_dx === dx && _dy === dy) {
135
+ // same direction
136
+ current = neighbor;
137
+ last_value = score;
138
+ }
139
+
140
+ }
141
+ }
142
+
40
143
  }
144
+
145
+ if (result[result.length - 1] !== prev) {
146
+
147
+ //check if last node needs to be added
148
+ result.push(prev);
149
+
150
+ }
151
+
152
+ result.reverse();
153
+
154
+ return result;
41
155
  }
42
156
 
157
+
158
+ /**
159
+ *
160
+ * @param {number} index0
161
+ * @param {number} index1
162
+ * @param {number} width
163
+ * @returns {number}
164
+ */
165
+ function heuristic(index0, index1, width) {
166
+ const x1 = index0 % width;
167
+ const y1 = (index0 / width) | 0;
168
+
169
+ //
170
+ const x2 = index1 % width;
171
+ const y2 = (index1 / width) | 0;
172
+
173
+ //
174
+ const dx = Math.abs(x1 - x2);
175
+ const dy = Math.abs(y1 - y2);
176
+
177
+ return dx + dy;
178
+ }
179
+
180
+
181
+ const open = new Uint32Heap();
182
+
183
+ const closed = new BitSet();
184
+ closed.preventShrink();
185
+
43
186
  /**
44
187
  *
45
188
  * @param {number[]|Uint8Array|Uint16Array|Float32Array} field
@@ -48,8 +191,7 @@ function computeOrthogonalNeighbors(result, index, width, height) {
48
191
  * @param {number} start
49
192
  * @param {number} goal
50
193
  * @param {number} crossingPenalty
51
- * @param {number} bendPenalty
52
- * @param {number} blockValue
194
+ * @param {number} blockValue value in the field that signifies impassible obstacle
53
195
  * @returns {Array.<number>} array of indices representing path from start to end
54
196
  */
55
197
  export function find_path_on_grid_astar(
@@ -57,170 +199,97 @@ export function find_path_on_grid_astar(
57
199
  width, height,
58
200
  start, goal,
59
201
  crossingPenalty,
60
- bendPenalty,
61
202
  blockValue
62
203
  ) {
63
204
 
64
205
  assert.defined(field, 'field');
65
206
  assert.notNull(field, 'field');
66
207
 
67
-
68
208
  assert.isNonNegativeInteger(start, "start");
69
209
  assert.isNonNegativeInteger(goal, "goal");
70
210
 
71
211
  assert.isNumber(crossingPenalty, 'crossingPenalty');
72
- assert.isNumber(bendPenalty, 'bendPenalty');
73
212
  assert.isNumber(blockValue, 'blockValue');
74
213
 
214
+ // prepare sets
215
+ open.clear();
216
+ closed.reset();
75
217
 
76
- let limitCycles = 5000000;
77
-
78
- const heuristic = function (index0, index1) {
79
- const x1 = index0 % width;
80
- const y1 = Math.floor(index0 / width);
81
- //
82
- const x2 = index1 % width;
83
- const y2 = Math.floor(index1 / width);
84
- //
85
- const dx = Math.abs(x1 - x2);
86
- const dy = Math.abs(y1 - y2);
87
- return dx + dy;
88
- };
89
-
90
- const came_from = [];
91
- const f_score = [];
218
+ /**
219
+ * Contains refined heuristic value
220
+ * @type {number[]}
221
+ */
92
222
  const g_score = [];
93
223
 
94
- const open = new BinaryHeap(function score(i1) {
95
- return f_score[i1];
96
- });
224
+ g_score[start] = 0;
97
225
 
98
- const closed = [];
99
226
 
100
- g_score[start] = 0;
101
- f_score[goal] = heuristic(start, goal);
102
-
103
- const directionTo = [];
104
- directionTo[start] = 0;
105
-
106
- open.push(start);
107
-
108
- function pathTo(node) {
109
- let pP = new Vector2(-1, -1),
110
- pC = new Vector2();
111
- let dx = 1,
112
- dy = 1,
113
- _dx = 0,
114
- _dy = 0;
115
- const result = [];
116
- let prev = node;
117
- while (node !== void 0) {
118
- index2point(pC, node, width);
119
- _dx = pC.x - pP.x;
120
- _dy = pC.y - pP.y;
121
- //
122
- if (_dx !== 0) {
123
- _dx /= Math.abs(_dx);
124
- }
125
- if (_dy !== 0) {
126
- _dy /= Math.abs(_dy);
127
- }
128
- if (dx !== _dx || dy !== _dy) {
129
- dx = _dx;
130
- dy = _dy;
131
- //only record points where connection bends to save space
132
- result.push(prev);
133
- }
134
- prev = node;
135
- node = came_from[node];
136
- //swap
137
- const t = pP;
138
- pP = pC;
139
- pC = t;
140
- }
141
- if (result[result.length - 1] !== prev) {
142
- //check if last node needs to be added
143
- result.push(prev);
144
- }
145
- result.reverse();
146
- return result;
147
- }
227
+ open.insert(start, heuristic(start, goal, width));
228
+
229
+ while (!open.is_empty()) {
148
230
 
149
- const neighbors = [];
150
- while (open.size() > 0) {
151
- if (limitCycles-- === 0) {
152
- throw new Error("maximum number of cycles reached");
153
- }
154
231
  // Grab the lowest f(x) to process next. Heap keeps this sorted for us.
155
- const currentNode = open.pop();
232
+ const currentNode = open.pop_min();
156
233
 
157
- // End case -- result has been found, return the traced path.
158
234
  if (currentNode === goal) {
159
- return pathTo(currentNode);
235
+ // End case -- result has been found, return the traced path.
236
+ return pathTo(currentNode, g_score, width, height);
160
237
  }
161
238
 
162
239
  // Normal case -- move currentNode from open to closed, process each of its neighbors.
163
- closed[currentNode] = true;
240
+ closed.set(currentNode, true);
164
241
 
165
242
  // Find all neighbors for the current node.
166
- neighbors.length = 0;
167
- computeOrthogonalNeighbors(neighbors, currentNode, width, height);
168
- const numNeighbours = neighbors.length;
169
- if (numNeighbours === 0) {
170
- continue;
171
- }
172
- const directionToCurrent = directionTo[currentNode];
173
- for (let i = 0; i < numNeighbours; ++i) {
243
+ const neighbour_count = computeNeighbors(neighbors, currentNode, width, height);
244
+
245
+ for (let i = 0; i < neighbour_count; ++i) {
174
246
  const neighbor = neighbors[i];
175
247
 
176
- if (closed[neighbor] !== void 0) {
177
- // Not a valid node to process, skip to next neighbor.
248
+ if (closed.get(neighbor)) {
249
+ // Already closed, skip to next neighbor.
178
250
  continue;
179
251
  }
180
252
 
181
253
  // The g score is the shortest distance from start to current node.
182
254
  // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
183
255
  const neighborValue = field[neighbor];
256
+
184
257
  if (neighborValue === blockValue) {
185
- //cell is blocked, cloe and continue
186
- closed[neighbor] = true;
258
+ //cell is blocked, close and continue
259
+ closed.set(neighbor, true);
187
260
  continue;
188
261
  }
189
- const direction = neighbor - currentNode;
190
- let turnValue;
191
- if (direction !== directionToCurrent) {
192
- turnValue = bendPenalty;
193
- } else {
194
- turnValue = 0;
195
- }
196
- const transitionCost = neighborValue * crossingPenalty + 1 + turnValue;
197
262
 
198
- const gScore = g_score[currentNode] + transitionCost,
199
- notInOpenSet = !open.contains(neighbor);
263
+ // Cost of traversing to this neighbour
264
+ const transition_cost = neighborValue * crossingPenalty + 1;
200
265
 
201
- if (notInOpenSet || gScore < g_score[neighbor]) {
266
+ // updated path cost
267
+ const gScore = g_score[currentNode] + transition_cost;
202
268
 
203
- // Found an optimal (so far) path to this node. Take score for node to see how good it is.
204
- came_from[neighbor] = currentNode;
269
+ const index_in_open_set = open.find_index_by_id(neighbor);
205
270
 
206
- directionTo[neighbor] = direction;
271
+ const not_in_open_set = index_in_open_set === -1;
207
272
 
273
+ if (not_in_open_set || gScore < g_score[neighbor]) {
274
+
275
+ // update refined score
208
276
  g_score[neighbor] = gScore;
209
- const h = heuristic(neighbor, goal);
210
277
 
211
- f_score[neighbor] = gScore + h;
278
+ const h = heuristic(neighbor, goal, width);
212
279
 
280
+ const fScore = gScore + h;
213
281
 
214
- if (notInOpenSet) {
282
+ if (not_in_open_set) {
215
283
  // Pushing to heap will put it in proper place based on the 'f' value.
216
- open.push(neighbor);
284
+ open.insert(neighbor, fScore);
217
285
  } else {
218
- // Already seen the node, but since it has been rescored we need to reorder it in the heap
219
- open.updateElementScore(neighbor);
286
+ // Already seen the node, but since it has been re-scored we need to reorder it in the heap
287
+ open.__update_score_by_index(index_in_open_set, fScore);
220
288
  }
221
289
  }
222
290
  }
223
291
  }
292
+
224
293
  // No result was found - empty array signifies failure to find path.
225
294
  return [];
226
295
  }