@carbonenginejs/core-math 0.1.0

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.
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Small WebGL numeric constants used by the typed-array pool helpers.
3
+ *
4
+ * These are duplicated here to keep core-math standalone and browser-friendly:
5
+ * importing the old ccpwgl `constant` alias would pull the package back toward
6
+ * an application-specific module graph.
7
+ */
8
+
9
+ export const GL_BYTE = 5120;
10
+ export const GL_UNSIGNED_BYTE = 5121;
11
+ export const GL_SHORT = 5122;
12
+ export const GL_UNSIGNED_SHORT = 5123;
13
+ export const GL_INT = 5124;
14
+ export const GL_UNSIGNED_INT = 5125;
15
+ export const GL_FLOAT = 5126;
16
+
package/src/curve.js ADDED
@@ -0,0 +1,390 @@
1
+ export const curve = {};
2
+
3
+ /**
4
+ * Evaluates a curve
5
+ *
6
+ * @param {{}|Tw2GeometryCurve} curve
7
+ * @param {Array} curve.knots
8
+ * @param {number} curve.degree
9
+ * @param {Array} curve.controls
10
+ * @param {number} curve.dimension
11
+ * @param {number} time
12
+ * @param {*} value
13
+ * @param {Boolean} cycle
14
+ * @param {number} duration
15
+ */
16
+ curve.evaluate = function(curve, time, value, cycle, duration)
17
+ {
18
+ let count = curve.knots.length;
19
+ let knot = count - 1;
20
+ let t = 0;
21
+ for (let i = 0; i < curve.knots.length; ++i)
22
+ {
23
+ if (curve.knots[i] > time)
24
+ {
25
+ knot = i;
26
+ break;
27
+ }
28
+ }
29
+
30
+ if (curve.degree === 0)
31
+ {
32
+ for (let i = 0; i < curve.dimension; ++i)
33
+ {
34
+ value[i] = curve.controls[knot * curve.dimension + i];
35
+ }
36
+ }
37
+ else if (curve.degree === 1)
38
+ {
39
+ let knot0 = cycle ? (knot + count - 1) % count : knot === 0 ? 0 : knot - 1;
40
+ let dt = curve.knots[knot] - curve.knots[knot0];
41
+
42
+ if (dt < 0)
43
+ {
44
+ dt += duration;
45
+ }
46
+
47
+ if (dt > 0)
48
+ {
49
+ t = (time - curve.knots[curve.knots.length - 1]) / dt;
50
+ }
51
+
52
+ for (let i = 0; i < curve.dimension; ++i)
53
+ {
54
+ value[i] = curve.controls[knot0 * curve.dimension + i] * (1 - t) + curve.controls[knot * curve.dimension + i] * t;
55
+ }
56
+ }
57
+ else
58
+ {
59
+ let k_2 = cycle ? (knot + count - 2) % count : knot === 0 ? 0 : knot - 2;
60
+ let k_1 = cycle ? (knot + count - 1) % count : knot === 0 ? 0 : knot - 1;
61
+
62
+ let p1 = (k_2) * curve.dimension;
63
+ let p2 = (k_1) * curve.dimension;
64
+ let p3 = knot * curve.dimension;
65
+
66
+ let ti_2 = curve.knots[k_2];
67
+ let ti_1 = curve.knots[k_1];
68
+ let ti = curve.knots[knot];
69
+ let ti1 = curve.knots[(knot + 1) % count];
70
+
71
+ if (ti_2 > ti)
72
+ {
73
+ ti += duration;
74
+ ti1 += duration;
75
+ time += duration;
76
+ }
77
+
78
+ if (ti_1 > ti)
79
+ {
80
+ ti += duration;
81
+ ti1 += duration;
82
+ time += duration;
83
+ }
84
+
85
+ if (ti1 < ti)
86
+ {
87
+ ti1 += duration;
88
+ }
89
+
90
+ let tmti_1 = (time - ti_1);
91
+ let tmti_2 = (time - ti_2);
92
+ let dL0 = ti - ti_1;
93
+ let dL1_1 = ti - ti_2;
94
+ let dL1_2 = ti1 - ti_1;
95
+
96
+ let L0 = tmti_1 / dL0;
97
+ let L1_1 = tmti_2 / dL1_1;
98
+ let L1_2 = tmti_1 / dL1_2;
99
+
100
+ let ci_2 = (L1_1 + L0) - L0 * L1_1;
101
+ let ci = L0 * L1_2;
102
+ let ci_1 = ci_2 - ci;
103
+ ci_2 = 1 - ci_2;
104
+
105
+ for (let i = 0; i < curve.dimension; ++i)
106
+ {
107
+ value[i] = ci_2 * curve.controls[p1 + i] + ci_1 * curve.controls[p2 + i] + ci * curve.controls[p3 + i];
108
+ }
109
+ }
110
+ };
111
+
112
+ /**
113
+ * ag_horner1
114
+ *
115
+ * @param P
116
+ * @param deg
117
+ * @param s
118
+ * @returns {*}
119
+ */
120
+ curve.ag_horner1 = function(P, deg, s)
121
+ {
122
+ let h = P[deg];
123
+ while (--deg >= 0) h = (s * h) + P[deg];
124
+ return (h);
125
+ };
126
+
127
+ /**
128
+ * ag_zeroin2
129
+ *
130
+ * @param a
131
+ * @param b
132
+ * @param fa
133
+ * @param fb
134
+ * @param tol
135
+ * @param pars
136
+ * @returns {*}
137
+ */
138
+ curve.ag_zeroin2 = function(a, b, fa, fb, tol, pars)
139
+ {
140
+ let test;
141
+ let c, d, e, fc, del, m, machtol, p, q, r, s;
142
+
143
+ /* initialization */
144
+ machtol = 1.192092896e-07;
145
+ let label1 = true;
146
+
147
+ /* start iteration */
148
+ while (true)
149
+ {
150
+ if (label1)
151
+ {
152
+ c = a;
153
+ fc = fa;
154
+ d = b - a;
155
+ e = d;
156
+ }
157
+
158
+ if (Math.abs(fc) < Math.abs(fb))
159
+ {
160
+ a = b;
161
+ b = c;
162
+ c = a;
163
+ fa = fb;
164
+ fb = fc;
165
+ fc = fa;
166
+ }
167
+ label1 = false;
168
+
169
+ /* convergence test */
170
+ del = 2.0 * machtol * Math.abs(b) + 0.5 * tol;
171
+ m = 0.5 * (c - b);
172
+ test = ((Math.abs(m) > del) && (fb !== 0.0));
173
+ if (test)
174
+ {
175
+ if ((Math.abs(e) < del) || (Math.abs(fa) <= Math.abs(fb)))
176
+ {
177
+ /* bisection */
178
+ d = m;
179
+ e = d;
180
+ }
181
+ else
182
+ {
183
+ s = fb / fa;
184
+ if (a === c)
185
+ {
186
+ /* linear interpolation */
187
+ p = 2.0 * m * s;
188
+ q = 1.0 - s;
189
+ }
190
+ else
191
+ {
192
+ /* inverse quadratic interpolation */
193
+ q = fa / fc;
194
+ r = fb / fc;
195
+ p = s * (2.0 * m * q * (q - r) - (b - a) * (r - 1.0));
196
+ q = (q - 1.0) * (r - 1.0) * (s - 1.0);
197
+ }
198
+ /* adjust the sign */
199
+ if (p > 0.0) q = -q;
200
+ else p = -p;
201
+ /* check if interpolation is acceptable */
202
+ s = e;
203
+ e = d;
204
+ if ((2.0 * p < 3.0 * m * q - Math.abs(del * q)) && (p < Math.abs(0.5 * s * q)))
205
+ {
206
+ d = p / q;
207
+ }
208
+ else
209
+ {
210
+ d = m;
211
+ e = d;
212
+ }
213
+ }
214
+ /* complete step */
215
+ a = b;
216
+ fa = fb;
217
+ if (Math.abs(d) > del) b += d;
218
+ else if (m > 0.0) b += del;
219
+ else b -= del;
220
+ fb = curve.ag_horner1(pars.p, pars.deg, b);
221
+ if (fb * (fc / Math.abs(fc)) > 0.0)
222
+ {
223
+ label1 = true;
224
+ }
225
+ }
226
+ else
227
+ {
228
+ break;
229
+ }
230
+ }
231
+ return (b);
232
+ };
233
+
234
+ /**
235
+ * ag_zeroin
236
+ *
237
+ * @param a
238
+ * @param b
239
+ * @param tol
240
+ * @param pars
241
+ * @returns {*}
242
+ */
243
+ curve.ag_zeroin = function(a, b, tol, pars)
244
+ {
245
+ let fa, fb;
246
+
247
+ fa = curve.ag_horner1(pars.p, pars.deg, a);
248
+ if (Math.abs(fa) < 1.192092896e-07) return (a);
249
+
250
+ fb = curve.ag_horner1(pars.p, pars.deg, b);
251
+ if (Math.abs(fb) < 1.192092896e-07) return (b);
252
+
253
+ return (curve.ag_zeroin2(a, b, fa, fb, tol, pars));
254
+ };
255
+
256
+ /**
257
+ * polyZeroes
258
+ *
259
+ * @param Poly
260
+ * @param deg
261
+ * @param a
262
+ * @param a_closed
263
+ * @param b
264
+ * @param b_closed
265
+ * @param Roots
266
+ * @returns {*}
267
+ */
268
+ curve.polyZeroes = function(Poly, deg, a, a_closed, b, b_closed, Roots)
269
+ {
270
+ let i, left_ok, right_ok, nr, ndr, skip;
271
+
272
+ let e, f, s, pe, ps, tol, p, p_x = new Array(22),
273
+ d, d_x = new Array(22),
274
+ dr, dr_x = new Array(22);
275
+
276
+ let ply = {
277
+ p: [],
278
+ deg: 0
279
+ };
280
+
281
+ e = pe = 0.0;
282
+ f = 0.0;
283
+
284
+ for (i = 0; i < deg + 1; ++i)
285
+ {
286
+ f += Math.abs(Poly[i]);
287
+ }
288
+ tol = (Math.abs(a) + Math.abs(b)) * (deg + 1) * 1.192092896e-07;
289
+
290
+ /* Zero polynomial to tolerance? */
291
+ if (f <= tol) return (-1);
292
+
293
+ p = p_x;
294
+ d = d_x;
295
+ dr = dr_x;
296
+ for (i = 0; i < deg + 1; ++i)
297
+ {
298
+ p[i] = 1.0 / f * Poly[i];
299
+ }
300
+
301
+ /* determine true degree */
302
+ while (Math.abs(p[deg]) < tol) deg--;
303
+
304
+ /* Identically zero poly already caught so constant fn !== 0 */
305
+ nr = 0;
306
+ if (deg === 0) return (nr);
307
+
308
+ /* check for linear case */
309
+ if (deg === 1)
310
+ {
311
+ Roots[0] = -p[0] / p[1];
312
+ left_ok = (a_closed) ? (a < Roots[0] + tol) : (a < Roots[0] - tol);
313
+ right_ok = (b_closed) ? (b > Roots[0] - tol) : (b > Roots[0] + tol);
314
+ nr = (left_ok && right_ok) ? 1 : 0;
315
+ if (nr)
316
+ {
317
+ if (a_closed && Roots[0] < a) Roots[0] = a;
318
+ else if (b_closed && Roots[0] > b) Roots[0] = b;
319
+ }
320
+ return nr;
321
+ }
322
+ /* handle non-linear case */
323
+ else
324
+ {
325
+ ply.p = p;
326
+ ply.deg = deg;
327
+
328
+ /* compute derivative */
329
+ for (i = 1; i <= deg; i++) d[i - 1] = i * p[i];
330
+
331
+ /* find roots of derivative */
332
+ ndr = curve.polyZeroes(d, deg - 1, a, 0, b, 0, dr);
333
+ if (ndr.length === 0) return (0);
334
+
335
+ /* find roots between roots of the derivative */
336
+ for (i = skip = 0; i <= ndr; i++)
337
+ {
338
+ if (nr > deg) return (nr);
339
+ if (i === 0)
340
+ {
341
+ s = a;
342
+ ps = curve.ag_horner1(p, deg, s);
343
+ if (Math.abs(ps) <= tol && a_closed) Roots[nr++] = a;
344
+ }
345
+ else
346
+ {
347
+ s = e;
348
+ ps = pe;
349
+ }
350
+ if (i === ndr)
351
+ {
352
+ e = b;
353
+ skip = 0;
354
+ }
355
+ else e = dr[i];
356
+ pe = curve.ag_horner1(p, deg, e);
357
+ if (skip) skip = 0;
358
+ else
359
+ {
360
+ if (Math.abs(pe) < tol)
361
+ {
362
+ if (i !== ndr || b_closed)
363
+ {
364
+ Roots[nr++] = e;
365
+ skip = 1;
366
+ }
367
+ }
368
+ else if ((ps < 0 && pe > 0) || (ps > 0 && pe < 0))
369
+ {
370
+ Roots[nr++] = curve.ag_zeroin(s, e, 0.0, ply);
371
+ if ((nr > 1) && Roots[nr - 2] >= Roots[nr - 1] - tol)
372
+ {
373
+ Roots[nr - 2] = (Roots[nr - 2] + Roots[nr - 1]) * 0.5;
374
+ nr--;
375
+ }
376
+ }
377
+ }
378
+ }
379
+ }
380
+
381
+ return (nr);
382
+ };
383
+
384
+ export const {
385
+ evaluate,
386
+ ag_horner1,
387
+ ag_zeroin2,
388
+ ag_zeroin,
389
+ polyZeroes
390
+ } = curve;
@@ -0,0 +1,132 @@
1
+ import { vec3 } from "../vec3.js";
2
+ import { toJSON } from "./json.js";
3
+
4
+
5
+ /**
6
+ * Creates a box
7
+ * @author Three.js converted
8
+ * @param {Object} [options={}]
9
+ * @param {Number} [options.width=1]
10
+ * @param {Number} [options.height=1]
11
+ * @param {Number} [options.depth=1]
12
+ * @param {Number} [widthSegments=1]
13
+ * @param {Number} [heightSegments=1]
14
+ * @param {Number} [depthSegments=1]
15
+ * @returns {Object}
16
+ */
17
+ export function createBox(options = {})
18
+ {
19
+ let {
20
+ width = 1,
21
+ height = 1,
22
+ depth = 1,
23
+ widthSegments = 1,
24
+ heightSegments = 1,
25
+ depthSegments = 1
26
+ } = options;
27
+
28
+ widthSegments = Math.floor(widthSegments);
29
+ heightSegments = Math.floor(heightSegments);
30
+ depthSegments = Math.floor(depthSegments);
31
+
32
+ const
33
+ indices = [],
34
+ positions = [],
35
+ normals = [],
36
+ uvs = [];
37
+
38
+ let numberOfVertices = 0;
39
+
40
+ function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY)
41
+ {
42
+ const
43
+ segmentWidth = width / gridX,
44
+ segmentHeight = height / gridY,
45
+ widthHalf = width / 2,
46
+ heightHalf = height / 2,
47
+ depthHalf = depth / 2,
48
+ gridX1 = gridX + 1,
49
+ gridY1 = gridY + 1;
50
+
51
+ let vertexCounter = 0;
52
+
53
+ const vec3_0 = vec3.alloc();
54
+
55
+ // generate vertices, normals and uvs
56
+
57
+ for (let iy = 0; iy < gridY1; iy++)
58
+ {
59
+ const y = iy * segmentHeight - heightHalf;
60
+
61
+ for (let ix = 0; ix < gridX1; ix++)
62
+ {
63
+ const x = ix * segmentWidth - widthHalf;
64
+ // set values to correct vec3_0 component
65
+ vec3_0[u] = x * udir;
66
+ vec3_0[v] = y * vdir;
67
+ vec3_0[w] = depthHalf;
68
+ // now apply vec3_0 to vertex buffer
69
+ positions.push(vec3_0[0], vec3_0[1], vec3_0[2]);
70
+ // set values to correct vec3_0 component
71
+ vec3_0[u] = 0;
72
+ vec3_0[v] = 0;
73
+ vec3_0[w] = depth > 0 ? 1 : -1;
74
+ // now apply vec3_0 to normal buffer
75
+ normals.push(vec3_0[0], vec3_0[1], vec3_0[2]);
76
+ // uvs
77
+ uvs.push(ix / gridX);
78
+ uvs.push(1 - (iy / gridY));
79
+ // counters
80
+ vertexCounter += 1;
81
+ }
82
+ }
83
+
84
+ vec3.unalloc(vec3_0);
85
+
86
+ // indices
87
+ // 1. you need three indices to draw a single face
88
+ // 2. a single segment consists of two faces
89
+ // 3. so we need to generate six (2*3) indices per segment
90
+ for (let iy = 0; iy < gridY; iy++)
91
+ {
92
+ for (let ix = 0; ix < gridX; ix++)
93
+ {
94
+ const
95
+ a = numberOfVertices + ix + gridX1 * iy,
96
+ b = numberOfVertices + ix + gridX1 * (iy + 1),
97
+ c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1),
98
+ d = numberOfVertices + (ix + 1) + gridX1 * iy;
99
+ // faces
100
+ indices.push(a, b, d);
101
+ indices.push(b, c, d);
102
+ }
103
+ }
104
+
105
+ // update total number of vertices
106
+ numberOfVertices += vertexCounter;
107
+ }
108
+
109
+ buildPlane(2, 1, 0, - 1, - 1, depth, height, width, depthSegments, heightSegments); // px
110
+ buildPlane(2, 1, 0, 1, - 1, depth, height, - width, depthSegments, heightSegments); // nx
111
+ buildPlane(0, 2, 1, 1, 1, width, depth, height, widthSegments, depthSegments); // py
112
+ buildPlane(0, 2, 1, 1, - 1, width, depth, - height, widthSegments, depthSegments); // ny
113
+ buildPlane(0, 1, 2, 1, - 1, width, height, depth, widthSegments, heightSegments); // pz
114
+ buildPlane(0, 1, 2, - 1, - 1, width, height, - depth, widthSegments, heightSegments); // nz
115
+
116
+ // Normalize
117
+ const result = toJSON(indices, positions, uvs, normals);
118
+ result.shape = {
119
+ factory: createBox,
120
+ options: {
121
+ width,
122
+ height,
123
+ depth,
124
+ widthSegments,
125
+ heightSegments,
126
+ depthSegments
127
+ }
128
+ };
129
+ return result;
130
+
131
+ }
132
+