patterncppMinor
Diagonal gradient optimization
Viewed 0 times
optimizationdiagonalgradient
Problem
With the SDL library, I'm creating an
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* 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:
The result must be calculated as
In your case you should do:
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.
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.