From 4e12a200649a56fc4fcd5433dad2433ac8225613 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 20 Oct 2019 15:56:47 +0200 Subject: [PATCH] Use the physical size for the renderer Position and scale the frames manually instead of relying on the renderer "logical size". This will allow to handle client rotation properly. --- app/src/input_manager.c | 51 +++++++++++++---------------------------- app/src/screen.c | 51 ++++++++++++++++++++++++++++++----------- app/src/screen.h | 12 ++++++++++ 3 files changed, 65 insertions(+), 49 deletions(-) diff --git a/app/src/input_manager.c b/app/src/input_manager.c index 8c4c230a..30200f33 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -7,33 +7,6 @@ #include "util/lock.h" #include "util/log.h" -// Convert window coordinates (as provided by SDL_GetMouseState() to renderer -// coordinates (as provided in SDL mouse events) -// -// See my question: -// -static void -convert_to_renderer_coordinates(SDL_Renderer *renderer, int *x, int *y) { - SDL_Rect viewport; - float scale_x, scale_y; - SDL_RenderGetViewport(renderer, &viewport); - SDL_RenderGetScale(renderer, &scale_x, &scale_y); - *x = (int) (*x / scale_x) - viewport.x; - *y = (int) (*y / scale_y) - viewport.y; -} - -static struct point -get_mouse_point(struct screen *screen) { - int x; - int y; - SDL_GetMouseState(&x, &y); - convert_to_renderer_coordinates(screen->renderer, &x, &y); - return (struct point) { - .x = x, - .y = y, - }; -} - static const int ACTION_DOWN = 1; static const int ACTION_UP = 1 << 1; @@ -427,8 +400,8 @@ convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen, to->inject_touch_event.action = AMOTION_EVENT_ACTION_MOVE; to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; to->inject_touch_event.position.screen_size = screen->frame_size; - to->inject_touch_event.position.point.x = from->x; - to->inject_touch_event.position.point.y = from->y; + to->inject_touch_event.position.point = + screen_convert_to_frame_coords(screen, from->x, from->y); to->inject_touch_event.pressure = 1.f; to->inject_touch_event.buttons = convert_mouse_buttons(from->state); @@ -464,12 +437,14 @@ convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen, } struct size frame_size = screen->frame_size; + // SDL touch event coordinates are normalized in the range [0; 1] + float x = from->x * frame_size.width; + float y = from->y * frame_size.height; to->inject_touch_event.pointer_id = from->fingerId; to->inject_touch_event.position.screen_size = frame_size; - // SDL touch event coordinates are normalized in the range [0; 1] - to->inject_touch_event.position.point.x = from->x * frame_size.width; - to->inject_touch_event.position.point.y = from->y * frame_size.height; + to->inject_touch_event.position.point = + screen_convert_to_frame_coords(screen, x, y); to->inject_touch_event.pressure = from->pressure; to->inject_touch_event.buttons = 0; return true; @@ -504,8 +479,8 @@ convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen, to->inject_touch_event.pointer_id = POINTER_ID_MOUSE; to->inject_touch_event.position.screen_size = screen->frame_size; - to->inject_touch_event.position.point.x = from->x; - to->inject_touch_event.position.point.y = from->y; + to->inject_touch_event.position.point = + screen_convert_to_frame_coords(screen, from->x, from->y); to->inject_touch_event.pressure = 1.f; to->inject_touch_event.buttons = convert_mouse_buttons(SDL_BUTTON(from->button)); @@ -557,9 +532,15 @@ input_manager_process_mouse_button(struct input_manager *im, static bool convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen, struct control_msg *to) { + + // mouse_x and mouse_y are expressed in pixels relatice to the window + int mouse_x; + int mouse_y; + SDL_GetMouseState(&mouse_x, &mouse_y); + struct position position = { .screen_size = screen->frame_size, - .point = get_mouse_point(screen), + .point = screen_convert_to_frame_coords(screen, mouse_x, mouse_y), }; to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT; diff --git a/app/src/screen.c b/app/src/screen.c index b2df91d4..56c9c725 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -149,6 +149,32 @@ get_initial_optimal_size(struct size frame_size, uint16_t req_width, return window_size; } +static void +update_frame_rect(struct screen *screen) { + int ww; + int wh; + SDL_GL_GetDrawableSize(screen->window, &ww, &wh); + + // 32 bits because we need to multiply two 16 bits values + uint32_t fw = screen->frame_size.width; + uint32_t fh = screen->frame_size.height; + + SDL_Rect *rect = &screen->rect; + + bool keep_width = fw * wh > fh * ww; + if (keep_width) { + rect->x = 0; + rect->w = ww; + rect->h = ww * fh / fw; + rect->y = (wh - rect->h) / 2; + } else { + rect->y = 0; + rect->h = wh; + rect->w = wh * fw / fh; + rect->x = (ww - rect->w) / 2; + } +} + void screen_init(struct screen *screen) { *screen = (struct screen) SCREEN_INITIALIZER; @@ -206,13 +232,6 @@ screen_init_rendering(struct screen *screen, const char *window_title, return false; } - if (SDL_RenderSetLogicalSize(screen->renderer, frame_size.width, - frame_size.height)) { - LOGE("Could not set renderer logical size: %s", SDL_GetError()); - screen_destroy(screen); - return false; - } - SDL_Surface *icon = read_xpm(icon_xpm); if (icon) { SDL_SetWindowIcon(screen->window, icon); @@ -258,12 +277,6 @@ static bool prepare_for_frame(struct screen *screen, struct size new_frame_size) { if (screen->frame_size.width != new_frame_size.width || screen->frame_size.height != new_frame_size.height) { - if (SDL_RenderSetLogicalSize(screen->renderer, new_frame_size.width, - new_frame_size.height)) { - LOGE("Could not set renderer logical size: %s", SDL_GetError()); - return false; - } - // frame dimension changed, destroy texture SDL_DestroyTexture(screen->texture); @@ -309,6 +322,7 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) { mutex_unlock(vb->mutex); return false; } + update_frame_rect(screen); update_texture(screen, frame); mutex_unlock(vb->mutex); @@ -318,13 +332,14 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) { void screen_window_resized(struct screen *screen) { + update_frame_rect(screen); screen_render(screen); } void screen_render(struct screen *screen) { SDL_RenderClear(screen->renderer); - SDL_RenderCopy(screen->renderer, screen->texture, NULL, NULL); + SDL_RenderCopy(screen->renderer, screen->texture, NULL, &screen->rect); SDL_RenderPresent(screen->renderer); } @@ -417,3 +432,11 @@ screen_handle_window_event(struct screen *screen, break; } } + +struct point +screen_convert_to_frame_coords(struct screen *screen, float x, float y) { + struct point out; + out.x = (x - screen->rect.x) * screen->frame_size.width / screen->rect.w; + out.y = (y - screen->rect.y) * screen->frame_size.height / screen->rect.h; + return out; +} diff --git a/app/src/screen.h b/app/src/screen.h index 8fb3d33c..a61c37d3 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -22,6 +22,7 @@ struct screen { // Since we receive the event SIZE_CHANGED before MAXIMIZED, we must be // able to revert the size to its non-maximized value. struct size windowed_window_size_backup; + struct SDL_Rect rect; bool has_frame; bool fullscreen; bool maximized; @@ -44,6 +45,12 @@ struct screen { .width = 0, \ .height = 0, \ }, \ + .rect = { \ + .x = 0, \ + .y = 0, \ + .w = 0, \ + .h = 0, \ + }, \ .has_frame = false, \ .fullscreen = false, \ .maximized = false, \ @@ -98,4 +105,9 @@ screen_resize_to_pixel_perfect(struct screen *screen); void screen_handle_window_event(struct screen *screen, const SDL_WindowEvent *event); +// convert point from window coordinates to frame coordinates +// x and y are expressed in pixels (float to allow partial pixels) +struct point +screen_convert_to_frame_coords(struct screen *screen, float x, float y); + #endif