Settings
A shader can’t see your program’s variables. What it needs from your game
comes in through its settings: the USE lines at the top of the block.
USE NUMBER
USE NUMBER name is a number your program can set. DEFAULT says what it is
until your program does; without one, it’s 0.
SCREEN 320, 240
SHADER "tint"
USE NUMBER red DEFAULT 1.0
USE NUMBER green DEFAULT 1.0
USE NUMBER blue DEFAULT 1.0
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * red, c.g * green, c.b * blue, c.a)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(60) y(100) scale((3, 3))
!! shader("tint")
SHOW SPRITE 0
ENABLE SPRITE 1
SET SPRITE 1 !! image("hero") x(180) y(100) scale((3, 3))
!! shader("tint") shader_params({green: 0.4, blue: 0.4})
SHOW SPRITE 1
PAUSE
shader_params goes with shader, and takes a dictionary of names and
values. The first hero has the defaults, all 1, and looks as it always does.
The second has less green and blue, and comes out red. Two sprites, one
shader, a setting each: a setting belongs to the layer or sprite the shader is
on, not to the shader.
A setting you don’t give keeps its default. A setting the shader doesn’t have is a mistake, and I stop and tell you which ones it does have:
SCREEN 320, 240
SHADER "tint"
USE NUMBER red DEFAULT 1.0
USE NUMBER green DEFAULT 1.0
USE NUMBER blue DEFAULT 1.0
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * red, c.g * green, c.b * blue, c.a)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(140) y(100) shader("tint") shader_params({gren: 0.4})
There’s no gren, so I stop, and say the settings are blue, green and
red. The same goes for a shader name I don’t know: shader("tnt") stops
too.
Changing a setting
On a layer, shader_params by itself, without shader, changes the settings
of the shader that’s already on, and leaves the rest of them as they were:
SCREEN 320, 240
SHADER "tint"
USE NUMBER red DEFAULT 1.0
USE NUMBER green DEFAULT 1.0
USE NUMBER blue DEFAULT 1.0
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * red, c.g * green, c.b * blue, c.a)
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("tint")
t = 0
DO
IF COOLDOWN(1)
t = t + 0.02
SET LAYER 0 !! shader_params({red: 0.6 + SIN(t) * 0.4, green: 0.6 + SIN(t + 2) * 0.4})
END IF
LOOP
blue is never changed, so it stays at its default, and the red and green
drift in and out of step with each other. Changing a layer’s numbers this way
is cheap, so it’s fine to do every tick.
It changes the shader that’s on, so there has to be one. On a layer with no shader, there’s nothing for the numbers to go to, and I stop:
SCREEN 320, 240
SET LAYER 0 !! shader_params({red: 0.5})
A sprite’s or a shape’s settings go with its shader every time: give
shader again, with the new shader_params.
SCREEN 320, 240
SHADER "tint"
USE NUMBER red DEFAULT 1.0
USE NUMBER green DEFAULT 1.0
USE NUMBER blue DEFAULT 1.0
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * red, c.g * green, c.b * blue, c.a)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(140) y(100) scale((3, 3))
SHOW SPRITE 0
hurt = FALSE
DO
IF COOLDOWN(30)
hurt = NOT hurt
IF hurt
SET SPRITE 0 !! shader("tint") shader_params({green: 0.3, blue: 0.3})
ELSE
SET SPRITE 0 !! shader("tint")
END IF
END IF
LOOP
The hero goes red, then back, every half second. Without shader_params,
the settings go back to their defaults.
Crash-tan’s Tip: For a setting on a sprite that changes every tick, a glow or a flash, let a behavior run the shader: it moves the setting for you, without your program sending the shader again each time. That’s in the chapter on behaviors.
USE COLOR
USE COLOR name is a color your program can set: four numbers, red, green,
blue and alpha, each from 0 to 1, as a shader sees them. Its DEFAULT is
written RGB(r, g, b) or RGBA(r, g, b, a); without one, it’s black. In
the shader, it’s a color like any other, and .r, .g, .b and .a are its
parts.
Your program gives it as three numbers, or four with the alpha, in brackets like a place:
SCREEN 320, 240
SHADER "tint"
USE COLOR tint DEFAULT RGB(1.0, 1.0, 1.0)
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * tint.r, c.g * tint.g, c.b * tint.b, c.a)
END WHEN
END SHADER
LOADIMG "hero.png", "hero"
ENABLE SPRITE 0
SET SPRITE 0 !! image("hero") x(40) y(100) scale((3, 3))
!! shader("tint") shader_params({tint: (1.0, 0.4, 0.4)})
SHOW SPRITE 0
ENABLE SPRITE 1
SET SPRITE 1 !! image("hero") x(140) y(100) scale((3, 3))
!! shader("tint") shader_params({tint: (0.4, 1.0, 0.4)})
SHOW SPRITE 1
ENABLE SPRITE 2
SET SPRITE 2 !! image("hero") x(240) y(100) scale((3, 3))
!! shader("tint") shader_params({tint: [0.4, 0.4, 1.0]})
SHOW SPRITE 2
PAUSE
A red hero, a green one and a blue one. The last color is a list, which works just as well as brackets. Give three numbers and the alpha is 1; 255 in a palette is 1 here.
A color takes the room of four numbers, so a shader can have up to 16 of
them, or fewer and some USE NUMBERs besides.
USE IMAGE
USE IMAGE name is a picture the shader can read from, besides its own.
SAMPLE(name, uv) reads it, the way OWNTEXTURE(uv) reads the shader’s own
picture, and your program says which picture it is by giving its name as the
setting:
SCREEN 320, 240
SHADER "window"
USE IMAGE outside
WHEN DRAWING
c = IMAGE
view = SAMPLE(outside, UV)
bright = c.r * 0.3 + c.g * 0.59 + c.b * 0.11
SET COLOR = MIX(view, c, STEP(0.2, bright))
END WHEN
END SHADER
LOADIMG "city.png", "city"
LOADIMG "greyscale.png", "tiles"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("window") shader_params({outside: "tiles"})
PAUSE
Wherever the city is dark, you see the tiles picture through it instead.
A picture is stretched over the whole of what the shader’s on: UV runs 0
to 1 across it whatever size it is. A shader can use up to four pictures.
Crash-tan’s Tip: A picture is given when the shader goes on, with
shaderandshader_paramstogether, on a layer as on a sprite. To change which picture it reads, put the shader on again with the new one.
What a DEFAULT can be
A DEFAULT is a plain number, like 0.5 or 3. It can’t be a sum, and it
can’t have a minus in front. When a setting should start out below zero, give
it its value from your program, with shader_params, as the shader goes on.