Compare commits

...

5 Commits

Author SHA1 Message Date
Romain Vimont
a9275f2555 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.
2019-10-20 21:09:30 +02:00
Romain Vimont
c160825854 Handle window resizing in screen
Only the screen knows what to do when the window is resized.

This paves the way to do other actions on window resizing.
2019-10-20 16:21:10 +02:00
Romain Vimont
fd9f41548a Pass screen to mouse event converters
Mouse events coordinates depend on the screen size and location, so the
converter need to access the screen.

The fact that it needs the position or the size is an internal detail,
so pass a pointer to the whole screen structure.
2019-10-20 16:21:10 +02:00
Romain Vimont
56527c0808 Move event conversion to input_manager
Only keep helper functions separated.

This will help to convert coordinates internally when necessary.
2019-10-20 16:09:00 +02:00
Romain Vimont
1315c2b00d Rename "input_manager" variables to "im"
It is used a lot, a short name improves readability.
2019-10-20 16:09:00 +02:00
7 changed files with 215 additions and 199 deletions

View File

@ -5,7 +5,7 @@
#define MAP(FROM, TO) case FROM: *to = TO; return true #define MAP(FROM, TO) case FROM: *to = TO; return true
#define FAIL default: return false #define FAIL default: return false
static bool bool
convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) { convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to) {
switch (from) { switch (from) {
MAP(SDL_KEYDOWN, AKEY_EVENT_ACTION_DOWN); MAP(SDL_KEYDOWN, AKEY_EVENT_ACTION_DOWN);
@ -33,7 +33,7 @@ autocomplete_metastate(enum android_metastate metastate) {
return metastate; return metastate;
} }
static enum android_metastate enum android_metastate
convert_meta_state(SDL_Keymod mod) { convert_meta_state(SDL_Keymod mod) {
enum android_metastate metastate = 0; enum android_metastate metastate = 0;
if (mod & KMOD_LSHIFT) { if (mod & KMOD_LSHIFT) {
@ -74,7 +74,7 @@ convert_meta_state(SDL_Keymod mod) {
return autocomplete_metastate(metastate); return autocomplete_metastate(metastate);
} }
static bool bool
convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) { convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) {
switch (from) { switch (from) {
MAP(SDLK_RETURN, AKEYCODE_ENTER); MAP(SDLK_RETURN, AKEYCODE_ENTER);
@ -128,7 +128,7 @@ convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod) {
} }
} }
static enum android_motionevent_buttons enum android_motionevent_buttons
convert_mouse_buttons(uint32_t state) { convert_mouse_buttons(uint32_t state) {
enum android_motionevent_buttons buttons = 0; enum android_motionevent_buttons buttons = 0;
if (state & SDL_BUTTON_LMASK) { if (state & SDL_BUTTON_LMASK) {
@ -150,24 +150,6 @@ convert_mouse_buttons(uint32_t state) {
} }
bool bool
convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
if (!convert_keycode_action(from->type, &to->inject_keycode.action)) {
return false;
}
uint16_t mod = from->keysym.mod;
if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod)) {
return false;
}
to->inject_keycode.metastate = convert_meta_state(mod);
return true;
}
static bool
convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) { convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
switch (from) { switch (from) {
MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN); MAP(SDL_MOUSEBUTTONDOWN, AMOTION_EVENT_ACTION_DOWN);
@ -177,41 +159,6 @@ convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to) {
} }
bool bool
convert_mouse_button(const SDL_MouseButtonEvent *from, struct size screen_size,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) {
return false;
}
to->inject_touch_event.pointer_id = POINTER_ID_MOUSE;
to->inject_touch_event.position.screen_size = screen_size;
to->inject_touch_event.position.point.x = from->x;
to->inject_touch_event.position.point.y = from->y;
to->inject_touch_event.pressure = 1.f;
to->inject_touch_event.buttons =
convert_mouse_buttons(SDL_BUTTON(from->button));
return true;
}
bool
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct size screen_size,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
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_size;
to->inject_touch_event.position.point.x = from->x;
to->inject_touch_event.position.point.y = from->y;
to->inject_touch_event.pressure = 1.f;
to->inject_touch_event.buttons = convert_mouse_buttons(from->state);
return true;
}
static bool
convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) { convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) {
switch (from) { switch (from) {
MAP(SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE); MAP(SDL_FINGERMOTION, AMOTION_EVENT_ACTION_MOVE);
@ -220,39 +167,3 @@ convert_touch_action(SDL_EventType from, enum android_motionevent_action *to) {
FAIL; FAIL;
} }
} }
bool
convert_touch(const SDL_TouchFingerEvent *from, struct size screen_size,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_touch_action(from->type, &to->inject_touch_event.action)) {
return false;
}
to->inject_touch_event.pointer_id = from->fingerId;
to->inject_touch_event.position.screen_size = screen_size;
// SDL touch event coordinates are normalized in the range [0; 1]
to->inject_touch_event.position.point.x = from->x * screen_size.width;
to->inject_touch_event.position.point.y = from->y * screen_size.height;
to->inject_touch_event.pressure = from->pressure;
to->inject_touch_event.buttons = 0;
return true;
}
bool
convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct position position,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
to->inject_scroll_event.position = position;
int mul = from->direction == SDL_MOUSEWHEEL_NORMAL ? 1 : -1;
// SDL behavior seems inconsistent between horizontal and vertical scrolling
// so reverse the horizontal
// <https://wiki.libsdl.org/SDL_MouseWheelEvent#Remarks>
to->inject_scroll_event.hscroll = -mul * from->x;
to->inject_scroll_event.vscroll = mul * from->y;
return true;
}

