Palette Basics - AlbertGBarber/PixelSpork GitHub Wiki

Jump to:

Palettes Overview:

A Pixel Spork Palette is a struct that stores an array of FastLED colors and the array's length. They are commonly used as the source of colors for effects. For instance, if we had a Palette containing red, green, and blue, any effects using the Palette would use red, green, and blue for their colors.

For example, to define a palette using red, green, and blue for colors you would:

CRGB rgbPal_arr[] = { CRGB::Red, CRGB::Green, CRGB::Blue }; //create an array of CRGB colors
palettePS rgbPalette = { rgbPal_arr, SIZE(rgbPal_arr) }; //Create the palette using the CRGB array and the array's length

The first line above defines an array of CRGB colors, storing red, green, blue. The second line creates our palette, named rgbPalette, using the CRGB array and the array's length, 3.

The palette's length is stored in its length (uint8_t) variable, ie rgbPalette.length is 3. The color array is stored in the paletteArr variable. Note that it is a pointer (see "Advanced Stuff" below).

Note that we are using the SIZE() macro to automatically set the array length.

As you can see, defining palettes is pretty easy, just stuff some colors in an array and you're ready to go. Palettes can store up to 255 colors, but I recommend staying between 2-5 colors, which seems to work well with most effects.

Note that PixelSpork palettes are not the same as FastLED palettes. I found FastLED palettes to be a bit tricky to define and work with, so I opted to create my own. It should be fairly straight forward to translate a FastLED palette to PixelSpork; for any gradient palette, pick the "main" colors, and use them in the PixelSpork palette. For example, if you had a FastLED palette that was a gradient from orange to purple, you would create a PixelSpork palette using the orange and purple end colors. You can always tweak the palette by adding more mid-gradient colors. In PixelSpork, color gradients are controlled by effects themselves, or are managed by one of the palette utility classes.

Manipulating Palettes:

Palette Functions:

In general you don't change palettes directly, rather you use helper functions or utility classes to manage them. A list of helper functions is available here. As an example, we will swap the first and last colors in the rgbPalette above:

//Below we will swap the the first and last colors in rgbPalette 
CRGB firstColor = paletteUtils::getPaletteColor( rgbPalette, 0 ); //Get the first color from the palette, and store it in firstColor
CRGB lastColor = paletteUtils::getPaletteColor( rgbPalette, rgbPalette.length - 1) ; //Get the last color from the palette, and store it in lastColor
   
paletteUtils::setColor( rgbPalette, firstColor, rgbPalette.length - 1 ); //Store the firstColor in at the end of the palette
paletteUtils::setColor( rgbPalette, lastColor, 0 ); //Store the lastColor in at the start of the palette

The first two lines use the palette helper function namespace, paletteUtilsPS, to store the colors at the start and end of the palette in firstColor and lastColor by using the getPaletteColor() helper function. This function takes a palette and an index (uint8_t) as an argument. The index is the position in the palette's array that we want the color from. In this case 0 (the first index) and rgbPalette.length - 1 (2) (the last index).

The next two lines, use the setColor() helper function to set the colors at the first and last index of rgbPalette. It works much the same way as getPaletteColor(), taking the palette, the color we want to set, and the index that we want to set it at as arguments.

A full list of helper functions is available here, however a lot of common palette tasks can be automated using palette utility functions, as explained below.

Palette Utilities:

To create palettes that blend or change over time you'll want to use a palette utility class. These are explained in more detail here, including examples.

The current list of palette utilities includes:

  • Palette Blender -- Produces a palette that blends from one palette to another over time. Has additional options for looping and randomizing the palettes.

  • Palette Cycle -- Similar to Palette Blender, but takes a list of palettes and cycles though them.

  • Palette Single Cycle -- Takes a single palette and shifts the colors over time, ie a palette of {red, green, blue} would shift to {blue, red, green}, each color is shifted forward by one. Lots of different options for shifting, adding random colors, etc.

  • Palette Slider -- Produces a palette that is a shifting subset of an original palette. For example, using a palette of {red, green, blue, yellow}, we could produce a palette that starts as {red, green}, then shifts to {green, blue}, then to {blue, yellow}, etc. Several different options for shifting.

  • Palette Noise -- Produces a palette where the colors vary using FastLED Perlin noise, centered around a central hue. Allows easy creation of "theme" or "mood" palette, for example a green-based forest palette, or blue/teal ocean palette.

