From 144f44c523edfab569e960288dd6d84ad7f4d5f4 Mon Sep 17 00:00:00 2001 From: divverent Date: Wed, 5 Aug 2009 12:55:45 +0000 Subject: [PATCH] glx, sdl, wgl: autodetect all supported video modes, override the Quake menu's list by it git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@9089 d7cf8633-e32d-0410-b094-e92efae38249 --- menu.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++---- menu.h | 3 +- vid.h | 9 ++++ vid_agl.c | 5 ++ vid_glx.c | 34 +++++++++++++ vid_null.c | 5 ++ vid_sdl.c | 23 +++++++++ vid_shared.c | 57 ++++++++++++++++++++++ vid_wgl.c | 28 +++++++++++ 9 files changed, 286 insertions(+), 9 deletions(-) diff --git a/menu.c b/menu.c index 7417844b..661ad7b9 100644 --- a/menu.c +++ b/menu.c @@ -2729,8 +2729,7 @@ static void M_Reset_Draw (void) //============================================================================= /* VIDEO MENU */ -// note: if modes are added to the beginning of this list, update VID_DEFAULT -video_resolution_t video_resolutions[] = +static video_resolution_t video_resolutions_hardcoded[] = { {"Standard 4x3" , 320, 240, 320, 240, 1 }, {"Standard 4x3" , 400, 300, 400, 300, 1 }, @@ -2791,14 +2790,15 @@ video_resolution_t video_resolutions[] = {NULL, 0, 0, 0, 0, 0} }; // this is the number of the default mode (640x480) in the list above -#define VID_DEFAULT 3 -#define VID_RES_COUNT ((int)(sizeof(video_resolutions) / sizeof(video_resolutions[0])) - 1) #define VIDEO_ITEMS 11 static int video_cursor = 0; static int video_cursor_table[VIDEO_ITEMS] = {68, 88, 96, 104, 112, 120, 128, 136, 144, 152, 168}; static int video_resolution; +video_resolution_t *video_resolutions; +int video_resolutions_count; + void M_Menu_Video_f (void) { int i; @@ -2809,7 +2809,7 @@ void M_Menu_Video_f (void) // Look for the closest match to the current resolution video_resolution = 0; - for (i = 1;i < VID_RES_COUNT;i++) + for (i = 1;i < video_resolutions_count;i++) { // if the new mode would be a worse match in width, skip it if (fabs(video_resolutions[i].width - vid.width) > fabs(video_resolutions[video_resolution].width - vid.width)) @@ -2927,13 +2927,13 @@ static void M_Menu_Video_AdjustSliders (int dir) { // Resolution int r; - for(r = 0;r < VID_RES_COUNT;r++) + for(r = 0;r < video_resolutions_count;r++) { video_resolution += dir; - if (video_resolution >= VID_RES_COUNT) + if (video_resolution >= video_resolutions_count) video_resolution = 0; if (video_resolution < 0) - video_resolution = VID_RES_COUNT - 1; + video_resolution = video_resolutions_count - 1; if (video_resolutions[video_resolution].width >= vid_minwidth.integer && video_resolutions[video_resolution].height >= vid_minheight.integer) break; } @@ -4672,6 +4672,121 @@ static void M_Shutdown(void); void M_Init (void) { + vid_mode_t res[1024]; + size_t res_count, i; + + res_count = VID_ListModes(res, sizeof(res) / sizeof(*res)); + res_count = VID_SortModes(res, res_count, false, false, true); + if(res_count) + { + video_resolutions_count = res_count; + video_resolutions = (video_resolution_t *) Mem_Alloc(cls.permanentmempool, sizeof(*video_resolutions) * (video_resolutions_count + 1)); + memset(&video_resolutions[video_resolutions_count], 0, sizeof(video_resolutions[video_resolutions_count])); + for(i = 0; i < res_count; ++i) + { + int n, d, t; + video_resolutions[i].type = "Detected mode"; // FIXME make this more dynamic + video_resolutions[i].width = res[i].width; + video_resolutions[i].height = res[i].height; + video_resolutions[i].pixelheight = res[i].pixelheight_num / (double) res[i].pixelheight_denom; + n = res[i].pixelheight_denom * video_resolutions[i].width; + d = res[i].pixelheight_num * video_resolutions[i].height; + while(d) + { + t = n; + n = d; + d = t % d; + } + d = (res[i].pixelheight_num * video_resolutions[i].height) / n; + n = (res[i].pixelheight_denom * video_resolutions[i].width) / n; + switch(n * 0x10000 | d) + { + case 0x00040003: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "Standard 4x3"; + break; + case 0x00050004: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 512; + if(res[i].pixelheight_denom == res[i].pixelheight_num) + video_resolutions[i].type = "Square Pixel (LCD) 5x4"; + else + video_resolutions[i].type = "Short Pixel (CRT) 5x4"; + break; + case 0x00080005: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 400; + if(res[i].pixelheight_denom == res[i].pixelheight_num) + video_resolutions[i].type = "Widescreen 8x5"; + else + video_resolutions[i].type = "Tall Pixel (CRT) 8x5"; + + break; + case 0x00050003: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 384; + video_resolutions[i].type = "Widescreen 5x3"; + break; + case 0x000D0009: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 400; + video_resolutions[i].type = "Widescreen 14x9"; + break; + case 0x00100009: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "Widescreen 16x9"; + break; + case 0x00030002: + video_resolutions[i].conwidth = 720; + video_resolutions[i].conheight = 480; + video_resolutions[i].type = "NTSC 3x2"; + break; + case 0x000D000B: + video_resolutions[i].conwidth = 720; + video_resolutions[i].conheight = 566; + video_resolutions[i].type = "PAL 14x11"; + break; + case 0x00080007: + if(video_resolutions[i].width >= 512) + { + video_resolutions[i].conwidth = 512; + video_resolutions[i].conheight = 448; + video_resolutions[i].type = "SNES 8x7"; + } + else + { + video_resolutions[i].conwidth = 256; + video_resolutions[i].conheight = 224; + video_resolutions[i].type = "NES 8x7"; + } + break; + default: + video_resolutions[i].conwidth = 640; + video_resolutions[i].conheight = 640 * d / n; + video_resolutions[i].type = "Detected mode"; + break; + } + if(video_resolutions[i].conwidth > video_resolutions[i].width || video_resolutions[i].conheight > video_resolutions[i].height) + { + double f1, f2; + f1 = video_resolutions[i].conwidth > video_resolutions[i].width; + f2 = video_resolutions[i].conheight > video_resolutions[i].height; + if(f1 > f2) + { + video_resolutions[i].conwidth = video_resolutions[i].width; + video_resolutions[i].conheight = video_resolutions[i].conheight / f1; + } + else + { + video_resolutions[i].conwidth = video_resolutions[i].conwidth / f2; + video_resolutions[i].conheight = video_resolutions[i].height; + } + } + } + } + menuplyr_load = true; menuplyr_pixels = NULL; diff --git a/menu.h b/menu.h index dd7eed7f..7ca77ef3 100644 --- a/menu.h +++ b/menu.h @@ -93,6 +93,7 @@ typedef struct video_resolution_s double pixelheight; ///< pixel aspect } video_resolution_t; -extern video_resolution_t video_resolutions[]; +extern video_resolution_t *video_resolutions; +extern int video_resolutions_count; #endif diff --git a/vid.h b/vid.h index 5ffbdd7b..ff9cddc8 100644 --- a/vid.h +++ b/vid.h @@ -156,5 +156,14 @@ void VID_Start(void); extern unsigned int vid_gammatables_serial; // so other subsystems can poll if gamma parameters have changed; this starts with 0 and gets increased by 1 each time the gamma parameters get changed and VID_BuildGammaTables should be called again extern qboolean vid_gammatables_trivial; // this is set to true if all color control values are at default setting, and it therefore would make no sense to use the gamma table void VID_BuildGammaTables(unsigned short *ramps, int rampsize); // builds the current gamma tables into an array (needs 3*rampsize items) + +typedef struct +{ + int width, height, bpp, refreshrate; + int pixelheight_num, pixelheight_denom; +} +vid_mode_t; +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount); +size_t VID_SortModes(vid_mode_t *modes, size_t count, qboolean usebpp, qboolean userefreshrate, qboolean useaspect); #endif diff --git a/vid_agl.c b/vid_agl.c index 4b2e02b1..97c36dbf 100644 --- a/vid_agl.c +++ b/vid_agl.c @@ -1121,3 +1121,8 @@ void Sys_SendKeyEvents(void) void IN_Move (void) { } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + return 0; // FIXME implement this +} diff --git a/vid_glx.c b/vid_glx.c index d08bab4b..e1023fdc 100644 --- a/vid_glx.c +++ b/vid_glx.c @@ -1078,3 +1078,37 @@ void Sys_SendKeyEvents(void) void IN_Move (void) { } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + if(vidmode_ext) + { + int i, bpp; + size_t k; + XF86VidModeModeInfo **vidmodes; + int num_vidmodes; + + XF86VidModeGetAllModeLines(vidx11_display, vidx11_screen, &num_vidmodes, &vidmodes); + k = 0; + for (i = 0; i < num_vidmodes; i++) + { + if(k >= maxcount) + break; + // we don't get bpp info, so let's just assume all of 8, 15, 16, 24, 32 work + for(bpp = 8; bpp <= 32; bpp = ((bpp == 8) ? 15 : (bpp & 0xF8) + 8)) + { + if(k >= maxcount) + break; + modes[k].width = vidmodes[i]->hdisplay; + modes[k].height = vidmodes[i]->vdisplay; + modes[k].bpp = 8; + modes[k].refreshrate = vidmodes[i]->dotclock / vidmodes[i]->htotal / vidmodes[i]->vtotal; + modes[k].pixelheight_num = 1; + modes[k].pixelheight_denom = 1; // xvidmode does not provide this + ++k; + } + } + return k; + } + return 0; // FIXME implement this +} diff --git a/vid_null.c b/vid_null.c index bade6d07..4313d9dc 100644 --- a/vid_null.c +++ b/vid_null.c @@ -91,3 +91,8 @@ void Sys_SendKeyEvents(void) void IN_Move(void) { } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + return 0; +} diff --git a/vid_sdl.c b/vid_sdl.c index 56d1ad61..fe1a3605 100644 --- a/vid_sdl.c +++ b/vid_sdl.c @@ -808,3 +808,26 @@ void VID_Finish (void) SDL_GL_SwapBuffers(); } } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + int i; + size_t k; + SDL_Rect **vidmodes; + int bpp = SDL_GetVideoInfo()->vfmt->BitsPerPixel; + + k = 0; + for(vidmodes = SDL_ListModes(NULL, SDL_FULLSCREEN|SDL_HWSURFACE); *vidmodes; ++vidmodes) + { + if(k >= maxcount) + break; + modes[k].width = vidmodes[i]->w; + modes[k].height = vidmodes[i]->h; + modes[k].bpp = bpp; + modes[k].refreshrate = 60; // no support for refresh rate in SDL + modes[k].pixelheight_num = 1; + modes[k].pixelheight_denom = 1; // SDL does not provide this + ++k; + } + return k; +} diff --git a/vid_shared.c b/vid_shared.c index 2b5ea935..daf9b045 100644 --- a/vid_shared.c +++ b/vid_shared.c @@ -1267,3 +1267,60 @@ void VID_Start(void) VID_OpenSystems(); } +int VID_SortModes_Compare(void *a_, void *b_) +{ + vid_mode_t *a = (vid_mode_t *) a_; + vid_mode_t *b = (vid_mode_t *) b_; + if(a->width > b->width) + return +1; + if(a->width < b->width) + return -1; + if(a->height > b->height) + return +1; + if(a->height < b->height) + return -1; + if(a->refreshrate > b->refreshrate) + return +1; + if(a->refreshrate < b->refreshrate) + return -1; + if(a->bpp > b->bpp) + return +1; + if(a->bpp < b->bpp) + return -1; + if(a->pixelheight_num * b->pixelheight_denom > a->pixelheight_denom * b->pixelheight_num) + return +1; + if(a->pixelheight_num * b->pixelheight_denom < a->pixelheight_denom * b->pixelheight_num) + return -1; + return 0; +} +size_t VID_SortModes(vid_mode_t *modes, size_t count, qboolean usebpp, qboolean userefreshrate, qboolean useaspect) +{ + size_t i; + if(count == 0) + return; + // 1. sort them + qsort(modes, count, sizeof(*modes), VID_SortModes_Compare); + // 2. remove duplicates + for(i = 1; i < count; ++i) + { + if(modes[i].width != modes[i-1].width) + continue; + if(modes[i].height != modes[i-1].height) + continue; + if(userefreshrate) + if(modes[i].refreshrate != modes[i-1].refreshrate) + continue; + if(usebpp) + if(modes[i].bpp != modes[i-1].bpp) + continue; + if(useaspect) + if(modes[i].pixelheight_num * modes[i-1].pixelheight_denom != modes[i].pixelheight_denom * modes[i-1].pixelheight_num) + continue; + // a dupe! + if(i < count-1) + memmove(&modes[i], &modes[i+1], sizeof(*modes) * (count-1 - i)); + --i; // check this index again, as mode i+1 is now here + --count; + } + return count; +} diff --git a/vid_wgl.c b/vid_wgl.c index c714e0eb..e6cb7002 100644 --- a/vid_wgl.c +++ b/vid_wgl.c @@ -2068,3 +2068,31 @@ static void IN_Shutdown(void) g_pdi = NULL; #endif } + +size_t VID_ListModes(vid_mode_t *modes, size_t maxcount) +{ + int i, k; + DEVMODE thismode; + + thismode.dmSize = sizeof(thismode); + thismode.dmDriverExtra = 0; + k = 0; + for(i = 0; EnumDisplaySettings(NULL, i, &thismode); ++i) + { + if(~thismode.dmFields & (DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY)) + { + Con_DPrintf("enumerating modes yielded a bogus item... please debug this\n"); + continue; + } + if(k >= maxcount) + break; + modes[k].width = thismode.dmPelsWidth; + modes[k].height = thismode.dmPelsHeight; + modes[k].bpp = thismode.dmBitsPerPixel; + modes[k].refreshrate = thismode.dmDisplayFrequency; + modes[k].pixelheight_num = 1; + modes[k].pixelheight_denom = 1; // Win32 apparently does not provide this (FIXME) + ++k; + } + return k; +} -- 2.39.2