A name that a sprite already owns cannot name a property, and a division by zero cannot answer (#63, #64)
game-maker / suite (push) Failing after 11m29s
game-maker / suite (push) Failing after 11m29s
#63: a shader Property node named "width" quietly took over the sprite row of the same name. isSpriteProp lives in PropertySchema now and is derived from FULL_SCHEMAS.sprite instead of being a second list that drifts. isValidPropertyName rejects those ten names, and the compiler reports it at the node as its own problem: "width" is a sprite property, told apart from "not a word" and from a duplicate. #64: Divide emitted (a / b) and handed NaN to the driver. It emits divide(a, b) now, with the guard in the prologue next to straight(), scalar and per channel: zero divided by zero is zero. That was already the house rule in the behavior and particle graphs - only the shader had never been told. Clamp comes along as a shader node for the same reason: the behavior catalog has had it all along.
This commit is contained in:
1 parent
150f2e0906
commit
c990dbcb26
6 files changed
+203
-6
No files matched your search
@@ -373,6 +373,71 @@ describe('compileShader', () => {
|
||||
expect(build.problems).toEqual({ [two]: 'Feeds itself' });
|
||||
});
|
||||
|
||||
it('refuses a property named like a row the sprite brings itself (#63)', () => {
|
||||
const f = makeSpriteScene();
|
||||
const s = shaderEditor(f);
|
||||
s.add(SHADER_OUTPUT);
|
||||
// One of the sprite's own rows, one of the transform rows, one legitimate name.
|
||||
const wide = s.add(SHADER_PROPERTY, property('width'));
|
||||
const turned = s.add(SHADER_PROPERTY, property('rotation'));
|
||||
const fine = s.add(SHADER_PROPERTY, property('amount'));
|
||||
const build = compileShader(s.asset().graph);
|
||||
expect(build.compiled).toBeNull();
|
||||
expect(build.problems).toEqual({
|
||||
[wide]: '"width" is a sprite property',
|
||||
[turned]: '"rotation" is a sprite property',
|
||||
});
|
||||
expect(build.problems[fine]).toBeUndefined();
|
||||
// The row is not declared either, so the sprite keeps one width row – the one that is 100.
|
||||
expect(shaderParamDefs(s.asset().graph).map((r) => r.key)).toEqual(['amount']);
|
||||
const sprite = findAssetOf(f.project, f.spriteId, 'sprite')!;
|
||||
f.stack.execute(new SetAssetPropertyCommand(f.spriteId, SHADER_KEY, s.id));
|
||||
const rows = schemaForAsset(f.project, sprite).filter((d) => d.key === 'width');
|
||||
expect(rows).toHaveLength(1);
|
||||
expect(rows[0]).toMatchObject({ label: 'Width', default: 100 });
|
||||
});
|
||||
|
||||
it('divides through a guard, so dividing by zero is 0 and not the driver’s choice (#64)', () => {
|
||||
const f = makeProject();
|
||||
const s = shaderEditor(f);
|
||||
const zero = s.add(SHADER_NUMBER, { value: 0 });
|
||||
const half = s.add('ShaderDivide', { a: 1 });
|
||||
const held = s.add('ShaderClamp', { min: 0, max: 0.5 });
|
||||
const output = s.add(SHADER_OUTPUT);
|
||||
s.link(zero, 'value', half, 'b');
|
||||
s.link(half, 'result', held, 'value');
|
||||
s.link(held, 'result', output, 'color');
|
||||
const { fragment } = compileShader(s.asset().graph).compiled!;
|
||||
expect(fragment).toContain('float divide(float a, float b) { return b == 0.0 ? 0.0 : a / b; }');
|
||||
expect(fragment).toMatch(/float n\d+_result = divide\(1\.0, n\d+_value\);/);
|
||||
expect(fragment).toMatch(/float n\d+_result = clamp\(n\d+_result, 0\.0, 0\.5\);/);
|
||||
// Nothing writes the bare operator any more – that was the NaN (#64).
|
||||
expect(fragment).not.toMatch(/n\d+_\w+ \/ n\d+_\w+/);
|
||||
|
||||
// A colour divides per channel, through the vec3 overload of the same guard.
|
||||
const c = shaderEditor(f, 'Faded');
|
||||
const texel = c.add(SHADER_TEXTURE_COLOR);
|
||||
const by = c.add('ShaderDivide', { b: 2 });
|
||||
const out = c.add(SHADER_OUTPUT);
|
||||
c.link(texel, 'color', by, 'a');
|
||||
c.link(by, 'result', out, 'color');
|
||||
const coloured = compileShader(c.asset().graph).compiled!.fragment;
|
||||
expect(coloured).toContain(
|
||||
'vec3 divide(vec3 a, vec3 b) { return vec3(divide(a.x, b.x), divide(a.y, b.y), divide(a.z, b.z)); }',
|
||||
);
|
||||
expect(coloured).toMatch(/vec3 n\d+_result = divide\(n\d+_color, vec3\(2\.0\)\);/);
|
||||
// A clamped colour keeps its type: clamp(vec3, float, float) is one of the GLSL overloads.
|
||||
const k = shaderEditor(f, 'Held');
|
||||
const rgb = k.add(SHADER_TEXTURE_COLOR);
|
||||
const clamped = k.add('ShaderClamp', { min: 0.25, max: 0.75 });
|
||||
const out2 = k.add(SHADER_OUTPUT);
|
||||
k.link(rgb, 'color', clamped, 'value');
|
||||
k.link(clamped, 'result', out2, 'color');
|
||||
expect(compileShader(k.asset().graph).compiled!.fragment).toMatch(
|
||||
/vec3 n\d+_result = clamp\(n\d+_color, 0\.25, 0\.75\);/,
|
||||
);
|
||||
});
|
||||
|
||||
it('gives the graph the pixel’s place, the picture at another spot, its size and the clock', () => {
|
||||
const f = makeProject();
|
||||
const s = shaderEditor(f, 'Flip');
|
||||
|
||||
Reference in new issue
Block a user