DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/output/output_surface_sdl2.cpp
00001 #include <sys/types.h>
00002 #include <assert.h>
00003 #include <math.h>
00004 
00005 #include "dosbox.h"
00006 #include "sdlmain.h"
00007 #include "vga.h"
00008 
00009 #include <algorithm> // std::transform
00010 
00011 using namespace std;
00012 
00013 #if defined(C_SDL2)
00014 Bitu OUTPUT_SURFACE_SetSize()
00015 {
00016     Bitu bpp = 0;
00017     Bitu retFlags = 0;
00018     (void)bpp;
00019 
00020     SDL_SetWindowMinimumSize(sdl.window, 1, 1); /* NTS: 0 x 0 is not valid */
00021 
00022     sdl.clip.w = sdl.draw.width;
00023     sdl.clip.h = sdl.draw.height;
00024     if (GFX_IsFullscreen()) {
00025         if (sdl.desktop.full.fixed) {
00026             sdl.clip.x = (Sint16)((sdl.desktop.full.width - sdl.draw.width) / 2);
00027             sdl.clip.y = (Sint16)((sdl.desktop.full.height - sdl.draw.height) / 2);
00028             sdl.window = GFX_SetSDLWindowMode(sdl.desktop.full.width, sdl.desktop.full.height, SCREEN_SURFACE);
00029             if (sdl.window == NULL)
00030                 E_Exit("Could not set fullscreen video mode %ix%i-%i: %s", sdl.desktop.full.width, sdl.desktop.full.height, sdl.desktop.bpp, SDL_GetError());
00031         }
00032         else {
00033             sdl.clip.x = 0;
00034             sdl.clip.y = 0;
00035             sdl.window = GFX_SetSDLWindowMode(sdl.draw.width, sdl.draw.height, SCREEN_SURFACE);
00036             if (sdl.window == NULL)
00037                 LOG_MSG("Fullscreen not supported: %s", SDL_GetError());
00038             GFX_CaptureMouse();
00039         }
00040     }
00041     else {
00042         int width = sdl.draw.width;
00043         int height = sdl.draw.height;
00044         int menuheight = 0;
00045 
00046         sdl.clip.x = 0; sdl.clip.y = 0;
00047 
00048 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00049         /* scale the menu bar if the window is large enough */
00050         {
00051             Bitu consider_height = menu.maxwindow ? currentWindowHeight : height;
00052             Bitu consider_width = menu.maxwindow ? currentWindowWidth : width;
00053             Bitu final_height = max(max(consider_height, userResizeWindowHeight), (Bitu)(sdl.clip.y + sdl.clip.h));
00054             Bitu final_width = max(max(consider_width, userResizeWindowWidth), (Bitu)(sdl.clip.x + sdl.clip.w));
00055             Bitu scale = 1;
00056 
00057             while ((final_width / scale) >= (640 * 2) && (final_height / scale) >= (400 * 2))
00058                 scale++;
00059 
00060             LOG_MSG("menuScale=%lu", (unsigned long)scale);
00061             mainMenu.setScale(scale);
00062         }
00063 
00064         if (mainMenu.isVisible()) menuheight = mainMenu.menuBox.h;
00065 #endif
00066 
00067         /* menu size and consideration of width and height */
00068         Bitu consider_height = height + (unsigned int)menuheight + (sdl.overscan_width * 2);
00069         Bitu consider_width = width + (sdl.overscan_width * 2);
00070 
00071         if (menu.maxwindow) {
00072             if (consider_height < currentWindowHeight)
00073                 consider_height = currentWindowHeight;
00074             if (consider_width < currentWindowWidth)
00075                 consider_width = currentWindowWidth;
00076         }
00077 
00078 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00079         if (mainMenu.isVisible())
00080         {
00081             extern unsigned int min_sdldraw_menu_width;
00082             extern unsigned int min_sdldraw_menu_height;
00083             /* enforce a minimum 500x300 surface size.
00084              * the menus are useless below 500x300 */
00085             if (consider_width < (min_sdldraw_menu_width + (sdl.overscan_width * 2)))
00086                 consider_width = (min_sdldraw_menu_width + (sdl.overscan_width * 2));
00087             if (consider_height < (min_sdldraw_menu_height + (sdl.overscan_width * 2) + (unsigned int)menuheight))
00088                 consider_height = (min_sdldraw_menu_height + (sdl.overscan_width * 2) + (unsigned int)menuheight);
00089         }
00090 #endif
00091 
00092         /* decide where the rectangle on the screen goes */
00093         int final_width,final_height;
00094 
00095 #if C_XBRZ
00096         /* scale to fit the window.
00097          * fit by aspect ratio if asked to do so. */
00098         if (sdl_xbrz.enable)
00099         {
00100             final_height = (int)max(consider_height, userResizeWindowHeight) - (int)menuheight - ((int)sdl.overscan_width * 2);
00101             final_width = (int)max(consider_width, userResizeWindowWidth) - ((int)sdl.overscan_width * 2);
00102 
00103             sdl.clip.x = sdl.clip.y = 0;
00104             sdl.clip.w = final_width;
00105             sdl.clip.h = final_height;
00106             if (render.aspect) aspectCorrectFitClip(sdl.clip.w, sdl.clip.h, sdl.clip.x, sdl.clip.y, final_width, final_height);
00107         }
00108         else
00109 #endif 
00110         /* center the screen in the window */
00111         {
00112 
00113             final_height = (int)max(max(consider_height, userResizeWindowHeight), (Bitu)(sdl.clip.y + sdl.clip.h)) - (int)menuheight - ((int)sdl.overscan_width * 2);
00114             final_width = (int)max(max(consider_width, userResizeWindowWidth), (Bitu)(sdl.clip.x + sdl.clip.w)) - ((int)sdl.overscan_width * 2);
00115             int ax = (final_width - (sdl.clip.x + sdl.clip.w)) / 2;
00116             int ay = (final_height - (sdl.clip.y + sdl.clip.h)) / 2;
00117             if (ax < 0) ax = 0;
00118             if (ay < 0) ay = 0;
00119             sdl.clip.x += ax + (int)sdl.overscan_width;
00120             sdl.clip.y += ay + (int)sdl.overscan_width;
00121             // sdl.clip.w = currentWindowWidth - sdl.clip.x;
00122             // sdl.clip.h = currentWindowHeight - sdl.clip.y;
00123         }
00124 
00125         {
00126             final_width += (int)sdl.overscan_width * 2;
00127             final_height += (int)menuheight + (int)sdl.overscan_width * 2;
00128             sdl.clip.y += (int)menuheight;
00129 
00130             LOG_MSG("surface consider=%ux%u final=%ux%u",
00131                 (unsigned int)consider_width,
00132                 (unsigned int)consider_height,
00133                 (unsigned int)final_width,
00134                 (unsigned int)final_height);
00135         }
00136 
00137         sdl.window = GFX_SetSDLWindowMode(final_width, final_height, SCREEN_SURFACE);
00138         if (sdl.window == NULL)
00139             E_Exit("Could not set windowed video mode %ix%i: %s", (int)sdl.draw.width, (int)sdl.draw.height, SDL_GetError());
00140 
00141         sdl.surface = SDL_GetWindowSurface(sdl.window);
00142         if (sdl.surface->w < (sdl.clip.x+sdl.clip.w) ||
00143             sdl.surface->h < (sdl.clip.y+sdl.clip.h)) {
00144             /* the window surface must not be smaller than the size we want!
00145              * This is a way to prevent that! */
00146             SDL_SetWindowMinimumSize(sdl.window, sdl.clip.x+sdl.clip.w, sdl.clip.y+sdl.clip.h);
00147             sdl.window = GFX_SetSDLWindowMode(sdl.clip.x+sdl.clip.w, sdl.clip.y+sdl.clip.h, SCREEN_SURFACE);
00148         }
00149     }
00150     sdl.surface = SDL_GetWindowSurface(sdl.window);
00151     if (sdl.surface == NULL)
00152         E_Exit("Could not retrieve window surface: %s", SDL_GetError());
00153     switch (sdl.surface->format->BitsPerPixel) {
00154     case 8:
00155         retFlags = GFX_CAN_8;
00156         break;
00157     case 15:
00158         retFlags = GFX_CAN_15;
00159         break;
00160     case 16:
00161         retFlags = GFX_CAN_16;
00162         break;
00163     case 32:
00164         retFlags = GFX_CAN_32;
00165         break;
00166     }
00167 
00168 #if C_XBRZ
00169     if (sdl_xbrz.enable)
00170     {
00171         bool old_scale_on = sdl_xbrz.scale_on;
00172         xBRZ_SetScaleParameters(sdl.draw.width, sdl.draw.height, sdl.clip.w, sdl.clip.h);
00173         if (sdl_xbrz.scale_on != old_scale_on) {
00174             // when we are scaling, we ask render code not to do any aspect correction
00175             // when we are not scaling, render code is allowed to do aspect correction at will
00176             // due to this, at each scale mode change we need to schedule resize again because window size could change
00177             PIC_AddEvent(VGA_SetupDrawing, 50); // schedule another resize here, render has already been initialized at this point and we have just changed its option
00178         }
00179     }
00180 #endif
00181 
00182     /* WARNING: If the user is resizing our window to smaller than what we want, SDL2 will give us a
00183      *          window surface according to the smaller size, and then we crash! */
00184     assert(sdl.surface->w >= (sdl.clip.x+sdl.clip.w));
00185     assert(sdl.surface->h >= (sdl.clip.y+sdl.clip.h));
00186 
00187     sdl.deferred_resize = false;
00188     sdl.must_redraw_all = true;
00189 
00190     /* Fix a glitch with aspect=true occuring when
00191     changing between modes with different dimensions */
00192     SDL_FillRect(sdl.surface, NULL, SDL_MapRGB(sdl.surface->format, 0, 0, 0));
00193 #if DOSBOXMENU_TYPE == DOSBOXMENU_SDLDRAW
00194     mainMenu.screenWidth = sdl.surface->w;
00195     mainMenu.screenHeight = sdl.surface->h;
00196     mainMenu.updateRect();
00197     mainMenu.setRedraw();
00198     GFX_DrawSDLMenu(mainMenu, mainMenu.display_list);
00199 #endif
00200 
00201     return retFlags;
00202 }
00203 #endif /*defined(C_SDL2)*/