| Summary: | Don't copy all right and down pixels in SoftwareRenderer with rotate and odd sizes | ||
|---|---|---|---|
| Product: | SDL | Reporter: | Nik <truecat17> |
| Component: | render | Assignee: | Sam Lantinga <slouken> |
| Status: | NEW --- | QA Contact: | Sam Lantinga <slouken> |
| Severity: | normal | ||
| Priority: | P2 | CC: | sezeroz, sylvain.becker |
| Version: | 2.0.8 | ||
| Hardware: | x86_64 | ||
| OS: | Linux | ||
| Attachments: |
patch
test case |
||
your test case is incorrect because your look at the wrong position: not Uint32 color = pixels[y * res->pitch + (W - 1) * 4]; but Uint32 color = pixels[y * (res->pitch / 4) + (W - 1)]; and not Uint32 color = pixels[(H - 1) * res->pitch + x * 4]; but Uint32 color = pixels[(H - 1) * (res->pitch / 4) + x]; And you also need to retrieve the rotated surface by calling: SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_RGBA32, pixels, res->pitch); There is one pixel shift, but as you said, this is because of odd width/height. According to SDL_render.h doc, if you don't provide the center, "rotation will be done around dstrect.w/2, dstrect.h/2).". So I am not sure this is a bug. if you want a perfect 180 rotation, you can use flip flags. >your test case is incorrect because Oops, I made some stupid mistakes in first, sorry >SDL_RenderReadPixels SoftwareRenderer draw directly on surface, is not? In any way, it string is not affects Here is new version of test-code: #include <iostream> #include <SDL2/SDL.h> int main(int, char **) { //odd values: const size_t W = 3; const size_t H = 5; SDL_Surface *orig = SDL_CreateRGBSurfaceWithFormat(0, W, H, 32, SDL_PIXELFORMAT_RGBA32); //any color const Uint32 DEFAULT_COLOR = SDL_MapRGBA(orig->format, 128, 128, 128, 255); Uint32 *pixels = (Uint32*)orig->pixels; for (size_t i = 0; i < W * H; ++i) { pixels[i] = DEFAULT_COLOR; } SDL_Surface *res = SDL_CreateRGBSurfaceWithFormat(0, W, H, 32, SDL_PIXELFORMAT_RGBA32); SDL_Renderer *renderer = SDL_CreateSoftwareRenderer(res); SDL_Texture *origTexture = SDL_CreateTextureFromSurface(renderer, orig); SDL_RenderCopyEx(renderer, origTexture, 0, 0, 180, 0, SDL_FLIP_NONE); pixels = (Uint32*)res->pixels; for (size_t y = 0; y < H; ++y) { for (size_t x = 0; x < W; ++x) { Uint32 color = pixels[y * W + x]; std::cout << (color == DEFAULT_COLOR) << ' '; } std::cout << '\n'; } return 0; } >So I am not sure this is a bug. But it's 100% bug, try rotate surface 1x1 - get pixel with value 0 >if you want a perfect 180 rotation, you can use flip flags. It's workaround, I need rotate to 180 correctly And 90 & 270 rotation incorrectly on odd size too Created attachment 3374 [details]
patch
You're right, no need of SDL_RenderReadPixels.
I can propose this patch that seems working but I haven't tested much outside of the test-case. Please give a try with various rotations to see if it holds.
It fixes useless colorkey error message in SDL_rotate.c. It seems to be working Created attachment 3382 [details] test case careful on if you use head SDL sources, there is an issue with bug #4188 which break rotations 90 using RenderCopyEx. Here's my test case. you can modify angle and also renderer (software,opengl,gles2) with the Hint. And see the output. The output must be the same for all renderers. The patch seems to fix 180 rotation offset, for all renderers (software, opengl, gles2). For 90 rotation, there is still an offset, but it's the same for all 3 renderers. Previously, there were also an offset for 180, the same for all 3 renderers. >The output must be the same for all renderers.
Yes, but it's very strange
If we set dstrect's x = y = 0, why appearance offset?
SDL rotate about center area with width = max(srcrect.w, dstrect.w) and height = max(srcrect.h, dstrect.h)?
Or what?
I don't understand for what need this strange behavior
I agree the offset is strange, but consistent among renderers. You could check on window to see how it behaves. RenderCopyEx rotate and also can stretch. |
#include <iostream> #include <SDL2/SDL.h> int main(int, char **) { //odd values: const size_t W = 3; const size_t H = 5; //any color const Uint32 DEFAULT_COLOR = (128 << 24) + (128 << 16) + (128 << 8) + 255; SDL_Surface *orig = SDL_CreateRGBSurfaceWithFormat(0, W, H, 32, SDL_PIXELFORMAT_RGBA32); Uint32 *pixels = (Uint32*)orig->pixels; for (size_t i = 0; i < W * H; ++i) { pixels[i] = DEFAULT_COLOR; } SDL_Surface *res = SDL_CreateRGBSurfaceWithFormat(0, W, H, 32, SDL_PIXELFORMAT_RGBA32); SDL_Renderer *renderer = SDL_CreateSoftwareRenderer(res); SDL_Texture *origTexture = SDL_CreateTextureFromSurface(renderer, orig); SDL_RenderCopyEx(renderer, origTexture, 0, 0, 180, 0, SDL_FLIP_NONE); pixels = (Uint32*)res->pixels; //all right pixels for (size_t y = 0; y < H; ++y) { Uint32 color = pixels[y * res->pitch + (W - 1) * 4]; if (color != DEFAULT_COLOR) { std::cout << "Error on pixel <" << (W - 1) << ", " << y << ">\n"; } } //and all down pixels for (size_t x = 0; x < W; ++x) { Uint32 color = pixels[(H - 1) * res->pitch + x * 4]; if (color != DEFAULT_COLOR) { std::cout << "Error on pixel <" << x << ", " << (H - 1) << ">\n"; } } return 0; }