Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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 shader and shader_params together, 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.