Hi,
As promised, I investigated a problem with a 1-pixel postponement
during scaling. I'm not sure you have the time to look at it but I'd
welcome your opinion :)
Example: I scale an image 300%, so the scaling will essentially copy
each source pixel 3x on the destination surface.
The algorithm precomputes an array of pointer jumps ("should I advance
source pointer or not").
It uses the "fixed-point float" technique to store the jump increments
as 65536th units, and >>16 before storing it. When the increment >
65536 there's a jump.
What happens after 3 loops?
step = (int)(65536 / 3) = 21845
1: increment = 21845 (< 65536)
2: increment = 43690 (< 65536)
3: increment = 65535 (still < 65536)
4: increment = 87380 (> 65536) => jump=1 => incr-=65536
So the first pixel will be copied 4x instead of 3x.
I have a game editor that scales a background tile 900% and the
1-pixel shift looks bad, plus it doesn't align with the editor brush
:/
Solution: don't use fixed-point floats and avoid losing precision
- option 1: using doubles
- option 2: adding src->w until it reaches dst->w (SDL_stretch)
I attach 2 versions to fix zoomSurfaceY. If that's good I could work
on zoomSurfaceRGBA too.
(I also remove a small portion of the code that is actually unused)
-- Sylvain
Index: SDL_gfx-2.0.17/SDL_rotozoom.c
===================================================================
--- SDL_gfx-2.0.17.orig/SDL_rotozoom.c 2008-08-02 20:40:10.000000000 +0200
+++ SDL_gfx-2.0.17/SDL_rotozoom.c 2008-08-02 21:13:49.000000000 +0200
@@ -369,15 +369,16 @@
int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
{
- Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+ Uint32 x, y, *sax, *say, *csax, *csay;
+ double sx, sy, csx, csy;
Uint8 *sp, *dp, *csp;
int dgap;
/*
* Variable setup
*/
- sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
- sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
+ sx = 1.0 * src->w / dst->w;
+ sy = 1.0 * src->h / dst->h;
/*
* Allocate memory for row increments
@@ -399,29 +400,18 @@
csax = sax;
for (x = 0; x < dst->w; x++) {
csx += sx;
- *csax = (csx >> 16);
- csx &= 0xffff;
+ *csax = (int) csx;
+ while (csx >= 1)
+ csx -= 1;
csax++;
}
csy = 0;
csay = say;
for (y = 0; y < dst->h; y++) {
csy += sy;
- *csay = (csy >> 16);
- csy &= 0xffff;
- csay++;
- }
-
- csx = 0;
- csax = sax;
- for (x = 0; x < dst->w; x++) {
- csx += (*csax);
- csax++;
- }
- csy = 0;
- csay = say;
- for (y = 0; y < dst->h; y++) {
- csy += (*csay);
+ *csay = (int) csy;
+ while (csy >= 1)
+ csy -= 1;
csay++;
}
Index: SDL_gfx-2.0.17/SDL_rotozoom.c
===================================================================
--- SDL_gfx-2.0.17.orig/SDL_rotozoom.c 2008-08-02 20:40:10.000000000 +0200
+++ SDL_gfx-2.0.17/SDL_rotozoom.c 2008-08-02 22:47:36.000000000 +0200
@@ -369,17 +369,12 @@
int zoomSurfaceY(SDL_Surface * src, SDL_Surface * dst, int flipx, int flipy)
{
- Uint32 x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy;
+ Uint32 x, y, *sax, *say, *csax, *csay;
+ int csx, csy;
Uint8 *sp, *dp, *csp;
int dgap;
/*
- * Variable setup
- */
- sx = (Uint32) (65536.0 * (float) src->w / (float) dst->w);
- sy = (Uint32) (65536.0 * (float) src->h / (float) dst->h);
-
- /*
* Allocate memory for row increments
*/
if ((sax = (Uint32 *) malloc(dst->w * sizeof(Uint32))) == NULL) {
@@ -398,30 +393,23 @@
csx = 0;
csax = sax;
for (x = 0; x < dst->w; x++) {
- csx += sx;
- *csax = (csx >> 16);
- csx &= 0xffff;
- csax++;
- }
- csy = 0;
- csay = say;
- for (y = 0; y < dst->h; y++) {
- csy += sy;
- *csay = (csy >> 16);
- csy &= 0xffff;
- csay++;
- }
-
- csx = 0;
- csax = sax;
- for (x = 0; x < dst->w; x++) {
- csx += (*csax);
+ csx += src->w;
+ *csax = 0;
+ while (csx >= dst->w) {
+ csx -= dst->w;
+ (*csax)++;
+ }
csax++;
}
csy = 0;
csay = say;
for (y = 0; y < dst->h; y++) {
- csy += (*csay);
+ csy += src->h;
+ *csay = 0;
+ while (csy >= dst->h) {
+ csy -= dst->h;
+ (*csay)++;
+ }
csay++;
}