Skip to content
Advertisement

How can I add a colour gradient feature to my bresenham line drawing algorithm?

I’ve found this thread on StackOverflow but my python understanding isn’t that good to properly translate it to C, I’m trying to add that gradient feature to this line drawing algorithm:

#define sign(x) ((x > 0)? 1 : ((x < 0)? -1: 0))

x = x1; 
y = y1;
dx = abs(x2 - x1); 
dy = abs(y2 - y1);
s1 = sign(x2 - x1); 
s2 = sign(y2 - y1);
swap = 0;

if (dy > dx) {
    temp = dx;
    dx = dy;
    dy = temp;
    swap = 1;
}

D = 2*dy - dx;
for (i = 0; i < dx; i++) {
    display_pixel (x, y); 
    while (D >= 0) { 
        D = D - 2*dx;
        if (swap)
            x += s1;
        else
            y += s2;
    } 
    D = D + 2*dy;
    if (swap)
        y += s2;
    else
        x += s1; 
} 

I feel bad for asking such a trivial task but I really can’t understand what is going on on the python side nor how the colours are represented (mine are int(0xttrrggbb))

Advertisement

Answer

Figured it out:

#define GAMMA 0.43

//Returns a linear value in the range [0,1]
//for sRGB input in [0,255].
double ChannelInvCompanding(int c)
{
    double y;

    c = c & 0xFF;
    y = (double) c;
    y = y / 255.0;
    if (c <= 0.04045)
        y = y / 12.92;
    else
        y = pow(((y + 0.055) / 1.055), 2.4);
    return (y);
}

//Convert color from 0..255 to 0..1
//Inverse Srgb Companding for 
//Red, Green, and Blue
double  *InverseSrgbCompanding(int c)
{
    double  *r = malloc(4 * sizeof(double));

    r[0] = (double) get_t(c);
    r[1] = ChannelInvCompanding(get_r(c));
    r[2] = ChannelInvCompanding(get_g(c));
    r[3] = ChannelInvCompanding(get_b(c));

    return (r);
}

//Apply companding to Red, Green, and Blue
double ChannelCompanding(double c)
{
    double x;

    if (c <= 0.0031308)
        x = 12.92 * c; 
    else
        x = (1.055 * pow(c, (1/2.4))) - 0.055;
    return (x);
}

//return new color. Convert 0..1 back into 0..255
//Srgb Companding for Red, Green, and Blue
int SrgbCompanding(double *c)
{
    int t;
    int r;
    int g;
    int b;

    t = (int)c[0];
    r = (int)(ChannelCompanding(c[1]) * 255);
    g = (int)(ChannelCompanding(c[2]) * 255);
    b = (int)(ChannelCompanding(c[3]) * 255);
    free(c);
    return (create_trgb(t, r, g, b));
}

//sums channels
//does not include transperancy
double sumChannels(double *c)
{
    double x = c[1] + c[2] + c[3];
    return (x);
}

//Lerping see
//https://en.wikipedia.org/wiki/Linear_interpolation
//#Programming_language_support
double lerp_int(double c1, double c2, double t)
{
    return (c1 * (1 - t) + c2 * t);
    //return ((1 - t) * c1 + t * c2);
}

double  *lerp(double *c1, double *c2, double t)
{
    double  *r = malloc(4 * sizeof(double));

    //r[1] = ((1 - t) * c1[1] + t * c2[1]);
    //r[2] = ((1 - t) * c1[2] + t * c2[2]);
    //r[3] = ((1 - t) * c1[3] + t * c2[3]);
    r[1] = (c1[1] * (1 - t)) + c2[1] * t;
    r[2] = (c1[2] * (1 - t)) + c2[2] * t;
    r[3] = (c1[3] * (1 - t)) + c2[3] * t;
    return (r);
}

typedef struct s_bresvars {
    int x; 
    int y;
    int dx; 
    int dy;
    int s1; 
    int s2;
    int swap;
    int temp;
    int d;
    int i;
}   t_bresvars;



int sign(int x)
{
    if (x > 0)
        return (1);
    else if (x < 0)
        return (-1);
    else
        return (0);
}


void    bresenhams_alg(int x1, int y1, int x2, int y2, int scolor, int ecolor, t_vars *vars)
{
    double step;
    double *color;
    double intensity;
    double total;
    int temp;
    int d;
    int clr;

    double *color1_lin = InverseSrgbCompanding(scolor);
    double bright1 = pow(sumChannels(c.color1_lin), GAMMA);
    double *color2_lin = InverseSrgbCompanding(ecolor);
    double bright2 = pow(sumChannels(c.color2_lin), GAMMA);

    int x = x1; 
    int y = y1;
    int dx = abs(x2 - x1); 
    int dy = abs(y2 - y1);
    int s1 = sign(x2 - x1); 
    int s2 = sign(y2 - y1);
    int swap = 0;
    int i = 0;
    double step_c = 0;

    if (dy > dx) {
        temp = dx;
        dx = dy;
        dy = temp;
        swap = 1;
    }

    d = 2*dy - dx;
    step = (1.0 / dx);
    while (i < dx)
    {
        step_c += step;
        intensity = pow(lerp_int(bright1, bright2, step), (1 / GAMMA));
        color = lerp(color1_lin, color2_lin, step);
        total = sumChannels(color);
        if (total != 0)
            c[1] = (c[1] * intensity / total);
            c[2] = (c[2] * intensity / total);
            c[3] = (c[3] * intensity / total);
        clr = SrgbCompanding(color);
        pixel_put(x, y, clr); 
        while (v.d >= 0)
        { 
            v.d = v.d - 2 * v.dx;
            if (v.swap)
                v.x += v.s1;
            else
                v.y += v.s2;
        } 
        v.d = v.d + 2 * v.dy;
        if (v.swap)
            v.y += v.s2;
        else
            v.x += v.s1;
        v.i++;
    }
    free(color1_lin);
    free(color2_lin);
}
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement