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>
39 lines
2.0 KiB
JavaScript
39 lines
2.0 KiB
JavaScript
/** 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";
|