@oidoid/void 0.1.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.
Files changed (66) hide show
  1. package/bin/ase +14 -0
  2. package/dist/atlas/aseprite.d.ts +37 -0
  3. package/dist/atlas/aseprite.js +2 -0
  4. package/dist/atlas/aseprite.js.map +1 -0
  5. package/dist/atlas/atlas.d.ts +20 -0
  6. package/dist/atlas/atlas.js +68 -0
  7. package/dist/atlas/atlas.js.map +1 -0
  8. package/dist/audio/synth.d.ts +4 -0
  9. package/dist/audio/synth.js +21 -0
  10. package/dist/audio/synth.js.map +1 -0
  11. package/dist/graphics/bitmap.d.ts +14 -0
  12. package/dist/graphics/bitmap.js +14 -0
  13. package/dist/graphics/bitmap.js.map +1 -0
  14. package/dist/graphics/cam.d.ts +16 -0
  15. package/dist/graphics/cam.js +42 -0
  16. package/dist/graphics/cam.js.map +1 -0
  17. package/dist/graphics/frag.glsl.d.ts +1 -0
  18. package/dist/graphics/frag.glsl.js +15 -0
  19. package/dist/graphics/frag.glsl.js.map +1 -0
  20. package/dist/graphics/frame-listener.d.ts +16 -0
  21. package/dist/graphics/frame-listener.js +83 -0
  22. package/dist/graphics/frame-listener.js.map +1 -0
  23. package/dist/graphics/renderer.d.ts +12 -0
  24. package/dist/graphics/renderer.js +184 -0
  25. package/dist/graphics/renderer.js.map +1 -0
  26. package/dist/graphics/vert.glsl.d.ts +1 -0
  27. package/dist/graphics/vert.glsl.js +46 -0
  28. package/dist/graphics/vert.glsl.js.map +1 -0
  29. package/dist/index.d.ts +32 -0
  30. package/dist/index.js +79 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/input/gamepad-poller.d.ts +8 -0
  33. package/dist/input/gamepad-poller.js +38 -0
  34. package/dist/input/gamepad-poller.js.map +1 -0
  35. package/dist/input/input.d.ts +44 -0
  36. package/dist/input/input.js +175 -0
  37. package/dist/input/input.js.map +1 -0
  38. package/dist/input/keyboard-poller.d.ts +7 -0
  39. package/dist/input/keyboard-poller.js +30 -0
  40. package/dist/input/keyboard-poller.js.map +1 -0
  41. package/dist/input/pointer-poller.d.ts +12 -0
  42. package/dist/input/pointer-poller.js +67 -0
  43. package/dist/input/pointer-poller.js.map +1 -0
  44. package/dist/sprite/sprite.d.ts +51 -0
  45. package/dist/sprite/sprite.js +161 -0
  46. package/dist/sprite/sprite.js.map +1 -0
  47. package/dist/storage/json-storage.d.ts +4 -0
  48. package/dist/storage/json-storage.js +13 -0
  49. package/dist/storage/json-storage.js.map +1 -0
  50. package/dist/test/tsconfig.json +13 -0
  51. package/dist/text/font.d.ts +6 -0
  52. package/dist/text/font.js +18 -0
  53. package/dist/text/font.js.map +1 -0
  54. package/dist/text/text-layout.d.ts +11 -0
  55. package/dist/text/text-layout.js +73 -0
  56. package/dist/text/text-layout.js.map +1 -0
  57. package/dist/tsconfig.json +12 -0
  58. package/dist/types/2d.d.ts +9 -0
  59. package/dist/types/2d.js +2 -0
  60. package/dist/types/2d.js.map +1 -0
  61. package/dist/void.js +60 -0
  62. package/dist/void.js.map +7 -0
  63. package/dist/void.meta.json +294 -0
  64. package/license.text +661 -0
  65. package/package.json +73 -0
  66. package/readme.md +33 -0
