@woosh/meep-engine 2.35.17 → 2.36.2
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/BinaryBuffer.js +42 -17
- package/core/bvh2/BinaryNode.js +1 -1
- package/core/bvh2/aabb3/AABB3.js +2 -2
- package/core/bvh2/aabb3/aabb3_array_combine.js +20 -0
- package/core/bvh2/aabb3/aabb3_array_intersects_frustum_array.js +20 -0
- package/core/bvh2/aabb3/aabb3_array_intersects_ray.js +1 -0
- package/core/bvh2/aabb3/aabb3_array_intersects_ray_array.js +14 -0
- package/core/bvh2/{aabb3_combined_surface_area.js → aabb3/aabb3_combined_surface_area.js} +3 -3
- package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +1 -19
- package/core/bvh2/bvh3/BVHNodeProxy.js +53 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +848 -0
- package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +142 -0
- package/core/bvh2/bvh3/bvh_query_leaves_generic.js +79 -0
- package/core/bvh2/bvh3/bvh_query_leaves_ray.js +95 -0
- package/core/bvh2/bvh3/query/BVHQuery.js +11 -0
- package/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +36 -0
- package/core/bvh2/bvh3/query/BVHQueryIntersectsRay.js +36 -0
- package/core/collection/array/copyArray.js +2 -2
- package/core/collection/table/RowFirstTable.js +25 -7
- package/core/collection/table/RowFirstTableSpec.js +4 -4
- package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +1 -1
- package/{engine/graphics/util → core/geom/3d/aabb}/computeBoundingBoxFromVertexData.js +1 -1
- package/core/geom/3d/compose_matrix4_array.js +53 -0
- package/{engine/graphics/util → core/geom/3d}/decompose_matrix_4_array.js +0 -0
- package/core/geom/AABB2.d.ts +2 -0
- package/core/geom/Vector1.js +2 -3
- package/core/geom/Vector3.js +5 -1
- package/core/process/undo/ActionProcessor.js +31 -3
- package/core/process/undo/ActionProcessor.spec.js +1 -1
- package/engine/animation/curve/AnimationCurve.js +40 -1
- package/engine/animation/curve/Keyframe.js +19 -0
- package/engine/animation/curve/compression/animation_curve_to_float_array.js +35 -0
- package/engine/animation/curve/compression/downsample_float_array.js +50 -0
- package/engine/animation/curve/compression/downsample_float_array_curve_by_error.js +147 -0
- package/engine/animation/curve/compression/downsample_float_array_curve_by_error.spec.js +47 -0
- package/engine/animation/curve/compression/prototypeCurveCompression.js +154 -0
- package/engine/animation/curve/draw/build_curve_editor.js +316 -0
- package/engine/animation/curve/draw/build_plot_entity_from_array.js +47 -0
- package/engine/animation/curve/draw/build_tangent_editor.js +115 -0
- package/engine/animation/curve/draw/draw_grid.js +27 -0
- package/engine/animation/curve/draw/draw_label.js +17 -0
- package/engine/animation/curve/draw/plot_array.js +76 -0
- package/engine/animation/curve/draw/plot_data.js +49 -0
- package/engine/asset/loaders/GLTFAssetLoader.js +3 -0
- package/engine/asset/loaders/gltf/GLTFAssetTransformMikkTSpaceTangents.js +27 -0
- package/engine/ecs/EntityComponentDataset.js +7 -4
- package/engine/ecs/foliage/InstancedFoliage.js +1 -1
- package/engine/ecs/foliage/ViewState.js +1 -1
- package/engine/ecs/parent/EntityNode.d.ts +7 -3
- package/engine/ecs/parent/EntityNode.js +21 -0
- package/engine/ecs/parent/entity_node_compute_bounding_box.js +41 -0
- package/engine/ecs/transform/Transform.js +2 -2
- package/engine/graphics/ecs/highlight/HighlightDefinition.d.ts +10 -0
- package/engine/graphics/ecs/highlight/HighlightDefinition.js +18 -8
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +5 -0
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +46 -12
- package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +81 -95
- package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +16 -5
- package/engine/graphics/ecs/mesh-v2/render/adapters/InstancedRendererAdapter.js +2 -0
- package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +1 -0
- package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +1 -1
- package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +1 -2
- package/engine/graphics/geometry/MikkT/MikkTSpace.js +2210 -0
- package/engine/graphics/geometry/MikkT/MikkTSpace.spec.js +22 -0
- package/engine/graphics/geometry/MikkT/buffer_geometry_ensure_tangents.js +34 -0
- package/engine/graphics/geometry/MikkT/buffer_geometry_generate_tangents.js +28 -0
- package/engine/graphics/{compute_geometry_polycount.js → geometry/compute_geometry_polycount.js} +0 -0
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +34 -3
- package/engine/graphics/geometry/skining/computeSkinnedMeshBoundingVolumes.js +1 -1
- package/engine/graphics/micron/format/serialization/collection/geometry_collection_serialization.js +83 -0
- package/engine/graphics/micron/format/serialization/collection/geometry_collection_serialization.spec.js +24 -0
- package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +42 -19
- package/engine/graphics/micron/plugin/GLTF_MICRON_ID_FIELD.js +5 -0
- package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -4
- package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +10 -0
- package/engine/graphics/micron/prototypeVirtualGeometry.js +5 -3
- package/engine/graphics/micron/render/refinement/ActivePatchList.js +2 -2
- package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +2 -2
- package/engine/graphics/micron/render/v1/MicronRenderContext.js +0 -6
- package/engine/graphics/render/forward_plus/LightManager.js +3 -1
- package/engine/graphics/util/composeMatrix4.js +1 -53
- package/engine/graphics/util/composeMatrix4RotationScale.js +1 -1
- package/engine/intelligence/blackboard/AbstractBlackboard.js +9 -0
- package/engine/notify/Notification.js +1 -1
- package/engine/ui/DraggableAspect.js +4 -1
- package/engine/ui/notification/ViewEmitter.js +7 -1
- package/engine/ui/notification/notificationGenerator.js +1 -1
- package/engine/ui/scene/SceneGUIContext.js +11 -130
- package/engine/ui/scene/initializeNotifications.js +141 -0
- package/package.json +1 -1
- package/view/elements/notify/NotificationView.js +1 -2
|
@@ -213,6 +213,28 @@ export class ActionProcessor {
|
|
|
213
213
|
|
|
214
214
|
}
|
|
215
215
|
|
|
216
|
+
/**
|
|
217
|
+
*
|
|
218
|
+
* @param {M} descriptor
|
|
219
|
+
* @returns {number[]}
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
__find_mark_indices_by_description(descriptor) {
|
|
223
|
+
const result = [];
|
|
224
|
+
|
|
225
|
+
const marks = this.marks;
|
|
226
|
+
const mark_count = marks.length;
|
|
227
|
+
for (let i = 0; i < mark_count; i++) {
|
|
228
|
+
const mark = marks[i];
|
|
229
|
+
|
|
230
|
+
if (mark.description === descriptor) {
|
|
231
|
+
result.push(i);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
return result;
|
|
236
|
+
}
|
|
237
|
+
|
|
216
238
|
/**
|
|
217
239
|
* Navigate to a specific mark back or forward
|
|
218
240
|
* @param {M} mark_descriptor specific mark description
|
|
@@ -221,7 +243,7 @@ export class ActionProcessor {
|
|
|
221
243
|
*/
|
|
222
244
|
navigateTo(mark_descriptor) {
|
|
223
245
|
// find all matching marks
|
|
224
|
-
const matching_marks = this.
|
|
246
|
+
const matching_marks = this.__find_mark_indices_by_description(mark_descriptor);
|
|
225
247
|
|
|
226
248
|
if (matching_marks.length === 0) {
|
|
227
249
|
// not found
|
|
@@ -232,9 +254,15 @@ export class ActionProcessor {
|
|
|
232
254
|
throw new Error(`Attempting to navigate to a non-unique mark descriptor '${mark_descriptor}'. Mark descriptor must be unique, instead ${matching_marks.length} matches were found`);
|
|
233
255
|
}
|
|
234
256
|
|
|
235
|
-
const
|
|
257
|
+
const match_index = matching_marks[0];
|
|
236
258
|
|
|
237
|
-
|
|
259
|
+
let target;
|
|
260
|
+
if (match_index + 1 >= this.marks.length) {
|
|
261
|
+
// mark is already at the end, go to the end of the history
|
|
262
|
+
target = this.history.length;
|
|
263
|
+
} else {
|
|
264
|
+
target = this.marks[match_index + 1].index;
|
|
265
|
+
}
|
|
238
266
|
|
|
239
267
|
let temp_cursor = this.cursor;
|
|
240
268
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { inverseLerp } from "../../../core/math/inverseLerp.js";
|
|
2
|
+
import { lerp } from "../../../core/math/lerp.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
*
|
|
@@ -32,12 +33,18 @@ function evaluate(t, keyframe0, keyframe1) {
|
|
|
32
33
|
export class AnimationCurve {
|
|
33
34
|
constructor() {
|
|
34
35
|
/**
|
|
35
|
-
*
|
|
36
|
+
* @readonly
|
|
36
37
|
* @type {Keyframe[]}
|
|
37
38
|
*/
|
|
38
39
|
this.keys = [];
|
|
39
40
|
}
|
|
40
41
|
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
*
|
|
45
|
+
* @param {number} t
|
|
46
|
+
* @return {number}
|
|
47
|
+
*/
|
|
41
48
|
evaluate(t) {
|
|
42
49
|
const keys = this.keys;
|
|
43
50
|
const key_count = keys.length;
|
|
@@ -69,4 +76,36 @@ export class AnimationCurve {
|
|
|
69
76
|
return keys[key_count - 1].value;
|
|
70
77
|
}
|
|
71
78
|
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
*
|
|
82
|
+
* @param {number} index
|
|
83
|
+
* @param {number} weight
|
|
84
|
+
*/
|
|
85
|
+
smoothTangents(index, weight) {
|
|
86
|
+
const keys = this.keys;
|
|
87
|
+
|
|
88
|
+
const key_main = keys[index];
|
|
89
|
+
|
|
90
|
+
const has_previous = index > 0;
|
|
91
|
+
if (has_previous) {
|
|
92
|
+
const key_previous = keys[index - 1];
|
|
93
|
+
|
|
94
|
+
key_main.inTangent = key_main.value - key_previous.value;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const has_next = index < keys.length - 1;
|
|
98
|
+
if (has_next) {
|
|
99
|
+
const key_next = keys[index + 1];
|
|
100
|
+
|
|
101
|
+
key_main.outTangent = key_next.value - key_main.value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (has_previous && has_next) {
|
|
105
|
+
const average = lerp(key_main.inTangent, key_main.outTangent, 0.5);
|
|
106
|
+
key_main.inTangent = average;
|
|
107
|
+
key_main.outTangent = average;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
}
|
|
72
111
|
}
|
|
@@ -24,4 +24,23 @@ export class Keyframe {
|
|
|
24
24
|
*/
|
|
25
25
|
this.outTangent = 0;
|
|
26
26
|
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {number} time
|
|
31
|
+
* @param {number} value
|
|
32
|
+
* @param {number} inTangent
|
|
33
|
+
* @param {number} outTangent
|
|
34
|
+
* @return {Keyframe}
|
|
35
|
+
*/
|
|
36
|
+
static from(time, value, inTangent = 0, outTangent = 0) {
|
|
37
|
+
const r = new Keyframe();
|
|
38
|
+
|
|
39
|
+
r.time = time;
|
|
40
|
+
r.value = value;
|
|
41
|
+
r.inTangent = inTangent;
|
|
42
|
+
r.outTangent = outTangent;
|
|
43
|
+
|
|
44
|
+
return r;
|
|
45
|
+
}
|
|
27
46
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Sample entire animation curve into a flat array with discrete equal intervals
|
|
6
|
+
* @param {number[]|Float32Array} out
|
|
7
|
+
* @param {number} out_offset
|
|
8
|
+
* @param {number} sample_count
|
|
9
|
+
* @param {AnimationCurve} curve
|
|
10
|
+
*/
|
|
11
|
+
export function animation_curve_to_float_array(out, curve, out_offset = 0, sample_count = out.length) {
|
|
12
|
+
const keyframes = curve.keys;
|
|
13
|
+
const keyframe_count = keyframes.length;
|
|
14
|
+
|
|
15
|
+
if (keyframe_count === 0) {
|
|
16
|
+
// not data
|
|
17
|
+
out.fill(0, out_offset, out_offset + sample_count);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const key_first = keyframes[0];
|
|
22
|
+
const key_last = keyframes[keyframe_count - 1];
|
|
23
|
+
|
|
24
|
+
const time_start = key_first.time;
|
|
25
|
+
const time_end = key_last.time;
|
|
26
|
+
const time_span = time_end - time_start;
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < sample_count; i++) {
|
|
29
|
+
const f = i / (sample_count - 1);
|
|
30
|
+
|
|
31
|
+
const t = time_start + (f * time_span);
|
|
32
|
+
|
|
33
|
+
out[i + out_offset] = curve.evaluate(t);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import { assert } from "../../../../core/assert.js";
|
|
4
|
+
import { lerp } from "../../../../core/math/lerp.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {number[]|Float32Array} output
|
|
9
|
+
* @param {number} output_offset
|
|
10
|
+
* @param {number[]|Float32Array} input
|
|
11
|
+
* @param {number} input_offset
|
|
12
|
+
* @param {number} input_size
|
|
13
|
+
*/
|
|
14
|
+
export function downsample_float_array(output, output_offset, input, input_offset, input_size) {
|
|
15
|
+
assert.isNonNegativeInteger(output_offset, 'output_offset');
|
|
16
|
+
assert.isNonNegativeInteger(input_offset, 'input_offset');
|
|
17
|
+
assert.isNonNegativeInteger(input_size, 'input_size');
|
|
18
|
+
|
|
19
|
+
const target_samples = input_size / 2;
|
|
20
|
+
|
|
21
|
+
if (!Number.isInteger(target_samples)) {
|
|
22
|
+
throw new Error(`input_size(=${input_size}) is not divisible by 2`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (target_samples === 1) {
|
|
26
|
+
// special case, take average
|
|
27
|
+
output[output_offset] = (
|
|
28
|
+
input[input_offset] + input[input_offset + 1]
|
|
29
|
+
) / 2;
|
|
30
|
+
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let i = 0;
|
|
35
|
+
for (; i < target_samples; i++) {
|
|
36
|
+
|
|
37
|
+
const f = i / (target_samples - 1);
|
|
38
|
+
|
|
39
|
+
const input_sample_offset = input_offset + i * 2;
|
|
40
|
+
|
|
41
|
+
const s0 = input[input_sample_offset];
|
|
42
|
+
const s1 = input[input_sample_offset + 1];
|
|
43
|
+
|
|
44
|
+
const sample_value = lerp(s0, s1, f);
|
|
45
|
+
|
|
46
|
+
// TODO implement decision scheme that would pick between min/max/average
|
|
47
|
+
|
|
48
|
+
output[output_offset + i] = sample_value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import { max2 } from "../../../../core/math/max2.js";
|
|
5
|
+
import { lerp } from "../../../../core/math/lerp.js";
|
|
6
|
+
import { min3 } from "../../../../core/math/min3.js";
|
|
7
|
+
import { max3 } from "../../../../core/math/max3.js";
|
|
8
|
+
import { downsample_float_array } from "./downsample_float_array.js";
|
|
9
|
+
import { array_copy } from "../../../../core/collection/array/copyArray.js";
|
|
10
|
+
import { isPowerOfTwo } from "../../../../core/math/isPowerOrTwo.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {number[]} input
|
|
15
|
+
* @param {number} input_offset
|
|
16
|
+
* @param {number} input_size
|
|
17
|
+
* @param {number} f
|
|
18
|
+
* @return {number}
|
|
19
|
+
*/
|
|
20
|
+
function array_sampler_linear(input, input_offset, input_size, f) {
|
|
21
|
+
const t = f * (input_size - 1);
|
|
22
|
+
|
|
23
|
+
const fraction = t % 1;
|
|
24
|
+
|
|
25
|
+
if (fraction === 0) {
|
|
26
|
+
return input[input_offset + t];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const i0 = Math.floor(t);
|
|
30
|
+
const i1 = i0 + 1;
|
|
31
|
+
|
|
32
|
+
const s0 = input[input_offset + i0];
|
|
33
|
+
const s1 = input[input_offset + i1];
|
|
34
|
+
|
|
35
|
+
return lerp(s0, s1, fraction);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
*
|
|
40
|
+
* @param {number[]|Float32Array} input0
|
|
41
|
+
* @param {number} input0_offset
|
|
42
|
+
* @param {number} input0_size
|
|
43
|
+
* @param {number[]|Float32Array} input1
|
|
44
|
+
* @param {number} input1_offset
|
|
45
|
+
* @param {number} input1_size
|
|
46
|
+
*/
|
|
47
|
+
function compute_float_array_curve_linear_sampling_relative_error(
|
|
48
|
+
input0, input0_offset, input0_size,
|
|
49
|
+
input1, input1_offset, input1_size
|
|
50
|
+
) {
|
|
51
|
+
|
|
52
|
+
const largest_size = max2(input0_size, input1_size);
|
|
53
|
+
|
|
54
|
+
let max_error = 0;
|
|
55
|
+
|
|
56
|
+
let min = Number.POSITIVE_INFINITY;
|
|
57
|
+
let max = Number.NEGATIVE_INFINITY;
|
|
58
|
+
|
|
59
|
+
for (let i = 0; i < largest_size; i++) {
|
|
60
|
+
const f = i / (largest_size - 1);
|
|
61
|
+
|
|
62
|
+
const s0 = array_sampler_linear(input0, input0_offset, input0_size, f);
|
|
63
|
+
const s1 = array_sampler_linear(input1, input1_offset, input1_size, f);
|
|
64
|
+
|
|
65
|
+
const error = Math.abs(s0 - s1);
|
|
66
|
+
|
|
67
|
+
if (error > max_error) {
|
|
68
|
+
max_error = error;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
min = min3(min, s0, s1);
|
|
72
|
+
max = max3(max, s0, s1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const span = max - min;
|
|
76
|
+
|
|
77
|
+
if (span === 0) {
|
|
78
|
+
// avoid division by 0
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return max_error / span;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
*
|
|
87
|
+
* @param {number[]} output
|
|
88
|
+
* @param {number} output_offset
|
|
89
|
+
* @param {number[]} input
|
|
90
|
+
* @param {number} input_offset
|
|
91
|
+
* @param {number} input_size
|
|
92
|
+
* @param {number} [error]
|
|
93
|
+
* @return {number}
|
|
94
|
+
*/
|
|
95
|
+
export function downsample_float_array_curve_by_error(output, output_offset, input, input_offset, input_size, error = 0.03) {
|
|
96
|
+
if (!isPowerOfTwo(input_size)) {
|
|
97
|
+
throw new Error(`Input size must be a power of two, instead was '${input_size}'`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const buffer_0 = new Float32Array(input_size >>> 1); // first step needs half the size of the original buffer
|
|
101
|
+
const buffer_1 = new Float32Array(input_size >>> 2); // next step needs quarter
|
|
102
|
+
|
|
103
|
+
let current = input;
|
|
104
|
+
let current_offset = input_offset;
|
|
105
|
+
let current_size = input_size;
|
|
106
|
+
|
|
107
|
+
let next = buffer_0;
|
|
108
|
+
let next_offset = 0;
|
|
109
|
+
let next_size = buffer_0.length;
|
|
110
|
+
|
|
111
|
+
let current_error = 0;
|
|
112
|
+
|
|
113
|
+
while (current_error <= error && current_size > 1) {
|
|
114
|
+
downsample_float_array(next, next_offset, current, current_offset, current_size);
|
|
115
|
+
|
|
116
|
+
current_error = compute_float_array_curve_linear_sampling_relative_error(
|
|
117
|
+
input, input_offset, input_size,
|
|
118
|
+
next, next_offset, next_size
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (current_error > error) {
|
|
122
|
+
// reached best possible reduction
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
current = next;
|
|
127
|
+
current_offset = next_offset;
|
|
128
|
+
current_size = next_size;
|
|
129
|
+
|
|
130
|
+
// perform swap
|
|
131
|
+
if (next === buffer_0) {
|
|
132
|
+
next = buffer_1;
|
|
133
|
+
} else {
|
|
134
|
+
next = buffer_0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
next_offset = 0;
|
|
138
|
+
// next will be half the current size
|
|
139
|
+
next_size = current_size >>> 1;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
// copy current buffer to output
|
|
144
|
+
array_copy(current, current_offset, output, output_offset, current_size);
|
|
145
|
+
|
|
146
|
+
return current_size;
|
|
147
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { downsample_float_array_curve_by_error } from "./downsample_float_array_curve_by_error.js";
|
|
2
|
+
|
|
3
|
+
test('1 constant to 1', () => {
|
|
4
|
+
const output = [];
|
|
5
|
+
|
|
6
|
+
const sample_count = downsample_float_array_curve_by_error(output, 0, [1], 0, 1, 0.1);
|
|
7
|
+
|
|
8
|
+
expect(sample_count).toBe(1);
|
|
9
|
+
expect(output[0]).toBe(1);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test('4 constants to 1', () => {
|
|
13
|
+
const output = [];
|
|
14
|
+
|
|
15
|
+
const sample_count = downsample_float_array_curve_by_error(output, 0, [1, 1, 1, 1], 0, 4, 0.1);
|
|
16
|
+
|
|
17
|
+
expect(sample_count).toBe(1);
|
|
18
|
+
expect(output[0]).toBe(1);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('2 constants to 1 with error = 0', () => {
|
|
22
|
+
const output = [];
|
|
23
|
+
|
|
24
|
+
const sample_count = downsample_float_array_curve_by_error(output, 0, [1, 1], 0, 2, 0);
|
|
25
|
+
|
|
26
|
+
expect(sample_count).toBe(1);
|
|
27
|
+
expect(output[0]).toBe(1);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test('2 different constants to 2', () => {
|
|
31
|
+
const output = [];
|
|
32
|
+
|
|
33
|
+
const sample_count = downsample_float_array_curve_by_error(output, 0, [1, 2], 0, 2, 0.1);
|
|
34
|
+
|
|
35
|
+
expect(sample_count).toBe(2);
|
|
36
|
+
expect(output).toEqual([1, 2]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('4 to 2, linear scale compression', () => {
|
|
40
|
+
const output = [];
|
|
41
|
+
|
|
42
|
+
const sample_count = downsample_float_array_curve_by_error(output, 0, [1, 2, 3, 4], 0, 4, 0.1);
|
|
43
|
+
|
|
44
|
+
expect(sample_count).toBe(2);
|
|
45
|
+
expect(output[0]).toBeCloseTo(1);
|
|
46
|
+
expect(output[1]).toBeCloseTo(4);
|
|
47
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { EngineHarness } from "../../../EngineHarness.js";
|
|
2
|
+
import { AnimationCurve } from "../AnimationCurve.js";
|
|
3
|
+
import { Keyframe } from "../Keyframe.js";
|
|
4
|
+
import { EngineConfiguration } from "../../../EngineConfiguration.js";
|
|
5
|
+
import GUIElementSystem from "../../../ecs/gui/GUIElementSystem.js";
|
|
6
|
+
import ViewportPositionSystem from "../../../ecs/gui/position/ViewportPositionSystem.js";
|
|
7
|
+
import { animation_curve_to_float_array } from "./animation_curve_to_float_array.js";
|
|
8
|
+
import { downsample_float_array_curve_by_error } from "./downsample_float_array_curve_by_error.js";
|
|
9
|
+
import { build_plot_entity_from_array } from "../draw/build_plot_entity_from_array.js";
|
|
10
|
+
|
|
11
|
+
const eh = new EngineHarness();
|
|
12
|
+
|
|
13
|
+
async function init() {
|
|
14
|
+
|
|
15
|
+
const config = new EngineConfiguration();
|
|
16
|
+
|
|
17
|
+
const engine = eh.engine;
|
|
18
|
+
|
|
19
|
+
config.addSystem(new GUIElementSystem(engine.gameView, engine));
|
|
20
|
+
config.addSystem(new ViewportPositionSystem(engine.gameView.size));
|
|
21
|
+
|
|
22
|
+
await config.apply(engine);
|
|
23
|
+
|
|
24
|
+
await eh.initialize();
|
|
25
|
+
|
|
26
|
+
main(engine);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function build_error_scale(ecd, curve) {
|
|
30
|
+
const curve_data = [];
|
|
31
|
+
animation_curve_to_float_array(curve_data, curve, 0, 256);
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
build_plot_entity_from_array({
|
|
35
|
+
data: curve_data,
|
|
36
|
+
x: 10, y: 0
|
|
37
|
+
}).build(ecd);
|
|
38
|
+
|
|
39
|
+
const compressed_01 = [];
|
|
40
|
+
downsample_float_array_curve_by_error(compressed_01, 0, curve_data, 0, curve_data.length, 0.01);
|
|
41
|
+
|
|
42
|
+
build_plot_entity_from_array({
|
|
43
|
+
data: compressed_01,
|
|
44
|
+
x: 10, y: 202,
|
|
45
|
+
label: '1%'
|
|
46
|
+
}).build(ecd);
|
|
47
|
+
|
|
48
|
+
const compressed_03 = [];
|
|
49
|
+
downsample_float_array_curve_by_error(compressed_03, 0, curve_data, 0, curve_data.length, 0.03);
|
|
50
|
+
|
|
51
|
+
build_plot_entity_from_array({
|
|
52
|
+
data: compressed_03,
|
|
53
|
+
x: 10, y: 404,
|
|
54
|
+
label: '3%'
|
|
55
|
+
}).build(ecd);
|
|
56
|
+
|
|
57
|
+
const compressed_05 = [];
|
|
58
|
+
downsample_float_array_curve_by_error(compressed_05, 0, curve_data, 0, curve_data.length, 0.05);
|
|
59
|
+
|
|
60
|
+
build_plot_entity_from_array({
|
|
61
|
+
data: compressed_05,
|
|
62
|
+
x: 10, y: 606,
|
|
63
|
+
label: '5%'
|
|
64
|
+
}).build(ecd);
|
|
65
|
+
|
|
66
|
+
const compressed_10 = [];
|
|
67
|
+
downsample_float_array_curve_by_error(compressed_10, 0, curve_data, 0, curve_data.length, 0.10);
|
|
68
|
+
|
|
69
|
+
build_plot_entity_from_array({
|
|
70
|
+
data: compressed_10,
|
|
71
|
+
x: 10, y: 808,
|
|
72
|
+
label: '10%'
|
|
73
|
+
}).build(ecd);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async function main(engine) {
|
|
77
|
+
|
|
78
|
+
// EngineHarness.buildBasics({ engine });
|
|
79
|
+
function sample_curve_0() {
|
|
80
|
+
|
|
81
|
+
const curve = new AnimationCurve();
|
|
82
|
+
|
|
83
|
+
curve.keys.push(Keyframe.from(0, 0));
|
|
84
|
+
curve.keys.push(Keyframe.from(1, 1));
|
|
85
|
+
curve.keys.push(Keyframe.from(2, 0.5));
|
|
86
|
+
|
|
87
|
+
return curve;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function sample_curve_1() {
|
|
91
|
+
|
|
92
|
+
const curve = new AnimationCurve();
|
|
93
|
+
|
|
94
|
+
curve.keys.push(Keyframe.from(0, 0));
|
|
95
|
+
curve.keys.push(Keyframe.from(0.1, 1));
|
|
96
|
+
curve.keys.push(Keyframe.from(2, 0.5));
|
|
97
|
+
|
|
98
|
+
return curve;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function sample_curve_2() {
|
|
102
|
+
|
|
103
|
+
const curve = new AnimationCurve();
|
|
104
|
+
|
|
105
|
+
curve.keys.push(Keyframe.from(0, 1));
|
|
106
|
+
curve.keys.push(Keyframe.from(1, 2));
|
|
107
|
+
curve.keys.push(Keyframe.from(2, 3));
|
|
108
|
+
curve.keys.push(Keyframe.from(3, 4));
|
|
109
|
+
|
|
110
|
+
return curve;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function sample_curve_3() {
|
|
114
|
+
|
|
115
|
+
const curve = new AnimationCurve();
|
|
116
|
+
|
|
117
|
+
curve.keys.push(Keyframe.from(0, 1));
|
|
118
|
+
curve.keys.push(Keyframe.from(1, 1));
|
|
119
|
+
curve.keys.push(Keyframe.from(2, 1));
|
|
120
|
+
curve.keys.push(Keyframe.from(3, 1));
|
|
121
|
+
|
|
122
|
+
return curve;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function sample_curve_4() {
|
|
126
|
+
|
|
127
|
+
const curve = new AnimationCurve();
|
|
128
|
+
|
|
129
|
+
curve.keys.push(Keyframe.from(0, 1, 0, 1));
|
|
130
|
+
// curve.keys.push(Keyframe.from(1, 2, 1, -1));
|
|
131
|
+
curve.keys.push(Keyframe.from(1, 2, -1, 1));
|
|
132
|
+
curve.keys.push(Keyframe.from(2, 1));
|
|
133
|
+
|
|
134
|
+
return curve;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const curve = sample_curve_2();
|
|
138
|
+
|
|
139
|
+
const ecd = engine.entityManager.dataset;
|
|
140
|
+
|
|
141
|
+
build_error_scale(ecd, curve);
|
|
142
|
+
|
|
143
|
+
// const editor_view = build_curve_editor({ curve });
|
|
144
|
+
//
|
|
145
|
+
// new EntityBuilder()
|
|
146
|
+
// .add(ViewportPosition.fromJSON({
|
|
147
|
+
// offset: { x: 0, y: 0 }
|
|
148
|
+
// }))
|
|
149
|
+
// .add(GUIElement.fromView(editor_view))
|
|
150
|
+
// .build(ecd);
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
init();
|