summaryrefslogtreecommitdiff
path: root/src/i_video.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/i_video.c')
-rw-r--r--src/i_video.c470
1 files changed, 386 insertions, 84 deletions
diff --git a/src/i_video.c b/src/i_video.c
index fdde7766..bf8ab77b 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,13 +166,19 @@ static boolean initialized = false;
// disable mouse?
static boolean nomouse = false;
-extern int usemouse;
+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;
@@ -133,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)
@@ -146,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
@@ -184,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
@@ -196,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()
@@ -232,26 +324,36 @@ static boolean MouseShouldBeGrabbed()
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)
+#endif /* #ifndef _WIN32_WCE */
+}
- return (gamestate == GS_LEVEL) && !demoplayback && !advancedemo;
+void I_SetGrabMouseCallback(grabmouse_callback_t func)
+{
+ grabmouse_callback = func;
+}
-#endif /* #ifndef _WIN32_WCE */
+// Set the variable controlling FPS dots.
+
+void I_DisplayFPSDots(boolean dots_on)
+{
+ display_fps_dots = dots_on;
}
// Update the value of window_focused when we get a focus event
@@ -307,13 +409,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);
@@ -334,11 +435,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);
@@ -346,11 +450,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);
}
//
@@ -540,6 +649,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;
@@ -568,32 +745,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)
{
@@ -636,9 +799,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:
@@ -703,7 +865,15 @@ static void I_ReadMouse(void)
ev.type = ev_mouse;
ev.data1 = mouse_button_state;
ev.data2 = AccelerateMouse(x);
- ev.data3 = -AccelerateMouse(y);
+
+ if (!novert)
+ {
+ ev.data3 = -AccelerateMouse(y);
+ }
+ else
+ {
+ ev.data3 = 0;
+ }
D_PostEvent(&ev);
}
@@ -792,7 +962,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,
@@ -832,7 +1002,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;
@@ -860,7 +1030,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;
@@ -915,19 +1085,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
@@ -972,7 +1141,7 @@ void I_FinishUpdate (void)
//
void I_ReadScreen (byte* scr)
{
- memcpy (scr, screens[0], SCREENWIDTH*SCREENHEIGHT);
+ memcpy(scr, I_VideoBuffer, SCREENWIDTH*SCREENHEIGHT);
}
@@ -996,17 +1165,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_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_SetWindowCaption(void)
+static 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);
@@ -1015,7 +1224,7 @@ void I_SetWindowCaption(void)
// Set the application icon
-void I_SetWindowIcon(void)
+static void I_InitWindowIcon(void)
{
SDL_Surface *surface;
Uint8 *mask;
@@ -1405,11 +1614,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.
@@ -1571,6 +1788,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,6 +1887,27 @@ static void SetSDLVideoDriver(void)
#endif
}
+static void SetWindowPositionVars(void)
+{
+ char buf[64];
+ int x, y;
+
+ if (window_position == NULL || !strcmp(window_position, ""))
+ {
+ return;
+ }
+
+ if (!strcmp(window_position, "center"))
+ {
+ 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);
+ }
+}
+
static char *WindowBoxType(screen_mode_t *mode, int w, int h)
{
if (mode->width != w && mode->height != h)
@@ -1819,22 +2079,19 @@ 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
//
@@ -1920,23 +2177,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
@@ -1958,5 +2213,52 @@ void I_InitGraphics(void)
}
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)
+ {
+ 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
+}