@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
|
@@ -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
|
+
}
|