@woosh/meep-engine 2.75.3 → 2.75.5
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/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +35 -21
- package/package.json +2 -2
- package/src/core/collection/array/array_compute_min_max.js +20 -0
- package/src/core/collection/map/HashMap.js +16 -14
- package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +23 -13
- package/src/core/geom/2d/intersect_ray_2d.js +7 -14
- package/src/core/geom/3d/aabb/AABB3.js +13 -0
- package/src/core/geom/3d/topology/samples/sampleFloodFill.js +21 -21
- package/src/core/geom/3d/topology/tm_face_area.js +1 -1
- package/src/core/geom/3d/triangle/computeTriangleSurfaceArea.js +39 -0
- package/src/core/process/task/util/countTask.js +1 -2
- package/src/engine/EngineBootstrapper.js +15 -7
- package/src/engine/animation/curve/AnimationCurve.js +50 -31
- package/src/engine/animation/curve/AnimationCurve.spec.js +9 -1
- package/src/engine/animation/curve/compression/prototypeCurveCompression.js +20 -11
- package/src/engine/animation/curve/compute_curve_aabb.js +26 -0
- package/src/engine/animation/curve/draw/build_curve_editor.js +82 -42
- package/src/engine/animation/curve/draw/build_plot_entity_from_array.js +5 -5
- package/src/engine/animation/curve/preset/CURVE_EASE_IN.js +8 -0
- package/src/engine/animation/curve/preset/CURVE_EASE_IN_OUT.js +7 -0
- package/src/engine/animation/curve/preset/CURVE_EASE_OUT.js +7 -0
- package/src/engine/asset/loaders/image/png/PNGReader.js +119 -1
- package/src/engine/graphics/GraphicsEngine.d.ts +6 -3
- package/src/engine/graphics/canvas/canvas2d_draw_grid.js +42 -0
- package/src/engine/{animation/curve/draw/draw_label.js → graphics/canvas/canvas2d_draw_label.js} +6 -1
- package/src/engine/graphics/canvas/canvas2d_draw_linear_scale.js +64 -0
- package/src/engine/graphics/canvas/canvas2d_draw_path.js +60 -0
- package/src/engine/graphics/canvas/canvas2d_plot_data_line.js +84 -0
- package/src/engine/{animation/curve/draw/plot_array.js → graphics/canvas/canvas2d_plot_line_array.js} +8 -25
- package/src/engine/graphics/geometry/VertexDataSpec.d.ts +10 -0
- package/src/engine/graphics/geometry/VertexDataSpec.js +20 -21
- package/src/engine/graphics/geometry/computeMeshSurfaceArea.js +2 -37
- package/src/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +8 -26
- package/src/engine/graphics/material/manager/MaterialManager.d.ts +6 -0
- package/src/engine/graphics/sh3/LightProbeVolume.js +38 -17
- package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +26 -35
- package/src/engine/graphics/sh3/prototypeSH3Probe.js +166 -100
- package/src/engine/graphics/texture/makeOnePixelTexture.js +19 -0
- package/src/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +5 -68
- package/src/engine/graphics/texture/virtual/v2/VirtualTexturePage.js +1 -1
- package/src/engine/input/devices/PointerDevice.js +6 -3
- package/src/engine/makeSimpleTaskProgressView.js +33 -0
- package/src/engine/scene/transitionToScene.js +9 -10
- package/src/view/task/TaskLoadingScreen.js +5 -12
- package/src/view/task/TaskProgressView.js +9 -9
- package/src/engine/animation/curve/draw/draw_grid.js +0 -27
- package/src/engine/animation/curve/draw/plot_data.js +0 -49
- package/src/engine/graphics/geometry/QuadGeometry.js +0 -13
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { binarySearchHighIndex } from "../../../core/collection/array/binarySearchHighIndex.js";
|
|
1
2
|
import { inverseLerp } from "../../../core/math/inverseLerp.js";
|
|
2
3
|
import { lerp } from "../../../core/math/lerp.js";
|
|
3
4
|
import { invokeObjectToJSON } from "../../../core/model/object/invokeObjectToJSON.js";
|
|
4
5
|
import { Keyframe } from "./Keyframe.js";
|
|
5
|
-
import { binarySearchHighIndex } from "../../../core/collection/array/binarySearchHighIndex.js";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
*
|
|
@@ -44,22 +44,22 @@ function compareKeyframeToTime(time, keyframe) {
|
|
|
44
44
|
* @see https://github.com/nothke/ThreadableCurve/blob/master/ThreadableCurve.cs
|
|
45
45
|
*/
|
|
46
46
|
export class AnimationCurve {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.keys = [];
|
|
53
|
-
}
|
|
47
|
+
/**
|
|
48
|
+
* @readonly
|
|
49
|
+
* @type {Keyframe[]}
|
|
50
|
+
*/
|
|
51
|
+
keys = [];
|
|
54
52
|
|
|
55
53
|
/**
|
|
56
54
|
*
|
|
57
55
|
* @param {Keyframe} key
|
|
56
|
+
* @returns {number} key index
|
|
58
57
|
*/
|
|
59
58
|
add(key) {
|
|
60
59
|
const keys = this.keys;
|
|
61
60
|
|
|
62
|
-
const
|
|
61
|
+
const key_count = keys.length;
|
|
62
|
+
const last_key_index = key_count - 1;
|
|
63
63
|
|
|
64
64
|
if (
|
|
65
65
|
last_key_index < 0
|
|
@@ -69,6 +69,8 @@ export class AnimationCurve {
|
|
|
69
69
|
// inserted key goes at the end
|
|
70
70
|
keys.push(key);
|
|
71
71
|
|
|
72
|
+
return key_count;
|
|
73
|
+
|
|
72
74
|
} else {
|
|
73
75
|
|
|
74
76
|
// figure out the right place to insert the key
|
|
@@ -76,6 +78,20 @@ export class AnimationCurve {
|
|
|
76
78
|
|
|
77
79
|
// insert key at the right place
|
|
78
80
|
keys.splice(i, 0, key);
|
|
81
|
+
|
|
82
|
+
return i;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @param {Keyframe[]} keys
|
|
89
|
+
*/
|
|
90
|
+
addMany(keys) {
|
|
91
|
+
const key_count = keys.length;
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < key_count; i++) {
|
|
94
|
+
this.add(keys[i]);
|
|
79
95
|
}
|
|
80
96
|
}
|
|
81
97
|
|
|
@@ -111,15 +127,9 @@ export class AnimationCurve {
|
|
|
111
127
|
static from(keys) {
|
|
112
128
|
const curve = new AnimationCurve();
|
|
113
129
|
|
|
114
|
-
|
|
130
|
+
curve.addMany(keys);
|
|
115
131
|
|
|
116
|
-
|
|
117
|
-
curve.add(keys[i]);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
for (let i = 0; i < key_count; i++) {
|
|
121
|
-
curve.smoothTangents(i, 1);
|
|
122
|
-
}
|
|
132
|
+
curve.smoothAllTangents();
|
|
123
133
|
|
|
124
134
|
return curve;
|
|
125
135
|
}
|
|
@@ -149,7 +159,7 @@ export class AnimationCurve {
|
|
|
149
159
|
return keys[0].value;
|
|
150
160
|
}
|
|
151
161
|
|
|
152
|
-
if (t
|
|
162
|
+
if (t <= keys[0].time) {
|
|
153
163
|
// before start
|
|
154
164
|
return keys[0].value;
|
|
155
165
|
}
|
|
@@ -169,13 +179,11 @@ export class AnimationCurve {
|
|
|
169
179
|
return keys[key_count - 1].value;
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
|
|
173
182
|
/**
|
|
174
|
-
*
|
|
175
|
-
* @param {number} index
|
|
176
|
-
* @param {number} weight value between 0 and 1
|
|
183
|
+
* Set tangents of a key to match surrounding keys
|
|
184
|
+
* @param {number} index index of keyframe
|
|
177
185
|
*/
|
|
178
|
-
|
|
186
|
+
alignTangents(index) {
|
|
179
187
|
const keys = this.keys;
|
|
180
188
|
|
|
181
189
|
const key_main = keys[index];
|
|
@@ -193,19 +201,28 @@ export class AnimationCurve {
|
|
|
193
201
|
|
|
194
202
|
key_main.outTangent = key_next.value - key_main.value;
|
|
195
203
|
}
|
|
204
|
+
}
|
|
196
205
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
206
|
+
/**
|
|
207
|
+
*
|
|
208
|
+
* @param {number} index Index of keyframe to be affected
|
|
209
|
+
* @param {number} weight How much smoothing to apply, 1 will be fully smoothed out and 0 will have no effect at all. Value between 0 and 1
|
|
210
|
+
*/
|
|
211
|
+
smoothTangents(index, weight) {
|
|
212
|
+
const keys = this.keys;
|
|
213
|
+
|
|
214
|
+
const key = keys[index];
|
|
202
215
|
|
|
216
|
+
const average = lerp(key.inTangent, key.outTangent, 0.5);
|
|
217
|
+
|
|
218
|
+
key.inTangent = lerp(key.inTangent, average, weight);
|
|
219
|
+
key.outTangent = lerp(key.outTangent, average, weight);
|
|
203
220
|
}
|
|
204
221
|
|
|
205
222
|
smoothAllTangents() {
|
|
206
223
|
const n = this.length;
|
|
207
224
|
for (let i = 0; i < n; i++) {
|
|
208
|
-
this.smoothTangents(i,
|
|
225
|
+
this.smoothTangents(i, 1);
|
|
209
226
|
}
|
|
210
227
|
}
|
|
211
228
|
|
|
@@ -215,10 +232,12 @@ export class AnimationCurve {
|
|
|
215
232
|
};
|
|
216
233
|
}
|
|
217
234
|
|
|
218
|
-
fromJSON({ keys }) {
|
|
235
|
+
fromJSON({ keys = [] }) {
|
|
219
236
|
this.clear();
|
|
220
237
|
|
|
221
|
-
|
|
238
|
+
const key_count = keys.length;
|
|
239
|
+
|
|
240
|
+
for (let i = 0; i < key_count; i++) {
|
|
222
241
|
|
|
223
242
|
const keyframe = new Keyframe();
|
|
224
243
|
|
|
@@ -52,13 +52,21 @@ test("evaluate on empty curve", () => {
|
|
|
52
52
|
expect(curve.evaluate(0)).toBe(0);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
test("evaluate before first frame", () => {
|
|
55
|
+
test("evaluate before first frame, 1 frame curve", () => {
|
|
56
56
|
const curve = new AnimationCurve();
|
|
57
57
|
|
|
58
58
|
curve.add(Keyframe.from(1, 7));
|
|
59
59
|
|
|
60
60
|
expect(curve.evaluate(0.9)).toEqual(7);
|
|
61
61
|
});
|
|
62
|
+
test("evaluate before first frame, 2 frame curve", () => {
|
|
63
|
+
const curve = new AnimationCurve();
|
|
64
|
+
|
|
65
|
+
curve.add(Keyframe.from(1, 7));
|
|
66
|
+
curve.add(Keyframe.from(2, 10));
|
|
67
|
+
|
|
68
|
+
expect(curve.evaluate(0.9)).toEqual(7);
|
|
69
|
+
});
|
|
62
70
|
|
|
63
71
|
test("sample linear curve with 2 points", () => {
|
|
64
72
|
const curve = new AnimationCurve();
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import Entity from "../../../ecs/Entity.js";
|
|
2
|
+
import GUIElement from "../../../ecs/gui/GUIElement.js";
|
|
1
3
|
import GUIElementSystem from "../../../ecs/gui/GUIElementSystem.js";
|
|
4
|
+
import ViewportPosition from "../../../ecs/gui/position/ViewportPosition.js";
|
|
2
5
|
import ViewportPositionSystem from "../../../ecs/gui/position/ViewportPositionSystem.js";
|
|
3
6
|
import { EngineConfiguration } from "../../../EngineConfiguration.js";
|
|
4
7
|
import { EngineHarness } from "../../../EngineHarness.js";
|
|
5
8
|
import { AnimationCurve } from "../AnimationCurve.js";
|
|
9
|
+
import { build_curve_editor } from "../draw/build_curve_editor.js";
|
|
6
10
|
import { build_plot_entity_from_array } from "../draw/build_plot_entity_from_array.js";
|
|
7
11
|
import { Keyframe } from "../Keyframe.js";
|
|
12
|
+
import { CURVE_EASE_OUT } from "../preset/CURVE_EASE_OUT.js";
|
|
8
13
|
import { downsample_float_array_curve_by_error } from "./downsample_float_array_curve_by_error.js";
|
|
9
14
|
import { sample_animation_curve_to_float_array } from "./sample_animation_curve_to_float_array.js";
|
|
10
15
|
|
|
@@ -134,22 +139,26 @@ async function main(engine) {
|
|
|
134
139
|
return curve;
|
|
135
140
|
}
|
|
136
141
|
|
|
137
|
-
const curve = sample_curve_0();
|
|
142
|
+
// const curve = sample_curve_0();
|
|
138
143
|
|
|
139
|
-
curve.smoothAllTangents();
|
|
144
|
+
// curve.smoothAllTangents();
|
|
145
|
+
|
|
146
|
+
const curve = CURVE_EASE_OUT;
|
|
140
147
|
|
|
141
148
|
const ecd = engine.entityManager.dataset;
|
|
142
149
|
|
|
143
|
-
build_error_scale(ecd, curve);
|
|
150
|
+
// build_error_scale(ecd, curve);
|
|
151
|
+
|
|
152
|
+
console.log(curve);
|
|
153
|
+
|
|
154
|
+
const editor_view = build_curve_editor({ curve });
|
|
144
155
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
// .add(GUIElement.fromView(editor_view))
|
|
152
|
-
// .build(ecd);
|
|
156
|
+
new Entity()
|
|
157
|
+
.add(ViewportPosition.fromJSON({
|
|
158
|
+
offset: { x: 0, y: 0 }
|
|
159
|
+
}))
|
|
160
|
+
.add(GUIElement.fromView(editor_view))
|
|
161
|
+
.build(ecd);
|
|
153
162
|
|
|
154
163
|
}
|
|
155
164
|
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { max2 } from "../../../core/math/max2.js";
|
|
2
|
+
import { min2 } from "../../../core/math/min2.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {AABB2} out
|
|
7
|
+
* @param {AnimationCurve} curve
|
|
8
|
+
*/
|
|
9
|
+
export function compute_curve_aabb(out, curve) {
|
|
10
|
+
let x0 = Number.POSITIVE_INFINITY;
|
|
11
|
+
let x1 = Number.NEGATIVE_INFINITY;
|
|
12
|
+
let y0 = Number.POSITIVE_INFINITY;
|
|
13
|
+
let y1 = Number.NEGATIVE_INFINITY;
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < curve.keys.length; i++) {
|
|
16
|
+
const keyframe = curve.keys[i];
|
|
17
|
+
|
|
18
|
+
x0 = min2(x0, keyframe.time)
|
|
19
|
+
x1 = max2(x1, keyframe.time)
|
|
20
|
+
|
|
21
|
+
y0 = min2(y0, keyframe.value);
|
|
22
|
+
y1 = max2(y1, keyframe.value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
out.set(x0, y0, x1, y1);
|
|
26
|
+
}
|
|
@@ -1,38 +1,19 @@
|
|
|
1
|
-
import Vector2 from "../../../../core/geom/Vector2.js";
|
|
2
|
-
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
3
|
-
import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
4
|
-
import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
|
|
5
1
|
import Signal from "../../../../core/events/signal/Signal.js";
|
|
2
|
+
import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
|
|
3
|
+
import Vector2 from "../../../../core/geom/Vector2.js";
|
|
6
4
|
import ObservedValue from "../../../../core/model/ObservedValue.js";
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
5
|
+
import { number_pretty_print } from "../../../../core/primitives/numbers/number_pretty_print.js";
|
|
6
|
+
import LabelView from "../../../../view/common/LabelView.js";
|
|
7
|
+
import { CSS_ABSOLUTE_POSITIONING } from "../../../../view/CSS_ABSOLUTE_POSITIONING.js";
|
|
8
|
+
import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
9
|
+
import EmptyView from "../../../../view/elements/EmptyView.js";
|
|
10
|
+
import { canvas2d_plot_data_line } from "../../../graphics/canvas/canvas2d_plot_data_line.js";
|
|
11
|
+
import { MouseEvents } from "../../../input/devices/events/MouseEvents.js";
|
|
12
|
+
import { readPositionFromMouseEvent } from "../../../input/devices/PointerDevice.js";
|
|
9
13
|
import { DraggableAspect } from "../../../ui/DraggableAspect.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
*
|
|
15
|
-
* @param {AABB2} out
|
|
16
|
-
* @param {AnimationCurve} curve
|
|
17
|
-
*/
|
|
18
|
-
function compute_curve_aabb(out, curve) {
|
|
19
|
-
let x0 = Number.POSITIVE_INFINITY;
|
|
20
|
-
let x1 = Number.NEGATIVE_INFINITY;
|
|
21
|
-
let y0 = Number.POSITIVE_INFINITY;
|
|
22
|
-
let y1 = Number.NEGATIVE_INFINITY;
|
|
23
|
-
|
|
24
|
-
for (let i = 0; i < curve.keys.length; i++) {
|
|
25
|
-
const keyframe = curve.keys[i];
|
|
26
|
-
|
|
27
|
-
x0 = min2(x0, keyframe.time)
|
|
28
|
-
x1 = max2(x1, keyframe.time)
|
|
29
|
-
|
|
30
|
-
y0 = min2(y0, keyframe.value);
|
|
31
|
-
y1 = max2(y1, keyframe.value);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
out.set(x0, y0, x1, y1);
|
|
35
|
-
}
|
|
14
|
+
import { sample_animation_curve_to_float_array } from "../compression/sample_animation_curve_to_float_array.js";
|
|
15
|
+
import { compute_curve_aabb } from "../compute_curve_aabb.js";
|
|
16
|
+
import { Keyframe } from "../Keyframe.js";
|
|
36
17
|
|
|
37
18
|
/**
|
|
38
19
|
*
|
|
@@ -85,16 +66,20 @@ function position_canvas_to_curve(size, frame, margin, x, y) {
|
|
|
85
66
|
*
|
|
86
67
|
* @param {AnimationCurve} curve
|
|
87
68
|
* @param {Vector2} [size]
|
|
88
|
-
* @param {Vector2} [margin]
|
|
69
|
+
* @param {Vector2} [margin] How much space to leave empty around the plotted bounds
|
|
89
70
|
* @returns {View}
|
|
90
71
|
*/
|
|
91
72
|
export function build_curve_editor({
|
|
92
73
|
curve,
|
|
93
|
-
size = new Vector2(
|
|
94
|
-
margin = new Vector2(
|
|
74
|
+
size = new Vector2(300, 300),
|
|
75
|
+
margin = new Vector2(36, 36)
|
|
95
76
|
}) {
|
|
96
77
|
|
|
97
|
-
const vContainer = new EmptyView(
|
|
78
|
+
const vContainer = new EmptyView({
|
|
79
|
+
css: {
|
|
80
|
+
pointerEvents: "auto"
|
|
81
|
+
}
|
|
82
|
+
});
|
|
98
83
|
|
|
99
84
|
const graph = new CanvasView();
|
|
100
85
|
graph.size.copy(size);
|
|
@@ -109,6 +94,16 @@ export function build_curve_editor({
|
|
|
109
94
|
*/
|
|
110
95
|
const active_keyframe = new ObservedValue(null);
|
|
111
96
|
|
|
97
|
+
const vCoordinate = new LabelView("", {
|
|
98
|
+
css: {
|
|
99
|
+
...CSS_ABSOLUTE_POSITIONING,
|
|
100
|
+
zIndex: 1000,
|
|
101
|
+
background: `rgba(0, 0, 0, 0.4)`,
|
|
102
|
+
padding: '4px 6px',
|
|
103
|
+
color: 'white',
|
|
104
|
+
font: '12px Tahoma, monospaced'
|
|
105
|
+
}
|
|
106
|
+
});
|
|
112
107
|
|
|
113
108
|
function handle_curve_update() {
|
|
114
109
|
compute_curve_aabb(frame, curve);
|
|
@@ -125,13 +120,14 @@ export function build_curve_editor({
|
|
|
125
120
|
|
|
126
121
|
sample_animation_curve_to_float_array(data, 0, curve, data.length);
|
|
127
122
|
|
|
128
|
-
|
|
123
|
+
canvas2d_plot_data_line({
|
|
129
124
|
data,
|
|
130
125
|
ctx: graph.context2d,
|
|
131
126
|
width: width,
|
|
132
127
|
height: graph.size.y,
|
|
133
128
|
margin: margin,
|
|
134
|
-
range_y: [frame.y0, frame.y1]
|
|
129
|
+
range_y: [frame.y0, frame.y1],
|
|
130
|
+
range_x: [frame.x0, frame.x1],
|
|
135
131
|
});
|
|
136
132
|
}
|
|
137
133
|
|
|
@@ -218,11 +214,17 @@ export function build_curve_editor({
|
|
|
218
214
|
position.y
|
|
219
215
|
);
|
|
220
216
|
|
|
221
|
-
console.log(keyframe_coord);
|
|
217
|
+
// console.log(keyframe_coord);
|
|
222
218
|
|
|
223
219
|
keyframe.time = keyframe_coord.x;
|
|
224
220
|
keyframe.value = keyframe_coord.y;
|
|
225
221
|
|
|
222
|
+
vCoordinate.updateText(`${number_pretty_print(keyframe_coord.x)}, ${number_pretty_print(keyframe_coord.y)}`);
|
|
223
|
+
vCoordinate.position.set(
|
|
224
|
+
position.x,
|
|
225
|
+
position.y - 24
|
|
226
|
+
);
|
|
227
|
+
|
|
226
228
|
let keyframe_index = curve.keys.indexOf(keyframe);
|
|
227
229
|
|
|
228
230
|
if (keyframe_index < (curve.keys.length - 1) && keyframe.time > curve.keys[keyframe_index + 1].time) {
|
|
@@ -243,12 +245,15 @@ export function build_curve_editor({
|
|
|
243
245
|
keyframe_index = prev_index;
|
|
244
246
|
}
|
|
245
247
|
|
|
248
|
+
curve.alignTangents(keyframe_index);
|
|
246
249
|
curve.smoothTangents(keyframe_index, 1);
|
|
247
250
|
|
|
248
251
|
if (keyframe_index > 0) {
|
|
252
|
+
curve.alignTangents(keyframe_index - 1);
|
|
249
253
|
curve.smoothTangents(keyframe_index - 1, 1);
|
|
250
254
|
}
|
|
251
255
|
if (keyframe_index < curve.keys.length - 1) {
|
|
256
|
+
curve.alignTangents(keyframe_index + 1);
|
|
252
257
|
curve.smoothTangents(keyframe_index + 1, 1);
|
|
253
258
|
}
|
|
254
259
|
|
|
@@ -261,15 +266,33 @@ export function build_curve_editor({
|
|
|
261
266
|
previous.copy(position);
|
|
262
267
|
|
|
263
268
|
active_keyframe.set(keyframe);
|
|
269
|
+
|
|
270
|
+
vContainer.addChild(vCoordinate);
|
|
264
271
|
},
|
|
265
272
|
dragEnd() {
|
|
266
273
|
handle_curve_update();
|
|
274
|
+
|
|
275
|
+
vContainer.removeChild(vCoordinate);
|
|
267
276
|
}
|
|
268
277
|
});
|
|
269
278
|
|
|
270
|
-
draggable.getPointer().on.tap.add(
|
|
271
|
-
|
|
272
|
-
|
|
279
|
+
draggable.getPointer().on.tap.add(
|
|
280
|
+
/**
|
|
281
|
+
*
|
|
282
|
+
* @param position
|
|
283
|
+
* @param {MouseEvent} event
|
|
284
|
+
*/
|
|
285
|
+
(position, event) => {
|
|
286
|
+
// make active
|
|
287
|
+
active_keyframe.set(keyframe);
|
|
288
|
+
|
|
289
|
+
if (event.ctrlKey) {
|
|
290
|
+
// remove
|
|
291
|
+
curve.remove(keyframe);
|
|
292
|
+
remove_keyframe(keyframe);
|
|
293
|
+
update_graph();
|
|
294
|
+
}
|
|
295
|
+
});
|
|
273
296
|
|
|
274
297
|
marker.on.linked.add(draggable.start, draggable);
|
|
275
298
|
marker.on.unlinked.add(draggable.stop, draggable);
|
|
@@ -307,6 +330,23 @@ export function build_curve_editor({
|
|
|
307
330
|
curve.keys.forEach(remove_keyframe);
|
|
308
331
|
});
|
|
309
332
|
|
|
333
|
+
vContainer.el.addEventListener(MouseEvents.DoubleClick, (e) => {
|
|
334
|
+
|
|
335
|
+
const mouse_position = new Vector2();
|
|
336
|
+
|
|
337
|
+
readPositionFromMouseEvent(mouse_position, e, vContainer.el);
|
|
338
|
+
|
|
339
|
+
const curve_position = position_canvas_to_curve(graph.size, frame, margin, mouse_position.x, mouse_position.y);
|
|
340
|
+
|
|
341
|
+
const key = Keyframe.from(curve_position.x, curve_position.y);
|
|
342
|
+
const key_index = curve.add(key);
|
|
343
|
+
|
|
344
|
+
curve.alignTangents(key_index);
|
|
345
|
+
curve.smoothTangents(key_index, 1);
|
|
346
|
+
|
|
347
|
+
add_keyframe(key);
|
|
348
|
+
update_graph();
|
|
349
|
+
});
|
|
310
350
|
|
|
311
351
|
graph.on.linked.add(handle_curve_update);
|
|
312
352
|
|
|
@@ -3,8 +3,8 @@ import { CanvasView } from "../../../../view/elements/CanvasView.js";
|
|
|
3
3
|
import Entity from "../../../ecs/Entity.js";
|
|
4
4
|
import GUIElement from "../../../ecs/gui/GUIElement.js";
|
|
5
5
|
import ViewportPosition from "../../../ecs/gui/position/ViewportPosition.js";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { canvas2d_draw_label } from "../../../graphics/canvas/canvas2d_draw_label.js";
|
|
7
|
+
import { canvas2d_plot_data_line } from "../../../graphics/canvas/canvas2d_plot_data_line.js";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
*
|
|
@@ -35,13 +35,13 @@ export function build_plot_entity_from_array({
|
|
|
35
35
|
});
|
|
36
36
|
const ctx = canvasView.context2d;
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
canvas2d_plot_data_line({ ctx, data, width, height, margin });
|
|
39
39
|
|
|
40
40
|
const text = `${data.length}`;
|
|
41
|
-
|
|
41
|
+
canvas2d_draw_label({ ctx: ctx, text: text, x: margin.x, y: height - (20) });
|
|
42
42
|
|
|
43
43
|
if (typeof label === "string" && label.length > 0) {
|
|
44
|
-
|
|
44
|
+
canvas2d_draw_label({ ctx: ctx, text: label, x: width - margin.x - 50, y: 20 })
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
return new Entity()
|
|
@@ -9,6 +9,25 @@ import { crc } from "./crc.js";
|
|
|
9
9
|
import { PNG } from './PNG.js';
|
|
10
10
|
import { PNG_HEADER_BYTES } from "./PNG_HEADER_BYTES.js";
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Uint8Array} encoded_chunk
|
|
15
|
+
* @returns {ArrayBuffer}
|
|
16
|
+
*/
|
|
17
|
+
function inflate(encoded_chunk) {
|
|
18
|
+
const inflator = new zlib.Inflate();
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
inflator.push(encoded_chunk);
|
|
22
|
+
|
|
23
|
+
if (inflator.err) {
|
|
24
|
+
throw new Error(inflator.err);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
return inflator.result.buffer;
|
|
29
|
+
}
|
|
30
|
+
|
|
12
31
|
/**
|
|
13
32
|
*
|
|
14
33
|
* @param {Uint8Array} buffer
|
|
@@ -162,8 +181,18 @@ PNGReader.prototype.decodeChunk = function () {
|
|
|
162
181
|
case 'sRGB':
|
|
163
182
|
this.decodesRGB(chunk);
|
|
164
183
|
break;
|
|
184
|
+
case 'tIME':
|
|
185
|
+
this.decodetIME(chunk);
|
|
186
|
+
break;
|
|
187
|
+
case 'zTXt':
|
|
188
|
+
this.decodezTXt(chunk);
|
|
189
|
+
break;
|
|
190
|
+
case 'iTXt':
|
|
191
|
+
this.decodeiTXt(chunk);
|
|
192
|
+
break;
|
|
165
193
|
default:
|
|
166
|
-
|
|
194
|
+
// skip unknown block
|
|
195
|
+
// console.warn(`Unsupported block ${type}`);
|
|
167
196
|
break;
|
|
168
197
|
}
|
|
169
198
|
|
|
@@ -183,6 +212,95 @@ PNGReader.prototype.decodesRGB = function (chunk) {
|
|
|
183
212
|
// TODO add metadata to the PNG representation
|
|
184
213
|
}
|
|
185
214
|
|
|
215
|
+
/**
|
|
216
|
+
* https://www.w3.org/TR/2003/REC-PNG-20031110/#11tIME
|
|
217
|
+
* @param {Uint8Array} chunk
|
|
218
|
+
*/
|
|
219
|
+
PNGReader.prototype.decodetIME = function (chunk) {
|
|
220
|
+
const year_high = readUInt8(chunk, 0);
|
|
221
|
+
const year_low = readUInt8(chunk, 1);
|
|
222
|
+
|
|
223
|
+
const year = (year_high << 8) | year_low;
|
|
224
|
+
|
|
225
|
+
const month = readUInt8(chunk, 2);
|
|
226
|
+
const day = readUInt8(chunk, 3);
|
|
227
|
+
const hour = readUInt8(chunk, 4);
|
|
228
|
+
const minute = readUInt8(chunk, 5);
|
|
229
|
+
const second = readUInt8(chunk, 6);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* International textual data
|
|
234
|
+
* @see https://www.w3.org/TR/2003/REC-PNG-20031110/
|
|
235
|
+
* @param {Uint8Array} chunk
|
|
236
|
+
*/
|
|
237
|
+
PNGReader.prototype.decodeiTXt = function (chunk) {
|
|
238
|
+
const buffer = BinaryBuffer.fromArrayBuffer(chunk.buffer);
|
|
239
|
+
const keyword = buffer.readASCIICharacters(79, true);
|
|
240
|
+
const compression_flag = buffer.readUint8();
|
|
241
|
+
const compression_method = buffer.readUint8();
|
|
242
|
+
|
|
243
|
+
const language_tag = buffer.readASCIICharacters(Infinity, true);
|
|
244
|
+
const translated_keyword = buffer.readASCIICharacters(Infinity, true);
|
|
245
|
+
|
|
246
|
+
const remaining_bytes = buffer.data.length - buffer.position;
|
|
247
|
+
|
|
248
|
+
let text;
|
|
249
|
+
|
|
250
|
+
if (compression_flag === 0) {
|
|
251
|
+
text = buffer.readASCIICharacters(remaining_bytes);
|
|
252
|
+
} else if (compression_flag === 1) {
|
|
253
|
+
const decoded = inflate(new Uint8Array(buffer.data, buffer.position, remaining_bytes));
|
|
254
|
+
|
|
255
|
+
buffer.fromArrayBuffer(decoded);
|
|
256
|
+
|
|
257
|
+
text = buffer.readASCIICharacters(decoded.byteLength);
|
|
258
|
+
} else {
|
|
259
|
+
throw new Error(`Invalid compression flag value '${compression_flag}'`);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return {
|
|
263
|
+
keyword,
|
|
264
|
+
language_tag,
|
|
265
|
+
translated_keyword,
|
|
266
|
+
text
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Compressed textual data
|
|
273
|
+
* @see https://www.w3.org/TR/2003/REC-PNG-20031110/#11zTXt
|
|
274
|
+
* @param {Uint8Array} chunk
|
|
275
|
+
*/
|
|
276
|
+
PNGReader.prototype.decodezTXt = function (chunk) {
|
|
277
|
+
const buffer = BinaryBuffer.fromArrayBuffer(chunk.buffer);
|
|
278
|
+
|
|
279
|
+
const keyword = buffer.readASCIICharacters(79, true);
|
|
280
|
+
|
|
281
|
+
const compression_method = buffer.readUint8();
|
|
282
|
+
|
|
283
|
+
let value;
|
|
284
|
+
|
|
285
|
+
if (compression_method === 0) {
|
|
286
|
+
// deflate method
|
|
287
|
+
|
|
288
|
+
const encoded_chunk = new Uint8Array(chunk.buffer, buffer.position);
|
|
289
|
+
|
|
290
|
+
const decompressed_data = inflate(encoded_chunk);
|
|
291
|
+
|
|
292
|
+
buffer.fromArrayBuffer(decompressed_data);
|
|
293
|
+
|
|
294
|
+
value = buffer.readASCIICharacters(decompressed_data.length);
|
|
295
|
+
} else {
|
|
296
|
+
throw new Error(`Unsupported compression method '${compression_method}'`);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return {
|
|
300
|
+
keyword: keyword,
|
|
301
|
+
text: value
|
|
302
|
+
}
|
|
303
|
+
}
|
|
186
304
|
|
|
187
305
|
/**
|
|
188
306
|
* https://www.w3.org/TR/PNG/#11tEXt
|