render: fixes to how we convert touch events for logical scaling. We now handle HiDPI correctly, and touches are clamped to the viewport. So if you are rendering to a logical 640x480 in a 720p window, and touch the letterboxing at point (640,700), it will report the touch at (0.5,1.0) instead of outside the documented range.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index b506556..71604bc 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -688,40 +688,60 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
event->button.x = (int)(event->button.x / (scale.x * renderer->dpi_scale.x));
event->button.y = (int)(event->button.y / (scale.y * renderer->dpi_scale.y));
}
- }
+ }
} else if (event->type == SDL_FINGERDOWN ||
event->type == SDL_FINGERUP ||
event->type == SDL_FINGERMOTION) {
int logical_w, logical_h;
+ float physical_w, physical_h;
SDL_Rect viewport;
SDL_FPoint scale;
GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale);
- if (logical_w) {
- int w, h;
- if (renderer->GetOutputSize) {
- renderer->GetOutputSize(renderer, &w, &h);
- } else {
- SDL_GetWindowSize(renderer->window, &w, &h);
- }
+ /* !!! FIXME: we probably should drop events that are outside of the
+ !!! FIXME: viewport, but we can't do that from an event watcher,
+ !!! FIXME: and we would have to track if a touch happened outside
+ !!! FIXME: the viewport and then slid into it to insert extra
+ !!! FIXME: events, which is a mess, so for now we just clamp these
+ !!! FIXME: events to the edge. */
- event->tfinger.x *= (w - 1);
- event->tfinger.y *= (h - 1);
-
- event->tfinger.x -= (viewport.x * renderer->dpi_scale.x);
- event->tfinger.y -= (viewport.y * renderer->dpi_scale.y);
- event->tfinger.x = (event->tfinger.x / (scale.x * renderer->dpi_scale.x));
- event->tfinger.y = (event->tfinger.y / (scale.y * renderer->dpi_scale.y));
+ if (renderer->GetOutputSize) {
+ int w, h;
+ renderer->GetOutputSize(renderer, &w, &h);
+ physical_w = (float) w;
+ physical_h = (float) h;
+ } else {
+ int w, h;
+ SDL_GetWindowSize(renderer->window, &w, &h);
+ physical_w = ((float) w) * renderer->dpi_scale.x;
+ physical_h = ((float) h) * renderer->dpi_scale.y;
+ }
- if (logical_w > 1) {
- event->tfinger.x = event->tfinger.x / (logical_w - 1);
+ if (physical_w == 0.0f) { /* nowhere for the touch to go, avoid division by zero and put it dead center. */
+ event->tfinger.x = 0.5f;
+ } else {
+ const float normalized_viewport_x = ((float) viewport.x) / physical_w;
+ const float normalized_viewport_w = ((float) viewport.w) / physical_w;
+ if (event->tfinger.x <= normalized_viewport_x) {
+ event->tfinger.x = 0.0f; /* to the left of the viewport, clamp to the edge. */
+ } else if (event->tfinger.x >= (normalized_viewport_x + normalized_viewport_w)) {
+ event->tfinger.x = 1.0f; /* to the right of the viewport, clamp to the edge. */
} else {
- event->tfinger.x = 0.5f;
+ event->tfinger.x = (event->tfinger.x - normalized_viewport_x) / normalized_viewport_w;
}
- if (logical_h > 1) {
- event->tfinger.y = event->tfinger.y / (logical_h - 1);
+ }
+
+ if (physical_h == 0.0f) { /* nowhere for the touch to go, avoid division by zero and put it dead center. */
+ event->tfinger.y = 0.5f;
+ } else {
+ const float normalized_viewport_y = ((float) viewport.y) / physical_h;
+ const float normalized_viewport_h = ((float) viewport.h) / physical_h;
+ if (event->tfinger.y <= normalized_viewport_y) {
+ event->tfinger.y = 0.0f; /* to the left of the viewport, clamp to the edge. */
+ } else if (event->tfinger.y >= (normalized_viewport_y + normalized_viewport_h)) {
+ event->tfinger.y = 1.0f; /* to the right of the viewport, clamp to the edge. */
} else {
- event->tfinger.y = 0.5f;
+ event->tfinger.y = (event->tfinger.y - normalized_viewport_y) / normalized_viewport_h;
}
}
}