From a9275f2555d28fe6fd0fe4224d9157332d2b69b4 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 draw elements having a size independant of the device frame. --- app/src/input_manager.c | 51 +++++++++++++---------------------------- app/src/screen.c | 51 ++++++++++++++++++++++++++++++----------- app/src/screen.h | 18 ++++++++++++--- 3 files changed, 68 insertions(+), 52 deletions(-) diff --git a/app/src/input_manager.c b/app/src/input_manager.c index fe891990..36f7f202 100644 --- a/app/src/input_manager.c +++ b/app/src/input_manager.c @@ -7,33 +7,6 @@ #include "lock_util.h" #include "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; @@ -407,8 +380,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); @@ -444,12 +417,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; @@ -484,8 +459,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)); @@ -537,9 +512,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 f90863dd..1b637ad7 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -122,6 +122,32 @@ get_initial_optimal_size(struct size frame_size) { return get_optimal_size(frame_size, frame_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; @@ -170,13 +196,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); @@ -220,12 +239,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); @@ -271,6 +284,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); @@ -280,13 +294,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); } @@ -332,3 +347,11 @@ screen_resize_to_pixel_perfect(struct screen *screen) { LOGD("Resized to pixel-perfect"); } } + +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 fed84ece..43bbbbf5 100644 --- a/app/src/screen.h +++ b/app/src/screen.h @@ -17,6 +17,7 @@ struct screen { struct size frame_size; //used only in fullscreen mode to know the windowed window size struct size windowed_window_size; + struct SDL_Rect rect; bool has_frame; bool fullscreen; bool no_window; @@ -34,9 +35,15 @@ struct screen { .width = 0, \ .height = 0, \ }, \ - .has_frame = false, \ - .fullscreen = false, \ - .no_window = false, \ + .rect = { \ + .x = 0, \ + .y = 0, \ + .w = 0, \ + .h = 0, \ + }, \ + .has_frame = false, \ + .fullscreen = false, \ + .no_window = false, \ } // initialize default values @@ -80,4 +87,9 @@ screen_resize_to_fit(struct screen *screen); void screen_resize_to_pixel_perfect(struct screen *screen); +// 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