3. Overview of Color Blend

Blending is still fundamentally a linear interpolation between between to RGB colors. But, these colors need to be normalized and converted to linear RGB values.

Monolith encodes color as a pretty standard 32-bit RGBA color, each channel being 8-bits, or a value between 0 and 255. The process of normalizing is dividing each 8-bit Red, Green, and Blue component by 255 to get them in range 0 and 1.

<<normalize_colors>>=
c0_n[0] = c0.r * oned255;
c0_n[1] = c0.g * oned255;
c0_n[2] = c0.b * oned255;
c1_n[0] = c1.r * oned255;
c1_n[1] = c1.g * oned255;
c1_n[2] = c1.b * oned255;

Once they have been normalized, the RGB components can be converted in to linear values. This is done by undoing the gamma non-linearity added.

<<ungamma_stuff>>=
c0_n[0] = ungammait(c0_n[0]);
c0_n[1] = ungammait(c0_n[1]);
c0_n[2] = ungammait(c0_n[2]);
c1_n[0] = ungammait(c1_n[0]);
c1_n[1] = ungammait(c1_n[1]);
c1_n[2] = ungammait(c1_n[2]);

The function that inverts the gamma function ungammait, is defined below.

This mathematical process was adopted from the equation found on the Wikipedia Page on sRGB. This un-gamma-fying processing is applied to each channel.

(This gamma nonlinearity is a process I do not fully understand. It's full of magic numbers of which I do not know how they were derived.)

<<gammafuncs>>=
/* gets normalized sRGB to linear RGB */
static float ungammait(float u)
{
    float y;
    y = 0;

    if (u <= 0.04045) {
        y = u / 12.92;
    } else {
        y = pow((u + 0.055)/1.055, 2.4);
    }

    return y;
}

Linear interpolation between the colors can now finally happen. For those more included to music production, think of it as a cross-fade.

<<lerpit>>=
out_n[0] = (1 - a) * c0_n[0] + a * c1_n[0];
out_n[1] = (1 - a) * c0_n[1] + a * c1_n[1];
out_n[2] = (1 - a) * c0_n[2] + a * c1_n[2];

The new interpolated color needs to get returned to sRGB color space. First the color needs to get gamma-fied; the gamma non-linearity that was previously removed gets re-introduced again. Then, each component is properly scaled and truncated to be an 8-bit value.

<<regamma_stuff>>=
out_n[0] = gammait(out_n[0]);
out_n[1] = gammait(out_n[1]);
out_n[2] = gammait(out_n[2]);

Applying the gamma function for each RGB channel brings it back to normalize sRGB space.

<<gammafuncs>>=
static float gammait(float u)
{
    float y;
    y = 0;

    if (u <= 0.0031308) {
        y = u * 12.92;
    } else {
        y = pow(u, 1.0/2.4) * 1.055 - 0.055;
    }

    return y;
}

The final step involves storing this in the output color' point. Check for null values first!

<<scale_and_store>>=
if (out != NULL) {
    out->r = floor(out_n[0] * 255);
    out->g = floor(out_n[1] * 255);
    out->b = floor(out_n[2] * 255);
}

And that's it!



prev | home | next