Color Modes Example - AlbertGBarber/PixelSpork GitHub Wiki
In this example we'll go over Color Modes, a special setting in many effects that allows you to substitute a rainbow or custom gradient in place of an effect's normal colors. This page is intended to be paired with the "Color_Modes" library example code. Note that this example builds on the previous examples in the "Starter Guide" at the top of the right-hand wiki sidebar, so I won't be going over anything that's already been covered in a previous example.
In the example, we'll cycle through the rainbow "Color Modes" (1-4), using a Color Mode Fill effect to draw the Color Mode on the whole strip. Once we've cycled through each Color Mode, we'll switch to a Theater Chase effect to show how Color Modes interact with effects. To properly show all the Color Modes, we need a 2D Segment Set. To many sure the example works with any strip, we'll create a Segment Set with 4 "rows" by splitting the strip into 4 equal Segments. To get the best effect, arrange your strip into a matrix with 4 equal rows in a serpentine layout. However, if you already have a 2D layout and Segment Set for your LEDs, I encourage you to use it, as that will probably help you understand more.
Note that to understand each Color Mode, you'll want to have a good understanding of Segment Sets, specifically the difference between Segments and Segment Lines.
Example Cycling through Color Modes for a Strip of 60 LEDs, Split into 4 "Rows" |
(Ignore the first LED color's glitching, this is a visual artifact) |
Example Cycling through Color Modes Using the Theater Chase Effect |
Note: when compiling using the Arduino IDE, if you have your "compiler warnings" (found in "preferences") set to "More" or "All" you may get a few warnings when you first compile a sketch. These should mainly concern the possible non-usage of various static variables, and are expected. They will not prevent the code from running!
Color modes are a special setting included in many effects. They replace the effect's colors with either a rainbow or custom gradient. Allowing you to create rainbow effects with very little extra work.
To set an effect's Color Mode you would:
<yourEffectName>.colorMode = <a Color mode number>;
Color modes are designed to interact directly with 2D Segment Sets, with each mode spreading the rainbow across the Segment Set in a different orientation. So how a rainbow looks, will depend on the effect's Segment Set layout and settings. You can also configure the rainbow/gradient to shift over time, adding an extra bit of spice to your effects (more on that later). All of the math for drawing the rainbow/gradient is done automatically whenever the effect draws, so you simply have to set a Color Mode and the library takes care of the rest.
There are 4 main ways a Color Mode gradient can be displayed:
-
Linearly across all the LEDs in the segment set, so that the rainbow gradient starts at the first LED and ends at the last.
-
Radially, so that each whole segment is a single color from the rainbow gradient.
-
Linearly, but using segment lines, so that each line is a single color.
-
With time (4D?), so that the whole segment set is a single color, but that color cycles through the rainbow over time.
When parsed out into rainbow and custom gradients, this creates 10 unique Color Modes.
To read about all the details of Color Modes, including a list of the mode numbers, see here.
To view most of the Color Modes, we need a 2D Segment Set, ideally with more than 2 Segments. For this example, we'll create a generic Segment Set "matrix" with 4 "rows" by splitting the strip into 4 equal Segments, arranging them in a serpentine layout. If possible, you should arrange your strip into 4 rows to match the Segment Set. Alternatively, if you already have a 2D layout and Segment Set for your LEDs, I encourage you to use it over the generic setup. Not only will the Color Modes look better, but you'll probably get a better understanding of what each Color Mode is doing.
To Create the Segment Set we do:
//Segment 0, starting at LED 0 with length for NUM_LEDS/4
const PROGMEM segmentSecCont sec0[] = { {0, NUM_LEDS / 4} };
SegmentPS segment0 = { sec0, SIZE(sec0), true };
//Segment 1, starting at LED (NUM_LEDS * 1/4) with length for NUM_LEDS/4
const PROGMEM segmentSecCont sec1[] = { {(NUM_LEDS * 1 / 4), NUM_LEDS / 4} };
SegmentPS segment1 = { sec1, SIZE(sec1), false }; //reversed direction for serpentine layout
//Segment 2, starting at LED (NUM_LEDS * 2/4) with length for NUM_LEDS/4
const PROGMEM segmentSecCont sec2[] = { {(NUM_LEDS * 2 / 4), NUM_LEDS / 4} };
SegmentPS segment2 = { sec2, SIZE(sec2), true };
//Segment 3, starting at LED (NUM_LEDS * 3/4) with length for NUM_LEDS/4
const PROGMEM segmentSecCont sec3[] = { {(NUM_LEDS * 3 / 4), NUM_LEDS / 4} };
SegmentPS segment3 = { sec3, SIZE(sec3), false }; //reversed direction for serpentine layout
//Create the segment set using the quarter segments above
SegmentPS *quatSegs_arr[] = { &segment0, &segment1, &segment2, &segment3 };
SegmentSetPS quarterSegs( leds, NUM_LEDS, quatSegs_arr, SIZE(quatSegs_arr) );
The Segment Set above is named "quarterSegs", and is made up of 4 equal length Segments with one section each. To see more on 2D Segment Sets see here or here.
For this example, we'll create two effects; a Color Mode Fill and a Theater Chase.
Color Mode Fill is a simple effect that fills in the Segment Set using a Color Mode. Without any extra adjustment, this just fills in the Set with a static rainbow, but later we'll change some settings to make the rainbow shift over time.
To create the Color Mode Fill, we do:
ColorModeFillPS colorModeFill(quarterSegs, 1, 70);
//Setup a ColorModeFillPS effect using our segment set and starting at Color Mode 1.
//(we'll cycle the color mode later)
Theater Chase is another simple effect that moves bands of color along the Segment Set. It is configured to draw along segment lines, with each line being a solid color.
To create the effect, we do:
TheaterChaseSL theaterChase(quarterSegs, CRGB::Red, 0, 3, 2, 100);
//Setup a theaterChaseSL effect using red as the running color on a blank background
//(since we're using color modes, the red will be overridden by the color mode)
//The chase will use bands of color of length 3, with 2 spaces in between, updating at 100ms
The code above creates a Theater Chase effect, named theaterChase
. The effect is configured to run on our quarterSegs
Segment Set, using a black background, with color bands of length 3, and 2 spaces in between. The effect updates at 100ms. Note that while we use red as the band color, since we'll be changing the effect's color mode, the band color will be replaced by a rainbow gradient. Also note that the Color Mode is not included in the effect's constructor, so we'll need to set it during runtime. It is rare for an effect to set a Color Mode in the constructor. By default any effects that use Color Modes have the mode set to 0, which draws the effects colors as normal.
So far we have talked about what Color Modes are, but not how to configure them.
How a Color Mode looks depends on a group of settings in each Segment Set, which control how long the rainbow/gradient is, how many gradient steps it has, if the gradient moves over time and how fast, etc.
The length of a gradient is how many Segments, Segment Lines, or LEDs the gradient takes up before it starts repeating. In the Segment Set, the Color Modes and corresponding length settings can be found here. By default the lengths are set so that one full gradient fills the Segments, Segment Lines, or LEDs. We won't change any lengths in this example, but I have left a set of commented length settings at the end of the Arduino setup() function should you want to experiment.
By default, all the Color Mode rainbow/gradients are static (except the "4D" modes: 4, 9, 5, and 10). We can set a gradient to move over time by setting runOffset
to true and change gradient's speed using offsetRateOrig
in the Segment Set.
For this example, we'll do this in the Arduino setup() function:
quarterSegs.runOffset = true; //tell the segment set to shift the color mode gradients over time
quarterSegs.offsetRateOrig = 60; //Set the rate that the gradient shifts at in ms
Note that these settings are tied to our quarterSegs
Segment Set, and so, will be shared between any effects using quarterSegs
. Furthermore, the motion is controlled internally by the library, and is updated whenever any effect draws, so your cycle speed is limited by your effect's speed. To stop the motion, we would set runOffset
to false.
By default, Color Mode gradients have 256 color steps, one step for each color in a FastLED CRGB rainbow. The gradient moves by increasing what step each LED is on. Depending on our cycle rate, this can cause the gradient to move very slowly. Rather than forcing you to run your cycles (and effects) very fast, we can adjust how many color steps are taken each cycle using offsetStep
. In the example code, we set it in the Arduino setup() function:
quarterSegs.offsetStep = 3;
Changing the steps taken does make our gradient more coarse, but in practice it's not noticeable for low offsetStep
values.
The goal for this example is to demo each rainbow Color Mode (1-4) on our quarterSegs
Segment Set using our colorModeFill
effect, and then switch to our theaterChase
effect to show how Color Modes interact with effects. For this, we'll need some variables to track what Color Mode we're on, and how long to stay on each mode:
//we'll use this to track the color mode
uint8_t colorMode = 1;
//Some time tracking variables for switching color modes and effects
unsigned long currentTime;
unsigned long modeSwitchTime = 5000; //how often we switch color modes (ms)
unsigned long effectChangeTime = 4 * modeSwitchTime; //what time we switch from the colorMode fill to theaterChase effect (after color mode 4)
Note that effectChangeTime
sets the time when we swap from the colorModeFill
to theaterChase
effect. We're only doing Color Modes 1-4, so effectChangeTime
is 4 * modeSwitchTime
. Note that you can also disable the theaterChase
effect using the USE_THEATER_CHASE
boolean at the top of the code. When disabled, the colorModeFill
effect will run indefinitely, which may be helpful in understanding the differences between each Color Mode.
Then we can create our loop() code:
void loop() {
//Finally we get to the actual code:
//The code below switches color modes every "modeSwitchTime" ms, telling you which mode we're on and how it draws
EVERY_N_MILLISECONDS(modeSwitchTime) {
//Cycle through the color modes, but skip color mode 0 (since that just displays the effect as normal)
colorMode = (colorMode + 1) % 5;
if(colorMode == 0) { colorMode = 1; }
//Set the color modes for both effects
colorModeFill.colorMode = colorMode;
theaterChase.colorMode = colorMode;
//Output a message about what color mode we're using
switch(colorMode) {
case 1:
Serial.println("Now using color mode 1, the rainbow is spread across all LEDs in the segment set.");
break;
case 2:
Serial.println("Now using color mode 2, the rainbow is spread across all segments in the set.");
break;
case 3:
Serial.println("Now using color mode 3, the rainbow is spread across all segment lines in the set.");
break;
case 4:
Serial.println("Now using color mode 4, the segment set is a single color that cycles through the rainbow.");
break;
}
}
//Draw either the colorModeFill or theaterChase effects
//We start by doing the colorModeFill until we hit effectChangeTime (after we're done each color mode)
//And then we switch to just doing theaterChase forever (if USE_THEATER_CHASE is true).
currentTime = millis();
if(currentTime > effectChangeTime && USE_THEATER_CHASE) {
theaterChase.update();
} else {
colorModeFill.update();
}
}
The code above may look like a lot, but it's not really doing much. The first "block" marked by the EVERY_N_MILLISECONDS(){}
controls what Color Mode we're on, switching after modeSwitchTime
. When we switch, we set the Color Mode for our colorModeFill
and theaterChase
effects, and write out a serial message telling you about the current mode.
The second "block", tracks the total elapsed time. At first, it draws colorModeFill
by updating it, but once we've cycled through each Color Mode once (effectChangeTime
has passed), it swaps to drawing theaterChase
(as long as USE_THEATER_CHASE is true, see the top of the code).
This example explained Color Modes, which allow you to easily add rainbow or custom gradients to your effects. For more on Color Modes, see here.
At this point, we've covered the core mechanics and features of Pixel Spork. In our next example, Cycling Multiple Effects`, I'll show you how to cycle between and control a list of effects.