Page 1 of 1

Drawing gradient

Posted: Mon Feb 29, 2016 1:37 pm
by BrightLight
This is not a OSDev-specific question, so I put it in general programming.
How do I draw a gradient? For example in CSS:

Code: Select all

background-image: linear-gradient(#000000,#FFFFFF);
How would I draw this same gradient with a specific width and height? Any algorithms?

Re: Drawing gradient

Posted: Mon Feb 29, 2016 1:55 pm
by Octocontrabass
As the name suggests, a linear gradient is calculated using a linear equation. You can consider the position within the gradient as the X coordinate, and the intensity of the color as the Y coordinate, then solve for a linear equation that describes the intensity of that color component for each location along the gradient. You'll need to solve three times, one for each color component.

I'm intentionally ignoring things like gamma correction and perceptual linearity for the sake of a simple explanation.

Re: Drawing gradient

Posted: Mon Feb 29, 2016 2:08 pm
by shmx
This is very easy. :)

Code: Select all

void DrawGradientRectandgle(int XS, int YS, int XE, int YE, int C1, int C2)
{
    int x, y;
    int r1 = (C1 & 0xFF0000) >> 16;
    int r2 = (C2 & 0xFF0000) >> 16;
    int g1 = (C1 & 0x00FF00) >> 8;
    int g2 = (C2 & 0x00FF00) >> 8;
    int b1 = C1 & 0x0000FF;
    int b2 = C2 & 0x0000FF;
    int h = abs(YE - YS);
    double d_r = (double)(r2 - r1) / h;
    double d_g = (double)(g2 - g1) / h;
    double d_b = (double)(b2 - b1) / h;
    double cur_r = r1, cur_g = g1, cur_b = b1;
    for(y = YS; y <= YE; y++)
    {
        for(x = XS; x <= XE; x++)
            SetPixel(x, y, RGB((int)cur_r, (int)cur_g, (int)cur_b));
        cur_r += d_r;
        cur_g += d_g;
        cur_b += d_b;
    }
}
Note: This is a simple algorithm but not effective.

Re: Drawing gradient

Posted: Mon Feb 29, 2016 2:10 pm
by SpyderTL
Essentially, you are doing a linear interpolation (LERP) on each component of your value. In your case, R/G/B. So each of these components will have a minimum value and a maximum value, and a factor between 0.0 and 1.0 to produce an output value.

If Min = { 0.0, 0.0, 0.0 } and Max = { 1.0, 0.5, 0.25 }, then Lerp(Min, Max, 0.5) will return { 0.5, 0.25, 0.125 }.

Just do that for each pixel, and multiply the result by { 255, 255, 255 } if you want a 24-bit value...

It's possible to do the math using integer only calculations, but it's more involved.

Rectangles (top, bottom, left, right) are easier to calculate than triangles (p1, p2, p3). For triangles, you have to interpolate once per scan line to get the min value, and again to get the max value, then once per pixel between the min and max to interpolate every pixel using the interpolated min and max values. This is essentially how all 3d graphics rendering works.

Re: Drawing gradient

Posted: Tue Mar 01, 2016 6:08 am
by Combuster
Basic fundamentals: Bresenham. Note that instead of it being presented as a line drawing algorithm (give all pairs from x0,y0 to x1,y1), you can use it for any other form of interpolation as well (for example, x0,r0 to x1,r1)

Re: Drawing gradient

Posted: Tue Mar 01, 2016 11:30 am
by BrightLight
Thanks, all, for your explanations!