diff --git a/src/dedicated/i_video.c b/src/dedicated/i_video.c index 1d784d601..062c459ed 100644 --- a/src/dedicated/i_video.c +++ b/src/dedicated/i_video.c @@ -115,6 +115,10 @@ INT32 VID_GetModeForSize(INT32 w, INT32 h) return -1; } +void VID_RefreshModeList(void) +{ +} + void VID_PrepareModeList(void) { } @@ -125,6 +129,13 @@ INT32 VID_SetMode(INT32 modeNum) return true; } +boolean I_CheckAboveDesktopRes(INT32 width, INT32 height) +{ + (void)width; + (void)height; + return false; +} + void I_StartupGraphics(void) { } diff --git a/src/i_video.h b/src/i_video.h index 9a43f82a7..d4bb659ee 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -95,6 +95,7 @@ INT32 VID_SetMode(INT32 modenum); */ const char *VID_GetModeName(INT32 modenum); +void VID_RefreshModeList(void); void VID_PrepareModeList(void); /** \brief can video system do fullscreen @@ -121,6 +122,7 @@ void I_ReadScreen(UINT8 * restrict scr, INT32 scale); UINT32 I_GetRefreshRate(void); +boolean I_CheckAboveDesktopRes(INT32 width, INT32 height); boolean I_CheckNativeRes(void); void I_SetBorderlessWindow(void); diff --git a/src/m_menu.c b/src/m_menu.c index c2978fe82..3abed5d03 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -306,7 +306,6 @@ static void M_SetupMultiHandler(INT32 choice); // Options // Split into multiple parts due to size -static void M_VideoModeMenu(INT32 choice); static void M_Setup1PControlsMenu(void); static void M_Setup2PControlsMenu(void); static void M_Setup3PControlsMenu(void); @@ -9713,14 +9712,11 @@ static void M_ResetControls(INT32 choice) // =============== //added : 30-01-98: -#define MAXCOLUMNMODES 12 //max modes displayed in one column -#define MAXMODEDESCS (MAXCOLUMNMODES*3) - static modedesc_t modedescs[MAXMODEDESCS]; -static void M_VideoModeMenu(INT32 choice) +void M_VideoModeMenu(INT32 choice) { - INT32 i, j, vdup, nummodes, width, height; + INT32 i, nummodes, width, height; const char *desc; (void)choice; @@ -9734,54 +9730,30 @@ static void M_VideoModeMenu(INT32 choice) nummodes = VID_NumModes(); // DOS does not skip mode 0, because mode 0 is ALWAYS present - i = 0; - for (; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++) + for (i = 0; i < nummodes && vidm_nummodes < MAXMODEDESCS; i++) { desc = VID_GetModeName(i); - if (desc) - { - vdup = 0; - // when a resolution exists both under VGA and VESA, keep the - // VESA mode, which is always a higher modenum - for (j = 0; j < vidm_nummodes; j++) - { - if (fastcmp(modedescs[j].desc, desc)) - { - // mode(0): 320x200 is always standard VGA, not vesa - if (modedescs[j].modenum) - { - modedescs[j].modenum = i; - vdup = 1; + if (!desc) + continue; - if (i == vid.modenum) - vidm_selected = j; - } - else - vdup = 1; + modedescs[vidm_nummodes].modenum = i; + modedescs[vidm_nummodes].desc = desc; - break; - } - } + if (i == vid.modenum) + vidm_selected = vidm_nummodes; - if (!vdup) - { - modedescs[vidm_nummodes].modenum = i; - modedescs[vidm_nummodes].desc = desc; + // Pull out the width and height + sscanf(desc, "%u%*c%u", &width, &height); - if (i == vid.modenum) - vidm_selected = vidm_nummodes; + // Show resolutions above desktop res as red. + if (I_CheckAboveDesktopRes(width, height)) + modedescs[vidm_nummodes].goodratio = 2; + // Show multiples of 320x200 as green. + else if (SCR_IsAspectCorrect(width, height)) + modedescs[vidm_nummodes].goodratio = 1; - // Pull out the width and height - sscanf(desc, "%u%*c%u", &width, &height); - - // Show multiples of 320x200 as green. - if (SCR_IsAspectCorrect(width, height)) - modedescs[vidm_nummodes].goodratio = 1; - - vidm_nummodes++; - } - } + vidm_nummodes++; } vidm_column_size = (vidm_nummodes+2) / 3; @@ -9977,7 +9949,11 @@ static void M_DrawVideoMode(void) V_DrawString(row, col, highlightflags|MENUCAPS, modedescs[i].desc); // Show multiples of 320x200 as green. else - V_DrawString(row, col, ((modedescs[i].goodratio) ? recommendedflags : 0)|MENUCAPS, modedescs[i].desc); + { + const UINT8 goodratio = modedescs[i].goodratio; + const INT32 goodflag = ((goodratio == 2) ? warningflags : (goodratio == 1) ? recommendedflags : 0); + V_DrawString(row, col, goodflag|MENUCAPS, modedescs[i].desc); + } col += 8; if ((i % vidm_column_size) == (vidm_column_size-1)) @@ -10001,7 +9977,6 @@ static void M_DrawVideoMode(void) va("Wait %d second%s", testtime, (testtime > 1) ? "s" : "")); M_CentreText(OP_VideoModeDef.y + 158, "or press ESC to return"); - } else { @@ -10017,9 +9992,26 @@ static void M_DrawVideoMode(void) V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 138, recommendedflags|MENUCAPS, "Marked modes are recommended."); V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 146, - highlightflags|MENUCAPS, "Other modes may have visual errors."); - V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 158, - highlightflags|MENUCAPS, "Larger modes may have performance issues."); + warningflags|MENUCAPS, "Marked modes are above Desktop resolution"); + + if (rendermode == render_opengl) + { +#ifdef USE_FBO_OGL + if (!cv_glframebuffer.value) +#endif + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 154, + warningflags|MENUCAPS, "and will have visual errors in OpenGL mode."); + + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 166, + highlightflags|MENUCAPS, "Other modes may have visual errors."); + } + else + { + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 154, + highlightflags|MENUCAPS, "Other modes may have visual errors."); + V_DrawCenteredString(BASEVIDWIDTH/2, OP_VideoModeDef.y + 166, + highlightflags|MENUCAPS, "Larger modes may have performance issues."); + } } // Draw the cursor for the VidMode menu diff --git a/src/m_menu.h b/src/m_menu.h index 2b048fe90..d94df99f6 100644 --- a/src/m_menu.h +++ b/src/m_menu.h @@ -223,6 +223,11 @@ extern menu_t *currentMenu; extern menu_t MainDef; extern menu_t SP_LoadDef; +#define MAXCOLUMNMODES 12 //max modes displayed in one column +#define MAXMODEDESCS (MAXCOLUMNMODES*3) +extern menu_t OP_VideoModeDef; +void M_VideoModeMenu(INT32 choice); + // Call upon joystick hotplug void M_SetupJoystickMenu(INT32 choice); extern menu_t OP_JoystickSetDef; diff --git a/src/screen.c b/src/screen.c index b292c646d..a0e884bc1 100644 --- a/src/screen.c +++ b/src/screen.c @@ -42,8 +42,8 @@ INT32 setmodeneeded = 0; // video mode change needed if > 0 (the mode number to static CV_PossibleValue_t shittyscreen_cons_t[] = {{0, "Okay"}, {1, "Shitty"}, {2, "Extra Shitty"}, {0, NULL}}; //added : 03-02-98: default screen mode, as loaded/saved in config -consvar_t cv_scr_width = {"scr_width", "1280", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; -consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_scr_width = {"scr_width", "1280", CV_SAVE|CV_CALL, CV_Unsigned, VID_RefreshModeList, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_scr_height = {"scr_height", "800", CV_SAVE|CV_CALL, CV_Unsigned, VID_RefreshModeList, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_renderview = {"renderview", "On", 0, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_frameskip = {"frameskip", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; @@ -315,8 +315,9 @@ void SCR_CheckDefaultMode(void) void SCR_SetDefaultMode(void) { // remember the default screen size - CV_SetValue(&cv_scr_width, vid.width); - CV_SetValue(&cv_scr_height, vid.height); + CV_StealthSetValue(&cv_scr_width, vid.width); + CV_StealthSetValue(&cv_scr_height, vid.height); + VID_RefreshModeList(); // probably not needed but justin käs } // Change fullscreen on/off according to cv_fullscreen diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 72354ca1e..1dcf028fb 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -84,15 +84,20 @@ #endif // maximum number of windowed modes (see windowedModes[][]) -#define MAXWINMODES (22) +#define MAXWINMODES (128) -/** \brief -*/ -static INT32 numVidModes = -1; +static void I_FillScreenResolutionsList(boolean force); -/** \brief -*/ -static char vidModeName[33][32]; // allow 33 different modes +typedef struct +{ + char name[10]; + INT32 w; + INT32 h; +} video_mode_t; + +static video_mode_t windowedModes[MAXWINMODES] = {{"320x200", 320, 200}}; // make sure the default mode exists +static const char *fallback_resolution_name = "Fallback"; +static int vid_nummodes = 1; rendermode_t rendermode = render_none; @@ -139,9 +144,6 @@ static SDL_bool disable_mouse = SDL_FALSE; #define MOUSE_MENU false //(!disable_mouse && cv_usemouse.value && menuactive && !USE_FULLSCREEN) #define MOUSEBUTTONS_MAX MOUSEBUTTONS -// first entry in the modelist which is not bigger than MAXVIDWIDTHxMAXVIDHEIGHT -static INT32 firstEntry = 0; - // Total mouse motion X/Y offsets static INT32 mousemovex = 0, mousemovey = 0; @@ -162,38 +164,6 @@ static SDL_Texture *texture = NULL; static SDL_GLContext sdlglcontext = NULL; #endif static SDL_bool havefocus = SDL_TRUE; -static const char *fallback_resolution_name = "Fallback"; - -// windowed video modes from which to choose from. -static INT32 windowedModes[MAXWINMODES][2] = -{ - {2560,1440}, // 1.66 - {1920,1200}, // 1.60,6.00 - {1920,1080}, // 1.66 - {1680,1050}, // 1.60,5.25 - {1600,1200}, // 1.33 - {1600, 900}, // 1.66 - {1366, 768}, // 1.66 - {1440, 900}, // 1.60,4.50 - {1280,1024}, // 1.33? - {1280, 960}, // 1.33,4.00 - {1280, 800}, // 1.60,4.00 - {1280, 720}, // 1.66 - {1152, 864}, // 1.33,3.60 - {1024, 768}, // 1.33,3.20 - { 960, 600}, // 1.33,3.20 - { 800, 600}, // 1.33,2.50 - { 735, 415}, // 1.33,2.50 - { 640, 480}, // 1.33,2.00 - { 640, 400}, // 1.60,2.00 - { 500, 300}, // 1.33 - { 320, 240}, // 1.33,1.00 - { 320, 200}, // 1.60,1.00 -}; - -#define CUSTOMMODENUM 9999 -static INT32 custom_width = 0; -static INT32 custom_height = 0; static SDL_bool Impl_CreateWindow(SDL_bool fullscreen); static void Impl_SetWindowIcon(void); @@ -519,11 +489,20 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) return; } - if (windowmoved && rendermode == render_opengl) + if (windowmoved) { I_CheckDesktopRes(); + + // if we say moved our game window to a different screen + // refetch our resolutions + I_FillScreenResolutionsList(false); +#ifdef HWRENDER #ifdef USE_FBO_OGL - I_DownSample(); + if (rendermode == render_opengl) + { + I_DownSample(); + } +#endif #endif windowmoved = SDL_FALSE; } @@ -540,7 +519,8 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) if (!firsttimeonmouse) { - if (cv_usemouse.value) I_StartupMouse(); + if (cv_usemouse.value) + I_StartupMouse(); } } else if (!mousefocus && !kbfocus) @@ -1222,9 +1202,9 @@ static void VID_Command_ModeList_f(void) "Under opengl, fullscreen only supports native desktop resolution.\n" "Under software, the mode is stretched up to desktop resolution.\n"); - for (i = 0; i < MAXWINMODES; i++) + for (i = 0; i < vid_nummodes; i++) { - CONS_Printf("%2d: %dx%d\n", i, windowedModes[i][0], windowedModes[i][1]); + CONS_Printf("%2d: %dx%d\n", i, windowedModes[i].w, windowedModes[i].h); } } @@ -1263,7 +1243,7 @@ static void I_CheckDesktopRes(void) return; } - if (SDL_GetDesktopDisplayMode(currentDisplayIndex, &curmode) != 0) + if (SDL_GetCurrentDisplayMode(currentDisplayIndex, &curmode) != 0) { return; } @@ -1278,6 +1258,11 @@ boolean I_CheckNativeRes(void) return (vid.width == desktopwidth && vid.height == desktopheight); } +boolean I_CheckAboveDesktopRes(INT32 width, INT32 height) +{ + return (width > desktopwidth || height > desktopheight); +} + #ifdef USE_FBO_OGL void RefreshOGLSDLSurface(void) @@ -1508,13 +1493,207 @@ void I_SetPalette(RGBA_t *palette) } } +// make sure the canonical resolutions are always available +static const struct { + const int w, h; +} canonicals[] = { + {1920, 1200}, // 16:10 + {1280, 800}, // 16:10 + { 960, 600}, // 16:10 + { 640, 400}, // 16:10 + { 320, 200}, // Vanilla Doom +}; +static const int num_canonicals = sizeof(canonicals)/sizeof(*canonicals); + +// [FG] sort resolutions by width first and height second +static int cmp_resolutions(const void *a, const void *b) +{ + const video_mode_t *ma = (const video_mode_t *) a; + const video_mode_t *mb = (const video_mode_t *) b; + + return (ma->w == mb->w) ? mb->h - ma->h : mb->w - ma->w; +} + +static void I_AppendResolution(SDL_DisplayMode *mode, int *list_size) +{ + int i; + + for (i = 0; i < *list_size; i++) + if (windowedModes[i].w == mode->w + && windowedModes[i].h == mode->h) + return; + + snprintf(windowedModes[*list_size].name, + sizeof(windowedModes[*list_size].name), + "%dx%d", mode->w, mode->h); + windowedModes[*list_size].w = mode->w; + windowedModes[*list_size].h = mode->h; + + (*list_size)++; +} + +// small helper to check if a video mode is canonical +static boolean IsModeCanonical(int w, int h) +{ + for (int i = 0; i < num_canonicals; i++) + { + if (canonicals[i].w == w && canonicals[i].h == h) + return true; + } + + return false; +} + +// check if our desired resolution already is in the videomode list +static int IsCustomResolutionInList(int list_size) +{ + INT32 custom_w = cv_scr_width.value; + INT32 custom_h = cv_scr_height.value; + + // startup + if (!custom_w || !custom_h) + return -2; + + // invalid resolution + // dont even attempt to add it + if (custom_w < BASEVIDWIDTH || custom_w > MAXVIDWIDTH + || custom_h < BASEVIDHEIGHT || custom_h > MAXVIDHEIGHT) + return -1; + + for (int i = 0; i < list_size; i++) + { + if (windowedModes[i].w == custom_w && windowedModes[i].h == custom_h) + { + return 1; + } + } + + return 0; +} + +// +// I_FillScreenResolutionsList +// Get all the supported screen resolutions +// and fill the list with them +// +static void I_FillScreenResolutionsList(boolean force) +{ + int currentDisplayIndex = -1; + static int oldDisplayIndex = -1; + SDL_DisplayMode mode; + int i = 0, list_size = 0; + int count = 0; + char custom_resolution[10]; + + currentDisplayIndex = SDL_GetWindowDisplayIndex(window); + + // No valid index + if (currentDisplayIndex < 0) + { + return; + } + + // didnt change screen, no need to redo the list + if (!force && currentDisplayIndex == oldDisplayIndex) + { + return; + } + + oldDisplayIndex = currentDisplayIndex; + + // Don't call SDL_ListModes if SDL has not been initialized + count = SDL_GetNumDisplayModes(currentDisplayIndex); + + list_size = 0; + + // on success, SDL_GetNumDisplayModes() always returns at least 1 + if (count > 0) + { + // -2 for the desired resolution and for NULL + count = min(count, MAXWINMODES - 2 - num_canonicals); + + for (i = count - 1 + num_canonicals; i >= 0; i--) + { + // make sure the canonical resolutions are always available + if (i > count - 1) + { + mode.w = canonicals[i - count].w; + mode.h = canonicals[i - count].h; + } + else + { + SDL_GetDisplayMode(currentDisplayIndex, i, &mode); + } + + I_AppendResolution(&mode, &list_size); + } + + windowedModes[list_size].name[0] = '\0'; + } + + const int customresinlist = IsCustomResolutionInList(list_size); + + if (customresinlist == 0) + { + // did not find mode from list, make custom resolution if the values somewhat make sense + if (list_size < MAXWINMODES) + { + snprintf(custom_resolution, sizeof(custom_resolution), "%dx%d", cv_scr_width.value, cv_scr_height.value); + + // [FG] if the desired resolution not in the list, append it + snprintf(windowedModes[list_size].name, + sizeof(windowedModes[list_size].name), + "%dx%d", cv_scr_width.value, cv_scr_height.value); + windowedModes[list_size].w = cv_scr_width.value; + windowedModes[list_size].h = cv_scr_height.value; + list_size++; + } + else + CONS_Alert(CONS_ERROR, "Could not set custom resolution!\n"); + } + else if (customresinlist == -1) + CONS_Alert(CONS_ERROR, "Could not set custom resolution!\n"); + + // [FG] sort the list + SDL_qsort(windowedModes, list_size, sizeof(*windowedModes), cmp_resolutions); + + // if we have more video modes than we can list + // try to shrink the list, lowest resolutions first + // whilst keeping the canonicals + if (list_size > MAXMODEDESCS) + { + // list is sorted from largest to smallest, so start at the end + for (i = list_size - 1; i >= 0 && list_size > MAXMODEDESCS; i--) + { + if (IsModeCanonical(windowedModes[i].w, windowedModes[i].h)) + continue; + + // Should we like, instead prioritize checking for non aspect correct resolutions to remove? + + // we gotta shift everything + // due to canonicals we cant just shrink the list + for (int k = i; k < list_size - 1; k++) + { + windowedModes[k] = windowedModes[k + 1]; + } + + list_size--; + } + } + + windowedModes[list_size].name[0] = '\0'; + vid_nummodes = list_size; + + // be sure to update the video menu + if (menuactive && + currentMenu == &OP_VideoModeDef) + M_VideoModeMenu(0); +} + // return number of fullscreen + X11 modes INT32 VID_NumModes(void) { - if (USE_FULLSCREEN && numVidModes != -1) - return numVidModes - firstEntry; - else - return MAXWINMODES; + return vid_nummodes; } const char *VID_GetModeName(INT32 modeNum) @@ -1524,42 +1703,34 @@ const char *VID_GetModeName(INT32 modeNum) return fallback_resolution_name; } - if (modeNum > MAXWINMODES) + if (modeNum > vid_nummodes) return NULL; - sprintf(&vidModeName[modeNum][0], "%dx%d", - windowedModes[modeNum][0], - windowedModes[modeNum][1]); - - return &vidModeName[modeNum][0]; + return windowedModes[modeNum].name; } INT32 VID_GetModeForSize(INT32 w, INT32 h) { int i; - for (i = 0; i < MAXWINMODES; i++) + for (i = 0; i < vid_nummodes; i++) { - if (windowedModes[i][0] == w && windowedModes[i][1] == h) + if (windowedModes[i].w == w && windowedModes[i].h == h) { return i; } } - // did not find mode from list, make custom resolution if the values somewhat make sense - // opengl mode does not mind about max resolution defined in screen.h - // if not using opengl, check against the maximum as well - if ((w >= BASEVIDWIDTH && h >= BASEVIDHEIGHT) && - (rendermode == render_opengl || (w <= MAXVIDWIDTH && h <= MAXVIDHEIGHT))) - { - custom_width = w; - custom_height = h; - return CUSTOMMODENUM; - } - return -1; } +void VID_RefreshModeList(void) +{ + // check if we even need to rebuild the list + if (IsCustomResolutionInList(vid_nummodes) == 0) + I_FillScreenResolutionsList(true); +} + void VID_PrepareModeList(void) { // Under SDL2, we just use the windowed modes list, and scale in windowed fullscreen. @@ -1591,17 +1762,10 @@ INT32 VID_SetMode(INT32 modeNum) { vid.recalc = true; - if (modeNum >= 0 && modeNum < MAXWINMODES) + if (modeNum >= 0 && modeNum < vid_nummodes) { - vid.width = windowedModes[modeNum][0]; - vid.height = windowedModes[modeNum][1]; - vid.modenum = modeNum; - } - else if (modeNum == CUSTOMMODENUM && custom_width && custom_height) - { - // at this point these values are assumed to be okay - vid.width = custom_width; - vid.height = custom_height; + vid.width = windowedModes[modeNum].w; + vid.height = windowedModes[modeNum].h; vid.modenum = modeNum; } else @@ -1634,7 +1798,6 @@ INT32 VID_SetMode(INT32 modeNum) return SDL_TRUE; } - static SDL_bool Impl_CreateContext(void) { // Renderer-specific stuff @@ -1657,6 +1820,9 @@ static SDL_bool Impl_CreateContext(void) I_Error("Failed to set up GL context: %s\n", SDL_GetError()); } + // be sure to fill the resolution list the moment we have a window + I_FillScreenResolutionsList(false); + return SDL_TRUE; } #endif @@ -1698,6 +1864,9 @@ static SDL_bool Impl_CreateContext(void) SDL_RenderSetLogicalSize(renderer, BASEVIDWIDTH, BASEVIDHEIGHT); + // be sure to fill the resolution list the moment we have a window + I_FillScreenResolutionsList(false); + return SDL_TRUE; } @@ -1935,8 +2104,6 @@ void I_StartupGraphics(void) usesdl2soft = M_CheckParm("-softblit"); borderlesswindow = M_CheckParm("-borderless"); - VID_Command_ModeList_f(); - #ifdef HWRENDER if (rendermode == render_opengl) { @@ -1960,6 +2127,9 @@ void I_StartupGraphics(void) vid.height = BASEVIDHEIGHT; // BitsPerPixel is the SDL interface's vid.recalc = true; // Set up the console stufff + // be sure to print AFTER window creation + VID_Command_ModeList_f(); + #ifdef HAVE_TTF I_ShutdownTTF(); #endif