@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.
- package/core/binary/Base64.js +58 -31
- package/core/binary/Base64.spec.js +14 -0
- package/core/binary/operations/ceilPowerOfTwo.spec.js +17 -0
- package/core/bvh2/binary/2/BinaryUint32BVH.js +7 -1
- package/core/bvh2/binary/2/BinaryUint32BVH.spec.js +31 -1
- package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.js +5 -5
- package/core/bvh2/bvh3/bvh_query_user_data_nearest_to_point.spec.js +70 -0
- package/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.spec.js +2 -2
- package/core/collection/IteratorUtils.js +1 -0
- package/core/collection/queue/Deque.js +5 -2
- package/core/color/Color.js +29 -7
- package/core/color/hsluv/HSLuv.js +187 -0
- package/core/geom/3d/aabb/aabb3_matrix4_project.js +1 -0
- package/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +1 -1
- package/core/geom/Quaternion.js +52 -38
- package/core/model/ModuleRegistry.js +1 -1
- package/core/model/reactive/model/terminal/ReactiveReference.js +1 -1
- package/core/model/reactive/trigger/ReactiveTrigger.js +14 -4
- package/core/primitives/strings/compareStrings.js +22 -0
- package/editor/Editor.js +2 -0
- package/editor/ecs/component/editors/ImagePathEditor.js +83 -0
- package/editor/ecs/component/editors/ecs/terrain/TerrainEditor.js +12 -6
- package/editor/tools/v2/BlenderCameraOrientationGizmo.js +22 -11
- package/engine/EngineHarness.js +7 -0
- package/engine/asset/loaders/geometry/geometry/computeBufferAttributeHash.js +5 -6
- package/engine/asset/loaders/image/codec/Codec.js +9 -0
- package/engine/asset/loaders/image/codec/CodecWithFallback.js +52 -11
- package/engine/asset/loaders/image/codec/ThreadedImageDecoder.js +12 -0
- package/engine/asset/loaders/image/png/PNGReader.js +2 -1
- package/engine/asset/loaders/image/png/PNG_HEADER_BYTES.js +1 -0
- package/engine/computeStridedIntegerArrayHash.js +19 -0
- package/engine/ecs/EntityBuilder.d.ts +2 -0
- package/engine/ecs/gui/GUIElement.d.ts +3 -1
- package/engine/ecs/terrain/ecs/layers/TerrainLayers.js +5 -3
- package/engine/ecs/terrain/ecs/splat/SplatMapping.js +27 -4
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +11 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +14 -6
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +2 -8
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +2 -1
- package/engine/graphics/ecs/mesh-v2/aggregate/SGMeshSystem.js +17 -2
- package/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +336 -0
- package/engine/graphics/geometry/optimization/merge/prototypeGeometryMerge.js +176 -0
- package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +7 -3
- package/engine/graphics/micron/build/hierarchy/merge_patches.js +0 -1
- package/engine/graphics/micron/prototypeVirtualGeometry.js +3 -3
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +32 -1
- package/engine/graphics/render/forward_plus/LightManager.js +58 -13
- package/engine/graphics/render/forward_plus/debug/createScreenGrid.js +192 -9
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +42 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_PREAMBLE.js +1 -0
- package/engine/graphics/render/forward_plus/materials/ForwardPlusThreeMaterial.js +5 -0
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +1 -4
- package/engine/graphics/render/forward_plus/model/Decal.js +33 -5
- package/engine/graphics/render/forward_plus/model/PointLight.js +1 -1
- package/engine/graphics/render/forward_plus/plugin/MaterialTransformer.js +4 -0
- package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +480 -12
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +49 -29
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +11 -0
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +34 -0
- package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +9 -1
- package/engine/graphics/texture/atlas/TextureAtlas.js +29 -16
- package/engine/graphics/texture/atlas/TextureAtlasDebugger.js +75 -19
- package/engine/graphics/texture/sampler/Sampler2D.d.ts +2 -0
- package/engine/graphics/texture/sampler/Sampler2D.js +72 -11
- package/engine/sound/ecs/SoundListenerSystem.js +5 -0
- package/engine/sound/ecs/emitter/SoundEmitter.js +12 -1
- package/package.json +1 -1
- package/view/elements/button/ButtonView.js +12 -1
- package/view/tooltip/TooltipManager.js +0 -95
package/core/binary/Base64.js
CHANGED
|
@@ -3,13 +3,21 @@
|
|
|
3
3
|
* @author Jameson Little
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
18
|
+
const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
11
19
|
|
|
12
|
-
for (
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
for (
|
|
112
|
-
|
|
113
|
-
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
|
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
|
|
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 (
|
|
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 (
|
|
85
|
-
|
|
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();
|
|
@@ -200,11 +200,14 @@ export class Deque {
|
|
|
200
200
|
*/
|
|
201
201
|
__index_of(e) {
|
|
202
202
|
const size = this.size();
|
|
203
|
-
|
|
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 =
|
|
210
|
+
const el = data[index];
|
|
208
211
|
|
|
209
212
|
if (el === e) {
|
|
210
213
|
return i;
|
package/core/color/Color.js
CHANGED
|
@@ -157,7 +157,8 @@ export class Color {
|
|
|
157
157
|
let _h = h % 1;
|
|
158
158
|
|
|
159
159
|
if (_h < 0) {
|
|
160
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
307
|
+
let _h = h;
|
|
305
308
|
|
|
306
309
|
if (_h < 0) {
|
|
307
|
-
|
|
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(
|
|
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.
|
|
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 *
|
|
55
|
+
let cycle_limit = max2(heap.size, num_faces_to_remove * 10) + 10;
|
|
56
56
|
|
|
57
57
|
while (
|
|
58
58
|
!heap.is_empty()
|