Main menu

Post navigation

Multicolor Gradients: An Introduction to Working with Palette Effects

Working with color palettes is one of the fundamental aspects of 2D rendering. I’ve gone over the various color depths used in computer graphics in a earlier post on rendering with GDI, however there are a couple of aspects I didn’t directly mention.

Specifically, the biggest advantage in using a color palette is the sizable speed advantage you gain by having a fixed amount of colors that allow for a direct index into the color table that correspond to a range of values generated by your effect.

I’ll have a more in-depth discussion on this topic in a follow-up post; for now let’s take a look at the steps needed to generate a gradient palette with a variable amount of colors, which is needed by a variety of effects, and a brief introduction to working with pointers in C# so that we can display our gradients to the screen in an efficient manner.

Basic Gradient

A simple two color gradient is generated by breaking the start and end colors down into their RGB values, 0-255 for each channel, then for each channel subtract the start color value from the end color value, multiply this by the current step (position) in the gradient, then divide that value by the total number of steps in the gradient (length), then add that total value to its respective channels start value.

Here is a C# routine that will generate a two color gradient with the specified number of steps:

Multicolor Gradient

We can extend this functionality to create a gradient with an arbitrary number of colors by wrapping this simple function in a routine that takes the total number of desired steps (length) of the gradient, then by using the C# ‘params’ keyword our function can accept any amount of colors we desire. The ‘params‘ keyword allows us to pass an object (the type is specified as part of the param declaration) array to a function.

Note: due to the usually static nature of method signatures in C#, as well as any standard calling convention system, to allow for the flexibility of variable arguments the ‘params‘ argument must always be last in your method signature.

This code accomplishes its task by “pinning” the starting address of the in-memory surface array (PixelBuffer) so that its memory is in a locked position, which makes it ineligible for garbage collection or reallocation during the execution of our loop.

Inside the fixed statement we can now calculate the offset of the starting position of each virtual ‘line’ (or row) in the array, by multiplying the stride times the current position (loop counter), this should sound familiar if you’ve read my post on GDI via C#.

Once the address has been calculated, we call upon the .NET Marshal.Copy method to copy the bytes stored in the initialLine variable and iterate them over the entire in-memory surface buffer.

After the pixel buffer has been pre-calculated, each frame we simply need to do a direct “Blt”, or more accurately a simple memory copy, from the buffer surface to the display surface:

Marshal.Copy( PixelBuffer, 0, display.Surface, PixelBuffer.Length );

Sample Application and Examples

The full source code and example applications are included in my Rendering Framework project.