ref: 6528c14df3fa13bd3d5aed1e715205975b724f14
dir: /src/setup/display.c/
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright(C) 2006 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
// 02111-1307, USA.
//
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32_WCE
#include "libc_wince.h"
#endif
#include "textscreen.h"
#include "m_config.h"
#include "mode.h"
#include "display.h"
typedef struct
{
int w, h;
} screen_mode_t;
// List of aspect ratio-uncorrected modes
static screen_mode_t screen_modes_unscaled[] =
{
{ 320, 200 },
{ 640, 400 },
{ 960, 600 },
{ 1280, 800 },
{ 1600, 1000 },
{ 0, 0},
};
// List of aspect ratio-corrected modes
static screen_mode_t screen_modes_scaled[] =
{
{ 256, 200 },
{ 320, 240 },
{ 512, 400 },
{ 640, 480 },
{ 800, 600 },
{ 960, 720 },
{ 1024, 800 },
{ 1280, 960 },
{ 1280, 1000 },
{ 1600, 1200 },
{ 0, 0},
};
// List of fullscreen modes generated at runtime
static screen_mode_t *screen_modes_fullscreen = NULL;
static int vidmode = 0;
static char *video_driver = "";
static int autoadjust_video_settings = 1;
static int aspect_ratio_correct = 1;
static int fullscreen = 1;
static int screen_width = 320;
static int screen_height = 200;
static int startup_delay = 1000;
static int graphical_startup = 1;
static int show_endoom = 1;
static int usegamma = 0;
// These are the last screen width/height values that were chosen by the
// user. These are used when finding the "nearest" mode, so when
// changing the fullscreen / aspect ratio options, the setting does not
// jump around.
static int selected_screen_width = 0, selected_screen_height;
static int system_video_env_set;
// Set the SDL_VIDEODRIVER environment variable
void SetDisplayDriver(void)
{
static int first_time = 1;
if (first_time)
{
system_video_env_set = getenv("SDL_VIDEODRIVER") != NULL;
first_time = 0;
}
// Don't override the command line environment, if it has been set.
if (system_video_env_set)
{
return;
}
// Use the value from the configuration file, if it has been set.
if (strcmp(video_driver, "") != 0)
{
char *env_string;
env_string = malloc(strlen(video_driver) + 30);
sprintf(env_string, "SDL_VIDEODRIVER=%s", video_driver);
putenv(env_string);
free(env_string);
}
else
{
#if defined(_WIN32) && !defined(_WIN32_WCE)
// On Windows, use DirectX over windib by default.
putenv("SDL_VIDEODRIVER=directx");
#endif
}
}
static void ModeSelected(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(mode))
{
TXT_CAST_ARG(screen_mode_t, mode);
screen_width = mode->w;
screen_height = mode->h;
// This is now the most recently selected screen width
selected_screen_width = screen_width;
selected_screen_height = screen_height;
}
static int GoodFullscreenMode(screen_mode_t *mode)
{
int w, h;
w = mode->w;
h = mode->h;
// 320x200 and 640x400 are always good (special case)
if ((w == 320 && h == 200) || (w == 640 && h == 400))
{
return 1;
}
// Special case: 320x240 letterboxed mode is okay (but not aspect
// ratio corrected 320x240)
if (w == 320 && h == 240 && !aspect_ratio_correct)
{
return 1;
}
// Ignore all modes less than 640x480
return w >= 640 && h >= 480;
}
// Build screen_modes_fullscreen
static void BuildFullscreenModesList(void)
{
SDL_Rect **modes;
screen_mode_t *m1;
screen_mode_t *m2;
screen_mode_t m;
int num_modes;
int i;
// Free the existing modes list, if one exists
if (screen_modes_fullscreen != NULL)
{
free(screen_modes_fullscreen);
}
// Get a list of fullscreen modes and find out how many
// modes are in the list.
modes = SDL_ListModes(NULL, SDL_FULLSCREEN);
if (modes == NULL || modes == (SDL_Rect **) -1)
{
num_modes = 0;
}
else
{
for (num_modes=0; modes[num_modes] != NULL; ++num_modes);
}
// Build the screen_modes_fullscreen array
screen_modes_fullscreen = malloc(sizeof(screen_mode_t) * (num_modes + 1));
for (i=0; i<num_modes; ++i)
{
screen_modes_fullscreen[i].w = modes[i]->w;
screen_modes_fullscreen[i].h = modes[i]->h;
}
screen_modes_fullscreen[i].w = 0;
screen_modes_fullscreen[i].h = 0;
// Reverse the order of the modes list (smallest modes first)
for (i=0; i<num_modes / 2; ++i)
{
m1 = &screen_modes_fullscreen[i];
m2 = &screen_modes_fullscreen[num_modes - 1 - i];
memcpy(&m, m1, sizeof(screen_mode_t));
memcpy(m1, m2, sizeof(screen_mode_t));
memcpy(m2, &m, sizeof(screen_mode_t));
}
}
static int FindBestMode(screen_mode_t *modes)
{
int i;
int best_mode;
int best_mode_diff;
int diff;
best_mode = -1;
best_mode_diff = 0;
for (i=0; modes[i].w != 0; ++i)
{
if (fullscreen && !GoodFullscreenMode(&modes[i]))
{
continue;
}
diff = (selected_screen_width - modes[i].w)
* (selected_screen_width - modes[i].w)
+ (selected_screen_height - modes[i].h)
* (selected_screen_height - modes[i].h);
if (best_mode == -1 || diff < best_mode_diff)
{
best_mode_diff = diff;
best_mode = i;
}
}
return best_mode;
}
static void GenerateModesTable(TXT_UNCAST_ARG(widget),
TXT_UNCAST_ARG(modes_table))
{
TXT_CAST_ARG(txt_table_t, modes_table);
char buf[15];
screen_mode_t *modes;
txt_radiobutton_t *rbutton;
int i;
// Pick which modes list to use
if (fullscreen)
{
if (screen_modes_fullscreen == NULL)
{
BuildFullscreenModesList();
}
modes = screen_modes_fullscreen;
}
else if (aspect_ratio_correct)
{
modes = screen_modes_scaled;
}
else
{
modes = screen_modes_unscaled;
}
// Build the table
TXT_ClearTable(modes_table);
TXT_SetColumnWidths(modes_table, 15, 15, 15);
for (i=0; modes[i].w != 0; ++i)
{
// Skip bad fullscreen modes
if (fullscreen && !GoodFullscreenMode(&modes[i]))
{
continue;
}
sprintf(buf, "%ix%i", modes[i].w, modes[i].h);
rbutton = TXT_NewRadioButton(buf, &vidmode, i);
TXT_AddWidget(modes_table, rbutton);
TXT_SignalConnect(rbutton, "selected", ModeSelected, &modes[i]);
}
// Find the nearest mode in the list that matches the current
// settings
vidmode = FindBestMode(modes);
screen_width = modes[vidmode].w;
screen_height = modes[vidmode].h;
}
#if defined(_WIN32) && !defined(_WIN32_WCE)
static int win32_video_driver = 0;
static char *win32_video_drivers[] =
{
"DirectX",
"Windows GDI",
};
// Restart the textscreen library. Used when the video_driver variable
// is changed.
static void RestartTextscreen(void)
{
TXT_Shutdown();
SetDisplayDriver();
TXT_Init();
}
static void SetWin32VideoDriver(void)
{
if (!strcmp(video_driver, "windib"))
{
win32_video_driver = 1;
}
else
{
win32_video_driver = 0;
}
}
static void UpdateVideoDriver(TXT_UNCAST_ARG(widget),
TXT_UNCAST_ARG(modes_table))
{
TXT_CAST_ARG(txt_table_t, modes_table);
char *drivers[] =
{
"",
"windib",
};
video_driver = drivers[win32_video_driver != 0];
// When the video driver is changed, we need to restart the textscreen
// library.
RestartTextscreen();
// Rebuild the video modes list
BuildFullscreenModesList();
GenerateModesTable(NULL, modes_table);
}
#endif
void ConfigDisplay(void)
{
txt_window_t *window;
txt_table_t *modes_table;
txt_checkbox_t *fs_checkbox;
txt_checkbox_t *ar_checkbox;
// First time in? Initialise selected_screen_{width,height}
if (selected_screen_width == 0)
{
selected_screen_width = screen_width;
selected_screen_height = screen_height;
}
// Open the window
window = TXT_NewWindow("Display Configuration");
TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP,
TXT_SCREEN_W / 2, 5);
TXT_AddWidgets(window,
fs_checkbox = TXT_NewCheckBox("Fullscreen", &fullscreen),
ar_checkbox = TXT_NewCheckBox("Correct aspect ratio",
&aspect_ratio_correct),
NULL);
modes_table = TXT_NewTable(3);
// On Windows, there is an extra control to change between
// the Windows GDI and DirectX video drivers.
#if defined(_WIN32) && !defined(_WIN32_WCE)
{
txt_table_t *driver_table;
txt_dropdown_list_t *driver_list;
driver_table = TXT_NewTable(2);
TXT_SetColumnWidths(driver_table, 20, 0);
TXT_AddWidgets(driver_table,
TXT_NewLabel("Video driver"),
driver_list = TXT_NewDropdownList(&win32_video_driver,
win32_video_drivers,
2),
NULL);
TXT_SignalConnect(driver_list, "changed",
UpdateVideoDriver, modes_table);
SetWin32VideoDriver();
TXT_AddWidget(window, driver_table);
}
#endif
// Screen modes list
TXT_AddWidgets(window,
TXT_NewSeparator("Screen mode"),
modes_table,
TXT_NewSeparator("Misc."),
NULL);
if (gamemission == heretic || gamemission == hexen)
{
TXT_AddWidget(window,
TXT_NewCheckBox("Graphical startup", &graphical_startup));
}
if (gamemission == doom || gamemission == heretic)
{
TXT_AddWidget(window,
TXT_NewCheckBox("Show ENDOOM screen", &show_endoom));
}
TXT_SignalConnect(fs_checkbox, "changed", GenerateModesTable, modes_table);
TXT_SignalConnect(ar_checkbox, "changed", GenerateModesTable, modes_table);
GenerateModesTable(NULL, modes_table);
}
void BindDisplayVariables(void)
{
M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings);
M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct);
M_BindVariable("fullscreen", &fullscreen);
M_BindVariable("screen_width", &screen_width);
M_BindVariable("screen_height", &screen_height);
M_BindVariable("startup_delay", &startup_delay);
M_BindVariable("video_driver", &video_driver);
M_BindVariable("usegamma", &usegamma);
if (gamemission == doom || gamemission == heretic)
{
M_BindVariable("show_endoom", &show_endoom);
}
if (gamemission == heretic || gamemission == hexen)
{
M_BindVariable("graphical_startup", &graphical_startup);
}
}