@nodetool-ai/game-renderer 0.8.1 → 0.8.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/README.md +46 -0
- package/dist/.nodetool-build-stamp +1 -1
- package/dist/audio/mixer.d.ts +75 -0
- package/dist/audio/mixer.d.ts.map +1 -0
- package/dist/audio/mixer.js +345 -0
- package/dist/audio/mixer.js.map +1 -0
- package/dist/audio/player.d.ts +67 -0
- package/dist/audio/player.d.ts.map +1 -0
- package/dist/audio/player.js +337 -0
- package/dist/audio/player.js.map +1 -0
- package/dist/audio/spatial.d.ts +50 -0
- package/dist/audio/spatial.d.ts.map +1 -0
- package/dist/audio/spatial.js +166 -0
- package/dist/audio/spatial.js.map +1 -0
- package/dist/audio/voices.d.ts +11 -0
- package/dist/audio/voices.d.ts.map +1 -0
- package/dist/audio/voices.js +22 -0
- package/dist/audio/voices.js.map +1 -0
- package/dist/audio.d.ts +6 -38
- package/dist/audio.d.ts.map +1 -1
- package/dist/audio.js +3 -226
- package/dist/audio.js.map +1 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +5 -5
- package/dist/browser.js.map +1 -1
- package/dist/browser3d.d.ts +2 -0
- package/dist/browser3d.d.ts.map +1 -0
- package/dist/browser3d.js +2 -0
- package/dist/browser3d.js.map +1 -0
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +29 -19
- package/dist/build.js.map +1 -1
- package/dist/build3d.d.ts +11 -0
- package/dist/build3d.d.ts.map +1 -0
- package/dist/build3d.js +126 -0
- package/dist/build3d.js.map +1 -0
- package/dist/canvas2d.d.ts +12 -3
- package/dist/canvas2d.d.ts.map +1 -1
- package/dist/canvas2d.js +59 -12
- package/dist/canvas2d.js.map +1 -1
- package/dist/fixed-tick-host.d.ts +10 -0
- package/dist/fixed-tick-host.d.ts.map +1 -0
- package/dist/fixed-tick-host.js +29 -0
- package/dist/fixed-tick-host.js.map +1 -0
- package/dist/frame-budget.d.ts +34 -0
- package/dist/frame-budget.d.ts.map +1 -0
- package/dist/frame-budget.js +52 -0
- package/dist/frame-budget.js.map +1 -0
- package/dist/frame.d.ts +20 -1
- package/dist/frame.d.ts.map +1 -1
- package/dist/frame.js +69 -1
- package/dist/frame.js.map +1 -1
- package/dist/game3d-capture-page.js +5834 -0
- package/dist/game3d-player.js +6001 -0
- package/dist/imageDiff.d.ts +9 -0
- package/dist/imageDiff.d.ts.map +1 -0
- package/dist/imageDiff.js +30 -0
- package/dist/imageDiff.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/input-bindings.d.ts +76 -0
- package/dist/input-bindings.d.ts.map +1 -0
- package/dist/input-bindings.js +377 -0
- package/dist/input-bindings.js.map +1 -0
- package/dist/input.d.ts +1 -1
- package/dist/input.d.ts.map +1 -1
- package/dist/input.js +1 -14
- package/dist/input.js.map +1 -1
- package/dist/input3d.d.ts +3 -0
- package/dist/input3d.d.ts.map +1 -0
- package/dist/input3d.js +3 -0
- package/dist/input3d.js.map +1 -0
- package/dist/node.d.ts +5 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +28 -11
- package/dist/node.js.map +1 -1
- package/dist/node3d.d.ts +29 -0
- package/dist/node3d.d.ts.map +1 -0
- package/dist/node3d.js +160 -0
- package/dist/node3d.js.map +1 -0
- package/dist/particles/curves.d.ts +16 -0
- package/dist/particles/curves.d.ts.map +1 -0
- package/dist/particles/curves.js +49 -0
- package/dist/particles/curves.js.map +1 -0
- package/dist/particles/index.d.ts +6 -0
- package/dist/particles/index.d.ts.map +1 -0
- package/dist/particles/index.js +6 -0
- package/dist/particles/index.js.map +1 -0
- package/dist/particles/random.d.ts +10 -0
- package/dist/particles/random.d.ts.map +1 -0
- package/dist/particles/random.js +26 -0
- package/dist/particles/random.js.map +1 -0
- package/dist/particles/render2d.d.ts +40 -0
- package/dist/particles/render2d.d.ts.map +1 -0
- package/dist/particles/render2d.js +70 -0
- package/dist/particles/render2d.js.map +1 -0
- package/dist/particles/shapes.d.ts +18 -0
- package/dist/particles/shapes.d.ts.map +1 -0
- package/dist/particles/shapes.js +92 -0
- package/dist/particles/shapes.js.map +1 -0
- package/dist/particles/simulator.d.ts +88 -0
- package/dist/particles/simulator.d.ts.map +1 -0
- package/dist/particles/simulator.js +371 -0
- package/dist/particles/simulator.js.map +1 -0
- package/dist/player-v1.js +2502 -0
- package/dist/preparation3d.d.ts +3 -0
- package/dist/preparation3d.d.ts.map +1 -0
- package/dist/preparation3d.js +3 -0
- package/dist/preparation3d.js.map +1 -0
- package/dist/renderPipeline.d.ts +12 -0
- package/dist/renderPipeline.d.ts.map +1 -0
- package/dist/renderPipeline.js +17 -0
- package/dist/renderPipeline.js.map +1 -0
- package/dist/renderer3d/animation/index.d.ts +11 -0
- package/dist/renderer3d/animation/index.d.ts.map +1 -0
- package/dist/renderer3d/animation/index.js +212 -0
- package/dist/renderer3d/animation/index.js.map +1 -0
- package/dist/renderer3d/assets/cache.d.ts +14 -0
- package/dist/renderer3d/assets/cache.d.ts.map +1 -0
- package/dist/renderer3d/assets/cache.js +74 -0
- package/dist/renderer3d/assets/cache.js.map +1 -0
- package/dist/renderer3d/assets/dispose.d.ts +4 -0
- package/dist/renderer3d/assets/dispose.d.ts.map +1 -0
- package/dist/renderer3d/assets/dispose.js +41 -0
- package/dist/renderer3d/assets/dispose.js.map +1 -0
- package/dist/renderer3d/assets/hdri-contract.d.ts +23 -0
- package/dist/renderer3d/assets/hdri-contract.d.ts.map +1 -0
- package/dist/renderer3d/assets/hdri-contract.js +2 -0
- package/dist/renderer3d/assets/hdri-contract.js.map +1 -0
- package/dist/renderer3d/assets/instances.d.ts +5 -0
- package/dist/renderer3d/assets/instances.d.ts.map +1 -0
- package/dist/renderer3d/assets/instances.js +86 -0
- package/dist/renderer3d/assets/instances.js.map +1 -0
- package/dist/renderer3d/capture-driver-types.d.ts +42 -0
- package/dist/renderer3d/capture-driver-types.d.ts.map +1 -0
- package/dist/renderer3d/capture-driver-types.js +2 -0
- package/dist/renderer3d/capture-driver-types.js.map +1 -0
- package/dist/renderer3d/capture-page.d.ts +36 -0
- package/dist/renderer3d/capture-page.d.ts.map +1 -0
- package/dist/renderer3d/capture-page.js +68 -0
- package/dist/renderer3d/capture-page.js.map +1 -0
- package/dist/renderer3d/culling.d.ts +10 -0
- package/dist/renderer3d/culling.d.ts.map +1 -0
- package/dist/renderer3d/culling.js +27 -0
- package/dist/renderer3d/culling.js.map +1 -0
- package/dist/renderer3d/environment/index.d.ts +4 -0
- package/dist/renderer3d/environment/index.d.ts.map +1 -0
- package/dist/renderer3d/environment/index.js +9 -0
- package/dist/renderer3d/environment/index.js.map +1 -0
- package/dist/renderer3d/environment/sky.d.ts +45 -0
- package/dist/renderer3d/environment/sky.d.ts.map +1 -0
- package/dist/renderer3d/environment/sky.js +221 -0
- package/dist/renderer3d/environment/sky.js.map +1 -0
- package/dist/renderer3d/hud/fonts.d.ts +13 -0
- package/dist/renderer3d/hud/fonts.d.ts.map +1 -0
- package/dist/renderer3d/hud/fonts.js +69 -0
- package/dist/renderer3d/hud/fonts.js.map +1 -0
- package/dist/renderer3d/hud/paint.d.ts +4 -0
- package/dist/renderer3d/hud/paint.d.ts.map +1 -0
- package/dist/renderer3d/hud/paint.js +22 -0
- package/dist/renderer3d/hud/paint.js.map +1 -0
- package/dist/renderer3d/import.d.ts +34 -0
- package/dist/renderer3d/import.d.ts.map +1 -0
- package/dist/renderer3d/import.js +408 -0
- package/dist/renderer3d/import.js.map +1 -0
- package/dist/renderer3d/index.d.ts +74 -0
- package/dist/renderer3d/index.d.ts.map +1 -0
- package/dist/renderer3d/index.js +338 -0
- package/dist/renderer3d/index.js.map +1 -0
- package/dist/renderer3d/lights/index.d.ts +7 -0
- package/dist/renderer3d/lights/index.d.ts.map +1 -0
- package/dist/renderer3d/lights/index.js +67 -0
- package/dist/renderer3d/lights/index.js.map +1 -0
- package/dist/renderer3d/materials/index.d.ts +4 -0
- package/dist/renderer3d/materials/index.d.ts.map +1 -0
- package/dist/renderer3d/materials/index.js +8 -0
- package/dist/renderer3d/materials/index.js.map +1 -0
- package/dist/renderer3d/passes/post-processing.d.ts +44 -0
- package/dist/renderer3d/passes/post-processing.d.ts.map +1 -0
- package/dist/renderer3d/passes/post-processing.js +213 -0
- package/dist/renderer3d/passes/post-processing.js.map +1 -0
- package/dist/renderer3d/pipeline.d.ts +15 -0
- package/dist/renderer3d/pipeline.d.ts.map +1 -0
- package/dist/renderer3d/pipeline.js +10 -0
- package/dist/renderer3d/pipeline.js.map +1 -0
- package/dist/renderer3d/playwright-contract.d.ts +3 -0
- package/dist/renderer3d/playwright-contract.d.ts.map +1 -0
- package/dist/renderer3d/playwright-contract.js +4 -0
- package/dist/renderer3d/playwright-contract.js.map +1 -0
- package/dist/renderer3d/preparation.d.ts +79 -0
- package/dist/renderer3d/preparation.d.ts.map +1 -0
- package/dist/renderer3d/preparation.js +458 -0
- package/dist/renderer3d/preparation.js.map +1 -0
- package/dist/renderer3d/scene-sync.d.ts +8 -0
- package/dist/renderer3d/scene-sync.d.ts.map +1 -0
- package/dist/renderer3d/scene-sync.js +96 -0
- package/dist/renderer3d/scene-sync.js.map +1 -0
- package/dist/renderer3d/shadows/cascades.d.ts +40 -0
- package/dist/renderer3d/shadows/cascades.d.ts.map +1 -0
- package/dist/renderer3d/shadows/cascades.js +244 -0
- package/dist/renderer3d/shadows/cascades.js.map +1 -0
- package/dist/renderer3d/shadows/index.d.ts +44 -0
- package/dist/renderer3d/shadows/index.d.ts.map +1 -0
- package/dist/renderer3d/shadows/index.js +129 -0
- package/dist/renderer3d/shadows/index.js.map +1 -0
- package/dist/renderer3d/types.d.ts +18 -0
- package/dist/renderer3d/types.d.ts.map +1 -0
- package/dist/renderer3d/types.js +2 -0
- package/dist/renderer3d/types.js.map +1 -0
- package/dist/smoke.d.ts +15 -0
- package/dist/smoke.d.ts.map +1 -0
- package/dist/smoke.js +138 -0
- package/dist/smoke.js.map +1 -0
- package/dist/standalone-player.d.ts +11 -1
- package/dist/standalone-player.d.ts.map +1 -1
- package/dist/standalone-player.js +67 -41
- package/dist/standalone-player.js.map +1 -1
- package/dist/standalone-player3d.d.ts +14 -0
- package/dist/standalone-player3d.d.ts.map +1 -0
- package/dist/standalone-player3d.js +255 -0
- package/dist/standalone-player3d.js.map +1 -0
- package/dist/touch-controls.d.ts +22 -8
- package/dist/touch-controls.d.ts.map +1 -1
- package/dist/touch-controls.js +88 -21
- package/dist/touch-controls.js.map +1 -1
- package/dist/ui/controller.d.ts +59 -0
- package/dist/ui/controller.d.ts.map +1 -0
- package/dist/ui/controller.js +201 -0
- package/dist/ui/controller.js.map +1 -0
- package/dist/ui/hud2d.d.ts +11 -0
- package/dist/ui/hud2d.d.ts.map +1 -0
- package/dist/ui/hud2d.js +25 -0
- package/dist/ui/hud2d.js.map +1 -0
- package/dist/ui/layout.d.ts +42 -0
- package/dist/ui/layout.d.ts.map +1 -0
- package/dist/ui/layout.js +182 -0
- package/dist/ui/layout.js.map +1 -0
- package/dist/ui/paint.d.ts +45 -0
- package/dist/ui/paint.d.ts.map +1 -0
- package/dist/ui/paint.js +121 -0
- package/dist/ui/paint.js.map +1 -0
- package/dist/webgpu/effects.d.ts +22 -0
- package/dist/webgpu/effects.d.ts.map +1 -0
- package/dist/webgpu/effects.js +69 -0
- package/dist/webgpu/effects.js.map +1 -0
- package/dist/webgpu/hud.d.ts +4 -0
- package/dist/webgpu/hud.d.ts.map +1 -0
- package/dist/webgpu/hud.js +27 -0
- package/dist/webgpu/hud.js.map +1 -0
- package/dist/webgpu/lighting.d.ts +4 -0
- package/dist/webgpu/lighting.d.ts.map +1 -0
- package/dist/webgpu/lighting.js +47 -0
- package/dist/webgpu/lighting.js.map +1 -0
- package/dist/webgpu/pipeline.d.ts +11 -0
- package/dist/webgpu/pipeline.d.ts.map +1 -0
- package/dist/webgpu/pipeline.js +11 -0
- package/dist/webgpu/pipeline.js.map +1 -0
- package/dist/webgpu/sprites.d.ts +6 -0
- package/dist/webgpu/sprites.d.ts.map +1 -0
- package/dist/webgpu/sprites.js +74 -0
- package/dist/webgpu/sprites.js.map +1 -0
- package/dist/webgpu/types.d.ts +14 -0
- package/dist/webgpu/types.d.ts.map +1 -0
- package/dist/webgpu/types.js +2 -0
- package/dist/webgpu/types.js.map +1 -0
- package/dist/webgpu.d.ts +4 -3
- package/dist/webgpu.d.ts.map +1 -1
- package/dist/webgpu.js +119 -279
- package/dist/webgpu.js.map +1 -1
- package/package.json +47 -10
package/dist/ui/paint.js
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { gameFontFamily } from "../fonts.js";
|
|
2
|
+
import { GAME_UI_TEXT_SIZE, layoutGameUi } from "./layout.js";
|
|
3
|
+
const PANEL = "#1b1f2a";
|
|
4
|
+
const BAR_FILL = "#4caf50";
|
|
5
|
+
const BAR_TRACK = "#1b1f2a";
|
|
6
|
+
const BUTTON = "#2b3445";
|
|
7
|
+
const TEXT = "#ffffff";
|
|
8
|
+
const FOCUS = "#ffffff";
|
|
9
|
+
/** The CSS font of HUD text, the same weight and fallback stack as `hud` labels. */
|
|
10
|
+
export function gameUiFont(size, fontId, gameId) {
|
|
11
|
+
const family = fontId && gameId ? `"${gameFontFamily(gameId, fontId)}", ` : "";
|
|
12
|
+
return `600 ${size}px ${family}system-ui, -apple-system, "Segoe UI", sans-serif`;
|
|
13
|
+
}
|
|
14
|
+
/** Measures HUD text with a Canvas2D context, so layout and painting agree on text widths. */
|
|
15
|
+
export function canvasGameUiMeasure(context, gameId) {
|
|
16
|
+
return (text, size, fontId) => {
|
|
17
|
+
context.font = gameUiFont(size, fontId, gameId);
|
|
18
|
+
return context.measureText(text).width;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Asset ids of the images a HUD tree draws, for the renderer to load before painting. */
|
|
22
|
+
export function gameUiImageIds(ui) {
|
|
23
|
+
return [...new Set((ui?.nodes ?? []).flatMap((node) => node.kind === "image" && node.visible !== false ? [node.assetId] : []))];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Lays out and paints a HUD tree onto a Canvas2D context whose origin is the HUD rectangle's top-left corner.
|
|
27
|
+
* Returns the boxes it drew, in HUD pixels.
|
|
28
|
+
*/
|
|
29
|
+
export function paintGameUi(context, ui, viewport, options = {}) {
|
|
30
|
+
const boxes = layoutGameUi(ui, viewport, canvasGameUiMeasure(context, options.gameId), ui.insets ?? options.insets);
|
|
31
|
+
context.save();
|
|
32
|
+
const scale = options.scale ?? 1;
|
|
33
|
+
if (scale !== 1) {
|
|
34
|
+
context.scale(scale, scale);
|
|
35
|
+
}
|
|
36
|
+
for (const box of boxes) {
|
|
37
|
+
context.globalAlpha = box.opacity;
|
|
38
|
+
paintBox(context, box, options, box.node.id === ui.focusId);
|
|
39
|
+
}
|
|
40
|
+
context.restore();
|
|
41
|
+
return boxes;
|
|
42
|
+
}
|
|
43
|
+
function rect(context, x, y, width, height, radius) {
|
|
44
|
+
if (radius > 0) {
|
|
45
|
+
context.beginPath();
|
|
46
|
+
context.roundRect(x, y, width, height, Math.min(radius, width / 2, height / 2));
|
|
47
|
+
context.fill();
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
context.fillRect(x, y, width, height);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function paintText(context, text, x, y, size, fontId, color, align, baseline, gameId) {
|
|
54
|
+
context.font = gameUiFont(size, fontId, gameId);
|
|
55
|
+
context.fillStyle = color;
|
|
56
|
+
context.textAlign = align;
|
|
57
|
+
context.textBaseline = baseline;
|
|
58
|
+
context.fillText(text, x, y);
|
|
59
|
+
}
|
|
60
|
+
function paintBox(context, box, options, focused) {
|
|
61
|
+
const { node, x, y, width, height } = box;
|
|
62
|
+
switch (node.kind) {
|
|
63
|
+
case "panel": {
|
|
64
|
+
context.fillStyle = node.color ?? PANEL;
|
|
65
|
+
rect(context, x, y, width, height, node.cornerRadius ?? 0);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
case "image": {
|
|
69
|
+
const image = options.images?.get(node.assetId);
|
|
70
|
+
if (image) {
|
|
71
|
+
context.drawImage(image, x, y, width, height);
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
case "text": {
|
|
76
|
+
const align = node.align ?? "left";
|
|
77
|
+
const anchorX = align === "left" ? x : align === "center" ? x + width / 2 : x + width;
|
|
78
|
+
paintText(context, node.text, anchorX, y, node.size ?? GAME_UI_TEXT_SIZE, node.fontId, node.color ?? TEXT, align, "top", options.gameId);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
case "bar": {
|
|
82
|
+
context.fillStyle = node.background ?? BAR_TRACK;
|
|
83
|
+
context.fillRect(x, y, width, height);
|
|
84
|
+
const max = node.max ?? 1;
|
|
85
|
+
const fraction = Math.max(0, Math.min(1, (node.value ?? 0) / max));
|
|
86
|
+
context.fillStyle = node.color ?? BAR_FILL;
|
|
87
|
+
switch (node.direction ?? "leftToRight") {
|
|
88
|
+
case "leftToRight":
|
|
89
|
+
context.fillRect(x, y, width * fraction, height);
|
|
90
|
+
break;
|
|
91
|
+
case "rightToLeft":
|
|
92
|
+
context.fillRect(x + width * (1 - fraction), y, width * fraction, height);
|
|
93
|
+
break;
|
|
94
|
+
case "bottomToTop":
|
|
95
|
+
context.fillRect(x, y + height * (1 - fraction), width, height * fraction);
|
|
96
|
+
break;
|
|
97
|
+
case "topToBottom":
|
|
98
|
+
context.fillRect(x, y, width, height * fraction);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
case "button": {
|
|
104
|
+
context.fillStyle = node.background ?? BUTTON;
|
|
105
|
+
rect(context, x, y, width, height, Math.min(8, height / 4));
|
|
106
|
+
if (node.text) {
|
|
107
|
+
paintText(context, node.text, x + width / 2, y + height / 2, node.size ?? GAME_UI_TEXT_SIZE, node.fontId, node.color ?? TEXT, "center", "middle", options.gameId);
|
|
108
|
+
}
|
|
109
|
+
if (focused) {
|
|
110
|
+
context.strokeStyle = FOCUS;
|
|
111
|
+
context.lineWidth = 2;
|
|
112
|
+
context.strokeRect(x - 2, y - 2, width + 4, height + 4);
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
case "stack":
|
|
117
|
+
case "grid":
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=paint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paint.js","sourceRoot":"","sources":["../../src/ui/paint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createDefaultRegistry, createExecutor, createGPUContextFromDevice, createRecipeRunner, LabeledTexture } from "@nodetool-ai/gpu/pool";
|
|
2
|
+
import type { GameRendererEffect } from "../index.js";
|
|
3
|
+
interface EffectEncoding {
|
|
4
|
+
readonly effects: readonly GameRendererEffect[];
|
|
5
|
+
readonly source: LabeledTexture;
|
|
6
|
+
readonly output: LabeledTexture;
|
|
7
|
+
readonly encoder: GPUCommandEncoder;
|
|
8
|
+
readonly effectContext: ReturnType<typeof createGPUContextFromDevice>;
|
|
9
|
+
readonly effectExecutor: ReturnType<typeof createExecutor>;
|
|
10
|
+
readonly effectRecipeRunner: ReturnType<typeof createRecipeRunner>;
|
|
11
|
+
readonly effectRegistry: ReturnType<typeof createDefaultRegistry>;
|
|
12
|
+
readonly srgbTarget: LabeledTexture | undefined;
|
|
13
|
+
readonly lutTarget: LabeledTexture | undefined;
|
|
14
|
+
readonly toSrgbPipeline: GPURenderPipeline;
|
|
15
|
+
readonly toLinearPipeline: GPURenderPipeline;
|
|
16
|
+
readonly getLutTexture: (id: string, size: number) => Promise<LabeledTexture>;
|
|
17
|
+
readonly convertColor: (encoder: GPUCommandEncoder, source: LabeledTexture, output: LabeledTexture, pipeline: GPURenderPipeline) => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function encodeGameEffects(options: EffectEncoding): Promise<LabeledTexture>;
|
|
20
|
+
export declare const PRESENT_SHADER = "\noverride decodeInput: bool = false;\noverride encodeOutput: bool = true;\noverride cropScaleX: f32 = 1.0;\noverride cropScaleY: f32 = 1.0;\noverride cropOffsetX: f32 = 0.0;\noverride cropOffsetY: f32 = 0.0;\n@group(0) @binding(0) var sourceSampler: sampler;\n@group(0) @binding(1) var sourceTexture: texture_2d<f32>;\nstruct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };\n@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {\n let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\n var output: VertexOutput;\n output.position = vec4f(positions[index], 0.0, 1.0);\n output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);\n return output;\n}\n@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let uv = input.uv * vec2f(cropScaleX, cropScaleY) + vec2f(cropOffsetX, cropOffsetY);\n let premul = textureSample(sourceTexture, sourceSampler, uv);\n let straight = premul.rgb / max(premul.a, 1.0 / 255.0);\n let linear = select(straight / 12.92, pow((straight + 0.055) / 1.055, vec3f(2.4)),\n straight > vec3f(0.04045));\n let encoded = select(straight * 12.92, 1.055 * pow(straight, vec3f(1.0 / 2.4)) - 0.055,\n straight > vec3f(0.0031308));\n var converted = select(straight, linear, decodeInput);\n converted = select(converted, encoded, encodeOutput);\n return vec4f(clamp(converted, vec3f(0.0), vec3f(1.0)) * premul.a, premul.a);\n}";
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=effects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.d.ts","sourceRoot":"","sources":["../../src/webgpu/effects.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6C,qBAAqB,EAAE,cAAc,EAAE,0BAA0B,EAAE,kBAAkB,EAAiB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAExM,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,UAAU,cAAc;IACtB,QAAQ,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,aAAa,EAAE,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;IACtE,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC3D,QAAQ,CAAC,kBAAkB,EAAE,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;IACnE,QAAQ,CAAC,cAAc,EAAE,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;IAClE,QAAQ,CAAC,UAAU,EAAE,cAAc,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,SAAS,EAAE,cAAc,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,cAAc,EAAE,iBAAiB,CAAC;IAC3C,QAAQ,CAAC,gBAAgB,EAAE,iBAAiB,CAAC;IAC7C,QAAQ,CAAC,aAAa,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAC9E,QAAQ,CAAC,YAAY,EAAE,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,iBAAiB,KAAK,IAAI,CAAC;CAC1I;AAED,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC,CAgCxF;AAED,eAAO,MAAM,cAAc,s8CA4BzB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { colorBrightnessContrastV1, colorCubeLutV1, filtersGlowV1 } from "@nodetool-ai/gpu/pool";
|
|
2
|
+
import * as d from "typegpu/data";
|
|
3
|
+
export async function encodeGameEffects(options) {
|
|
4
|
+
let { source, output } = options;
|
|
5
|
+
const { encoder } = options;
|
|
6
|
+
source.markWritten();
|
|
7
|
+
options.effectContext.uniformRing.beginSubmission();
|
|
8
|
+
for (const effect of options.effects) {
|
|
9
|
+
if (effect.kind === "brightnessContrast") {
|
|
10
|
+
options.effectExecutor.encode({ ctx: options.effectContext, module: colorBrightnessContrastV1,
|
|
11
|
+
encoder, inputs: { source }, output,
|
|
12
|
+
params: { brightness: effect.brightness, contrast: effect.contrast },
|
|
13
|
+
dispatch: { kind: "fragment" } });
|
|
14
|
+
}
|
|
15
|
+
else if (effect.kind === "bloom") {
|
|
16
|
+
options.effectRecipeRunner.encode({ ctx: options.effectContext, module: filtersGlowV1,
|
|
17
|
+
registry: options.effectRegistry, executor: options.effectExecutor, encoder, inputs: { source }, output,
|
|
18
|
+
params: { threshold: effect.threshold, softness: effect.softness,
|
|
19
|
+
radius: effect.radius, intensity: effect.intensity } });
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
const srgbSource = options.srgbTarget;
|
|
23
|
+
const srgbOutput = options.lutTarget;
|
|
24
|
+
if (!srgbSource || !srgbOutput) {
|
|
25
|
+
throw new Error("LUT color targets are unavailable");
|
|
26
|
+
}
|
|
27
|
+
const lut = await options.getLutTexture(effect.assetId, effect.size);
|
|
28
|
+
options.convertColor(encoder, source, srgbSource, options.toSrgbPipeline);
|
|
29
|
+
options.effectExecutor.encode({ ctx: options.effectContext, module: colorCubeLutV1,
|
|
30
|
+
encoder, inputs: { source: srgbSource, lut }, output: srgbOutput,
|
|
31
|
+
params: { size: effect.size, intensity: effect.intensity,
|
|
32
|
+
domainMin: d.vec4f(...effect.domainMin, 0), domainMax: d.vec4f(...effect.domainMax, 0) },
|
|
33
|
+
dispatch: { kind: "fragment" } });
|
|
34
|
+
options.convertColor(encoder, srgbOutput, output, options.toLinearPipeline);
|
|
35
|
+
}
|
|
36
|
+
[source, output] = [output, source];
|
|
37
|
+
}
|
|
38
|
+
return source;
|
|
39
|
+
}
|
|
40
|
+
export const PRESENT_SHADER = `
|
|
41
|
+
override decodeInput: bool = false;
|
|
42
|
+
override encodeOutput: bool = true;
|
|
43
|
+
override cropScaleX: f32 = 1.0;
|
|
44
|
+
override cropScaleY: f32 = 1.0;
|
|
45
|
+
override cropOffsetX: f32 = 0.0;
|
|
46
|
+
override cropOffsetY: f32 = 0.0;
|
|
47
|
+
@group(0) @binding(0) var sourceSampler: sampler;
|
|
48
|
+
@group(0) @binding(1) var sourceTexture: texture_2d<f32>;
|
|
49
|
+
struct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };
|
|
50
|
+
@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {
|
|
51
|
+
let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
|
|
52
|
+
var output: VertexOutput;
|
|
53
|
+
output.position = vec4f(positions[index], 0.0, 1.0);
|
|
54
|
+
output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);
|
|
55
|
+
return output;
|
|
56
|
+
}
|
|
57
|
+
@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
58
|
+
let uv = input.uv * vec2f(cropScaleX, cropScaleY) + vec2f(cropOffsetX, cropOffsetY);
|
|
59
|
+
let premul = textureSample(sourceTexture, sourceSampler, uv);
|
|
60
|
+
let straight = premul.rgb / max(premul.a, 1.0 / 255.0);
|
|
61
|
+
let linear = select(straight / 12.92, pow((straight + 0.055) / 1.055, vec3f(2.4)),
|
|
62
|
+
straight > vec3f(0.04045));
|
|
63
|
+
let encoded = select(straight * 12.92, 1.055 * pow(straight, vec3f(1.0 / 2.4)) - 0.055,
|
|
64
|
+
straight > vec3f(0.0031308));
|
|
65
|
+
var converted = select(straight, linear, decodeInput);
|
|
66
|
+
converted = select(converted, encoded, encodeOutput);
|
|
67
|
+
return vec4f(clamp(converted, vec3f(0.0), vec3f(1.0)) * premul.a, premul.a);
|
|
68
|
+
}`;
|
|
69
|
+
//# sourceMappingURL=effects.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"effects.js","sourceRoot":"","sources":["../../src/webgpu/effects.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GameRenderFrame } from "@nodetool-ai/protocol";
|
|
2
|
+
export declare const HUD_SHADER = "\n@group(0) @binding(0) var sourceSampler: sampler;\n@group(0) @binding(1) var sourceTexture: texture_2d<f32>;\nstruct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };\n@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {\n let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\n var output: VertexOutput;\n output.position = vec4f(positions[index], 0.0, 1.0);\n output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);\n return output;\n}\n@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let color = textureSample(sourceTexture, sourceSampler, input.uv);\n return vec4f(color.rgb * color.a, color.a);\n}";
|
|
3
|
+
export declare function paintWebGPUHud(canvas: HTMLCanvasElement, width: number, height: number, frame: GameRenderFrame, images?: ReadonlyMap<string, unknown>): void;
|
|
4
|
+
//# sourceMappingURL=hud.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hud.d.ts","sourceRoot":"","sources":["../../src/webgpu/hud.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,eAAO,MAAM,UAAU,+tBAcrB,CAAC;AAGH,wBAAgB,cAAc,CAAC,MAAM,EAAE,iBAAiB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAC7G,MAAM,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAS7C"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { paintGameHud2D } from "../ui/hud2d.js";
|
|
2
|
+
export const HUD_SHADER = `
|
|
3
|
+
@group(0) @binding(0) var sourceSampler: sampler;
|
|
4
|
+
@group(0) @binding(1) var sourceTexture: texture_2d<f32>;
|
|
5
|
+
struct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };
|
|
6
|
+
@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {
|
|
7
|
+
let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
|
|
8
|
+
var output: VertexOutput;
|
|
9
|
+
output.position = vec4f(positions[index], 0.0, 1.0);
|
|
10
|
+
output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);
|
|
11
|
+
return output;
|
|
12
|
+
}
|
|
13
|
+
@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
14
|
+
let color = textureSample(sourceTexture, sourceSampler, input.uv);
|
|
15
|
+
return vec4f(color.rgb * color.a, color.a);
|
|
16
|
+
}`;
|
|
17
|
+
export function paintWebGPUHud(canvas, width, height, frame, images) {
|
|
18
|
+
canvas.width = width;
|
|
19
|
+
canvas.height = height;
|
|
20
|
+
const context = canvas.getContext("2d");
|
|
21
|
+
if (!context) {
|
|
22
|
+
throw new Error("HUD canvas is unavailable");
|
|
23
|
+
}
|
|
24
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
25
|
+
paintGameHud2D(context, frame, 1, images);
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=hud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hud.js","sourceRoot":"","sources":["../../src/webgpu/hud.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,UAAU,GAAG;;;;;;;;;;;;;;EAcxB,CAAC;AAGH,MAAM,UAAU,cAAc,CAAC,MAAyB,EAAE,KAAa,EAAE,MAAc,EAAE,KAAsB,EAC7G,MAAqC;IACjC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACrD,cAAc,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { GameRenderFrame } from "@nodetool-ai/protocol";
|
|
2
|
+
export declare const LIGHT_SHADER = "\nstruct Camera { center: vec2f, viewport: vec2f, zoom: f32, padding0: f32, padding1: f32, padding2: f32 };\nstruct PointLight { position: vec2f, radius: f32, intensity: f32, color: vec4f, falloff: f32, pad0: f32, pad1: f32, pad2: f32 };\nstruct Lighting { ambient: vec4f, info: vec4f, points: array<PointLight, 32> };\nfn srgbToLinear(rgb: vec3f) -> vec3f {\n return select(rgb / 12.92, pow((rgb + 0.055) / 1.055, vec3f(2.4)), rgb > vec3f(0.04045));\n}\n@group(0) @binding(0) var<uniform> camera: Camera;\n@group(0) @binding(1) var<uniform> lighting: Lighting;\nstruct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };\n@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {\n let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));\n var output: VertexOutput;\n output.position = vec4f(positions[index], 0.0, 1.0);\n output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);\n return output;\n}\n@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let world = camera.center + (input.uv - vec2f(0.5, 0.5)) * camera.viewport / camera.zoom * vec2f(1.0, -1.0);\n var irradiance = srgbToLinear(lighting.ambient.rgb) * lighting.ambient.a;\n for (var i = 0u; i < 32u; i += 1u) {\n if (i >= u32(lighting.info.x)) { break; }\n let point = lighting.points[i];\n let distance = length(world - point.position);\n if (distance < point.radius) {\n irradiance += srgbToLinear(point.color.rgb) * point.intensity * pow(1.0 - distance / point.radius, point.falloff);\n }\n }\n return vec4f(irradiance, 1.0);\n}";
|
|
3
|
+
export declare function gameLightingUniforms(frame: GameRenderFrame): Float32Array;
|
|
4
|
+
//# sourceMappingURL=lighting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lighting.d.ts","sourceRoot":"","sources":["../../src/webgpu/lighting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,eAAO,MAAM,YAAY,umDA6BvB,CAAC;AAGH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,eAAe,GAAG,YAAY,CAczE"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { parseTint } from "../frame.js";
|
|
2
|
+
export const LIGHT_SHADER = `
|
|
3
|
+
struct Camera { center: vec2f, viewport: vec2f, zoom: f32, padding0: f32, padding1: f32, padding2: f32 };
|
|
4
|
+
struct PointLight { position: vec2f, radius: f32, intensity: f32, color: vec4f, falloff: f32, pad0: f32, pad1: f32, pad2: f32 };
|
|
5
|
+
struct Lighting { ambient: vec4f, info: vec4f, points: array<PointLight, 32> };
|
|
6
|
+
fn srgbToLinear(rgb: vec3f) -> vec3f {
|
|
7
|
+
return select(rgb / 12.92, pow((rgb + 0.055) / 1.055, vec3f(2.4)), rgb > vec3f(0.04045));
|
|
8
|
+
}
|
|
9
|
+
@group(0) @binding(0) var<uniform> camera: Camera;
|
|
10
|
+
@group(0) @binding(1) var<uniform> lighting: Lighting;
|
|
11
|
+
struct VertexOutput { @builtin(position) position: vec4f, @location(0) uv: vec2f };
|
|
12
|
+
@vertex fn vertexMain(@builtin(vertex_index) index: u32) -> VertexOutput {
|
|
13
|
+
let positions = array<vec2f, 3>(vec2f(-1.0, -1.0), vec2f(3.0, -1.0), vec2f(-1.0, 3.0));
|
|
14
|
+
var output: VertexOutput;
|
|
15
|
+
output.position = vec4f(positions[index], 0.0, 1.0);
|
|
16
|
+
output.uv = positions[index] * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);
|
|
17
|
+
return output;
|
|
18
|
+
}
|
|
19
|
+
@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
20
|
+
let world = camera.center + (input.uv - vec2f(0.5, 0.5)) * camera.viewport / camera.zoom * vec2f(1.0, -1.0);
|
|
21
|
+
var irradiance = srgbToLinear(lighting.ambient.rgb) * lighting.ambient.a;
|
|
22
|
+
for (var i = 0u; i < 32u; i += 1u) {
|
|
23
|
+
if (i >= u32(lighting.info.x)) { break; }
|
|
24
|
+
let point = lighting.points[i];
|
|
25
|
+
let distance = length(world - point.position);
|
|
26
|
+
if (distance < point.radius) {
|
|
27
|
+
irradiance += srgbToLinear(point.color.rgb) * point.intensity * pow(1.0 - distance / point.radius, point.falloff);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return vec4f(irradiance, 1.0);
|
|
31
|
+
}`;
|
|
32
|
+
export function gameLightingUniforms(frame) {
|
|
33
|
+
const lighting = new Float32Array(392);
|
|
34
|
+
const sceneLighting = frame.lighting;
|
|
35
|
+
if (sceneLighting) {
|
|
36
|
+
const ambient = parseTint(sceneLighting.ambient.color);
|
|
37
|
+
lighting.set([ambient[0], ambient[1], ambient[2], sceneLighting.ambient.intensity,
|
|
38
|
+
sceneLighting.points.length, 1], 0);
|
|
39
|
+
for (const [index, point] of sceneLighting.points.entries()) {
|
|
40
|
+
const color = parseTint(point.color);
|
|
41
|
+
lighting.set([point.x, point.y, point.radius, point.intensity,
|
|
42
|
+
color[0], color[1], color[2], 0, point.falloff], 8 + index * 12);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return lighting;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=lighting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lighting.js","sourceRoot":"","sources":["../../src/webgpu/lighting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,MAAM,CAAC,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6B1B,CAAC;AAGH,MAAM,UAAU,oBAAoB,CAAC,KAAsB;IACvD,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,KAAK,CAAC,QAAQ,CAAC;IACrC,IAAI,aAAa,EAAE,CAAC;QAClB,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACvD,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,OAAO,CAAC,SAAS;YAC/E,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtC,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;YAC5D,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACrC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS;gBAC3D,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GameRenderPipeline } from "../renderPipeline.js";
|
|
2
|
+
export interface WebGPURenderContext {
|
|
3
|
+
readonly lighting: () => void | Promise<void>;
|
|
4
|
+
readonly sprites: () => void | Promise<void>;
|
|
5
|
+
readonly effects: () => void | Promise<void>;
|
|
6
|
+
readonly hud: () => void | Promise<void>;
|
|
7
|
+
}
|
|
8
|
+
export declare class WebGPURenderPipeline extends GameRenderPipeline<WebGPURenderContext> {
|
|
9
|
+
constructor();
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=pipeline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/webgpu/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1C;AAED,qBAAa,oBAAqB,SAAQ,kBAAkB,CAAC,mBAAmB,CAAC;IAC/E,cAMC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { GameRenderPipeline } from "../renderPipeline.js";
|
|
2
|
+
export class WebGPURenderPipeline extends GameRenderPipeline {
|
|
3
|
+
constructor() {
|
|
4
|
+
super();
|
|
5
|
+
this.register({ name: "lighting", order: 0, render: (context) => context.lighting() });
|
|
6
|
+
this.register({ name: "sprites", order: 1, render: (context) => context.sprites() });
|
|
7
|
+
this.register({ name: "effects", order: 2, render: (context) => context.effects() });
|
|
8
|
+
this.register({ name: "hud", order: 3, render: (context) => context.hud() });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/webgpu/pipeline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAS1D,MAAM,OAAO,oBAAqB,SAAQ,kBAAuC;IAC/E;QACE,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACvF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QACrF,IAAI,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC/E,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Batch, TextureEntry, Blend } from "./types.js";
|
|
2
|
+
export declare const INSTANCE_FLOATS = 14;
|
|
3
|
+
export declare const SHADER = "\nstruct Camera { center: vec2f, viewport: vec2f, zoom: f32, padding0: f32, padding1: f32, padding2: f32 };\noverride linearizeInput: bool = false;\nfn srgbToLinear(rgb: vec3f) -> vec3f {\n return select(rgb / 12.92, pow((rgb + 0.055) / 1.055, vec3f(2.4)), rgb > vec3f(0.04045));\n}\nfn linearToSrgb(rgb: vec3f) -> vec3f {\n return select(rgb * 12.92, 1.055 * pow(rgb, vec3f(1.0 / 2.4)) - 0.055, rgb > vec3f(0.0031308));\n}\n@group(0) @binding(0) var<uniform> camera: Camera;\n@group(0) @binding(1) var atlasSampler: sampler;\n@group(0) @binding(2) var atlas: texture_2d<f32>;\n@group(1) @binding(0) var lightSampler: sampler;\n@group(1) @binding(1) var lightTexture: texture_2d<f32>;\n\nstruct VertexInput {\n @builtin(vertex_index) corner: u32,\n @location(0) center: vec2f,\n @location(1) size: vec2f,\n @location(2) uv: vec4f,\n @location(3) color: vec4f,\n @location(4) rotation: f32,\n @location(5) unlit: f32,\n};\nstruct VertexOutput {\n @builtin(position) position: vec4f,\n @location(0) uv: vec2f,\n @location(1) color: vec4f,\n @location(3) @interpolate(flat) unlit: f32,\n @location(4) lightUv: vec2f,\n};\n@vertex fn vertexMain(input: VertexInput) -> VertexOutput {\n let corners = array<vec2f, 6>(\n vec2f(-0.5, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, 0.5),\n vec2f(0.5, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));\n let local = corners[input.corner] * input.size;\n let sine = sin(input.rotation);\n let cosine = cos(input.rotation);\n let rotated = vec2f(local.x * cosine - local.y * sine, local.x * sine + local.y * cosine);\n let world = input.center + rotated;\n let clip = (world - camera.center) * camera.zoom * 2.0 / camera.viewport;\n var output: VertexOutput;\n output.position = vec4f(clip, 0.0, 1.0);\n let uvCorner = corners[input.corner] + vec2f(0.5, 0.5);\n output.uv = input.uv.xy + vec2f(uvCorner.x, 1.0 - uvCorner.y) * input.uv.zw;\n output.color = input.color;\n output.unlit = input.unlit;\n output.lightUv = clip * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);\n return output;\n}\n@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {\n let sampled = textureSample(atlas, atlasSampler, input.uv) * input.color;\n var straight = select(sampled.rgb, srgbToLinear(sampled.rgb), linearizeInput);\n if (input.unlit < 0.5) {\n let irradiance = textureSampleLevel(lightTexture, lightSampler, input.lightUv, 0.0).rgb;\n let lit = clamp(srgbToLinear(sampled.rgb) * irradiance, vec3f(0.0), vec3f(1.0));\n straight = select(linearToSrgb(lit), lit, linearizeInput);\n }\n return vec4f(straight * sampled.a, sampled.a);\n}";
|
|
4
|
+
export declare function appendBatch(batches: Batch[], texture: TextureEntry, blend: Blend, index: number): void;
|
|
5
|
+
export declare function writeInstance(target: Float32Array, index: number, ...values: number[]): void;
|
|
6
|
+
//# sourceMappingURL=sprites.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprites.d.ts","sourceRoot":"","sources":["../../src/webgpu/sprites.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC7D,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,MAAM,0iFA2DjB,CAAC;AAEH,wBAAgB,WAAW,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAOpG;AAEH,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAE1F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export const INSTANCE_FLOATS = 14;
|
|
2
|
+
export const SHADER = `
|
|
3
|
+
struct Camera { center: vec2f, viewport: vec2f, zoom: f32, padding0: f32, padding1: f32, padding2: f32 };
|
|
4
|
+
override linearizeInput: bool = false;
|
|
5
|
+
fn srgbToLinear(rgb: vec3f) -> vec3f {
|
|
6
|
+
return select(rgb / 12.92, pow((rgb + 0.055) / 1.055, vec3f(2.4)), rgb > vec3f(0.04045));
|
|
7
|
+
}
|
|
8
|
+
fn linearToSrgb(rgb: vec3f) -> vec3f {
|
|
9
|
+
return select(rgb * 12.92, 1.055 * pow(rgb, vec3f(1.0 / 2.4)) - 0.055, rgb > vec3f(0.0031308));
|
|
10
|
+
}
|
|
11
|
+
@group(0) @binding(0) var<uniform> camera: Camera;
|
|
12
|
+
@group(0) @binding(1) var atlasSampler: sampler;
|
|
13
|
+
@group(0) @binding(2) var atlas: texture_2d<f32>;
|
|
14
|
+
@group(1) @binding(0) var lightSampler: sampler;
|
|
15
|
+
@group(1) @binding(1) var lightTexture: texture_2d<f32>;
|
|
16
|
+
|
|
17
|
+
struct VertexInput {
|
|
18
|
+
@builtin(vertex_index) corner: u32,
|
|
19
|
+
@location(0) center: vec2f,
|
|
20
|
+
@location(1) size: vec2f,
|
|
21
|
+
@location(2) uv: vec4f,
|
|
22
|
+
@location(3) color: vec4f,
|
|
23
|
+
@location(4) rotation: f32,
|
|
24
|
+
@location(5) unlit: f32,
|
|
25
|
+
};
|
|
26
|
+
struct VertexOutput {
|
|
27
|
+
@builtin(position) position: vec4f,
|
|
28
|
+
@location(0) uv: vec2f,
|
|
29
|
+
@location(1) color: vec4f,
|
|
30
|
+
@location(3) @interpolate(flat) unlit: f32,
|
|
31
|
+
@location(4) lightUv: vec2f,
|
|
32
|
+
};
|
|
33
|
+
@vertex fn vertexMain(input: VertexInput) -> VertexOutput {
|
|
34
|
+
let corners = array<vec2f, 6>(
|
|
35
|
+
vec2f(-0.5, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, 0.5),
|
|
36
|
+
vec2f(0.5, 0.5), vec2f(-0.5, -0.5), vec2f(0.5, -0.5));
|
|
37
|
+
let local = corners[input.corner] * input.size;
|
|
38
|
+
let sine = sin(input.rotation);
|
|
39
|
+
let cosine = cos(input.rotation);
|
|
40
|
+
let rotated = vec2f(local.x * cosine - local.y * sine, local.x * sine + local.y * cosine);
|
|
41
|
+
let world = input.center + rotated;
|
|
42
|
+
let clip = (world - camera.center) * camera.zoom * 2.0 / camera.viewport;
|
|
43
|
+
var output: VertexOutput;
|
|
44
|
+
output.position = vec4f(clip, 0.0, 1.0);
|
|
45
|
+
let uvCorner = corners[input.corner] + vec2f(0.5, 0.5);
|
|
46
|
+
output.uv = input.uv.xy + vec2f(uvCorner.x, 1.0 - uvCorner.y) * input.uv.zw;
|
|
47
|
+
output.color = input.color;
|
|
48
|
+
output.unlit = input.unlit;
|
|
49
|
+
output.lightUv = clip * vec2f(0.5, -0.5) + vec2f(0.5, 0.5);
|
|
50
|
+
return output;
|
|
51
|
+
}
|
|
52
|
+
@fragment fn fragmentMain(input: VertexOutput) -> @location(0) vec4f {
|
|
53
|
+
let sampled = textureSample(atlas, atlasSampler, input.uv) * input.color;
|
|
54
|
+
var straight = select(sampled.rgb, srgbToLinear(sampled.rgb), linearizeInput);
|
|
55
|
+
if (input.unlit < 0.5) {
|
|
56
|
+
let irradiance = textureSampleLevel(lightTexture, lightSampler, input.lightUv, 0.0).rgb;
|
|
57
|
+
let lit = clamp(srgbToLinear(sampled.rgb) * irradiance, vec3f(0.0), vec3f(1.0));
|
|
58
|
+
straight = select(linearToSrgb(lit), lit, linearizeInput);
|
|
59
|
+
}
|
|
60
|
+
return vec4f(straight * sampled.a, sampled.a);
|
|
61
|
+
}`;
|
|
62
|
+
export function appendBatch(batches, texture, blend, index) {
|
|
63
|
+
const last = batches[batches.length - 1];
|
|
64
|
+
if (last?.texture === texture && last.blend === blend) {
|
|
65
|
+
last.count++;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
batches.push({ texture, blend, first: index, count: 1 });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function writeInstance(target, index, ...values) {
|
|
72
|
+
target.set(values, index * INSTANCE_FLOATS);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=sprites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprites.js","sourceRoot":"","sources":["../../src/webgpu/sprites.ts"],"names":[],"mappings":"AACA,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2DpB,CAAC;AAEH,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,OAAqB,EAAE,KAAY,EAAE,KAAa;IAC5F,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,IAAI,EAAE,OAAO,KAAK,OAAO,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACtD,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,MAAoB,EAAE,KAAa,EAAE,GAAG,MAAgB;IAClF,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TextureEntry {
|
|
2
|
+
readonly texture: GPUTexture;
|
|
3
|
+
readonly bindGroup: GPUBindGroup;
|
|
4
|
+
readonly width: number;
|
|
5
|
+
readonly height: number;
|
|
6
|
+
}
|
|
7
|
+
export type Blend = "normal" | "additive";
|
|
8
|
+
export interface Batch {
|
|
9
|
+
readonly texture: TextureEntry;
|
|
10
|
+
readonly blend: Blend;
|
|
11
|
+
readonly first: number;
|
|
12
|
+
count: number;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/webgpu/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,YAAY,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE1C,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,OAAO,EAAE,YAAY,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;CACf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/webgpu/types.ts"],"names":[],"mappings":""}
|
package/dist/webgpu.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { GameRenderFrame } from "@nodetool-ai/protocol";
|
|
2
2
|
import { AssetCache } from "./canvas2d.js";
|
|
3
|
+
import { type GameParticleField } from "./particles/render2d.js";
|
|
3
4
|
import type { GameHudEffectOrder, GameRenderer, GameRendererCapabilities, GameRendererEffect, GameRendererStats } from "./index.js";
|
|
4
5
|
/** Draws ordered sprites as consecutive texture batches on a private WebGPU device. */
|
|
5
6
|
export declare class WebGPUGameRenderer implements GameRenderer {
|
|
@@ -9,6 +10,7 @@ export declare class WebGPUGameRenderer implements GameRenderer {
|
|
|
9
10
|
private readonly format;
|
|
10
11
|
private readonly assets;
|
|
11
12
|
private readonly adapterType;
|
|
13
|
+
private readonly renderPipeline;
|
|
12
14
|
readonly backend = "webgpu";
|
|
13
15
|
private readonly pipeline;
|
|
14
16
|
private readonly effectSpritePipeline;
|
|
@@ -43,6 +45,7 @@ export declare class WebGPUGameRenderer implements GameRenderer {
|
|
|
43
45
|
private readonly textures;
|
|
44
46
|
private readonly validatedLuts;
|
|
45
47
|
private readonly fallback;
|
|
48
|
+
private readonly particleDot;
|
|
46
49
|
private readonly placeholders;
|
|
47
50
|
private instanceBuffer;
|
|
48
51
|
private instanceCapacity;
|
|
@@ -62,11 +65,9 @@ export declare class WebGPUGameRenderer implements GameRenderer {
|
|
|
62
65
|
private getTexture;
|
|
63
66
|
private getLutTexture;
|
|
64
67
|
private placeholder;
|
|
65
|
-
render(frame: GameRenderFrame, interpolation: number): Promise<GameRendererStats>;
|
|
68
|
+
render(frame: GameRenderFrame, interpolation: number, particles?: GameParticleField): Promise<GameRendererStats>;
|
|
66
69
|
private renderFrame;
|
|
67
70
|
private updateHud;
|
|
68
|
-
private appendBatch;
|
|
69
|
-
private writeInstance;
|
|
70
71
|
private ensureInstanceCapacity;
|
|
71
72
|
resize(width: number, height: number): void;
|
|
72
73
|
invalidateAsset(assetId: string): void;
|
package/dist/webgpu.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webgpu.d.ts","sourceRoot":"","sources":["../src/webgpu.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webgpu.d.ts","sourceRoot":"","sources":["../src/webgpu.ts"],"names":[],"mappings":"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"}
|