glmaths 0.0.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/src/quat2.ts ADDED
@@ -0,0 +1,412 @@
1
+ import glm from '.'
2
+ import { equals } from './internalUtils'
3
+ import { Vec3 } from './vec3'
4
+ import { Quat } from './quat'
5
+ import { Mat4 } from './mat4'
6
+
7
+ /**
8
+ * Dual Quaternion for rigid body transformations (rotation + translation)
9
+ * Stored as [real.x, real.y, real.z, real.w, dual.x, dual.y, dual.z, dual.w]
10
+ * @extends Float32Array
11
+ */
12
+ export class Quat2 extends Float32Array {
13
+
14
+ static get identity() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
15
+ static get Identity() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
16
+ static get IDENTITY() { return new Quat2(0, 0, 0, 1, 0, 0, 0, 0) }
17
+
18
+ /**
19
+ * Creates a new dual quaternion
20
+ *
21
+ * @param {Number} x1 real X component, defaults to 0
22
+ * @param {Number} y1 real Y component, defaults to 0
23
+ * @param {Number} z1 real Z component, defaults to 0
24
+ * @param {Number} w1 real W component, defaults to 1
25
+ * @param {Number} x2 dual X component, defaults to 0
26
+ * @param {Number} y2 dual Y component, defaults to 0
27
+ * @param {Number} z2 dual Z component, defaults to 0
28
+ * @param {Number} w2 dual W component, defaults to 0
29
+ */
30
+ constructor(x1 = 0, y1 = 0, z1 = 0, w1 = 1, x2 = 0, y2 = 0, z2 = 0, w2 = 0) {
31
+ super(8)
32
+ this[0] = x1; this[1] = y1; this[2] = z1; this[3] = w1
33
+ this[4] = x2; this[5] = y2; this[6] = z2; this[7] = w2
34
+ }
35
+
36
+ /**
37
+ * Get the real part as a Quat
38
+ *
39
+ * @param {Quat} out the receiving quaternion, defaults to quat()
40
+ * @returns {Quat} out
41
+ */
42
+ getReal(out = new Quat()): Quat {
43
+ out[0] = this[0]; out[1] = this[1]; out[2] = this[2]; out[3] = this[3]
44
+ return out
45
+ }
46
+
47
+ /**
48
+ * Get the dual part as a Quat
49
+ *
50
+ * @param {Quat} out the receiving quaternion, defaults to quat()
51
+ * @returns {Quat} out
52
+ */
53
+ getDual(out = new Quat()): Quat {
54
+ out[0] = this[4]; out[1] = this[5]; out[2] = this[6]; out[3] = this[7]
55
+ return out
56
+ }
57
+
58
+ /**
59
+ * Set the real part from a quaternion
60
+ *
61
+ * @param {Quat} q the source quaternion
62
+ * @returns {Quat2} this
63
+ */
64
+ setReal(q: Quat) {
65
+ this[0] = q[0]; this[1] = q[1]; this[2] = q[2]; this[3] = q[3]
66
+ return this
67
+ }
68
+
69
+ /**
70
+ * Set the dual part from a quaternion
71
+ *
72
+ * @param {Quat} q the source quaternion
73
+ * @returns {Quat2} this
74
+ */
75
+ setDual(q: Quat) {
76
+ this[4] = q[0]; this[5] = q[1]; this[6] = q[2]; this[7] = q[3]
77
+ return this
78
+ }
79
+
80
+ /**
81
+ * Get the translation component
82
+ *
83
+ * @param {Vec3} out the receiving vector, defaults to vec3()
84
+ * @returns {Vec3} out
85
+ */
86
+ getTranslation(out = new Vec3()): Vec3 {
87
+ const ax = this[4], ay = this[5], az = this[6], aw = this[7]
88
+ const bx = -this[0], by = -this[1], bz = -this[2], bw = this[3]
89
+ out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2
90
+ out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2
91
+ out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2
92
+ return out
93
+ }
94
+
95
+ /**
96
+ * Create from rotation quaternion and translation vector
97
+ *
98
+ * @param {Quat} q the rotation quaternion
99
+ * @param {Vec3} t the translation vector
100
+ * @param {Quat2} out the receiving dual quaternion, defaults to quat2()
101
+ * @returns {Quat2} out
102
+ */
103
+ static fromRotationTranslation(q: Quat, t: Vec3, out = new Quat2()): Quat2 {
104
+ const ax = t[0] * 0.5, ay = t[1] * 0.5, az = t[2] * 0.5
105
+ const bx = q[0], by = q[1], bz = q[2], bw = q[3]
106
+ out[0] = bx; out[1] = by; out[2] = bz; out[3] = bw
107
+ out[4] = ax * bw + ay * bz - az * by
108
+ out[5] = ay * bw + az * bx - ax * bz
109
+ out[6] = az * bw + ax * by - ay * bx
110
+ out[7] = -ax * bx - ay * by - az * bz
111
+ return out
112
+ }
113
+
114
+ /**
115
+ * Create from translation only
116
+ *
117
+ * @param {Vec3} t the translation vector
118
+ * @param {Quat2} out the receiving dual quaternion, defaults to quat2()
119
+ * @returns {Quat2} out
120
+ */
121
+ static fromTranslation(t: Vec3, out = new Quat2()): Quat2 {
122
+ out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1
123
+ out[4] = t[0] * 0.5; out[5] = t[1] * 0.5; out[6] = t[2] * 0.5; out[7] = 0
124
+ return out
125
+ }
126
+
127
+ /**
128
+ * Create from rotation only
129
+ *
130
+ * @param {Quat} q the rotation quaternion
131
+ * @param {Quat2} out the receiving dual quaternion, defaults to quat2()
132
+ * @returns {Quat2} out
133
+ */
134
+ static fromRotation(q: Quat, out = new Quat2()): Quat2 {
135
+ out[0] = q[0]; out[1] = q[1]; out[2] = q[2]; out[3] = q[3]
136
+ out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 0
137
+ return out
138
+ }
139
+
140
+ /**
141
+ * Create from a 4x4 matrix
142
+ *
143
+ * @param {Mat4} m the source matrix
144
+ * @param {Quat2} out the receiving dual quaternion, defaults to quat2()
145
+ * @returns {Quat2} out
146
+ */
147
+ static fromMat4(m: Mat4, out = new Quat2()): Quat2 {
148
+ const r = m.getRotation()
149
+ const t = m.getTranslation()
150
+ return Quat2.fromRotationTranslation(r, t, out)
151
+ }
152
+
153
+ /**
154
+ * Creates a copy of this dual quaternion
155
+ *
156
+ * @returns {Quat2} a new dual quaternion
157
+ */
158
+ clone() {
159
+ return new Quat2(this[0], this[1], this[2], this[3], this[4], this[5], this[6], this[7])
160
+ }
161
+
162
+ /**
163
+ * Multiply two dual quaternions
164
+ *
165
+ * @param {Quat2} b the second operand
166
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
167
+ * @returns {Quat2} out
168
+ */
169
+ // @ts-ignore
170
+ multiply = (b: Quat2, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 => {
171
+ const ax0 = this[0], ay0 = this[1], az0 = this[2], aw0 = this[3]
172
+ const bx1 = b[4], by1 = b[5], bz1 = b[6], bw1 = b[7]
173
+ const ax1 = this[4], ay1 = this[5], az1 = this[6], aw1 = this[7]
174
+ const bx0 = b[0], by0 = b[1], bz0 = b[2], bw0 = b[3]
175
+
176
+ out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0
177
+ out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0
178
+ out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0
179
+ out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0
180
+
181
+ out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 +
182
+ ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0
183
+ out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 +
184
+ ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0
185
+ out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 +
186
+ az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0
187
+ out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 +
188
+ aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0
189
+ return out
190
+ }
191
+
192
+ /**
193
+ * Translate by a Vec3
194
+ *
195
+ * @param {Vec3} v the translation vector
196
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
197
+ * @returns {Quat2} out
198
+ */
199
+ translate(v: Vec3, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
200
+ const ax1 = this[0], ay1 = this[1], az1 = this[2], aw1 = this[3]
201
+ const bx1 = v[0] * 0.5, by1 = v[1] * 0.5, bz1 = v[2] * 0.5
202
+ const ax2 = this[4], ay2 = this[5], az2 = this[6], aw2 = this[7]
203
+ out[0] = ax1; out[1] = ay1; out[2] = az1; out[3] = aw1
204
+ out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2
205
+ out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2
206
+ out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2
207
+ out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2
208
+ return out
209
+ }
210
+
211
+ /**
212
+ * Calculates the conjugate of a dual quaternion
213
+ *
214
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
215
+ * @returns {Quat2} out
216
+ */
217
+ conjugate(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
218
+ out[0] = -this[0]; out[1] = -this[1]; out[2] = -this[2]; out[3] = this[3]
219
+ out[4] = -this[4]; out[5] = -this[5]; out[6] = -this[6]; out[7] = this[7]
220
+ return out
221
+ }
222
+
223
+ /**
224
+ * Calculates the inverse of a dual quaternion
225
+ *
226
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
227
+ * @returns {Quat2} out
228
+ */
229
+ invert(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
230
+ const sqlen = this.squaredLength()
231
+ out[0] = -this[0] / sqlen; out[1] = -this[1] / sqlen
232
+ out[2] = -this[2] / sqlen; out[3] = this[3] / sqlen
233
+ out[4] = -this[4] / sqlen; out[5] = -this[5] / sqlen
234
+ out[6] = -this[6] / sqlen; out[7] = this[7] / sqlen
235
+ return out
236
+ }
237
+
238
+ /**
239
+ * Squared length of the real part
240
+ *
241
+ * @returns {Number} squared length
242
+ */
243
+ squaredLength() {
244
+ const x = this[0], y = this[1], z = this[2], w = this[3]
245
+ return x * x + y * y + z * z + w * w
246
+ }
247
+
248
+ /**
249
+ * Length of the real part
250
+ *
251
+ * @returns {Number} length
252
+ */
253
+ len() {
254
+ return Math.sqrt(this.squaredLength())
255
+ }
256
+
257
+ /**
258
+ * Normalize the dual quaternion
259
+ *
260
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
261
+ * @returns {Quat2} out
262
+ */
263
+ normalize(out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
264
+ let magnitude = this.squaredLength()
265
+ if (magnitude > 0) {
266
+ magnitude = Math.sqrt(magnitude)
267
+ const a0 = this[0] / magnitude, a1 = this[1] / magnitude
268
+ const a2 = this[2] / magnitude, a3 = this[3] / magnitude
269
+ const b0 = this[4], b1 = this[5], b2 = this[6], b3 = this[7]
270
+ const a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3
271
+ out[0] = a0; out[1] = a1; out[2] = a2; out[3] = a3
272
+ out[4] = (b0 - a0 * a_dot_b) / magnitude
273
+ out[5] = (b1 - a1 * a_dot_b) / magnitude
274
+ out[6] = (b2 - a2 * a_dot_b) / magnitude
275
+ out[7] = (b3 - a3 * a_dot_b) / magnitude
276
+ }
277
+ return out
278
+ }
279
+
280
+ /**
281
+ * Dot product of the real parts of two dual quaternions
282
+ *
283
+ * @param {Quat2} a the first operand
284
+ * @param {Quat2} b the second operand
285
+ * @returns {Number} dot product
286
+ */
287
+ static dot(a: Quat2, b: Quat2) {
288
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
289
+ }
290
+
291
+ /**
292
+ * Performs a linear interpolation between two dual quaternions
293
+ *
294
+ * @param {Quat2} a the first operand
295
+ * @param {Quat2} b the second operand
296
+ * @param {Number} t interpolation amount, in the range [0-1]
297
+ * @param {Quat2} out the receiving dual quaternion, defaults to quat2()
298
+ * @returns {Quat2} out
299
+ */
300
+ static lerp(a: Quat2, b: Quat2, t: number, out = new Quat2()): Quat2 {
301
+ const mt = 1 - t
302
+ if (Quat2.dot(a, b) < 0) t = -t
303
+ out[0] = a[0] * mt + b[0] * t
304
+ out[1] = a[1] * mt + b[1] * t
305
+ out[2] = a[2] * mt + b[2] * t
306
+ out[3] = a[3] * mt + b[3] * t
307
+ out[4] = a[4] * mt + b[4] * t
308
+ out[5] = a[5] * mt + b[5] * t
309
+ out[6] = a[6] * mt + b[6] * t
310
+ out[7] = a[7] * mt + b[7] * t
311
+ return out
312
+ }
313
+
314
+ /**
315
+ * Adds two dual quaternions
316
+ *
317
+ * @param {Quat2} b the second operand
318
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
319
+ * @returns {Quat2} out
320
+ */
321
+ plus(b: Quat2, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
322
+ out[0] = this[0] + b[0]; out[1] = this[1] + b[1]
323
+ out[2] = this[2] + b[2]; out[3] = this[3] + b[3]
324
+ out[4] = this[4] + b[4]; out[5] = this[5] + b[5]
325
+ out[6] = this[6] + b[6]; out[7] = this[7] + b[7]
326
+ return out
327
+ }
328
+
329
+ /**
330
+ * Scales a dual quaternion by a scalar
331
+ *
332
+ * @param {Number} s the scalar to scale by
333
+ * @param {Quat2} out the receiving dual quaternion, defaults to this
334
+ * @returns {Quat2} out
335
+ */
336
+ scale(s: number, out = glm.ALWAYS_COPY ? new Quat2() : this): Quat2 {
337
+ out[0] = this[0] * s; out[1] = this[1] * s
338
+ out[2] = this[2] * s; out[3] = this[3] * s
339
+ out[4] = this[4] * s; out[5] = this[5] * s
340
+ out[6] = this[6] * s; out[7] = this[7] * s
341
+ return out
342
+ }
343
+
344
+ /**
345
+ * Returns whether two dual quaternions are approximately equal
346
+ *
347
+ * @param {Quat2} b the second operand
348
+ * @returns {Boolean} true if the dual quaternions are approximately equal
349
+ */
350
+ equals(b: Quat2) {
351
+ return (
352
+ equals(this[0], b[0]) && equals(this[1], b[1]) &&
353
+ equals(this[2], b[2]) && equals(this[3], b[3]) &&
354
+ equals(this[4], b[4]) && equals(this[5], b[5]) &&
355
+ equals(this[6], b[6]) && equals(this[7], b[7])
356
+ )
357
+ }
358
+
359
+ /**
360
+ * Returns whether two dual quaternions are exactly equal
361
+ *
362
+ * @param {Quat2} b the second operand
363
+ * @returns {Boolean} true if the dual quaternions are exactly equal
364
+ */
365
+ exactEquals(b: Quat2) {
366
+ return (
367
+ this[0] === b[0] && this[1] === b[1] && this[2] === b[2] && this[3] === b[3] &&
368
+ this[4] === b[4] && this[5] === b[5] && this[6] === b[6] && this[7] === b[7]
369
+ )
370
+ }
371
+
372
+ /**
373
+ * Returns a string representation of a dual quaternion
374
+ *
375
+ * @returns {String} string representation of the dual quaternion
376
+ */
377
+ toString() {
378
+ const fmt = (v: number, suffix: string) => {
379
+ if (v === 0) return ''
380
+ const abs = Math.abs(v)
381
+ const s = abs === 1 && suffix ? suffix : `${abs}${suffix}`
382
+ return v < 0 ? ` - ${s}` : ` + ${s}`
383
+ }
384
+ const qStr = (w: number, x: number, y: number, z: number) => {
385
+ const parts = [
386
+ w !== 0 ? `${w}` : '',
387
+ fmt(x, 'i'),
388
+ fmt(y, 'j'),
389
+ fmt(z, 'k')
390
+ ].join('').trim().replace(/^\+ /, '') || '0'
391
+ return parts
392
+ }
393
+ const real = qStr(this[3], this[0], this[1], this[2])
394
+ const dual = qStr(this[7], this[4], this[5], this[6])
395
+ return `(${real}) + \u03B5(${dual})`
396
+ }
397
+ }
398
+ export interface Quat2 {
399
+ sqrLen: () => number
400
+ str: () => string
401
+ add: (b: Quat2, out?: Quat2) => Quat2
402
+ }
403
+
404
+ // @aliases
405
+ Quat2.prototype.sqrLen = Quat2.prototype.squaredLength
406
+ Quat2.prototype.str = Quat2.prototype.toString
407
+ Quat2.prototype.add = Quat2.prototype.plus
408
+
409
+ export const quat2 = Object.assign(
410
+ (x1 = 0, y1 = 0, z1 = 0, w1 = 1, x2 = 0, y2 = 0, z2 = 0, w2 = 0) => new Quat2(x1, y1, z1, w1, x2, y2, z2, w2),
411
+ Quat2
412
+ )
package/src/utils.ts ADDED
@@ -0,0 +1,248 @@
1
+ import { Vec2 } from './vec2'
2
+ import { Vec3 } from './vec3'
3
+ import { Vec4 } from './vec4'
4
+ import { Quat } from './quat'
5
+ import { Quat2 } from './quat2'
6
+ import { Mat2 } from './mat2'
7
+ import { Mat2x3 } from './mat2x3'
8
+ import { Mat3 } from './mat3'
9
+ import { Mat4 } from './mat4'
10
+
11
+ export type Vec = Vec2 | Vec3 | Vec4
12
+ export type Vector = Vec
13
+ export type Mat = Mat2 | Mat2x3 | Mat3 | Mat4
14
+ export type GenType = Vec | Mat | Quat | Quat2
15
+
16
+ function makeArr<T extends GenType>(a: T): T {
17
+ if (a instanceof Vec2) return new Vec2() as unknown as T
18
+ if (a instanceof Vec3) return new Vec3() as unknown as T
19
+ if (a instanceof Vec4) return new Vec4() as unknown as T
20
+ if (a instanceof Mat2) return new Mat2() as unknown as T
21
+ if (a instanceof Mat2x3) return new Mat2x3() as unknown as T
22
+ if (a instanceof Mat3) return new Mat3() as unknown as T
23
+ if (a instanceof Mat4) return new Mat4() as unknown as T
24
+ if (a instanceof Quat) return new Quat() as unknown as T
25
+ if (a instanceof Quat2) return new Quat2() as unknown as T
26
+ if (a instanceof Float32Array) return new Float32Array() as unknown as T
27
+ throw `unknown type`
28
+ }
29
+
30
+ function calc1<T extends number | GenType>(
31
+ fn: (x: number, i: number) => number,
32
+ x: T,
33
+ out?: T extends GenType ? T : never
34
+ ) {
35
+ if (typeof x === 'number')
36
+ return fn(x, 0)
37
+ const xArr = x as GenType
38
+ const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
39
+ for (let i = 0; i < xArr.length; ++i)
40
+ outArr[i] = fn(xArr[i], i)
41
+ return outArr as T
42
+ }
43
+
44
+ /**
45
+ * Converts degrees to radians
46
+ *
47
+ * @param {Number} degrees angle in degrees
48
+ * @returns {Number} angle in radians
49
+ */
50
+ export function radians(degrees: number): number
51
+ export function radians<T extends GenType>(degrees: T, out?: T): T
52
+ export function radians<T extends number | GenType>(degrees: T, out?: T extends GenType ? T : never) {
53
+ return calc1<T>(x => x / 180.0 * Math.PI, degrees, out)
54
+ }
55
+ export const rad = radians
56
+ export const toRadians = radians
57
+
58
+ /**
59
+ * Converts radians to degrees
60
+ *
61
+ * @param {Number} radians angle in radians
62
+ * @returns {Number} angle in degrees
63
+ */
64
+ export function degrees(radians: number): number
65
+ export function degrees<T extends GenType>(radians: T, out?: T): T
66
+ export function degrees<T extends number | GenType>(radians: T, out?: T extends GenType ? T : never) {
67
+ return calc1<T>(x => x / Math.PI * 180.0, radians, out)
68
+ }
69
+ export const deg = degrees
70
+ export const toDegrees = degrees
71
+
72
+ /**
73
+ * Rounds a number to the nearest integer, with half-values rounding away from zero
74
+ *
75
+ * @param {Number} x the value to round
76
+ * @returns {Number} the rounded value
77
+ */
78
+ export function round(x: number): number
79
+ export function round<T extends GenType>(x: T, out?: T): T
80
+ export function round<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
81
+ return calc1<T>(x => x >= 0 ? Math.round(x) : x % 0.5 === 0 ? Math.floor(x) : Math.round(x), x, out)
82
+ }
83
+
84
+ /**
85
+ * Clamps a number between a minimum and maximum value
86
+ *
87
+ * @param {Number} x the value to clamp
88
+ * @param {Number} min the minimum value
89
+ * @param {Number} max the maximum value
90
+ * @returns {Number} the clamped value
91
+ */
92
+ export function clamp(x: number, min: number, max: number): number
93
+ export function clamp<T extends GenType>(x: T, min: number, max: number, out?: T): T
94
+ export function clamp<T extends number | GenType>(
95
+ x: T,
96
+ min: number, max: number,
97
+ out?: T extends GenType ? T : never
98
+ ) {
99
+ return calc1<T>(x => Math.min(Math.max(x, min), max), x, out)
100
+ }
101
+
102
+ /**
103
+ * Clamps a number between 0 and 1
104
+ *
105
+ * @param {Number} x the value to clamp
106
+ * @returns {Number} the clamped value in the range [0, 1]
107
+ */
108
+ export function clamp01(x: number): number
109
+ export function clamp01<T extends GenType>(x: T, out?: T): T
110
+ export function clamp01<T extends number | GenType>(
111
+ x: T,
112
+ out?: T extends GenType ? T : never
113
+ ) {
114
+ return calc1<T>(x => Math.min(Math.max(x, 0), 1), x, out)
115
+ }
116
+ export const saturate = clamp01
117
+
118
+ /**
119
+ * Performs a linear interpolation between two values
120
+ *
121
+ * @param {Number | Float32Array} x the first value
122
+ * @param {Number | Float32Array} y the second value
123
+ * @param {Number} a interpolation amount in the range [0, 1]
124
+ * @param {Float32Array} out if given Float32Array, puts result in out
125
+ * @returns {Number | Float32Array} the interpolated value
126
+ */
127
+ export function mix(x: number, y: number, a: number): number
128
+ export function mix<T extends GenType>(x: T, y: T, a: number, out?: T): T
129
+ export function mix<T extends number | GenType>(
130
+ x: T, y: T, t: number,
131
+ out?: T extends GenType ? T : never
132
+ ) {
133
+ if (typeof x === 'number')
134
+ return x * (1 - t) + (y as number) * t
135
+ const xArr = x as GenType
136
+ const yArr = y as GenType
137
+ const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
138
+ if (xArr.length !== yArr.length)
139
+ throw `${xArr.length} length != ${yArr} length`
140
+ for (let i = 0; i < xArr.length; ++i)
141
+ outArr[i] = xArr[i] * (1 - t) + yArr[i] * t
142
+ return outArr
143
+ }
144
+ export const lerp = mix
145
+
146
+ /**
147
+ * Returns 0 if x is less than edge, otherwise returns 1
148
+ *
149
+ * @param {Number} edge the threshold value
150
+ * @param {Number} x the value to test
151
+ * @returns {Number} 0 or 1
152
+ */
153
+ export function step(edge: number, x: number): number
154
+ export function step<T extends GenType>(edge: number, x: T, out?: T): T
155
+ export function step<T extends GenType>(edge: T, x: T, out?: T): T
156
+ export function step<T extends number | GenType>(edge: T, x: T, out?: T extends GenType ? T : never) {
157
+ if (typeof x === 'number' && typeof edge === 'number')
158
+ return x < edge ? 0 : 1
159
+ const xArr = x as GenType
160
+ const outArr = (out && out.length === xArr.length ? out : makeArr(xArr)) as GenType
161
+ if (typeof edge === 'number') {
162
+ for (let i = 0; i < xArr.length; ++i)
163
+ outArr[i] = xArr[i] < edge ? 0 : 1
164
+ return outArr as T
165
+ }
166
+ const edgeArr = edge as GenType
167
+ if (xArr.length !== edgeArr.length)
168
+ throw `${xArr.length} length != ${edgeArr} length`
169
+ for (let i = 0; i < xArr.length; ++i)
170
+ outArr[i] = xArr[i] < edgeArr[i] ? 0 : 1
171
+ return outArr as T
172
+ }
173
+
174
+ /**
175
+ * Performs Hermite interpolation between two values
176
+ *
177
+ * @param {Number} edge0 the lower edge of the Hermite function
178
+ * @param {Number} edge1 the upper edge of the Hermite function
179
+ * @param {Number} x the source value for interpolation
180
+ * @returns {Number} the interpolated value in the range [0, 1]
181
+ */
182
+ export function smoothstep(edge0: number, edge1: number, x: number): number
183
+ export function smoothstep<T extends GenType>(edge0: T, edge1: T, x: number, out?: T): T
184
+ export function smoothstep<T extends GenType>(edge0: T, edge1: T, x: T, out?: T): T
185
+ export function smoothstep<T extends number | GenType>(edge0: T, edge1: T, x: T, out?: T extends GenType ? T : never) {
186
+ if (typeof edge0 === 'number' && typeof x === 'number') {
187
+ const t = clamp((x - edge0) / (edge1 as number - edge0), 0, 1)
188
+ return t * t * (3 - 2 * t)
189
+ }
190
+ const aArr = edge0 as GenType
191
+ const bArr = edge1 as GenType
192
+ if (aArr.length !== bArr.length)
193
+ throw `${aArr.length} length != ${bArr} length`
194
+ const outArr = (out && out.length === aArr.length ? out : makeArr(aArr)) as GenType
195
+ if (typeof x === 'number') {
196
+ for (let i = 0; i < aArr.length; ++i) {
197
+ const a = aArr[i]
198
+ const t = clamp((x - a) / (bArr[i] - a), 0, 1)
199
+ outArr[i] = t * t * (3 - 2 * t)
200
+ }
201
+ return outArr as T
202
+ }
203
+ const xArr = x as GenType
204
+ if (xArr.length !== aArr.length)
205
+ throw `${xArr.length} length != ${aArr} length`
206
+ for (let i = 0; i < aArr.length; ++i) {
207
+ const a = aArr[i]
208
+ const t = clamp((xArr[i] - a) / (bArr[i] - a), 0, 1)
209
+ outArr[i] = t * t * (3 - 2 * t)
210
+ }
211
+ return outArr as T
212
+ }
213
+
214
+ /**
215
+ * Returns the fractional part of a number
216
+ *
217
+ * @param {Number} x the value
218
+ * @returns {Number} the fractional part of x
219
+ */
220
+ export function fract(x: number): number
221
+ export function fract<T extends GenType>(x: T, out?: T): T
222
+ export function fract<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
223
+ return calc1<T>(x => x - Math.floor(x), x, out)
224
+ }
225
+
226
+ /**
227
+ * Returns the sign of a number
228
+ *
229
+ * @param {Number} x the value
230
+ * @returns {Number} -1, 0, or 1
231
+ */
232
+ export function sign(x: number): number
233
+ export function sign<T extends GenType>(x: T, out?: T): T
234
+ export function sign<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
235
+ return calc1<T>(x => x > 0 ? 1 : x < 0 ? -1 : 0, x, out)
236
+ }
237
+
238
+ /**
239
+ * Returns the absolute value of the components of a number or vector
240
+ *
241
+ * @param {Number} x the value
242
+ * @returns {Number} -1, 0, or 1
243
+ */
244
+ export function abs(x: number): number
245
+ export function abs<T extends GenType>(x: T, out?: T): T
246
+ export function abs<T extends number | GenType>(x: T, out?: T extends GenType ? T : never) {
247
+ return calc1<T>(x => Math.abs(x), x, out)
248
+ }