@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.
package/src/vec3.js ADDED
@@ -0,0 +1,1116 @@
1
+ import { vec3 as glVec3, mat4 as glMat4 } from "gl-matrix";
2
+ import { num } from "./num.js";
3
+ import { pool } from "./pool.js";
4
+ import { vec4 } from "./vec4.js";
5
+
6
+ const
7
+ vec3 = { ...glVec3 },
8
+ mat4 = { ...glMat4 };
9
+
10
+ /**
11
+ * Vector 3
12
+ * @typedef {Float32Array} vec3
13
+ */
14
+
15
+ /**
16
+ * Allocates a pooled vec3
17
+ * @returns {Float32Array|vec3}
18
+ */
19
+ vec3.alloc = function ()
20
+ {
21
+ return pool.allocF32(3);
22
+ };
23
+
24
+ /**
25
+ * Unallocates a pooled vec3
26
+ * @param {vec3|Float32Array} a
27
+ */
28
+ vec3.unalloc = function (a)
29
+ {
30
+ pool.freeType(a);
31
+ };
32
+
33
+ vec3.unallocMany = function(arr)
34
+ {
35
+ for (let i = 0; i < arr.length; i++)
36
+ {
37
+ pool.freeType(arr[i]);
38
+ }
39
+ };
40
+
41
+ /**
42
+ * X_AXIS
43
+ * @type {vec3}
44
+ */
45
+ vec3.X_AXIS = vec3.fromValues(1, 0, 0);
46
+
47
+ /**
48
+ * Y Axis
49
+ * @type {vec3}
50
+ */
51
+ vec3.Y_AXIS = vec3.fromValues(0, 1, 0);
52
+
53
+ /**
54
+ * Z Axis
55
+ * @type {vec3}
56
+ */
57
+ vec3.Z_AXIS = vec3.fromValues(0, 0, 1);
58
+
59
+
60
+ /**
61
+ * Adds a scalar to a vec3
62
+ *
63
+ * @param {vec3} out
64
+ * @param {vec3} a
65
+ * @param {Number} s
66
+ * @returns {vec3} out
67
+ */
68
+ vec3.addScalar = function (out, a, s)
69
+ {
70
+ out[0] = a[0] + s;
71
+ out[1] = a[1] + s;
72
+ out[2] = a[2] + s;
73
+ return out;
74
+ };
75
+
76
+ /**
77
+ * Converts radians to degrees
78
+ *
79
+ * @param {vec3} out
80
+ * @param {vec3} a
81
+ * @returns {vec3} out
82
+ */
83
+ vec3.degrees = function (out, a)
84
+ {
85
+ out[0] = num.degrees(a[0]);
86
+ out[1] = num.degrees(a[1]);
87
+ out[2] = num.degrees(a[2]);
88
+ return out;
89
+ };
90
+
91
+ /**
92
+ * Converts radians to unwrapped degrees
93
+ *
94
+ * @param {vec3} out
95
+ * @param {vec3} a
96
+ * @returns {vec3} out
97
+ */
98
+ vec3.degreesUnwrapped = function (out, a)
99
+ {
100
+ out[0] = num.degreesUnwrapped(a[0]);
101
+ out[1] = num.degreesUnwrapped(a[1]);
102
+ out[2] = num.degreesUnwrapped(a[2]);
103
+ return out;
104
+ };
105
+
106
+ /**
107
+ * Gets normalized direction between two points
108
+ * @param {vec3} out
109
+ * @param {vec3} a
110
+ * @param {vec3} b
111
+ * @returns {vec3}
112
+ */
113
+ vec3.direction = function (out, a, b)
114
+ {
115
+ vec3.subtract(out, a, b);
116
+ vec3.normalize(out, out);
117
+ return out;
118
+ };
119
+
120
+ /**
121
+ * Gets the direction from a quat
122
+ * @param {vec3} out
123
+ * @param {vec3} axis
124
+ * @param {quat} q
125
+ * @returns {vec3} out
126
+ */
127
+ vec3.directionFromQuat = function (out, axis, q)
128
+ {
129
+ return vec3.transformQuat(out, axis, q);
130
+ };
131
+
132
+ /**
133
+ * Gets the direction from a mat4's axis
134
+ * @param {vec3} out
135
+ * @param {vec3} axis
136
+ * @param {mat4} m
137
+ * @returns {vec3} out
138
+ */
139
+ vec3.directionFromMat4 = function (out, axis, m)
140
+ {
141
+ const quat_0 = mat4.getRotation(vec4.alloc(), m);
142
+ vec3.transformQuat(out, axis, quat_0);
143
+ vec4.unalloc(quat_0);
144
+ return out;
145
+ };
146
+
147
+ /**
148
+ * Divides a vec3 by a scalar
149
+ *
150
+ * @param {vec3} out
151
+ * @param {vec3} a
152
+ * @param {Number} s
153
+ * @returns {vec3} out
154
+ */
155
+ vec3.divideScalar = function (out, a, s)
156
+ {
157
+ return vec3.multiplyScalar(out, a, 1 / s);
158
+ };
159
+
160
+ /**
161
+ * Euler functions
162
+ * @type {{*}}
163
+ */
164
+ vec3.euler = {};
165
+
166
+ /**
167
+ * Default euler order
168
+ * @type {string}
169
+ */
170
+ vec3.euler.DEFAULT_ORDER = "XYZ";
171
+
172
+
173
+ /**
174
+ * Sets a euler from a quat
175
+ *
176
+ * @param {vec3} out
177
+ * @param {quat} q
178
+ * @param {string} [order=vec3.euler.DEFAULT_ORDER]
179
+ * @returns {vec3} out
180
+ */
181
+ vec3.euler.fromQuat = function (out, q, order = vec3.euler.DEFAULT_ORDER)
182
+ {
183
+ // mat4.alloc
184
+ const mat4_0 = mat4.fromQuat(pool.allocF32(16), q);
185
+ vec3.euler.fromMat4(out, mat4_0, order);
186
+ pool.unalloc(mat4_0);
187
+ return out;
188
+ };
189
+
190
+ /**
191
+ * Sets a euler from a mat4
192
+ *
193
+ * @author three.js (converted)
194
+ * @param {vec3} out
195
+ * @param {mat4} m
196
+ * @param {string} [order=vec3.euler.DEFAULT_ORDER]
197
+ * @returns {vec3} out
198
+ */
199
+ vec3.euler.fromMat4 = function (out, m, order = vec3.euler.DEFAULT_ORDER)
200
+ {
201
+ const
202
+ m11 = m[0], m12 = m[4], m13 = m[8],
203
+ m21 = m[1], m22 = m[5], m23 = m[9],
204
+ m31 = m[2], m32 = m[6], m33 = m[10];
205
+
206
+ const clamp = num.clamp;
207
+
208
+ if (order === "XYZ")
209
+ {
210
+ out[1] = Math.asin(clamp(m13, -1, 1));
211
+ if (Math.abs(m13) < 0.99999)
212
+ {
213
+ out[0] = Math.atan2(-m23, m33);
214
+ out[2] = Math.atan2(-m12, m11);
215
+ }
216
+ else
217
+ {
218
+ out[0] = Math.atan2(m32, m22);
219
+ out[2] = 0;
220
+ }
221
+ }
222
+ else if (order === "YXZ")
223
+ {
224
+ out[0] = Math.asin(-clamp(m23, -1, 1));
225
+ if (Math.abs(m23) < 0.99999)
226
+ {
227
+ out[1] = Math.atan2(m13, m33);
228
+ out[2] = Math.atan2(m21, m22);
229
+ }
230
+ else
231
+ {
232
+ out[1] = Math.atan2(-m31, m11);
233
+ out[2] = 0;
234
+ }
235
+ }
236
+ else if (order === "ZXY")
237
+ {
238
+ out[0] = Math.asin(clamp(m32, -1, 1));
239
+ if (Math.abs(m32) < 0.99999)
240
+ {
241
+ out[1] = Math.atan2(-m31, m33);
242
+ out[2] = Math.atan2(-m12, m22);
243
+ }
244
+ else
245
+ {
246
+ out[1] = 0;
247
+ out[2] = Math.atan2(m21, m11);
248
+ }
249
+ }
250
+ else if (order === "ZYX")
251
+ {
252
+ out[1] = Math.asin(-clamp(m31, -1, 1));
253
+ if (Math.abs(m31) < 0.99999)
254
+ {
255
+ out[0] = Math.atan2(m32, m33);
256
+ out[2] = Math.atan2(m21, m11);
257
+ }
258
+ else
259
+ {
260
+ out[0] = 0;
261
+ out[2] = Math.atan2(-m12, m22);
262
+ }
263
+ }
264
+ else if (order === "YZX")
265
+ {
266
+ out[2] = Math.asin(clamp(m21, -1, 1));
267
+ if (Math.abs(m21) < 0.99999)
268
+ {
269
+ out[0] = Math.atan2(-m23, m22);
270
+ out[1] = Math.atan2(-m31, m11);
271
+ }
272
+ else
273
+ {
274
+ out[0] = 0;
275
+ out[1] = Math.atan2(m13, m33);
276
+ }
277
+ }
278
+ else if (order === "XZY")
279
+ {
280
+ out[2] = Math.asin(-clamp(m12, -1, 1));
281
+ if (Math.abs(m12) < 0.99999)
282
+ {
283
+ out[0] = Math.atan2(m32, m22);
284
+ out[1] = Math.atan2(m13, m11);
285
+ }
286
+ else
287
+ {
288
+ out[0] = Math.atan2(-m23, m33);
289
+ out[1] = 0;
290
+ }
291
+ }
292
+ else
293
+ {
294
+ out[0] = 0;
295
+ out[1] = 0;
296
+ out[2] = 0;
297
+ throw new Error("Unrecognised euler order: " + order);
298
+ }
299
+
300
+ return out;
301
+ };
302
+
303
+ /**
304
+ * Gets a quat from a euler
305
+ * - Differs from quat.getEuler as it allows for different euler ordering
306
+ *
307
+ * - http://www.mathworks.com/matlabcentral/fileexchange/
308
+ * - 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
309
+ * - content/SpinCalc.m
310
+ *
311
+ * @param {quat} out
312
+ * @param {vec3} euler
313
+ * @param [order=vec3.euler.DEFAULT_ORDER]
314
+ * @returns {quat} out
315
+ */
316
+ vec3.euler.getQuat = function (out, euler, order = vec3.euler.DEFAULT_ORDER)
317
+ {
318
+ const
319
+ x = euler[0],
320
+ y = euler[1],
321
+ z = euler[2];
322
+
323
+ const
324
+ cosYaw = Math.cos(x / 2),
325
+ cosPitch = Math.cos(y / 2),
326
+ cosRoll = Math.cos(z / 2),
327
+ sinYaw = Math.sin(x / 2),
328
+ sinPitch = Math.sin(y / 2),
329
+ sinRoll = Math.sin(z / 2);
330
+
331
+ if (order === "XYZ")
332
+ {
333
+ out[0] = sinYaw * cosPitch * cosRoll + cosYaw * sinPitch * sinRoll;
334
+ out[1] = cosYaw * sinPitch * cosRoll - sinYaw * cosPitch * sinRoll;
335
+ out[2] = cosYaw * cosPitch * sinRoll + sinYaw * sinPitch * cosRoll;
336
+ out[3] = cosYaw * cosPitch * cosRoll - sinYaw * sinPitch * sinRoll;
337
+ }
338
+ else if (order === "YXZ")
339
+ {
340
+ out[0] = sinYaw * cosPitch * cosRoll + cosYaw * sinPitch * sinRoll;
341
+ out[1] = cosYaw * sinPitch * cosRoll - sinYaw * cosPitch * sinRoll;
342
+ out[2] = cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll;
343
+ out[3] = cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll;
344
+ }
345
+ else if (order === "ZXY")
346
+ {
347
+ out[0] = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll;
348
+ out[1] = cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll;
349
+ out[2] = cosYaw * cosPitch * sinRoll + sinYaw * sinPitch * cosRoll;
350
+ out[3] = cosYaw * cosPitch * cosRoll - sinYaw * sinPitch * sinRoll;
351
+ }
352
+ else if (order === "ZYX")
353
+ {
354
+ out[0] = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll;
355
+ out[1] = cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll;
356
+ out[2] = cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll;
357
+ out[3] = cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll;
358
+ }
359
+ else if (order === "YZX")
360
+ {
361
+ out[0] = sinYaw * cosPitch * cosRoll + cosYaw * sinPitch * sinRoll;
362
+ out[1] = cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll;
363
+ out[2] = cosYaw * cosPitch * sinRoll - sinYaw * sinPitch * cosRoll;
364
+ out[3] = cosYaw * cosPitch * cosRoll - sinYaw * sinPitch * sinRoll;
365
+ }
366
+ else if (order === "XZY")
367
+ {
368
+ out[0] = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll;
369
+ out[1] = cosYaw * sinPitch * cosRoll - sinYaw * cosPitch * sinRoll;
370
+ out[2] = cosYaw * cosPitch * sinRoll + sinYaw * sinPitch * cosRoll;
371
+ out[3] = cosYaw * cosPitch * cosRoll + sinYaw * sinPitch * sinRoll;
372
+ }
373
+ else
374
+ {
375
+ out[0] = 0;
376
+ out[1] = 0;
377
+ out[2] = 0;
378
+ out[3] = 1;
379
+ throw new Error("Unrecognised euler order: " + order);
380
+ }
381
+ return out;
382
+ };
383
+
384
+
385
+ /**
386
+ * Gets a quat from a euler values
387
+ *
388
+ * @param {quat} out
389
+ * @param {Number} x
390
+ * @param {Number} y
391
+ * @param {Number} z
392
+ * @param {String} [order]
393
+ * @return {quat} out
394
+ */
395
+ vec3.euler.getQuatFromValues = function (out, x, y, z, order)
396
+ {
397
+ const vec3_0 = vec3.set(vec3.alloc(), x, y, z);
398
+ vec3.euler.getQuat(out, vec3_0, order);
399
+ vec3.unalloc(vec3_0);
400
+ return out;
401
+ };
402
+
403
+ /**
404
+ * Gets a quat from a euler that uses degrees
405
+ *
406
+ * @param {quat} out
407
+ * @param {vec3} v
408
+ * @param {String} [order]
409
+ * @return {quat} out
410
+ */
411
+ vec3.euler.getQuatFromDegrees = function (out, v, order)
412
+ {
413
+ const vec3_0 = vec3.radians(vec3.alloc(), v);
414
+ vec3.euler.getQuat(out, vec3_0, order);
415
+ vec3.unalloc(vec3_0);
416
+ return out;
417
+ };
418
+
419
+ /**
420
+ * Gets a quat from euler degree values
421
+ *
422
+ * @param {quat} out
423
+ * @param {Number} x
424
+ * @param {Number} y
425
+ * @param {Number} z
426
+ * @param {String} [order]
427
+ * @return {quat} out
428
+ */
429
+ vec3.euler.getQuatFromDegreeValues = function (out, x, y, z, order)
430
+ {
431
+ const vec3_0 = vec3.set(vec3.alloc(), x, y, z);
432
+ vec3.radians(vec3_0, vec3_0);
433
+ vec3.euler.getQuat(out, vec3_0, order);
434
+ vec3.unalloc(vec3_0);
435
+ return out;
436
+ };
437
+
438
+ /**
439
+ * Sets a euler from quat, and stores in degrees
440
+ *
441
+ * @param {vec3} out
442
+ * @param {quat} q
443
+ * @param {String} [order]
444
+ * @return {vec3} out
445
+ */
446
+ vec3.euler.fromQuatInDegrees = function (out, q, order)
447
+ {
448
+ vec3.euler.fromQuat(out, q, order);
449
+ return vec3.degrees(out, out);
450
+ };
451
+
452
+ /**
453
+ * Exponential decay
454
+ *
455
+ * @param {vec3} out
456
+ * @param {vec3} omega0
457
+ * @param {vec3} torque
458
+ * @param {number} I
459
+ * @param {number} drag
460
+ * @param {number} time
461
+ * @returns {vec3} out
462
+ */
463
+ vec3.exponentialDecay = function (out, omega0, torque, I, drag, time)
464
+ {
465
+ out[0] = num.exponentialDecay(omega0[0], torque[0], I, drag, time);
466
+ out[1] = num.exponentialDecay(omega0[1], torque[1], I, drag, time);
467
+ out[2] = num.exponentialDecay(omega0[2], torque[2], I, drag, time);
468
+ return out;
469
+ };
470
+
471
+ /**
472
+ * Creates a spherical
473
+ * @returns {vec3}
474
+ */
475
+ vec3.createSpherical = function ()
476
+ {
477
+ return vec3.fromValues(0, 0, 1);
478
+ };
479
+
480
+ /**
481
+ * Sets a vec3 with cartesian coordinates from spherical coordinates and an optional center point
482
+ * @param {vec3} out - receiving vec3
483
+ * @param {vec3} spherical - source vec3 with spherical coordinates (phi, theta, radius)
484
+ * @param {vec3} [center] - Optional center
485
+ * @returns {vec3} out - receiving vec3
486
+ */
487
+ vec3.fromSpherical = function (out, spherical, center)
488
+ {
489
+ const
490
+ phi = spherical[0],
491
+ theta = spherical[1],
492
+ radius = spherical[2];
493
+
494
+ const sinPhi = Math.sin(phi);
495
+
496
+ out[0] = radius * sinPhi * Math.sin(theta); // x
497
+ out[1] = radius * Math.cos(phi); // y
498
+ out[2] = radius * sinPhi * Math.cos(theta); // z
499
+
500
+ if (center)
501
+ {
502
+ out[0] += center[0];
503
+ out[1] += center[1];
504
+ out[2] += center[2];
505
+ }
506
+
507
+ return out;
508
+ };
509
+
510
+
511
+
512
+ /**
513
+ * Gets spherical coordinates from a vector
514
+ * @param {vec3} out
515
+ * @param {vec3} a
516
+ * @returns {vec3} out
517
+ */
518
+ vec3.getSpherical = function (out, a)
519
+ {
520
+ let phi = 0,
521
+ theta = 0,
522
+ radius = vec3.length(a);
523
+
524
+ if (radius !== 0)
525
+ {
526
+ phi = Math.acos(num.clamp(a[1] / radius, -1, 1));
527
+ theta = Math.atan2(a[0], a[2]);
528
+ }
529
+
530
+ out[0] = phi;
531
+ out[1] = theta;
532
+ out[2] = radius;
533
+ return out;
534
+ };
535
+
536
+ /**
537
+ * Makes a spherical value "safe"
538
+ * @param {vec3} out
539
+ * @param {vec3} a
540
+ * @returns {vec3} out
541
+ */
542
+ vec3.makeSphericalSafe = function (out, a)
543
+ {
544
+ out[0] = Math.max(num.EPSILON, Math.min(Math.PI - num.EPSILON, a[0]));
545
+ out[1] = a[1];
546
+ out[2] = a[2];
547
+ return out;
548
+ };
549
+
550
+ /**
551
+ * Checks if all elements are 0
552
+ * @param {vec3} a
553
+ * @returns {boolean}
554
+ */
555
+ vec3.isEmpty = function (a)
556
+ {
557
+ return a[0] === 0 && a[1] === 0 && a[2] === 0;
558
+ };
559
+
560
+ /**
561
+ * Multiplies a vec3 by a scalar
562
+ *
563
+ * @param {vec3} out
564
+ * @param {vec3} a
565
+ * @param {Number} s
566
+ * @returns {vec3} out
567
+ */
568
+ vec3.multiplyScalar = function (out, a, s)
569
+ {
570
+ out[0] = a[0] * s;
571
+ out[1] = a[1] * s;
572
+ out[2] = a[2] * s;
573
+ return out;
574
+ };
575
+
576
+ /**
577
+ * Converts from long, lat and radius to a vector
578
+ * @param {vec3} out
579
+ * @param {Number} radius
580
+ * @param {Number} latitude
581
+ * @param {Number} longitude
582
+ * @returns {vec3} out
583
+ */
584
+ vec3.polarToCartesian = function (out, radius, latitude, longitude)
585
+ {
586
+ out[0] = radius * Math.cos(latitude) * Math.sin(longitude);
587
+ out[1] = radius * Math.sin(latitude);
588
+ out[2] = radius * Math.cos(latitude) * Math.cos(longitude);
589
+ return out;
590
+ };
591
+
592
+ /**
593
+ * Projects a world vec3 to screen space with viewport settings
594
+ * @param {vec3} out - receiving vec3
595
+ * @param {vec3} a - local vec3
596
+ * @param {mat4} m - model view projection matrix
597
+ * @param {vec4} viewport - view port settings (x, y, width, height)
598
+ * @returns {vec3} out - receiving vec3 (x, y, perspectiveDivide)
599
+ */
600
+ vec3.project = function (out, a, m, viewport)
601
+ {
602
+ let x = a[0],
603
+ y = a[1],
604
+ z = a[2];
605
+
606
+ let outX = m[0] * x + m[4] * y + m[8] * z + m[12],
607
+ outY = m[1] * x + m[5] * y + m[9] * z + m[13],
608
+ perD = m[3] * x + m[7] * y + m[11] * z + m[15];
609
+
610
+ let projectionX = (outX / perD + 1) / 2;
611
+ let projectionY = 1 - (outY / perD + 1) / 2;
612
+
613
+ out[0] = projectionX * viewport[2] + viewport[0];
614
+ out[1] = projectionY * viewport[3] + viewport[1];
615
+ out[2] = perD;
616
+ return out;
617
+ };
618
+
619
+ /**
620
+ * Converts degrees to radians
621
+ *
622
+ * @param {vec3} out
623
+ * @param {vec3} a
624
+ * @returns {vec3} out
625
+ */
626
+ vec3.radians = function (out, a)
627
+ {
628
+ out[0] = num.radians(a[0]);
629
+ out[1] = num.radians(a[1]);
630
+ out[2] = num.radians(a[2]);
631
+ return out;
632
+ };
633
+
634
+ /**
635
+ * Converts degrees to unwrapped radians
636
+ *
637
+ * @param {vec3} out
638
+ * @param {vec3} a
639
+ * @returns {vec3} out
640
+ */
641
+ vec3.radiansUnwrapped = function (out, a)
642
+ {
643
+ out[0] = num.radiansUnwrapped(a[0]);
644
+ out[1] = num.radiansUnwrapped(a[1]);
645
+ out[2] = num.radiansUnwrapped(a[2]);
646
+ return out;
647
+ };
648
+
649
+ /**
650
+ * Sets a vec3 from a scalar
651
+ *
652
+ * @param {vec3} out
653
+ * @param {Number} s
654
+ * @returns {vec3} out
655
+ */
656
+ vec3.setScalar = function (out, s)
657
+ {
658
+ out[0] = s;
659
+ out[1] = s;
660
+ out[2] = s;
661
+ return out;
662
+ };
663
+
664
+ /**
665
+ * Subtracts a scalar from a vec3
666
+ *
667
+ * @param {vec3} out
668
+ * @param {vec3} a
669
+ * @param {Number} s
670
+ * @returns {vec3} out
671
+ */
672
+ vec3.subtractScalar = function (out, a, s)
673
+ {
674
+ out[0] = a[0] - s;
675
+ out[1] = a[1] - s;
676
+ out[2] = a[2] - s;
677
+ return out;
678
+ };
679
+
680
+ /**
681
+ * Unprojects a vec3 with canvas coordinates to world space
682
+ *
683
+ * @param {vec3} out - receiving vec3
684
+ * @param {vec3} a - vec3 to unproject
685
+ * @param {mat4} invViewProj - inverse view projection matrix
686
+ * @param {vec4|Array} viewport - [ x, y, width, height ]
687
+ * @returns {vec3} out
688
+ * @throw On perspective divide error
689
+ */
690
+ vec3.unproject = function (out, a, invViewProj, viewport)
691
+ {
692
+ const vec4_0 = vec4.alloc(4);
693
+
694
+ let x = a[0],
695
+ y = a[1],
696
+ z = a[2];
697
+
698
+ vec4_0[0] = (x - viewport[0]) * 2.0 / viewport[2] - 1.0;
699
+ vec4_0[1] = (y - viewport[1]) * 2.0 / viewport[3] - 1.0;
700
+ vec4_0[2] = 2.0 * z - 1.0;
701
+ vec4_0[3] = 1.0;
702
+
703
+ vec4.transformMat4(vec4_0, vec4_0, invViewProj);
704
+
705
+ if (vec4_0[3] === 0.0)
706
+ {
707
+ vec4.unalloc(vec4_0);
708
+ out[0] = 0;
709
+ out[1] = 0;
710
+ out[2] = 0;
711
+ throw new Error("Perspective divide error");
712
+ }
713
+
714
+ out[0] = vec4_0[0] / vec4_0[3];
715
+ out[1] = vec4_0[1] / vec4_0[3];
716
+ out[2] = vec4_0[2] / vec4_0[3];
717
+
718
+ vec4.unalloc(vec4_0);
719
+
720
+ return out;
721
+ };
722
+
723
+ /**
724
+ * Unwraps degrees
725
+ *
726
+ * @param {vec3} out
727
+ * @param {vec3} a
728
+ * @returns {vec3}
729
+ */
730
+ vec3.unwrapDegrees = function (out, a)
731
+ {
732
+ out[0] = num.unwrapDegrees(a[0]);
733
+ out[1] = num.unwrapDegrees(a[1]);
734
+ out[2] = num.unwrapDegrees(a[2]);
735
+ return out;
736
+ };
737
+
738
+ /**
739
+ * Unwraps radians
740
+ *
741
+ * @param {vec3} out
742
+ * @param {vec3} a
743
+ * @returns {vec3}
744
+ */
745
+ vec3.unwrapRadians = function (out, a)
746
+ {
747
+ out[0] = num.unwrapRadians(a[0]);
748
+ out[1] = num.unwrapRadians(a[1]);
749
+ out[2] = num.unwrapRadians(a[2]);
750
+ return out;
751
+ };
752
+
753
+ /**
754
+ * Converts from linear color to rgb
755
+ * @param {vec3} out
756
+ * @param {vec3} linear
757
+ * @returns {vec3}
758
+ */
759
+ vec3.toRGB = function (out, linear)
760
+ {
761
+ out[0] = num.colorFromLinear(linear[0]);
762
+ out[1] = num.colorFromLinear(linear[1]);
763
+ out[2] = num.colorFromLinear(linear[2]);
764
+ return out;
765
+ };
766
+
767
+ /**
768
+ * Converts from linear color to rgba
769
+ * @param {vec4} out
770
+ * @param {vec3} linear
771
+ * @param {Number} [linearAlpha=1]
772
+ * @return {vec4} out
773
+ */
774
+ vec3.toRGBA = function (out, linear, linearAlpha = 1)
775
+ {
776
+ out[0] = num.colorFromLinear(linear[0]);
777
+ out[1] = num.colorFromLinear(linear[1]);
778
+ out[2] = num.colorFromLinear(linear[2]);
779
+ out[3] = num.colorFromLinear(linearAlpha);
780
+ return out;
781
+ };
782
+
783
+ /**
784
+ * Converts to linear color from rgba
785
+ * @param {vec3} out
786
+ * @param {vec3} rgb
787
+ * @returns {vec3} out
788
+ */
789
+ vec3.fromRGB = function (out, rgb)
790
+ {
791
+ out[0] = num.linearFromColor(rgb[0]);
792
+ out[1] = num.linearFromColor(rgb[1]);
793
+ out[2] = num.linearFromColor(rgb[2]);
794
+ return out;
795
+ };
796
+
797
+ /**
798
+ * Gets hex value from linear color
799
+ * @param {vec4} linear
800
+ * @returns {string} hex value
801
+ */
802
+ vec3.toHex = function (linear)
803
+ {
804
+ return "#" +
805
+ num.hexFromLinear(linear[0]) +
806
+ num.hexFromLinear(linear[1]) +
807
+ num.hexFromLinear(linear[2]);
808
+ };
809
+
810
+ /**
811
+ * Gets hex rgba from linear colour
812
+ * @param {vec3} linear
813
+ * @param {Number} [linearAlpha=1]
814
+ * @return {string}
815
+ */
816
+ vec3.toHexA = function (linear, linearAlpha = 1)
817
+ {
818
+ return "#" +
819
+ num.hexFromLinear(linear[0]) +
820
+ num.hexFromLinear(linear[1]) +
821
+ num.hexFromLinear(linear[2]) +
822
+ num.hexFromLinear(linearAlpha);
823
+ };
824
+
825
+ /**
826
+ * Gets RGB from hex
827
+ * @param {vec3} out
828
+ * @param {String} hex
829
+ * @return {vec3} out
830
+ */
831
+ vec3.fromHex = function (out, hex)
832
+ {
833
+ // Set empty color in case of error
834
+ out[0] = 0;
835
+ out[1] = 0;
836
+ out[2] = 0;
837
+
838
+ if (hex.length === 4 || hex.length === 5)
839
+ {
840
+ out[0] = ("0x" + hex[1] + hex[1]) / 255;
841
+ out[1] = ("0x" + hex[2] + hex[2]) / 255;
842
+ out[2] = ("0x" + hex[3] + hex[3]) / 255;
843
+ }
844
+ // RGB hex
845
+ else if (hex.length === 7 || hex.length === 9)
846
+ {
847
+ out[0] = ("0x" + hex[1] + hex[2]) / 255;
848
+ out[1] = ("0x" + hex[3] + hex[4]) / 255;
849
+ out[2] = ("0x" + hex[5] + hex[6]) / 255;
850
+ }
851
+ else
852
+ {
853
+ throw new TypeError("Invalid hex");
854
+ }
855
+
856
+ return out;
857
+ };
858
+
859
+
860
+ vec3.linearToHSV = function (out, linear)
861
+ {
862
+ let rabs,
863
+ gabs,
864
+ babs, rr,
865
+ gg, bb,
866
+ h,
867
+ s,
868
+ v,
869
+ diff,
870
+ diffc,
871
+ percentRoundFn;
872
+
873
+ rabs = linear[0];
874
+ gabs = linear[1];
875
+ babs = linear[2];
876
+
877
+ v = Math.max(rabs, gabs, babs);
878
+ diff = v - Math.min(rabs, gabs, babs);
879
+ diffc = c => (v - c) / 6 / diff + 1 / 2;
880
+ percentRoundFn = num => Math.round(num * 100) / 100;
881
+
882
+ if (diff == 0)
883
+ {
884
+ h = s = 0;
885
+ }
886
+ else
887
+ {
888
+ s = diff / v;
889
+ rr = diffc(rabs);
890
+ gg = diffc(gabs);
891
+ bb = diffc(babs);
892
+
893
+ if (rabs === v)
894
+ {
895
+ h = bb - gg;
896
+ }
897
+ else if (gabs === v)
898
+ {
899
+ h = (1 / 3) + rr - bb;
900
+ }
901
+ else if (babs === v)
902
+ {
903
+ h = (2 / 3) + gg - rr;
904
+ }
905
+
906
+ if (h < 0)
907
+ {
908
+ h += 1;
909
+ }
910
+ else if (h > 1)
911
+ {
912
+ h -= 1;
913
+ }
914
+ }
915
+
916
+ out[0] = Math.round(h * 360);
917
+ out[1] = percentRoundFn(s * 100);
918
+ out[2] = percentRoundFn(v * 100);
919
+ return out;
920
+ };
921
+
922
+ /**
923
+ * Sets a vec3 from an array with an optional offset
924
+ * @param {vec3} out
925
+ * @param {TypedArray|Array} array
926
+ * @param {Number} [offset=0]
927
+ * @returns {vec3} out
928
+ */
929
+ vec3.fromArray = function (out, array, offset = 0)
930
+ {
931
+ out[0] = array[offset];
932
+ out[1] = array[offset + 1];
933
+ out[2] = array[offset + 2];
934
+ return out;
935
+ };
936
+
937
+ /**
938
+ * Sets a vec3 from a mat4 column
939
+ * @param {vec3} out
940
+ * @param {mat4} m
941
+ * @param {Number} index
942
+ * @returns {vec3} out
943
+ */
944
+ vec3.fromMat4Column = function (out, m, index)
945
+ {
946
+ return vec3.fromArray(out, m, index * 4);
947
+ };
948
+
949
+ /**
950
+ * Sets a vec3 from a mat3 column
951
+ * @param {vec3} out
952
+ * @param {mat4} m
953
+ * @param {Number} index
954
+ * @returns {vec3} out
955
+ */
956
+ vec3.fromMat3Column = function (out, m, index)
957
+ {
958
+ return vec3.fromArray(out, m, index * 3);
959
+ };
960
+
961
+ /**
962
+ * Converts srgb to linear colour
963
+ * @param {vec3} out
964
+ * @param {vec3} srgb
965
+ * @returns {vec3} out
966
+ */
967
+ vec3.fromSRGB = function (out, srgb)
968
+ {
969
+ out[0] = num.linearFromSRGB(srgb[0]);
970
+ out[1] = num.linearFromSRGB(srgb[1]);
971
+ out[2] = num.linearFromSRGB(srgb[2]);
972
+ return out;
973
+ };
974
+
975
+ /**
976
+ * Converts linear colour to srgb
977
+ * @param {vec3} out
978
+ * @param {vec3} srgb
979
+ * @returns {vec3} out
980
+ */
981
+ vec3.toSRGB = function (out, linear)
982
+ {
983
+ out[0] = num.srgbFromLinear(linear[0]);
984
+ out[1] = num.srgbFromLinear(linear[1]);
985
+ out[2] = num.srgbFromLinear(linear[2]);
986
+ return out;
987
+ };
988
+
989
+ /**
990
+ * Three js
991
+ * Todo: replace with glMatrix
992
+ */
993
+ vec3.applyQuaternion = function (out, a, q)
994
+ {
995
+
996
+ const
997
+ x = a[0],
998
+ y = a[1],
999
+ z = a[2],
1000
+ qx = q[0],
1001
+ qy = q[1],
1002
+ qz = q[2],
1003
+ qw = q[3];
1004
+
1005
+ // calculate quat * vector
1006
+ const
1007
+ ix = qw * x + qy * z - qz * y,
1008
+ iy = qw * y + qz * x - qx * z,
1009
+ iz = qw * z + qx * y - qy * x,
1010
+ iw = -qx * x - qy * y - qz * z;
1011
+
1012
+ // calculate result * inverse quat
1013
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
1014
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
1015
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
1016
+
1017
+ return out;
1018
+ };
1019
+
1020
+
1021
+ export { vec3 };
1022
+
1023
+ export const {
1024
+ add,
1025
+ angle,
1026
+ bezier,
1027
+ ceil,
1028
+ clone,
1029
+ copy,
1030
+ create,
1031
+ cross,
1032
+ dist,
1033
+ distance,
1034
+ div,
1035
+ divide,
1036
+ dot,
1037
+ equals,
1038
+ exactEquals,
1039
+ floor,
1040
+ forEach,
1041
+ fromValues,
1042
+ hermite,
1043
+ inverse,
1044
+ len,
1045
+ length,
1046
+ lerp,
1047
+ max,
1048
+ min,
1049
+ mul,
1050
+ multiply,
1051
+ negate,
1052
+ normalize,
1053
+ random,
1054
+ rotateX,
1055
+ rotateY,
1056
+ rotateZ,
1057
+ round,
1058
+ scale,
1059
+ scaleAndAdd,
1060
+ set,
1061
+ slerp,
1062
+ sqrDist,
1063
+ sqrLen,
1064
+ squaredDistance,
1065
+ squaredLength,
1066
+ str,
1067
+ sub,
1068
+ subtract,
1069
+ transformMat3,
1070
+ transformMat4,
1071
+ transformQuat,
1072
+ zero,
1073
+ alloc,
1074
+ unalloc,
1075
+ unallocMany,
1076
+ X_AXIS,
1077
+ Y_AXIS,
1078
+ Z_AXIS,
1079
+ addScalar,
1080
+ degrees,
1081
+ degreesUnwrapped,
1082
+ direction,
1083
+ directionFromQuat,
1084
+ directionFromMat4,
1085
+ divideScalar,
1086
+ euler,
1087
+ exponentialDecay,
1088
+ createSpherical,
1089
+ fromSpherical,
1090
+ getSpherical,
1091
+ makeSphericalSafe,
1092
+ isEmpty,
1093
+ multiplyScalar,
1094
+ polarToCartesian,
1095
+ project,
1096
+ radians,
1097
+ radiansUnwrapped,
1098
+ setScalar,
1099
+ subtractScalar,
1100
+ unproject,
1101
+ unwrapDegrees,
1102
+ unwrapRadians,
1103
+ toRGB,
1104
+ toRGBA,
1105
+ fromRGB,
1106
+ toHex,
1107
+ toHexA,
1108
+ fromHex,
1109
+ linearToHSV,
1110
+ fromArray,
1111
+ fromMat4Column,
1112
+ fromMat3Column,
1113
+ fromSRGB,
1114
+ toSRGB,
1115
+ applyQuaternion
1116
+ } = vec3;