View File

@ -7,36 +7,22 @@
#include "config.h" #include "config.h"
#include "control_msg.h" #include "control_msg.h"
struct complete_mouse_motion_event { bool
SDL_MouseMotionEvent *mouse_motion_event; convert_keycode_action(SDL_EventType from, enum android_keyevent_action *to);
struct size screen_size;
};
struct complete_mouse_wheel_event { enum android_metastate
SDL_MouseWheelEvent *mouse_wheel_event; convert_meta_state(SDL_Keymod mod);
struct point position;
};
bool bool
convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to); convert_keycode(SDL_Keycode from, enum android_keycode *to, uint16_t mod);
enum android_motionevent_buttons
convert_mouse_buttons(uint32_t state);
bool bool
convert_mouse_button(const SDL_MouseButtonEvent *from, struct size screen_size, convert_mouse_action(SDL_EventType from, enum android_motionevent_action *to);
struct control_msg *to);
// the video size may be different from the real device size, so we need the
// size to which the absolute position apply, to scale it accordingly
bool
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct size screen_size,
struct control_msg *to);
bool bool
convert_touch(const SDL_TouchFingerEvent *from, struct size screen_size, convert_touch_action(SDL_EventType from, enum android_motionevent_action *to);
struct control_msg *to);
// on Android, a scroll event requires the current mouse position
bool
convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct position position,
struct control_msg *to);
#endif #endif

View File

