@woosh/meep-engine 2.35.16 → 2.36.1

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 (101) hide show
  1. package/core/binary/BinaryBuffer.js +42 -17
  2. package/core/bvh2/BinaryNode.js +1 -1
  3. package/core/bvh2/aabb3/AABB3.js +2 -2
  4. package/core/bvh2/aabb3/aabb3_array_combine.js +20 -0
  5. package/core/bvh2/aabb3/aabb3_array_intersects_frustum_array.js +20 -0
  6. package/core/bvh2/aabb3/aabb3_array_intersects_ray.js +1 -0
  7. package/core/bvh2/aabb3/aabb3_array_intersects_ray_array.js +14 -0
  8. package/core/bvh2/{aabb3_combined_surface_area.js → aabb3/aabb3_combined_surface_area.js} +3 -3
  9. package/core/bvh2/aabb3/aabb3_intersects_frustum_array.js +1 -19
  10. package/core/bvh2/bvh3/BVHNodeProxy.js +53 -0
  11. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +848 -0
  12. package/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +142 -0
  13. package/core/bvh2/bvh3/bvh_query_leaves_generic.js +79 -0
  14. package/core/bvh2/bvh3/bvh_query_leaves_ray.js +95 -0
  15. package/core/bvh2/bvh3/query/BVHQuery.js +11 -0
  16. package/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +36 -0
  17. package/core/bvh2/bvh3/query/BVHQueryIntersectsRay.js +36 -0
  18. package/core/collection/array/copyArray.js +2 -2
  19. package/core/collection/table/RowFirstTable.js +25 -7
  20. package/core/collection/table/RowFirstTableSpec.js +4 -4
  21. package/core/geom/3d/aabb/aabb3_matrix4_project.spec.js +1 -1
  22. package/{engine/graphics/util → core/geom/3d/aabb}/computeBoundingBoxFromVertexData.js +1 -1
  23. package/core/geom/3d/compose_matrix4_array.js +53 -0
  24. package/{engine/graphics/util → core/geom/3d}/decompose_matrix_4_array.js +0 -0
  25. package/core/geom/AABB2.d.ts +2 -0
  26. package/core/geom/Vector1.js +2 -3
  27. package/core/geom/Vector3.js +5 -1
  28. package/core/process/undo/ActionProcessor.js +31 -3
  29. package/core/process/undo/ActionProcessor.spec.js +1 -1
  30. package/engine/animation/curve/AnimationCurve.js +40 -1
  31. package/engine/animation/curve/Keyframe.js +19 -0
  32. package/engine/animation/curve/compression/animation_curve_to_float_array.js +35 -0
  33. package/engine/animation/curve/compression/downsample_float_array.js +50 -0
  34. package/engine/animation/curve/compression/downsample_float_array_curve_by_error.js +147 -0
  35. package/engine/animation/curve/compression/downsample_float_array_curve_by_error.spec.js +47 -0
  36. package/engine/animation/curve/compression/prototypeCurveCompression.js +154 -0
  37. package/engine/animation/curve/draw/build_curve_editor.js +316 -0
  38. package/engine/animation/curve/draw/build_plot_entity_from_array.js +47 -0
  39. package/engine/animation/curve/draw/build_tangent_editor.js +115 -0
  40. package/engine/animation/curve/draw/draw_grid.js +27 -0
  41. package/engine/animation/curve/draw/draw_label.js +17 -0
  42. package/engine/animation/curve/draw/plot_array.js +76 -0
  43. package/engine/animation/curve/draw/plot_data.js +49 -0
  44. package/engine/asset/loaders/GLTFAssetLoader.js +3 -0
  45. package/engine/asset/loaders/gltf/GLTFAssetTransformMikkTSpaceTangents.js +27 -0
  46. package/engine/ecs/EntityComponentDataset.js +7 -4
  47. package/engine/ecs/foliage/InstancedFoliage.js +1 -1
  48. package/engine/ecs/foliage/ViewState.js +1 -1
  49. package/engine/ecs/parent/EntityNode.d.ts +7 -3
  50. package/engine/ecs/parent/EntityNode.js +21 -0
  51. package/engine/ecs/parent/entity_node_compute_bounding_box.js +41 -0
  52. package/engine/ecs/transform/Transform.js +2 -2
  53. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.d.ts +5 -0
  54. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +46 -12
  55. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +81 -95
  56. package/engine/graphics/ecs/mesh-v2/render/ShadedGeometryRendererContext.js +16 -5
  57. package/engine/graphics/ecs/mesh-v2/render/adapters/InstancedRendererAdapter.js +2 -0
  58. package/engine/graphics/ecs/mesh-v2/sample/load_gltf.js +1 -0
  59. package/engine/graphics/ecs/mesh-v2/sample/prototypeShadedGeometry.js +3 -4
  60. package/engine/graphics/ecs/path/PathDisplaySystem.js +2 -1
  61. package/engine/graphics/ecs/path/testPathDisplaySystem.js +8 -8
  62. package/engine/graphics/ecs/path/tube/CapType.d.ts +5 -0
  63. package/engine/graphics/ecs/path/tube/CapType.js +9 -0
  64. package/engine/graphics/ecs/path/tube/TubePathStyle.d.ts +2 -0
  65. package/engine/graphics/ecs/path/tube/TubePathStyle.js +10 -1
  66. package/engine/graphics/ecs/path/tube/build/GeometryOutput.js +90 -0
  67. package/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +3 -2
  68. package/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +1 -1
  69. package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +1 -2
  70. package/engine/graphics/ecs/path/tube/build/makeTubeGeometry.js +353 -91
  71. package/engine/graphics/ecs/path/tube/prototypeAnimatedPathMask.js +390 -0
  72. package/engine/graphics/geometry/MikkT/MikkTSpace.js +2210 -0
  73. package/engine/graphics/geometry/MikkT/MikkTSpace.spec.js +22 -0
  74. package/engine/graphics/geometry/MikkT/buffer_geometry_ensure_tangents.js +34 -0
  75. package/engine/graphics/geometry/MikkT/buffer_geometry_generate_tangents.js +28 -0
  76. package/engine/graphics/{compute_geometry_polycount.js → geometry/compute_geometry_polycount.js} +0 -0
  77. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +34 -3
  78. package/engine/graphics/geometry/skining/computeSkinnedMeshBoundingVolumes.js +1 -1
  79. package/engine/graphics/micron/format/serialization/collection/geometry_collection_serialization.js +83 -0
  80. package/engine/graphics/micron/format/serialization/collection/geometry_collection_serialization.spec.js +24 -0
  81. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +42 -19
  82. package/engine/graphics/micron/plugin/GLTF_MICRON_ID_FIELD.js +5 -0
  83. package/engine/graphics/micron/plugin/MicronRenderPlugin.js +0 -4
  84. package/engine/graphics/micron/plugin/shaded_geometry/MicronShadedGeometryRenderAdapter.js +10 -0
  85. package/engine/graphics/micron/prototypeVirtualGeometry.js +5 -3
  86. package/engine/graphics/micron/render/refinement/ActivePatchList.js +2 -2
  87. package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +2 -2
  88. package/engine/graphics/micron/render/v1/MicronRenderContext.js +0 -6
  89. package/engine/graphics/render/forward_plus/LightManager.js +3 -1
  90. package/engine/graphics/util/composeMatrix4.js +1 -53
  91. package/engine/graphics/util/composeMatrix4RotationScale.js +1 -1
  92. package/engine/intelligence/behavior/ecs/BehaviorComponent.js +1 -1
  93. package/engine/intelligence/blackboard/AbstractBlackboard.js +9 -0
  94. package/engine/notify/Notification.js +1 -1
  95. package/engine/ui/DraggableAspect.js +4 -1
  96. package/engine/ui/notification/ViewEmitter.js +7 -1
  97. package/engine/ui/notification/notificationGenerator.js +1 -1
  98. package/engine/ui/scene/SceneGUIContext.js +11 -130
  99. package/engine/ui/scene/initializeNotifications.js +141 -0
  100. package/package.json +1 -1
  101. package/view/elements/notify/NotificationView.js +1 -2
