The SHADER block
Every shader is a SHADER block with a name. Inside it go the settings it
takes, each on a USE line, and then one WHEN DRAWING block: the code that
runs for every pixel.
SCREEN 320, 240
SHADER "darker"
USE NUMBER amount DEFAULT 0.5
WHEN DRAWING
c = IMAGE
SET COLOR = RGBA(c.r * amount, c.g * amount, c.b * amount, c.a)
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("darker")
PAUSE
Here’s what each part does:
SHADER "darker"names it. The name is how a layer, a sprite or a behavior asks for it, and defining a second shader with the same name replaces the first.USE NUMBER amount DEFAULT 0.5is a setting. Your program can change it while the game runs, andDEFAULTis what it is until it does. The next chapter but four is all about settings.WHEN DRAWING…END WHENis the code. It runs once for every pixel.IMAGEis the color the pixel was going to be: what’s drawn on the layer there, or the sprite’s picture.SET COLOR =is the color it is instead.
SET LAYER 0 !! shader("darker") puts the shader on layer 0, and from then
on everything on that layer goes through it, including what’s drawn later.
Only two kinds of line
Inside WHEN DRAWING there are exactly two kinds of line. A name and =
makes or changes a variable of the shader’s own:
c = IMAGE
grey = (c.r + c.g + c.b) / 3.0
And SET COLOR = says what the pixel’s color is:
SET COLOR = RGBA(grey, grey, grey, c.a)
There’s no IF, no loops, no PRINT, no FUNCTION. That sounds like a lot
to give up, and it isn’t: the chapter on choices shows how a shader decides
things without them.
The lines run top to bottom, and a variable can be given a new value as you
go. If there’s more than one SET COLOR, the last one wins:
SCREEN 320, 240
SHADER "last"
WHEN DRAWING
c = IMAGE
c = c * 0.5
SET COLOR = RGBA(1.0, 0.0, 0.0, 1.0)
SET COLOR = RGBA(c.r, c.g, c.b, 1.0)
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("last")
PAUSE
The city comes out at half brightness, not red.
And a shader with no SET COLOR at all leaves every pixel as it was. That’s
not useful by itself, but it’s a handy way to switch a shader off while you
look for what’s wrong with it.
Comments
A comment in a shader starts with ', on a line of its own or at the end of
one:
SCREEN 320, 240
SHADER "commented"
' Turn the picture upside down.
WHEN DRAWING
' UV.y runs 0 at the top to 1 at the bottom, so this reads from the
' other end.
SET COLOR = OWNTEXTURE(VEC2(UV.x, 1.0 - UV.y)) ' and that's all
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("commented")
PAUSE
The shader block is the one place in Crash BASIC 2 where // isn’t a
comment. I hand the lines between SHADER and END SHADER to the shader
language as you wrote them, and the shader language came from Crash BASIC 1,
where a comment starts with '. So this stops, on the line with the //:
SCREEN 320, 240
SHADER "oops"
WHEN DRAWING
// Not a comment in here.
SET COLOR = IMAGE
END WHEN
END SHADER
Big and small letters
The shader language doesn’t mind how you write a word: SET COLOR,
set color and Set Color are the same, and so are IMAGE, image and
Image. So are your own variables: c and C are one variable.
SCREEN 320, 240
SHADER "casual"
WHEN DRAWING
Pixel = image
set color = rgba(PIXEL.r, pixel.g, 0.0, 1.0)
END WHEN
END SHADER
LOADIMG "city.png", "city"
PUTIMAGE (32, 0), "city"
SET LAYER 0 !! shader("casual")
PAUSE
This book writes the language’s own words in capitals and your names in small letters, so you can tell them apart at a glance.