diff options
Diffstat (limited to 'src/i_video.c')
-rw-r--r-- | src/i_video.c | 547 |
1 files changed, 398 insertions, 149 deletions
diff --git a/src/i_video.c b/src/i_video.c index 66104de9..ac75dd50 100644 --- a/src/i_video.c +++ b/src/i_video.c @@ -29,14 +29,19 @@ #include <stdlib.h> #include <ctype.h> #include <math.h> +#include <string.h> + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#endif #include "icon.c" #include "config.h" -#include "deh_main.h" -#include "doomdef.h" -#include "doomstat.h" -#include "d_main.h" +#include "deh_str.h" +#include "doomtype.h" +#include "doomkeys.h" #include "i_joystick.h" #include "i_system.h" #include "i_swap.h" @@ -44,12 +49,55 @@ #include "i_video.h" #include "i_scale.h" #include "m_argv.h" -#include "s_sound.h" -#include "sounds.h" +#include "m_config.h" +#include "tables.h" #include "v_video.h" #include "w_wad.h" #include "z_zone.h" +// Lookup table for mapping ASCII characters to their equivalent when +// shift is pressed on an American layout keyboard: + +static const char shiftxform[] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, ' ', '!', '"', '#', '$', '%', '&', + '"', // shift-' + '(', ')', '*', '+', + '<', // shift-, + '_', // shift-- + '>', // shift-. + '?', // shift-/ + ')', // shift-0 + '!', // shift-1 + '@', // shift-2 + '#', // shift-3 + '$', // shift-4 + '%', // shift-5 + '^', // shift-6 + '&', // shift-7 + '*', // shift-8 + '(', // shift-9 + ':', + ':', // shift-; + '<', + '+', // shift-= + '>', '?', '@', + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '[', // shift-[ + '!', // shift-backslash - OH MY GOD DOES WATCOM SUCK + ']', // shift-] + '"', '_', + '\'', // shift-` + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', + 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + '{', '|', '}', '~', 127 +}; + + #define LOADING_DISK_W 16 #define LOADING_DISK_H 16 @@ -84,15 +132,22 @@ static screen_mode_t *screen_modes_corrected[] = { &mode_squash_5x, }; -extern void M_QuitDOOM(); -extern boolean advancedemo; - // SDL video driver name char *video_driver = ""; +// Window position: + +static char *window_position = ""; + +// SDL surface for the screen. + static SDL_Surface *screen; +// Window title + +static char *window_title = ""; + // Intermediate 8-bit buffer that we draw to instead of 'screen'. // This is used when we are rendering in 32-bit screen mode. // When in a real 8-bit screen mode, screenbuffer == screen. @@ -111,19 +166,19 @@ static boolean initialized = false; // disable mouse? static boolean nomouse = false; -extern int usemouse; - -// Disallow mouse and joystick movement to cause forward/backward -// motion. Specified with the '-novert' command line parameter. -// This is an int to allow saving to config file. - -int novert = 0; +int usemouse = 1; // Bit mask of mouse button state. static unsigned int mouse_button_state = 0; -// if true, screens[0] is screen->pixel +// Disallow mouse and joystick movement to cause forward/backward +// motion. Specified with the '-novert' command line parameter. +// This is an int to allow saving to config file + +int novert = 0; + +// if true, I_VideoBuffer is screen->pixels static boolean native_surface; @@ -139,7 +194,7 @@ int screen_bpp = 8; // Automatically adjust video settings if the selected mode is // not a valid video mode. -int autoadjust_video_settings = 1; +static int autoadjust_video_settings = 1; // Run in full screen mode? (int type for config code) @@ -152,17 +207,40 @@ int aspect_ratio_correct = true; // Time to wait for the screen to settle on startup before starting the // game (ms) -int startup_delay = 1000; +static int startup_delay = 1000; // Grab the mouse? (int type for config code) -int grabmouse = true; +static int grabmouse = true; + +// The screen buffer; this is modified to draw things to the screen + +byte *I_VideoBuffer = NULL; + +// If true, game is running as a screensaver + +boolean screensaver_mode = false; // Flag indicating whether the screen is currently visible: // when the screen isnt visible, don't render the screen boolean screenvisible; +// If true, we display dots at the bottom of the screen to +// indicate FPS. + +static boolean display_fps_dots; + +// If this is true, the screen is rendered but not blitted to the +// video buffer. + +static boolean noblit; + +// Callback function to invoke to determine whether to grab the +// mouse pointer. + +static grabmouse_callback_t grabmouse_callback = NULL; + // disk image data and background overwritten by the disk to be // restored by EndRead @@ -190,6 +268,10 @@ static unsigned int last_resize_time; int vanilla_keyboard_mapping = true; +// Is the shift key currently down? + +static int shiftdown = 0; + // Mouse acceleration // // This emulates some of the behavior of DOS mouse drivers by increasing @@ -202,6 +284,10 @@ int vanilla_keyboard_mapping = true; float mouse_acceleration = 2.0; int mouse_threshold = 10; +// Gamma correction level to use + +int usegamma = 0; + static void ApplyWindowResize(unsigned int w, unsigned int h); static boolean MouseShouldBeGrabbed() @@ -222,42 +308,39 @@ static boolean MouseShouldBeGrabbed() if (fullscreen) return true; -#ifdef _WIN32_WCE - - // On Windows CE, always grab input. This is because hardware - // button events are only acquired by SDL when the input is grabbed. - // Almost all Windows CE devices should have touch screens anyway, - // so this shouldn't affect mouse grabbing behavior. - - return true; - -#else - // Don't grab the mouse if mouse input is disabled if (!usemouse || nomouse) return false; - // Drone players don't need mouse focus - - if (drone) - return false; - // if we specify not to grab the mouse, never grab if (!grabmouse) return false; - // when menu is active or game is paused, release the mouse + // Invoke the grabmouse callback function to determine whether + // the mouse should be grabbed - if (menuactive || paused) - return false; + if (grabmouse_callback != NULL) + { + return grabmouse_callback(); + } + else + { + return true; + } +} - // only grab mouse when playing levels (but not demos) +void I_SetGrabMouseCallback(grabmouse_callback_t func) +{ + grabmouse_callback = func; +} - return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo; +// Set the variable controlling FPS dots. -#endif /* #ifndef _WIN32_WCE */ +void I_DisplayFPSDots(boolean dots_on) +{ + display_fps_dots = dots_on; } // Update the value of window_focused when we get a focus event @@ -313,13 +396,12 @@ static void SetShowCursor(boolean show) } } -static void LoadDiskImage(void) +void I_EnableLoadingDisk(void) { patch_t *disk; + byte *tmpbuf; char *disk_name; int y; - int xoffset = SCREENWIDTH - LOADING_DISK_W; - int yoffset = SCREENHEIGHT - LOADING_DISK_H; char buf[20]; SDL_VideoDriverName(buf, 15); @@ -340,11 +422,14 @@ static void LoadDiskImage(void) disk = W_CacheLumpName(disk_name, PU_STATIC); + // Draw the patch into a temporary buffer + + tmpbuf = Z_Malloc(SCREENWIDTH * (disk->height + 1), PU_STATIC, NULL); + V_UseBuffer(tmpbuf); + // Draw the disk to the screen: - V_DrawPatch(SCREENWIDTH - LOADING_DISK_W, - SCREENHEIGHT - LOADING_DISK_H, - 0, disk); + V_DrawPatch(0, 0, disk); disk_image = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); saved_background = Z_Malloc(LOADING_DISK_W * LOADING_DISK_H, PU_STATIC, NULL); @@ -352,11 +437,16 @@ static void LoadDiskImage(void) for (y=0; y<LOADING_DISK_H; ++y) { memcpy(disk_image + LOADING_DISK_W * y, - screens[0] + SCREENWIDTH * (y + yoffset) + xoffset, + tmpbuf + SCREENWIDTH * y, LOADING_DISK_W); } + // All done - free the screen buffer and restore the normal + // video buffer. + W_ReleaseLumpName(disk_name); + V_RestoreBuffer(); + Z_Free(tmpbuf); } // @@ -416,6 +506,7 @@ static int TranslateKey(SDL_keysym *sym) case SDLK_CAPSLOCK: return KEY_CAPSLOCK; case SDLK_SCROLLOCK: return KEY_SCRLCK; + case SDLK_NUMLOCK: return KEY_NUMLOCK; case SDLK_KP0: return KEYP_0; case SDLK_KP1: return KEYP_1; @@ -546,6 +637,74 @@ static int AccelerateMouse(int val) } } +// Get the equivalent ASCII (Unicode?) character for a keypress. + +static int GetTypedChar(SDL_Event *event) +{ + int key; + + // If Vanilla keyboard mapping enabled, the keyboard + // scan code is used to give the character typed. + // This does not change depending on keyboard layout. + // If you have a German keyboard, pressing 'z' will + // give 'y', for example. It is desirable to be able + // to fix this so that people with non-standard + // keyboard mappings can type properly. If vanilla + // mode is disabled, use the properly translated + // version. + + if (vanilla_keyboard_mapping) + { + key = TranslateKey(&event->key.keysym); + + // Is shift held down? If so, perform a translation. + + if (shiftdown > 0) + { + if (key >= 0 && key < arrlen(shiftxform)) + { + key = shiftxform[key]; + } + else + { + key = 0; + } + } + + return key; + } + else + { + // Unicode value, from key layout. + + return tolower(event->key.keysym.unicode); + } +} + +static void UpdateShiftStatus(SDL_Event *event) +{ + int change; + + if (event->type == SDL_KEYDOWN) + { + change = 1; + } + else if (event->type == SDL_KEYUP) + { + change = -1; + } + else + { + return; + } + + if (event->key.keysym.sym == SDLK_LSHIFT + || event->key.keysym.sym == SDLK_RSHIFT) + { + shiftdown += change; + } +} + void I_GetEvent(void) { SDL_Event sdlevent; @@ -574,32 +733,18 @@ void I_GetEvent(void) I_Quit(); } + UpdateShiftStatus(&sdlevent); + // process event switch (sdlevent.type) { case SDL_KEYDOWN: + // data1 has the key pressed, data2 has the character + // (shift-translated, etc) event.type = ev_keydown; event.data1 = TranslateKey(&sdlevent.key.keysym); - - // If Vanilla keyboard mapping enabled, the keyboard - // scan code is used to give the character typed. - // This does not change depending on keyboard layout. - // If you have a German keyboard, pressing 'z' will - // give 'y', for example. It is desirable to be able - // to fix this so that people with non-standard - // keyboard mappings can type properly. If vanilla - // mode is disabled, use the properly translated - // version. - - if (vanilla_keyboard_mapping) - { - event.data2 = event.data1; - } - else - { - event.data2 = tolower(sdlevent.key.keysym.unicode); - } + event.data2 = GetTypedChar(&sdlevent); if (event.data1 != 0) { @@ -642,9 +787,8 @@ void I_GetEvent(void) break; case SDL_QUIT: - // bring up the "quit doom?" prompt - S_StartSound(NULL,sfx_swtchn); - M_QuitDOOM(0); + event.type = ev_quit; + D_PostEvent(&event); break; case SDL_ACTIVEEVENT: @@ -718,7 +862,7 @@ static void I_ReadMouse(void) { ev.data3 = 0; } - + D_PostEvent(&ev); } @@ -777,6 +921,14 @@ static void UpdateGrab(void) else if (!grab && currently_grabbed) { SetShowCursor(true); + + // When releasing the mouse from grab, warp the mouse cursor to + // the bottom-right of the screen. This is a minimally distracting + // place for it to appear - we may only have released the grab + // because we're at an end of level intermission screen, for + // example. + + SDL_WarpMouse(screen->w - 16, screen->h - 16); } currently_grabbed = grab; @@ -806,7 +958,7 @@ static boolean BlitArea(int x1, int y1, int x2, int y2) if (SDL_LockSurface(screenbuffer) >= 0) { - I_InitScale(screens[0], + I_InitScale(I_VideoBuffer, (byte *) screenbuffer->pixels + (y_offset * screenbuffer->pitch) + x_offset, @@ -846,7 +998,7 @@ static void UpdateRect(int x1, int y1, int x2, int y2) void I_BeginRead(void) { - byte *screenloc = screens[0] + byte *screenloc = I_VideoBuffer + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH + (SCREENWIDTH - LOADING_DISK_W); int y; @@ -874,7 +1026,7 @@ void I_BeginRead(void) void I_EndRead(void) { - byte *screenloc = screens[0] + byte *screenloc = I_VideoBuffer + (SCREENHEIGHT - LOADING_DISK_H) * SCREENWIDTH + (SCREENWIDTH - LOADING_DISK_W); int y; @@ -929,19 +1081,18 @@ void I_FinishUpdate (void) return; // draws little dots on the bottom of the screen - if (devparm) - { + if (display_fps_dots) + { i = I_GetTime(); tics = i - lasttic; lasttic = i; if (tics > 20) tics = 20; for (i=0 ; i<tics*2 ; i+=4) - screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff; + I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0xff; for ( ; i<20*4 ; i+=4) - screens[0][ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0; - + I_VideoBuffer[ (SCREENHEIGHT-1)*SCREENWIDTH + i] = 0x0; } // draw to screen @@ -986,7 +1137,7 @@ void I_FinishUpdate (void) // void I_ReadScreen (byte* scr) { - memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT); + memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT); } @@ -1010,17 +1161,57 @@ void I_SetPalette (byte *doompalette) palette_to_set = true; } +// Given an RGB value, find the closest matching palette index. + +int I_GetPaletteIndex(int r, int g, int b) +{ + int best, best_diff, diff; + int i; + + best = 0; best_diff = INT_MAX; + + for (i = 0; i < 256; ++i) + { + diff = (r - palette[i].r) * (r - palette[i].r) + + (g - palette[i].g) * (g - palette[i].g) + + (b - palette[i].b) * (b - palette[i].b); + + if (diff < best_diff) + { + best = i; + best_diff = diff; + } + + if (diff == 0) + { + break; + } + } + + return best; +} + // -// Set the window caption +// Set the window title // -void I_SetWindowCaption(void) +void I_SetWindowTitle(char *title) +{ + window_title = title; +} + +// +// Call the SDL function to set the window title, based on +// the title set with I_SetWindowTitle. +// + +void I_InitWindowTitle(void) { char *buf; - buf = Z_Malloc(strlen(gamedescription) + strlen(PACKAGE_STRING) + 10, + buf = Z_Malloc(strlen(window_title) + strlen(PACKAGE_STRING) + 5, PU_STATIC, NULL); - sprintf(buf, "%s - %s", gamedescription, PACKAGE_STRING); + sprintf(buf, "%s - %s", window_title, PACKAGE_STRING); SDL_WM_SetCaption(buf, NULL); @@ -1029,18 +1220,18 @@ void I_SetWindowCaption(void) // Set the application icon -void I_SetWindowIcon(void) +void I_InitWindowIcon(void) { SDL_Surface *surface; Uint8 *mask; int i; // Generate the mask - + mask = malloc(icon_w * icon_h / 8); memset(mask, 0, icon_w * icon_h / 8); - for (i=0; i<icon_w * icon_h; ++i) + for (i=0; i<icon_w * icon_h; ++i) { if (icon_data[i * 3] != 0x00 || icon_data[i * 3 + 1] != 0x00 @@ -1419,11 +1610,19 @@ static void SetScaleFactor(int factor) } } -static void CheckCommandLine(void) +void I_GraphicsCheckCommandLine(void) { int i; //! + // @vanilla + // + // Disable blitting the screen. + // + + noblit = M_CheckParm ("-noblit"); + + //! // @category video // // Grab the mouse when running in windowed mode. @@ -1471,7 +1670,7 @@ static void CheckCommandLine(void) } //! - // @category video + // @category video // // Disable the mouse. // @@ -1480,24 +1679,6 @@ static void CheckCommandLine(void) //! // @category video - // - // Disable vertical mouse movement. - // - - if (M_CheckParm("-novert")) - novert = true; - - //! - // @category video - // - // Enable vertical mouse movement. - // - - if (M_CheckParm("-nonovert")) - novert = false; - - //! - // @category video // @arg <x> // // Specify the screen width, in pixels. @@ -1603,6 +1784,28 @@ static void CheckCommandLine(void) { SetScaleFactor(3); } + + //! + // @category video + // + // Disable vertical mouse movement. + // + + if (M_CheckParm("-novert")) + { + novert = true; + } + + //! + // @category video + // + // Enable vertical mouse movement. + // + + if (M_CheckParm("-nonovert")) + { + novert = false; + } } // Check if we have been invoked as a screensaver by xscreensaver. @@ -1648,36 +1851,27 @@ static void SetSDLVideoDriver(void) putenv(env_string); free(env_string); } +} -#if defined(_WIN32) && !defined(_WIN32_WCE) - - // Allow -gdi as a shortcut for using the windib driver. - - //! - // @category video - // @platform windows - // - // Use the Windows GDI driver instead of DirectX. - // +static void SetWindowPositionVars(void) +{ + char buf[64]; + int x, y; - if (M_CheckParm("-gdi") > 0) + if (window_position == NULL || !strcmp(window_position, "")) { - putenv("SDL_VIDEODRIVER=windib"); + return; } - // From the SDL 1.2.10 release notes: - // - // > The "windib" video driver is the default now, to prevent - // > problems with certain laptops, 64-bit Windows, and Windows - // > Vista. - // - // The hell with that. - - if (getenv("SDL_VIDEODRIVER") == NULL) + if (!strcmp(window_position, "center")) { - putenv("SDL_VIDEODRIVER=directx"); + putenv("SDL_VIDEO_CENTERED=1"); + } + else if (sscanf(window_position, "%i,%i", &x, &y) == 2) + { + sprintf(buf, "SDL_VIDEO_WINDOW_POS=%i,%i", x, y); + putenv(buf); } -#endif } static char *WindowBoxType(screen_mode_t *mode, int w, int h) @@ -1851,22 +2045,28 @@ void I_InitGraphics(void) } SetSDLVideoDriver(); + SetWindowPositionVars(); if (SDL_Init(SDL_INIT_VIDEO) < 0) { I_Error("Failed to initialize video: %s", SDL_GetError()); } - // Check for command-line video-related parameters. - - CheckCommandLine(); - // Set up title and icon. Windows cares about the ordering; this // has to be done before the call to SDL_SetVideoMode. - I_SetWindowCaption(); + I_InitWindowTitle(); #if !SDL_VERSION_ATLEAST(1, 3, 0) - I_SetWindowIcon(); + I_InitWindowIcon(); +#endif + + // Warning to OS X users... though they might never see it :( +#ifdef __MACOSX__ + if (fullscreen) + { + printf("Some old versions of OS X might crash in fullscreen mode.\n" + "If this happens to you, switch back to windowed mode.\n"); + } #endif // @@ -1952,23 +2152,21 @@ void I_InitGraphics(void) if (native_surface) { - screens[0] = (unsigned char *) screen->pixels; + I_VideoBuffer = (unsigned char *) screen->pixels; - screens[0] += (screen->h - SCREENHEIGHT) / 2; + I_VideoBuffer += (screen->h - SCREENHEIGHT) / 2; } else { - screens[0] = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, - PU_STATIC, NULL); + I_VideoBuffer = (unsigned char *) Z_Malloc (SCREENWIDTH * SCREENHEIGHT, + PU_STATIC, NULL); } - // "Loading from disk" icon - - LoadDiskImage(); + V_RestoreBuffer(); // Clear the screen to black. - memset(screens[0], 0, SCREENWIDTH * SCREENHEIGHT); + memset(I_VideoBuffer, 0, SCREENWIDTH * SCREENHEIGHT); // We need SDL to give us translated versions of keys as well @@ -1984,11 +2182,62 @@ void I_InitGraphics(void) while (SDL_PollEvent(&dummy)); - if (usemouse && !nomouse && (fullscreen || grabmouse)) + initialized = true; + + // Call I_ShutdownGraphics on quit + + I_AtExit(I_ShutdownGraphics, true); +} + +// Bind all variables controlling video options into the configuration +// file system. + +void I_BindVideoVariables(void) +{ + M_BindVariable("use_mouse", &usemouse); + M_BindVariable("autoadjust_video_settings", &autoadjust_video_settings); + M_BindVariable("fullscreen", &fullscreen); + M_BindVariable("aspect_ratio_correct", &aspect_ratio_correct); + M_BindVariable("startup_delay", &startup_delay); + M_BindVariable("screen_width", &screen_width); + M_BindVariable("screen_height", &screen_height); + M_BindVariable("screen_bpp", &screen_bpp); + M_BindVariable("grabmouse", &grabmouse); + M_BindVariable("mouse_acceleration", &mouse_acceleration); + M_BindVariable("mouse_threshold", &mouse_threshold); + M_BindVariable("video_driver", &video_driver); + M_BindVariable("window_position", &window_position); + M_BindVariable("usegamma", &usegamma); + M_BindVariable("vanilla_keyboard_mapping", &vanilla_keyboard_mapping); + M_BindVariable("novert", &novert); + + // Windows Vista or later? Set screen color depth to + // 32 bits per pixel, as 8-bit palettized screen modes + // don't work properly in recent versions. + +#if defined(_WIN32) && !defined(_WIN32_WCE) { - CenterMouse(); + OSVERSIONINFOEX version_info; + + ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); + version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + + GetVersionEx((OSVERSIONINFO *) &version_info); + + if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT + && version_info.dwMajorVersion >= 6) + { + screen_bpp = 32; + } } +#endif - initialized = true; -} + // Disable fullscreen by default on OS X, as there is an SDL bug + // where some old versions of OS X (<= Snow Leopard) crash. +#ifdef __MACOSX__ + fullscreen = 0; + screen_width = 800; + screen_height = 600; +#endif +} |