@woosh/meep-engine 2.38.2 → 2.39.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.
- package/core/geom/Quaternion.js +70 -0
- package/core/geom/Vector2.js +17 -0
- package/core/geom/v3_angle_between.js +17 -3
- package/engine/ecs/EntityBuilder.d.ts +3 -1
- package/engine/ecs/EntityBuilder.js +10 -1
- package/engine/ecs/EntityComponentDataset.js +1 -1
- package/engine/ecs/parent/ChildEntities.d.ts +3 -0
- package/engine/ecs/parent/ChildEntities.js +41 -0
- package/engine/ecs/system/AbstractContextSystem.js +4 -2
- package/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +1 -1
- package/engine/graphics/ecs/path/PathDisplayEvents.js +3 -2
- package/engine/graphics/ecs/path/PathDisplaySystem.js +5 -0
- package/engine/graphics/ecs/path/highlight/PathDisplayHighlightSystem.d.ts +7 -0
- package/engine/graphics/ecs/path/highlight/PathDisplayHighlightSystem.js +141 -0
- package/engine/graphics/ecs/path/testPathDisplaySystem.js +86 -25
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.d.ts +3 -0
- package/engine/graphics/ecs/path/tube/BasicMaterialDefinition.js +8 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.d.ts +1 -0
- package/engine/graphics/ecs/path/tube/TubeMaterialType.js +1 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.d.ts +12 -0
- package/engine/graphics/ecs/path/tube/TubePathStyle.js +54 -9
- package/engine/graphics/ecs/path/tube/build/TubePathBuilder.js +67 -25
- package/engine/graphics/ecs/path/tube/build/build_geometry_catmullrom.js +12 -2
- package/engine/graphics/ecs/path/tube/build/build_geometry_linear.js +13 -2
- package/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +33 -28
- package/engine/graphics/ecs/path/tube/build/compute_smooth_profile_normals.js +41 -0
- package/engine/graphics/ecs/path/tube/build/fix_shape_normal_order.js +45 -0
- package/engine/graphics/ecs/path/tube/build/makeTubeGeometry.js +123 -347
- package/engine/graphics/ecs/path/tube/build/make_cap.js +274 -0
- package/engine/graphics/ecs/path/tube/build/make_ring_faces.js +40 -0
- package/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +152 -0
- package/package.json +1 -1
- package/view/View.js +2 -2
- package/view/{compose3x3transform.js → m3_cm_compose_transform.js} +11 -3
- package/view/m3_rm_compose_transform.js +45 -0
- package/view/multiplyMatrices3.js +4 -4
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { Vector3 } from "three";
|
|
2
|
+
import { max2 } from "../../../../../../core/math/max2.js";
|
|
3
|
+
import { m3_rm_compose_transform } from "../../../../../../view/m3_rm_compose_transform.js";
|
|
4
|
+
import { m3_multiply } from "../../../../../../view/multiplyMatrices3.js";
|
|
5
|
+
import { make_ring_vertices } from "./make_ring_vertices.js";
|
|
6
|
+
import { make_ring_faces } from "./make_ring_faces.js";
|
|
7
|
+
import { v2_distance } from "../../../../../../core/geom/Vector2.js";
|
|
8
|
+
import { CapType } from "../CapType.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param {number} radial_segments
|
|
13
|
+
* @returns {number}
|
|
14
|
+
*/
|
|
15
|
+
function compute_cap_round_segment_count(radial_segments) {
|
|
16
|
+
return max2(3, Math.ceil(radial_segments / 4));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
*
|
|
21
|
+
* @param {number[]} shape
|
|
22
|
+
* @param {number} shape_length
|
|
23
|
+
* @param {number} cx
|
|
24
|
+
* @param {number} cy
|
|
25
|
+
* @returns {number}
|
|
26
|
+
*/
|
|
27
|
+
function compute_shape_radius(shape, shape_length, cx = 0, cy = 0) {
|
|
28
|
+
let max_distance = 0;
|
|
29
|
+
for (let i = 0; i < shape_length; i++) {
|
|
30
|
+
const i2 = i * 2;
|
|
31
|
+
|
|
32
|
+
const x = shape[i2];
|
|
33
|
+
const y = shape[i2 + 1];
|
|
34
|
+
|
|
35
|
+
// NOTE: can be optimized by delaying SQRT
|
|
36
|
+
const distance = v2_distance(x, y, cx, cy);
|
|
37
|
+
|
|
38
|
+
if (distance > max_distance) {
|
|
39
|
+
max_distance = distance;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return max_distance;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
*
|
|
48
|
+
* @param {number} index
|
|
49
|
+
* @param {Float32Array|number[]} in_positions
|
|
50
|
+
* @param {Vector3[]} in_normals
|
|
51
|
+
* @param {Vector3[]} in_binormals
|
|
52
|
+
* @param {Vector3[]} in_tangents
|
|
53
|
+
* @param {GeometryOutput} out
|
|
54
|
+
* @param {number[]} shape
|
|
55
|
+
* @param {number[]|Float32Array} shape_normal
|
|
56
|
+
* @param {number} shape_length
|
|
57
|
+
* @param {number[]} shape_transform
|
|
58
|
+
* @param {number} direction
|
|
59
|
+
*/
|
|
60
|
+
function make_cap_round(
|
|
61
|
+
out,
|
|
62
|
+
index,
|
|
63
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
64
|
+
shape, shape_normal, shape_length, shape_transform, direction
|
|
65
|
+
) {
|
|
66
|
+
// how many radial segments will be placed laterally to make up the cap
|
|
67
|
+
const cap_segment_count = compute_cap_round_segment_count(shape_length);
|
|
68
|
+
|
|
69
|
+
const i3 = index * 3;
|
|
70
|
+
|
|
71
|
+
const Px = in_positions[i3];
|
|
72
|
+
const Py = in_positions[i3 + 1];
|
|
73
|
+
const Pz = in_positions[i3 + 2];
|
|
74
|
+
|
|
75
|
+
// retrieve corresponding normal and binormal
|
|
76
|
+
|
|
77
|
+
const N = in_normals[index];
|
|
78
|
+
const B = in_binormals[index];
|
|
79
|
+
const T = in_tangents[index];
|
|
80
|
+
|
|
81
|
+
const tangent = new Vector3();
|
|
82
|
+
tangent.crossVectors(N, B);
|
|
83
|
+
tangent.normalize();
|
|
84
|
+
tangent.multiplyScalar(-direction);
|
|
85
|
+
|
|
86
|
+
const normal = direction > 0 ? N : N.clone().negate();
|
|
87
|
+
const binormal = direction > 0 ? B : B.clone().negate();
|
|
88
|
+
|
|
89
|
+
const angular_step_i = (Math.PI / 2) / cap_segment_count;
|
|
90
|
+
|
|
91
|
+
const uv_u = index / (in_positions.length / 3 - 1);
|
|
92
|
+
|
|
93
|
+
let i;
|
|
94
|
+
|
|
95
|
+
const index_offset = out.cursor_vertices;
|
|
96
|
+
|
|
97
|
+
const m3 = new Float32Array(9);
|
|
98
|
+
|
|
99
|
+
const radius_raw = compute_shape_radius(shape, shape_length);
|
|
100
|
+
|
|
101
|
+
// extract scale from shape matrix
|
|
102
|
+
const scale_x = Math.hypot(shape_transform[0], shape_transform[3]);
|
|
103
|
+
const scale_y = Math.hypot(shape_transform[1], shape_transform[4]);
|
|
104
|
+
|
|
105
|
+
const radius = radius_raw * max2(scale_x, scale_y);
|
|
106
|
+
|
|
107
|
+
for (i = 0; i <= cap_segment_count; i++) {
|
|
108
|
+
|
|
109
|
+
const j = direction>0? i:cap_segment_count-i;
|
|
110
|
+
|
|
111
|
+
const angle_b = j * angular_step_i ;
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
const cos_b = Math.cos(angle_b);
|
|
115
|
+
const sin_b = Math.sin(angle_b);
|
|
116
|
+
|
|
117
|
+
// build shape transform matrix that scales original shape down
|
|
118
|
+
m3_rm_compose_transform(m3, 0, 0, sin_b, sin_b, 0, 0, 0);
|
|
119
|
+
m3_multiply(m3, shape_transform, m3);
|
|
120
|
+
|
|
121
|
+
const _d = radius;
|
|
122
|
+
|
|
123
|
+
// compute offset for ring center
|
|
124
|
+
const _px = Px + tangent.x * cos_b * _d;
|
|
125
|
+
const _py = Py + tangent.y * cos_b * _d;
|
|
126
|
+
const _pz = Pz + tangent.z * cos_b * _d;
|
|
127
|
+
|
|
128
|
+
// build ring
|
|
129
|
+
// TODO normals on produced geometry are incorrect as they need to be bent along the cap
|
|
130
|
+
make_ring_vertices(
|
|
131
|
+
out,
|
|
132
|
+
_px, _py, _pz,
|
|
133
|
+
normal, binormal, tangent,
|
|
134
|
+
uv_u, v4_no_bend,
|
|
135
|
+
shape, shape_normal, shape_length, m3
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
make_ring_faces(out, index_offset, cap_segment_count, shape_length);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const m3_zero = new Float32Array(9);
|
|
143
|
+
const v4_array = new Float32Array(4);
|
|
144
|
+
|
|
145
|
+
const v4_no_bend = new Float32Array([0, 1, 0, 0]);
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
*
|
|
149
|
+
* @param {number} index
|
|
150
|
+
* @param {Float32Array|number[]} in_positions
|
|
151
|
+
* @param {Vector3[]} in_normals
|
|
152
|
+
* @param {Vector3[]} in_binormals
|
|
153
|
+
* @param {Vector3[]} in_tangents
|
|
154
|
+
* @param {GeometryOutput} out
|
|
155
|
+
* @param {number[]} shape
|
|
156
|
+
* @param {number[]|Float32Array} shape_normals
|
|
157
|
+
* @param {number} shape_length
|
|
158
|
+
* @param {number[]} shape_transform
|
|
159
|
+
* @param {number} direction
|
|
160
|
+
*/
|
|
161
|
+
function make_cap_flat(
|
|
162
|
+
out,
|
|
163
|
+
index,
|
|
164
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
165
|
+
shape, shape_normal, shape_length, shape_transform, direction
|
|
166
|
+
) {
|
|
167
|
+
// how many radial segments will be placed laterally to make up the cap
|
|
168
|
+
const i3 = index * 3;
|
|
169
|
+
|
|
170
|
+
const Px = in_positions[i3];
|
|
171
|
+
const Py = in_positions[i3 + 1];
|
|
172
|
+
const Pz = in_positions[i3 + 2];
|
|
173
|
+
|
|
174
|
+
// retrieve corresponding normal and binormal
|
|
175
|
+
|
|
176
|
+
const N = in_normals[index];
|
|
177
|
+
const B = in_binormals[index];
|
|
178
|
+
|
|
179
|
+
const tangent = new Vector3();
|
|
180
|
+
tangent.crossVectors(N, B);
|
|
181
|
+
tangent.normalize();
|
|
182
|
+
|
|
183
|
+
const normal = direction > 0 ? N.clone().negate() : N;
|
|
184
|
+
|
|
185
|
+
const uv_u = index / (in_positions.length / 3 - 1);
|
|
186
|
+
|
|
187
|
+
const index_offset = out.cursor_vertices;
|
|
188
|
+
|
|
189
|
+
make_ring_vertices(
|
|
190
|
+
out,
|
|
191
|
+
Px, Py, Pz,
|
|
192
|
+
normal, B, in_tangents[index],
|
|
193
|
+
uv_u, v4_no_bend,
|
|
194
|
+
shape, shape_normal, shape_length, shape_transform
|
|
195
|
+
);
|
|
196
|
+
|
|
197
|
+
make_ring_vertices(
|
|
198
|
+
out,
|
|
199
|
+
Px, Py, Pz,
|
|
200
|
+
normal, B, in_tangents[index],
|
|
201
|
+
uv_u, v4_no_bend,
|
|
202
|
+
shape, shape_normal, shape_length, m3_zero
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
make_ring_faces(out, index_offset, 1, shape_length);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
*
|
|
210
|
+
* @param {number} index
|
|
211
|
+
* @param {Float32Array|number[]} in_positions
|
|
212
|
+
* @param {Vector3[]} in_normals
|
|
213
|
+
* @param {Vector3[]} in_binormals
|
|
214
|
+
* @param {GeometryOutput} out
|
|
215
|
+
* @param {Vector3[]} in_tangents
|
|
216
|
+
* @param {number[]} shape
|
|
217
|
+
* @param {number[]|Float32Array} shape_normal
|
|
218
|
+
* @param {number} shape_length
|
|
219
|
+
* @param {number[]|Float32Array} shape_transform
|
|
220
|
+
* @param {number} direction
|
|
221
|
+
* @param {CapType} type
|
|
222
|
+
*/
|
|
223
|
+
export function make_cap(
|
|
224
|
+
out,
|
|
225
|
+
index,
|
|
226
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
227
|
+
shape, shape_normal, shape_length, shape_transform, direction, type
|
|
228
|
+
) {
|
|
229
|
+
if (type === CapType.None) {
|
|
230
|
+
// do nothing
|
|
231
|
+
} else if (type === CapType.Round) {
|
|
232
|
+
make_cap_round(
|
|
233
|
+
out,
|
|
234
|
+
index,
|
|
235
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
236
|
+
shape, shape_normal, shape_length, shape_transform,
|
|
237
|
+
direction
|
|
238
|
+
);
|
|
239
|
+
} else if (type === CapType.Flat) {
|
|
240
|
+
make_cap_flat(
|
|
241
|
+
out,
|
|
242
|
+
index,
|
|
243
|
+
in_positions, in_normals, in_binormals, in_tangents,
|
|
244
|
+
shape, shape_normal, shape_length, shape_transform,
|
|
245
|
+
direction
|
|
246
|
+
);
|
|
247
|
+
} else {
|
|
248
|
+
throw new Error(`Unsupported cap type '${type}'`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
*
|
|
254
|
+
* @param {number} count how many caps
|
|
255
|
+
* @param {{polygon_count:number, vertex_count:number}} out
|
|
256
|
+
* @param {number} radial_segments
|
|
257
|
+
* @param {CapType} type
|
|
258
|
+
*/
|
|
259
|
+
export function compute_cap_geometry_size(count, out, radial_segments, type) {
|
|
260
|
+
|
|
261
|
+
if (type === CapType.None) {
|
|
262
|
+
// do nothing
|
|
263
|
+
} else if (type === CapType.Round) {
|
|
264
|
+
const cap_segment_count = compute_cap_round_segment_count(radial_segments);
|
|
265
|
+
|
|
266
|
+
out.vertex_count += count * (cap_segment_count + 1) * (radial_segments + 1);
|
|
267
|
+
out.polygon_count += count * cap_segment_count * (radial_segments) * 2;
|
|
268
|
+
} else if (type === CapType.Flat) {
|
|
269
|
+
out.vertex_count += count * (2) * (radial_segments + 1);
|
|
270
|
+
out.polygon_count += count * (radial_segments) * 2;
|
|
271
|
+
} else {
|
|
272
|
+
throw new Error(`Unsupported cap type '${type}'`);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* @param {GeometryOutput} out
|
|
4
|
+
* @param {number} index_offset
|
|
5
|
+
* @param {number} path_segments
|
|
6
|
+
* @param {number} profile_segments
|
|
7
|
+
*/
|
|
8
|
+
export function make_ring_faces(out, index_offset, path_segments, profile_segments) {
|
|
9
|
+
const indices = out.indices;
|
|
10
|
+
|
|
11
|
+
let i = 0, j = 0;
|
|
12
|
+
|
|
13
|
+
for (j = 1; j <= path_segments; j++) {
|
|
14
|
+
|
|
15
|
+
for (i = 1; i <= profile_segments; i++) {
|
|
16
|
+
|
|
17
|
+
const s_1 = profile_segments + 1;
|
|
18
|
+
|
|
19
|
+
const a = index_offset + s_1 * (j - 1) + (i - 1);
|
|
20
|
+
const b = index_offset + s_1 * j + (i - 1);
|
|
21
|
+
const c = index_offset + s_1 * j + i;
|
|
22
|
+
const d = index_offset + s_1 * (j - 1) + i;
|
|
23
|
+
|
|
24
|
+
// faces
|
|
25
|
+
|
|
26
|
+
const ci = out.cursor_indices;
|
|
27
|
+
|
|
28
|
+
indices[ci] = a;
|
|
29
|
+
indices[ci + 1] = b;
|
|
30
|
+
indices[ci + 2] = d;
|
|
31
|
+
|
|
32
|
+
indices[ci + 3] = b;
|
|
33
|
+
indices[ci + 4] = c;
|
|
34
|
+
indices[ci + 5] = d;
|
|
35
|
+
|
|
36
|
+
out.cursor_indices += 6;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
//
|
|
2
|
+
|
|
3
|
+
import { v3_dot } from "../../../../../../core/geom/v3_dot.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {GeometryOutput} out
|
|
8
|
+
* @param {number} Px
|
|
9
|
+
* @param {number} Py
|
|
10
|
+
* @param {number} Pz
|
|
11
|
+
* @param {Vector3} N normal
|
|
12
|
+
* @param {Vector3} B binormal
|
|
13
|
+
* @param {Vector3} T tangent
|
|
14
|
+
* @param {number} u X component of UV
|
|
15
|
+
* @param {number[]|Float32Array} bend_angle
|
|
16
|
+
* @param {number[]|Float32Array} shape 2d shape, format [x0,y1, x1,y1, ... , xN,yN]
|
|
17
|
+
* @param {number[]|Float32Array} shape_normals
|
|
18
|
+
* @param {number} shape_length number of points in the shape
|
|
19
|
+
* @param {number[]|Float32Array} shape_transform 3x3 2d transform matrix for shape Note that matrix uses row-major order
|
|
20
|
+
*/
|
|
21
|
+
export function make_ring_vertices(
|
|
22
|
+
out,
|
|
23
|
+
Px, Py, Pz,
|
|
24
|
+
N, B, T,
|
|
25
|
+
u, bend_angle,
|
|
26
|
+
shape, shape_normals, shape_length,
|
|
27
|
+
shape_transform
|
|
28
|
+
) {
|
|
29
|
+
const out_positions = out.positions;
|
|
30
|
+
const out_normals = out.normals;
|
|
31
|
+
const out_uvs = out.uvs;
|
|
32
|
+
|
|
33
|
+
for (let i = 0; i <= shape_length; i++) {
|
|
34
|
+
const j = i % shape_length;
|
|
35
|
+
const i2 = j * 2;
|
|
36
|
+
|
|
37
|
+
const shape_x = shape[i2];
|
|
38
|
+
const shape_y = shape[i2 + 1];
|
|
39
|
+
|
|
40
|
+
// apply transform to the shape
|
|
41
|
+
const tx = shape_transform[0] * shape_x + shape_transform[3] * shape_y + shape_transform[6];
|
|
42
|
+
const ty = shape_transform[1] * shape_x + shape_transform[4] * shape_y + shape_transform[7];
|
|
43
|
+
|
|
44
|
+
const b_sin_x = ty * N.x;
|
|
45
|
+
const b_sin_y = ty * N.y;
|
|
46
|
+
const b_sin_z = ty * N.z;
|
|
47
|
+
|
|
48
|
+
const n_cos_x = tx * B.x;
|
|
49
|
+
const n_cos_y = tx * B.y;
|
|
50
|
+
const n_cos_z = tx * B.z;
|
|
51
|
+
|
|
52
|
+
// compute radial normal
|
|
53
|
+
const radial_normal_x_raw = (n_cos_x - b_sin_x);
|
|
54
|
+
const radial_normal_y_raw = (n_cos_y - b_sin_y);
|
|
55
|
+
const radial_normal_z_raw = (n_cos_z - b_sin_z);
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
const radial_normal_magnitude = Math.hypot(radial_normal_x_raw, radial_normal_y_raw, radial_normal_z_raw);
|
|
59
|
+
|
|
60
|
+
let normal_x;
|
|
61
|
+
let normal_y;
|
|
62
|
+
let normal_z;
|
|
63
|
+
|
|
64
|
+
if (radial_normal_magnitude !== 0) {
|
|
65
|
+
|
|
66
|
+
const normalization_factor = 1 / radial_normal_magnitude;
|
|
67
|
+
|
|
68
|
+
// re-normalize and compensate by bending angle
|
|
69
|
+
normal_x = radial_normal_x_raw * normalization_factor;
|
|
70
|
+
normal_y = radial_normal_y_raw * normalization_factor;
|
|
71
|
+
normal_z = radial_normal_z_raw * normalization_factor;
|
|
72
|
+
|
|
73
|
+
} else {
|
|
74
|
+
// normal would be 0 and produce NaNs, apply arbitrary offset
|
|
75
|
+
normal_x = T.x;
|
|
76
|
+
normal_y = T.y;
|
|
77
|
+
normal_z = T.z;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const shape_normal_x = shape_normals[i2];
|
|
81
|
+
const shape_normal_y = shape_normals[i2 + 1];
|
|
82
|
+
|
|
83
|
+
const t_nx = shape_transform[0] * shape_normal_x + shape_transform[3] * shape_normal_y + shape_transform[6];
|
|
84
|
+
const t_ny = shape_transform[1] * shape_normal_x + shape_transform[4] * shape_normal_y + shape_transform[7];
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
const nb_sin_x = t_ny * N.x;
|
|
88
|
+
const nb_sin_y = t_ny * N.y;
|
|
89
|
+
const nb_sin_z = t_ny * N.z;
|
|
90
|
+
|
|
91
|
+
const nn_cos_x = t_nx * B.x;
|
|
92
|
+
const nn_cos_y = t_nx * B.y;
|
|
93
|
+
const nn_cos_z = t_nx * B.z;
|
|
94
|
+
|
|
95
|
+
const n_normal_x_raw = (-nn_cos_x - nb_sin_x);
|
|
96
|
+
const n_normal_y_raw = (-nn_cos_y - nb_sin_y);
|
|
97
|
+
const n_normal_z_raw = (-nn_cos_z - nb_sin_z);
|
|
98
|
+
|
|
99
|
+
const n_normal_magnitude = Math.hypot(n_normal_x_raw, n_normal_y_raw, n_normal_z_raw);
|
|
100
|
+
|
|
101
|
+
const cv = out.cursor_vertices;
|
|
102
|
+
const cv3 = cv * 3;
|
|
103
|
+
|
|
104
|
+
if(n_normal_magnitude !== 0){
|
|
105
|
+
out_normals[cv3] = n_normal_x_raw / n_normal_magnitude;
|
|
106
|
+
out_normals[cv3 + 1] = n_normal_y_raw / n_normal_magnitude;
|
|
107
|
+
out_normals[cv3 + 2] = n_normal_z_raw / n_normal_magnitude;
|
|
108
|
+
}else {
|
|
109
|
+
|
|
110
|
+
out_normals[cv3] = T.x;
|
|
111
|
+
out_normals[cv3 + 1] = T.y;
|
|
112
|
+
out_normals[cv3 + 2] = T.z;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let bend_magnitude = 1;
|
|
116
|
+
|
|
117
|
+
// rotate bend normal by 90deg
|
|
118
|
+
|
|
119
|
+
const cross_x = bend_angle[1] * T.z - bend_angle[2] * T.y;
|
|
120
|
+
const cross_y = bend_angle[2] * T.x - bend_angle[0] * T.z;
|
|
121
|
+
const cross_z = bend_angle[0] * T.y - bend_angle[1] * T.x;
|
|
122
|
+
|
|
123
|
+
const rotated_bend_normal_length = Math.hypot(cross_x, cross_y, cross_z);
|
|
124
|
+
const bend_normal_length_inv = 1 / rotated_bend_normal_length;
|
|
125
|
+
|
|
126
|
+
// apply bend angle
|
|
127
|
+
const dot = v3_dot(
|
|
128
|
+
cross_x * bend_normal_length_inv, cross_y * bend_normal_length_inv, cross_z * bend_normal_length_inv,
|
|
129
|
+
normal_x, normal_y, normal_z
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
bend_magnitude += Math.abs(dot) * bend_angle[3];
|
|
133
|
+
|
|
134
|
+
// compute vertex position
|
|
135
|
+
const vx = Px + radial_normal_x_raw * bend_magnitude;
|
|
136
|
+
const vy = Py + radial_normal_y_raw * bend_magnitude;
|
|
137
|
+
const vz = Pz + radial_normal_z_raw * bend_magnitude;
|
|
138
|
+
|
|
139
|
+
out_positions[cv3] = vx;
|
|
140
|
+
out_positions[cv3 + 1] = vy;
|
|
141
|
+
out_positions[cv3 + 2] = vz;
|
|
142
|
+
|
|
143
|
+
// UV
|
|
144
|
+
const cv2 = cv * 2;
|
|
145
|
+
|
|
146
|
+
out_uvs[cv2] = u;
|
|
147
|
+
out_uvs[cv2 + 1] = i / shape_length;
|
|
148
|
+
|
|
149
|
+
out.cursor_vertices++;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"productName": "Meep",
|
|
6
6
|
"description": "production-ready JavaScript game engine based on Entity Component System Architecture",
|
|
7
7
|
"author": "Alexander Goldring",
|
|
8
|
-
"version": "2.
|
|
8
|
+
"version": "2.39.1",
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"gl-matrix": "3.4.3",
|
|
11
11
|
"fast-levenshtein": "2.0.6",
|
package/view/View.js
CHANGED
|
@@ -10,7 +10,7 @@ import Signal from "../core/events/signal/Signal.js";
|
|
|
10
10
|
import { SignalBinding } from "../core/events/signal/SignalBinding.js";
|
|
11
11
|
import { assert } from "../core/assert.js";
|
|
12
12
|
import Vector1 from "../core/geom/Vector1.js";
|
|
13
|
-
import {
|
|
13
|
+
import { m3_cm_compose_transform } from "./m3_cm_compose_transform.js";
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
const scratch_m3_0 = new Float32Array(9);
|
|
@@ -26,7 +26,7 @@ function setElementTransform(domElement, position, scale, rotation) {
|
|
|
26
26
|
|
|
27
27
|
const m3 = scratch_m3_0;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
m3_cm_compose_transform(m3, position.x, position.y, scale.x, scale.y,0,0, rotation);
|
|
30
30
|
|
|
31
31
|
|
|
32
32
|
/*
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
+
* Composes column-major transform matrix
|
|
3
|
+
* Column-major matrices are used in CSS
|
|
2
4
|
*
|
|
3
5
|
* @param {number[]|Float32Array} result
|
|
4
6
|
* @param {number} tX translation X offset
|
|
@@ -9,7 +11,13 @@
|
|
|
9
11
|
* @param {number} cy center of rotation Y
|
|
10
12
|
* @param {number} angle rotation angle
|
|
11
13
|
*/
|
|
12
|
-
export function
|
|
14
|
+
export function m3_cm_compose_transform(
|
|
15
|
+
result,
|
|
16
|
+
tX, tY,
|
|
17
|
+
sX, sY,
|
|
18
|
+
cx, cy,
|
|
19
|
+
angle
|
|
20
|
+
) {
|
|
13
21
|
const neg_angle = -angle;
|
|
14
22
|
|
|
15
23
|
const sin = Math.sin(neg_angle);
|
|
@@ -34,7 +42,7 @@ export function compose3x3transform(result, tX, tY, sX, sY, cx, cy, angle) {
|
|
|
34
42
|
* @param {number} tX
|
|
35
43
|
* @param {number} tY
|
|
36
44
|
*/
|
|
37
|
-
export function
|
|
45
|
+
export function m3_cm_from_translation(result, tX, tY) {
|
|
38
46
|
result[0] = 1;
|
|
39
47
|
result[1] = 0;
|
|
40
48
|
result[2] = tX;
|
|
@@ -53,6 +61,6 @@ export function m3_from_translation(result, tX, tY) {
|
|
|
53
61
|
* @param {mat3|number[]|Float32Array} m3
|
|
54
62
|
* @returns {number}
|
|
55
63
|
*/
|
|
56
|
-
export function
|
|
64
|
+
export function m3_cm_extract_rotation(m3) {
|
|
57
65
|
return Math.atan2(m3[3], m3[0]);
|
|
58
66
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Composes row-major transform matrix, row-major format is used in OpenGL
|
|
3
|
+
*
|
|
4
|
+
* @param {number[]|Float32Array} result
|
|
5
|
+
* @param {number} tX translation X offset
|
|
6
|
+
* @param {number} tY translation Y offset
|
|
7
|
+
* @param {number} sX scale in X axis
|
|
8
|
+
* @param {number} sY scale in Y axis
|
|
9
|
+
* @param {number} cx center of rotation X
|
|
10
|
+
* @param {number} cy center of rotation Y
|
|
11
|
+
* @param {number} angle rotation angle
|
|
12
|
+
*/
|
|
13
|
+
export function m3_rm_compose_transform(
|
|
14
|
+
result,
|
|
15
|
+
tX, tY,
|
|
16
|
+
sX, sY,
|
|
17
|
+
cx, cy,
|
|
18
|
+
angle
|
|
19
|
+
) {
|
|
20
|
+
const neg_angle = -angle;
|
|
21
|
+
|
|
22
|
+
const sin = Math.sin(neg_angle);
|
|
23
|
+
const cos = Math.cos(neg_angle);
|
|
24
|
+
|
|
25
|
+
result[0] = sX * cos;
|
|
26
|
+
result[3] = sX * sin;
|
|
27
|
+
result[6] = -sX * (cos * cx + sin * cy) + cx + tX;
|
|
28
|
+
|
|
29
|
+
result[1] = -sY * sin;
|
|
30
|
+
result[4] = sY * cos;
|
|
31
|
+
result[7] = -sY * (-sin * cx + cos * cy) + cy + tY;
|
|
32
|
+
|
|
33
|
+
result[2] = 0;
|
|
34
|
+
result[5] = 0;
|
|
35
|
+
result[8] = 1;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
export function m3_rm_extract_scale(result, m3) {
|
|
40
|
+
const scale_x = Math.hypot(m3[0], m3[3]);
|
|
41
|
+
const scale_y = Math.hypot(m3[1], m3[4]);
|
|
42
|
+
|
|
43
|
+
result[0] = scale_x;
|
|
44
|
+
result[1] = scale_y;
|
|
45
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Performs matrix multiplication of 3x3 matrices
|
|
3
3
|
* r = a * b
|
|
4
|
-
* @param {number[]} a first matrix
|
|
5
|
-
* @param {number[]} b second matrix
|
|
6
|
-
* @param {number[]} r result matrix
|
|
4
|
+
* @param {number[]|Float32Array} a first matrix
|
|
5
|
+
* @param {number[]|Float32Array} b second matrix
|
|
6
|
+
* @param {number[]|Float32Array} r result matrix
|
|
7
7
|
*/
|
|
8
|
-
export function
|
|
8
|
+
export function m3_multiply(a, b, r) {
|
|
9
9
|
//read out values of input matrices to support the case where result is written back into one of the inputs
|
|
10
10
|
const a0 = a[0];
|
|
11
11
|
const a1 = a[1];
|