@woosh/meep-engine 2.39.38 → 2.39.41

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 (69) hide show
  1. package/core/binary/Base64.js +58 -31
  2. package/core/binary/Base64.spec.js +14 -0
  3. package/core/binary/operations/ceilPowerOfTwo.spec.js +17 -0
  4. package/core/bvh2/binary/2/BinaryUint32BVH.js +7 -1
  5. package/core/bvh2/binary/2/BinaryUint32BVH.spec.js +31 -1
  6. package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.js +5 -5
  7. package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.spec.js +70 -0
  8. package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.spec.js +2 -2
  9. package/core/collection/IteratorUtils.js +1 -0
  10. package/core/collection/queue/Deque.js +5 -2
  11. package/core/color/Color.js +29 -7
  12. package/core/color/hsluv/HSLuv.js +187 -0
  13. package/core/geom/3d/aabb/aabb3_matrix4_project.js +1 -0
  14. package/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +1 -1
  15. package/core/geom/Quaternion.js +52 -38
  16. package/core/model/ModuleRegistry.js +1 -1
  17. package/core/model/reactive/model/terminal/ReactiveReference.js +1 -1
  18. package/core/model/reactive/trigger/ReactiveTrigger.js +14 -4
  19. package/core/primitives/strings/compareStrings.js +22 -0
  20. package/editor/Editor.js +2 -0
  21. package/editor/ecs/component/editors/ImagePathEditor.js +83 -0
  22. package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +12 -6
  23. package/editor/tools/v2/BlenderCameraOrientationGizmo.js +22 -11
  24. package/engine/EngineHarness.js +7 -0
  25. package/engine/asset/loaders/geometry/geometry/computeBufferAttributeHash.js +5 -6
  26. package/engine/asset/loaders/image/codec/Codec.js +9 -0
  27. package/engine/asset/loaders/image/codec/CodecWithFallback.js +52 -11
  28. package/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +12 -0
  29. package/engine/asset/loaders/image/png/PNGReader.js +2 -1
  30. package/engine/asset/loaders/image/png/PNG_HEADER_BYTES.js +1 -0
  31. package/engine/computeStridedIntegerArrayHash.js +19 -0
  32. package/engine/ecs/EntityBuilder.d.ts +2 -0
  33. package/engine/ecs/gui/GUIElement.d.ts +3 -1
  34. package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +5 -3
  35. package/engine/ecs/terrain/ecs/splat/SplatMapping.js +27 -4
  36. package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +11 -2
  37. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +14 -6
  38. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -8
  39. package/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +2 -1
  40. package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +17 -2
  41. package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +336 -0
  42. package/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +176 -0
  43. package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +7 -3
  44. package/engine/graphics/micron/build/hierarchy/merge_patches.js +0 -1
  45. package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -3
  46. package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +32 -1
  47. package/engine/graphics/render/forward_plus/LightManager.js +58 -13
  48. package/engine/graphics/render/forward_plus/debug/createScreenGrid.js +192 -9
  49. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +42 -1
  50. package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +1 -0
  51. package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +5 -0
  52. package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -4
  53. package/engine/graphics/render/forward_plus/model/Decal.js +33 -5
  54. package/engine/graphics/render/forward_plus/model/PointLight.js +1 -1
  55. package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +4 -0
  56. package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +480 -12
  57. package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +49 -29
  58. package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +11 -0
  59. package/engine/graphics/texture/atlas/CachingTextureAtlas.js +34 -0
  60. package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +9 -1
  61. package/engine/graphics/texture/atlas/TextureAtlas.js +29 -16
  62. package/engine/graphics/texture/atlas/TextureAtlasDebugger.js +75 -19
  63. package/engine/graphics/texture/sampler/Sampler2D.d.ts +2 -0
  64. package/engine/graphics/texture/sampler/Sampler2D.js +72 -11
  65. package/engine/sound/ecs/SoundListenerSystem.js +5 -0
  66. package/engine/sound/ecs/emitter/SoundEmitter.js +12 -1
  67. package/package.json +1 -1
  68. package/view/elements/button/ButtonView.js +12 -1
  69. package/view/tooltip/TooltipManager.js +0 -95
