@fi4f/hg 0.0.1 → 0.0.2

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/stage.ts DELETED
@@ -1,481 +0,0 @@
1
- import { Event } from "./event.js"
2
- import { Scene } from "./scene.js"
3
- import type { Maybe } from "./types.js"
4
- import { Vector2 } from "./vector2.js"
5
-
6
- export type Stage = {
7
- // configure
8
- readonly configureDebug : "print" | "paint" | boolean
9
- readonly configureW : number
10
- readonly configureH : number
11
- readonly configureUpdatesPerSecond : number
12
- readonly configureRendersPerSecond : number
13
- readonly configureLogicalBackground : string
14
- readonly configureVirtualBackground : string
15
- readonly configureScaleIncrement ?: number | undefined
16
- readonly configureImageSmoothing ?: ImageSmoothingQuality | undefined
17
-
18
- // canvas
19
- logicalCanvasElement: HTMLCanvasElement
20
- virtualCanvasElement: OffscreenCanvas
21
- logicalCanvasContext: CanvasRenderingContext2D
22
- virtualCanvasContext: OffscreenCanvasRenderingContext2D
23
- virtualScale: number
24
-
25
- // events
26
- events: Event.Tree
27
-
28
- // debugs
29
- debugs: Map<string, string | undefined>
30
-
31
- // scene
32
- scene ?: Scene | undefined
33
-
34
- // metrics
35
- lastUpdate : number
36
- lastRender : number
37
- millisPerUpdate : number
38
- millisPerRender : number
39
- framesPerSecond : number
40
- updatesPerSecond: number
41
- rendersPerSecond: number
42
-
43
- averageMillisPerUpdate: number
44
- minimumMillisPerUpdate: number
45
- maximumMillisPerUpdate: number
46
-
47
- averageMillisPerRender: number
48
- minimumMillisPerRender: number
49
- maximumMillisPerRender: number
50
-
51
- oneSecondAccumulator: number
52
- updateAccumulator : number
53
- renderAccumulator : number
54
-
55
- framesPerSecondAccumulator : number
56
- updatesPerSecondAccumulator: number
57
- rendersPerSecondAccumulator: number
58
-
59
- averageMillisPerUpdateAccumulator: number
60
- minimumMillisPerUpdateAccumulator: number
61
- maximumMillisPerUpdateAccumulator: number
62
-
63
- averageMillisPerRenderAccumulator: number
64
- minimumMillisPerRenderAccumulator: number
65
- maximumMillisPerRenderAccumulator: number
66
- }
67
-
68
- export const Stage = {
69
- new(c: HTMLCanvasElement, o ?: {
70
- debug ?: "print" | "paint" | boolean
71
- w ?: number
72
- h ?: number
73
- ups ?: number
74
- rps ?: number
75
- lbg ?: string
76
- vbg ?: string
77
- si ?: number
78
- is ?: ImageSmoothingQuality
79
- }) {
80
- const configureDebug = o?.debug ?? false
81
- const configureW = o?.w ?? 0
82
- const configureH = o?.h ?? 0
83
- const configureUpdatesPerSecond = o?.ups ?? 0
84
- const configureRendersPerSecond = o?.rps ?? 0
85
- const configureLogicalBackground = o?.lbg ?? "#000"
86
- const configureVirtualBackground = o?.vbg ?? "#fff"
87
- const configureScaleIncrement = o?.si
88
- const configureImageSmoothing = o?.is
89
-
90
- const logicalCanvasElement = c
91
- const virtualCanvasElement = new OffscreenCanvas(
92
- configureW || logicalCanvasElement.width,
93
- configureH || logicalCanvasElement.height
94
- )
95
-
96
- const logicalCanvasContext = logicalCanvasElement.getContext("2d")!
97
- const virtualCanvasContext = virtualCanvasElement.getContext("2d")!
98
-
99
- logicalCanvasContext.imageSmoothingEnabled = !!configureImageSmoothing
100
- virtualCanvasContext.imageSmoothingEnabled = !!configureImageSmoothing
101
- if (configureImageSmoothing) {
102
- logicalCanvasContext.imageSmoothingQuality = configureImageSmoothing
103
- virtualCanvasContext.imageSmoothingQuality = configureImageSmoothing
104
- }
105
-
106
- let virtualScale = Math.min(
107
- logicalCanvasElement.width / virtualCanvasElement.width,
108
- logicalCanvasElement.height / virtualCanvasElement.height
109
- )
110
- if (configureScaleIncrement)
111
- virtualScale = Math.floor(virtualScale / configureScaleIncrement) * configureScaleIncrement
112
-
113
- const millisPerUpdate = configureUpdatesPerSecond ? 1000 / configureUpdatesPerSecond : 0
114
- const millisPerRender = configureRendersPerSecond ? 1000 / configureRendersPerSecond : 0
115
-
116
- const stage = {
117
- configureDebug,
118
- configureW,
119
- configureH,
120
- configureUpdatesPerSecond,
121
- configureRendersPerSecond,
122
- configureLogicalBackground,
123
- configureVirtualBackground,
124
- configureScaleIncrement,
125
- configureImageSmoothing,
126
-
127
- logicalCanvasElement,
128
- virtualCanvasElement,
129
- logicalCanvasContext,
130
- virtualCanvasContext,
131
- virtualScale,
132
-
133
- events: Event.Tree.new(),
134
- debugs: new Map(),
135
-
136
- lastUpdate: 0,
137
- lastRender: 0,
138
- millisPerUpdate,
139
- millisPerRender,
140
- framesPerSecond : 0,
141
- updatesPerSecond: 0,
142
- rendersPerSecond: 0,
143
-
144
- averageMillisPerUpdate: 0,
145
- minimumMillisPerUpdate: 0,
146
- maximumMillisPerUpdate: 0,
147
-
148
- averageMillisPerRender: 0,
149
- minimumMillisPerRender: 0,
150
- maximumMillisPerRender: 0,
151
-
152
- oneSecondAccumulator: 0,
153
- updateAccumulator: 0,
154
- renderAccumulator: 0,
155
-
156
- framesPerSecondAccumulator : 0,
157
- updatesPerSecondAccumulator: 0,
158
- rendersPerSecondAccumulator: 0,
159
-
160
- averageMillisPerUpdateAccumulator: 0,
161
- minimumMillisPerUpdateAccumulator: Infinity,
162
- maximumMillisPerUpdateAccumulator: 0,
163
-
164
- averageMillisPerRenderAccumulator: 0,
165
- minimumMillisPerRenderAccumulator: Infinity,
166
- maximumMillisPerRenderAccumulator: 0,
167
- } satisfies Stage
168
-
169
- Stage.setDebugInfo(stage, "stage:frame" , undefined)
170
- Stage.setDebugInfo(stage, "stage:update", undefined)
171
- Stage.setDebugInfo(stage, "stage:render", undefined)
172
- Stage.setDebugInfo(stage, "stage:canvas", undefined)
173
-
174
- new ResizeObserver(() => resize(stage)).observe(c)
175
- Stage.listen< Vector2>(stage, "stage:resize", wh => onResize(stage, wh))
176
- Stage.listen<Maybe<Scene>>(stage, "stage:change", sc => onChange(stage, sc))
177
-
178
- requestAnimationFrame(
179
- firstFrame => requestAnimationFrame(
180
- lastFrame => requestAnimationFrame(
181
- thisFrame => animate(stage, firstFrame, lastFrame, thisFrame)
182
- )
183
- )
184
- )
185
-
186
- return stage
187
- },
188
-
189
- getLogicalSize(stage: Stage) {
190
- return Vector2.new(
191
- stage.logicalCanvasElement.width,
192
- stage.logicalCanvasElement.height
193
- )
194
- },
195
-
196
- getVirtualSize(stage: Stage) {
197
- return Vector2.new(
198
- stage.virtualCanvasElement.width,
199
- stage.virtualCanvasElement.height
200
- )
201
- },
202
-
203
- getVirtualScale(stage: Stage) {
204
- return stage.virtualScale
205
- },
206
-
207
- change(stage: Stage, scene: Maybe<Scene>) {
208
- Stage.dispatch(stage, "stage:change", scene)
209
- },
210
-
211
- listen<T>(stage: Stage, type : string, listener : Event.Listener<T>, o ?: { path ?: string, defer ?: boolean }) {
212
- Event.listen(stage.events, type, listener, o)
213
- },
214
-
215
- deafen<T>(stage: Stage, type ?: string, listener ?: Event.Listener<T>, o ?: { path ?: string, defer ?: boolean }) {
216
- Event.deafen(stage.events, type, listener, o)
217
- },
218
-
219
- dispatch<T>(stage: Stage, type: string, event: T, o ?: { path ?: string, defer ?: boolean }) {
220
- Event.dispatch(stage.events, type, event, o)
221
- },
222
-
223
- poll(stage: Stage) {
224
- Event.poll(stage.events)
225
- },
226
-
227
- getDebugInfo(stage: Stage, id: string) {
228
- return stage.debugs.get(id)
229
- },
230
-
231
- setDebugInfo(stage: Stage, id: string, info: string | undefined) {
232
- stage.debugs.set(id, info)
233
- }
234
- }
235
-
236
- function resize(stage: Stage) {
237
- const w = stage.logicalCanvasElement.getBoundingClientRect().width
238
- const h = stage.logicalCanvasElement.getBoundingClientRect().height
239
- Stage.dispatch(stage, "stage:resize", [w, h])
240
- }
241
-
242
- function onResize(stage: Stage, [w, h]: Vector2) {
243
- stage.logicalCanvasElement.width = w
244
- stage.logicalCanvasElement.height = h
245
- stage.virtualCanvasElement = new OffscreenCanvas(
246
- stage.configureW || stage.logicalCanvasElement.width,
247
- stage.configureH || stage.logicalCanvasElement.height
248
- )
249
-
250
- stage.logicalCanvasContext = stage.logicalCanvasElement.getContext("2d")!
251
- stage.virtualCanvasContext = stage.virtualCanvasElement.getContext("2d")!
252
-
253
- stage.logicalCanvasContext.imageSmoothingEnabled = !!stage.configureImageSmoothing
254
- stage.virtualCanvasContext.imageSmoothingEnabled = !!stage.configureImageSmoothing
255
- if (stage.configureImageSmoothing) {
256
- stage.logicalCanvasContext.imageSmoothingQuality = stage.configureImageSmoothing
257
- stage.virtualCanvasContext.imageSmoothingQuality = stage.configureImageSmoothing
258
- }
259
-
260
- stage.virtualScale = Math.min(
261
- stage.logicalCanvasElement.width / stage.virtualCanvasElement.width,
262
- stage.logicalCanvasElement.height / stage.virtualCanvasElement.height
263
- )
264
- if (stage.configureScaleIncrement)
265
- stage.virtualScale = Math.floor(stage.virtualScale / stage.configureScaleIncrement) * stage.configureScaleIncrement
266
- }
267
-
268
- function onChange(stage: Stage, scene: Maybe<Scene>) {
269
- if (stage.scene && stage.scene.onDetach)
270
- stage.scene.onDetach(stage)
271
- stage.scene = scene
272
- if (stage.scene && stage.scene.onAttach)
273
- stage.scene.onAttach(stage)
274
- }
275
-
276
- function update(stage: Stage, t: number, dt: number) {
277
- Stage.poll(stage)
278
- if (Scene.doesUpdate(stage.scene))
279
- stage.scene.onUpdate({ stage, t, dt })
280
- }
281
-
282
- function render(stage: Stage, t: number, dt: number) {
283
- const f = stage.logicalCanvasContext
284
- const g = stage.virtualCanvasContext
285
-
286
- f.resetTransform()
287
- g.resetTransform()
288
-
289
- f.fillStyle = stage.configureLogicalBackground
290
- const [lw, lh] = Stage.getLogicalSize(stage)
291
- f.fillRect(0, 0, lw, lh)
292
-
293
- g.fillStyle = stage.configureVirtualBackground
294
- const [vw, vh] = Stage.getVirtualSize(stage)
295
- g.fillRect(0, 0, vw, vh)
296
-
297
- const vs = Stage.getVirtualScale(stage)
298
- f.translate(
299
- lw / 2 - vw * vs / 2,
300
- lh / 2 - vh * vs / 2
301
- )
302
- f.scale(vs, vs)
303
-
304
- if (Scene.doesRender(stage.scene))
305
- stage.scene.onRender({ stage, t, dt, g })
306
-
307
- f.drawImage(stage.virtualCanvasElement, 0, 0)
308
-
309
- if (stage.configureDebug && stage.configureDebug !== "print")
310
- paintDebugInfos(stage)
311
- }
312
-
313
- function animate(stage: Stage, firstFrame: number, lastFrame: number, thisFrame: number) {
314
- const delta = thisFrame - lastFrame
315
-
316
- stage.oneSecondAccumulator += delta
317
- stage.updateAccumulator += delta
318
- stage.renderAccumulator += delta
319
-
320
- stage.framesPerSecondAccumulator += 1
321
-
322
- if (stage.updateAccumulator >= stage.millisPerUpdate) {
323
- const t = (thisFrame - firstFrame) / 1000
324
- const dt = (thisFrame - stage.lastUpdate) / 1000
325
-
326
- const a = performance.now()
327
- update(stage, t, dt)
328
- const b = performance.now()
329
-
330
- const millisThisUpdate = b - a
331
-
332
- stage.lastUpdate = thisFrame
333
- stage.updatesPerSecondAccumulator += 1
334
- stage.updateAccumulator -= stage.millisPerUpdate
335
-
336
- stage.averageMillisPerUpdateAccumulator += millisThisUpdate
337
- stage.minimumMillisPerUpdateAccumulator = Math.min(millisThisUpdate, stage.minimumMillisPerUpdateAccumulator)
338
- stage.maximumMillisPerUpdateAccumulator = Math.max(millisThisUpdate, stage.maximumMillisPerUpdateAccumulator)
339
- }
340
-
341
- if (stage.renderAccumulator >= stage.millisPerRender) {
342
- const t = (thisFrame - firstFrame) / 1000
343
- const dt = (thisFrame - stage.lastRender) / 1000
344
-
345
- const a = performance.now()
346
- render(stage, t, dt)
347
- const b = performance.now()
348
-
349
- const millisThisRender = b - a
350
-
351
- stage.lastRender = thisFrame
352
- stage.rendersPerSecondAccumulator += 1
353
- stage.renderAccumulator -= stage.millisPerRender
354
-
355
- stage.averageMillisPerRenderAccumulator += millisThisRender
356
- stage.minimumMillisPerRenderAccumulator = Math.min(millisThisRender, stage.minimumMillisPerRenderAccumulator)
357
- stage.maximumMillisPerRenderAccumulator = Math.max(millisThisRender, stage.maximumMillisPerRenderAccumulator)
358
- }
359
-
360
- if (stage.oneSecondAccumulator >= 1000) {
361
- // update metrics
362
- stage.framesPerSecond = stage.framesPerSecondAccumulator
363
- stage.updatesPerSecond = stage.updatesPerSecondAccumulator
364
- stage.rendersPerSecond = stage.rendersPerSecondAccumulator
365
-
366
- stage.averageMillisPerUpdate = stage.averageMillisPerUpdateAccumulator / stage.updatesPerSecondAccumulator
367
- stage.minimumMillisPerUpdate = stage.minimumMillisPerUpdateAccumulator
368
- stage.maximumMillisPerUpdate = stage.maximumMillisPerUpdateAccumulator
369
-
370
- stage.averageMillisPerRender = stage.averageMillisPerRenderAccumulator / stage.rendersPerSecondAccumulator
371
- stage.minimumMillisPerRender = stage.minimumMillisPerRenderAccumulator
372
- stage.maximumMillisPerRender = stage.maximumMillisPerRenderAccumulator
373
-
374
- // reset accumulators
375
- stage.framesPerSecondAccumulator = 0
376
- stage.updatesPerSecondAccumulator = 0
377
- stage.rendersPerSecondAccumulator = 0
378
-
379
- stage.averageMillisPerUpdateAccumulator = 0
380
- stage.minimumMillisPerUpdateAccumulator = Infinity
381
- stage.maximumMillisPerUpdateAccumulator = 0
382
-
383
- stage.averageMillisPerRenderAccumulator = 0
384
- stage.minimumMillisPerRenderAccumulator = Infinity
385
- stage.maximumMillisPerRenderAccumulator = 0
386
-
387
- stage.oneSecondAccumulator -= 1000
388
-
389
- Stage.setDebugInfo(stage, "stage:frame" , getFrameInfo (stage))
390
- Stage.setDebugInfo(stage, "stage:update", getUpdateInfo(stage))
391
- Stage.setDebugInfo(stage, "stage:render", getRenderInfo(stage))
392
- Stage.setDebugInfo(stage, "stage:canvas", getCanvasInfo(stage))
393
-
394
- if (stage.configureDebug && stage.configureDebug !== "paint")
395
- printDebugInfos(stage)
396
- }
397
-
398
- requestAnimationFrame(nextFrame => animate(stage, firstFrame, thisFrame, nextFrame))
399
- }
400
-
401
- function getFrameInfo(stage: Stage) {
402
- return `FRAME ${stage.framesPerSecond.toFixed(0)} hz`
403
- }
404
-
405
- function getUpdateInfo(stage: Stage) {
406
- return `UPDATE ${stage.updatesPerSecond.toFixed(0)} hz @ ${stage.averageMillisPerUpdate.toFixed(2)} [${stage.minimumMillisPerUpdate.toFixed(2)} - ${stage.maximumMillisPerUpdate.toFixed(2)}] of ${stage.millisPerUpdate.toFixed(2)} ms`
407
- }
408
-
409
- function getRenderInfo(stage: Stage) {
410
- return `RENDER ${stage.rendersPerSecond.toFixed(0)} hz @ ${stage.averageMillisPerRender.toFixed(2)} [${stage.minimumMillisPerRender.toFixed(2)} - ${stage.maximumMillisPerRender.toFixed(2)}] of ${stage.millisPerRender.toFixed(2)} ms`
411
- }
412
-
413
- function getCanvasInfo(stage: Stage) {
414
- const [lw, lh] = Stage.getLogicalSize (stage)
415
- const [vw, vh] = Stage.getVirtualSize (stage)
416
- const vs = Stage.getVirtualScale(stage)
417
- return `CANVAS ${lw}x${lh} ${vw}x${vh} ${(100 * vs).toFixed(2)}%`
418
- }
419
-
420
- function printDebugInfos(stage: Stage) {
421
- let infos = "*** DEBUG ***\n"
422
- for (const [id, info] of stage.debugs) {
423
- if (!info) continue
424
- infos += `${info}\n`
425
- }
426
- console.log(infos)
427
- }
428
-
429
- function paintDebugInfos(stage: Stage) {
430
- const g = stage.logicalCanvasContext
431
-
432
- const configureDebugBackground = "#000a"
433
- const configureDebugForeground = "#ffff"
434
- const configurePaddingX = 10 as const
435
- const configurePaddingY = 10 as const
436
- const configureSpacingY = 0 as const
437
- const configureFont = "16px monospace" as const
438
-
439
- g.resetTransform()
440
- g.font = configureFont
441
-
442
- let w = 0;
443
- let h = 0;
444
- for (const [id, info] of stage.debugs) {
445
- if (!info) continue
446
-
447
- const tm = g.measureText(info)
448
- w = Math.max(w, tm.width)
449
- h += (
450
- tm.fontBoundingBoxAscent +
451
- tm.fontBoundingBoxDescent +
452
- configureSpacingY
453
- )
454
- }
455
-
456
- if (h > 0) {
457
- w += configurePaddingX * 2
458
- h += configurePaddingY * 2
459
- h -= configureSpacingY
460
- }
461
-
462
- // draw background
463
- g.fillStyle = configureDebugBackground
464
- g.fillRect(0, 0, w, h)
465
-
466
- // draw foreground
467
- g.fillStyle = configureDebugForeground
468
- let x = configurePaddingX
469
- let y = configurePaddingY
470
- for (const [id, info] of stage.debugs) {
471
- if (!info) continue
472
-
473
- const tm = g.measureText(info)
474
- g.fillText(info, x, y + tm.fontBoundingBoxAscent)
475
- y += (
476
- configureSpacingY +
477
- tm.fontBoundingBoxAscent +
478
- tm.fontBoundingBoxDescent
479
- )
480
- }
481
- }
package/src/types.ts DELETED
@@ -1 +0,0 @@
1
- export type Maybe<T> = T | undefined
package/src/vector2.ts DELETED
@@ -1,80 +0,0 @@
1
- import { ADD, SUB, MUL, DIV, MOD } from "./math.js";
2
-
3
- export type Vector2 = [number, number]
4
-
5
- export const X = 0 as const;
6
- export const Y = 1 as const;
7
-
8
- export const __get__ = {
9
- x(a: Vector2) { return a[X] },
10
- y(a: Vector2) { return a[Y] },
11
- }
12
-
13
- export const __set__ = {
14
- x(a: Vector2, x: number) { return a[X] = x },
15
- y(a: Vector2, y: number) { return a[Y] = y },
16
- }
17
-
18
- export function x(a: Vector2, x ?: number) {
19
- return x === undefined ? __get__.x(a) : __set__.x(a, x)
20
- }
21
-
22
- export function y(a: Vector2, y ?: number) {
23
- return y === undefined ? __get__.y(a) : __set__.y(a, y)
24
- }
25
-
26
- export const Vector2 = {
27
- X, Y,
28
- __get__,
29
- __set__,
30
- x, y,
31
-
32
- new(...a: Array<number>) {
33
- if (a.length === 1) return [ a[X]! , a[X]! ] satisfies Vector2
34
- else return [ a[X] ?? 0, a[Y] ?? 0 ] satisfies Vector2
35
- },
36
-
37
- from(a: number | Array<number>) {
38
- if (typeof a === "number") return [ a , a ] satisfies Vector2
39
- else return [ a[X] ?? 0, a[Y] ?? 0 ] satisfies Vector2
40
- },
41
-
42
- el(op: (a: number, b: number) => number, a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
43
- const [ xa, ya ] = Vector2.from(a)
44
- const [ xb, yb ] = Vector2.from(b)
45
- __set__.x(out, op(xa, xb))
46
- __set__.y(out, op(ya, yb))
47
- return out
48
- },
49
-
50
- add(a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
51
- return Vector2.el(ADD, a, b, out)
52
- },
53
-
54
- sub(a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
55
- return Vector2.el(SUB, a, b, out)
56
- },
57
-
58
- hmul(a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
59
- return Vector2.el(MUL, a, b, out)
60
- },
61
-
62
- hdiv(a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
63
- return Vector2.el(DIV, a, b, out)
64
- },
65
-
66
- hmod(a: number | Vector2, b: number | Vector2, out: Vector2 = Vector2.new()) {
67
- return Vector2.el(MOD, a, b, out)
68
- },
69
-
70
- dot(a: number | Vector2, b: number | Vector2 = a) {
71
- const [xa, ya] = Vector2.from(a)
72
- const [xb, yb] = Vector2.from(b)
73
- return xa * xb + ya * yb
74
- },
75
-
76
- toString(a: number | Vector2) {
77
- const [x, y] = Vector2.from(a)
78
- return `vec2<${x}, ${y}>`
79
- }
80
- }
package/src/vector3.ts DELETED
@@ -1,88 +0,0 @@
1
- import { ADD, SUB, MUL, DIV, MOD } from "./math.js";
2
-
3
- export type Vector3 = [number, number, number]
4
-
5
- export const X = 0 as const;
6
- export const Y = 1 as const;
7
- export const Z = 2 as const;
8
-
9
- export const __get__ = {
10
- x(a: Vector3) { return a[X] },
11
- y(a: Vector3) { return a[Y] },
12
- z(a: Vector3) { return a[Z] },
13
- }
14
-
15
- export const __set__ = {
16
- x(a: Vector3, x: number) { return a[X] = x },
17
- y(a: Vector3, y: number) { return a[Y] = y },
18
- z(a: Vector3, z: number) { return a[Z] = z },
19
- }
20
-
21
- export function x(a: Vector3, x ?: number) {
22
- return x === undefined ? __get__.x(a) : __set__.x(a, x)
23
- }
24
-
25
- export function y(a: Vector3, y ?: number) {
26
- return y === undefined ? __get__.y(a) : __set__.y(a, y)
27
- }
28
-
29
- export function z(a: Vector3, z ?: number) {
30
- return z === undefined ? __get__.z(a) : __set__.z(a, z)
31
- }
32
-
33
- export const Vector3 = {
34
- X, Y, Z,
35
- __get__,
36
- __set__,
37
- x, y, z,
38
-
39
- new(...a: Array<number>) {
40
- if (a.length === 1) return [ a[X]! , a[X]! , a[X]! ] satisfies Vector3
41
- else return [ a[X] ?? 0, a[Y] ?? 0, a[Z] ?? 0 ] satisfies Vector3
42
- },
43
-
44
- from(a: number | Array<number>) {
45
- if (typeof a === "number") return [ a , a , a ] satisfies Vector3
46
- else return [ a[X] ?? 0, a[Y] ?? 0, a[Z] ?? 0 ] satisfies Vector3
47
- },
48
-
49
- el(op: (a: number, b: number) => number, a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
50
- const [ xa, ya, za ] = Vector3.from(a)
51
- const [ xb, yb, zb ] = Vector3.from(b)
52
- __set__.x(out, op(xa, xb))
53
- __set__.y(out, op(ya, yb))
54
- __set__.z(out, op(za, zb))
55
- return out
56
- },
57
-
58
- add(a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
59
- return Vector3.el(ADD, a, b, out)
60
- },
61
-
62
- sub(a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
63
- return Vector3.el(SUB, a, b, out)
64
- },
65
-
66
- hmul(a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
67
- return Vector3.el(MUL, a, b, out)
68
- },
69
-
70
- hdiv(a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
71
- return Vector3.el(DIV, a, b, out)
72
- },
73
-
74
- hmod(a: number | Vector3, b: number | Vector3, out: Vector3 = Vector3.new()) {
75
- return Vector3.el(MOD, a, b, out)
76
- },
77
-
78
- dot(a: number | Vector3, b: number | Vector3 = a) {
79
- const [xa, ya, za] = Vector3.from(a)
80
- const [xb, yb, zb] = Vector3.from(b)
81
- return xa * xb + ya * yb + za * zb
82
- },
83
-
84
- toString(a: number | Vector3) {
85
- const [x, y, z] = Vector3.from(a)
86
- return `vec3<${x}, ${y}, ${z}>`
87
- }
88
- }