@@ -0,0 +1,316 @@
1
+ import Vector2 from "../../../../core/geom/Vector2.d.ts";
2
+ import EmptyView from "../../../../view/elements/EmptyView.js";
3
+ import { CanvasView } from "../../../../view/elements/CanvasView.js";
4
+ import AABB2 from "../../../../core/geom/AABB2.d.ts";
5
+ import Signal from "../../../../core/events/signal/Signal.d.ts";
6
+ import ObservedValue from "../../../../core/model/ObservedValue.js";
7
+ import { animation_curve_to_float_array } from "../compression/animation_curve_to_float_array.js";
8
+ import { plot_data } from "./plot_data.js";
9
+ 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
+ }
36
+
37
+ /**
38
+ *
39
+ * @param {Vector2} size
40
+ * @param {AABB2} frame
41
+ * @param {Vector2} margin
42
+ * @param {number} x
43
+ * @param {number} y
44
+ * @return {Vector2}
45
+ */
46
+ function position_curve_to_canvas(size, frame, margin, x, y) {
47
+ const width = size.x;
48
+ const height = size.y;
49
+
50
+ const curve_width = frame.getWidth();
51
+ const curve_width_multiplier = curve_width > 0 ? 1 / curve_width : 0;
52
+ const u = (x - frame.x0) * curve_width_multiplier;
53
+
54
+ const curve_height = frame.getHeight();
55
+ const curve_height_multiplier = curve_height > 0 ? 1 / curve_height : 0;
56
+ const v = 1 - (y - frame.y0) * curve_height_multiplier;
57
+
58
+ return new Vector2(margin.x + (u * (width - margin.x * 2)), margin.y + v * (height - margin.y * 2));
59
+ }
60
+
61
+ /**
62
+ *
63
+ * @param {Vector2} size
64
+ * @param {AABB2} frame
65
+ * @param {Vector2} margin
66
+ * @param {number} x
67
+ * @param {number} y
68
+ * @return {Vector2}
69
+ */
70
+ function position_canvas_to_curve(size, frame, margin, x, y) {
71
+
72
+ const width = size.x;
73
+ const height = size.y;
74
+
75
+ const u = (x - margin.x) / (width - margin.x * 2);
76
+ const v = 1 - (y - margin.y) / (height - margin.y * 2);
77
+
78
+ return new Vector2(
79
+ u * frame.getWidth() + frame.x0,
80
+ v * frame.getHeight() + frame.y0
81
+ );
82
+ }
83
+
84
+ /**
85
+ *
86
+ * @param {AnimationCurve} curve
87
+ * @param {Vector2} [size]
88
+ * @param {Vector2} [margin]
89
+ * @returns {View}
90
+ */
91
+ export function build_curve_editor({
92
+ curve,
93
+ size = new Vector2(600, 200),
94
+ margin = new Vector2(8, 36)
95
+ }) {
96
+
97
+ const vContainer = new EmptyView();
98
+
99
+ const graph = new CanvasView();
100
+ graph.size.copy(size);
101
+
102
+ const frame = new AABB2();
103
+
104
+ const frame_updated = new Signal();
105
+
106
+ /**
107
+ *
108
+ * @type {ObservedValue<Keyframe>}
109
+ */
110
+ const active_keyframe = new ObservedValue(null);
111
+
112
+
113
+ function handle_curve_update() {
114
+ compute_curve_aabb(frame, curve);
115
+
116
+ frame_updated.send0();
117
+
118
+ update_graph();
119
+ }
120
+
121
+
122
+ function update_graph() {
123
+ const width = graph.size.x;
124
+ const data = new Float32Array(width);
125
+
126
+ animation_curve_to_float_array(data, curve, 0, data.length);
127
+
128
+ plot_data({
129
+ data,
130
+ ctx: graph.context2d,
131
+ width: width,
132
+ height: graph.size.y,
133
+ margin: margin,
134
+ range_y: [frame.y0, frame.y1]
135
+ });
136
+ }
137
+
138
+ const keyframe_views = new Map();
139
+
140
+ function add_keyframe(keyframe) {
141
+ const vContainerMarker = new EmptyView({
142
+ css: {
143
+ position: "absolute",
144
+ top: 0,
145
+ left: 0,
146
+ pointerEvents: "none"
147
+ }
148
+ });
149
+
150
+ const marker_size = 8;
151
+ const marker = new EmptyView({
152
+ css: {
153
+ width: `${marker_size}px`,
154
+ height: `${marker_size}px`,
155
+ background: "#00ff00",
156
+ border: "none",
157
+ position: "absolute",
158
+ top: `-${marker_size / 2}px`,
159
+ left: `-${marker_size / 2}px`,
160
+ pointerEvents: "auto",
161
+ borderRadius: `${marker_size}px`
162
+ }
163
+ });
164
+
165
+ // add extra element for mouse event capture to make it easier to click on the marker
166
+ const marker_hit_pad_size = 24;
167
+ marker.addChild(new EmptyView({
168
+ css: {
169
+ opacity: 0,
170
+ width: `${marker_hit_pad_size}px`,
171
+ height: `${marker_hit_pad_size}px`,
172
+ borderRadius: `${marker_hit_pad_size}px`,
173
+ // background: 'rgba(255,0,0,0.2)',
174
+ position: "absolute",
175
+ top: `-${(marker_hit_pad_size - marker_size) / 2}px`,
176
+ left: `-${(marker_hit_pad_size - marker_size) / 2}px`
177
+ }
178
+ }))
179
+
180
+ function updatePosition() {
181
+ const canvas_coordinates = position_curve_to_canvas(
182
+ graph.size,
183
+ frame,
184
+ margin,
185
+ keyframe.time,
186
+ keyframe.value
187
+ );
188
+ vContainerMarker.position.copy(canvas_coordinates);
189
+ }
190
+
191
+ function updateActiveState() {
192
+ if (active_keyframe.get() === keyframe) {
193
+ marker.css({
194
+ background: '#FFFFFF'
195
+ });
196
+ } else {
197
+ marker.css({
198
+ background: '#00ff00'
199
+ });
200
+ }
201
+ }
202
+
203
+ updatePosition();
204
+
205
+ const marker_el = marker.el;
206
+
207
+ const previous = new Vector2();
208
+ const draggable = new DraggableAspect({
209
+ el: marker_el, drag(position) {
210
+ const delta = new Vector2();
211
+ delta.subVectors(position, previous);
212
+
213
+ const keyframe_coord = position_canvas_to_curve(
214
+ graph.size,
215
+ frame,
216
+ margin,
217
+ position.x,
218
+ position.y
219
+ );
220
+
221
+ console.log(keyframe_coord);
222
+
223
+ keyframe.time = keyframe_coord.x;
224
+ keyframe.value = keyframe_coord.y;
225
+
226
+ let keyframe_index = curve.keys.indexOf(keyframe);
227
+
228
+ if (keyframe_index < (curve.keys.length - 1) && keyframe.time > curve.keys[keyframe_index + 1].time) {
229
+ const next_index = keyframe_index + 1;
230
+ const next = curve.keys[next_index];
231
+
232
+ curve.keys[next_index] = keyframe;
233
+ curve.keys[keyframe_index] = next;
234
+
235
+ keyframe_index = next_index;
236
+ } else if (keyframe_index > 0 && keyframe.time < curve.keys[keyframe_index - 1].time) {
237
+ const prev_index = keyframe_index - 1;
238
+ const prev = curve.keys[prev_index];
239
+
240
+ curve.keys[prev_index] = keyframe;
241
+ curve.keys[keyframe_index] = prev;
242
+
243
+ keyframe_index = prev_index;
244
+ }
245
+
246
+ curve.smoothTangents(keyframe_index, 1);
247
+
248
+ if (keyframe_index > 0) {
249
+ curve.smoothTangents(keyframe_index - 1, 1);
250
+ }
251
+ if (keyframe_index < curve.keys.length - 1) {
252
+ curve.smoothTangents(keyframe_index + 1, 1);
253
+ }
254
+
255
+ updatePosition();
256
+ update_graph();
257
+
258
+ previous.copy(position);
259
+ },
260
+ dragStart(position) {
261
+ previous.copy(position);
262
+
263
+ active_keyframe.set(keyframe);
264
+ },
265
+ dragEnd() {
266
+ handle_curve_update();
267
+ }
268
+ });
269
+
270
+ draggable.getPointer().on.tap.add(() => {
271
+ active_keyframe.set(keyframe);
272
+ });
273
+
274
+ marker.on.linked.add(draggable.start, draggable);
275
+ marker.on.unlinked.add(draggable.stop, draggable);
276
+
277
+ marker.bindSignal(frame_updated, updatePosition);
278
+ marker.bindSignal(active_keyframe.onChanged, updateActiveState);
279
+
280
+ // const vTangentEditor = build_tangent_editor({
281
+ // keyframe: keyframe,
282
+ // size: graph.size,
283
+ // ctx: graph.context2d,
284
+ // frame,
285
+ // margin
286
+ // });
287
+ // vContainerMarker.addChild(vTangentEditor);
288
+
289
+ vContainerMarker.addChild(marker);
290
+
291
+ keyframe_views.set(keyframe, vContainerMarker);
292
+
293
+ vContainer.addChild(vContainerMarker);
294
+ }
295
+
296
+ function remove_keyframe(keyframe) {
297
+ const marker_view = keyframe_views.get(keyframe);
298
+
299
+ vContainer.removeChild(marker_view);
300
+ }
301
+
302
+ graph.on.linked.add(() => {
303
+ curve.keys.forEach(add_keyframe);
304
+ });
305
+
306
+ graph.on.unlinked.add(() => {
307
+ curve.keys.forEach(remove_keyframe);
308
+ });
309
+
310
+
311
+ graph.on.linked.add(handle_curve_update);
312
+
313
+ vContainer.addChild(graph);
314
+
315
+ return vContainer;
316
+ }
@@ -0,0 +1,47 @@
1
+ import { CanvasView } from "../../../../view/elements/CanvasView.js";
2
+ import { plot_data } from "./plot_data.js";
3
+ import { draw_label } from "./draw_label.js";
4
+ import EntityBuilder from "../../../ecs/EntityBuilder.js";
5
+ import ViewportPosition from "../../../ecs/gui/position/ViewportPosition.js";
6
+ import GUIElement from "../../../ecs/gui/GUIElement.js";
7
+ import Vector2 from "../../../../core/geom/Vector2.js";
8
+
9
+ /**
10
+ *
11
+ * @param {number[]} data
12
+ * @param {number} x
13
+ * @param {number} y
14
+ * @param {number} [width]
15
+ * @param {number} [height]
16
+ * @param {Vector2} [margin]
17
+ * @param {string} [label]
18
+ * @return {EntityBuilder}
19
+ */
20
+ export function build_plot_entity_from_array({
21
+ data,
22
+ x, y,
23
+ width = 600,
24
+ height = 200,
25
+ margin = new Vector2(10,10),
26
+ label = ''
27
+ }) {
28
+
29
+ const canvasView = new CanvasView();
30
+ canvasView.size.set(width, height);
31
+ const ctx = canvasView.context2d;
32
+
33
+ plot_data({ ctx, data, width, height, margin });
34
+
35
+ const text = `${data.length}`;
36
+ draw_label(ctx, text, margin.x, height - (20));
37
+
38
+ if (typeof label === "string" && label.length > 0) {
39
+ draw_label(ctx, label, 0, 0)
40
+ }
41
+
42
+ return new EntityBuilder()
43
+ .add(ViewportPosition.fromJSON({
44
+ offset: { x, y }
45
+ }))
46
+ .add(GUIElement.fromView(canvasView));
47
+ }
@@ -0,0 +1,115 @@
1
+ import EmptyView from "../../../../view/elements/EmptyView.js";
2
+
3
+ /**
4
+ *
5
+ * @param {CanvasRenderingContext2D} ctx
6
+ * @param {Keyframe} keyframe
7
+ * @param {Vector2} size
8
+ * @param {AABB2} frame
9
+ * @param {Vector2} margin
10
+ */
11
+ export function build_tangent_editor({
12
+ ctx,
13
+ keyframe,
14
+ size,
15
+ frame,
16
+ margin
17
+ }) {
18
+
19
+ const scale = 36;
20
+
21
+
22
+ function build_handle() {
23
+
24
+ const marker_size = 4;
25
+ const marker = new EmptyView({
26
+ css: {
27
+ width: `${marker_size}px`,
28
+ height: `${marker_size}px`,
29
+ background: "#00ff00",
30
+ border: "none",
31
+ position: "absolute",
32
+ top: `-${marker_size / 2}px`,
33
+ left: `-${marker_size / 2}px`,
34
+ pointerEvents: "auto"
35
+ }
36
+ });
37
+
38
+ // add extra element for mouse event capture to make it easier to click on the marker
39
+ const marker_hit_pad_size = 24;
40
+ marker.addChild(new EmptyView({
41
+ css: {
42
+ opacity: 0,
43
+ width: `${marker_hit_pad_size}px`,
44
+ height: `${marker_hit_pad_size}px`,
45
+ borderRadius: `${marker_hit_pad_size}px`,
46
+ // background: 'rgba(255,0,0,0.2)',
47
+ position: "absolute",
48
+ top: `-${(marker_hit_pad_size - marker_size) / 2}px`,
49
+ left: `-${(marker_hit_pad_size - marker_size) / 2}px`
50
+ }
51
+ }))
52
+
53
+ return marker;
54
+ }
55
+
56
+ function build_tangent() {
57
+ const view = new EmptyView({
58
+ css: {
59
+ position: "absolute",
60
+ left: "0",
61
+ top: "0",
62
+ background: 'red'
63
+ }
64
+ });
65
+ view.position.set(-0.5, -0.5);
66
+ view.transformOrigin.set(0, 0.5);
67
+
68
+ return view;
69
+ }
70
+
71
+
72
+ const handle_in = build_handle();
73
+ const handle_out = build_handle();
74
+
75
+ const tangent_in = build_tangent();
76
+
77
+ const tangent_out = build_tangent();
78
+
79
+
80
+ function update_positions() {
81
+ tangent_in.size.set(scale, 1);
82
+ const angle_in = Math.PI - Math.atan2(keyframe.inTangent, 1);
83
+ tangent_in.rotation.set(angle_in);
84
+
85
+ tangent_out.size.set(scale, 1);
86
+ const angle_out = -Math.atan2(keyframe.outTangent, 1);
87
+ tangent_out.rotation.set(angle_out);
88
+
89
+ handle_in.position.set(
90
+ Math.cos(angle_in) * scale, Math.sin(angle_in) * scale
91
+ );
92
+
93
+ handle_out.position.set(
94
+ Math.cos(angle_out) * scale, Math.sin(angle_out) * scale
95
+ );
96
+ }
97
+
98
+ const vContainer = new EmptyView({
99
+ css: {
100
+ position: 'absolute',
101
+ left: 0,
102
+ top: 0
103
+ }
104
+ });
105
+
106
+ vContainer.addChild(handle_in);
107
+ vContainer.addChild(handle_out);
108
+
109
+ vContainer.addChild(tangent_in);
110
+ vContainer.addChild(tangent_out);
111
+
112
+ vContainer.on.linked.add(update_positions);
113
+
114
+ return vContainer;
115
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ *
3
+ * @param {CanvasRenderingContext2D} ctx
4
+ * @param {number} width
5
+ * @param {number} height
6
+ * @param {string} color
7
+ * @param {number} spacing
8
+ * @param {number} [offset_x]
9
+ * @param {number} [offset_y]
10
+ */
11
+ export function draw_grid({ ctx, width, height, color = 'red', spacing = 10, offset_x = 0, offset_y = 0 }) {
12
+ ctx.fillStyle = 'none';
13
+ ctx.lineWidth = 1;
14
+ ctx.strokeStyle = color;
15
+
16
+
17
+ ctx.beginPath();
18
+ for (let x = offset_x; x < width; x += spacing) {
19
+ ctx.moveTo(x, 0);
20
+ ctx.lineTo(x, height);
21
+ }
22
+ for (let y = offset_y; y < width; y += spacing) {
23
+ ctx.moveTo(0, y);
24
+ ctx.lineTo(width, y);
25
+ }
26
+ ctx.stroke();
27
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ *
3
+ * @param {CanvasRenderingContext2D} ctx
4
+ * @param {string} text
5
+ * @param {number} x
6
+ * @param {number} y
7
+ */
8
+ export function draw_label(ctx, text, x, y) {
9
+
10
+ ctx.fillStyle = 'white';
11
+ ctx.font = '10px Tahoma';
12
+
13
+ ctx.strokeStyle = `rgba(0, 0, 0, 0.5)`;
14
+ ctx.lineWidth = 2;
15
+ ctx.strokeText(text, x, y);
16
+ ctx.fillText(text, x, y);
17
+ }
@@ -0,0 +1,76 @@
1
+ import { min2 } from "../../../../core/math/min2.js";
2
+ import { max2 } from "../../../../core/math/max2.js";
3
+
4
+ /**
5
+ *
6
+ * @param {number[]} data
7
+ * @return {number[]}
8
+ */
9
+ export function array_compute_min_max(data) {
10
+ const point_count = data.length;
11
+
12
+ let min = Number.POSITIVE_INFINITY;
13
+ let max = Number.NEGATIVE_INFINITY;
14
+ for (let i = 0; i < point_count; i++) {
15
+ min = min2(data[i], min);
16
+ max = max2(data[i], max);
17
+ }
18
+
19
+ return [min, max];
20
+ }
21
+
22
+ /**
23
+ *
24
+ * @param {CanvasRenderingContext2D} ctx
25
+ * @param {number} width
26
+ * @param {number} height
27
+ * @param {number} x_offset
28
+ * @param {number} y_offset
29
+ * @param {number[]} data
30
+ * @param {number[]} data_range_y
31
+ */
32
+ export function plot_array(
33
+ ctx,
34
+ width,
35
+ height,
36
+ x_offset,
37
+ y_offset,
38
+ data,
39
+ data_range_y
40
+ ) {
41
+ const point_count = data.length;
42
+
43
+ if (data_range_y === undefined) {
44
+ data_range_y = array_compute_min_max(data)
45
+ }
46
+
47
+ const [min, max] = data_range_y;
48
+
49
+ const value_span = max - min;
50
+ const normalization_multiplier = value_span !== 0 ? 1 / value_span : 0;
51
+
52
+ ctx.beginPath();
53
+ if (point_count === 1) {
54
+ ctx.moveTo(x_offset, height + y_offset);
55
+ ctx.lineTo(x_offset + width, height + y_offset);
56
+ } else {
57
+
58
+ for (let i = 0; i < point_count; i++) {
59
+ const value = data[i];
60
+ const value_normalized = (value - min) * normalization_multiplier;
61
+
62
+ const v = 1 - value_normalized;
63
+ const u = i / (point_count - 1);
64
+
65
+ const x = u * width + x_offset;
66
+ const y = v * height + y_offset;
67
+
68
+ if (i === 0) {
69
+ ctx.moveTo(x, y);
70
+ } else {
71
+ ctx.lineTo(x, y);
72
+ }
73
+ }
74
+ }
75
+ ctx.stroke();
76
+ }
@@ -0,0 +1,49 @@
1
+ import { draw_grid } from "./draw_grid.js";
2
+ import { plot_array } from "./plot_array.js";
3
+ import Vector2 from "../../../../core/geom/Vector2.js";
4
+
5
+ /**
6
+ *
7
+ * @param {CanvasRenderingContext2D} ctx
8
+ * @param {number[]|Float32Array} data
9
+ * @param {Vector2} [margin]
10
+ * @param {number} width
11
+ * @param {number} height
12
+ * @param {number[]} [range_y]
13
+ */
14
+ export function plot_data({
15
+ ctx,
16
+ data,
17
+ margin = Vector2.zero,
18
+ width,
19
+ height,
20
+ range_y
21
+ }) {
22
+
23
+ ctx.fillStyle = '#222222';
24
+ ctx.fillRect(0, 0, width, height);
25
+
26
+ draw_grid({
27
+ ctx,
28
+ width,
29
+ height,
30
+ color: '#262626',
31
+ spacing: 32
32
+ });
33
+
34
+ draw_grid({
35
+ ctx,
36
+ width,
37
+ height,
38
+ color: '#303030',
39
+ spacing: 32,
40
+ offset_x: 16,
41
+ offset_y: 16
42
+ });
43
+
44
+ ctx.fillStyle = 'none';
45
+ ctx.strokeStyle = '#00ff00';
46
+ ctx.lineWidth = 1;
47
+ plot_array(ctx, width - margin.x * 2, height - margin.y * 2, margin.x, margin.y, data, range_y);
48
+
49
+ }
@@ -406,6 +406,9 @@ export class GLTFAssetLoader extends AssetLoader {
406
406
  asset.has_root_transform = has_root_transform;
407
407
  asset.root_transform = root_transform;
408
408
 
409
+ // remember GLTF metadata
410
+ asset.gltf = gltf;
411
+
409
412
  if (gltf.animations !== undefined) {
410
413
  /**
411
414
  *
@@ -0,0 +1,27 @@
1
+ import { AssetTransformer } from "../../AssetTransformer.js";
2
+ import { buffer_geometry_ensure_tangents } from "../../../graphics/geometry/MikkT/buffer_geometry_ensure_tangents.js";
3
+
4
+ /**
5
+ * Ensures that all geometries have proper tangents
6
+ */
7
+ export class GLTFAssetTransformMikkTSpaceTangents extends AssetTransformer {
8
+ /**
9
+ *
10
+ * @param {Asset} source
11
+ * @param {AssetDescription} asset_description
12
+ * @return {Promise<Asset>}
13
+ */
14
+ async transform(source, asset_description) {
15
+ const root = source.create();
16
+
17
+ root.traverse(o => {
18
+ if (o.isMesh && o.geometry !== null) {
19
+ buffer_geometry_ensure_tangents(o.geometry);
20
+ }
21
+ });
22
+
23
+ return source;
24
+ }
25
+
26
+ static INSTANCE = new GLTFAssetTransformMikkTSpaceTangents();
27
+ }