diff options
Diffstat (limited to 'src/i_video.c')
-rw-r--r-- | src/i_video.c | 569 |
1 files changed, 282 insertions, 287 deletions
diff --git a/src/i_video.c b/src/i_video.c index 2ab3dd98..22b4c98c 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -38,10 +38,11 @@ #include "doomstat.h" #include "d_main.h" #include "i_joystick.h" -#include "i_scale.h" #include "i_system.h" #include "i_swap.h" #include "i_timer.h" +#include "i_video.h" +#include "i_scale.h" #include "m_argv.h" #include "s_sound.h" #include "sounds.h" @@ -49,17 +50,35 @@ #include "w_wad.h" #include "z_zone.h" -enum -{ - FULLSCREEN_OFF, - FULLSCREEN_ON, +// Non aspect ratio-corrected modes (direct multiples of 320x200) + +static screen_mode_t *screen_modes[] = { + &mode_scale_1x, + &mode_scale_2x, + &mode_scale_3x, + &mode_scale_4x, + &mode_scale_5x, }; -enum -{ - RATIO_CORRECT_NONE, - RATIO_CORRECT_LETTERBOX, - RATIO_CORRECT_STRETCH, +// Aspect ratio corrected modes (4:3 ratio) + +static screen_mode_t *screen_modes_corrected[] = { + + // Vertically stretched modes (320x200 -> 320x240 and multiples) + + &mode_stretch_1x, + &mode_stretch_2x, + &mode_stretch_3x, + &mode_stretch_4x, + &mode_stretch_5x, + + // Horizontally squashed modes (320x200 -> 256x200 and multiples) + + &mode_squash_1x, + &mode_squash_2x, + &mode_squash_3x, + &mode_squash_4x, + &mode_squash_5x, }; extern void M_QuitDOOM(); @@ -71,6 +90,7 @@ char *video_driver = ""; static SDL_Surface *screen; // palette + static SDL_Color palette[256]; static boolean palette_to_set; @@ -89,6 +109,11 @@ extern int usemouse; static boolean native_surface; +// Screen width and height, from configuration file. + +int screen_width = SCREENWIDTH; +int screen_height = SCREENHEIGHT; + // Automatically adjust video settings if the selected mode is // not a valid video mode. @@ -96,11 +121,11 @@ int autoadjust_video_settings = 1; // Run in full screen mode? (int type for config code) -int fullscreen = FULLSCREEN_ON; +int fullscreen = true; // Aspect ratio correction mode -int aspect_ratio_correct = RATIO_CORRECT_NONE; +int aspect_ratio_correct = true; // Time to wait for the screen to settle on startup before starting the // game (ms) @@ -116,13 +141,6 @@ int grabmouse = true; boolean screenvisible; -// Blocky mode, -// replace each 320x200 pixel with screenmultiply*screenmultiply pixels. -// According to Dave Taylor, it still is a bonehead thing -// to use .... - -int screenmultiply = 1; - // disk image data and background overwritten by the disk to be // restored by EndRead @@ -135,6 +153,10 @@ static boolean window_focused; static SDL_Cursor *cursors[2]; +// The screen mode and scale functions being used + +static screen_mode_t *screen_mode; + // If true, keyboard mapping is ignored, like in Vanilla Doom. // The sensible thing to do is to disable this if you have a non-US // keyboard. @@ -168,7 +190,7 @@ static boolean MouseShouldBeGrabbed() // always grab the mouse when full screen (dont want to // see the mouse pointer) - if (fullscreen != FULLSCREEN_OFF) + if (fullscreen) return true; // Don't grab the mouse if mouse input is disabled @@ -624,72 +646,9 @@ static void BlitArea(int x1, int y1, int x2, int y2) return; } - if (aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) - { - x_offset = (screen->w - SCREENWIDTH * screenmultiply) / 2; - y_offset = (screen->h - SCREENHEIGHT * screenmultiply) / 2; - } - else - { - x_offset = 0; - y_offset = 0; - } - - if (aspect_ratio_correct == RATIO_CORRECT_STRETCH) - { - if (screenmultiply == 1) - { - scale_function = I_Stretch1x; - } - else if (screenmultiply == 2) - { - scale_function = I_Stretch2x; - } - else if (screenmultiply == 3) - { - scale_function = I_Stretch3x; - } - else if (screenmultiply == 4) - { - scale_function = I_Stretch4x; - } - else if (screenmultiply == 5) - { - scale_function = I_Stretch5x; - } - else - { - I_Error("No aspect ratio stretching function for screenmultiply=%i", - screenmultiply); - return; - } - } else { - if (screenmultiply == 1) - { - scale_function = I_Scale1x; - } - else if (screenmultiply == 2) - { - scale_function = I_Scale2x; - } - else if (screenmultiply == 3) - { - scale_function = I_Scale3x; - } - else if (screenmultiply == 4) - { - scale_function = I_Scale4x; - } - else if (screenmultiply == 5) - { - scale_function = I_Scale5x; - } - else - { - I_Error("No scale function found!"); - return; - } - } + x_offset = (screen->w - screen_mode->width) / 2; + y_offset = (screen->h - screen_mode->height) / 2; + scale_function = screen_mode->DrawScreen; if (SDL_LockSurface(screen) >= 0) { @@ -710,11 +669,15 @@ static void UpdateRect(int x1, int y1, int x2, int y2) // Update the area +/* + TODO: fix loading disk + SDL_UpdateRect(screen, x1 * screenmultiply, y1 * screenmultiply, (x2-x1) * screenmultiply, (y2-y1) * screenmultiply); +*/ } void I_BeginRead(void) @@ -889,43 +852,6 @@ void I_SetWindowIcon(void) SDL_FreeSurface(surface); } -// Get window dimensions for the current settings - -static void GetWindowDimensions(int *windowwidth, int *windowheight) -{ - *windowwidth = SCREENWIDTH * screenmultiply; - - if (aspect_ratio_correct == RATIO_CORRECT_NONE) - *windowheight = SCREENHEIGHT * screenmultiply; - else - *windowheight = SCREENHEIGHT_4_3 * screenmultiply; -} - -// Check if the screen mode for the current settings is in the list available -// Not all machines support running in 320x200/640x400 (only support 4:3) -// Some don't even support modes below 640x480. - -static boolean CheckValidFSMode(void) -{ - SDL_Rect **modes; - int i; - int w, h; - - GetWindowDimensions(&w, &h); - - modes = SDL_ListModes(NULL, SDL_FULLSCREEN); - - for (i=0; modes[i]; ++i) - { - if (w == modes[i]->w && h == modes[i]->h) - return true; - } - - // not found - - return false; -} - static void CheckCommandLine(void) { //! @@ -961,7 +887,7 @@ static void CheckCommandLine(void) if (M_CheckParm("-window") || M_CheckParm("-nofullscreen")) { - fullscreen = FULLSCREEN_OFF; + fullscreen = false; } //! @@ -972,7 +898,7 @@ static void CheckCommandLine(void) if (M_CheckParm("-fullscreen")) { - fullscreen = FULLSCREEN_ON; + fullscreen = true; } //! @@ -983,138 +909,207 @@ static void CheckCommandLine(void) nomouse = M_CheckParm("-nomouse") > 0; - // 2x, 3x, 4x, 5x scale mode - - //! - // @category video - // - // Don't scale up the screen. - // +} + +// Pick the modes list to use: - if (M_CheckParm("-1")) +static void GetScreenModes(screen_mode_t ***modes_list, int *num_modes) +{ + if (aspect_ratio_correct) { - screenmultiply = 1; + *modes_list = screen_modes_corrected; + *num_modes = arrlen(screen_modes_corrected); } - - //! - // @category video - // - // Double up the screen to 2x its size. - // - - if (M_CheckParm("-2")) + else { - screenmultiply = 2; + *modes_list = screen_modes; + *num_modes = arrlen(screen_modes); } +} - //! - // @category video - // - // Double up the screen to 3x its size. - // +// Find which screen_mode_t to use for the given width and height. - if (M_CheckParm("-3")) - { - screenmultiply = 3; - } +static screen_mode_t *I_FindScreenMode(int w, int h) +{ + screen_mode_t **modes_list; + screen_mode_t *best_mode; + int modes_list_length; + int num_pixels; + int best_num_pixels; + int i; - //! - // @category video - // - // Double up the screen to 4x its size. - // + // Special case: 320x200 and 640x400 are available even if aspect + // ratio correction is turned on. These modes have non-square + // pixels. - if (M_CheckParm("-4")) + if (w == SCREENWIDTH && h == SCREENHEIGHT) { - screenmultiply = 4; + return &mode_scale_1x; } - - //! - // @category video - // - // Double up the screen to 5x its size. - // - - if (M_CheckParm("-5")) + else if (w == SCREENWIDTH*2 && h == SCREENHEIGHT*2) { - screenmultiply = 5; + return &mode_scale_2x; } - if (screenmultiply < 1) - screenmultiply = 1; - if (screenmultiply > 5) - screenmultiply = 5; -} + GetScreenModes(&modes_list, &modes_list_length); -static void AutoAdjustSettings(void) -{ - int oldw, oldh; - int old_ratio, old_screenmultiply; + // Find the biggest screen_mode_t in the list that fits within these + // dimensions - GetWindowDimensions(&oldw, &oldh); - old_screenmultiply = screenmultiply; - old_ratio = aspect_ratio_correct; + best_mode = NULL; + best_num_pixels = 0; - if (!CheckValidFSMode() && screenmultiply == 1 - && fullscreen == FULLSCREEN_ON - && aspect_ratio_correct == RATIO_CORRECT_NONE) + for (i=0; i<modes_list_length; ++i) { - // 320x200 is not valid. + // Will this fit within the dimensions? If not, ignore. - // Try turning on letterbox mode - avoid doubling up - // the screen if possible + if (modes_list[i]->width > w || modes_list[i]->height > h) + { + continue; + } - aspect_ratio_correct = RATIO_CORRECT_LETTERBOX; + num_pixels = modes_list[i]->width * modes_list[i]->height; - if (!CheckValidFSMode()) + if (num_pixels > best_num_pixels) { - // That doesn't work. Change it back. + // This is a better mode than the current one - aspect_ratio_correct = RATIO_CORRECT_NONE; + best_mode = modes_list[i]; + best_num_pixels = num_pixels; } } - if (!CheckValidFSMode() && screenmultiply == 1) - { - // Try doubling up the screen to 640x400 + return best_mode; +} - screenmultiply = 2; - } +// If the video mode set in the configuration file is not available, +// try to choose a different mode. - if (!CheckValidFSMode() - && fullscreen == FULLSCREEN_ON - && aspect_ratio_correct == RATIO_CORRECT_NONE) +static void I_AutoAdjustSettings(void) +{ + if (fullscreen) { - // This is not a valid mode. Try turning on letterbox mode + SDL_Rect **modes; + SDL_Rect *best_mode; + screen_mode_t *screen_mode; + int num_pixels, best_num_pixels; + int i; - aspect_ratio_correct = RATIO_CORRECT_LETTERBOX; - } + modes = SDL_ListModes(NULL, SDL_FULLSCREEN); + + // Find the best mode that matches the mode specified in the + // configuration file + + best_mode = NULL; + best_num_pixels = INT_MAX; + + for (i=0; modes[i] != NULL; ++i) + { + //printf("%ix%i?\n", modes[i]->w, modes[i]->h); + + // What screen_mode_t would be used for this video mode? + + screen_mode = I_FindScreenMode(modes[i]->w, modes[i]->h); + + // Never choose a screen mode that we cannot run in, or + // is poor quality for fullscreen + + if (screen_mode == NULL || screen_mode->poor_quality) + { + // printf("\tUnsupported / poor quality\n"); + continue; + } + + // Do we have the exact mode? + // If so, no autoadjust needed + + if (screen_width == modes[i]->w && screen_height == modes[i]->h) + { + // printf("\tExact mode!\n"); + return; + } + + // Only use modes bigger than the specified mode + + if (modes[i]->w < screen_width || modes[i]->h < screen_height) + { + // printf("\t< %ix%i\n", screen_width, screen_height); + continue; + } + + // Is this mode better than the current mode? + + num_pixels = modes[i]->w * modes[i]->h; + + if (num_pixels < best_num_pixels) + { + // printf("\tA valid mode\n"); + best_num_pixels = num_pixels; + best_mode = modes[i]; + } + } + + if (best_mode == NULL) + { + // Unable to find a valid mode! + + if (screen_width <= SCREENWIDTH && screen_height <= SCREENHEIGHT) + { + I_Error("Unable to find any valid video mode at all!"); + } + + // Reset back to the original defaults and try to find a + // mode + + screen_width = SCREENWIDTH; + screen_height = SCREENHEIGHT; + + I_AutoAdjustSettings(); + + return; + } + + printf("I_InitGraphics: %ix%i mode not supported on this machine.\n", + screen_width, screen_height); + + screen_width = best_mode->w; + screen_height = best_mode->h; - if (old_ratio != aspect_ratio_correct - || old_screenmultiply != screenmultiply) - { - printf("I_InitGraphics: %ix%i resolution is not supported " - "on this machine. \n", oldw, oldh); - printf("I_InitGraphics: Video settings adjusted to " - "compensate:\n"); - - if (old_ratio != aspect_ratio_correct) - printf("\tletterbox mode on (aspect_ratio_correct=%i)\n", - aspect_ratio_correct); - if (screenmultiply != old_screenmultiply) - printf("\tscreenmultiply=%i\n", screenmultiply); - - printf("NOTE: Your video settings have been adjusted. " - "To disable this behavior,\n" - "set autoadjust_video_settings to 0 in your " - "configuration file.\n"); } - - if (!CheckValidFSMode()) + else { - printf("I_InitGraphics: WARNING: Unable to find a valid " - "fullscreen video mode to run in.\n"); + screen_mode_t *best_mode; + + // + // Windowed mode. + // + // Find a screen_mode_t to fit within the current settings + // + + best_mode = I_FindScreenMode(screen_width, screen_height); + + // Do we have the exact mode already? + + if (best_mode->width == screen_width + && best_mode->height == screen_height) + { + return; + } + + printf("I_InitGraphics: Cannot run at specified mode: %ix%i\n", + screen_width, screen_height); + + screen_width = best_mode->width; + screen_height = best_mode->height; } + + printf("I_InitGraphics: Auto-adjusted to %ix%i.\n", + screen_width, screen_height); + + printf("NOTE: Your video settings have been adjusted. " + "To disable this behavior,\n" + "set autoadjust_video_settings to 0 in your " + "configuration file.\n"); } // Check if we have been invoked as a screensaver by xscreensaver. @@ -1131,24 +1126,6 @@ void I_CheckIsScreensaver(void) } } -// In screensaver mode, pick a screenmultiply value that fits -// inside the screen. It is okay to do this because settings -// are not saved in screensaver mode. - -static void FindScreensaverMultiply(void) -{ - int i; - - for (i=1; i<=4; ++i) - { - if (SCREENWIDTH * i <= screen->w - && SCREENHEIGHT * i <= screen->h) - { - screenmultiply = i; - } - } -} - static void CreateCursors(void) { static Uint8 empty_cursor_data = 0; @@ -1245,47 +1222,56 @@ void I_InitGraphics(void) CheckCommandLine(); - // Don't allow letterbox mode when windowed - - if (!fullscreen && aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) + doompal = W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE); + + if (screensaver_mode) { - aspect_ratio_correct = RATIO_CORRECT_NONE; + windowwidth = 0; + windowheight = 0; } - - if (fullscreen && autoadjust_video_settings) + else { - // Check that the fullscreen mode we are trying to use is valid; - // if not, try to automatically select a more appropriate one. + if (autoadjust_video_settings) + { + I_AutoAdjustSettings(); + } - AutoAdjustSettings(); - } + windowwidth = screen_width; + windowheight = screen_height; - // Generate lookup tables before setting the video mode. + screen_mode = I_FindScreenMode(windowwidth, windowheight); - doompal = W_CacheLumpName (DEH_String("PLAYPAL"),PU_CACHE); + if (screen_mode == NULL) + { + I_Error("I_InitGraphics: Unable to find a screen mode small " + "enough for %ix%i", windowwidth, windowheight); + } - if (aspect_ratio_correct == RATIO_CORRECT_STRETCH) - { - I_InitStretchTables(doompal); + if (windowwidth != screen_mode->width + || windowheight != screen_mode->height) + { + printf("I_InitGraphics: Letterboxed (%ix%i within %ix%i)\n", + screen_mode->width, screen_mode->height, + windowwidth, windowheight); + } + + // Generate lookup tables before setting the video mode. + + if (screen_mode->InitMode != NULL) + { + screen_mode->InitMode(doompal); + } } // Set the video mode. - GetWindowDimensions(&windowwidth, &windowheight); - flags |= SDL_SWSURFACE | SDL_HWPALETTE | SDL_DOUBLEBUF; - if (fullscreen != FULLSCREEN_OFF) + if (fullscreen) { flags |= SDL_FULLSCREEN; } - if (screensaver_mode) - { - windowwidth = 0; - windowheight = 0; - } - screen = SDL_SetVideoMode(windowwidth, windowheight, 8, flags); if (screen == NULL) @@ -1293,14 +1279,6 @@ void I_InitGraphics(void) I_Error("Error setting video mode: %s\n", SDL_GetError()); } - // In screensaver mode, screenmultiply as large as possible - // and set a blank cursor. - - if (screensaver_mode) - { - FindScreensaverMultiply(); - } - // Start with a clear black screen // (screen will be flipped after we set the palette) @@ -1316,7 +1294,7 @@ void I_InitGraphics(void) SDL_UnlockSurface(screen); } - + // Set the palette I_SetPalette(doompal); @@ -1332,6 +1310,26 @@ void I_InitGraphics(void) UpdateFocus(); UpdateGrab(); + // In screensaver mode, now find a screen_mode to use. + + if (screensaver_mode) + { + screen_mode = I_FindScreenMode(screen->w, screen->h); + + if (screen_mode == NULL) + { + I_Error("I_InitGraphics: Unable to find a screen mode small " + "enough for %ix%i", screen->w, screen->h); + } + + // Generate lookup tables before setting the video mode. + + if (screen_mode->InitMode != NULL) + { + screen_mode->InitMode(doompal); + } + } + // On some systems, it takes a second or so for the screen to settle // after changing modes. We include the option to add a delay when // setting the screen mode, so that the game doesn't start immediately @@ -1348,36 +1346,33 @@ void I_InitGraphics(void) // If we have to multiply, drawing is done to a separate 320x200 buf native_surface = !SDL_MUSTLOCK(screen) - && screenmultiply == 1 + && screen_mode == &mode_scale_1x && screen->pitch == SCREENWIDTH - && (aspect_ratio_correct == RATIO_CORRECT_NONE - || aspect_ratio_correct == RATIO_CORRECT_LETTERBOX); + && aspect_ratio_correct; // If not, allocate a buffer and copy from that buffer to the // screen when we do an update if (native_surface) { - screens[0] = (unsigned char *) (screen->pixels); + screens[0] = (unsigned char *) screen->pixels; - if (aspect_ratio_correct == RATIO_CORRECT_LETTERBOX) - { - screens[0] += ((SCREENHEIGHT_4_3 - SCREENHEIGHT) * screen->pitch) / 2; - } + screens[0] += (screen->h - SCREENHEIGHT) / 2; } else { - screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, PU_STATIC, NULL); + screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, + PU_STATIC, NULL); + + // Clear the screen to black. + + memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT); } // "Loading from disk" icon LoadDiskImage(); - // Clear the screen to black. - - memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT); - // We need SDL to give us translated versions of keys as well SDL_EnableUNICODE(1); |