/* Hatari - resolution.c This file is distributed under the GNU General Public License, version 2 or at your option any later version. Read the file gpl.txt for details. SDL resolution limitation and selection routines. */ const char Resolution_fileid[] = "Hatari resolution.c : " __DATE__ " " __TIME__; #include #include "main.h" #include "configuration.h" #include "resolution.h" #include "statusbar.h" #include "screen.h" #define DEBUG 0 #if DEBUG # define DEBUGPRINT(x) printf x #else #ifdef GEKKO # define DEBUGPRINT(x) // #include "log.h" #else # define DEBUGPRINT(x) #endif #endif static int DesktopWidth, DesktopHeight; /** * Initilizes resolution settings (gets current desktop * resolution, sets max Falcon/TT Videl zooming resolution). */ void Resolution_Init(void) { #if WITH_SDL2 SDL_DisplayMode dm; if (SDL_GetDesktopDisplayMode(0, &dm) == 0) { DesktopWidth = dm.w; DesktopHeight = dm.h; } else { #ifndef GEKKO fprintf(stderr, "SDL_GetDesktopDisplayMode failed: %s", SDL_GetError()); #else Log_Printf(LOG_ERROR, "SDL_GetDesktopDisplayMode failed: %s", SDL_GetError()); #endif DesktopWidth = 2*NUM_VISIBLE_LINE_PIXELS; DesktopHeight = 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT; } #else /* Needs to be called after SDL video and configuration * initialization, but before Hatari Screen init is called * for the first time! */ const SDL_VideoInfo* info = SDL_GetVideoInfo(); if (info->current_w >= 640 && info->current_h >= 400) { DesktopWidth = info->current_w; DesktopHeight = info->current_h; } else { /* target 800x600 screen with statusbar out of screen */ DesktopWidth = 2*NUM_VISIBLE_LINE_PIXELS; DesktopHeight = 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT; #ifndef GEKKO fprintf(stderr, "WARNING: invalid desktop size %dx%d, defaulting to %dx%d!\n", info->current_w, info->current_h, DesktopWidth, DesktopHeight); #else Log_Printf(LOG_ERROR, "WARNING: invalid desktop size %dx%d, defaulting to %dx%d!\n", info->current_w, info->current_h, DesktopWidth, DesktopHeight); #endif } #endif /* if user hasn't set own max zoom size, use desktop size */ if (!(ConfigureParams.Screen.nMaxWidth && ConfigureParams.Screen.nMaxHeight)) { ConfigureParams.Screen.nMaxWidth = DesktopWidth; ConfigureParams.Screen.nMaxHeight = DesktopHeight; } DEBUGPRINT(("Desktop resolution: %dx%d\n",DesktopWidth, DesktopHeight)); #ifndef GEKKO fprintf(stderr, "Configured max Hatari resolution = %dx%d, optimal for ST = %dx%d\n", ConfigureParams.Screen.nMaxWidth, ConfigureParams.Screen.nMaxHeight, 2*NUM_VISIBLE_LINE_PIXELS, 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT); #else Log_Printf(LOG_ERROR, "Configured max Hatari resolution = %dx%d, optimal for ST = %dx%d\n", ConfigureParams.Screen.nMaxWidth, ConfigureParams.Screen.nMaxHeight, 2*NUM_VISIBLE_LINE_PIXELS, 2*NUM_VISIBLE_LINES+STATUSBAR_MAX_HEIGHT); #endif } /** * Get current desktop resolution */ void Resolution_GetDesktopSize(int *width, int *height) { DEBUGPRINT(("resolution: limit to desktop size\n")); *width = DesktopWidth; *height = DesktopHeight; } /** * Get max resolution */ static void Resolution_GetMaxSize(int *width, int *height) { DEBUGPRINT(("resolution: force to specified max size\n")); *width = ConfigureParams.Screen.nMaxWidth; *height = ConfigureParams.Screen.nMaxHeight; } /** * Select best resolution from given SDL video modes. * - If width and height are given, select the smallest mode larger * or equal to requested size * - Otherwise select the largest available mode * return true for success and false if no matching mode was found. */ static inline bool Resolution_Select(SDL_Rect **modes, int *width, int *height) { #define TOO_LARGE 0x7fff int i, bestw, besth; if (!(*width && *height)) { /* search the largest mode (prefer wider ones) */ for (i = 0; modes[i]; i++) { if ((modes[i]->w > *width) && (modes[i]->h >= *height)) { *width = modes[i]->w; *height = modes[i]->h; } } DEBUGPRINT(("resolution: largest found video mode: %dx%d\n",*width,*height)); return true; } /* Search the smallest mode larger or equal to requested size */ bestw = TOO_LARGE; besth = TOO_LARGE; for (i = 0; modes[i]; i++) { if ((modes[i]->w >= *width) && (modes[i]->h >= *height)) { if ((modes[i]->w < bestw) || (modes[i]->h < besth)) { bestw = modes[i]->w; besth = modes[i]->h; } } } if (bestw == TOO_LARGE || besth == TOO_LARGE) { return false; } *width = bestw; *height = besth; DEBUGPRINT(("resolution: video mode found: %dx%d\n",*width,*height)); return true; #undef TOO_LARGE } /** * Search video mode size that best suits the given width/height/bpp * constraints and set them into given arguments. With zeroed arguments, * set largest video mode. * * Return true if mode is forced (shouldn't be further limited). */ bool Resolution_Search(int *width, int *height, int *bpp, bool keep) { #if !WITH_SDL2 SDL_Rect **modes; SDL_PixelFormat pixelformat; Uint32 modeflags = 0 /*SDL_HWSURFACE | SDL_HWPALETTE*/; #endif /* Search in available modes the best suited */ DEBUGPRINT(("resolution: video mode asked: %dx%dx%d (%s)\n", *width, *height, *bpp, bInFullScreen ? "fullscreen" : "windowed")); if (bInFullScreen) { /* resolution change not allowed? */ if (keep) { Resolution_GetDesktopSize(width, height); return true; } } if (ConfigureParams.Screen.bForceMax) { /* force given max size */ Resolution_GetMaxSize(width, height); return true; } #if !WITH_SDL2 if (bInFullScreen) modeflags |= SDL_FULLSCREEN; /*--- Search a video mode with asked bpp ---*/ if (*bpp != 0) { pixelformat.BitsPerPixel = *bpp; modes = SDL_ListModes(&pixelformat, modeflags); if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) { DEBUGPRINT(("resolution: searching a good video mode (given bpp)\n")); if (Resolution_Select(modes, width, height)) { DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n", *width, *height, *bpp)); return false; } } } /*--- Search a video mode with any bpp ---*/ modes = SDL_ListModes(NULL, modeflags); if ((modes != (SDL_Rect **) 0) && (modes != (SDL_Rect **) -1)) { DEBUGPRINT(("resolution: searching a good video mode (any bpp)\n")); if (Resolution_Select(modes, width, height)) { DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n", *width, *height, *bpp)); return false; } } if (modes == (SDL_Rect **) 0) { #ifndef GEKKO fprintf(stderr, "WARNING: No suitable video modes available!\n"); #else Log_Printf(LOG_ERROR, "WARNING: No suitable video modes available!\n"); #endif } if (modes == (SDL_Rect **) -1) { /* Any mode available */ DEBUGPRINT(("resolution: All resolutions available.\n")); } #endif DEBUGPRINT(("resolution: video mode selected: %dx%dx%d\n", *width, *height, *bpp)); return false; } /** * Set given width & height arguments to maximum size allowed in the * configuration, or if that's too large for the requested bit depth, * to the largest available video mode size. */ void Resolution_GetLimits(int *width, int *height, int *bpp, bool keep) { *width = *height = 0; /* constrain max size to what HW/SDL offers */ DEBUGPRINT(("resolution: request limits for: %dx%dx%d\n", *width, *height, *bpp)); /* forced resolution? */ if (Resolution_Search(width, height, bpp, keep)) { return; } if (!(*width && *height) || (ConfigureParams.Screen.nMaxWidth < *width && ConfigureParams.Screen.nMaxHeight < *height)) { DEBUGPRINT(("resolution: limit to user configured max\n")); *width = ConfigureParams.Screen.nMaxWidth; *height = ConfigureParams.Screen.nMaxHeight; } }