diff --git a/src/config.c b/src/config.c index 52fba7185f..5b8dc1cd36 100644 --- a/src/config.c +++ b/src/config.c @@ -88,6 +88,8 @@ general_configuration_t gGeneral_config_default = { 0, // show_height_as_units 1, // save_plugin_data 0, // fullscreen mode (default: windowed) + -1, // fullscreen_width + -1, // fullscreen_height -1, // window_width -1, // window_height LANGUAGE_ENGLISH_UK, // language @@ -252,6 +254,11 @@ void config_write_ini_general(FILE *fp) else fprintf(fp, "fullscreen_mode = borderless_fullscreen\n"); + if (gGeneral_config.fullscreen_width != -1) + fprintf(fp, "fullscreen_width = %d\n", gGeneral_config.fullscreen_width); + if (gGeneral_config.window_height != -1) + fprintf(fp, "fullscreen_height = %d\n", gGeneral_config.fullscreen_height); + if (gGeneral_config.window_width != -1) fprintf(fp, "window_width = %d\n", gGeneral_config.window_width); if (gGeneral_config.window_height != -1) @@ -557,6 +564,12 @@ static void config_general(char *setting, char *value){ else gGeneral_config.fullscreen_mode = 2; } + else if (strcmp(setting, "fullscreen_width") == 0) { + gGeneral_config.fullscreen_width = atoi(value); + } + else if (strcmp(setting, "fullscreen_height") == 0) { + gGeneral_config.fullscreen_height = atoi(value); + } else if (strcmp(setting, "window_width") == 0) { gGeneral_config.window_width = atoi(value); } diff --git a/src/config.h b/src/config.h index 3098031780..9ed0f7e8cd 100644 --- a/src/config.h +++ b/src/config.h @@ -132,6 +132,8 @@ typedef struct general_configuration { //new uint8 fullscreen_mode; + sint16 fullscreen_width; + sint16 fullscreen_height; sint16 window_width; sint16 window_height; uint16 language; diff --git a/src/platform/osinterface.c b/src/platform/osinterface.c index 1927a6aaab..ce6fba9a26 100644 --- a/src/platform/osinterface.c +++ b/src/platform/osinterface.c @@ -49,7 +49,6 @@ static void osinterface_create_window(); static void osinterface_close_window(); static void osinterface_resize(int width, int height); -static SDL_Window *_window; static SDL_Surface *_surface; static SDL_Palette *_palette; @@ -204,16 +203,16 @@ static void osinterface_create_window() RCT2_GLOBAL(0x009E2D8C, sint32) = 0; - _window = SDL_CreateWindow("OpenRCT2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, + gWindow = SDL_CreateWindow("OpenRCT2", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, _fullscreen_modes[gGeneral_config.fullscreen_mode] | SDL_WINDOW_RESIZABLE); - if (!_window) { + if (!gWindow) { RCT2_ERROR("SDL_CreateWindow failed %s", SDL_GetError()); exit(-1); } SDL_VERSION(&wmInfo.version); // Get the HWND context - if (SDL_GetWindowWMInfo(_window, &wmInfo) != SDL_TRUE) { + if (SDL_GetWindowWMInfo(gWindow, &wmInfo) != SDL_TRUE) { RCT2_ERROR("SDL_GetWindowWMInfo failed %s", SDL_GetError()); exit(-1); } @@ -225,6 +224,8 @@ static void osinterface_create_window() // Initialise the surface, palette and draw buffer osinterface_resize(width, height); + + platform_update_fullscreen_resolutions(); } @@ -297,7 +298,7 @@ void osinterface_update_palette(char* colours, int start_index, int num_colours) SDL_Surface *surface; int i; - surface = SDL_GetWindowSurface(_window); + surface = SDL_GetWindowSurface(gWindow); if (!surface) { RCT2_ERROR("SDL_GetWindowSurface failed %s", SDL_GetError()); exit(1); @@ -334,11 +335,11 @@ void osinterface_draw() SDL_UnlockSurface(_surface); // Copy the surface to the window - if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(_window), NULL)) { + if (SDL_BlitSurface(_surface, NULL, SDL_GetWindowSurface(gWindow), NULL)) { RCT2_ERROR("SDL_BlitSurface %s", SDL_GetError()); exit(1); } - if (SDL_UpdateWindowSurface(_window)) { + if (SDL_UpdateWindowSurface(gWindow)) { RCT2_ERROR("SDL_UpdateWindowSurface %s", SDL_GetError()); exit(1); } @@ -508,8 +509,8 @@ void osinterface_process_messages() static void osinterface_close_window() { - if (_window != NULL) - SDL_DestroyWindow(_window); + if (gWindow != NULL) + SDL_DestroyWindow(gWindow); if (_surface != NULL) SDL_FreeSurface(_surface); if (_palette != NULL) @@ -525,16 +526,45 @@ void osinterface_free() SDL_Quit(); } -void osinterface_set_fullscreen_mode(int mode){ - if (mode == gGeneral_config.fullscreen_mode) - return; +void osinterface_set_fullscreen_mode(int mode) +{ + int i, destinationArea, areaDiff, closestAreaDiff, closestWidth, closestHeight; - if (SDL_SetWindowFullscreen(_window, _fullscreen_modes[mode])){ + if (mode == SDL_WINDOW_FULLSCREEN) + SDL_SetWindowFullscreen(gWindow, 0); + + if (mode == SDL_WINDOW_FULLSCREEN) { + platform_update_fullscreen_resolutions(); + + closestAreaDiff = -1; + destinationArea = gGeneral_config.fullscreen_width * gGeneral_config.fullscreen_height; + for (i = 0; i < gNumResolutions; i++) { + // Check if exact match + if (gResolutions[i].width == gGeneral_config.fullscreen_width && gResolutions[i].height == gGeneral_config.fullscreen_height) { + closestWidth = gResolutions[i].width; + closestHeight = gResolutions[i].height; + break; + } + + // Check if area is closer to best match + areaDiff = abs((gResolutions[i].width * gResolutions[i].height) - destinationArea); + if (closestAreaDiff == -1 || areaDiff < closestAreaDiff) { + closestAreaDiff = areaDiff; + closestWidth = gResolutions[i].width; + closestHeight = gResolutions[i].height; + } + } + + if (closestAreaDiff != -1) + SDL_SetWindowSize(gWindow, closestWidth, closestHeight); + } else if (mode == 0) { + SDL_SetWindowSize(gWindow, gGeneral_config.window_width, gGeneral_config.window_height); + } + + if (SDL_SetWindowFullscreen(gWindow, _fullscreen_modes[mode])){ RCT2_ERROR("SDL_SetWindowFullscreen %s", SDL_GetError()); exit(1); } - //SDL automatically resizes the fullscreen window to the nearest allowed screen resolution - //No need to call osinterface_resize() here, SDL_WINDOWEVENT_SIZE_CHANGED event will be triggered anyway gGeneral_config.fullscreen_mode = mode; diff --git a/src/platform/platform.h b/src/platform/platform.h index 2b2e8db336..cbdc7db7c9 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -21,6 +21,8 @@ #ifndef _PLATFORM_H_ #define _PLATFORM_H_ +#include + #include "../common.h" #ifndef MAX_PATH @@ -29,12 +31,24 @@ #define INVALID_HANDLE -1 +typedef struct { + int width, height; +} resolution; + typedef struct { const char *path; uint64 size; uint64 last_modified; } file_info; +extern int gResolutionsAllowAnyAspectRatio; +extern int gNumResolutions; +extern resolution *gResolutions; +extern SDL_Window *gWindow; + +// Platform shared definitions +void platform_update_fullscreen_resolutions(); + // Platform specific definitions char platform_get_path_separator(); int platform_file_exists(const char *path); diff --git a/src/platform/shared.c b/src/platform/shared.c index 20a00a3bd2..afcccda54c 100644 --- a/src/platform/shared.c +++ b/src/platform/shared.c @@ -18,3 +18,81 @@ * along with this program. If not, see . *****************************************************************************/ +#include +#include +#include "../config.h" +#include "platform.h" + +int gNumResolutions; +resolution *gResolutions = NULL; + +SDL_Window *gWindow; + +int gResolutionsAllowAnyAspectRatio = 0; + +int resolution_sort_func(const void *pa, const void *pb) +{ + const resolution *a = (resolution*)pa; + const resolution *b = (resolution*)pb; + + int areaA = a->width * a->height; + int areaB = b->height * b->height; + + if (areaA == areaB) return 0; + if (areaA < areaB) return -1; + return 1; +} + +void platform_update_fullscreen_resolutions() +{ + int i, displayIndex, numDisplayModes; + SDL_DisplayMode mode; + resolution *resLook, *resPlace; + float desktopAspectRatio, aspectRatio; + + // Query number of display modes + displayIndex = SDL_GetWindowDisplayIndex(gWindow); + numDisplayModes = SDL_GetNumDisplayModes(displayIndex); + + // Get desktop aspect ratio + SDL_GetDesktopDisplayMode(displayIndex, &mode); + desktopAspectRatio = (float)mode.w / mode.h; + + if (gResolutions != NULL) + free(gResolutions); + + // Get resolutions + gNumResolutions = numDisplayModes; + gResolutions = malloc(gNumResolutions * sizeof(resolution)); + + gNumResolutions = 0; + for (i = 0; i < numDisplayModes; i++) { + SDL_GetDisplayMode(displayIndex, i, &mode); + + aspectRatio = (float)mode.w / mode.h; + if (gResolutionsAllowAnyAspectRatio || fabs(desktopAspectRatio - aspectRatio) < 0.0001f) { + gResolutions[gNumResolutions].width = mode.w; + gResolutions[gNumResolutions].height = mode.h; + gNumResolutions++; + } + } + + // Sort by area + qsort(gResolutions, gNumResolutions, sizeof(resolution), resolution_sort_func); + + // Remove duplicates + resPlace = &gResolutions[0]; + for (int i = 1; i < gNumResolutions; i++) { + resLook = &gResolutions[i]; + if (resLook->width != resPlace->width || resLook->height != resPlace->height) + *++resPlace = *resLook; + } + + gNumResolutions = (int)(resPlace - &gResolutions[0]) + 1; + + // Update config fullscreen resolution if not set + if (gGeneral_config.fullscreen_width == -1 || gGeneral_config.fullscreen_height == -1) { + gGeneral_config.fullscreen_width = gResolutions[gNumResolutions - 1].width; + gGeneral_config.fullscreen_height = gResolutions[gNumResolutions - 1].height; + } +} \ No newline at end of file diff --git a/src/windows/options.c b/src/windows/options.c index 216f3899b0..5507ca53d0 100644 --- a/src/windows/options.c +++ b/src/windows/options.c @@ -409,7 +409,30 @@ static void window_options_mousedown(int widgetIndex, rct_window*w, rct_widget* gDropdownItemsChecked = 1 << gGeneral_config.measurement_format; break; case WIDX_RESOLUTION_DROPDOWN: - // RCT2_CALLPROC_EBPSAFE(0x006BB2AF); + { + platform_update_fullscreen_resolutions(); + + int selectedResolution = -1; + for (i = 0; i < gNumResolutions; i++) { + resolution *resolution = &gResolutions[i]; + + gDropdownItemsFormat[i] = 1142; + + uint16 *args = (uint16*)&gDropdownItemsArgs[i]; + args[0] = 839; + args[1] = resolution->width; + args[2] = resolution->height; + + if (resolution->width == gGeneral_config.fullscreen_width && resolution->height == gGeneral_config.fullscreen_height) + selectedResolution = i; + } + + window_options_show_dropdown(w, widget, gNumResolutions); + + if (selectedResolution != -1 && selectedResolution < 32) + gDropdownItemsChecked = 1 << selectedResolution; + } + break; case WIDX_FULLSCREEN_DROPDOWN: gDropdownItemsFormat[0] = 1142; @@ -527,13 +550,19 @@ static void window_options_dropdown() window_options_update_height_markers(); break; case WIDX_RESOLUTION_DROPDOWN: - #ifdef _MSC_VER - __asm movzx ax, dropdownIndex - #else - __asm__ ( "movzx ax, %[dropdownIndex] " : : [dropdownIndex] "g" ((char)dropdownIndex) ); - #endif - // the switch replaces ax value - RCT2_CALLPROC_EBPSAFE(0x006BB37D); + { + resolution *resolution = &gResolutions[dropdownIndex]; + if (resolution->width != gGeneral_config.fullscreen_width || resolution->height != gGeneral_config.fullscreen_height) { + gGeneral_config.fullscreen_width = resolution->width; + gGeneral_config.fullscreen_height = resolution->height; + + if (gGeneral_config.fullscreen_mode == SDL_WINDOW_FULLSCREEN) + osinterface_set_fullscreen_mode(SDL_WINDOW_FULLSCREEN); + + config_save(); + gfx_invalidate_screen(); + } + } break; case WIDX_FULLSCREEN_DROPDOWN: if (dropdownIndex != gGeneral_config.fullscreen_mode){ @@ -592,8 +621,8 @@ static void window_options_invalidate() switch (w->page) { case WINDOW_OPTIONS_PAGE_DISPLAY: // resolution - RCT2_GLOBAL(0x013CE952 + 16, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_WIDTH, uint16); - RCT2_GLOBAL(0x013CE952 + 18, uint16) = RCT2_GLOBAL(RCT2_ADDRESS_CONFIG_RESOLUTION_HEIGHT, uint16); + RCT2_GLOBAL(0x013CE952 + 16, uint16) = gGeneral_config.fullscreen_width; + RCT2_GLOBAL(0x013CE952 + 18, uint16) = gGeneral_config.fullscreen_height; RCT2_GLOBAL(0x013CE952 + 12, uint16) = 2773 + gGeneral_config.fullscreen_mode; // landscape tile smoothing checkbox