@woosh/meep-engine 2.163.0 → 2.163.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/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "description": "Pure JavaScript game engine. Fully featured and production ready.",
7
7
  "type": "module",
8
8
  "author": "Alexander Goldring",
9
- "version": "2.163.0",
9
+ "version": "2.163.1",
10
10
  "main": "build/meep.module.js",
11
11
  "module": "build/meep.module.js",
12
12
  "exports": {
@@ -1,202 +1,218 @@
1
- import { BufferGeometry, Vector3 } from "three";
2
- import { assert } from "../../../../../../core/assert.js";
3
- import { v3_angle_cos_between } from "../../../../../../core/geom/vec3/v3_angle_cos_between.js";
4
- import { v3_length } from "../../../../../../core/geom/vec3/v3_length.js";
5
- import { CapType } from "../CapType.js";
6
- import { append_compute_cap_geometry_size, make_cap } from "./make_cap.js";
7
- import { make_ring_faces } from "./make_ring_faces.js";
8
- import { make_ring_vertices } from "./make_ring_vertices.js";
9
- import { StreamGeometryBuilder } from "./StreamGeometryBuilder.js";
10
-
11
-
12
- const v4_array = new Float32Array(4);
13
-
14
- /**
15
- * @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
16
- * @see https://github.com/hofk/THREEg.js/blob/488f1128a25321a76888aa1fa19db64750318444/THREEg.js#L3483
17
- * @param {Float32Array|number[]} in_positions
18
- * @param {Vector3[]} in_normals
19
- * @param {Vector3[]} in_binormals
20
- * @param {Vector3[]} in_tangents
21
- * @param {number[]} shape
22
- * @param {number[]|Float32Array} shape_normal
23
- * @param {number} shape_length
24
- * @param {number[]|Float32Array} shape_transform
25
- * @param {boolean} [closed]
26
- * @param {CapType} [cap_type]
27
- * @returns {BufferGeometry}
28
- */
29
- export function makeTubeGeometry(
30
- in_positions, in_normals, in_binormals, in_tangents,
31
- shape, shape_normal, shape_length, shape_transform, closed = false, cap_type = CapType.Round
32
- ) {
33
- assert.enum(cap_type, CapType, 'cap_type');
34
- assert.isBoolean(closed, 'closed');
35
-
36
- assert.isNumber(shape_length, 'shape_length');
37
- assert.isArrayLike(shape, 'shape');
38
-
39
- const out = new StreamGeometryBuilder();
40
-
41
- // helper variables
42
-
43
- const point_count = in_positions.length / 3;
44
- const tubular_segments = point_count - 1;
45
-
46
-
47
- const geometry_size = {
48
- vertex_count: (tubular_segments + 1) * (shape_length + 1),
49
- polygon_count: tubular_segments * shape_length * 2
50
- };
51
-
52
- if (!closed) {
53
- append_compute_cap_geometry_size(2, geometry_size, shape_length, cap_type);
54
- }
55
-
56
- out.allocate(
57
- geometry_size.vertex_count,
58
- geometry_size.polygon_count
59
- );
60
-
61
- // create buffer data
62
-
63
- if (!closed) {
64
- // start cap
65
- make_cap(
66
- out, 0,
67
- in_positions, in_normals, in_binormals, in_tangents,
68
- shape, shape_normal, shape_length, shape_transform, 1, cap_type
69
- );
70
- }
71
-
72
- const index_offset = out.cursor_vertices;
73
-
74
- for (let i = 0; i < tubular_segments; i++) {
75
-
76
- generateSegment(i);
77
-
78
- }
79
-
80
- // if the geometry is not closed, generate the last row of vertices and normals
81
- // at the regular position on the given path
82
- //
83
- // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
84
-
85
- generateSegment((closed === false) ? tubular_segments : 0);
86
-
87
- // finally create faces
88
- make_ring_faces(out, index_offset, tubular_segments, shape_length);
89
-
90
- if (!closed) {
91
- // end cap
92
- make_cap(
93
- out, point_count - 1,
94
- in_positions, in_normals, in_binormals, in_tangents,
95
- shape, shape_normal, shape_length, shape_transform, -1, cap_type
96
- );
97
- }
98
-
99
- /**
100
- *
101
- * @param {number} i
102
- */
103
- function generateSegment(i) {
104
-
105
- // we use getPointAt to sample evenly distributed points from the given path
106
-
107
- const i3 = i * 3;
108
-
109
- const Px = in_positions[i3];
110
- const Py = in_positions[i3 + 1];
111
- const Pz = in_positions[i3 + 2];
112
-
113
- // retrieve corresponding normal and binormal
114
-
115
- const N = in_normals[i];
116
- const B = in_binormals[i];
117
-
118
- // generate normals and vertices for the current segment
119
- compute_bend_normal(v4_array, i, tubular_segments, in_positions);
120
-
121
- make_ring_vertices(
122
- out,
123
- Px, Py, Pz,
124
- N, B, in_tangents[i],
125
- i / tubular_segments, v4_array,
126
- shape, shape_normal, shape_length, shape_transform
127
- );
128
-
129
- }
130
-
131
-
132
- return out.build();
133
- }
134
-
135
-
136
- /**
137
- *
138
- * @param {number[]|Float32Array} out
139
- * @param {number} index
140
- * @param {number} index_count
141
- * @param {number[]|Float32Array} positions
142
- */
143
- function compute_bend_normal(
144
- out,
145
- index,
146
- index_count,
147
- positions
148
- ) {
149
- if (index <= 0 || index >= index_count - 1) {
150
- // end points, no bending
151
-
152
- out[0] = 0;
153
- out[1] = 1;
154
- out[2] = 0;
155
- out[3] = 0;
156
-
157
- return;
158
- }
159
-
160
- const index_next = index + 1;
161
- const index_prev = index - 1;
162
-
163
- const address_current = index * 3;
164
- const address_next = index_next * 3;
165
- const address_prev = index_prev * 3;
166
-
167
- const i0_x = positions[address_prev];
168
- const i0_y = positions[address_prev + 1];
169
- const i0_z = positions[address_prev + 2];
170
-
171
- const i1_x = positions[address_current];
172
- const i1_y = positions[address_current + 1];
173
- const i1_z = positions[address_current + 2];
174
-
175
- const i2_x = positions[address_next];
176
- const i2_y = positions[address_next + 1];
177
- const i2_z = positions[address_next + 2];
178
-
179
- const d0_x = i0_x - i1_x;
180
- const d0_y = i0_y - i1_y;
181
- const d0_z = i0_z - i1_z;
182
-
183
- const d1_x = i1_x - i2_x;
184
- const d1_y = i1_y - i2_y;
185
- const d1_z = i1_z - i2_z;
186
-
187
- // compute rotation axis
188
- const cross_x = d0_y * d1_z - d0_z * d1_y;
189
- const cross_y = d0_z * d1_x - d0_x * d1_z;
190
- const cross_z = d0_x * d1_y - d0_y * d1_x;
191
-
192
- const angle = v3_angle_cos_between(d0_x, d0_y, d0_z, d1_x, d1_y, d1_z);
193
-
194
- const length_inv = 1 / v3_length(cross_x, cross_y, cross_z);
195
-
196
- out[0] = cross_x * length_inv;
197
- out[1] = cross_y * length_inv;
198
- out[2] = cross_z * length_inv;
199
-
200
- // bend amount
201
- out[3] = (1 - Math.abs(angle)) * 0.5;
202
- }
1
+ import { BufferGeometry, Vector3 } from "three";
2
+ import { assert } from "../../../../../../core/assert.js";
3
+ import { v3_angle_cos_between } from "../../../../../../core/geom/vec3/v3_angle_cos_between.js";
4
+ import { v3_length } from "../../../../../../core/geom/vec3/v3_length.js";
5
+ import { CapType } from "../CapType.js";
6
+ import { append_compute_cap_geometry_size, make_cap } from "./make_cap.js";
7
+ import { make_ring_faces } from "./make_ring_faces.js";
8
+ import { make_ring_vertices } from "./make_ring_vertices.js";
9
+ import { StreamGeometryBuilder } from "./StreamGeometryBuilder.js";
10
+
11
+
12
+ const v4_array = new Float32Array(4);
13
+
14
+ /**
15
+ * @see https://github.com/mrdoob/three.js/blob/master/src/geometries/TubeGeometry.js
16
+ * @see https://github.com/hofk/THREEg.js/blob/488f1128a25321a76888aa1fa19db64750318444/THREEg.js#L3483
17
+ * @param {Float32Array|number[]} in_positions
18
+ * @param {Vector3[]} in_normals
19
+ * @param {Vector3[]} in_binormals
20
+ * @param {Vector3[]} in_tangents
21
+ * @param {number[]} shape
22
+ * @param {number[]|Float32Array} shape_normal
23
+ * @param {number} shape_length
24
+ * @param {number[]|Float32Array} shape_transform
25
+ * @param {boolean} [closed]
26
+ * @param {CapType} [cap_type]
27
+ * @returns {BufferGeometry}
28
+ */
29
+ export function makeTubeGeometry(
30
+ in_positions, in_normals, in_binormals, in_tangents,
31
+ shape, shape_normal, shape_length, shape_transform, closed = false, cap_type = CapType.Round
32
+ ) {
33
+ assert.enum(cap_type, CapType, 'cap_type');
34
+ assert.isBoolean(closed, 'closed');
35
+
36
+ assert.isNumber(shape_length, 'shape_length');
37
+ assert.isArrayLike(shape, 'shape');
38
+
39
+ const out = new StreamGeometryBuilder();
40
+
41
+ // helper variables
42
+
43
+ const point_count = in_positions.length / 3;
44
+ const tubular_segments = point_count - 1;
45
+
46
+
47
+ const geometry_size = {
48
+ vertex_count: (tubular_segments + 1) * (shape_length + 1),
49
+ polygon_count: tubular_segments * shape_length * 2
50
+ };
51
+
52
+ if (!closed) {
53
+ append_compute_cap_geometry_size(2, geometry_size, shape_length, cap_type);
54
+ }
55
+
56
+ out.allocate(
57
+ geometry_size.vertex_count,
58
+ geometry_size.polygon_count
59
+ );
60
+
61
+ // create buffer data
62
+
63
+ if (!closed) {
64
+ // start cap
65
+ make_cap(
66
+ out, 0,
67
+ in_positions, in_normals, in_binormals, in_tangents,
68
+ shape, shape_normal, shape_length, shape_transform, 1, cap_type
69
+ );
70
+ }
71
+
72
+ const index_offset = out.cursor_vertices;
73
+
74
+ for (let i = 0; i < tubular_segments; i++) {
75
+
76
+ generateSegment(i);
77
+
78
+ }
79
+
80
+ // if the geometry is not closed, generate the last row of vertices and normals
81
+ // at the regular position on the given path
82
+ //
83
+ // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
84
+
85
+ generateSegment((closed === false) ? tubular_segments : 0);
86
+
87
+ // finally create faces
88
+ make_ring_faces(out, index_offset, tubular_segments, shape_length);
89
+
90
+ if (!closed) {
91
+ // end cap
92
+ make_cap(
93
+ out, point_count - 1,
94
+ in_positions, in_normals, in_binormals, in_tangents,
95
+ shape, shape_normal, shape_length, shape_transform, -1, cap_type
96
+ );
97
+ }
98
+
99
+ /**
100
+ *
101
+ * @param {number} i
102
+ */
103
+ function generateSegment(i) {
104
+
105
+ // we use getPointAt to sample evenly distributed points from the given path
106
+
107
+ const i3 = i * 3;
108
+
109
+ const Px = in_positions[i3];
110
+ const Py = in_positions[i3 + 1];
111
+ const Pz = in_positions[i3 + 2];
112
+
113
+ // retrieve corresponding normal and binormal
114
+
115
+ const N = in_normals[i];
116
+ const B = in_binormals[i];
117
+
118
+ // generate normals and vertices for the current segment
119
+ compute_bend_normal(v4_array, i, tubular_segments, in_positions);
120
+
121
+ make_ring_vertices(
122
+ out,
123
+ Px, Py, Pz,
124
+ N, B, in_tangents[i],
125
+ i / tubular_segments, v4_array,
126
+ shape, shape_normal, shape_length, shape_transform
127
+ );
128
+
129
+ }
130
+
131
+
132
+ return out.build();
133
+ }
134
+
135
+
136
+ /**
137
+ *
138
+ * @param {number[]|Float32Array} out
139
+ * @param {number} index
140
+ * @param {number} index_count
141
+ * @param {number[]|Float32Array} positions
142
+ */
143
+ function compute_bend_normal(
144
+ out,
145
+ index,
146
+ index_count,
147
+ positions
148
+ ) {
149
+ if (index <= 0 || index >= index_count - 1) {
150
+ // end points, no bending
151
+
152
+ out[0] = 0;
153
+ out[1] = 1;
154
+ out[2] = 0;
155
+ out[3] = 0;
156
+
157
+ return;
158
+ }
159
+
160
+ const index_next = index + 1;
161
+ const index_prev = index - 1;
162
+
163
+ const address_current = index * 3;
164
+ const address_next = index_next * 3;
165
+ const address_prev = index_prev * 3;
166
+
167
+ const i0_x = positions[address_prev];
168
+ const i0_y = positions[address_prev + 1];
169
+ const i0_z = positions[address_prev + 2];
170
+
171
+ const i1_x = positions[address_current];
172
+ const i1_y = positions[address_current + 1];
173
+ const i1_z = positions[address_current + 2];
174
+
175
+ const i2_x = positions[address_next];
176
+ const i2_y = positions[address_next + 1];
177
+ const i2_z = positions[address_next + 2];
178
+
179
+ const d0_x = i0_x - i1_x;
180
+ const d0_y = i0_y - i1_y;
181
+ const d0_z = i0_z - i1_z;
182
+
183
+ const d1_x = i1_x - i2_x;
184
+ const d1_y = i1_y - i2_y;
185
+ const d1_z = i1_z - i2_z;
186
+
187
+ // compute rotation axis
188
+ const cross_x = d0_y * d1_z - d0_z * d1_y;
189
+ const cross_y = d0_z * d1_x - d0_x * d1_z;
190
+ const cross_z = d0_x * d1_y - d0_y * d1_x;
191
+
192
+ const angle = v3_angle_cos_between(d0_x, d0_y, d0_z, d1_x, d1_y, d1_z);
193
+
194
+ const cross_length = v3_length(cross_x, cross_y, cross_z);
195
+
196
+ if (cross_length < 1e-10) {
197
+ // Collinear (or duplicate) neighbours: zero curvature, so no bend.
198
+ // The rotation axis is undefined here and computing it would be
199
+ // 0 / 0 = NaN, poisoning this ring's vertices (visible as shattered
200
+ // geometry on short / straight resampled segments, e.g. the animated
201
+ // marching dashes). Emit the same no-bend value the path ends use.
202
+ out[0] = 0;
203
+ out[1] = 1;
204
+ out[2] = 0;
205
+ out[3] = 0;
206
+
207
+ return;
208
+ }
209
+
210
+ const length_inv = 1 / cross_length;
211
+
212
+ out[0] = cross_x * length_inv;
213
+ out[1] = cross_y * length_inv;
214
+ out[2] = cross_z * length_inv;
215
+
216
+ // bend amount
217
+ out[3] = (1 - Math.abs(angle)) * 0.5;
218
+ }