@@ -3,13 +3,21 @@
3
3
  * @author Jameson Little
4
4
  */
5
5
 
6
- var lookup = [];
7
- var revLookup = [];
8
- var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
6
+ /**
7
+ *
8
+ * @type {string[]}
9
+ */
10
+ const lookup = [];
11
+ /**
12
+ *
13
+ * @type {number[]}
14
+ */
15
+ const revLookup = [];
16
+ const Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array;
9
17
 
10
- var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
18
+ const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
11
19
 
12
- for (var i = 0, len = code.length; i < len; ++i) {
20
+ for (let i = 0, len = code.length; i < len; ++i) {
13
21
  lookup[i] = code[i];
14
22
  revLookup[code.charCodeAt(i)] = i;
15
23
  }
@@ -19,6 +27,11 @@ for (var i = 0, len = code.length; i < len; ++i) {
19
27
  revLookup['-'.charCodeAt(0)] = 62;
20
28
  revLookup['_'.charCodeAt(0)] = 63;
21
29
 
30
+ /**
31
+ *
32
+ * @param {string} b64
33
+ * @return {number[]}
34
+ */
22
35
  function getLens(b64) {
23
36
  var len = b64.length;
24
37
 
@@ -41,12 +54,6 @@ function getLens(b64) {
41
54
  }
42
55
 
43
56
  // base64 is 4/3 + up to two characters of the original data
44
- function byteLength(b64) {
45
- var lens = getLens(b64);
46
- var validLen = lens[0];
47
- var placeHoldersLen = lens[1];
48
- return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
49
- }
50
57
 
51
58
  function _byteLength(b64, validLen, placeHoldersLen) {
52
59
  return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen;
@@ -99,37 +106,57 @@ function toByteArray(b64) {
99
106
  }
100
107
 
101
108
  function tripletToBase64(num) {
102
- return lookup[num >> 18 & 0x3F] +
103
- lookup[num >> 12 & 0x3F] +
104
- lookup[num >> 6 & 0x3F] +
105
- lookup[num & 0x3F];
109
+ return lookup[num >> 18 & 0x3F]
110
+ + lookup[num >> 12 & 0x3F]
111
+ + lookup[num >> 6 & 0x3F]
112
+ + lookup[num & 0x3F]
113
+ ;
106
114
  }
107
115
 
116
+ /**
117
+ *
118
+ * @param {Uint8Array} uint8
119
+ * @param {number} start
120
+ * @param {number} end
121
+ * @return {string}
122
+ */
108
123
  function encodeChunk(uint8, start, end) {
109
- var tmp;
110
- var output = [];
111
- for (var i = start; i < end; i += 3) {
112
- tmp =
113
- ((uint8[i] << 16) & 0xFF0000) +
114
- ((uint8[i + 1] << 8) & 0xFF00) +
115
- (uint8[i + 2] & 0xFF);
124
+ const output = [];
125
+
126
+ for (let i = start; i < end; i += 3) {
127
+
128
+ const tmp = ((uint8[i] << 16) & 0xFF0000)
129
+ + ((uint8[i + 1] << 8) & 0xFF00)
130
+ + (uint8[i + 2] & 0xFF);
131
+
116
132
  output.push(tripletToBase64(tmp));
117
133
  }
134
+
118
135
  return output.join('');
119
136
  }
120
137
 
138
+ /**
139
+ *
140
+ * @param {Uint8Array} uint8
141
+ * @return {string}
142
+ */
121
143
  function fromByteArray(uint8) {
122
- var tmp;
123
- var len = uint8.length;
124
- var extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
125
- var parts = [];
126
- var maxChunkLength = 16383; // must be multiple of 3
144
+ let tmp;
145
+
146
+ const len = uint8.length;
147
+ const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes
148
+ const parts = [];
149
+ const maxChunkLength = 16383; // must be multiple of 3
127
150
 
128
151
  // go through the array every three bytes, we'll deal with trailing stuff later
129
- for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
130
- parts.push(encodeChunk(
131
- uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)
132
- ));
152
+ const len2 = len - extraBytes;
153
+
154
+ for (let i = 0; i < len2; i += maxChunkLength) {
155
+ const end = (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength);
156
+
157
+ const chunk = encodeChunk(uint8, i, end);
158
+
159
+ parts.push(chunk);
133
160
  }
134
161
 
135
162
  // pad the end with zeros, but make sure to not forget the extra bytes
@@ -0,0 +1,14 @@
1
+ import { Base64 } from "./Base64.js";
2
+
3
+ test("to/from consistency", () => {
4
+ const source = new Uint8Array(256);
5
+ for (let i = 0; i < source.length; i++) {
6
+ source[i] = i;
7
+ }
8
+
9
+ const encoded = Base64.encode(source.buffer);
10
+
11
+ const decoded = Base64.decode(encoded);
12
+
13
+ expect(Array.from(new Uint8Array(decoded))).toEqual(Array.from(source));
14
+ });
@@ -0,0 +1,17 @@
1
+ import { ceilPowerOfTwo } from "./ceilPowerOfTwo.js";
2
+
3
+ test('test', () => {
4
+ expect(ceilPowerOfTwo(1)).toBe(1);
5
+
6
+ expect(ceilPowerOfTwo(2)).toBe(2);
7
+
8
+ expect(ceilPowerOfTwo(3)).toBe(4);
9
+ expect(ceilPowerOfTwo(4)).toBe(4);
10
+
11
+ expect(ceilPowerOfTwo(5)).toBe(8);
12
+ expect(ceilPowerOfTwo(7)).toBe(8);
13
+ expect(ceilPowerOfTwo(8)).toBe(8);
14
+
15
+ expect(ceilPowerOfTwo(9)).toBe(16);
16
+ expect(ceilPowerOfTwo(15)).toBe(16);
17
+ });
@@ -201,7 +201,13 @@ export class BinaryUint32BVH {
201
201
 
202
202
  const twoLeafLimit = ceilPowerOfTwo(count);
203
203
 
204
- this.__node_count_binary = twoLeafLimit - 1;
204
+ if (count <= 1) {
205
+ // special case
206
+ this.__node_count_binary = twoLeafLimit;
207
+ } else {
208
+ this.__node_count_binary = twoLeafLimit - 1;
209
+ }
210
+
205
211
  }
206
212
 
207
213
  /**
@@ -12,6 +12,36 @@ test('1 leaf build does not throw', () => {
12
12
  bvh.build();
13
13
  });
14
14
 
15
+ test('0 leaf tree must have a no binary nodes', () => {
16
+ const bvh = new BinaryUint32BVH();
17
+
18
+ bvh.setLeafCount(0);
19
+ bvh.initialize_structure();
20
+ bvh.build();
21
+
22
+ expect(bvh.getBinaryNodeCount()).toBe(0);
23
+ });
24
+
25
+ test('1 leaf tree must have a single binary node', () => {
26
+ const bvh = new BinaryUint32BVH();
27
+
28
+ bvh.setLeafCount(1);
29
+ bvh.initialize_structure();
30
+ bvh.build();
31
+
32
+ expect(bvh.getBinaryNodeCount()).toBe(1);
33
+ });
34
+
35
+ test('4 leaf tree must have a 3 binary nodes', () => {
36
+ const bvh = new BinaryUint32BVH();
37
+
38
+ bvh.setLeafCount(4);
39
+ bvh.initialize_structure();
40
+ bvh.build();
41
+
42
+ expect(bvh.getBinaryNodeCount()).toBe(3);
43
+ });
44
+
15
45
  test('read/write 1 leaf', () => {
16
46
  const bvh = new BinaryUint32BVH();
17
47
 
@@ -23,7 +53,7 @@ test('read/write 1 leaf', () => {
23
53
  expect(bvh.readLeafPayload(0)).toBe(7);
24
54
 
25
55
  const bounds = [];
26
- bvh.readBounds(0, bounds, 0);
56
+ bvh.readBounds(bvh.getLeafBlockAddress(), bounds, 0);
27
57
 
28
58
  expect(bounds[0]).toBeCloseTo(-3);
29
59
  expect(bounds[1]).toBeCloseTo(-7);
@@ -41,7 +41,7 @@ export function bvh_query_user_data_nearest_to_point(bvh, x, y, z, max_distance
41
41
  traversal_stack[traversal_cursor++] = root;
42
42
 
43
43
  let best_leaf_data = -1;
44
- let best_distance = max_distance;
44
+ let best_distance_sqr = max_distance * max_distance;
45
45
 
46
46
  while (traversal_cursor > stack_frame_address) {
47
47
  traversal_cursor--;
@@ -55,13 +55,13 @@ export function bvh_query_user_data_nearest_to_point(bvh, x, y, z, max_distance
55
55
  bvh.node_get_aabb(node, scratch_aabb);
56
56
 
57
57
  // compute distance to box
58
- const distance = max2(0, aabb3_signed_distance_sqr_to_point(
58
+ const distance_sqr = max2(0, aabb3_signed_distance_sqr_to_point(
59
59
  scratch_aabb[0], scratch_aabb[1], scratch_aabb[2],
60
60
  scratch_aabb[3], scratch_aabb[4], scratch_aabb[5],
61
61
  x, y, z
62
62
  ));
63
63
 
64
- if (distance > best_distance) {
64
+ if (distance_sqr > best_distance_sqr) {
65
65
  // node is too far
66
66
  continue;
67
67
  }
@@ -81,8 +81,8 @@ export function bvh_query_user_data_nearest_to_point(bvh, x, y, z, max_distance
81
81
  } else {
82
82
 
83
83
  // leaf node
84
- if (distance < best_distance) {
85
- best_distance = distance;
84
+ if (distance_sqr < best_distance_sqr) {
85
+ best_distance_sqr = distance_sqr;
86
86
  best_leaf_data = bvh.node_get_user_data(node);
87
87
  }
88
88
 
@@ -0,0 +1,70 @@
1
+ import { ExplicitBinaryBoundingVolumeHierarchy } from "./ExplicitBinaryBoundingVolumeHierarchy.js";
2
+ import { bvh_query_user_data_nearest_to_point } from "./bvh_query_user_data_nearest_to_point.js";
3
+
4
+ /**
5
+ *
6
+ * @param {number[]} boxes
7
+ * @return {ExplicitBinaryBoundingVolumeHierarchy}
8
+ */
9
+ function makeBvh(...boxes) {
10
+ const r = new ExplicitBinaryBoundingVolumeHierarchy();
11
+
12
+ for (let i = 0; i < boxes.length; i++) {
13
+ const box = boxes[i];
14
+
15
+ const node = r.allocate_node();
16
+
17
+ r.node_set_aabb(node, box);
18
+ r.node_set_user_data(node, i);
19
+
20
+ r.insert_leaf(node);
21
+ }
22
+
23
+ return r;
24
+ }
25
+
26
+ test('no data, infinite distance', () => {
27
+ const bvh = makeBvh();
28
+
29
+ const result = bvh_query_user_data_nearest_to_point(bvh, 0, 0, 0, Infinity);
30
+
31
+ expect(result).toBe(-1);
32
+ });
33
+
34
+ test('single point, distance too short', () => {
35
+ const bvh = makeBvh([1, 0, 0, 1, 0, 0]);
36
+
37
+ const result = bvh_query_user_data_nearest_to_point(bvh, 0, 0, 0, 0.5);
38
+
39
+ expect(result).toBe(-1);
40
+ });
41
+
42
+ test('single point, distance sufficient', () => {
43
+ const bvh = makeBvh([1, 0, 0, 1, 0, 0]);
44
+
45
+ const result = bvh_query_user_data_nearest_to_point(bvh, 0, 0, 0, 1.5);
46
+
47
+ expect(result).not.toBe(-1);
48
+ });
49
+
50
+ test('two point, distance sufficient to one', () => {
51
+ const bvh = makeBvh(
52
+ [1, 0, 0, 1, 0, 0],
53
+ [2, 0, 0, 2, 0, 0],
54
+ );
55
+
56
+ const result = bvh_query_user_data_nearest_to_point(bvh, 0, 0, 0, 1.5);
57
+
58
+ expect(result).toBe(0);
59
+ });
60
+
61
+ test('two point, distance sufficient to both', () => {
62
+ const bvh = makeBvh(
63
+ [1, 0, 0, 1, 0, 0],
64
+ [2, 0, 0, 2, 0, 0],
65
+ );
66
+
67
+ const result = bvh_query_user_data_nearest_to_point(bvh, 0, 0, 0, 2.5);
68
+
69
+ expect(result).toBe(0);
70
+ });
@@ -13,7 +13,7 @@ function orthographic_frustum(left, right, up, down, near, far) {
13
13
  ]);
14
14
  }
15
15
 
16
- test('Empty', () => {
16
+ test('Empty does not throw', () => {
17
17
  const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
18
18
 
19
19
  const res = [];
@@ -23,7 +23,7 @@ test('Empty', () => {
23
23
  compute_tight_near_far_clipping_planes(res, 0, 0b000011, bvh, frustum);
24
24
  });
25
25
 
26
- test('Axis-aligned, orthographic tight fit around a single small node', () => {
26
+ test.skip('Axis-aligned, orthographic tight fit around a single small node', () => {
27
27
  const frustum = orthographic_frustum(-1, 1, -1, 1, -1, 1);
28
28
 
29
29
  const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
@@ -13,4 +13,5 @@ export function collectIteratorValueToArray(result, iterator) {
13
13
  result.push(it.value);
14
14
  }
15
15
 
16
+ return result;
16
17
  }
@@ -200,11 +200,14 @@ export class Deque {
200
200
  */
201
201
  __index_of(e) {
202
202
  const size = this.size();
203
- const capacity = this.__data.length;
203
+
204
+ const data = this.__data;
205
+ const capacity = data.length;
206
+
204
207
  for (let i = 0; i < size; i++) {
205
208
  const index = (this.__head + i) % capacity;
206
209
 
207
- const el = this.__data[index];
210
+ const el = data[index];
208
211
 
209
212
  if (el === e) {
210
213
  return i;
@@ -157,7 +157,8 @@ export class Color {
157
157
  let _h = h % 1;
158
158
 
159
159
  if (_h < 0) {
160
- _h = h + 1;
160
+ // move into positive range
161
+ _h = _h + Math.ceil(Math.abs(_h));
161
162
  }
162
163
 
163
164
  const k_r = (_h * 12) % 12;
@@ -184,7 +185,8 @@ export class Color {
184
185
  let _h = h % 1;
185
186
 
186
187
  if (_h < 0) {
187
- _h = h + 1;
188
+ // move into positive range
189
+ _h = _h + Math.ceil(Math.abs(_h));
188
190
  }
189
191
 
190
192
  const h_face = _h * 6;
@@ -244,7 +246,8 @@ export class Color {
244
246
  let _h = h % 1;
245
247
 
246
248
  if (_h < 0) {
247
- _h = h + 1;
249
+ // move into positive range
250
+ _h = _h + Math.ceil(Math.abs(_h));
248
251
  }
249
252
 
250
253
  const h_face = _h * 6;
@@ -301,18 +304,21 @@ export class Color {
301
304
  * @param {number} v 0..1
302
305
  */
303
306
  setHSV(h, s, v) {
304
- let _h = h % 1;
307
+ let _h = h;
305
308
 
306
309
  if (_h < 0) {
307
- _h = h + 1;
310
+ // move into positive range
311
+ _h = _h + Math.ceil(Math.abs(_h));
308
312
  }
309
313
 
314
+ _h = _h % 1
315
+
310
316
  const _s = clamp01(s);
311
317
  const _v = clamp01(v);
312
318
 
313
319
  let r, g, b;
314
320
 
315
- const i = Math.floor(h * 6);
321
+ const i = Math.floor(_h * 6);
316
322
  const f = _h * 6 - i;
317
323
  const p = _v * (1 - _s);
318
324
  const q = _v * (1 - f * _s);
@@ -409,7 +415,8 @@ export class Color {
409
415
  * @param {Color} other
410
416
  */
411
417
  copy(other) {
412
- this.setRGB(this.r, this.g, this.b);
418
+ this.a = other.a;
419
+ this.setRGB(other.r, other.g, other.b);
413
420
  }
414
421
 
415
422
  /**
@@ -530,6 +537,21 @@ export class Color {
530
537
  return new Color(r, g, b);
531
538
  }
532
539
 
540
+ /**
541
+ *
542
+ * @param {number} h
543
+ * @param {number} s
544
+ * @param {number} v
545
+ * @return {Color}
546
+ */
547
+ static fromHSV(h, s, v) {
548
+ const color = new Color();
549
+
550
+ color.setHSV(h, s, v);
551
+
552
+ return color;
553
+ }
554
+
533
555
 
534
556
  /**
535
557
  *
@@ -0,0 +1,187 @@
1
+ /**
2
+ * @see https://github.com/hsluv/hsluv-c/blob/master/src/hsluv.c
3
+ */
4
+
5
+ const temp_0 = new Float32Array(3);
6
+ const temp_1 = new Float32Array(3);
7
+ /* for RGB */
8
+ const m = new Float32Array([
9
+ 3.24096994190452134377, -1.53738317757009345794, -0.49861076029300328366,
10
+ -0.96924363628087982613, 1.87596750150772066772, 0.04155505740717561247,
11
+ 0.05563007969699360846, -0.20397695888897656435, 1.05697151424287856072
12
+ ]);
13
+
14
+ /* for XYZ */
15
+ const m_inv = new Float32Array([
16
+ 0.41239079926595948129, 0.35758433938387796373, 0.18048078840183428751,
17
+ 0.21263900587151035754, 0.71516867876775592746, 0.07219231536073371500,
18
+ 0.01933081871559185069, 0.11919477979462598791, 0.95053215224966058086
19
+ ]);
20
+
21
+ function dot_product(t1, offset_1, t2, offset_2) {
22
+ return t1[offset_1] * t2[offset_2] + t1[offset_1 + 1] * t2[offset_2 + 1] + t1[offset_1 + 2] * t2[offset_2 + 2];
23
+ }
24
+
25
+ /* Used for rgb conversions */
26
+
27
+ function from_linear(c) {
28
+ if (c <= 0.0031308)
29
+ return 12.92 * c;
30
+ else
31
+ return 1.055 * Math.pow(c, 1.0 / 2.4) - 0.055;
32
+ }
33
+
34
+ function to_linear(c) {
35
+ if (c > 0.04045)
36
+ return Math.pow((c + 0.055) / 1.055, 2.4);
37
+ else
38
+ return c / 12.92;
39
+ }
40
+
41
+ const ref_u = 0.19783000664283680764;
42
+ const ref_v = 0.46831999493879100370;
43
+
44
+ const kappa = 903.29629629629629629630;
45
+ const epsilon = 0.00885645167903563082;
46
+
47
+
48
+ /**
49
+ *
50
+ * @param {number} theta
51
+ * @param {number[]|Float32Array} line
52
+ * @param {number} line_address
53
+ * @return {number}
54
+ */
55
+ function ray_length_until_intersect(theta, line, line_address) {
56
+ return line[line_address + 1] / (Math.sin(theta) - line[line_address] * Math.cos(theta));
57
+ }
58
+
59
+ function get_bounds( l, bounds)
60
+ {
61
+ const tl = l + 16.0;
62
+ const sub1 = (tl * tl * tl) / 1560896.0;
63
+ const sub2 = (sub1 > epsilon ? sub1 : (l / kappa));
64
+ let channel;
65
+ let t;
66
+
67
+ for(channel = 0; channel < 3; channel++) {
68
+ const ch3 = channel*3;
69
+ let m1 = m[ch3];
70
+ let m2 = m[ch3+1];
71
+ let m3 = m[ch3+2];
72
+
73
+ for (t = 0; t < 2; t++) {
74
+ const top1 = (284517.0 * m1 - 94839.0 * m3) * sub2;
75
+ const top2 = (838422.0 * m3 + 769860.0 * m2 + 731718.0 * m1) * l * sub2 - 769860.0 * t * l;
76
+ const bottom = (632260.0 * m3 - 126452.0 * m2) * sub2 + 126452.0 * t;
77
+
78
+ const bounds_index = channel * 2 + t;
79
+ const bounds_address = bounds_index*2;
80
+
81
+ bounds[bounds_address] = top1 / bottom;
82
+ bounds[bounds_address] = top2 / bottom;
83
+ }
84
+ }
85
+ }
86
+
87
+ function max_chroma_for_lh(l, h) {
88
+ let min_len = Infinity;
89
+ const hrad = h * 0.01745329251994329577; /* (2 * pi / 360) */
90
+ const bounds = new Float32Array(12);
91
+ let i;
92
+
93
+ get_bounds(l, bounds);
94
+
95
+ for (i = 0; i < 6; i++) {
96
+ const len = ray_length_until_intersect(hrad, bounds, i * 2);
97
+
98
+ if (len >= 0 && len < min_len)
99
+ min_len = len;
100
+ }
101
+
102
+ return min_len;
103
+ }
104
+
105
+ function hsluv2lch(input, output) {
106
+ let h = input[0];
107
+ const s = input[1];
108
+ const l = input[2];
109
+ let c;
110
+
111
+ /* White and black: disambiguate chroma */
112
+ if (l > 99.9999999 || l < 0.00000001)
113
+ c = 0.0;
114
+ else
115
+ c = max_chroma_for_lh(l, h) / 100.0 * s;
116
+
117
+ /* Grays: disambiguate hue */
118
+ if (s < 0.00000001)
119
+ h = 0.0;
120
+
121
+ output[0] = l;
122
+ output[1] = c;
123
+ output[2] = h;
124
+ }
125
+
126
+ function lch2luv(input, output) {
127
+
128
+ }
129
+
130
+ function luv2xyz(input, output) {
131
+
132
+ }
133
+
134
+ function xyz2rgb(input, output) {
135
+ const r = from_linear(dot_product(m, 0, input, 0));
136
+
137
+ const g = from_linear(dot_product(m, 3, input, 0));
138
+
139
+ const b = from_linear(dot_product(m, 6, input, 0));
140
+
141
+ output[0] = r;
142
+ output[1] = g;
143
+ output[2] = b;
144
+ }
145
+
146
+ function rgb2xyz(input, output) {
147
+
148
+ }
149
+
150
+ function xyz2luv(input, output) {
151
+
152
+ }
153
+
154
+ function luv2lch(input, output) {
155
+
156
+ }
157
+
158
+ function lch2hsluv(input, output) {
159
+
160
+ }
161
+
162
+
163
+ /**
164
+ *
165
+ * @param {number[]} input
166
+ * @param {number[]} output
167
+ */
168
+ export function rgb2hsluv(input, output) {
169
+ rgb2xyz(input, temp_0);
170
+ xyz2luv(temp_0, temp_1);
171
+ luv2lch(temp_1, temp_0);
172
+ lch2hsluv(temp_0, output);
173
+ }
174
+
175
+ /**
176
+ *
177
+ * @param {number[]} input
178
+ * @param {number[]} output
179
+ */
180
+ export function hsluv2rgb(input, output) {
181
+ hsluv2lch(input, temp_0);
182
+ lch2luv(temp_0, temp_1);
183
+ luv2xyz(temp_1, temp_0);
184
+ xyz2rgb(temp_0, output);
185
+ }
186
+
187
+
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * NOTE: Based on Transforming Axis-Aligned Bounding Boxes by Jim Arvo from "Graphics Gems", Academic Press, 1990
3
+ * NOTE: {@link result} and {@link aabb} must be different objects
3
4
  * @param {ArrayLike<number>|number[]|Float32Array} result
4
5
  * @param {ArrayLike<number>|number[]|Float32Array} aabb
5
6
  * @param {number[]} matrix 4x4 matrix
@@ -52,7 +52,7 @@ export function edge_collapse_reduce_face_count(mesh, num_faces_to_remove, heap,
52
52
  const target_face_count = max2(0, mesh_faces.size - num_faces_to_remove);
53
53
 
54
54
  let cycle_count = 0;
55
- let cycle_limit = max2(heap.size, num_faces_to_remove * 4);
55
+ let cycle_limit = max2(heap.size, num_faces_to_remove * 10) + 10;
56
56
 
57
57
  while (
58
58
  !heap.is_empty()