Files
feuerwerk/tools/e2e/lib/pictures.mjs
T
adminandClaude Opus 5.5 df61b08bd1
game-maker / gate (push) Successful in 3m3s
game-maker / suite (push) Successful in 14m26s
Soften a shader's picture in one pass with a Blur node (#300)
A blur already worked with Sample texture, but only by wiring every
sample by hand: 25 nodes for a 5x5. Averaging their colours also gave
a dark seam wherever a neighbour was transparent. The Blur node writes
the loop itself and averages the right way.

- Blur takes radius (pixels of the picture, 0 to 8, fractions allowed)
  and u/v like Sample texture, and gives color and alpha.
- Kind is Box (default) or Gaussian, Direction is Both, Horizontal or
  Vertical. Both are arguments of one prelude helper, blur().
- The samples are averaged premultiplied and only then made straight,
  so a transparent neighbour lowers the opacity and adds no black.
- The outermost ring counts by the part of the radius that reaches
  it, so a radius from a Property changes smoothly and compiles
  nothing again.
- A node may now declare prepare, a vec4 the compiler works out once
  into a local. Color and alpha read that one sum instead of blurring
  twice.
- A reached Blur counts as a shifted sample, so the picture comes
  with the Output's Edge. It cannot feed the Vertex output.
- Both perf tools take GM_PERF_BLUR=<radius>.

Wider blurs and bloom need several passes. That is #301.

Measured on stein2 (HD 630, one run per value, fps), Box blur:
- 48x48 sprites at 100/400/800: radius 2 59.8/58.4/55.6,
  radius 4 53.1/51.4/36.3, radius 8 46.6/24.4/14.4.
- 256x256 field shaders at 1/10/50: radius 2 60.2/56.0/49.0,
  radius 4 60.1/49.0/27.1, radius 8 52.4/34.9/11.4.

Tests:
- Gate: 224 files, 3467 tests, CHECK EXIT 0 (+7).
- e2e 28: ALL PASSED, 94 checks (+5 in 28l-vi). Pixels match the
  arithmetic to 1: the last red texel at radius 0.5/1/4 reads
  187/173/154 (expected 188/173/154).
- Counter-checks: Blur not counted as shifted fails 1 unit test.
  Blur output left premultiplied fails the seam and spot checks.
- e2e total 1712 is computed (1707 + 5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 13:11:31 +02:00

39 lines
2.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** A 32 px picture, red on the left and green on the right, pasted in for pixel checks (28l, 29e). */
export const PASTE_HALVES = `(async () => {
const canvas = document.createElement('canvas');
canvas.width = 32;
canvas.height = 32;
const g = canvas.getContext('2d');
g.fillStyle = '#e63c3c'; g.fillRect(0, 0, 16, 32);
g.fillStyle = '#3cc85a'; g.fillRect(16, 0, 16, 32);
const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
const transfer = new DataTransfer();
transfer.items.add(new File([blob], 'halves.png', { type: 'image/png' }));
window.dispatchEvent(new ClipboardEvent('paste', { clipboardData: transfer, bubbles: true }));
})()`;
export const HALVES_LEFT = '#e63c3c';
export const HALVES_RIGHT = '#3cc85a';
/** A 16 px transparent picture with one white pixel at (4, 4), for the Blur's spot (28l-vi). */
export const PASTE_DOT = `(async () => {
const canvas = document.createElement('canvas');
canvas.width = 16;
canvas.height = 16;
const g = canvas.getContext('2d');
g.fillStyle = '#ffffff'; g.fillRect(4, 4, 1, 1);
const blob = await new Promise((resolve) => canvas.toBlob(resolve, 'image/png'));
const transfer = new DataTransfer();
transfer.items.add(new File([blob], 'dot.png', { type: 'image/png' }));
window.dispatchEvent(new ClipboardEvent('paste', { clipboardData: transfer, bubbles: true }));
})()`;
export const FIND_DOT =
"__gm.state.project.assets.filter((a) => a.type === 'texture' && a.name === 'dot' && a.width === 16).map((a) => a.id).at(-1) ?? null";
/**
* The pasted picture's asset, once the paste has landed: the newest one named after the pasted
* file. Size alone is not enough – in the full run a module before 47 leaves a 32 px "wedge"
* behind, and taking the first 32 px texture picked that one (CI task 217).
*/
export const FIND_HALVES =
"__gm.state.project.assets.filter((a) => a.type === 'texture' && a.name === 'halves' && a.width === 32 && a.height === 32).map((a) => ({ id: a.id, file: a.file })).at(-1) ?? null";