@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.
Files changed (48) hide show
  1. package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +35 -21
  2. package/package.json +2 -2
  3. package/src/core/collection/array/array_compute_min_max.js +20 -0
  4. package/src/core/collection/map/HashMap.js +16 -14
  5. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +23 -13
  6. package/src/core/geom/2d/intersect_ray_2d.js +7 -14
  7. package/src/core/geom/3d/aabb/AABB3.js +13 -0
  8. package/src/core/geom/3d/topology/samples/sampleFloodFill.js +21 -21
  9. package/src/core/geom/3d/topology/tm_face_area.js +1 -1
  10. package/src/core/geom/3d/triangle/computeTriangleSurfaceArea.js +39 -0
  11. package/src/core/process/task/util/countTask.js +1 -2
  12. package/src/engine/EngineBootstrapper.js +15 -7
  13. package/src/engine/animation/curve/AnimationCurve.js +50 -31
  14. package/src/engine/animation/curve/AnimationCurve.spec.js +9 -1
  15. package/src/engine/animation/curve/compression/prototypeCurveCompression.js +20 -11
  16. package/src/engine/animation/curve/compute_curve_aabb.js +26 -0
  17. package/src/engine/animation/curve/draw/build_curve_editor.js +82 -42
  18. package/src/engine/animation/curve/draw/build_plot_entity_from_array.js +5 -5
  19. package/src/engine/animation/curve/preset/CURVE_EASE_IN.js +8 -0
  20. package/src/engine/animation/curve/preset/CURVE_EASE_IN_OUT.js +7 -0
  21. package/src/engine/animation/curve/preset/CURVE_EASE_OUT.js +7 -0
  22. package/src/engine/asset/loaders/image/png/PNGReader.js +119 -1
  23. package/src/engine/graphics/GraphicsEngine.d.ts +6 -3
  24. package/src/engine/graphics/canvas/canvas2d_draw_grid.js +42 -0
  25. package/src/engine/{animation/curve/draw/draw_label.js → graphics/canvas/canvas2d_draw_label.js} +6 -1
  26. package/src/engine/graphics/canvas/canvas2d_draw_linear_scale.js +64 -0
  27. package/src/engine/graphics/canvas/canvas2d_draw_path.js +60 -0
  28. package/src/engine/graphics/canvas/canvas2d_plot_data_line.js +84 -0
  29. package/src/engine/{animation/curve/draw/plot_array.js → graphics/canvas/canvas2d_plot_line_array.js} +8 -25
  30. package/src/engine/graphics/geometry/VertexDataSpec.d.ts +10 -0
  31. package/src/engine/graphics/geometry/VertexDataSpec.js +20 -21
  32. package/src/engine/graphics/geometry/computeMeshSurfaceArea.js +2 -37
  33. package/src/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +8 -26
  34. package/src/engine/graphics/material/manager/MaterialManager.d.ts +6 -0
  35. package/src/engine/graphics/sh3/LightProbeVolume.js +38 -17
  36. package/src/engine/graphics/sh3/path_tracer/prototypePathTracer.js +26 -35
  37. package/src/engine/graphics/sh3/prototypeSH3Probe.js +166 -100
  38. package/src/engine/graphics/texture/makeOnePixelTexture.js +19 -0
  39. package/src/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +5 -68
  40. package/src/engine/graphics/texture/virtual/v2/VirtualTexturePage.js +1 -1
  41. package/src/engine/input/devices/PointerDevice.js +6 -3
  42. package/src/engine/makeSimpleTaskProgressView.js +33 -0
  43. package/src/engine/scene/transitionToScene.js +9 -10
  44. package/src/view/task/TaskLoadingScreen.js +5 -12
  45. package/src/view/task/TaskProgressView.js +9 -9
  46. package/src/engine/animation/curve/draw/draw_grid.js +0 -27
  47. package/src/engine/animation/curve/draw/plot_data.js +0 -49
  48. 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
- constructor() {
48
- /**
49
- * @readonly
50
- * @type {Keyframe[]}
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 last_key_index = keys.length - 1;
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
- const key_count = keys.length;
130
+ curve.addMany(keys);
115
131
 
116
- for (let i = 0; i < key_count; i++) {
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 < keys[0].time) {
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
- smoothTangents(index, weight) {
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
- if (has_previous && has_next) {
198
- const average = lerp(key_main.inTangent, key_main.outTangent, 0.5);
199
- key_main.inTangent = average;
200
- key_main.outTangent = average;
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, 0);
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
- for (let i = 0; i < keys.length; i++) {
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
- // const editor_view = build_curve_editor({ curve });
146
- //
147
- // new EntityBuilder()
148
- // .add(ViewportPosition.fromJSON({
149
- // offset: { x: 0, y: 0 }
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 { sample_animation_curve_to_float_array } from "../compression/sample_animation_curve_to_float_array.js";
8
- import { plot_data } from "./plot_data.js";
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 { min2 } from "../../../../core/math/min2.js";
11
- import { max2 } from "../../../../core/math/max2.js";
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(600, 200),
94
- margin = new Vector2(8, 36)
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
- plot_data({
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
- active_keyframe.set(keyframe);
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 { draw_label } from "./draw_label.js";
7
- import { plot_data } from "./plot_data.js";
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
- plot_data({ ctx, data, width, height, margin });
38
+ canvas2d_plot_data_line({ ctx, data, width, height, margin });
39
39
 
40
40
  const text = `${data.length}`;
41
- draw_label(ctx, text, margin.x, height - (20));
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
- draw_label(ctx, label, width - margin.x - 50 , 20)
44
+ canvas2d_draw_label({ ctx: ctx, text: label, x: width - margin.x - 50, y: 20 })
45
45
  }
46
46
 
47
47
  return new Entity()
@@ -0,0 +1,8 @@
1
+ import { AnimationCurve } from "../AnimationCurve.js";
2
+ import { Keyframe } from "../Keyframe.js";
3
+
4
+ export const CURVE_EASE_IN = Object.freeze(AnimationCurve.from([
5
+ Keyframe.from(0,0,0,0),
6
+ Keyframe.from(1,1,Math.PI,1),
7
+ ]))
8
+
@@ -0,0 +1,7 @@
1
+ import { AnimationCurve } from "../AnimationCurve.js";
2
+ import { Keyframe } from "../Keyframe.js";
3
+
4
+ export const CURVE_EASE_IN_OUT = Object.freeze(AnimationCurve.from([
5
+ Keyframe.from(0, 0, 0, 0),
6
+ Keyframe.from(1, 1, 0, 0),
7
+ ]))
@@ -0,0 +1,7 @@
1
+ import { AnimationCurve } from "../AnimationCurve.js";
2
+ import { Keyframe } from "../Keyframe.js";
3
+
4
+ export const CURVE_EASE_OUT = Object.freeze(AnimationCurve.from([
5
+ Keyframe.from(0, 0, Math.PI, 1),
6
+ Keyframe.from(1, 1, 0, 0),
7
+ ]))
@@ -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
- console.warn(`Unsupported block ${type}`);
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