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.
@@ -0,0 +1,390 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+ import glmaths, { Vec4, vec4, Mat4, Quat } from '../dist/esm/glmaths'
4
+
5
+ function closeTo(actual: number, expected: number, numDigits = 5) {
6
+ const pass = Math.abs(actual - expected) < Math.pow(10, -numDigits) / 2
7
+ assert.ok(pass, `expected ${actual} to be close to ${expected}`)
8
+ }
9
+
10
+ const EPSILON = glmaths.EPSILON
11
+
12
+ describe('Vec4', () => {
13
+ describe('constructor', () => {
14
+ it('creates zero vector by default', () => {
15
+ const v = new Vec4()
16
+ assert.strictEqual(v[0], 0)
17
+ assert.strictEqual(v[1], 0)
18
+ assert.strictEqual(v[2], 0)
19
+ assert.strictEqual(v[3], 0)
20
+ })
21
+ it('creates with given values', () => {
22
+ const v = new Vec4(1, 2, 3, 4)
23
+ assert.strictEqual(v[0], 1)
24
+ assert.strictEqual(v[1], 2)
25
+ assert.strictEqual(v[2], 3)
26
+ assert.strictEqual(v[3], 4)
27
+ })
28
+ it('extends Float32Array with length 4', () => {
29
+ assert.ok(new Vec4() instanceof Float32Array)
30
+ assert.strictEqual(new Vec4().length, 4)
31
+ })
32
+ })
33
+
34
+ describe('x/y/z/w getters and setters', () => {
35
+ it('gets and sets', () => {
36
+ const v = new Vec4()
37
+ v.x = 1; v.y = 2; v.z = 3; v.w = 4
38
+ assert.strictEqual(v.x, 1)
39
+ assert.strictEqual(v.y, 2)
40
+ assert.strictEqual(v.z, 3)
41
+ assert.strictEqual(v.w, 4)
42
+ })
43
+ })
44
+
45
+ describe('static constants', () => {
46
+ it('ZERO', () => {
47
+ const v = Vec4.ZERO
48
+ assert.strictEqual(v[0], 0)
49
+ assert.strictEqual(v[1], 0)
50
+ assert.strictEqual(v[2], 0)
51
+ assert.strictEqual(v[3], 0)
52
+ })
53
+ it('ONE', () => {
54
+ const v = Vec4.ONE
55
+ assert.strictEqual(v[0], 1)
56
+ assert.strictEqual(v[1], 1)
57
+ assert.strictEqual(v[2], 1)
58
+ assert.strictEqual(v[3], 1)
59
+ })
60
+ })
61
+
62
+ describe('arithmetic', () => {
63
+ it('plus with vector', () => {
64
+ const a = new Vec4(1, 2, 3, 4)
65
+ const b = new Vec4(5, 6, 7, 8)
66
+ const out = new Vec4()
67
+ a.plus(b, out)
68
+ assert.strictEqual(out[0], 6)
69
+ assert.strictEqual(out[1], 8)
70
+ assert.strictEqual(out[2], 10)
71
+ assert.strictEqual(out[3], 12)
72
+ })
73
+ it('plus with scalar', () => {
74
+ const a = new Vec4(1, 2, 3, 4)
75
+ const r = a.plus(10)
76
+ assert.strictEqual(r[0], 11)
77
+ assert.strictEqual(r[1], 12)
78
+ assert.strictEqual(r[2], 13)
79
+ assert.strictEqual(r[3], 14)
80
+ })
81
+ it('minus', () => {
82
+ const a = new Vec4(5, 7, 9, 11)
83
+ const b = new Vec4(1, 2, 3, 4)
84
+ const out = new Vec4()
85
+ a.minus(b, out)
86
+ assert.strictEqual(out[0], 4)
87
+ assert.strictEqual(out[1], 5)
88
+ assert.strictEqual(out[2], 6)
89
+ assert.strictEqual(out[3], 7)
90
+ })
91
+ it('mult with vector', () => {
92
+ const a = new Vec4(2, 3, 4, 5)
93
+ const b = new Vec4(6, 7, 8, 9)
94
+ const out = new Vec4()
95
+ a.mult(b, out)
96
+ assert.strictEqual(out[0], 12)
97
+ assert.strictEqual(out[1], 21)
98
+ assert.strictEqual(out[2], 32)
99
+ assert.strictEqual(out[3], 45)
100
+ })
101
+ it('div with scalar', () => {
102
+ const a = new Vec4(10, 20, 30, 40)
103
+ const r = a.div(10)
104
+ assert.strictEqual(r[0], 1)
105
+ assert.strictEqual(r[1], 2)
106
+ assert.strictEqual(r[2], 3)
107
+ assert.strictEqual(r[3], 4)
108
+ })
109
+ it('scale with number', () => {
110
+ const a = new Vec4(1, 2, 3, 4)
111
+ const r = a.scale(2)
112
+ assert.strictEqual(r[0], 2)
113
+ assert.strictEqual(r[1], 4)
114
+ assert.strictEqual(r[2], 6)
115
+ assert.strictEqual(r[3], 8)
116
+ })
117
+ it('scale with vector', () => {
118
+ const a = new Vec4(1, 2, 3, 4)
119
+ const r = a.scale(new Vec4(2, 3, 4, 5))
120
+ assert.strictEqual(r[0], 2)
121
+ assert.strictEqual(r[1], 6)
122
+ assert.strictEqual(r[2], 12)
123
+ assert.strictEqual(r[3], 20)
124
+ })
125
+ })
126
+
127
+ describe('negate', () => {
128
+ it('negates all components', () => {
129
+ const a = new Vec4(1, -2, 3, -4)
130
+ const r = a.negate()
131
+ assert.strictEqual(r[0], -1)
132
+ assert.strictEqual(r[1], 2)
133
+ assert.strictEqual(r[2], -3)
134
+ assert.strictEqual(r[3], 4)
135
+ })
136
+ })
137
+
138
+ describe('normalize', () => {
139
+ it('normalizes to unit length', () => {
140
+ const a = new Vec4(1, 2, 3, 4)
141
+ const r = a.normalize()
142
+ closeTo(r.len(), 1)
143
+ })
144
+ it('handles zero vector', () => {
145
+ const a = new Vec4(0, 0, 0, 0)
146
+ a.normalize()
147
+ assert.strictEqual(a[0], 0)
148
+ })
149
+ })
150
+
151
+ describe('len / squaredLength', () => {
152
+ it('length of (1,0,0,0) is 1', () => {
153
+ assert.strictEqual(new Vec4(1, 0, 0, 0).len(), 1)
154
+ })
155
+ it('squared length', () => {
156
+ assert.strictEqual(new Vec4(1, 2, 3, 4).squaredLength(), 30)
157
+ })
158
+ })
159
+
160
+ describe('floor / round / ceil', () => {
161
+ it('floor', () => {
162
+ const v = new Vec4(1.7, 2.3, 3.9, 4.1)
163
+ const r = v.floor()
164
+ assert.strictEqual(r[0], 1)
165
+ assert.strictEqual(r[1], 2)
166
+ assert.strictEqual(r[2], 3)
167
+ assert.strictEqual(r[3], 4)
168
+ })
169
+ it('round', () => {
170
+ const v = new Vec4(1.4, 2.6, 3.5, 4.1)
171
+ const r = v.round()
172
+ assert.strictEqual(r[0], 1)
173
+ assert.strictEqual(r[1], 3)
174
+ assert.strictEqual(r[2], 4)
175
+ assert.strictEqual(r[3], 4)
176
+ })
177
+ it('ceil', () => {
178
+ const v = new Vec4(1.1, 2.0, 3.9, 4.01)
179
+ const r = v.ceil()
180
+ assert.strictEqual(r[0], 2)
181
+ assert.strictEqual(r[1], 2)
182
+ assert.strictEqual(r[2], 4)
183
+ assert.strictEqual(r[3], 5)
184
+ })
185
+ })
186
+
187
+ describe('inverse', () => {
188
+ it('inverts components', () => {
189
+ const v = new Vec4(2, 4, 5, 10)
190
+ const r = v.inverse()
191
+ closeTo(r[0], 0.5)
192
+ closeTo(r[1], 0.25)
193
+ closeTo(r[2], 0.2)
194
+ closeTo(r[3], 0.1)
195
+ })
196
+ })
197
+
198
+ describe('clone / toString', () => {
199
+ it('clones independently', () => {
200
+ const a = new Vec4(1, 2, 3, 4)
201
+ const b = a.clone()
202
+ b[0] = 99
203
+ assert.strictEqual(a[0], 1)
204
+ })
205
+ it('toString', () => {
206
+ assert.strictEqual(new Vec4(1, 2, 3, 4).toString(), 'vec4(1, 2, 3, 4)')
207
+ })
208
+ })
209
+
210
+ describe('equals / exactEquals', () => {
211
+ it('exactEquals', () => {
212
+ assert.strictEqual(new Vec4(1, 2, 3, 4).exactEquals(new Vec4(1, 2, 3, 4)), true)
213
+ assert.strictEqual(new Vec4(1, 2, 3, 4).exactEquals(new Vec4(1, 2, 3, 5)), false)
214
+ })
215
+ it('equals with epsilon', () => {
216
+ const a = new Vec4(1, 2, 3, 4)
217
+ const b = new Vec4(1 + EPSILON * 0.1, 2, 3, 4)
218
+ assert.strictEqual(a.equals(b), true)
219
+ })
220
+ })
221
+
222
+ describe('static dot', () => {
223
+ it('calculates dot product', () => {
224
+ const a = new Vec4(1, 2, 3, 4)
225
+ const b = new Vec4(5, 6, 7, 8)
226
+ assert.strictEqual(Vec4.dot(a, b), 70)
227
+ })
228
+ })
229
+
230
+ describe('static lerp', () => {
231
+ it('interpolates at t=0.5', () => {
232
+ const out = Vec4.lerp(new Vec4(0, 0, 0, 0), new Vec4(10, 20, 30, 40), 0.5)
233
+ assert.strictEqual(out[0], 5)
234
+ assert.strictEqual(out[1], 10)
235
+ assert.strictEqual(out[2], 15)
236
+ assert.strictEqual(out[3], 20)
237
+ })
238
+ })
239
+
240
+ describe('static distance / squaredDistance', () => {
241
+ it('distance', () => {
242
+ const a = new Vec4(0, 0, 0, 0)
243
+ const b = new Vec4(1, 0, 0, 0)
244
+ assert.strictEqual(Vec4.distance(a, b), 1)
245
+ })
246
+ it('squaredDistance', () => {
247
+ const a = new Vec4(0, 0, 0, 0)
248
+ const b = new Vec4(1, 2, 3, 4)
249
+ assert.strictEqual(Vec4.squaredDistance(a, b), 30)
250
+ })
251
+ })
252
+
253
+ describe('static max / min', () => {
254
+ it('max', () => {
255
+ const out = Vec4.max(new Vec4(1, 5, 3, 7), new Vec4(3, 2, 6, 4))
256
+ assert.strictEqual(out[0], 3)
257
+ assert.strictEqual(out[1], 5)
258
+ assert.strictEqual(out[2], 6)
259
+ assert.strictEqual(out[3], 7)
260
+ })
261
+ it('min', () => {
262
+ const out = Vec4.min(new Vec4(1, 5, 3, 7), new Vec4(3, 2, 6, 4))
263
+ assert.strictEqual(out[0], 1)
264
+ assert.strictEqual(out[1], 2)
265
+ assert.strictEqual(out[2], 3)
266
+ assert.strictEqual(out[3], 4)
267
+ })
268
+ })
269
+
270
+ describe('scaleAndAdd', () => {
271
+ it('adds scaled vector', () => {
272
+ const a = new Vec4(1, 2, 3, 4)
273
+ const b = new Vec4(1, 1, 1, 1)
274
+ const out = new Vec4()
275
+ a.scaleAndAdd(b, 3, out)
276
+ closeTo(out[0], 4)
277
+ closeTo(out[1], 5)
278
+ closeTo(out[2], 6)
279
+ closeTo(out[3], 7)
280
+ })
281
+ it('static version', () => {
282
+ const out = Vec4.scaleAndAdd(new Vec4(1, 2, 3, 4), new Vec4(2, 2, 2, 2), 0.5)
283
+ closeTo(out[0], 2)
284
+ closeTo(out[1], 3)
285
+ closeTo(out[2], 4)
286
+ closeTo(out[3], 5)
287
+ })
288
+ })
289
+
290
+ describe('abs', () => {
291
+ it('absolute value of components', () => {
292
+ const v = new Vec4(-1, -2, 3, -4)
293
+ const out = new Vec4()
294
+ v.abs(out)
295
+ assert.strictEqual(out[0], 1)
296
+ assert.strictEqual(out[1], 2)
297
+ assert.strictEqual(out[2], 3)
298
+ assert.strictEqual(out[3], 4)
299
+ })
300
+ })
301
+
302
+ describe('transformMat4', () => {
303
+ it('identity transform', () => {
304
+ const v = new Vec4(1, 2, 3, 1)
305
+ const out = new Vec4()
306
+ v.transformMat4(Mat4.identity, out)
307
+ closeTo(out[0], 1)
308
+ closeTo(out[1], 2)
309
+ closeTo(out[2], 3)
310
+ closeTo(out[3], 1)
311
+ })
312
+ })
313
+
314
+ describe('transformQuat', () => {
315
+ it('identity quat leaves vector unchanged', () => {
316
+ const v = new Vec4(1, 2, 3, 4)
317
+ const out = new Vec4()
318
+ v.transformQuat(Quat.identity, out)
319
+ closeTo(out[0], 1)
320
+ closeTo(out[1], 2)
321
+ closeTo(out[2], 3)
322
+ closeTo(out[3], 4) // w preserved
323
+ })
324
+ })
325
+
326
+ describe('GLSL functions', () => {
327
+ it('clamp', () => {
328
+ const v = new Vec4(-1, 0.5, 2, 0.5)
329
+ const out = new Vec4()
330
+ v.clamp(0, 1, out)
331
+ assert.strictEqual(out[0], 0)
332
+ closeTo(out[1], 0.5)
333
+ assert.strictEqual(out[2], 1)
334
+ closeTo(out[3], 0.5)
335
+ })
336
+ it('mix', () => {
337
+ const a = new Vec4(0, 0, 0, 0)
338
+ const b = new Vec4(10, 20, 30, 40)
339
+ const out = new Vec4()
340
+ a.mix(b, 0.5, out)
341
+ closeTo(out[0], 5)
342
+ closeTo(out[1], 10)
343
+ closeTo(out[2], 15)
344
+ closeTo(out[3], 20)
345
+ })
346
+ it('step', () => {
347
+ const v = new Vec4(0.3, 0.5, 0.7, 1.0)
348
+ const out = new Vec4()
349
+ v.step(0.5, out)
350
+ assert.strictEqual(out[0], 0)
351
+ assert.strictEqual(out[1], 1)
352
+ assert.strictEqual(out[2], 1)
353
+ assert.strictEqual(out[3], 1)
354
+ })
355
+ it('fract', () => {
356
+ const v = new Vec4(1.7, 2.3, 3.9, 0.1)
357
+ const out = new Vec4()
358
+ v.fract(out)
359
+ closeTo(out[0], 0.7)
360
+ closeTo(out[1], 0.3)
361
+ closeTo(out[2], 0.9)
362
+ closeTo(out[3], 0.1)
363
+ })
364
+ it('sign', () => {
365
+ const v = new Vec4(-5, 0, 3, -1)
366
+ const out = new Vec4()
367
+ v.sign(out)
368
+ assert.strictEqual(out[0], -1)
369
+ assert.strictEqual(out[1], 0)
370
+ assert.strictEqual(out[2], 1)
371
+ assert.strictEqual(out[3], -1)
372
+ })
373
+ it('saturate', () => {
374
+ const v = new Vec4(-0.5, 0.5, 1.5, 0)
375
+ const out = new Vec4()
376
+ v.saturate(out)
377
+ assert.strictEqual(out[0], 0)
378
+ closeTo(out[1], 0.5)
379
+ assert.strictEqual(out[2], 1)
380
+ assert.strictEqual(out[3], 0)
381
+ })
382
+ })
383
+
384
+ describe('factory function', () => {
385
+ it('creates Vec4', () => {
386
+ const v = vec4(1, 2, 3, 4)
387
+ assert.ok(v instanceof Vec4)
388
+ })
389
+ })
390
+ })
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "declaration": true,
7
+ "declarationMap": true,
8
+ "sourceMap": true,
9
+ "outDir": "./dist",
10
+ "rootDir": "./src",
11
+ "strict": true,
12
+ "importHelpers": false,
13
+ "types": ["node"],
14
+ "lib": ["ES2020", "DOM"]
15
+ },
16
+ "include": ["src", "tests"]
17
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "module": "CommonJS",
5
+ "moduleResolution": "node"
6
+ },
7
+ "include": ["src", "tests"]
8
+ }