@ -7,33 +7,6 @@
#include "lock_util.h" #include "lock_util.h"
#include "log.h" #include "log.h"
// Convert window coordinates (as provided by SDL_GetMouseState() to renderer
// coordinates (as provided in SDL mouse events)
//
// See my question:
// <https://stackoverflow.com/questions/49111054/how-to-get-mouse-position-on-mouse-wheel-event>
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_DOWN = 1;
static const int ACTION_UP = 1 << 1; static const int ACTION_UP = 1 << 1;
@ -212,7 +185,7 @@ clipboard_paste(struct controller *controller) {
} }
void void
input_manager_process_text_input(struct input_manager *input_manager, input_manager_process_text_input(struct input_manager *im,
const SDL_TextInputEvent *event) { const SDL_TextInputEvent *event) {
char c = event->text[0]; char c = event->text[0];
if (isalpha(c) || c == ' ') { if (isalpha(c) || c == ' ') {
@ -227,14 +200,32 @@ input_manager_process_text_input(struct input_manager *input_manager,
LOGW("Could not strdup input text"); LOGW("Could not strdup input text");
return; return;
} }
if (!controller_push_msg(input_manager->controller, &msg)) { if (!controller_push_msg(im->controller, &msg)) {
SDL_free(msg.inject_text.text); SDL_free(msg.inject_text.text);
LOGW("Could not request 'inject text'"); LOGW("Could not request 'inject text'");
} }
} }
static bool
convert_input_key(const SDL_KeyboardEvent *from, struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_KEYCODE;
if (!convert_keycode_action(from->type, &to->inject_keycode.action)) {
return false;
}
uint16_t mod = from->keysym.mod;
if (!convert_keycode(from->keysym.sym, &to->inject_keycode.keycode, mod)) {
return false;
}
to->inject_keycode.metastate = convert_meta_state(mod);
return true;
}
void void
input_manager_process_key(struct input_manager *input_manager, input_manager_process_key(struct input_manager *im,
const SDL_KeyboardEvent *event, const SDL_KeyboardEvent *event,
bool control) { bool control) {
// control: indicates the state of the command-line option --no-control // control: indicates the state of the command-line option --no-control
@ -261,7 +252,7 @@ input_manager_process_key(struct input_manager *input_manager,
return; return;
} }
struct controller *controller = input_manager->controller; struct controller *controller = im->controller;
// capture all Ctrl events // capture all Ctrl events
if (ctrl || cmd) { if (ctrl || cmd) {
@ -336,23 +327,23 @@ input_manager_process_key(struct input_manager *input_manager,
return; return;
case SDLK_f: case SDLK_f:
if (!shift && cmd && !repeat && down) { if (!shift && cmd && !repeat && down) {
screen_switch_fullscreen(input_manager->screen); screen_switch_fullscreen(im->screen);
} }
return; return;
case SDLK_x: case SDLK_x:
if (!shift && cmd && !repeat && down) { if (!shift && cmd && !repeat && down) {
screen_resize_to_fit(input_manager->screen); screen_resize_to_fit(im->screen);
} }
return; return;
case SDLK_g: case SDLK_g:
if (!shift && cmd && !repeat && down) { if (!shift && cmd && !repeat && down) {
screen_resize_to_pixel_perfect(input_manager->screen); screen_resize_to_pixel_perfect(im->screen);
} }
return; return;
case SDLK_i: case SDLK_i:
if (!shift && cmd && !repeat && down) { if (!shift && cmd && !repeat && down) {
struct fps_counter *fps_counter = struct fps_counter *fps_counter =
input_manager->video_buffer->fps_counter; im->video_buffer->fps_counter;
switch_fps_counter_state(fps_counter); switch_fps_counter_state(fps_counter);
} }
return; return;
@ -382,8 +373,23 @@ input_manager_process_key(struct input_manager *input_manager,
} }
} }
static bool
convert_mouse_motion(const SDL_MouseMotionEvent *from, struct screen *screen,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
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 =
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);
return true;
}
void void
input_manager_process_mouse_motion(struct input_manager *input_manager, input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event) { const SDL_MouseMotionEvent *event) {
if (!event->state) { if (!event->state) {
// do not send motion events when no button is pressed // do not send motion events when no button is pressed
@ -394,33 +400,76 @@ input_manager_process_mouse_motion(struct input_manager *input_manager,
return; return;
} }
struct control_msg msg; struct control_msg msg;
if (convert_mouse_motion(event, input_manager->screen->frame_size, &msg)) { if (convert_mouse_motion(event, im->screen, &msg)) {
if (!controller_push_msg(input_manager->controller, &msg)) { if (!controller_push_msg(im->controller, &msg)) {
LOGW("Could not request 'inject mouse motion event'"); LOGW("Could not request 'inject mouse motion event'");
} }
} }
} }
static bool
convert_touch(const SDL_TouchFingerEvent *from, struct screen *screen,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_touch_action(from->type, &to->inject_touch_event.action)) {
return false;
}
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;
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;
}
void void
input_manager_process_touch(struct input_manager *input_manager, input_manager_process_touch(struct input_manager *im,
const SDL_TouchFingerEvent *event) { const SDL_TouchFingerEvent *event) {
struct control_msg msg; struct control_msg msg;
if (convert_touch(event, input_manager->screen->frame_size, &msg)) { if (convert_touch(event, im->screen, &msg)) {
if (!controller_push_msg(input_manager->controller, &msg)) { if (!controller_push_msg(im->controller, &msg)) {
LOGW("Could not request 'inject touch event'"); LOGW("Could not request 'inject touch event'");
} }
} }
} }
static bool static bool
is_outside_device_screen(struct input_manager *input_manager, int x, int y) is_outside_device_screen(struct input_manager *im, int x, int y)
{ {
return x < 0 || x >= input_manager->screen->frame_size.width || return x < 0 || x >= im->screen->frame_size.width ||
y < 0 || y >= input_manager->screen->frame_size.height; y < 0 || y >= im->screen->frame_size.height;
}
static bool
convert_mouse_button(const SDL_MouseButtonEvent *from, struct screen *screen,
struct control_msg *to) {
to->type = CONTROL_MSG_TYPE_INJECT_TOUCH_EVENT;
if (!convert_mouse_action(from->type, &to->inject_touch_event.action)) {
return false;
}
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 =
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));
return true;
} }
void void
input_manager_process_mouse_button(struct input_manager *input_manager, input_manager_process_mouse_button(struct input_manager *im,
const SDL_MouseButtonEvent *event, const SDL_MouseButtonEvent *event,
bool control) { bool control) {
if (event->which == SDL_TOUCH_MOUSEID) { if (event->which == SDL_TOUCH_MOUSEID) {
@ -429,19 +478,19 @@ input_manager_process_mouse_button(struct input_manager *input_manager,
} }
if (event->type == SDL_MOUSEBUTTONDOWN) { if (event->type == SDL_MOUSEBUTTONDOWN) {
if (control && event->button == SDL_BUTTON_RIGHT) { if (control && event->button == SDL_BUTTON_RIGHT) {
press_back_or_turn_screen_on(input_manager->controller); press_back_or_turn_screen_on(im->controller);
return; return;
} }
if (control && event->button == SDL_BUTTON_MIDDLE) { if (control && event->button == SDL_BUTTON_MIDDLE) {
action_home(input_manager->controller, ACTION_DOWN | ACTION_UP); action_home(im->controller, ACTION_DOWN | ACTION_UP);
return; return;
} }
// double-click on black borders resize to fit the device screen // double-click on black borders resize to fit the device screen
if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) { if (event->button == SDL_BUTTON_LEFT && event->clicks == 2) {
bool outside = bool outside =
is_outside_device_screen(input_manager, event->x, event->y); is_outside_device_screen(im, event->x, event->y);
if (outside) { if (outside) {
screen_resize_to_fit(input_manager->screen); screen_resize_to_fit(im->screen);
return; return;
} }
} }
@ -453,23 +502,47 @@ input_manager_process_mouse_button(struct input_manager *input_manager,
} }
struct control_msg msg; struct control_msg msg;
if (convert_mouse_button(event, input_manager->screen->frame_size, &msg)) { if (convert_mouse_button(event, im->screen, &msg)) {
if (!controller_push_msg(input_manager->controller, &msg)) { if (!controller_push_msg(im->controller, &msg)) {
LOGW("Could not request 'inject mouse button event'"); LOGW("Could not request 'inject mouse button event'");
} }
} }
} }
void static bool
input_manager_process_mouse_wheel(struct input_manager *input_manager, convert_mouse_wheel(const SDL_MouseWheelEvent *from, struct screen *screen,
const SDL_MouseWheelEvent *event) { 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 = { struct position position = {
.screen_size = input_manager->screen->frame_size, .screen_size = screen->frame_size,
.point = get_mouse_point(input_manager->screen), .point = screen_convert_to_frame_coords(screen, mouse_x, mouse_y),
}; };
to->type = CONTROL_MSG_TYPE_INJECT_SCROLL_EVENT;
to->inject_scroll_event.position = position;
int mul = from->direction == SDL_MOUSEWHEEL_NORMAL ? 1 : -1;
// SDL behavior seems inconsistent between horizontal and vertical scrolling
// so reverse the horizontal
// <https://wiki.libsdl.org/SDL_MouseWheelEvent#Remarks>
to->inject_scroll_event.hscroll = -mul * from->x;
to->inject_scroll_event.vscroll = mul * from->y;
return true;
}
void
input_manager_process_mouse_wheel(struct input_manager *im,
const SDL_MouseWheelEvent *event) {
struct control_msg msg; struct control_msg msg;
if (convert_mouse_wheel(event, position, &msg)) { if (convert_mouse_wheel(event, im->screen, &msg)) {
if (!controller_push_msg(input_manager->controller, &msg)) { if (!controller_push_msg(im->controller, &msg)) {
LOGW("Could not request 'inject mouse wheel event'"); LOGW("Could not request 'inject mouse wheel event'");
} }
} }

View File

@ -17,29 +17,29 @@ struct input_manager {
}; };
void void
input_manager_process_text_input(struct input_manager *input_manager, input_manager_process_text_input(struct input_manager *im,
const SDL_TextInputEvent *event); const SDL_TextInputEvent *event);
void void
input_manager_process_key(struct input_manager *input_manager, input_manager_process_key(struct input_manager *im,
const SDL_KeyboardEvent *event, const SDL_KeyboardEvent *event,
bool control); bool control);
void void
input_manager_process_mouse_motion(struct input_manager *input_manager, input_manager_process_mouse_motion(struct input_manager *im,
const SDL_MouseMotionEvent *event); const SDL_MouseMotionEvent *event);
void void
input_manager_process_touch(struct input_manager *input_manager, input_manager_process_touch(struct input_manager *im,
const SDL_TouchFingerEvent *event); const SDL_TouchFingerEvent *event);
void void
input_manager_process_mouse_button(struct input_manager *input_manager, input_manager_process_mouse_button(struct input_manager *im,
const SDL_MouseButtonEvent *event, const SDL_MouseButtonEvent *event,
bool control); bool control);
void void
input_manager_process_mouse_wheel(struct input_manager *input_manager, input_manager_process_mouse_wheel(struct input_manager *im,
const SDL_MouseWheelEvent *event); const SDL_MouseWheelEvent *event);
#endif #endif

View File

@ -145,9 +145,11 @@ handle_event(SDL_Event *event, bool control) {
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
switch (event->window.event) { switch (event->window.event) {
case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_render(&screen); screen_render(&screen);
break; break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
screen_window_resized(&screen);
break;
} }
break; break;
case SDL_TEXTINPUT: case SDL_TEXTINPUT:

View File

@ -122,6 +122,32 @@ get_initial_optimal_size(struct size frame_size) {
return get_optimal_size(frame_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 void
screen_init(struct screen *screen) { screen_init(struct screen *screen) {
*screen = (struct screen) SCREEN_INITIALIZER; *screen = (struct screen) SCREEN_INITIALIZER;
@ -170,13 +196,6 @@ screen_init_rendering(struct screen *screen, const char *window_title,
return false; 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); SDL_Surface *icon = read_xpm(icon_xpm);
if (icon) { if (icon) {
SDL_SetWindowIcon(screen->window, icon); SDL_SetWindowIcon(screen->window, icon);
@ -220,12 +239,6 @@ static bool
prepare_for_frame(struct screen *screen, struct size new_frame_size) { prepare_for_frame(struct screen *screen, struct size new_frame_size) {
if (screen->frame_size.width != new_frame_size.width if (screen->frame_size.width != new_frame_size.width
|| screen->frame_size.height != new_frame_size.height) { || 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 // frame dimension changed, destroy texture
SDL_DestroyTexture(screen->texture); SDL_DestroyTexture(screen->texture);
@ -271,6 +284,7 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
mutex_unlock(vb->mutex); mutex_unlock(vb->mutex);
return false; return false;
} }
update_frame_rect(screen);
update_texture(screen, frame); update_texture(screen, frame);
mutex_unlock(vb->mutex); mutex_unlock(vb->mutex);
@ -278,10 +292,16 @@ screen_update_frame(struct screen *screen, struct video_buffer *vb) {
return true; return true;
} }
void
screen_window_resized(struct screen *screen) {
update_frame_rect(screen);
screen_render(screen);
}
void void
screen_render(struct screen *screen) { screen_render(struct screen *screen) {
SDL_RenderClear(screen->renderer); 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); SDL_RenderPresent(screen->renderer);
} }
@ -327,3 +347,11 @@ screen_resize_to_pixel_perfect(struct screen *screen) {
LOGD("Resized to pixel-perfect"); 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;
}

View File

@ -17,6 +17,7 @@ struct screen {
struct size frame_size; struct size frame_size;
//used only in fullscreen mode to know the windowed window size //used only in fullscreen mode to know the windowed window size
struct size windowed_window_size; struct size windowed_window_size;
struct SDL_Rect rect;
bool has_frame; bool has_frame;
bool fullscreen; bool fullscreen;
bool no_window; bool no_window;
@ -34,6 +35,12 @@ struct screen {
.width = 0, \ .width = 0, \
.height = 0, \ .height = 0, \
}, \ }, \
.rect = { \
.x = 0, \
.y = 0, \
.w = 0, \
.h = 0, \
}, \
.has_frame = false, \ .has_frame = false, \
.fullscreen = false, \ .fullscreen = false, \
.no_window = false, \ .no_window = false, \
@ -60,6 +67,10 @@ screen_destroy(struct screen *screen);
bool bool
screen_update_frame(struct screen *screen, struct video_buffer *vb); screen_update_frame(struct screen *screen, struct video_buffer *vb);
// update content after window resizing
void
screen_window_resized(struct screen *screen);
// render the texture to the renderer // render the texture to the renderer
void void
screen_render(struct screen *screen); screen_render(struct screen *screen);
@ -76,4 +87,9 @@ screen_resize_to_fit(struct screen *screen);
void void
screen_resize_to_pixel_perfect(struct screen *screen); 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 #endif