HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Diagonal gradient optimization

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
optimizationdiagonalgradient

Problem

With the SDL library, I'm creating an SDL_Surface* at w and h dimensions.
SDL_Color is a struct with 4 unsigned char fields: a, r, g and b for alpha, red, green and blue. c1 is the origin color, c2 the destination color, and c is the color of the pixel at position (i,j).

That gradient works fine, but it is very basic and I'm just wondering if there is any way to optimize it, whether with a better SDL use or a faster algorithm.

SDL_Surface* DrawDescendingDiagonalGradient(SDL_Color& c1, SDL_Color& c2, int w, int h)    {
    SDL_Color c;
    SDL_Surface *s = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
    SDL_LockSurface(s);
    for (int j = 0; j format, c.r, c.g, c.b, c.a));
        }
    }
    SDL_UnlockSurface(s);
    return s;
}

Solution

In addition to Janos's answer.

You're truncating the color value too early here:


c.a = c1.a (w + h - i - j) / (w + h) + c2.a (i + j) / (w + h);

This results in a rounding error on each channel. Also this forces the compiler to perform two divisions per channel, as it cannot combine the divisions due to truncation rules of integer types.

For example:

int a = 1;
int b = 2;
int c = 3;

int result = a / c + b / c;


The result must be calculated as (a/c) + (b/c)=0 if optimized to (a+b)/c=1 the result will differ. And in your case you actually want (a+b)/c as the correct answer.

In your case you should do:

SDL_Surface* DrawDescendingDiagonalGradient(SDL_Color& c1, SDL_Color& c2, int w, int h){
    SDL_Color c;
    SDL_Surface *s = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
    SDL_LockSurface(s);
    int wh = w + h;
    for (int j = 0; j format, c.r, c.g, c.b, c.a));
        }
    }
    SDL_UnlockSurface(s);
    return s;
}


This will make sure you get the correct rounding and remove one division per channel. Also when running the code un-optimized (while debugging) this should perform slightly better due to elimination of some subexpressions.

Code Snippets

int a = 1;
int b = 2;
int c = 3;

int result = a / c + b / c;
SDL_Surface* DrawDescendingDiagonalGradient(SDL_Color& c1, SDL_Color& c2, int w, int h){
    SDL_Color c;
    SDL_Surface *s = SDL_CreateRGBSurface(0, w, h, 32, 0, 0, 0, 0);
    SDL_LockSurface(s);
    int wh = w + h;
    for (int j = 0; j < h; j++) {
        for (int i = 0; i < w; i++) {
            int ij = i + j;
            c.a = (c1.a * (wh - ij) + c2.a * ij) / wh;
            c.r = (c1.r * (wh - ij) + c2.r * ij) / wh;
            c.g = (c1.g * (wh - ij) + c2.g * ij) / wh;
            c.b = (c1.b * (wh - ij) + c2.b * ij) / wh;
            PutPixel32(s, i, j, SDL_MapRGBA(s->format, c.r, c.g, c.b, c.a));
        }
    }
    SDL_UnlockSurface(s);
    return s;
}

Context

StackExchange Code Review Q#60503, answer score: 4

Revisions (0)

No revisions yet.