package/bin/ase ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env sh
2
+ # ase --sheet=<file.png> [--data=<file.json>] [options] [files]
3
+ set -eu
4
+ exec aseprite \
5
+ --batch \
6
+ --color-mode=indexed \
7
+ --filename-format={title}--{tag}--{frame} \
8
+ --ignore-empty \
9
+ --list-slices \
10
+ --list-tags \
11
+ --merge-duplicates \
12
+ --sheet-pack \
13
+ --tagname-format={title}--{tag} \
14
+ "$@"
@@ -0,0 +1,37 @@
1
+ import type { Box, WH } from '../types/2d.js';
2
+ /** https://github.com/aseprite/aseprite/blob/master/docs/ase-file-specs.md */
3
+ export type Aseprite = {
4
+ readonly meta: AsepriteMeta;
5
+ readonly frames: AsepriteFrameMap;
6
+ };
7
+ export type AsepriteFrameMap = {
8
+ readonly [key: AsepriteAnimTagFrame]: AsepriteFrame;
9
+ };
10
+ export type AsepriteMeta = {
11
+ /** `--list-tags`. */
12
+ readonly frameTags: readonly AsepriteTagSpan[];
13
+ /** `--list-slices`. */
14
+ readonly slices: readonly AsepriteSlice[];
15
+ };
16
+ /** `--filename-format='{title}--{tag}--{frame}'`. */
17
+ export type AsepriteAnimTagFrame = `${AnimTag}--${bigint}`;
18
+ /** `--tagname-format={title}--{tag}`. */
19
+ export type AnimTag = `${string}--${string}`;
20
+ export type AsepriteFrame = {
21
+ /** Bounds including padding. */
22
+ readonly frame: Readonly<Box>;
23
+ /** WH without padding. */
24
+ readonly sourceSize: Readonly<WH>;
25
+ };
26
+ export type AsepriteTagSpan = {
27
+ readonly name: AnimTag | string;
28
+ readonly from: number;
29
+ /** The inclusive ending index, possibly equal to from. */
30
+ readonly to: number;
31
+ };
32
+ export type AsepriteSlice = {
33
+ readonly name: AnimTag | string;
34
+ readonly keys: readonly {
35
+ readonly bounds: Readonly<Box>;
36
+ }[];
37
+ };
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=aseprite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aseprite.js","sourceRoot":"","sources":["../../src/atlas/aseprite.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ import type { Box, WH, XY } from '../types/2d.js';
2
+ import type { AnimTag, Aseprite, AsepriteFrame, AsepriteFrameMap, AsepriteSlice, AsepriteTagSpan } from './aseprite.js';
3
+ export type Atlas<T extends AnimTag = AnimTag> = {
4
+ readonly [tag in T]: Anim<T>;
5
+ };
6
+ export type Anim<T extends AnimTag = AnimTag> = {
7
+ readonly cels: readonly Readonly<XY>[];
8
+ readonly hitbox: Readonly<Box>;
9
+ /** A multiple of 16 (maxAnimCels). */
10
+ readonly id: number;
11
+ readonly tag: T;
12
+ } & Readonly<WH>;
13
+ export declare const maxAnimCels = 16;
14
+ export declare function parseAtlas(ase: Aseprite): Atlas;
15
+ /** @internal */
16
+ export declare function parseAnim(id: number, span: AsepriteTagSpan, map: AsepriteFrameMap, slices: readonly AsepriteSlice[]): Anim;
17
+ /** @internal */
18
+ export declare function parseCel(frame: AsepriteFrame): Readonly<XY>;
19
+ /** @internal */
20
+ export declare function parseHitbox(span: AsepriteTagSpan, slices: readonly AsepriteSlice[]): Readonly<Box>;
@@ -0,0 +1,68 @@
1
+ export const maxAnimCels = 16;
2
+ export function parseAtlas(ase) {
3
+ const atlas = new Map();
4
+ for (const span of ase.meta.frameTags) {
5
+ const tag = parseTag(span.name);
6
+ if (atlas.has(tag))
7
+ throw Error(`duplicate tag "${tag}" in atlas`);
8
+ const id = atlas.size * maxAnimCels;
9
+ atlas.set(tag, parseAnim(id, span, ase.frames, ase.meta.slices));
10
+ }
11
+ const extraSlices = ase.meta.slices.filter(slice => !atlas.has(parseTag(slice.name)));
12
+ if (extraSlices.length) {
13
+ throw Error('unknown hitbox tags in atlas: ' +
14
+ `${extraSlices.map(slice => slice.name).join(', ')}`);
15
+ }
16
+ return Object.fromEntries(atlas);
17
+ }
18
+ /** @internal */
19
+ export function parseAnim(id, span, map, slices) {
20
+ const frames = [...parseAnimFrames(span, map)];
21
+ return {
22
+ id,
23
+ w: frames[0].sourceSize.w,
24
+ h: frames[0].sourceSize.h,
25
+ cels: frames.map(parseCel),
26
+ hitbox: parseHitbox(span, slices),
27
+ tag: parseTag(span.name)
28
+ };
29
+ }
30
+ function* parseAnimFrames(span, map) {
31
+ for (let i = span.from; i <= span.to && i - span.from < maxAnimCels; i++) {
32
+ const animTagFrame = `${span.name}--${i}`;
33
+ const frame = map[animTagFrame];
34
+ if (!frame)
35
+ throw Error(`missing frame "${animTagFrame}"`);
36
+ yield frame;
37
+ }
38
+ }
39
+ /** @internal */
40
+ export function parseCel(frame) {
41
+ return {
42
+ x: frame.frame.x + (frame.frame.w - frame.sourceSize.w) / 2,
43
+ y: frame.frame.y + (frame.frame.h - frame.sourceSize.h) / 2
44
+ };
45
+ }
46
+ /** @internal */
47
+ export function parseHitbox(span, slices) {
48
+ const tagSlices = slices.filter(slice => slice.name === span.name);
49
+ if (tagSlices.length > 1) {
50
+ throw Error(`tag "${span.name}" has multiple hitboxes`);
51
+ }
52
+ const box = tagSlices[0]?.keys[0]?.bounds ?? { x: 0, y: 0, w: 0, h: 0 };
53
+ // https://github.com/aseprite/aseprite/issues/3524
54
+ for (const key of tagSlices[0]?.keys ?? []) {
55
+ if (key.bounds.x !== box.x ||
56
+ key.bounds.y !== box.y ||
57
+ key.bounds.w !== box.w ||
58
+ key.bounds.h !== box.h)
59
+ throw Error(`tag "${span.name}" hitbox varies across frames`);
60
+ }
61
+ return box;
62
+ }
63
+ function parseTag(tag) {
64
+ if (!tag.includes('--'))
65
+ throw Error(`tag "${tag}" is malformed`);
66
+ return tag;
67
+ }
68
+ //# sourceMappingURL=atlas.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atlas.js","sourceRoot":"","sources":["../../src/atlas/atlas.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare class Synth {
2
+ #private;
3
+ beep(type: OscillatorType, startHz: number, endHz: number, duration: number): void;
4
+ }
@@ -0,0 +1,21 @@
1
+ export class Synth {
2
+ #context;
3
+ beep(type, startHz, endHz, duration // why can't this be short?
4
+ ) {
5
+ this.#context ??= new AudioContext();
6
+ const now = this.#context.currentTime;
7
+ const end = now + duration;
8
+ const oscillator = this.#context.createOscillator();
9
+ oscillator.type = type;
10
+ oscillator.frequency.setValueAtTime(startHz, now);
11
+ oscillator.frequency.exponentialRampToValueAtTime(endHz, end);
12
+ const gain = this.#context.createGain();
13
+ gain.gain.setValueAtTime(1, now);
14
+ gain.gain.exponentialRampToValueAtTime(0.01, end);
15
+ oscillator.connect(gain);
16
+ gain.connect(this.#context.destination);
17
+ oscillator.start();
18
+ oscillator.stop(end);
19
+ }
20
+ }
21
+ //# sourceMappingURL=synth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"synth.js","sourceRoot":"","sources":["../../src/audio/synth.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,KAAK;IAChB,QAAQ,CAAe;IAEvB,IAAI,CACF,IAAoB,EACpB,OAAe,EACf,KAAa,EACb,QAAgB,CAAC,2BAA2B;;QAE5C,IAAI,CAAC,QAAQ,KAAK,IAAI,YAAY,EAAE,CAAA;QACpC,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAA;QACrC,MAAM,GAAG,GAAG,GAAG,GAAG,QAAQ,CAAA;QAE1B,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,gBAAgB,EAAE,CAAA;QACnD,UAAU,CAAC,IAAI,GAAG,IAAI,CAAA;QACtB,UAAU,CAAC,SAAS,CAAC,cAAc,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QACjD,UAAU,CAAC,SAAS,CAAC,4BAA4B,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAE7D,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,CAAA;QACvC,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QAChC,IAAI,CAAC,IAAI,CAAC,4BAA4B,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;QAEjD,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACxB,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;QAEvC,UAAU,CAAC,KAAK,EAAE,CAAA;QAClB,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;CACF"}
@@ -0,0 +1,14 @@
1
+ export type Bitmap = {
2
+ /** 8x: i16, 8y: i16 */
3
+ readonly _xy: number;
4
+ /** w: u12, h: u12 */
5
+ readonly _wh: number;
6
+ /** id+cel: u15, flipX: b1, flipY: b1, zend: b1, z: u3 */
7
+ readonly _iffzz: number;
8
+ };
9
+ export declare class BitmapBuffer {
10
+ readonly buffer: Uint32Array;
11
+ size: number;
12
+ constructor(capacity: number);
13
+ push(bmp: Readonly<Bitmap>): void;
14
+ }
@@ -0,0 +1,14 @@
1
+ export class BitmapBuffer {
2
+ buffer;
3
+ size = 0;
4
+ constructor(capacity) {
5
+ this.buffer = new Uint32Array(capacity * 3);
6
+ }
7
+ push(bmp) {
8
+ this.buffer[this.size * 3] = bmp._xy;
9
+ this.buffer[this.size * 3 + 1] = bmp._wh;
10
+ this.buffer[this.size * 3 + 2] = bmp._iffzz;
11
+ this.size++;
12
+ }
13
+ }
14
+ //# sourceMappingURL=bitmap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../../src/graphics/bitmap.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,YAAY;IACd,MAAM,CAAa;IAC5B,IAAI,GAAG,CAAC,CAAA;IAER,YAAY,QAAgB;QAC1B,IAAI,CAAC,MAAM,GAAG,IAAI,WAAW,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,CAAC,GAAqB;QACxB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAA;QACpC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,GAAG,CAAA;QACxC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAA;QAC3C,IAAI,CAAC,IAAI,EAAE,CAAA;IACb,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ import type { Box, WH, XY } from '../types/2d.js';
2
+ export declare class Cam implements Box {
3
+ #private;
4
+ minWH: WH;
5
+ minScale: number;
6
+ x: number;
7
+ y: number;
8
+ lvl: Box;
9
+ get h(): number;
10
+ /** Fill or just barely not fill the viewport in scaled pixels. */
11
+ resize(zoomOut?: number): void;
12
+ get scale(): number;
13
+ /** Returns the integral position in level coordinates. */
14
+ toLevelXY(clientXY: Readonly<XY>): XY;
15
+ get w(): number;
16
+ }
@@ -0,0 +1,42 @@
1
+ export class Cam {
2
+ minWH = { w: 256, h: 256 };
3
+ minScale = 1;
4
+ x = 0; //xy?
5
+ y = 0;
6
+ lvl = { x: -4096, y: -4096, w: 8191, h: 8191 };
7
+ #clientWH = { w: 1, h: 1 };
8
+ #scale = 1;
9
+ #w = this.minWH.w;
10
+ #h = this.minWH.h;
11
+ get h() {
12
+ return this.#h;
13
+ }
14
+ /** Fill or just barely not fill the viewport in scaled pixels. */
15
+ resize(zoomOut) {
16
+ // WH of body in CSS px; document.body.getBoundingClientRect() returns
17
+ // incorrectly large sizing on mobile that includes the address bar
18
+ this.#clientWH.w = innerWidth;
19
+ this.#clientWH.h = innerHeight;
20
+ const nativeW = Math.round(this.#clientWH.w * devicePixelRatio); // physical
21
+ const nativeH = Math.round(this.#clientWH.h * devicePixelRatio);
22
+ this.#scale = Math.max(this.minScale, Math.floor(Math.min(nativeW / this.minWH.w, nativeH / this.minWH.h)) -
23
+ (zoomOut ?? 0) // Default is to zoom in as much as possible.
24
+ );
25
+ this.#w = Math.floor(nativeW / this.#scale);
26
+ this.#h = Math.floor(nativeH / this.#scale);
27
+ }
28
+ get scale() {
29
+ return this.#scale;
30
+ }
31
+ /** Returns the integral position in level coordinates. */
32
+ toLevelXY(clientXY) {
33
+ return {
34
+ x: Math.round(this.x + (clientXY.x / this.#clientWH.w) * this.#w),
35
+ y: Math.round(this.y + (clientXY.y / this.#clientWH.h) * this.#h)
36
+ };
37
+ }
38
+ get w() {
39
+ return this.#w;
40
+ }
41
+ }
42
+ //# sourceMappingURL=cam.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cam.js","sourceRoot":"","sources":["../../src/graphics/cam.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,GAAG;IACd,KAAK,GAAO,EAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAC,CAAA;IAC5B,QAAQ,GAAW,CAAC,CAAA;IACpB,CAAC,GAAW,CAAC,CAAA,CAAC,KAAK;IACnB,CAAC,GAAW,CAAC,CAAA;IACb,GAAG,GAAQ,EAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAC,CAAA;IAExC,SAAS,GAAO,EAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAC,CAAA;IACrC,MAAM,GAAG,CAAC,CAAA;IACV,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IACjB,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAA;IAEjB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;IAED,kEAAkE;IAClE,MAAM,CAAC,OAAgB;QACrB,sEAAsE;QACtE,mEAAmE;QACnE,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,UAAU,CAAA;QAC7B,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,WAAW,CAAA;QAE9B,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAA,CAAC,WAAW;QAC3E,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAA;QAE/D,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CACpB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAClE,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,6CAA6C;SAC/D,CAAA;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;QAC3C,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,0DAA0D;IAC1D,SAAS,CAAC,QAAsB;QAC9B,OAAO;YACL,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;YACjE,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC;SAClE,CAAA;IACH,CAAC;IAED,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,EAAE,CAAA;IAChB,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export declare const fragGLSL = "#version 300 es\nuniform mediump sampler2D uSpritesheet;\nuniform mediump uvec2 uSpritesheetSize;\n\nflat in highp ivec4 vTexXYWH;\nin highp vec2 vDstWH;\n\nout highp vec4 oFrag;\n\nvoid main() {\n highp vec2 px = vec2(vTexXYWH.xy) + mod(vDstWH, vec2(vTexXYWH.zw));\n oFrag = texture(uSpritesheet, px / vec2(uSpritesheetSize));\n if(oFrag.a < 1.) discard;\n}";
@@ -0,0 +1,15 @@
1
+ export const fragGLSL = `#version 300 es
2
+ uniform mediump sampler2D uSpritesheet;
3
+ uniform mediump uvec2 uSpritesheetSize;
4
+
5
+ flat in highp ivec4 vTexXYWH;
6
+ in highp vec2 vDstWH;
7
+
8
+ out highp vec4 oFrag;
9
+
10
+ void main() {
11
+ highp vec2 px = vec2(vTexXYWH.xy) + mod(vDstWH, vec2(vTexXYWH.zw));
12
+ oFrag = texture(uSpritesheet, px / vec2(uSpritesheetSize));
13
+ if(oFrag.a < 1.) discard;
14
+ }`;
15
+ //# sourceMappingURL=frag.glsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frag.glsl.js","sourceRoot":"","sources":["../../src/graphics/frag.glsl.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,QAAQ,GAAG;;;;;;;;;;;;;EAatB,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { Input } from '../input/input.js';
2
+ import { BitmapBuffer } from './bitmap.js';
3
+ import { Cam } from './cam.js';
4
+ import { Renderer } from './renderer.js';
5
+ export declare class FrameListener {
6
+ #private;
7
+ /** The running lifetime in milliseconds. */
8
+ age: number;
9
+ /** The exact duration in milliseconds to apply on a given update step. */
10
+ tick: number;
11
+ constructor(canvas: HTMLCanvasElement, input: Input<string>, renderer: Renderer);
12
+ cancel(): void;
13
+ get frame(): number;
14
+ register(op: 'add' | 'remove'): void;
15
+ render(cam: Readonly<Cam>, buffer: BitmapBuffer, loop?: () => void): void;
16
+ }
@@ -0,0 +1,83 @@
1
+ import { Input } from '../input/input.js';
2
+ import { BitmapBuffer } from './bitmap.js';
3
+ import { Cam } from './cam.js';
4
+ import { Renderer } from './renderer.js';
5
+ export class FrameListener {
6
+ /** The running lifetime in milliseconds. */
7
+ age = 0;
8
+ /** The exact duration in milliseconds to apply on a given update step. */
9
+ tick = 0;
10
+ #canvas;
11
+ #frame;
12
+ #loop;
13
+ #time;
14
+ #input;
15
+ #renderer;
16
+ constructor(canvas, input, renderer) {
17
+ this.#canvas = canvas;
18
+ this.#input = input;
19
+ this.#renderer = renderer;
20
+ }
21
+ cancel() {
22
+ if (this.#frame != null)
23
+ cancelAnimationFrame(this.#frame);
24
+ this.#frame = undefined;
25
+ this.tick = 0;
26
+ this.#time = undefined;
27
+ this.#input.reset();
28
+ this.#loop = undefined;
29
+ }
30
+ get frame() {
31
+ // Assume 60 FPS so games can scale to this number regardless of actual.
32
+ return Math.trunc(this.age / 16.666666666666668);
33
+ }
34
+ register(op) {
35
+ const fn = `${op}EventListener`;
36
+ for (const type of ['webglcontextrestored', 'webglcontextlost']) {
37
+ this.#canvas[fn](type, this.#onEvent, true);
38
+ }
39
+ globalThis[fn]('visibilitychange', this.#onEvent, true);
40
+ if (op === 'add')
41
+ this.#renderer.initGL();
42
+ this.#input.register(op);
43
+ }
44
+ render(cam, buffer, loop) {
45
+ this.#loop = loop;
46
+ if (!this.#isVisible() || !this.#renderer.hasContext())
47
+ return;
48
+ if (this.#loop)
49
+ this.#frame ??= requestAnimationFrame(this.#onFrame);
50
+ this.#renderer.render(cam, this.frame, buffer);
51
+ }
52
+ #isVisible() {
53
+ return document.visibilityState === 'visible';
54
+ }
55
+ #onEvent = (event) => {
56
+ event.preventDefault();
57
+ if (event.type === 'webglcontextrestored')
58
+ this.#renderer.initGL();
59
+ if (this.#renderer.hasContext() && this.#isVisible()) {
60
+ if (this.#loop)
61
+ this.#frame ??= requestAnimationFrame(this.#onFrame);
62
+ }
63
+ else {
64
+ if (this.#frame != null)
65
+ cancelAnimationFrame(this.#frame);
66
+ this.#frame = undefined;
67
+ this.tick = 0;
68
+ this.#time = undefined;
69
+ this.#input.reset();
70
+ }
71
+ };
72
+ #onFrame = (time) => {
73
+ this.#frame = undefined;
74
+ this.tick = time - (this.#time ?? time);
75
+ this.#time = time;
76
+ this.age += this.tick;
77
+ const loop = this.#loop;
78
+ this.#loop = undefined;
79
+ this.#input.poll(this.tick);
80
+ loop?.();
81
+ };
82
+ }
83
+ //# sourceMappingURL=frame-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frame-listener.js","sourceRoot":"","sources":["../../src/graphics/frame-listener.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type Atlas } from '../atlas/atlas.js';
2
+ import { BitmapBuffer } from './bitmap.js';
3
+ import { Cam } from './cam.js';
4
+ export declare class Renderer {
5
+ #private;
6
+ constructor(atlas: Atlas, canvas: HTMLCanvasElement, spritesheet: HTMLImageElement);
7
+ clearColor(rgba: number): void;
8
+ initGL(): void;
9
+ get loseContext(): WEBGL_lose_context | null;
10
+ hasContext(): boolean;
11
+ render(cam: Readonly<Cam>, frame: number, bmps: Readonly<BitmapBuffer>): void;
12
+ }
@@ -0,0 +1,184 @@
1
+ import { maxAnimCels } from '../atlas/atlas.js';
2
+ import { BitmapBuffer } from './bitmap.js';
3
+ import { Cam } from './cam.js';
4
+ import { fragGLSL } from './frag.glsl.js';
5
+ import { vertGLSL } from './vert.glsl.js';
6
+ const uv = new Int8Array([1, 1, 0, 1, 1, 0, 0, 0]);
7
+ export class Renderer {
8
+ #bmpBuffer = null;
9
+ #canvas;
10
+ #cels;
11
+ #gl;
12
+ #loseContext = null;
13
+ #spritesheet;
14
+ #uniforms = {};
15
+ #vertArray = null;
16
+ constructor(atlas, canvas, spritesheet) {
17
+ this.#canvas = canvas;
18
+ this.#spritesheet = spritesheet;
19
+ this.#cels = new Uint16Array(newCels(atlas));
20
+ }
21
+ clearColor(rgba) {
22
+ this.#gl.clearColor(((rgba >>> 24) & 0xff) / 0xff, ((rgba >>> 16) & 0xff) / 0xff, ((rgba >>> 8) & 0xff) / 0xff, ((rgba >>> 0) & 0xff) / 0xff);
23
+ }
24
+ initGL() {
25
+ const gl = this.#canvas.getContext('webgl2', {
26
+ antialias: false,
27
+ desynchronized: true, // breaks render stats
28
+ powerPreference: 'high-performance'
29
+ });
30
+ if (!gl)
31
+ throw Error('WebGL v2 unsupported');
32
+ this.#gl = gl;
33
+ // Allow transparent textures to be layered.
34
+ gl.enable(gl.BLEND);
35
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
36
+ // Enable z-buffer for [0, 1] ([foreground, background]).
37
+ gl.enable(gl.DEPTH_TEST);
38
+ gl.depthRange(0, 1);
39
+ gl.clearDepth(1);
40
+ gl.depthFunc(gl.LESS);
41
+ // Disable image colorspace conversions. The default is browser dependent.
42
+ gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, false);
43
+ const pgm = loadProgram(gl, vertGLSL, fragGLSL);
44
+ this.#uniforms = getUniformLocations(gl, pgm);
45
+ gl.uniform2ui(this.#uniforms.uSpritesheetSize, this.#spritesheet.naturalWidth, this.#spritesheet.naturalHeight);
46
+ this.#vertArray = gl.createVertexArray();
47
+ gl.bindVertexArray(this.#vertArray);
48
+ const uvBuffer = gl.createBuffer();
49
+ gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
50
+ gl.enableVertexAttribArray(0);
51
+ gl.vertexAttribIPointer(0, 2, gl.BYTE, 0, 0);
52
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
53
+ this.#bmpBuffer = gl.createBuffer();
54
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.#bmpBuffer);
55
+ gl.enableVertexAttribArray(1);
56
+ gl.vertexAttribIPointer(1, 1, gl.UNSIGNED_INT, 12, 0);
57
+ gl.vertexAttribDivisor(1, 1);
58
+ gl.enableVertexAttribArray(2);
59
+ gl.vertexAttribIPointer(2, 1, gl.UNSIGNED_INT, 12, 4);
60
+ gl.vertexAttribDivisor(2, 1);
61
+ gl.enableVertexAttribArray(3);
62
+ gl.vertexAttribIPointer(3, 1, gl.UNSIGNED_INT, 12, 8);
63
+ gl.vertexAttribDivisor(3, 1);
64
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
65
+ gl.bindVertexArray(null);
66
+ gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
67
+ gl.bufferData(gl.ARRAY_BUFFER, uv, gl.STATIC_DRAW);
68
+ gl.bindBuffer(this.#gl.ARRAY_BUFFER, null);
69
+ gl.uniform1i(this.#uniforms.uCels, 0);
70
+ gl.activeTexture(gl.TEXTURE0);
71
+ const dataTex = gl.createTexture();
72
+ gl.bindTexture(gl.TEXTURE_2D, dataTex);
73
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
74
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
75
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16UI, 1, this.#cels.length / 4, // 4 u8s per row
76
+ 0, gl.RGBA_INTEGER, gl.UNSIGNED_SHORT, this.#cels);
77
+ gl.uniform1i(this.#uniforms.uSpritesheet, 1);
78
+ gl.activeTexture(gl.TEXTURE1);
79
+ const spritesheetTex = gl.createTexture();
80
+ gl.bindTexture(gl.TEXTURE_2D, spritesheetTex);
81
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
82
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
83
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.#spritesheet);
84
+ this.#loseContext = gl.getExtension('WEBGL_lose_context');
85
+ }
86
+ get loseContext() {
87
+ return this.#loseContext;
88
+ }
89
+ hasContext() {
90
+ return !this.#gl.isContextLost();
91
+ }
92
+ render(cam, frame, bmps) {
93
+ this.#resize(cam);
94
+ this.#gl.clear(this.#gl.COLOR_BUFFER_BIT | this.#gl.DEPTH_BUFFER_BIT);
95
+ this.#gl.uniform4i(this.#uniforms.uCam, cam.x, cam.y, cam.w, cam.h);
96
+ this.#gl.uniform1ui(this.#uniforms.uFrame, frame);
97
+ this.#gl.bindVertexArray(this.#vertArray);
98
+ this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, this.#bmpBuffer);
99
+ this.#gl.bufferData(this.#gl.ARRAY_BUFFER, bmps.buffer, this.#gl.STREAM_DRAW);
100
+ this.#gl.bindBuffer(this.#gl.ARRAY_BUFFER, null);
101
+ this.#gl.drawArraysInstanced(this.#gl.TRIANGLE_STRIP, 0, uv.length / 2, // d
102
+ bmps.size);
103
+ this.#gl.bindVertexArray(null);
104
+ }
105
+ #resize(cam) {
106
+ const canvas = this.#canvas;
107
+ const nativeWH = { w: cam.w * cam.scale, h: cam.h * cam.scale };
108
+ if (canvas.width !== nativeWH.w || canvas.height !== nativeWH.h) {
109
+ canvas.width = nativeWH.w;
110
+ canvas.height = nativeWH.h;
111
+ this.#gl.viewport(0, 0, nativeWH.w, nativeWH.h);
112
+ }
113
+ // These pixels may be greater than, less than, or equal to native.
114
+ const clientW = nativeWH.w / devicePixelRatio;
115
+ const clientH = nativeWH.h / devicePixelRatio;
116
+ const diffW = Number.parseFloat(canvas.style.width.slice(0, -2)) - clientW;
117
+ const diffH = Number.parseFloat(canvas.style.height.slice(0, -2)) - clientH;
118
+ if (!Number.isFinite(diffW) ||
119
+ Math.abs(diffW) >= 0.5 ||
120
+ !Number.isFinite(diffH) ||
121
+ Math.abs(diffH) >= 0.5) {
122
+ canvas.style.width = `${clientW}px`;
123
+ canvas.style.height = `${clientH}px`;
124
+ }
125
+ }
126
+ }
127
+ function compileShader(gl, type, src) {
128
+ const shader = gl.createShader(type);
129
+ if (!shader)
130
+ throw Error('shader creation failed');
131
+ gl.shaderSource(shader, src.trim());
132
+ gl.compileShader(shader);
133
+ const log = gl.getShaderInfoLog(shader)?.slice(0, -1);
134
+ if (log)
135
+ console.warn(log);
136
+ return shader;
137
+ }
138
+ function getUniformLocations(gl, pgm) {
139
+ if (!pgm)
140
+ return {};
141
+ const len = gl.getProgramParameter(pgm, gl.ACTIVE_UNIFORMS);
142
+ const locations = {};
143
+ for (let i = 0; i < len; ++i) {
144
+ const uniform = gl.getActiveUniform(pgm, i);
145
+ if (uniform == null)
146
+ throw Error(`missing shader uniform at index ${i}`);
147
+ locations[uniform.name] = gl.getUniformLocation(pgm, uniform.name);
148
+ }
149
+ return locations;
150
+ }
151
+ function loadProgram(gl, vertGLSL, fragGLSL) {
152
+ const pgm = gl.createProgram();
153
+ if (!pgm)
154
+ return null;
155
+ const vert = compileShader(gl, gl.VERTEX_SHADER, vertGLSL);
156
+ const frag = compileShader(gl, gl.FRAGMENT_SHADER, fragGLSL);
157
+ gl.attachShader(pgm, vert);
158
+ gl.attachShader(pgm, frag);
159
+ gl.linkProgram(pgm);
160
+ gl.useProgram(pgm);
161
+ const log = gl.getProgramInfoLog(pgm)?.slice(0, -1);
162
+ if (log)
163
+ console.warn(log);
164
+ gl.detachShader(pgm, frag);
165
+ gl.detachShader(pgm, vert);
166
+ gl.deleteShader(frag);
167
+ gl.deleteShader(vert);
168
+ return pgm;
169
+ }
170
+ /** XYWH ordered by ID and padded to 16-cel blocks. */
171
+ function newCels(atlas) {
172
+ const cels = [];
173
+ for (const anim of Object.values(atlas)) {
174
+ // Animations are inserted in ID order.
175
+ for (const cel of anim.cels)
176
+ cels.push(cel.x, cel.y, anim.w, anim.h);
177
+ for (let i = anim.cels.length; i < maxAnimCels; i++) {
178
+ const cel = anim.cels[i % anim.cels.length];
179
+ cels.push(cel.x, cel.y, anim.w, anim.h);
180
+ }
181
+ }
182
+ return cels;
183
+ }
184
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../src/graphics/renderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare const vertGLSL = "#version 300 es\n// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/WebGL_best_practices#essl300_minimum_requirements_webgl_2\nuniform lowp usampler2D uCels;\nuniform mediump ivec4 uCam;\nuniform highp uint uFrame;\n\nlayout (location=0) in lowp ivec2 iUV;\nlayout (location=1) in highp uint iXY;\nlayout (location=2) in highp uint iWH;\nlayout (location=3) in highp uint iIFFZZ;\n\nflat out highp ivec4 vTexXYWH;\nout highp vec2 vDstWH;\n\nconst mediump int maxY = 0x1000;\nconst lowp int maxZ = 8;\nconst mediump int maxDepth = maxY * maxZ;\n\nvoid main() {\n mediump int x = int(iXY) >> 19;\n mediump int y = int(iXY << 16) >> 19;\n lowp int z = int(iIFFZZ & 0x7u);\n bool zend = bool(iIFFZZ & 0x8u);\n bool flipX = bool(iIFFZZ & 0x20u);\n bool flipY = bool(iIFFZZ & 0x10u);\n mediump int id = int((iIFFZZ >> 6) & 0x7ff0u);\n lowp int cel = int((iIFFZZ >> 6) & 0xfu);\n mediump int w = int((iWH >> 12) & 0xfffu);\n mediump int h = int(iWH & 0xfffu);\n\n lowp int frame = ((int(uFrame) - cel) / 4) & 0xf;\n mediump uvec4 texXYWH = texelFetch(uCels, ivec2(0, id + frame), 0);\n\n // https://www.patternsgameprog.com/opengl-2d-facade-25-get-the-z-of-a-pixel\n highp float depth = float((z + 1) * maxY - (y + (zend ? 0 : h))) / float(maxDepth);\n\n highp ivec2 targetWH = ivec2(iUV) * ivec2(w, h);\n highp ivec2 origWH = ivec2(iUV) * ivec2(texXYWH.zw);\n\n highp vec2 end = vec2(x + targetWH.x, y + targetWH.y);\n highp vec2 clip = ((-2. * vec2(uCam.xy) + 2. * end) / vec2(uCam.zw) - 1.) * vec2(1, -1);\n gl_Position = vec4(clip, depth, 1);\n vTexXYWH = ivec4(texXYWH);\n vDstWH = vec2(targetWH * ivec2(flipX ? -1 : 1, flipY ? -1 : 1));\n}";