Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fill array dynamicly with gradient color c++

what I'm trying to do is fill an array with an rainbow gradient. The array should hold 256 entries an filled with the hex value of colors.

rainbow

like:

array[0] = 0xFF0000 //red
...
array[85] = 0xFFA200 //orange
...
array[170] = 0x00AF0F //green
...
array[255] = 0xAE00FF //purple

because I do not want to assign all 256 colors "by hand" to the array I'm looking for an dynamicly approach for that. It's not necessarily need to be the ranbow displayed above. The picture is just for demonstration purpose.

Any suggestions how to do things like this in an (preferably) short code snipit avoiding a couple of nested for loops?

like image 369
flor1an Avatar asked Dec 18 '22 11:12

flor1an


2 Answers

We want to go from:

red -> yellow
yellow -> green
green -> cyan
cyan -> blue
blue -> magenta
magenta -> red

In each pass, one of the red, green, blue components is always 0, the second is 255, and the third is increasing or decreasing between 0 and 255.

In other words:

{255,  0,    0} -> {255, 255,   0} grn increases to 255
{255, 255,   0} -> {  0, 255,   0} red decreases to 0
{0  , 255,   0} -> {  0, 255, 255} blu increases to 255
{0  , 255, 255} -> {  0,   0, 255} grn decreases to 0
{0  ,   0, 255} -> {255,   0, 255} red increases to 255
{255,   0, 255} -> {255,   0,   0} blu decreases to 0

This produces 256 * 6 colors, we may not want all of those colors, so it has to be normalized. This can be done with following code:

//input: ratio is between 0.0 to 1.0
//output: rgb color
uint32_t rgb(double ratio)
{
    //we want to normalize ratio so that it fits in to 6 regions
    //where each region is 256 units long
    int normalized = int(ratio * 256 * 6);

    //find the region for this position
    int region = normalized / 256;

    //find the distance to the start of the closest region
    int x = normalized % 256;

    uint8_t r = 0, g = 0, b = 0;
    switch (region)
    {
    case 0: r = 255; g = 0;   b = 0;   g += x; break;
    case 1: r = 255; g = 255; b = 0;   r -= x; break;
    case 2: r = 0;   g = 255; b = 0;   b += x; break;
    case 3: r = 0;   g = 255; b = 255; g -= x; break;
    case 4: r = 0;   g = 0;   b = 255; r += x; break;
    case 5: r = 255; g = 0;   b = 255; b -= x; break;
    }
    return r + (g << 8) + (b << 16);
}

Usage:

double range = 500.0;
for (double i = 0; i < range; i++)
{
    uint32_t color = rgb(i / range);
    ...
}

Output:

enter image description here

like image 133
Barmak Shemirani Avatar answered Dec 24 '22 02:12

Barmak Shemirani


One way to do what you want is to interpolate each of the component colours (RGB) from their starting to their ending value. This means using steps that are of as equal size as possible.

To get the RGB components some bit manipulation is necessary. This code gives you the three component colours for a fully-stated colour fullColour:

std::array<float, 3> colourRGB;

for(unsigned i = 0; i<3; ++i) {
    colourRGB[i] = (fullColour & (0xFF << (i*8))) >> (i*8);

You use this to get the RGB array of your starting and ending colour (for example, for the red-orange range in your example this would be the RGB breakdown of 0xFF0000 and 0xFFA200). For each component you then work out the step size required for each step in your 'fade'. This is given by the total change in that component divided by the total number of steps. For the red-orange example the step size for the Red component would thus be 1.91 (because you have 86 steps and a total change of (0xA2 - 0x00, or 162 in decimal, yielding 162/86=1.91). The step sizes for the other components are zero as they don't change.

You can then iterate over the steps, at each one adding another step size and rounding to get the new value for each component. For example, at step s:

red[s] = startingRed + ((float)s * stepSizeRed)

To re-combine your rgb values back into a full colour, just apply some bit manipulation again:

fullColour[s] = 0;
for(unsigned i=0; i<3; ++i)
    fullColour[s] += rgbComponent[s][i] << (i*8);

This approach yields the required 'fade' from any starting to any ending colour in any number of steps.

like image 24
Smeeheey Avatar answered Dec 24 '22 01:12

Smeeheey