Fixed bug 3311 - Broken touch positions with SDL_RenderSetLogicalSize & HIGHDPI on iOS

Eric wing

Hi, I think I found a bug when using SDL_WINDOW_ALLOW_HIGHDPI with SDL_RenderSetLogicalSize on iOS. I use SDL_RenderSetLogicalSize for all my stuff. I just tried turning on SDL_WINDOW_ALLOW_HIGHDPI on iOS and suddenly all my touch/mouse positions are really broken/far-off-the-mark.

I actually don't have a real retina device (still) so I'm seeing this using the iOS simulator with a 6plus template.

Attached is a simple test program that can reproduce the problem. It uses RenderSetLogicalSize and draws some moving happy faces (to show the boundaries/space of the LogicalSize and that it is working correctly for that part).

When you click/touch, it will draw one more happy face where your button point is.

If you comment out SDL_WINDOW_ALLOW_HIGHDPI, everything works as expected. But if you compile with it in, the mouse coordinates seem really far off the mark. (Face appears far up and to the left.)


Alex Szpakowski on the mailing list suggests the problem is
"I believe this is a bug in SDL_Render?s platform-agnostic mouse coordinate scaling code. It assumes the units of the mouse coordinates are always in pixels, which isn?t the case where high-DPI is involved (regardless of whether iOS is used) ? they?re actually in ?DPI independent? coordinates (which matches the window size, but not the renderer output size)."

Additionally, if this is correct, the Mac under Retina is also probably affected too and "as well as any other platform SDL adds high-dpi support for in the future".
Sam Lantinga 2017-08-02 13:38:46 -07:00
parent 082f32d198
commit 9dbe5a9686
2 changed files with 27 additions and 12 deletions

View File

@ -168,29 +168,29 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
} else if (event->type == SDL_MOUSEMOTION) { } else if (event->type == SDL_MOUSEMOTION) {
SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID);
if (renderer->logical_w && window == renderer->window) { if (renderer->logical_w && window == renderer->window) {
event->motion.x -= renderer->viewport.x; event->motion.x -= (renderer->viewport.x * renderer->dpi_scale.x);
event->motion.y -= renderer->viewport.y; event->motion.y -= (renderer->viewport.y * renderer->dpi_scale.y);
event->motion.x = (int)(event->motion.x / renderer->scale.x); event->motion.x = (int)(event->motion.x / (renderer->scale.x * renderer->dpi_scale.x));
event->motion.y = (int)(event->motion.y / renderer->scale.y); event->motion.y = (int)(event->motion.y / (renderer->scale.y * renderer->dpi_scale.y));
if (event->motion.xrel > 0) { if (event->motion.xrel > 0) {
event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / renderer->scale.x)); event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (renderer->scale.x * renderer->dpi_scale.x)));
} else if (event->motion.xrel < 0) { } else if (event->motion.xrel < 0) {
event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / renderer->scale.x)); event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (renderer->scale.x * renderer->dpi_scale.x)));
} }
if (event->motion.yrel > 0) { if (event->motion.yrel > 0) {
event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / renderer->scale.y)); event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (renderer->scale.y * renderer->dpi_scale.y)));
} else if (event->motion.yrel < 0) { } else if (event->motion.yrel < 0) {
event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / renderer->scale.y)); event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (renderer->scale.y * renderer->dpi_scale.y)));
} }
} }
} else if (event->type == SDL_MOUSEBUTTONDOWN || } else if (event->type == SDL_MOUSEBUTTONDOWN ||
event->type == SDL_MOUSEBUTTONUP) { event->type == SDL_MOUSEBUTTONUP) {
SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); SDL_Window *window = SDL_GetWindowFromID(event->button.windowID);
if (renderer->logical_w && window == renderer->window) { if (renderer->logical_w && window == renderer->window) {
event->button.x -= renderer->viewport.x; event->motion.x -= (renderer->viewport.x * renderer->dpi_scale.x);
event->button.y -= renderer->viewport.y; event->motion.y -= (renderer->viewport.y * renderer->dpi_scale.y);
event->button.x = (int)(event->button.x / renderer->scale.x); event->motion.x = (int)(event->motion.x / (renderer->scale.x * renderer->dpi_scale.x));
event->button.y = (int)(event->button.y / renderer->scale.y); event->motion.y = (int)(event->motion.y / (renderer->scale.y * renderer->dpi_scale.y));
} }
} }
return 0; return 0;
@ -289,6 +289,18 @@ SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
renderer->window = window; renderer->window = window;
renderer->scale.x = 1.0f; renderer->scale.x = 1.0f;
renderer->scale.y = 1.0f; renderer->scale.y = 1.0f;
renderer->dpi_scale.x = 1.0f;
renderer->dpi_scale.y = 1.0f;
if (window && renderer->GetOutputSize) {
int window_w, window_h;
int output_w, output_h;
if (renderer->GetOutputSize(renderer, &output_w, &output_h) == 0) {
SDL_GetWindowSize(renderer->window, &window_w, &window_h);
renderer->dpi_scale.x = (float)window_w / output_w;
renderer->dpi_scale.y = (float)window_h / output_h;
}
}
if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) { if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) {
renderer->hidden = SDL_TRUE; renderer->hidden = SDL_TRUE;

View File

@ -154,6 +154,9 @@ struct SDL_Renderer
SDL_FPoint scale; SDL_FPoint scale;
SDL_FPoint scale_backup; SDL_FPoint scale_backup;
/* The pixel to point coordinate scale */
SDL_FPoint dpi_scale;
/* The list of textures */ /* The list of textures */
SDL_Texture *textures; SDL_Texture *textures;
SDL_Texture *target; SDL_Texture *target;