-
Notifications
You must be signed in to change notification settings - Fork 0
LorikeetAPI
The Lorikeet system is about as simple as it gets, with only one function that you generally need to call directly.
Returns: N/A
Parameter | Type | Description |
---|---|---|
palette_sprite | sprite | The palette sprite you want to make use of when drawing |
palette_index | real | The horizontal row of the palette sprite that you would like to draw with; defaults to 0 for the top row |
subimage | integer | The image index of the palette sprite that you wish to use; defaults to 0 |
shader | shader | The shader you wish to use; defaults to shd_lorikeet (obviously) |
Sets the indexed color shader and any required uniforms and texture samplers. palette_sprite
is the sprite asset that will be used as a palette, and ought to be comprised of one or more horizontal rows of pixels serving as the palette.
An example color palette.
You can store multiple palettes in a single image, and choose which palette to use with the palette_index
argument. This will default to 0 for the first palette row if none is specified. Choosing a fractional value will interpolate the result between palette rows, and can be used to smoothly transition: lorikeet_set(spr_palette, 0.5)
will yield colors blended 50% between the first and second palette rows, and lorikeet_set(spr_palette, 1.75)
will yield colors blended 75% of the way between the second row and third row.
The subimage
argument should be familiar to anyone who's ever drawn anything in GameMaker before and should be used if you have multiple subimages in the same sprite that you wish to use as palettes.
If you want to use the indexed color shader as part of another shader, you can specify which shader you want to draw with using the last shader
argument. Read farther down for information on how to do that.
Once you have set the shader, anything you draw will be use the grayscale color value (specifically the red channel) as the index to look up a color in the palette. Combined with the palette above, this:
will be rendered as this:
Returns: N/A
Resets the shader and returns to normal drawing. This function is identical to shader_reset()
and the main reason I included it is because I like the symmetry.
The Lorikeet shader itself is extremely fast, and only adds a small amount of code to the default shader. However, setting shader uniforms, and particular palette samplers, via lorikeet_set()
counts as a batch break in the same way that functions such as gpu_set_blendmode()
and matrix_set()
do, and *calling the function with every sprite you draw will incur a heavy penalty on the CPU side. lorikeet_set()
should therefore be treated as any other batch breaking function, which means that code such as this:
lorikeet_set(spr_palette_tree);
with (obj_tree) {
draw_sprite(spr_idx_tree, 0, self.x, self.y);
}
lorikeet_reset();
is vastly more performant than this:
with (obj_tree) {
lorikeet_set(spr_palette_tree);
draw_sprite(spr_idx_tree, 0, self.x, self.y);
lorikeet_reset();
}
due to the way that GameMaker batches and draws things.
Lorikeet's palette swapping shader code can easily be added to other shaders of your own, assuming you have basic knowledge of how shaders work.
Inside the fragment shader part of shd_lorikeet
you'll notice a code region labeled Copy everything in this region if you want to bring it into another shader
. As you can probably guess, you want to copy everything in that region into your new shader if you want to be able to use it elsewhere. Ideally it should go to the top of the shader file, because the shader compiler requires functions to be declared before they can be used elsewhere in the code.
Once you've added the 20 or so lines to your shader, you can call the GetLorikeetColor
function on a color value obtained from the texture of the indexed color sprite to get the corresponding color in the palette.
gl_FragColor = GetLorikeetColor(texture2D(gm_BaseTexture, v_vTexcoord));
This should only be done on a color obtained directly from a sampler. Using another color will likely give you a nonsense value which may only be what you're looking for by sheer coincidence, and will most likely look utterly ridiculous. The following is not correct:
gl_FragColor = GetLorikeetColor(v_vColour * texture2D(gm_BaseTexture, v_vTexcoord));
Instead you want to do this:
gl_FragColor = v_vColour * GetLorikeetColor(texture2D(gm_BaseTexture, v_vTexcoord));
You can see several examples of this in use in the demo project, including the water shader and snidr's 3D particle shader.