Shaders are computer programs which doesn't run in your computer CPU, but in the computer GPU, or video graphics card. These programs compute every vertex position and pixel color you see in the screen. If you create any interface in your Weaver program, you are using shaders.
If your game is made of very simple elements, like solid rectangles, you won't need o create a custom shader. But if you wish to show advanced visual effects to give for your game some unique visual identity, you will need to create custom shaders.
If you want to use a custom shader, first create it using the following command inside a Weaver directory:
weaver --shader SHADER_NAME
Where SHADER_NAME is your shader name. A shader name can countain any alphanumeric character and shouldn't begin with a digit. After using this command, check the directory shaders/. You should find a new directory called shaders/1-SHADER_NAME/. Or perhaps, instead of "1", you find another number before your shader name. This is your shader's id number and it's how you will identify this shader in your program.
To create a new interface which will use your custom shader, just call W.new_interface, passing the shader id number as the first argument. For example:
W.new_interface(1, W.width / 2, W.height / 2, W.width, W.height, NULL);
This creates a new interface as big as your game window which will render using your brand new shader. As the last variable is NULL not an image filename (the name of a file in image folder), you won't sent a texture for your shader as "texture1".
If you look inside the directory shaders/1-SHADER_NAME/, you will discover that your new shader is in fact two shaders. One is a vertex shader (in the file vertex.glsl) and the other is a fragment shader (in the file fragment.glsl). The first will be run in parallel once for each vertex drawn in your game every frame. The second will be run in parallel once for each pixel drawn in your game every frame.
The two shaders are written in the language GLSL, which is very similar to C. Teaching how to program in GLSL is out of scope of this page. But you can find lot of examples, tutorials and documentation in books and in the Internet. But we will document below what variables these shaders get from your game.
This is a list of variables that both the vertex shader and the fragment shader get from your main program:
An arbitrary integer which you can set in your game and use as you wish in your shaders. If you are rendering an interface, you can set this value in the integer variable/attribute. If you are rendering the entire screen in a 2-pass rendering, you can set this number in the variable W.final_shader_integer.
If you are rendering an interface, this is the interface color represented by it's variable/attribute r, g, b and a. For other elements, this value is undefined.
If you are rendering an interface, this is the interface width and height in pixels. If you are rendering the game screen (if you use 2 pass rendering), this is your window width and height.
This is the time in seconds. Every time we render in the screen, we increment this uniform to inform how many seconds passed since last rendering. But after 5 minutes, when hisuniform would have the value 600.0, instead we set it to 0 again, to prevent underflows and loss of precision of bigger float numbers.
If you use the time to rneder some animation, it's a good idea to make the animation cyclic with a period of 5 minutes.
This is a list of variables accessible only in the vertex shader:
The vertex coordinates before any movement, rotation or resize. An interface or a screen in 2-pass rendering always are quads with coordinates (-0.5, -0.5), (-0.5, 0.5), (0.5, 0.5) and (0.5, -0.5).
The matrix to multiply each vertex position to make it appear in the screen taking into account the window size, the object rotation, the object size and the object translation.
This is a list of variables accessible only in the fragment shader:
The object texture. If you are rendering the screen in a 2-pass rendering, this texture was the image rendered in the first pass.
These variables are set in the verte shader and then can be used in the fragment shader.
Which coordinate you should read from texture1.
Use a 2-pass rendering means instead of render all your game and interfaces in the window, you first render to a texture, and then render the texture in the screen. This means that when you finally are drawing in the screen, you already have a texture which tells you all about the scene yu are rendering.
You can then create a new shader to render the game in the screen with post-processing effects. You can use tricks like blurring or distorting your final image in the screen.
To enable a 2-pass rendering, just use the function W.change_final_shader, passing the id number of the shader which should render your final image in the screen. You can also pass an integer for this shader, setting the variable W.final_shader_integer.