These are also listed in the slide-bar on the right-hand side of this wiki page via palettes -> palette utility classes.

Using Palettes:

If an effect uses a palette, it will probably be required in its constructor. In most effects, the effect's palette is a pointer, which is tied to the palette you provide in the constructor. This is covered in more detail here. To change an effect's palette you would:

yourEffect.palette = &yourNewPalette; 

This changes the effect's palette address to be yourNewPalette. For some effects, you may need to use one of the effect's functions to change the palette. This should be specified in the effect's documentation.

Note that because effects point to a palette, changing the original palette will also change it for the effect. For example if we changed the last color in the rgbPalette to red, this would also change it for any effects using rgbPalette. This is also true for the original color array: if you change the last color in the rgbPal_arr above, it will also be changed for the palette itself.

Advanced Stuff:

  • The palette get and set functions (in the paletteUtilsPS namespace) prevent you from reading off the end of a palette by wrapping. For example if we try to get the third color from a palette with two colors by calling paletteUtilsPS::getPaletteColor(yourPalette, 2), we will get the first (0th index) color instead. The "2" index is wrapped back round to 0 via inputIndex % paletteLength. This helps prevent program crashes, and makes working with palettes a little more flexible.

  • The color array is tied to the palette using a pointer, paletteArr, whose address is set to the color array's when the palette is created. This means that any changes to the original color array will be reflected in the palette (the palette's color array and the original color array being one and the same).

  • Because a palette's length is defined manually, a trick you can do is set the length to a smaller value than the actual color array. The palette will act as a smaller palette, but you can increase its length at any time and "reveal" more colors. However, most effects don't expect the palette length to change, so it may cause bugs.

Palette Sets:

A paletteSetPS is a struct for storing an array of palette pointers. A set contains a pointer to an array of palette addresses and the length of the array (number of palettes). The struct's structure is very similar to a palette itself, having both an array, paletteArr, and a length, but instead of storing colors, the array stores whole palettes (via pointers). This struct is mainly used for the palette cycle utility class.

Having a pointer to an array of addresses may sound complicated, but in practice, defining a palette set is fairly straight-forward, as shown in the example below:

Example declaration:

//(assuming you've already created palette 1 and 2, etc)
palettePS *paletteArr[] = { &palette1, &palette2, etc}; //Create an array of palette pointers (using the address of palettes you've already created)
paletteSetPS paletteSet = {paletteArr, SIZE(paletteArr), SIZE(paletteArr)}; //Create the PaletteSetPS struct, named "paletteSet"
//The second SIZE() is used to record the maximum size of the palette array for memory management.
//It should always be the same as the actual size of the array. 

Note that the above definition includes a second SIZE(paletteArr) argument. This sets the maximum length of the palette set (maxLength), and is used for memory management. You should always use the same value as you use for the palette length. The palette array's memory is handled internally. You should never touch maxLength unless you are certain you know what you are doing. You can read more about memory management here.

Set Functions:

Note, the Palette Utils namespace contains some additional palette set helper functions (currently only the shuffleSet() function).

  • palettePS *getPalette(uint8_t index);
    

    Returns a pointer to the palette at the index in the set's palette array. Most effects use palette pointers, so returning a pointer is more useful than returning the palette itself.

    Example:

    palettePS *palettePtr = yourPaletteSet.getPalette(0);
    

    The line above sets palettePtr's address to the first (0th index) palette in the set. You could then use the palette in an effect (assuming the effect uses a palette) via:

    yourEffect.palette = palettePtr;
    
  • void setPalette(palettePS &palette, uint8_t index);
    

    Replaces the palette at the index by changing the array's palette pointer (wraps so you always add the palette somewhere). In other words, it replaces the pointer in the set's palette array with the new palette pointer.

    Example:

    yourPaletteSet.setPalette(yourPalette, 0);
    

    The line above sets the first (0th) palette in the set to be yourPalette.

  • void setPaletteByCopy(palettePS &palette, uint8_t index);
    

    Replaces the palette at the index by copying from the input palette (wraps so you always add the palette somewhere). Unlike the setPalette() function, this replaces the index palette's palette color array and length with that of the input palette's. This is handy if you have a temporary palette you want to place in the set.