diff --git a/app/src/screen.c b/app/src/screen.c index bf11dc02..2a587270 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -87,6 +87,26 @@ get_preferred_display_bounds(struct size *bounds) { return true; } +// Indicate if the width should be kept on computing the optimal rectangle size +// to display the content in the window. +// Return true if the width should be kept, false if the height should be kept. +static bool +should_keep_width(struct size window_size, struct size content_size) { + // 32 bits because we need to multiply two 16 bits values + uint32_t ww = window_size.width; + uint32_t wh = window_size.height; + uint32_t cw = content_size.width; + uint32_t ch = content_size.height; + + // To avoid keeping alternatively width and height on successive resizes + // due to rounding to integer, always prefer height (arbitrarily) if in the + // error range. + + // err = ceil of content aspect ratio + unsigned err = (cw + ch - 1) / ch; + return cw * wh > ch * (ww + err); +} + // return the optimal size of the window, with the following constraints: // - it attempts to keep at least one dimension of the current_size (i.e. it // crops the black borders) @@ -99,33 +119,33 @@ get_optimal_size(struct size current_size, struct size content_size) { return current_size; } - struct size display_size; - // 32 bits because we need to multiply two 16 bits values - uint32_t w; - uint32_t h; + struct size window_size; + struct size display_size; if (!get_preferred_display_bounds(&display_size)) { // could not get display bounds, do not constraint the size - w = current_size.width; - h = current_size.height; + window_size.width = current_size.width; + window_size.height = current_size.height; } else { - w = MIN(current_size.width, display_size.width); - h = MIN(current_size.height, display_size.height); + window_size.width = MIN(current_size.width, display_size.width); + window_size.height = MIN(current_size.height, display_size.height); } - bool keep_width = content_size.width * h > content_size.height * w; + bool keep_width = should_keep_width(window_size, content_size); if (keep_width) { // remove black borders on top and bottom - h = content_size.height * w / content_size.width; + window_size.height = content_size.height * window_size.width + / content_size.width; } else { // remove black borders on left and right (or none at all if it already // fits) - w = content_size.width * h / content_size.height; + window_size.width = content_size.width * window_size.height + / content_size.height; } - // w and h must fit into 16 bits - assert(w < 0x10000 && h < 0x10000); - return (struct size) {w, h}; + // width and height must fit into 16 bits + assert(window_size.width < 0x10000 && window_size.height < 0x10000); + return window_size; } // same as get_optimal_size(), but read the current size from the window @@ -164,17 +184,19 @@ get_initial_optimal_size(struct size content_size, uint16_t req_width, static void update_content_rect(struct screen *screen) { - int ww; - int wh; - SDL_GL_GetDrawableSize(screen->window, &ww, &wh); + int w; + int h; + SDL_GL_GetDrawableSize(screen->window, &w, &h); - // 32 bits because we need to multiply two 16 bits values - uint32_t cw = screen->content_size.width; - uint32_t ch = screen->content_size.height; + struct size window_size = {w, h}; + uint16_t ww = window_size.width; + uint16_t wh = window_size.height; + uint16_t cw = screen->content_size.width; + uint16_t ch = screen->content_size.height; SDL_Rect *rect = &screen->rect; - bool keep_width = cw * wh > ch * ww; + bool keep_width = should_keep_width(window_size, screen->content_size); if (keep_width) { rect->x = 0; rect->w = ww;