Hello list!
I have bumped into a very annoying issue. It’s weird, so I’d love to
hear what you have to say.
SDL_RenderCopy clips dstrect against the viewport. Then it adjusts the
srcrect by “appropriate” amount of pixels. This amount is actually
wrong, quite a lot, because of the rounding errors introduced in the “*
factor / factor” scale.
real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
For example:
I have a 32 x 32 srcrect and a 64 x 64 dstrect. So far the
stretching is done perfectly, by a factor of 2.
Now, consider dstrect being clipped against the viewport, so it becomes
56 x 64. Now, the factor becomes 1.75 ! The adjustment to "srcrect"
can’t handle this, cause srcrect is in integers.
And thus we now have incorrect mapping, with dstrect not being in the
right proportion to srcrect.
The problem is most evident when upscaling stuff, like displaying a 8x8
texture with a zoom of 64 or more, and moving it beyond the corners of
the screen. It looks really really bad.
-
Do we really need to clip dstrect against viewport? In OpenGL, I just
drew stuff and the viewport itself did the clipping for me. Avoided
the whole mess of uv/uw-screen mapping. Is it considered non-optimal? -
If the clipping is needed for some specific / weird renderers that
can’t handle this, would it be possible to move it to the renderers
in question, and leave the RenderCopy unclipped?
Not filling a bug report, as I’m feeling I’m missing something obvious
here.
Simple program to showcase the behavior:
/* gcc sdl2-config --cflags
-o rect sdl2-config --libs
rect.c
&& ./rect */ #include <SDL.h>
/* Create a 8x1 texture with 8 pixels of different color */
SDL_Texture *create_pattern(SDL_Renderer *renderer) {
SDL_Texture ret; int i;
//create 8x1 32bit surface
SDL_Surface surf = SDL_CreateRGBSurface(0,8,1,32,0,0,0,0);
//fill with 8 colors
for (i = 0; i < 8; i++) {
SDL_Rect target;
target.w = target.h = 1;
target.y = 0; target.x = i;
SDL_FillRect(surf, &target,
SDL_MapRGB(surf->format, rand()%255, rand()%255,
rand()%255)); }
//create a texture from it
ret = SDL_CreateTextureFromSurface(renderer, surf);
SDL_FreeSurface(surf);
return ret;
}
#define ZOOM 32
int main(int argc, char argv[]) {
SDL_Window window;
SDL_Renderer *renderer;
SDL_Texture *pattern;
SDL_Rect dstrect = { 0, 0, 8 * ZOOM, 1 * ZOOM };
int done = 0;
int x = ZOOM;
int dx = -1;
SDL_Init(SDL_INIT_VIDEO);
SDL_CreateWindowAndRenderer(320, 240, SDL_WINDOW_SHOWN,
&window, &renderer);
pattern = create_pattern(renderer); //create our texture
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
while (!done) {
SDL_Event event;
SDL_zero(event);
while (SDL_PollEvent(&event))
if (event.type == SDL_QUIT) done = 1;
SDL_RenderClear(renderer);
dstrect.x = x;
dstrect.y = 0;
//render this texture at x, 0
SDL_RenderCopy(renderer, pattern, NULL, &dstrect);
SDL_RenderPresent(renderer);
SDL_Delay(100);
//move x back and forth
x += dx;
if (x < -1 * ZOOM) dx = 1;
else if (x > 320 - 7 * ZOOM) dx = -1;
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}–
driedfruit