From 8cb963858f313c89e7cf238f4f8ae309610c8e04 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 28 Aug 2000 22:38:46 +0000 Subject: [PATCH] source/vid_svgalib.c source/in_svgalib.c: "accidently" port over newtree's svga stuff (I copied the wrong file then cleaned up the resulting mess:) Makefile.am include/Makefile.am doc/Makefile.am source/Makefile.am: fix things up so doc no longer causes make to barf and makd dist works source/dirent.c source/fnmatch.c source/in_svgalib.c source/vid_3dfxsvga.c source/vid_mgl.c source/vid_wgl.c: needed for make dist. No, nuq-3dfx does not get created (I don't have the libs or card) --- Makefile.am | 2 +- include/Makefile.am | 10 +- source/Makefile.am | 8 +- source/dirent.c | 313 ++++ source/fnmatch.c | 220 +++ source/in_svgalib.c | 385 +++++ source/vid_3dfxsvga.c | 651 ++++++++ source/vid_mgl.c | 3451 +++++++++++++++++++++++++++++++++++++++++ source/vid_svgalib.c | 970 ++++-------- source/vid_wgl.c | 1963 +++++++++++++++++++++++ 10 files changed, 7317 insertions(+), 656 deletions(-) create mode 100644 source/dirent.c create mode 100644 source/fnmatch.c create mode 100644 source/in_svgalib.c create mode 100644 source/vid_3dfxsvga.c create mode 100644 source/vid_mgl.c create mode 100644 source/vid_wgl.c diff --git a/Makefile.am b/Makefile.am index dfc971b..fa19fee 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,7 +3,7 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = include source doc -EXTRA_DIST = RPM/build_rpm.in RPM/uquake.spec.in \ +EXTRA_DIST = RPM/build_rpm.in RPM/nuq.spec.in \ tools/gas2masm/Makefile tools/gas2masm/gas2masm.c \ tools/gas2masm/gas2masm.dsp tools/gas2masm/gas2masm.dsw \ tools/gas2masm/gas2masm.mak tools/gas2masm/gas2masm.mdp diff --git a/include/Makefile.am b/include/Makefile.am index ee7344e..89d9b32 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -1,12 +1,12 @@ ## Process this file with automake to produce Makefile.in EXTRA_DIST = adivtab.h anorm_dots.h anorms.h asm_draw.h asm_ia32.h block16.h \ - block8.h bothdefs.h bspfile.h buildnum.h cdaudio.h checksum.h \ - cl_slist.h client.h cmd.h commdef.h compat.h console.h crc.h \ + block8.h bspfile.h cdaudio.h \ + client.h cmd.h compat.h console.h crc.h \ cvar.h d_iface.h d_ifacea.h d_local.h draw.h gl_warp_sin.h \ - glquake.h in_win.h info.h input.h keys.h link.h \ + glquake.h info.h input.h keys.h link.h \ mathlib.h mdfour.h menu.h model.h modelgen.h msg.h net.h \ - pmove.h pr_comp.h progdefs.h progs.h protocol.h qargs.h \ - qdefs.h qendian.h qstructs.h qtypes.h quakeasm.h quakedef.h \ + pr_comp.h progdefs.h progs.h protocol.h qargs.h \ + qdefs.h qendian.h qtypes.h quakeasm.h \ quakefs.h quakeio.h r_local.h r_shared.h render.h resource.h \ sbar.h screen.h server.h sizebuf.h sound.h spritegn.h sys.h \ uint32.h vid.h view.h wad.h winquake.h world.h zone.h \ diff --git a/source/Makefile.am b/source/Makefile.am index 64a3566..9e184e9 100644 --- a/source/Makefile.am +++ b/source/Makefile.am @@ -43,7 +43,7 @@ noinst_LIBRARIES= libqfsys.a libqfsnd.a libqfcd.a libqfnet.a math_ASM= math.S cl_math.S soft_ASM= d_draw.S d_draw16.S d_parta.S d_polysa.S d_scana.S d_spr8.S \ d_varsa.S r_aclipa.S r_aliasa.S r_drawa.S r_edgea.S r_varsa.S \ - surf16.s surf8.s + surf16.S surf8.S sound_ASM= snd_mixa.S common_ASM= sys_ia32.S worlda.S $(math_ASM) #endif @@ -165,7 +165,7 @@ nuq_sdl_DEPENDENCIES=libqfsys.a libqfsnd.a libqfcd.a libqfnet.a # # ... Linux SVGAlib # -svga_SOURCES= d_copy.S vid_svgalib.c +svga_SOURCES= d_copy.S vid_svgalib.c in_svgalib.c nuq_svga_SOURCES= $(combined_SOURCES) $(soft_SOURCES) $(svga_SOURCES) nuq_svga_LDADD= $(client_LIBS) $(SVGA_LIBS) @@ -230,6 +230,4 @@ nuq_wgl_DEPENDENCIES=libqfsys.a libqfsnd.a libqfcd.a libqfnet.a # Stuff that doesn't get linked into an executable NEEDS to be mentioned here, # or it won't be distributed with 'make dist' # -EXTRA_DIST= nuq-server.mak nuq-server.dsp \ - nuq-mgl.mak nuq-sdl.mak nuq.dsp \ - nuq-sgl.mak nuq-wgl.mak +EXTRA_DIST= #nuq.dsp diff --git a/source/dirent.c b/source/dirent.c new file mode 100644 index 0000000..edd9a9e --- /dev/null +++ b/source/dirent.c @@ -0,0 +1,313 @@ +/* + * dirent.c + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Peters + * + * $Id$ + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define SUFFIX "*" +#define SLASH "\\" + +#define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) /* is a directory */ + +/* + * opendir + * + * Returns a pointer to a DIR structure appropriately filled in to begin + * searching a directory. + */ +DIR * +opendir (const char *szPath) +{ + DIR *nd; + struct _stat statDir; + + errno = 0; + + if (!szPath) + { + errno = EFAULT; + return (DIR *) 0; + } + + if (szPath[0] == '\0') + { + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Attempt to determine if the given path really is a directory. */ + if (_stat (szPath, &statDir)) + { + /* Error, stat should have set an error value. */ + return (DIR *) 0; + } + + if (!S_ISDIR (statDir.st_mode)) + { + /* Error, stat reports not a directory. */ + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + nd = (DIR *) calloc (1, sizeof (DIR) + strlen (szPath) + strlen (SLASH) + + strlen (SUFFIX)); + + if (!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *) 0; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != '\0' && + nd->dd_name[strlen (nd->dd_name) - 1] != '/' && + nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + { + strcat (nd->dd_name, SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst_t structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + nd->dd_dir.d_name = nd->dd_dta.name; + + return nd; +} + + +/* + * readdir + * + * Return a pointer to a dirent structure filled with the information on the + * next entry in the directory. + */ +struct dirent * +readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return (struct dirent *) 0; + } + + if (dirp->dd_dir.d_name != dirp->dd_dta.name) + { + /* The structure does not seem to be set up correctly. */ + errno = EINVAL; + return (struct dirent *) 0; + } + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return (struct dirent *) 0; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + } + else + { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. */ + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) + { + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name); + return &dirp->dd_dir; + } + + return (struct dirent *) 0; +} + + +/* + * closedir + * + * Frees up resources allocated by opendir. + */ +int +closedir (DIR * dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) + { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + free (dirp); + + return rc; +} + +/* + * rewinddir + * + * Return to the beginning of the directory "stream". We simply call findclose + * and then reset things like an opendir. + */ +void +rewinddir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +/* + * telldir + * + * Returns the "position" in the "directory stream" which can be used with + * seekdir to go back to an old entry. We simply return the value in stat. + */ +long +telldir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +/* + * seekdir + * + * Seek to an entry previously returned by telldir. We rewind the directory + * and call readdir repeatedly until either dd_stat is the position number + * or -1 (off the end). This is not perfect, in that the directory may + * have changed while we weren't looking. But that is probably the case with + * any such system. + */ +void +seekdir (DIR * dirp, long lPos) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (lPos < -1) + { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } + else if (lPos == -1) + { + /* Seek past end. */ + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Rewind and read forward to the appropriate index. */ + rewinddir (dirp); + + while ((dirp->dd_stat < lPos) && readdir (dirp)) + ; + } +} diff --git a/source/fnmatch.c b/source/fnmatch.c new file mode 100644 index 0000000..da2c6a5 --- /dev/null +++ b/source/fnmatch.c @@ -0,0 +1,220 @@ +/* + fnmatch.c + + (description) + + Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#include "config.h" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include + +#include "fnmatch.h" + + +/* Comment out all this code if we are using the GNU C Library, and are not + actually compiling the library itself. This code is part of the GNU C + Library, but also included in many other GNU distributions. Compiling + and linking in this code is a waste when using the GNU C library + (especially if it is a shared library). Rather than having every GNU + program understand `configure --with-gnu-libc' and omit the object files, + it is simpler to just do this in the source for each such file. */ + +#if defined (_LIBC) || !defined (__GNU_LIBRARY__) + + +#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS) +extern int errno; +#endif + +/* Match STRING against the filename pattern PATTERN, returning zero if + it matches, nonzero if not. */ +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + register const char *p = pattern, *n = string; + register unsigned char c; + +/* Note that this evalutes C many times. */ +#define FOLD(c) ((flags & FNM_CASEFOLD) && isupper (c) ? tolower (c) : (c)) + +#ifdef _WIN32 + flags |= FNM_CASEFOLD; +#endif + + while ((c = *p++) != '\0') + { + c = FOLD (c); + + switch (c) + { + case '?': + if (*n == '\0') + return FNM_NOMATCH; + else if ((flags & FNM_FILE_NAME) && *n == '/') + return FNM_NOMATCH; + else if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + break; + + case '\\': + if (!(flags & FNM_NOESCAPE)) + { + c = *p++; + c = FOLD (c); + } + if (FOLD ((unsigned char)*n) != c) + return FNM_NOMATCH; + break; + + case '*': + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + for (c = *p++; c == '?' || c == '*'; c = *p++, ++n) + if (((flags & FNM_FILE_NAME) && *n == '/') || + (c == '?' && *n == '\0')) + return FNM_NOMATCH; + + if (c == '\0') + return 0; + + { + unsigned char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; + c1 = FOLD (c1); + for (--p; *n != '\0'; ++n) + if ((c == '[' || FOLD ((unsigned char)*n) == c1) && + fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + return 0; + return FNM_NOMATCH; + } + + case '[': + { + /* Nonzero if the sense of the character class is inverted. */ + register int not; + + if (*n == '\0') + return FNM_NOMATCH; + + if ((flags & FNM_PERIOD) && *n == '.' && + (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + return FNM_NOMATCH; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) + { + register unsigned char cstart = c, cend = c; + + if (!(flags & FNM_NOESCAPE) && c == '\\') + cstart = cend = *p++; + + cstart = cend = FOLD (cstart); + + if (c == '\0') + /* [ (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + c = FOLD (c); + + if ((flags & FNM_FILE_NAME) && c == '/') + /* [/] can never match. */ + return FNM_NOMATCH; + + if (c == '-' && *p != ']') + { + cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + cend = FOLD (cend); + + c = *p++; + } + + if (FOLD ((unsigned char)*n) >= cstart + && FOLD ((unsigned char)*n) <= cend) + goto matched; + + if (c == ']') + break; + } + if (!not) + return FNM_NOMATCH; + break; + + matched:; + /* Skip the rest of the [...] that already matched. */ + while (c != ']') + { + if (c == '\0') + /* [... (unterminated) loses. */ + return FNM_NOMATCH; + + c = *p++; + if (!(flags & FNM_NOESCAPE) && c == '\\') + /* XXX 1003.2d11 is unclear if this is right. */ + ++p; + } + if (not) + return FNM_NOMATCH; + } + break; + + default: + if (c != FOLD ((unsigned char)*n)) + return FNM_NOMATCH; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if ((flags & FNM_LEADING_DIR) && *n == '/') + /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ + return 0; + + return FNM_NOMATCH; +} + +#endif /* _LIBC or not __GNU_LIBRARY__. */ + diff --git a/source/in_svgalib.c b/source/in_svgalib.c new file mode 100644 index 0000000..0e1a5f7 --- /dev/null +++ b/source/in_svgalib.c @@ -0,0 +1,385 @@ +/* + in_svgalib.c + + (description) + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "qtypes.h" +#include "keys.h" +#include "client.h" +#include "sys.h" +#include "console.h" +#include "cvar.h" +#include "cmd.h" +#include "host.h" +#include "qargs.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#include +#include + + +static int UseKeyboard = 1; +static int UseMouse = 1; +static int in_svgalib_inited = 0; + +static unsigned char scantokey[128]; +static int mouse_buttons; +static int mouse_buttonstate; +static int mouse_oldbuttonstate; +static float mouse_x, mouse_y; +static float old_mouse_x, old_mouse_y; +static int mx, my; + +static void IN_init_kb(); +static void IN_init_mouse(); + +cvar_t *_windowed_mouse; +cvar_t *m_filter; +static cvar_t *mouse_button_commands[3]; + +static void keyhandler(int scancode, int state) +{ + int sc; + + sc = scancode & 0x7f; +#if 0 + Con_Printf("scancode=%x (%d%s)\n", scancode, sc, scancode&0x80?"+128":""); +#endif + Key_Event(scantokey[sc], state == KEY_EVENTPRESS); +} + + +static void mousehandler(int buttonstate, int dx, int dy, int dz, int drx, int dry, int drz) +{ + mouse_buttonstate = buttonstate; + mx += dx; + my += dy; + if (drx > 0) { + Key_Event(K_MWHEELUP, 1); + Key_Event(K_MWHEELUP, 0); + } else if (drx < 0) { + Key_Event(K_MWHEELDOWN, 1); + Key_Event(K_MWHEELDOWN, 0); + } +} + + +void Force_CenterView_f(void) +{ + cl.viewangles[PITCH] = 0; +} + + +int IN_Init(void) +{ + if (COM_CheckParm("-nokbd")) UseKeyboard = 0; + if (COM_CheckParm("-nomouse")) UseMouse = 0; + + if (UseKeyboard) + IN_init_kb(); + if (UseMouse) + IN_init_mouse(); + + in_svgalib_inited = 1; + return 1; +} + +static void IN_init_kb() +{ + int i; + + for (i=0 ; i<128 ; i++) { + scantokey[i] = ' '; + } + + scantokey[ 1] = K_ESCAPE; + scantokey[ 2] = '1'; + scantokey[ 3] = '2'; + scantokey[ 4] = '3'; + scantokey[ 5] = '4'; + scantokey[ 6] = '5'; + scantokey[ 7] = '6'; + scantokey[ 8] = '7'; + scantokey[ 9] = '8'; + scantokey[ 10] = '9'; + scantokey[ 11] = '0'; + scantokey[ 12] = '-'; + scantokey[ 13] = '='; + scantokey[ 14] = K_BACKSPACE; + scantokey[ 15] = K_TAB; + scantokey[ 16] = 'q'; + scantokey[ 17] = 'w'; + scantokey[ 18] = 'e'; + scantokey[ 19] = 'r'; + scantokey[ 20] = 't'; + scantokey[ 21] = 'y'; + scantokey[ 22] = 'u'; + scantokey[ 23] = 'i'; + scantokey[ 24] = 'o'; + scantokey[ 25] = 'p'; + scantokey[ 26] = '['; + scantokey[ 27] = ']'; + scantokey[ 28] = K_ENTER; + scantokey[ 29] = K_CTRL; /*left */ + scantokey[ 30] = 'a'; + scantokey[ 31] = 's'; + scantokey[ 32] = 'd'; + scantokey[ 33] = 'f'; + scantokey[ 34] = 'g'; + scantokey[ 35] = 'h'; + scantokey[ 36] = 'j'; + scantokey[ 37] = 'k'; + scantokey[ 38] = 'l'; + scantokey[ 39] = ';'; + scantokey[ 40] = '\''; + scantokey[ 41] = '`'; + scantokey[ 42] = K_SHIFT; /*left */ + scantokey[ 43] = '\\'; + scantokey[ 44] = 'z'; + scantokey[ 45] = 'x'; + scantokey[ 46] = 'c'; + scantokey[ 47] = 'v'; + scantokey[ 48] = 'b'; + scantokey[ 49] = 'n'; + scantokey[ 50] = 'm'; + scantokey[ 51] = ','; + scantokey[ 52] = '.'; + scantokey[ 53] = '/'; + scantokey[ 54] = K_SHIFT; /*right */ + scantokey[ 55] = KP_MULTIPLY; + scantokey[ 56] = K_ALT; /*left */ + scantokey[ 57] = ' '; + scantokey[ 58] = K_CAPSLOCK; + scantokey[ 59] = K_F1; + scantokey[ 60] = K_F2; + scantokey[ 61] = K_F3; + scantokey[ 62] = K_F4; + scantokey[ 63] = K_F5; + scantokey[ 64] = K_F6; + scantokey[ 65] = K_F7; + scantokey[ 66] = K_F8; + scantokey[ 67] = K_F9; + scantokey[ 68] = K_F10; + scantokey[ 69] = KP_NUMLCK; + scantokey[ 70] = K_SCRLCK; + scantokey[ 71] = KP_HOME; + scantokey[ 72] = KP_UPARROW; + scantokey[ 73] = KP_PGUP; + scantokey[ 74] = KP_MINUS; + scantokey[ 75] = KP_LEFTARROW; + scantokey[ 76] = KP_5; + scantokey[ 77] = KP_RIGHTARROW; + scantokey[ 79] = KP_END; + scantokey[ 78] = KP_PLUS; + scantokey[ 80] = KP_DOWNARROW; + scantokey[ 81] = KP_PGDN; + scantokey[ 82] = KP_INS; + scantokey[ 83] = KP_DEL; + /* 84 to 86 not used */ + scantokey[ 87] = K_F11; + scantokey[ 88] = K_F12; + /* 89 to 95 not used */ + scantokey[ 96] = KP_ENTER; /* keypad enter */ + scantokey[ 97] = K_CTRL; /* right */ + scantokey[ 98] = KP_DIVIDE; + scantokey[ 99] = K_PRNTSCR; /* print screen */ + scantokey[100] = K_ALT; /* right */ + + scantokey[101] = K_PAUSE; /* break */ + scantokey[102] = K_HOME; + scantokey[103] = K_UPARROW; + scantokey[104] = K_PGUP; + scantokey[105] = K_LEFTARROW; + scantokey[106] = K_RIGHTARROW; + scantokey[107] = K_END; + scantokey[108] = K_DOWNARROW; + scantokey[109] = K_PGDN; + scantokey[110] = K_INS; + scantokey[111] = K_DEL; + scantokey[119] = K_PAUSE; + + if (keyboard_init()) { + Sys_Error("keyboard_init() failed"); + } + keyboard_seteventhandler(keyhandler); +} + +static void IN_init_mouse() +{ + int mtype; + char *mousedev; + int mouserate = MOUSE_DEFAULTSAMPLERATE; + + mouse_button_commands[0] = Cvar_Get ("mouse1","+attack",0,"None"); + mouse_button_commands[1] = Cvar_Get ("mouse2","+strafe",0,"None"); + mouse_button_commands[2] = Cvar_Get ("mouse2","+forward",0,"None"); + m_filter = Cvar_Get ("m_filter","0",0,"None"); + Cmd_AddCommand("force_centerview", Force_CenterView_f); + + mouse_buttons = 3; + + mtype = vga_getmousetype(); + + mousedev = "/dev/mouse"; + if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV"); + if (COM_CheckParm("-mdev")) { + mousedev = com_argv[COM_CheckParm("-mdev")+1]; + } + + if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE")); + if (COM_CheckParm("-mrate")) { + mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]); + } + +#if 0 + printf("Mouse: dev=%s,type=%s,speed=%d\n", + mousedev, mice[mtype].name, mouserate); +#endif + if (mouse_init(mousedev, mtype, mouserate)) { + Con_Printf("No mouse found\n"); + UseMouse = 0; + } else{ + mouse_seteventhandler((void*)mousehandler); + } +} + +void IN_Shutdown(void) +{ + Con_Printf("IN_Shutdown\n"); + + if (UseMouse) mouse_close(); + if (UseKeyboard) keyboard_close(); + in_svgalib_inited = 0; +} + + +void IN_SendKeyEvents(void) +{ + if (!in_svgalib_inited) return; + + if (UseKeyboard) { + while ((keyboard_update())); + } +} + + +void IN_Commands(void) +{ + if (UseMouse) + { + /* Poll mouse values */ + while (mouse_update()) + ; + + /* Perform button actions */ + if ((mouse_buttonstate & MOUSE_LEFTBUTTON) && + !(mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) + Key_Event (K_MOUSE1, true); + else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) && + (mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) + Key_Event (K_MOUSE1, false); + + if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) && + !(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) + Key_Event (K_MOUSE2, true); + else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) && + (mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) + Key_Event (K_MOUSE2, false); + + if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) && + !(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) + Key_Event (K_MOUSE3, true); + else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) && + (mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) + Key_Event (K_MOUSE3, false); + + mouse_oldbuttonstate = mouse_buttonstate; + } +} + + +void IN_Move(usercmd_t *cmd) +{ + if (!UseMouse) return; + + /* Poll mouse values */ + while (mouse_update()) + ; + + if (m_filter->value) { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } else { + mouse_x = mx; + mouse_y = my; + } + old_mouse_x = mx; + old_mouse_y = my; + /* Clear for next update */ + mx = my = 0; + + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + + /* Add mouse X/Y movement to cmd */ + if ( (in_strafe.state & 1) || + (lookstrafe->value && (in_mlook.state & 1) )) { + cmd->sidemove += m_side->value * mouse_x; + } else { + cl.viewangles[YAW] -= m_yaw->value * mouse_x; + } + + if ((in_mlook.state & 1)) V_StopPitchDrift(); + + if ((in_mlook.state & 1) && !(in_strafe.state & 1)) { + cl.viewangles[PITCH] += m_pitch->value * mouse_y; + if (cl.viewangles[PITCH] > 80) { + cl.viewangles[PITCH] = 80; + } + if (cl.viewangles[PITCH] < -70) { + cl.viewangles[PITCH] = -70; + } + } else { + if ((in_strafe.state & 1) && noclip_anglehack) { + cmd->upmove -= m_forward->value * mouse_y; + } else { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } +} diff --git a/source/vid_3dfxsvga.c b/source/vid_3dfxsvga.c new file mode 100644 index 0000000..5d3a2f5 --- /dev/null +++ b/source/vid_3dfxsvga.c @@ -0,0 +1,651 @@ +/* + vid_3dfxsvga.c + + OpenGL device driver for 3Dfx chipsets running Linux + + Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999,2000 Nelson Rush. + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#include "qtypes.h" +#include "quakedef.h" +#include "glquake.h" +#include "sys.h" +#include "console.h" +#include "cvar.h" +#include "sbar.h" +#include "qendian.h" +#include "qargs.h" +//#include "lib_replace.h" + +#include +#include +#include + +#ifdef HAVE_DLFCN_H +# include +#endif +#ifndef RTLD_LAZY +# ifdef DL_LAZY +# define RTLD_LAZY DL_LAZY +# else +# define RTLD_LAZY 0 +# endif +#endif + +#include +#include +#include + +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 + + +//unsigned short d_8to16table[256]; +unsigned d_8to24table[256]; +unsigned char d_15to8table[65536]; + +static cvar_t *vid_mode; +static cvar_t *vid_redrawfull; +static cvar_t *vid_waitforrefresh; +extern cvar_t *gl_triplebuffer; + +#ifdef HAVE_DLOPEN +static void *dlhand = NULL; +#endif + +static fxMesaContext fc = NULL; +static int scr_width, scr_height; +static qboolean is8bit = 0; + +int VID_options_items = 0; + +/*-----------------------------------------------------------------------*/ + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +//int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int texture_extension_number = 1; + +float gldepthmin, gldepthmax; + +const char *gl_vendor; +const char *gl_renderer; +const char *gl_version; +const char *gl_extensions; + +// ARB Multitexture +int gl_mtex_enum = TEXTURE0_SGIS; +qboolean gl_arb_mtex = false; +qboolean gl_mtexable = false; + +/*-----------------------------------------------------------------------*/ +void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +{ +} + +void D_EndDirectRect (int x, int y, int width, int height) +{ +} + +void VID_Shutdown(void) +{ + if (!fc) + return; + + fxMesaDestroyContext(fc); +} + +void signal_handler(int sig) +{ + printf("Received signal %d, exiting...\n", sig); + Host_Shutdown(); + abort(); + //Sys_Quit(); + exit(0); +} + +void InitSig(void) +{ + signal(SIGHUP, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGQUIT, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGTRAP, signal_handler); +// signal(SIGIOT, signal_handler); + signal(SIGBUS, signal_handler); +// signal(SIGFPE, signal_handler); + signal(SIGSEGV, signal_handler); + signal(SIGTERM, signal_handler); +} + +void VID_ShiftPalette(unsigned char *p) +{ +// VID_SetPalette(p); +} + +void VID_SetPalette (unsigned char *palette) +{ + byte *pal; + unsigned r,g,b; + unsigned v; + int r1,g1,b1; + int k; + unsigned short i; + unsigned *table; + FILE *f; + char s[255]; +//#endif + float dist, bestdist; +// +// 8 8 8 encoding +// + Con_Printf("Converting 8to24\n"); + + pal = palette; + table = d_8to24table; + for (i=0 ; i<256 ; i++) + { + r = pal[0]; + g = pal[1]; + b = pal[2]; + pal += 3; + +// v = (255<<24) + (r<<16) + (g<<8) + (b<<0); +// v = (255<<0) + (r<<8) + (g<<16) + (b<<24); + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + *table++ = v; + } + d_8to24table[255] = 0; // 255 is transparent + + // JACK: 3D distance calcs - k is last closest, l is the distance. + { + static qboolean palflag = false; + + // FIXME: Precalculate this and cache to disk. + if (palflag) + return; + palflag = true; + } + + COM_FOpenFile("glquake/15to8.pal", &f); + if (f) { + fread(d_15to8table, 1<<15, 1, f); + fclose(f); + } else + { + for (i=0; i < (1<<15); i++) { + /* Maps + 000000000000000 + 000000000011111 = Red = 0x1F + 000001111100000 = Blue = 0x03E0 + 111110000000000 = Grn = 0x7C00 + */ + r = ((i & 0x1F) << 3)+4; + g = ((i & 0x03E0) >> 2)+4; + b = ((i & 0x7C00) >> 7)+4; + pal = (unsigned char *)d_8to24table; + for (v=0,k=0,bestdist=10000.0; v<256; v++,pal+=4) { + r1 = (int)r - (int)pal[0]; + g1 = (int)g - (int)pal[1]; + b1 = (int)b - (int)pal[2]; + dist = sqrt(((r1*r1)+(g1*g1)+(b1*b1))); + if (dist < bestdist) { + k=v; + bestdist = dist; + } + } + d_15to8table[i]=k; + } + snprintf(s, sizeof(s), "%s/glquake", com_gamedir); + Sys_mkdir (s); + snprintf(s, sizeof(s), "%s/glquake/15to8.pal", com_gamedir); + if ((f = fopen(s, "wb")) != NULL) { + fwrite(d_15to8table, 1<<15, 1, f); + fclose(f); + } + } +} + + +/* + CheckMultiTextureExtensions + + Check for ARB, SGIS, or EXT multitexture support +*/ +void +CheckMultiTextureExtensions ( void ) +{ + Con_Printf ("Checking for multitexture... "); + if (COM_CheckParm ("-nomtex")) + { + Con_Printf ("disabled\n"); + return; + } +#ifdef HAVE_DLOPEN + dlhand = dlopen (NULL, RTLD_LAZY); + if (dlhand == NULL) + { + Con_Printf ("unable to check\n"); + return; + } + if (strstr(gl_extensions, "GL_ARB_multitexture ")) + { + Con_Printf ("GL_ARB_multitexture\n"); + qglMTexCoord2f = (void *)dlsym(dlhand, "glMultiTexCoord2fARB"); + qglSelectTexture = (void *)dlsym(dlhand, "glActiveTextureARB"); + gl_mtex_enum = GL_TEXTURE0_ARB; + gl_mtexable = true; + gl_arb_mtex = true; + } else if (strstr(gl_extensions, "GL_SGIS_multitexture ")) + { + Con_Printf ("GL_SGIS_multitexture\n"); + qglMTexCoord2f = (void *)dlsym(dlhand, "glMTexCoord2fSGIS"); + qglSelectTexture = (void *)dlsym(dlhand, "glSelectTextureSGIS"); + gl_mtex_enum = TEXTURE0_SGIS; + gl_mtexable = true; + gl_arb_mtex = false; + } else if (strstr(gl_extensions, "GL_EXT_multitexture ")) + { + Con_Printf ("GL_EXT_multitexture\n"); + qglMTexCoord2f = (void *)dlsym(dlhand, "glMTexCoord2fEXT"); + qglSelectTexture = (void *)dlsym(dlhand, "glSelectTextureEXT"); + gl_mtex_enum = TEXTURE0_SGIS; + gl_mtexable = true; + gl_arb_mtex = false; + } else { + Con_Printf ("none found\n"); + } + dlclose(dlhand); + dlhand = NULL; +#else + gl_mtexable = false; +#endif +} + + +typedef void (GLAPIENTRY *gl3DfxSetDitherModeEXT_FUNC) (GrDitherMode_t mode); + +/* +=============== +GL_Init +=============== +*/ +void GL_Init (void) +{ + gl_vendor = glGetString (GL_VENDOR); + Con_Printf ("GL_VENDOR: %s\n", gl_vendor); + gl_renderer = glGetString (GL_RENDERER); + Con_Printf ("GL_RENDERER: %s\n", gl_renderer); + + gl_version = glGetString (GL_VERSION); + Con_Printf ("GL_VERSION: %s\n", gl_version); + gl_extensions = glGetString (GL_EXTENSIONS); + Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); + + CheckMultiTextureExtensions (); + + glClearColor (1,0,0,0); + glCullFace(GL_FRONT); + glEnable(GL_TEXTURE_2D); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.666); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glShadeModel (GL_FLAT); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + Con_Printf ("Dithering: "); + + dlhand = dlopen (NULL, RTLD_LAZY); + + if (dlhand == NULL) { + Con_SafePrintf ("unable to set.\n"); + return; + } + + if (strstr(gl_extensions, "3DFX_set_dither_mode")) { + gl3DfxSetDitherModeEXT_FUNC dither_select = NULL; + + dither_select = (void *) dlsym(dlhand, "gl3DfxSetDitherModeEXT"); + + if (COM_CheckParm ("-dither_2x2")) { + dither_select(GR_DITHER_2x2); + Con_Printf ("2x2.\n"); + } else if (COM_CheckParm ("-dither_4x4")) { + dither_select(GR_DITHER_4x4); + Con_Printf ("4x4.\n"); + } else { + glDisable(GL_DITHER); + Con_Printf ("disabled.\n"); + } + } + dlclose(dlhand); + dlhand = NULL; +} + +/* +================= +GL_BeginRendering + +================= +*/ +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + *x = *y = 0; + *width = scr_width; + *height = scr_height; + +// if (!wglMakeCurrent( maindc, baseRC )) +// Sys_Error ("wglMakeCurrent failed"); + +// glViewport (*x, *y, *width, *height); +} + + +void GL_EndRendering (void) +{ + glFlush(); + fxMesaSwapBuffers(); + Sbar_Changed (); +} + +static int resolutions[][3]={ + { 320, 200, GR_RESOLUTION_320x200 }, + { 320, 240, GR_RESOLUTION_320x240 }, + { 400, 256, GR_RESOLUTION_400x256 }, + { 400, 300, GR_RESOLUTION_400x300 }, + { 512, 256, GR_RESOLUTION_512x256 }, + { 512, 384, GR_RESOLUTION_512x384 }, + { 640, 200, GR_RESOLUTION_640x200 }, + { 640, 350, GR_RESOLUTION_640x350 }, + { 640, 400, GR_RESOLUTION_640x400 }, + { 640, 480, GR_RESOLUTION_640x480 }, + { 800, 600, GR_RESOLUTION_800x600 }, + { 856, 480, GR_RESOLUTION_856x480 }, + { 960, 720, GR_RESOLUTION_960x720 }, +#ifdef GR_RESOLUTION_1024x768 + { 1024, 768, GR_RESOLUTION_1024x768 }, +#endif +#ifdef GR_RESOLUTION_1152x864 + { 1152, 864, GR_RESOLUTION_1152x864 }, +#endif +#ifdef GR_RESOLUTION_1280x960 + { 1280, 960, GR_RESOLUTION_1280x960 }, +#endif +#ifdef GR_RESOLUTION_1280x1024 + { 1280, 1024, GR_RESOLUTION_1280x1024 }, +#endif +#ifdef GR_RESOLUTION_1600x1024 + { 1600, 1024, GR_RESOLUTION_1600x1024 }, +#endif +#ifdef GR_RESOLUTION_1600x1200 + { 1600, 1200, GR_RESOLUTION_1600x1200 }, +#endif +#ifdef GR_RESOLUTION_1792x1344 + { 1792, 1344, GR_RESOLUTION_1792x1344 }, +#endif +#ifdef GR_RESOLUTION_1856x1392 + { 1856, 1392, GR_RESOLUTION_1856x1392 }, +#endif +#ifdef GR_RESOLUTION_1920x1440 + { 1920, 1440, GR_RESOLUTION_1920x1440 }, +#endif +#ifdef GR_RESOLUTION_2048x1536 + { 2048, 1536, GR_RESOLUTION_2048x1536 }, +#endif +#ifdef GR_RESOLUTION_2048x2048 + { 2048, 2048, GR_RESOLUTION_2048x2048 } +#endif +}; + +#define NUM_RESOLUTIONS (sizeof(resolutions)/(sizeof(int)*3)) + + +static int +findres(int *width, int *height) +{ + int i; + + for(i=0; i < NUM_RESOLUTIONS; i++) { + if((*width <= resolutions[i][0]) && + (*height <= resolutions[i][1])) { + *width = resolutions[i][0]; + *height = resolutions[i][1]; + return resolutions[i][2]; + } + } + + *width = 640; + *height = 480; + return GR_RESOLUTION_640x480; +} + +qboolean VID_Is8bit(void) +{ + return is8bit; +} + +typedef void (GLAPIENTRY *glColorTableEXT_FUNC) (GLenum, GLenum, GLsizei, + GLenum, GLenum, const GLvoid *); +typedef void (GLAPIENTRY *gl3DfxSetPaletteEXT_FUNC) (GLuint *pal); + +void VID_Init8bitPalette() +{ + // Check for 8bit Extensions and initialize them. + int i; + + dlhand = dlopen (NULL, RTLD_LAZY); + + Con_SafePrintf ("8-bit GL extensions: "); + + if (dlhand == NULL) { + Con_SafePrintf ("unable to check.\n"); + return; + } + + if (COM_CheckParm("-no8bit")) { + Con_SafePrintf("disabled.\n"); + return; + } + + if (strstr(gl_extensions, "3DFX_set_global_palette")) { + char *oldpal; + GLubyte table[256][4]; + gl3DfxSetPaletteEXT_FUNC load_texture = NULL; + + Con_SafePrintf("3DFX_set_global_palette.\n"); + load_texture = (void *) dlsym(dlhand, "gl3DfxSetPaletteEXT"); + + glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); + oldpal = (char *) d_8to24table; //d_8to24table3dfx; + for (i=0;i<256;i++) { + table[i][2] = *oldpal++; + table[i][1] = *oldpal++; + table[i][0] = *oldpal++; + table[i][3] = 255; + oldpal++; + } + load_texture((GLuint *)table); + is8bit = true; + } else if (strstr(gl_extensions, "GL_EXT_shared_texture_palette")) { + char thePalette[256*3]; + char *oldPalette, *newPalette; + glColorTableEXT_FUNC load_texture = NULL; + + Con_SafePrintf("GL_EXT_shared.\n"); + load_texture = (void *) dlsym(dlhand, "glColorTableEXT"); + + glEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); + oldPalette = (char *) d_8to24table; //d_8to24table3dfx; + newPalette = thePalette; + for (i=0;i<256;i++) { + *newPalette++ = *oldPalette++; + *newPalette++ = *oldPalette++; + *newPalette++ = *oldPalette++; + oldPalette++; + } + load_texture(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette); + is8bit = true; + } + + dlclose(dlhand); + dlhand = NULL; + Con_SafePrintf ("not found.\n"); +} + +void VID_Init(unsigned char *palette) +{ + int i; + GLint attribs[32]; + char gldir[MAX_OSPATH]; + int width = 640, height = 480; + + vid_mode = Cvar_Get ("vid_mode", "5", 0, "None"); + vid_redrawfull = Cvar_Get ("vid_redrawfull", "0", 0," None"); + vid_waitforrefresh = Cvar_Get ("vid_waitforrefresh", "0", CVAR_ARCHIVE, + "None"); + + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.colormap = host_colormap; + vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); + +// interpret command-line params + +// set vid parameters + attribs[0] = FXMESA_DOUBLEBUFFER; + attribs[1] = FXMESA_ALPHA_SIZE; + attribs[2] = 1; + attribs[3] = FXMESA_DEPTH_SIZE; + attribs[4] = 1; + attribs[5] = FXMESA_NONE; + + if ((i = COM_CheckParm("-width")) != 0) + width = atoi(com_argv[i+1]); + if ((i = COM_CheckParm("-height")) != 0) + height = atoi(com_argv[i+1]); + + if ((i = COM_CheckParm("-conwidth")) != 0) + vid.conwidth = atoi(com_argv[i+1]); + else + vid.conwidth = 640; + + vid.conwidth &= 0xfff8; // make it a multiple of eight + + if (vid.conwidth < 320) + vid.conwidth = 320; + + // pick a conheight that matches with correct aspect + vid.conheight = vid.conwidth*3 / 4; + + if ((i = COM_CheckParm("-conheight")) != 0) + vid.conheight = atoi(com_argv[i+1]); + if (vid.conheight < 200) + vid.conheight = 200; + + fc = fxMesaCreateContext(0, findres(&width, &height), GR_REFRESH_75Hz, + attribs); + if (!fc) + Sys_Error("Unable to create 3DFX context.\n"); + + scr_width = width; + scr_height = height; + + fxMesaMakeCurrent(fc); + + if (vid.conheight > height) + vid.conheight = height; + if (vid.conwidth > width) + vid.conwidth = width; + vid.width = vid.conwidth; + vid.height = vid.conheight; + + vid.aspect = ((float)vid.height / (float)vid.width) * (320.0 / 240.0); + vid.numpages = 2; + + InitSig(); // trap evil signals + + GL_Init(); + + snprintf(gldir, sizeof(gldir), "%s/glquake", com_gamedir); + Sys_mkdir (gldir); + + VID_SetPalette(palette); + + // Check for 3DFX Extensions and initialize them. + VID_Init8bitPalette(); + + Con_SafePrintf ("Video mode %dx%d initialized.\n", width, height); + + vid.recalc_refdef = 1; // force a surface cache flush +} + +void VID_ExtraOptionDraw(unsigned int options_draw_cursor) +{ +/* Port specific Options menu entrys */ +} + +void VID_ExtraOptionCmd(int option_cursor) +{ +/* + switch(option_cursor) + { + case 12: // Always start with 12 + break; + } +*/ +} +void VID_InitCvars () +{ + gl_triplebuffer = Cvar_Get ("gl_triplebuffer","1",CVAR_ARCHIVE,"None"); +} + +void +VID_LockBuffer ( void ) +{ +} + +void +VID_UnlockBuffer ( void ) +{ +} + +void VID_SetCaption (char *text) +{ +} diff --git a/source/vid_mgl.c b/source/vid_mgl.c new file mode 100644 index 0000000..c11a930 --- /dev/null +++ b/source/vid_mgl.c @@ -0,0 +1,3451 @@ +/* + vid_mgl.c + + Win32 Scitech MGL video driver + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include + +#include "quakedef.h" +#include "winquake.h" +#include "sys.h" +#include "d_local.h" +#include "resource.h" +#include "in_win.h" +#include "keys.h" +#include "screen.h" +#include "wad.h" +#include "cmd.h" +#include "qendian.h" +#include "draw.h" +#include "console.h" +#include "sound.h" +#include "cdaudio.h" +#include "qargs.h" + +#define MINIMUM_MEMORY 0x550000 + +#define MAX_MODE_LIST 30 +#define VID_ROW_SIZE 3 + + +/* Unused */ +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; +byte *VGA_pagebase; + +qboolean dibonly; + +extern qboolean Minimized; + +HWND mainwindow; + +HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); + +int DIBWidth, DIBHeight; +qboolean DDActive; +RECT WindowRect; +DWORD WindowStyle, ExWindowStyle; + +int window_center_x, window_center_y, window_x, window_y, window_width, window_height; +RECT window_rect; + +static DEVMODE gdevmode; +static qboolean startwindowed = 0, windowed_mode_set = 0; +static int firstupdate = 1; +static qboolean vid_initialized = false, vid_palettized; +static int lockcount; +static int vid_fulldib_on_focus_mode; +static qboolean force_minimized, in_mode_set, is_mode0x13, force_mode_set; +static int vid_stretched, windowed_mouse; +static qboolean palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic; +static HICON hIcon; + +extern viddef_t vid; // global video state + +#define MODE_WINDOWED 0 +#define MODE_SETTABLE_WINDOW 2 +#define NO_MODE (MODE_WINDOWED - 1) +#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 3) + +// Note that 0 is MODE_WINDOWED +cvar_t *vid_mode; +// Note that 0 is MODE_WINDOWED +cvar_t *_vid_default_mode; +// Note that 3 is MODE_FULLSCREEN_DEFAULT +cvar_t *_vid_default_mode_win; +cvar_t *vid_wait; +cvar_t *vid_nopageflip; +cvar_t *_vid_wait_override; +cvar_t *vid_config_x; +cvar_t *vid_config_y; +cvar_t *vid_stretch_by_2; +cvar_t *_windowed_mouse; +cvar_t *vid_fullscreen_mode; +cvar_t *vid_windowed_mode; +cvar_t *block_switch; +cvar_t *vid_window_x; +cvar_t *vid_window_y; + +typedef struct { + int width; + int height; +} lmode_t; + +lmode_t lowresmodes[] = { + {320, 200}, + {320, 240}, + {400, 300}, + {512, 384}, +}; + +int vid_modenum = NO_MODE; +int vid_testingmode, vid_realmode; +double vid_testendtime; +int vid_default = MODE_WINDOWED; +static int windowed_default; + +modestate_t modestate = MS_UNINIT; + +static byte *vid_surfcache; +static int vid_surfcachesize; +static int VID_highhunkmark; + +unsigned char vid_curpal[256*3]; + +unsigned short d_8to16table[256]; +unsigned d_8to24table[256]; + +int driver = grDETECT,mode; +qboolean useWinDirect = true, useDirectDraw = true; +MGLDC *mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL; + +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int mode13; + int stretched; + int dib; + int fullscreen; + int bpp; + int halfscreen; + char modedesc[13]; +} vmode_t; + +static vmode_t modelist[MAX_MODE_LIST]; +static int nummodes; + +int aPage; // Current active display page +int vPage; // Current visible display page +int waitVRT = true; // True to wait for retrace on flip + +static vmode_t badmode; + +static byte backingbuf[48*24]; + +void VID_MenuDraw (void); +void VID_MenuKey (int key); + +LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +void AppActivate(BOOL fActive, BOOL minimize); + +/* +================ +VID_InitCvars +================ +*/ +void +VID_InitCvars () +{ + // It may not look like it, but this is important +} + +/* +================ +VID_RememberWindowPos +================ +*/ +void VID_RememberWindowPos (void) +{ + RECT rect; + + if (GetWindowRect (mainwindow, &rect)) + { + if ((rect.left < GetSystemMetrics (SM_CXSCREEN)) && + (rect.top < GetSystemMetrics (SM_CYSCREEN)) && + (rect.right > 0) && + (rect.bottom > 0)) + { + Cvar_SetValue (vid_window_x, (float)rect.left); + Cvar_SetValue (vid_window_y, (float)rect.top); + } + } +} + + +/* +================ +VID_CheckWindowXY +================ +*/ +void VID_CheckWindowXY (void) +{ + + if (((int)vid_window_x->value > (GetSystemMetrics (SM_CXSCREEN) - 160)) || + ((int)vid_window_y->value > (GetSystemMetrics (SM_CYSCREEN) - 120)) || + ((int)vid_window_x->value < 0) || + ((int)vid_window_y->value < 0)) + { + Cvar_SetValue (vid_window_x, 0.0); + Cvar_SetValue (vid_window_y, 0.0 ); + } +} + + +/* +================ +VID_UpdateWindowStatus +================ +*/ +void VID_UpdateWindowStatus (void) +{ + + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + window_center_x = (window_rect.left + window_rect.right) / 2; + window_center_y = (window_rect.top + window_rect.bottom) / 2; + + IN_UpdateClipCursor (); +} + + +extern void CL_ClearStates (); + +/* +================ +ClearAllStates +================ +*/ +void ClearAllStates (void) +{ + CL_ClearStates (); + Key_ClearStates (); + IN_ClearStates (); +} + + +/* +================ +VID_CheckAdequateMem +================ +*/ +qboolean VID_CheckAdequateMem (int width, int height) +{ + int tbuffersize; + + tbuffersize = width * height * sizeof (*d_pzbuffer); + + tbuffersize += D_SurfaceCacheForRes (width, height); + +// see if there's enough memory, allowing for the normal mode 0x13 pixel, +// z, and surface buffers + if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 + + 0x10000 * 3) < MINIMUM_MEMORY) + { + return false; // not enough memory for mode + } + + return true; +} + + +/* +================ +VID_AllocBuffers +================ +*/ +qboolean VID_AllocBuffers (int width, int height) +{ + int tsize, tbuffersize; + + tbuffersize = width * height * sizeof (*d_pzbuffer); + + tsize = D_SurfaceCacheForRes (width, height); + + tbuffersize += tsize; + +// see if there's enough memory, allowing for the normal mode 0x13 pixel, +// z, and surface buffers + if ((host_parms.memsize - tbuffersize + SURFCACHE_SIZE_AT_320X200 + + 0x10000 * 3) < MINIMUM_MEMORY) + { + Con_SafePrintf ("Not enough memory for video mode\n"); + return false; // not enough memory for mode + } + + vid_surfcachesize = tsize; + + if (d_pzbuffer) + { + D_FlushCaches (); + Hunk_FreeToHighMark (VID_highhunkmark); + d_pzbuffer = NULL; + } + + VID_highhunkmark = Hunk_HighMark (); + + d_pzbuffer = Hunk_HighAllocName (tbuffersize, "video"); + + vid_surfcache = (byte *)d_pzbuffer + + width * height * sizeof (*d_pzbuffer); + + return true; +} + + +void initFatalError(void) +{ + MGL_exit(); + MGL_fatalError(MGL_errorMsg(MGL_result())); + exit(EXIT_FAILURE); +} + +#if 0 //def NEW_SUSPEND + +int VID_Suspend (MGLDC *dc, int flags) +{ + int i; + if (flags & MGL_DEACTIVATE) + { + IN_RestoreOriginalMouseState (); + CDAudio_Pause (); + + // keep WM_PAINT from trying to redraw + in_mode_set = true; + block_drawing = true; + } + else if (flags & MGL_REACTIVATE) + { + IN_SetQuakeMouseState (); + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + CDAudio_Resume (); + in_mode_set = false; + + block_drawing = false; +// vid.recalc_refdef = 1; + force_mode_set = 1; + i = msg_suppress_1; + msg_suppress_1 = 1; + VID_Fullscreen_f(); + msg_suppress_1 = i; + force_mode_set = 0; + } + + return 1; +} + +#else + +int VID_Suspend (MGLDC *dc, int flags) +{ + + if (flags & MGL_DEACTIVATE) + { + // FIXME: this doesn't currently work on NT + if (block_switch->value && !WinNT) + { + return MGL_NO_DEACTIVATE; + } + + S_BlockSound (); + S_ClearBuffer (); + + IN_RestoreOriginalMouseState (); + CDAudio_Pause (); + + // keep WM_PAINT from trying to redraw + in_mode_set = true; + + block_drawing = true; // so we don't try to draw while switched away + } + else if (flags & MGL_REACTIVATE) + { + IN_SetQuakeMouseState (); + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + CDAudio_Resume (); + S_UnblockSound (); + + in_mode_set = false; + + vid.recalc_refdef = 1; + + block_drawing = false; + } + + return MGL_NO_SUSPEND_APP; +} +#endif + + +void registerAllDispDrivers(void) +{ + /* Event though these driver require WinDirect, we register + * them so that they will still be available even if DirectDraw + * is present and the user has disable the high performance + * WinDirect modes. + */ + MGL_registerDriver(MGL_VGA8NAME,VGA8_driver); +// MGL_registerDriver(MGL_VGAXNAME,VGAX_driver); + + /* Register display drivers */ + if (useWinDirect) + { +//we don't want VESA 1.X drivers MGL_registerDriver(MGL_SVGA8NAME,SVGA8_driver); + MGL_registerDriver(MGL_LINEAR8NAME,LINEAR8_driver); + + if (!COM_CheckParm ("-novbeaf")) + MGL_registerDriver(MGL_ACCEL8NAME,ACCEL8_driver); + } + + if (useDirectDraw) + { + MGL_registerDriver(MGL_DDRAW8NAME,DDRAW8_driver); + } +} + + +void registerAllMemDrivers(void) +{ + /* Register memory context drivers */ + MGL_registerDriver(MGL_PACKED8NAME,PACKED8_driver); +} + + +void VID_InitMGLFull (HINSTANCE hInstance) +{ + int i, xRes, yRes, bits, lowres, curmode, temp; + int lowstretchedres, stretchedmode = 0, lowstretched; + uchar *m; + +// FIXME: NT is checked for because MGL currently has a bug that causes it +// to try to use WinDirect modes even on NT + if (COM_CheckParm("-nowindirect") || + COM_CheckParm("-nowd") || + COM_CheckParm("-novesa") || + WinNT) + { + useWinDirect = false; + } + + if (COM_CheckParm("-nodirectdraw") || COM_CheckParm("-noddraw") || COM_CheckParm("-nodd")) + useDirectDraw = false; + + // Initialise the MGL + MGL_unregisterAllDrivers(); + registerAllDispDrivers(); + registerAllMemDrivers(); + MGL_detectGraph(&driver,&mode); + m = MGL_availableModes(); + + if (m[0] != 0xFF) + { + lowres = lowstretchedres = 99999; + lowstretched = 0; + curmode = 0; + + // find the lowest-res mode, or a mode we can stretch up to and get + // lowest-res that way + for (i = 0; m[i] != 0xFF; i++) + { + MGL_modeResolution(m[i], &xRes, &yRes,&bits); + + if ((bits == 8) && + (xRes <= MAXWIDTH) && + (yRes <= MAXHEIGHT) && + (curmode < MAX_MODE_LIST)) + { + if (m[i] == grVGA_320x200x256) + is_mode0x13 = true; + + if (!COM_CheckParm("-noforcevga")) + { + if (m[i] == grVGA_320x200x256) + { + mode = i; + break; + } + } + + if (xRes < lowres) + { + lowres = xRes; + mode = i; + } + + if ((xRes < lowstretchedres) && ((xRes >> 1) >= 320)) + { + lowstretchedres = xRes >> 1; + stretchedmode = i; + } + } + + curmode++; + } + + // if there's a mode we can stretch by 2 up to, thereby effectively getting + // a lower-res mode than the lowest-res real but still at least 320x200, that + // will be our default mode + if (lowstretchedres < lowres) + { + mode = stretchedmode; + lowres = lowstretchedres; + lowstretched = 1; + } + + // build the mode list, leaving room for the low-res stretched mode, if any + nummodes++; // leave room for default mode + + for (i = 0; m[i] != 0xFF; i++) + { + MGL_modeResolution(m[i], &xRes, &yRes,&bits); + + if ((bits == 8) && + (xRes <= MAXWIDTH) && + (yRes <= MAXHEIGHT) && + (nummodes < MAX_MODE_LIST)) + { + if (i == mode) + { + if (lowstretched) + { + stretchedmode = nummodes; + curmode = nummodes++; + } + else + { + curmode = MODE_FULLSCREEN_DEFAULT; + } + } + else + { + curmode = nummodes++; + } + + modelist[curmode].type = MS_FULLSCREEN; + modelist[curmode].width = xRes; + modelist[curmode].height = yRes; + snprintf (modelist[curmode].modedesc, sizeof(modelist[curmode].modedesc), "%dx%d", xRes, yRes); + + if (m[i] == grVGA_320x200x256) + modelist[curmode].mode13 = 1; + else + modelist[curmode].mode13 = 0; + + modelist[curmode].modenum = m[i]; + modelist[curmode].stretched = 0; + modelist[curmode].dib = 0; + modelist[curmode].fullscreen = 1; + modelist[curmode].halfscreen = 0; + modelist[curmode].bpp = 8; + } + } + + if (lowstretched) + { + modelist[MODE_FULLSCREEN_DEFAULT] = modelist[stretchedmode]; + modelist[MODE_FULLSCREEN_DEFAULT].stretched = 1; + modelist[MODE_FULLSCREEN_DEFAULT].width >>= 1; + modelist[MODE_FULLSCREEN_DEFAULT].height >>= 1; + snprintf (modelist[MODE_FULLSCREEN_DEFAULT].modedesc, sizeof(modelist[MODE_FULLSCREEN_DEFAULT].modedesc), "%dx%d", + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height); + } + + vid_default = MODE_FULLSCREEN_DEFAULT; + + temp = m[0]; + + if (!MGL_init(&driver, &temp, "")) + { + initFatalError(); + } + } + + MGL_setSuspendAppCallback(VID_Suspend); +} + + +MGLDC *createDisplayDC(int forcemem) +/**************************************************************************** +* +* Function: createDisplayDC +* Returns: Pointer to the MGL device context to use for the application +* +* Description: Initialises the MGL and creates an appropriate display +* device context to be used by the GUI. This creates and +* apropriate device context depending on the system being +* compile for, and should be the only place where system +* specific code is required. +* +****************************************************************************/ +{ + MGLDC *dc; + pixel_format_t pf; + int npages; + + // Start the specified video mode + if (!MGL_changeDisplayMode(mode)) + initFatalError(); + + npages = MGL_availablePages(mode); + + if (npages > 3) + npages = 3; + + if (!COM_CheckParm ("-notriplebuf")) + { + if (npages > 2) + { + npages = 2; + } + } + + if ((dc = MGL_createDisplayDC(npages)) == NULL) + return NULL; + + if (!forcemem && (MGL_surfaceAccessType(dc)) == MGL_LINEAR_ACCESS && (dc->mi.maxPage > 0)) + { + MGL_makeCurrentDC(dc); + memdc = NULL; + } + else + { + // Set up for blitting from a memory buffer + memdc = MGL_createMemoryDC(MGL_sizex(dc)+1,MGL_sizey(dc)+1,8,&pf); + MGL_makeCurrentDC(memdc); + } + + // Enable page flipping even for even for blitted surfaces + if (forcemem) + { + vid.numpages = 1; + } + else + { + vid.numpages = dc->mi.maxPage + 1; + + if (vid.numpages > 1) + { + // Set up for page flipping + MGL_setActivePage(dc, aPage = 1); + MGL_setVisualPage(dc, vPage = 0, false); + } + + if (vid.numpages > 3) + vid.numpages = 3; + } + + if (vid.numpages == 2) + waitVRT = true; + else + waitVRT = false; + + return dc; +} + + +void VID_InitMGLDIB (HINSTANCE hInstance) +{ + WNDCLASS wc; + HDC hdc; + + hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_ICON2)); + + /* Register the frame class */ + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)MainWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = "WinQuake"; + + if (!RegisterClass (&wc) ) + Sys_Error ("Couldn't register window class"); + + /* Find the size for the DIB window */ + /* Initialise the MGL for windowed operation */ + MGL_setAppInstance(hInstance); + registerAllMemDrivers(); + MGL_initWindowed(""); + + modelist[0].type = MS_WINDOWED; + modelist[0].width = 320; + modelist[0].height = 240; + strcpy (modelist[0].modedesc, "320x240"); + modelist[0].mode13 = 0; + modelist[0].modenum = MODE_WINDOWED; + modelist[0].stretched = 0; + modelist[0].dib = 1; + modelist[0].fullscreen = 0; + modelist[0].halfscreen = 0; + modelist[0].bpp = 8; + + modelist[1].type = MS_WINDOWED; + modelist[1].width = 640; + modelist[1].height = 480; + strcpy (modelist[1].modedesc, "640x480"); + modelist[1].mode13 = 0; + modelist[1].modenum = MODE_WINDOWED + 1; + modelist[1].stretched = 1; + modelist[1].dib = 1; + modelist[1].fullscreen = 0; + modelist[1].halfscreen = 0; + modelist[1].bpp = 8; + + modelist[2].type = MS_WINDOWED; + modelist[2].width = 800; + modelist[2].height = 600; + strcpy (modelist[2].modedesc, "800x600"); + modelist[2].mode13 = 0; + modelist[2].modenum = MODE_WINDOWED + 2; + modelist[2].stretched = 1; + modelist[2].dib = 1; + modelist[2].fullscreen = 0; + modelist[2].halfscreen = 0; + modelist[2].bpp = 8; + +// automatically stretch the default mode up if > 640x480 desktop resolution + hdc = GetDC(NULL); + + if ((GetDeviceCaps(hdc, HORZRES) > 640) && !COM_CheckParm("-noautostretch")) + { + vid_default = MODE_WINDOWED + 1; + } + else + { + vid_default = MODE_WINDOWED; + } + + windowed_default = vid_default; + + ReleaseDC(NULL,hdc); + + nummodes = 3; // reserve space for windowed mode + + DDActive = 0; +} + + +/* +================= +VID_InitFullDIB +================= +*/ +void VID_InitFullDIB (HINSTANCE hInstance) +{ + DEVMODE devmode; + int i, j, modenum, existingmode, originalnummodes, lowestres; + int numlowresmodes, bpp, done; + int cstretch, istretch, mstretch = 0; + BOOL stat; + +// enumerate 8 bpp modes + originalnummodes = nummodes; + modenum = 0; + lowestres = 99999; + + do + { + stat = EnumDisplaySettings (NULL, modenum, &devmode); + + if ((devmode.dmBitsPerPel == 8) && + (devmode.dmPelsWidth <= MAXWIDTH) && + (devmode.dmPelsHeight <= MAXHEIGHT) && + (nummodes < MAX_MODE_LIST)) + { + devmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT; + + if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == + DISP_CHANGE_SUCCESSFUL) + { + modelist[nummodes].type = MS_FULLDIB; + modelist[nummodes].width = devmode.dmPelsWidth; + modelist[nummodes].height = devmode.dmPelsHeight; + modelist[nummodes].modenum = 0; + modelist[nummodes].mode13 = 0; + modelist[nummodes].stretched = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = devmode.dmBitsPerPel; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc),"%ldx%ld", + devmode.dmPelsWidth, devmode.dmPelsHeight); + + // if the width is more than twice the height, reduce it by half because this + // is probably a dual-screen monitor + if (!COM_CheckParm("-noadjustaspect")) + { + if (modelist[nummodes].width > (modelist[nummodes].height << 1)) + { + modelist[nummodes].width >>= 1; + modelist[nummodes].halfscreen = 1; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%d", + modelist[nummodes].width, + modelist[nummodes].height); + } + } + + for (i=originalnummodes, existingmode = 0 ; i 8 bpp + if (nummodes == originalnummodes) + { + modenum = 0; + lowestres = 99999; + + Con_SafePrintf ("No 8-bpp fullscreen DIB modes found\n"); + + do + { + stat = EnumDisplaySettings (NULL, modenum, &devmode); + + if ((((devmode.dmPelsWidth <= MAXWIDTH) && + (devmode.dmPelsHeight <= MAXHEIGHT)) || + (!COM_CheckParm("-noadjustaspect") && + (devmode.dmPelsWidth <= (MAXWIDTH*2)) && + (devmode.dmPelsWidth > (devmode.dmPelsHeight*2)))) && + (nummodes < MAX_MODE_LIST) && + (devmode.dmBitsPerPel > 8)) + { + devmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT; + + if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == + DISP_CHANGE_SUCCESSFUL) + { + modelist[nummodes].type = MS_FULLDIB; + modelist[nummodes].width = devmode.dmPelsWidth; + modelist[nummodes].height = devmode.dmPelsHeight; + modelist[nummodes].modenum = 0; + modelist[nummodes].mode13 = 0; + modelist[nummodes].stretched = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = devmode.dmBitsPerPel; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc),"%ldx%ld", + devmode.dmPelsWidth, devmode.dmPelsHeight); + + // if the width is more than twice the height, reduce it by half because this + // is probably a dual-screen monitor + if (!COM_CheckParm("-noadjustaspect")) + { + if (modelist[nummodes].width > (modelist[nummodes].height*2)) + { + modelist[nummodes].width >>= 1; + modelist[nummodes].halfscreen = 1; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%d", + modelist[nummodes].width, + modelist[nummodes].height); + } + } + + for (i=originalnummodes, existingmode = 0 ; i= modelist[i].bpp)) + { + existingmode = 1; + break; + } + } + + if (!existingmode) + { + if (modelist[nummodes].width < lowestres) + lowestres = modelist[nummodes].width; + + nummodes++; + } + } + } + + switch (bpp) + { + case 8: + bpp = 16; + break; + + case 16: + bpp = 32; + break; + + case 32: + done = 1; + break; + } + } + +// now add the lowest stretch-by-2 pseudo-modes between 320-wide +// (inclusive) and lowest real res (not inclusive) +// don't bother if we have a real VGA mode 0x13 mode + if (!is_mode0x13) + { + for (i=originalnummodes, cstretch=0 ; i> 1) < lowestres) && + ((modelist[i].width >> 1) >= 320)) + { + lowestres = modelist[i].width >> 1; + cstretch = 1; + mstretch = i; + } + } + + if ((nummodes + cstretch) > MAX_MODE_LIST) + cstretch = MAX_MODE_LIST - nummodes; + + if (cstretch > 0) + { + for (i=(nummodes-1) ; i>=originalnummodes ; i--) + modelist[i+cstretch] = modelist[i]; + + nummodes += cstretch; + istretch = originalnummodes; + + modelist[istretch] = modelist[mstretch]; + modelist[istretch].width >>= 1; + modelist[istretch].height >>= 1; + modelist[istretch].stretched = 1; + snprintf (modelist[istretch].modedesc, sizeof(modelist[istretch].modedesc),"%dx%d", + modelist[istretch].width, modelist[istretch].height); + } + } + + if (nummodes != originalnummodes) + vid_default = MODE_FULLSCREEN_DEFAULT; + else + Con_SafePrintf ("No fullscreen DIB modes found\n"); +} + + +/* +================= +VID_NumModes +================= +*/ +int VID_NumModes (void) +{ + return nummodes; +} + + +/* +================= +VID_GetModePtr +================= +*/ +vmode_t *VID_GetModePtr (int modenum) +{ + + if ((modenum >= 0) && (modenum < nummodes)) + return &modelist[modenum]; + else + return &badmode; +} + + +/* +================= +VID_CheckModedescFixup +================= +*/ +void VID_CheckModedescFixup (int mode) +{ + int x, y, stretch; + + if (mode == MODE_SETTABLE_WINDOW) + { + modelist[mode].stretched = (int)vid_stretch_by_2->value; + stretch = modelist[mode].stretched; + + if (vid_config_x->value < (320 << stretch)) + vid_config_x->value = 320 << stretch; + + if (vid_config_y->value < (200 << stretch)) + vid_config_y->value = 200 << stretch; + + x = (int)vid_config_x->value; + y = (int)vid_config_y->value; + snprintf (modelist[mode].modedesc, sizeof(modelist[mode].modedesc), "%dx%d", x, y); + modelist[mode].width = x; + modelist[mode].height = y; + } +} + + +/* +================= +VID_GetModeDescriptionMemCheck +================= +*/ +char *VID_GetModeDescriptionMemCheck (int mode) +{ + char *pinfo; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + VID_CheckModedescFixup (mode); + + pv = VID_GetModePtr (mode); + pinfo = pv->modedesc; + + if (VID_CheckAdequateMem (pv->width, pv->height)) + { + return pinfo; + } + else + { + return NULL; + } +} + + +/* +================= +VID_GetModeDescription +================= +*/ +char *VID_GetModeDescription (int mode) +{ + char *pinfo; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + VID_CheckModedescFixup (mode); + + pv = VID_GetModePtr (mode); + pinfo = pv->modedesc; + return pinfo; +} + + +/* +================= +VID_GetModeDescription2 + +Tacks on "windowed" or "fullscreen" +================= +*/ +char *VID_GetModeDescription2 (int mode) +{ + static char pinfo[40]; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + VID_CheckModedescFixup (mode); + + pv = VID_GetModePtr (mode); + + if (modelist[mode].type == MS_FULLSCREEN) + { + snprintf(pinfo,sizeof(pinfo),"%s fullscreen", pv->modedesc); + } + else if (modelist[mode].type == MS_FULLDIB) + { + snprintf(pinfo,sizeof(pinfo),"%s fullscreen", pv->modedesc); + } + else + { + snprintf(pinfo,sizeof(pinfo), "%s windowed", pv->modedesc); + } + + return pinfo; +} + + +// KJB: Added this to return the mode driver name in description for console + +char *VID_GetExtModeDescription (int mode) +{ + static char pinfo[40]; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + VID_CheckModedescFixup (mode); + + pv = VID_GetModePtr (mode); + if (modelist[mode].type == MS_FULLSCREEN) + { + snprintf(pinfo, sizeof(pinfo), "%s fullscreen %s",pv->modedesc, + MGL_modeDriverName(pv->modenum)); + } + else if (modelist[mode].type == MS_FULLDIB) + { + snprintf(pinfo, sizeof(pinfo), "%s fullscreen DIB", pv->modedesc); + } + else + { + snprintf(pinfo, sizeof(pinfo), "%s windowed", pv->modedesc); + } + + return pinfo; +} + + +void DestroyDIBWindow (void) +{ + + if (modestate == MS_WINDOWED) + { + // destroy the associated MGL DC's; the window gets reused + if (windc) + MGL_destroyDC(windc); + if (dibdc) + MGL_destroyDC(dibdc); + windc = dibdc = NULL; + } +} + + +void DestroyFullscreenWindow (void) +{ + + if (modestate == MS_FULLSCREEN) + { + // destroy the existing fullscreen mode and DC's + if (mgldc) + MGL_destroyDC (mgldc); + if (memdc) + MGL_destroyDC (memdc); + mgldc = memdc = NULL; + } +} + + + +void DestroyFullDIBWindow (void) +{ + if (modestate == MS_FULLDIB) + { + ChangeDisplaySettings (NULL, CDS_FULLSCREEN); + + // Destroy the fullscreen DIB window and associated MGL DC's + if (windc) + MGL_destroyDC(windc); + if (dibdc) + MGL_destroyDC(dibdc); + windc = dibdc = NULL; + } +} + + +qboolean VID_SetWindowedMode (int modenum) +{ + HDC hdc; + pixel_format_t pf; + qboolean stretched; + int lastmodestate; + + if (!windowed_mode_set) + { + if (COM_CheckParm ("-resetwinpos")) + { + Cvar_SetValue (vid_window_x, 0.0); + Cvar_SetValue (vid_window_y, 0.0); + } + + windowed_mode_set = 1; + } + + VID_CheckModedescFixup (modenum); + + DDActive = 0; + lastmodestate = modestate; + + DestroyFullscreenWindow (); + DestroyFullDIBWindow (); + + if (windc) + MGL_destroyDC(windc); + if (dibdc) + MGL_destroyDC(dibdc); + windc = dibdc = NULL; + +// KJB: Signal to the MGL that we are going back to windowed mode + if (!MGL_changeDisplayMode(grWINDOWED)) + initFatalError(); + + WindowRect.top = WindowRect.left = 0; + + WindowRect.right = modelist[modenum].width; + WindowRect.bottom = modelist[modenum].height; + stretched = modelist[modenum].stretched; + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + if (stretched) + { + DIBWidth >>= 1; + DIBHeight >>= 1; + } + + WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | + WS_CLIPCHILDREN; + ExWindowStyle = 0; + AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0); + +// the first time we're called to set the mode, create the window we'll use +// for the rest of the session + if (!vid_mode_set) + { + mainwindow = CreateWindowEx ( + ExWindowStyle, + "WinQuake", + PROGRAM, + WindowStyle, + 0, 0, + WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, + NULL, + NULL, + global_hInstance, + NULL); + + if (!mainwindow) + Sys_Error ("Couldn't create DIB window"); + + // tell MGL to use this window for fullscreen modes + MGL_registerFullScreenWindow (mainwindow); + + vid_mode_set = true; + } + else + { + SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE); + SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle); + } + + if (!SetWindowPos (mainwindow, + NULL, + 0, 0, + WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, + SWP_NOCOPYBITS | SWP_NOZORDER | + SWP_HIDEWINDOW)) + { + Sys_Error ("Couldn't resize DIB window"); + } + + if (hide_window) + return true; + +// position and show the DIB window + VID_CheckWindowXY (); + SetWindowPos (mainwindow, NULL, (int)vid_window_x->value, + (int)vid_window_y->value, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + + if (force_minimized) + ShowWindow (mainwindow, SW_MINIMIZE); + else + ShowWindow (mainwindow, SW_SHOWDEFAULT); + + UpdateWindow (mainwindow); + + modestate = MS_WINDOWED; + vid_fulldib_on_focus_mode = 0; + +// because we have set the background brush for the window to NULL +// (to avoid flickering when re-sizing the window on the desktop), +// we clear the window to black when created, otherwise it will be +// empty while Quake starts up. + hdc = GetDC(mainwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(mainwindow, hdc); + + /* Create the MGL window DC and the MGL memory DC */ + if ((windc = MGL_createWindowedDC(mainwindow)) == NULL) + MGL_fatalError("Unable to create Windowed DC!"); + + if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL) + MGL_fatalError("Unable to create Memory DC!"); + + MGL_makeCurrentDC(dibdc); + + vid.buffer = vid.conbuffer = vid.direct = dibdc->surface; + vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine; + vid.numpages = 1; + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.height = vid.conheight = DIBHeight; + vid.width = vid.conwidth = DIBWidth; + vid.aspect = ((float)vid.height / (float)vid.width) * + (320.0 / 240.0); + + vid_stretched = stretched; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + + +qboolean VID_SetFullscreenMode (int modenum) +{ + + DDActive = 1; + + DestroyDIBWindow (); + DestroyFullDIBWindow (); + + mode = modelist[modenum].modenum; + + // Destroy old DC's, resetting back to fullscreen mode + if (mgldc) + MGL_destroyDC (mgldc); + if (memdc) + MGL_destroyDC (memdc); + mgldc = memdc = NULL; + + if ((mgldc = createDisplayDC (modelist[modenum].stretched || + (int)vid_nopageflip->value)) == NULL) + { + return false; + } + + modestate = MS_FULLSCREEN; + vid_fulldib_on_focus_mode = 0; + + vid.buffer = vid.conbuffer = vid.direct = NULL; + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + DIBHeight = vid.height = vid.conheight = modelist[modenum].height; + DIBWidth = vid.width = vid.conwidth = modelist[modenum].width; + vid.aspect = ((float)vid.height / (float)vid.width) * + (320.0 / 240.0); + + vid_stretched = modelist[modenum].stretched; + +// needed because we're not getting WM_MOVE messages fullscreen on NT + window_x = 0; + window_y = 0; + +// set the large icon, so the Quake icon will show up in the taskbar + SendMessage (mainwindow, WM_SETICON, (WPARAM)1, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)0, (LPARAM)hIcon); + +// shouldn't be needed, but Kendall needs to let us get the activation +// message for this not to be needed on NT + AppActivate (true, false); + + return true; +} + + +qboolean VID_SetFullDIBMode (int modenum) +{ + HDC hdc; + pixel_format_t pf; + int lastmodestate; + + DDActive = 0; + + DestroyFullscreenWindow (); + DestroyDIBWindow (); + + if (windc) + MGL_destroyDC(windc); + if (dibdc) + MGL_destroyDC(dibdc); + windc = dibdc = NULL; + + // KJB: Signal to the MGL that we are going back to windowed mode + if (!MGL_changeDisplayMode(grWINDOWED)) + initFatalError(); + + gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + gdevmode.dmBitsPerPel = modelist[modenum].bpp; + gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].stretched << + modelist[modenum].halfscreen; + gdevmode.dmPelsHeight = modelist[modenum].height << modelist[modenum].stretched; + gdevmode.dmSize = sizeof (gdevmode); + + if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + Sys_Error ("Couldn't set fullscreen DIB mode"); + + lastmodestate = modestate; + modestate = MS_FULLDIB; + vid_fulldib_on_focus_mode = modenum; + + WindowRect.top = WindowRect.left = 0; + + hdc = GetDC(NULL); + + WindowRect.right = modelist[modenum].width << modelist[modenum].stretched; + WindowRect.bottom = modelist[modenum].height << modelist[modenum].stretched; + + ReleaseDC(NULL,hdc); + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + WindowStyle = WS_POPUP | WS_SYSMENU | WS_CLIPSIBLINGS | WS_CLIPCHILDREN; + ExWindowStyle = 0; + AdjustWindowRectEx(&WindowRect, WindowStyle, FALSE, 0); + + SetWindowLong(mainwindow, GWL_STYLE, WindowStyle | WS_VISIBLE); + SetWindowLong(mainwindow, GWL_EXSTYLE, ExWindowStyle); + + if (!SetWindowPos (mainwindow, + NULL, + 0, 0, + WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, + SWP_NOCOPYBITS | SWP_NOZORDER)) + { + Sys_Error ("Couldn't resize DIB window"); + } + +// position and show the DIB window + SetWindowPos (mainwindow, HWND_TOPMOST, 0, 0, 0, 0, + SWP_NOSIZE | SWP_SHOWWINDOW | SWP_DRAWFRAME); + ShowWindow (mainwindow, SW_SHOWDEFAULT); + UpdateWindow (mainwindow); + + // Because we have set the background brush for the window to NULL + // (to avoid flickering when re-sizing the window on the desktop), we + // clear the window to black when created, otherwise it will be + // empty while Quake starts up. + hdc = GetDC(mainwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(mainwindow, hdc); + + /* Create the MGL window DC and the MGL memory DC */ + if ((windc = MGL_createWindowedDC(mainwindow)) == NULL) + MGL_fatalError("Unable to create Fullscreen DIB DC!"); + + if ((dibdc = MGL_createMemoryDC(DIBWidth,DIBHeight,8,&pf)) == NULL) + MGL_fatalError("Unable to create Memory DC!"); + + MGL_makeCurrentDC(dibdc); + + vid.buffer = vid.conbuffer = vid.direct = dibdc->surface; + vid.rowbytes = vid.conrowbytes = dibdc->mi.bytesPerLine; + vid.numpages = 1; + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.height = vid.conheight = DIBHeight; + vid.width = vid.conwidth = DIBWidth; + vid.aspect = ((float)vid.height / (float)vid.width) * + (320.0 / 240.0); + + vid_stretched = modelist[modenum].stretched; + +// needed because we're not getting WM_MOVE messages fullscreen on NT + window_x = 0; + window_y = 0; + + return true; +} + + +void VID_RestoreOldMode (int original_mode) +{ + static qboolean inerror = false; + + if (inerror) + return; + + in_mode_set = false; + inerror = true; + +// make sure mode set happens (video mode changes) + vid_modenum = original_mode - 1; + + if (!VID_SetMode (original_mode, vid_curpal)) + { + vid_modenum = MODE_WINDOWED - 1; + + if (!VID_SetMode (windowed_default, vid_curpal)) + Sys_Error ("Can't set any video mode"); + } + + inerror = false; +} + + +void VID_SetDefaultMode (void) +{ + + if (vid_initialized) + VID_SetMode (0, vid_curpal); + + IN_DeactivateMouse (); +} + + +int VID_SetMode (int modenum, unsigned char *palette) +{ + int original_mode, temp; + qboolean stat; + MSG msg; + HDC hdc; + + while ((modenum >= nummodes) || (modenum < 0)) + { + if (vid_modenum == NO_MODE) + { + if (modenum == vid_default) + { + modenum = windowed_default; + } + else + { + modenum = vid_default; + } + + Cvar_SetValue (vid_mode, (float)modenum); + } + else + { + Cvar_SetValue (vid_mode, (float)vid_modenum); + return 0; + } + } + + if (!force_mode_set && (modenum == vid_modenum)) + return true; + +// so Con_Printfs don't mess us up by forcing vid and snd updates + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + in_mode_set = true; + + CDAudio_Pause (); + S_ClearBuffer (); + + if (vid_modenum == NO_MODE) + original_mode = windowed_default; + else + original_mode = vid_modenum; + + // Set either the fullscreen or windowed mode + if (modelist[modenum].type == MS_WINDOWED) + { + if (_windowed_mouse->value && key_dest == key_game) + { + stat = VID_SetWindowedMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + IN_DeactivateMouse (); + IN_ShowMouse (); + stat = VID_SetWindowedMode(modenum); + } + } + else if (modelist[modenum].type == MS_FULLDIB) + { + stat = VID_SetFullDIBMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + stat = VID_SetFullscreenMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + + window_width = vid.width << vid_stretched; + window_height = vid.height << vid_stretched; + VID_UpdateWindowStatus (); + + CDAudio_Resume (); + scr_disabled_for_loading = temp; + + if (!stat) + { + VID_RestoreOldMode (original_mode); + return false; + } + + if (hide_window) + return true; + +// now we try to make sure we get the focus on the mode switch, because +// sometimes in some systems we don't. We grab the foreground, then +// finish setting up, pump all our messages, and sleep for a little while +// to let messages finish bouncing around the system, then we put +// ourselves at the top of the z order, then grab the foreground again, +// Who knows if it helps, but it probably doesn't hurt + if (!force_minimized) + SetForegroundWindow (mainwindow); + + hdc = GetDC(NULL); + + if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) + vid_palettized = true; + else + vid_palettized = false; + + VID_SetPalette (palette); + + ReleaseDC(NULL,hdc); + + vid_modenum = modenum; + Cvar_SetValue (vid_mode, (float)vid_modenum); + + if (!VID_AllocBuffers (vid.width, vid.height)) + { + // couldn't get memory for this mode; try to fall back to previous mode + VID_RestoreOldMode (original_mode); + return false; + } + + D_InitCaches (vid_surfcache, vid_surfcachesize); + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + + Sleep (100); + + if (!force_minimized) + { + SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, + SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + SWP_NOCOPYBITS); + + SetForegroundWindow (mainwindow); + } + +// fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + if (!msg_suppress_1) + Con_SafePrintf ("Video mode %s initialized\n", VID_GetModeDescription (vid_modenum)); + + VID_SetPalette (palette); + + in_mode_set = false; + vid.recalc_refdef = 1; + + return true; +} + +void VID_LockBuffer (void) +{ + + if (dibdc) + return; + + lockcount++; + + if (lockcount > 1) + return; + + MGL_beginDirectAccess(); + + if (memdc) + { + // Update surface pointer for linear access modes + vid.buffer = vid.conbuffer = vid.direct = memdc->surface; + vid.rowbytes = vid.conrowbytes = memdc->mi.bytesPerLine; + } + else if (mgldc) + { + // Update surface pointer for linear access modes + vid.buffer = vid.conbuffer = vid.direct = mgldc->surface; + vid.rowbytes = vid.conrowbytes = mgldc->mi.bytesPerLine; + } + + if (r_dowarp) + d_viewbuffer = r_warpbuffer; + else + d_viewbuffer = (void *)(byte *)vid.buffer; + + if (r_dowarp) + screenwidth = WARP_WIDTH; + else + screenwidth = vid.rowbytes; + +/* +// disabled until someone fixes, not defined right or anything + if (lcd_x->value) + screenwidth <<= 1; + */ + +} + + +void VID_UnlockBuffer (void) +{ + if (dibdc) + return; + + lockcount--; + + if (lockcount > 0) + return; + + if (lockcount < 0) + Sys_Error ("Unbalanced unlock"); + + MGL_endDirectAccess(); + +// to turn up any unlocked accesses + vid.buffer = vid.conbuffer = vid.direct = d_viewbuffer = NULL; + +} + + +int VID_ForceUnlockedAndReturnState (void) +{ + int lk; + + if (!lockcount) + return 0; + + lk = lockcount; + + if (dibdc) + { + lockcount = 0; + } + else + { + lockcount = 1; + VID_UnlockBuffer (); + } + + return lk; +} + + +void VID_ForceLockState (int lk) +{ + + if (!dibdc && lk) + { + lockcount = 0; + VID_LockBuffer (); + } + + lockcount = lk; +} + + +void VID_SetPalette (unsigned char *palette) +{ + INT i; + palette_t pal[256]; + HDC hdc; + + if (!Minimized) + { + palette_changed = true; + + // make sure we have the static colors if we're the active app + hdc = GetDC(NULL); + + if (vid_palettized && ActiveApp) + { + if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC) + { + // switch to SYSPAL_NOSTATIC and remap the colors + SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); + syscolchg = true; + pal_is_nostatic = true; + } + } + + ReleaseDC(NULL,hdc); + + // Translate the palette values to an MGL palette array and + // set the values. + for (i = 0; i < 256; i++) + { + pal[i].red = palette[i*3]; + pal[i].green = palette[i*3+1]; + pal[i].blue = palette[i*3+2]; + } + + if (DDActive) + { + if (!mgldc) + return; + + MGL_setPalette(mgldc,pal,256,0); + MGL_realizePalette(mgldc,256,0,false); + if (memdc) + MGL_setPalette(memdc,pal,256,0); + } + else + { + if (!windc) + return; + + MGL_setPalette(windc,pal,256,0); + MGL_realizePalette(windc,256,0,false); + if (dibdc) + { + MGL_setPalette(dibdc,pal,256,0); + MGL_realizePalette(dibdc,256,0,false); + } + } + } + + memcpy (vid_curpal, palette, sizeof(vid_curpal)); + + if (syscolchg) + { + PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0); + syscolchg = false; + } +} + + +void VID_ShiftPalette (unsigned char *palette) +{ + VID_SetPalette (palette); +} + + +/* +================= +VID_DescribeCurrentMode_f +================= +*/ +void VID_DescribeCurrentMode_f (void) +{ + Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); +} + + +/* +================= +VID_NumModes_f +================= +*/ +void VID_NumModes_f (void) +{ + + if (nummodes == 1) + Con_Printf ("%d video mode is available\n", nummodes); + else + Con_Printf ("%d video modes are available\n", nummodes); +} + + +/* +================= +VID_DescribeMode_f +================= +*/ +void VID_DescribeMode_f (void) +{ + int modenum; + + modenum = atoi (Cmd_Argv(1)); + + Con_Printf ("%s\n", VID_GetExtModeDescription (modenum)); +} + + +/* +================= +VID_DescribeModes_f +================= +*/ +void VID_DescribeModes_f (void) +{ + int i, lnummodes; + char *pinfo; + qboolean na; + vmode_t *pv; + + na = false; + + lnummodes = VID_NumModes (); + + for (i=0 ; iwidth, pv->height)) + { + Con_Printf ("%2d: %s\n", i, pinfo); + } + else + { + Con_Printf ("**: %s\n", pinfo); + na = true; + } + } + + if (na) + { + Con_Printf ("\n[**: not enough system RAM for mode]\n"); + } +} + + +/* +================= +VID_TestMode_f +================= +*/ +void VID_TestMode_f (void) +{ + int modenum; + double testduration; + + if (!vid_testingmode) + { + modenum = atoi (Cmd_Argv(1)); + + if (VID_SetMode (modenum, vid_curpal)) + { + vid_testingmode = 1; + testduration = atof (Cmd_Argv(2)); + if (testduration == 0) + testduration = 5.0; + vid_testendtime = realtime + testduration; + } + } +} + +/* +================= +VID_Windowed_f +================= +*/ +void VID_Windowed_f (void) +{ + + VID_SetMode ((int)vid_windowed_mode->value, vid_curpal); +} + + +/* +================= +VID_Fullscreen_f +================= +*/ +void VID_Fullscreen_f (void) +{ + + VID_SetMode ((int)vid_fullscreen_mode->value, vid_curpal); +} + +/* +================= +VID_Minimize_f +================= +*/ +void VID_Minimize_f (void) +{ + +// we only support minimizing windows; if you're fullscreen, +// switch to windowed first + if (modestate == MS_WINDOWED) + ShowWindow (mainwindow, SW_MINIMIZE); +} + + + +/* +================= +VID_ForceMode_f +================= +*/ +void VID_ForceMode_f (void) +{ + int modenum; + + if (!vid_testingmode) + { + modenum = atoi (Cmd_Argv(1)); + + force_mode_set = 1; + VID_SetMode (modenum, vid_curpal); + force_mode_set = 0; + } +} + + +void VID_Init (unsigned char *palette) +{ + int i, bestmatch = 0, bestmatchmetric, t, dr, dg, db; + int basenummodes; + byte *ptmp; + + vid_mode = Cvar_Get("vid_mode", "0", CVAR_NONE, "None"); + vid_wait = Cvar_Get("vid_wait", "0", CVAR_NONE, "None"); + vid_nopageflip = Cvar_Get("vid_nopageflip", "0", CVAR_ARCHIVE, "None"); + _vid_wait_override = Cvar_Get("_vid_wait_override", "0", CVAR_ARCHIVE, "None"); + _vid_default_mode = Cvar_Get("_vid_default_mode", "0", CVAR_ARCHIVE, "None"); + _vid_default_mode_win = Cvar_Get("_vid_default_mode_win", "3", CVAR_ARCHIVE, "None"); + vid_config_x = Cvar_Get("vid_config_x", "800", CVAR_ARCHIVE, "None"); + vid_config_y = Cvar_Get("vid_config_y", "600", CVAR_ARCHIVE, "None"); + vid_stretch_by_2 = Cvar_Get("vid_stretch_by_2", "1", CVAR_ARCHIVE, "None"); + _windowed_mouse = Cvar_Get("_windowed_mouse", "0", CVAR_ARCHIVE, "None"); + vid_fullscreen_mode = Cvar_Get("vid_fullscreen_mode", "3", CVAR_ARCHIVE, "None"); + vid_windowed_mode = Cvar_Get("vid_windowed_mode", "0", CVAR_ARCHIVE, "None"); + block_switch = Cvar_Get("block_switch", "0", CVAR_ARCHIVE, "None"); + vid_window_x = Cvar_Get("vid_window_x", "0", CVAR_ARCHIVE, "None"); + vid_window_y = Cvar_Get("vid_window_y", "0", CVAR_ARCHIVE, "None"); + + Cmd_AddCommand ("vid_testmode", VID_TestMode_f); + Cmd_AddCommand ("vid_nummodes", VID_NumModes_f); + Cmd_AddCommand ("vid_describecurrentmode", VID_DescribeCurrentMode_f); + Cmd_AddCommand ("vid_describemode", VID_DescribeMode_f); + Cmd_AddCommand ("vid_describemodes", VID_DescribeModes_f); + Cmd_AddCommand ("vid_forcemode", VID_ForceMode_f); + Cmd_AddCommand ("vid_windowed", VID_Windowed_f); + Cmd_AddCommand ("vid_fullscreen", VID_Fullscreen_f); + Cmd_AddCommand ("vid_minimize", VID_Minimize_f); + + if (COM_CheckParm ("-dibonly")) + dibonly = true; + + VID_InitMGLDIB (global_hInstance); + + basenummodes = nummodes; + + if (!dibonly) + VID_InitMGLFull (global_hInstance); + +// if there are no non-windowed modes, or only windowed and mode 0x13, then use +// fullscreen DIBs as well + if (((nummodes == basenummodes) || + ((nummodes == (basenummodes + 1)) && is_mode0x13)) && + !COM_CheckParm ("-nofulldib")) + + { + VID_InitFullDIB (global_hInstance); + } + + vid.maxwarpwidth = WARP_WIDTH; + vid.maxwarpheight = WARP_HEIGHT; + vid.colormap = host_colormap; + vid.fullbright = 256 - LittleLong (*((int *)vid.colormap + 2048)); + vid_testingmode = 0; + +// GDI doesn't let us remap palette index 0, so we'll remap color +// mappings from that black to another one + bestmatchmetric = 256*256*3; + + for (i=1 ; i<256 ; i++) + { + dr = palette[0] - palette[i*3]; + dg = palette[1] - palette[i*3+1]; + db = palette[2] - palette[i*3+2]; + + t = (dr * dr) + (dg * dg) + (db * db); + + if (t < bestmatchmetric) + { + bestmatchmetric = t; + bestmatch = i; + + if (t == 0) + break; + } + } + + for (i=0, ptmp = vid.colormap ; i<(1<<(VID_CBITS+8)) ; i++, ptmp++) + { + if (*ptmp == 0) + *ptmp = bestmatch; + } + + if (COM_CheckParm("-startwindowed")) + { + startwindowed = 1; + vid_default = windowed_default; + } + + if (hwnd_dialog) + DestroyWindow (hwnd_dialog); + +// sound initialization has to go here, preceded by a windowed mode set, +// so there's a window for DirectSound to work with but we're not yet +// fullscreen so the "hardware already in use" dialog is visible if it +// gets displayed + +// keep the window minimized until we're ready for the first real mode set + hide_window = true; + VID_SetMode (MODE_WINDOWED, palette); + hide_window = false; +// S_Init (); + + vid_initialized = true; + + force_mode_set = true; + VID_SetMode (vid_default, palette); + force_mode_set = false; + + vid_realmode = vid_modenum; + + VID_SetPalette (palette); + + vid_menudrawfn = VID_MenuDraw; + vid_menukeyfn = VID_MenuKey; + + strcpy (badmode.modedesc, "Bad mode"); +} + + +void VID_Shutdown (void) +{ + if (vid_initialized) + { + if (modestate == MS_FULLDIB) + ChangeDisplaySettings (NULL, CDS_FULLSCREEN); + + PostMessage (HWND_BROADCAST, WM_PALETTECHANGED, (WPARAM)mainwindow, (LPARAM)0); + PostMessage (HWND_BROADCAST, WM_SYSCOLORCHANGE, (WPARAM)0, (LPARAM)0); + + AppActivate(false, false); + DestroyDIBWindow (); + DestroyFullscreenWindow (); + DestroyFullDIBWindow (); + + if (hwnd_dialog) + DestroyWindow (hwnd_dialog); + + if (mainwindow) + DestroyWindow(mainwindow); + + MGL_exit(); + + vid_testingmode = 0; + vid_initialized = 0; + } +} + + +/* +================ +FlipScreen +================ +*/ +void FlipScreen(vrect_t *rects) +{ + /* Flip the surfaces */ + if (DDActive) + { + if (mgldc) + { + if (memdc) + { + while (rects) + { + if (vid_stretched) + { + MGL_stretchBltCoord(mgldc, memdc, + rects->x, + rects->y, + rects->x + rects->width, + rects->y + rects->height, + rects->x << 1, + rects->y << 1, + (rects->x + rects->width) << 1, + (rects->y + rects->height) << 1); + } + else + { + MGL_bitBltCoord(mgldc, memdc, + rects->x, rects->y, + (rects->x + rects->width), + (rects->y + rects->height), + rects->x, rects->y, MGL_REPLACE_MODE); + } + + rects = rects->pnext; + } + } + + if (vid.numpages > 1) + { + // We have a flipping surface, so do a hard page flip + aPage = (aPage+1) % vid.numpages; + vPage = (vPage+1) % vid.numpages; + MGL_setActivePage(mgldc,aPage); + MGL_setVisualPage(mgldc,vPage,waitVRT); + } + } + } + else + { + HDC hdcScreen; + + hdcScreen = GetDC(mainwindow); + + if (windc && dibdc) + { + MGL_setWinDC(windc,hdcScreen); + + while (rects) + { + if (vid_stretched) + { + MGL_stretchBltCoord(windc,dibdc, + rects->x, rects->y, + rects->x + rects->width, rects->y + rects->height, + rects->x << 1, rects->y << 1, + (rects->x + rects->width) << 1, + (rects->y + rects->height) << 1); + } + else + { + MGL_bitBltCoord(windc,dibdc, + rects->x, rects->y, + rects->x + rects->width, rects->y + rects->height, + rects->x, rects->y, MGL_REPLACE_MODE); + } + + rects = rects->pnext; + } + } + + ReleaseDC(mainwindow, hdcScreen); + } +} + + +void VID_Update (vrect_t *rects) +{ + vrect_t rect; + RECT trect; + + if (!vid_palettized && palette_changed) + { + palette_changed = false; + rect.x = 0; + rect.y = 0; + rect.width = vid.width; + rect.height = vid.height; + rect.pnext = NULL; + rects = ▭ + } + + if (firstupdate) + { + if (modestate == MS_WINDOWED) + { + GetWindowRect (mainwindow, &trect); + + if ((trect.left != (int)vid_window_x->value) || + (trect.top != (int)vid_window_y->value)) + { + if (COM_CheckParm ("-resetwinpos")) + { + Cvar_SetValue (vid_window_x, 0.0); + Cvar_SetValue (vid_window_y, 0.0); + } + + VID_CheckWindowXY (); + SetWindowPos (mainwindow, NULL, (int)vid_window_x->value, + (int)vid_window_y->value, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); + } + } + + if ((_vid_default_mode_win->value != vid_default) && + (!startwindowed || (_vid_default_mode_win->value < MODE_FULLSCREEN_DEFAULT))) + { + firstupdate = 0; + + if (COM_CheckParm ("-resetwinpos")) + { + Cvar_SetValue (vid_window_x, 0.0); + Cvar_SetValue (vid_window_y, 0.0); + } + + if ((_vid_default_mode_win->value < 0) || + (_vid_default_mode_win->value >= nummodes)) + { + Cvar_SetValue (_vid_default_mode_win, windowed_default); + } + + Cvar_SetValue (vid_mode, _vid_default_mode_win->value); + } + } + + // We've drawn the frame; copy it to the screen + FlipScreen (rects); + + if (vid_testingmode) + { + if (realtime >= vid_testendtime) + { + VID_SetMode (vid_realmode, vid_curpal); + vid_testingmode = 0; + } + } + else + { + if ((int)vid_mode->value != vid_realmode) + { + VID_SetMode ((int)vid_mode->value, vid_curpal); + Cvar_SetValue (vid_mode, (float)vid_modenum); + // so if mode set fails, we don't keep on + // trying to set that mode + vid_realmode = vid_modenum; + } + } + +// handle the mouse state when windowed if that's changed + if (modestate == MS_WINDOWED) + { + if (!_windowed_mouse->value) { + if (windowed_mouse) { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + windowed_mouse = false; + } else { + windowed_mouse = true; + if (key_dest == key_game && !mouseactive && ActiveApp) { + IN_ActivateMouse (); + IN_HideMouse (); + } else if (mouseactive && key_dest != key_game) { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + } + } +} + + +/* +================ +D_BeginDirectRect +================ +*/ +void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +{ + int i, j, reps, repshift; + vrect_t rect; + + if (!vid_initialized) + return; + + if (vid.aspect > 1.5) + { + reps = 2; + repshift = 1; + } + else + { + reps = 1; + repshift = 0; + } + + if (vid.numpages == 1) + { + VID_LockBuffer (); + + if (!vid.direct) + Sys_Error ("NULL vid.direct pointer"); + + for (i=0 ; i<(height << repshift) ; i += reps) + { + for (j=0 ; j> repshift) * width], + width); + } + } + + VID_UnlockBuffer (); + + rect.x = x; + rect.y = y; + rect.width = width; + rect.height = height << repshift; + rect.pnext = NULL; + + FlipScreen (&rect); + } + else + { + // unlock if locked + if (lockcount > 0) + MGL_endDirectAccess(); + + // set the active page to the displayed page + MGL_setActivePage (mgldc, vPage); + + // lock the screen + MGL_beginDirectAccess (); + + // save from and draw to screen + for (i=0 ; i<(height << repshift) ; i += reps) + { + for (j=0 ; jsurface + x + + ((y << repshift) + i + j) * mgldc->mi.bytesPerLine, + width); + memcpy ((byte *)mgldc->surface + x + + ((y << repshift) + i + j) * mgldc->mi.bytesPerLine, + &pbitmap[(i >> repshift) * width], + width); + } + } + + // unlock the screen + MGL_endDirectAccess (); + + // restore the original active page + MGL_setActivePage (mgldc, aPage); + + // relock the screen if it was locked + if (lockcount > 0) + MGL_beginDirectAccess(); + } +} + + +/* +================ +D_EndDirectRect +================ +*/ +void D_EndDirectRect (int x, int y, int width, int height) +{ + int i, j, reps, repshift; + vrect_t rect; + + if (!vid_initialized) + return; + + if (vid.aspect > 1.5) + { + reps = 2; + repshift = 1; + } + else + { + reps = 1; + repshift = 0; + } + + if (vid.numpages == 1) + { + VID_LockBuffer (); + + if (!vid.direct) + Sys_Error ("NULL vid.direct pointer"); + + for (i=0 ; i<(height << repshift) ; i += reps) + { + for (j=0 ; j 0) + MGL_endDirectAccess(); + + // set the active page to the displayed page + MGL_setActivePage (mgldc, vPage); + + // lock the screen + MGL_beginDirectAccess (); + + // restore to the screen + for (i=0 ; i<(height << repshift) ; i += reps) + { + for (j=0 ; jsurface + x + + ((y << repshift) + i + j) * mgldc->mi.bytesPerLine, + &backingbuf[(i + j) * 24], + width); + } + } + + // unlock the screen + MGL_endDirectAccess (); + + // restore the original active page + MGL_setActivePage (mgldc, aPage); + + // relock the screen if it was locked + if (lockcount > 0) + MGL_beginDirectAccess(); + } +} + + +//========================================================================== + +byte scantokey[128] = +{ +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', 13, K_CTRL, 'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', '/', K_SHIFT,KP_MULTIPLY, + K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE,K_SCRLCK,KP_HOME, + KP_UPARROW,KP_PGUP,KP_MINUS,KP_LEFTARROW,KP_5,KP_RIGHTARROW,KP_PLUS,KP_END, // 4 + KP_DOWNARROW,KP_PGDN,KP_INS,KP_DEL,0, 0, 0, K_F11, + K_F12, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +byte extscantokey[128] = +{ +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', KP_ENTER,K_CTRL,'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', KP_DIVIDE,K_SHIFT,'*', + K_ALT, ' ', K_CAPSLOCK,K_F1,K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, KP_NUMLCK,0, K_HOME, + K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+', K_END, // 4 + K_DOWNARROW,K_PGDN,K_INS,K_DEL, 0, 0, 0, K_F11, + K_F12, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +/* +======= +MapKey + +Map from windows to quake keynums +======= +*/ +int MapKey (int key) +{ + int extended; + + extended = (key >> 24) & 1; + + key = (key>>16)&255; + if (key > 127) + return 0; + + if (extended) + return extscantokey[key]; + else + return scantokey[key]; +} + + +void AppActivate(BOOL fActive, BOOL minimize) +/**************************************************************************** +* +* Function: AppActivate +* Parameters: fActive - True if app is activating +* +* Description: If the application is activating, then swap the system +* into SYSPAL_NOSTATIC mode so that our palettes will display +* correctly. +* +****************************************************************************/ +{ + HDC hdc; + int i, t; + static BOOL sound_active; + + ActiveApp = fActive; + +// messy, but it seems to work + if (vid_fulldib_on_focus_mode) + { + Minimized = minimize; + + if (Minimized) + ActiveApp = false; + } + + MGL_appActivate(windc, ActiveApp); + + if (vid_initialized) + { + // yield the palette if we're losing the focus + hdc = GetDC(NULL); + + if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) + { + if (ActiveApp) + { + if ((modestate == MS_WINDOWED) || (modestate == MS_FULLDIB)) + { + if (GetSystemPaletteUse(hdc) == SYSPAL_STATIC) + { + // switch to SYSPAL_NOSTATIC and remap the colors + SetSystemPaletteUse(hdc, SYSPAL_NOSTATIC); + syscolchg = true; + pal_is_nostatic = true; + } + } + } + else if (pal_is_nostatic) + { + if (GetSystemPaletteUse(hdc) == SYSPAL_NOSTATIC) + { + // switch back to SYSPAL_STATIC and the old mapping + SetSystemPaletteUse(hdc, SYSPAL_STATIC); + syscolchg = true; + } + + pal_is_nostatic = false; + } + } + + if (!Minimized) + VID_SetPalette (vid_curpal); + + scr_fullupdate = 0; + + ReleaseDC(NULL,hdc); + } + +// enable/disable sound on focus gain/loss + if (!ActiveApp && sound_active) + { + S_BlockSound (); + S_ClearBuffer (); + sound_active = false; + } + else if (ActiveApp && !sound_active) + { + S_UnblockSound (); + S_ClearBuffer (); + sound_active = true; + } + +// minimize/restore fulldib windows/mouse-capture normal windows on demand + if (!in_mode_set) + { + if (ActiveApp) + { + if (vid_fulldib_on_focus_mode) + { + if (vid_initialized) + { + msg_suppress_1 = true; // don't want to see normal mode set message + VID_SetMode (vid_fulldib_on_focus_mode, vid_curpal); + msg_suppress_1 = false; + + t = in_mode_set; + in_mode_set = true; + AppActivate (true, false); + in_mode_set = t; + } + + IN_ActivateMouse (); + IN_HideMouse (); + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse->value && key_dest == key_game) + { + IN_ActivateMouse (); + IN_HideMouse (); + } + } + + if (!ActiveApp) + { + if (modestate == MS_FULLDIB) + { + if (vid_initialized) + { + force_minimized = true; + i = vid_fulldib_on_focus_mode; + msg_suppress_1 = true; // don't want to see normal mode set message + VID_SetMode (windowed_default, vid_curpal); + msg_suppress_1 = false; + vid_fulldib_on_focus_mode = i; + force_minimized = false; + + // we never seem to get WM_ACTIVATE inactive from this mode set, so we'll + // do it manually + t = in_mode_set; + in_mode_set = true; + AppActivate (false, true); + in_mode_set = t; + } + + IN_DeactivateMouse (); + IN_ShowMouse (); + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse->value /* && mouseactive */) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + } + } +} + + +/* +================ +VID_HandlePause +================ +*/ +void VID_HandlePause (qboolean pause) +{ +#if 0 + if ((modestate == MS_WINDOWED) && _windowed_mouse->value) + { + if (pause) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + else + { + IN_ActivateMouse (); + IN_HideMouse (); + } + } +#endif +} + + +/* +=================================================================== + +MAIN WINDOW + +=================================================================== +*/ + +LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); + +/* main window procedure */ +LONG WINAPI MainWndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 0; + int fActive, fMinimized, temp; + HDC hdc; + PAINTSTRUCT ps; + extern unsigned int uiWheelMessage; + + if ( uMsg == uiWheelMessage ) { + uMsg = WM_MOUSEWHEEL; + wParam <<= 16; + } + + + switch (uMsg) + { + case WM_CREATE: + break; + + case WM_SYSCOMMAND: + + // Check for maximize being hit + switch (wParam & ~0x0F) + { + case SC_MAXIMIZE: + // if minimized, bring up as a window before going fullscreen, + // so MGL will have the right state to restore + if (Minimized) + { + force_mode_set = true; + VID_SetMode (vid_modenum, vid_curpal); + force_mode_set = false; + } + + VID_SetMode ((int)vid_fullscreen_mode->value, vid_curpal); + break; + + case SC_SCREENSAVE: + case SC_MONITORPOWER: + if (modestate != MS_WINDOWED) + { + // don't call DefWindowProc() because we don't want to start + // the screen saver fullscreen + break; + } + + // fall through windowed and allow the screen saver to start + + default: + if (!in_mode_set) + { + S_BlockSound (); + S_ClearBuffer (); + } + + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + + if (!in_mode_set) + { + S_UnblockSound (); + } + } + break; + + case WM_MOVE: + window_x = (int) LOWORD(lParam); + window_y = (int) HIWORD(lParam); + VID_UpdateWindowStatus (); + + if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized) + VID_RememberWindowPos (); + + break; + + case WM_SIZE: + Minimized = false; + + if (!(wParam & SIZE_RESTORED)) + { + if (wParam & SIZE_MINIMIZED) + Minimized = true; + } + break; + + case WM_SYSCHAR: + // keep Alt-Space from happening + break; + + case WM_ACTIVATE: + fActive = LOWORD(wParam); + fMinimized = (BOOL) HIWORD(wParam); + AppActivate(!(fActive == WA_INACTIVE), fMinimized); + + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + if (!in_mode_set) + { + if (windc) + MGL_activatePalette(windc,true); + + VID_SetPalette(vid_curpal); + } + + break; + + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + + if (!in_mode_set && host_initialized) + SCR_UpdateWholeScreen (); + + EndPaint(hWnd, &ps); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + if (!in_mode_set) + Key_Event (MapKey(lParam), true); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + if (!in_mode_set) + Key_Event (MapKey(lParam), false); + break; + + // this is complicated because Win32 seems to pack multiple mouse events into + // one update sometimes, so we always check all states and look for events + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + if (!in_mode_set) + { + temp = 0; + + if (wParam & MK_LBUTTON) + temp |= 1; + + if (wParam & MK_RBUTTON) + temp |= 2; + + if (wParam & MK_MBUTTON) + temp |= 4; + + IN_MouseEvent (temp); + } + break; + // JACK: This is the mouse wheel with the Intellimouse + // Its delta is either positive or neg, and we generate the proper + // Event. + case WM_MOUSEWHEEL: + if ((short) HIWORD(wParam) > 0) { + Key_Event(K_MWHEELUP, true); + Key_Event(K_MWHEELUP, false); + } else { + Key_Event(K_MWHEELDOWN, true); + Key_Event(K_MWHEELDOWN, false); + } + break; + // KJB: Added these new palette functions + case WM_PALETTECHANGED: + if ((HWND)wParam == hWnd) + break; + /* Fall through to WM_QUERYNEWPALETTE */ + case WM_QUERYNEWPALETTE: + hdc = GetDC(NULL); + + if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) + vid_palettized = true; + else + vid_palettized = false; + + ReleaseDC(NULL,hdc); + + scr_fullupdate = 0; + + if (vid_initialized && !in_mode_set && windc && MGL_activatePalette(windc,false) && !Minimized) + { + VID_SetPalette (vid_curpal); + InvalidateRect (mainwindow, NULL, false); + + // specifically required if WM_QUERYNEWPALETTE realizes a new palette + lRet = TRUE; + } + break; + + case WM_DISPLAYCHANGE: + if (!in_mode_set && (modestate == MS_WINDOWED) && !vid_fulldib_on_focus_mode) + { + force_mode_set = true; + VID_SetMode (vid_modenum, vid_curpal); + force_mode_set = false; + } + break; + + case WM_CLOSE: + // this causes Close in the right-click task bar menu not to work, but right + // now bad things happen if Close is handled in that case (garbage and a + // crash on Win95) + if (!in_mode_set) + { + if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) + { + Sys_Quit (); + } + } + break; + + case MM_MCINOTIFY: + lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 0 if handled message, 1 if not */ + return lRet; +} + + +extern void M_Menu_Options_f (void); +extern void M_Print (int cx, int cy, char *str); +extern void M_PrintWhite (int cx, int cy, char *str); +extern void M_DrawCharacter (int cx, int line, int num); +extern void M_DrawTransPic (int x, int y, qpic_t *pic); +extern void M_DrawPic (int x, int y, qpic_t *pic); + +static int vid_line, vid_wmodes; + +typedef struct +{ + int modenum; + char *desc; + int iscur; + int ismode13; + int width; +} modedesc_t; + +#define MAX_COLUMN_SIZE 5 +#define MODE_AREA_HEIGHT (MAX_COLUMN_SIZE + 6) +#define MAX_MODEDESCS (MAX_COLUMN_SIZE*3) + +static modedesc_t modedescs[MAX_MODEDESCS]; + +/* +================ +VID_MenuDraw +================ +*/ +void VID_MenuDraw (void) +{ + qpic_t *p; + char *ptr; + int lnummodes, i, j, k, column, row, dup, dupmode = 0; + char temp[100]; + vmode_t *pv; + modedesc_t tmodedesc; + + p = Draw_CachePic ("gfx/vidmodes.lmp"); + M_DrawPic ( (320-p->width)/2, 4, p); + + for (i=0 ; i<3 ; i++) + { + ptr = VID_GetModeDescriptionMemCheck (i); + modedescs[i].modenum = modelist[i].modenum; + modedescs[i].desc = ptr; + modedescs[i].ismode13 = 0; + modedescs[i].iscur = 0; + + if (vid_modenum == i) + modedescs[i].iscur = 1; + } + + vid_wmodes = 3; + lnummodes = VID_NumModes (); + + for (i=3 ; iwidth != 360) || COM_CheckParm("-allow360"))) + { + dup = 0; + + for (j=3 ; jmode13; + modedescs[k].iscur = 0; + modedescs[k].width = pv->width; + + if (i == vid_modenum) + modedescs[k].iscur = 1; + + if (!dup) + vid_wmodes++; + } + } + } + } + +// sort the modes on width (to handle picking up oddball dibonly modes +// after all the others) + for (i=3 ; i<(vid_wmodes-1) ; i++) + { + for (j=(i+1) ; j modedescs[j].width) + { + tmodedesc = modedescs[i]; + modedescs[i] = modedescs[j]; + modedescs[j] = tmodedesc; + } + } + } + + + M_Print (13*8, 36, "Windowed Modes"); + + column = 16; + row = 36+2*8; + + for (i=0 ; i<3; i++) + { + if (modedescs[i].iscur) + M_PrintWhite (column, row, modedescs[i].desc); + else + M_Print (column, row, modedescs[i].desc); + + column += 13*8; + } + + if (vid_wmodes > 3) + { + M_Print (12*8, 36+4*8, "Fullscreen Modes"); + + column = 16; + row = 36+6*8; + + for (i=3 ; ivalue); + + if (ptr) + { + snprintf (temp, sizeof(temp), "Current default: %s", ptr); + M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, temp); + } + + M_Print (15*8, 36 + MODE_AREA_HEIGHT * 8 + 8*8, + "Esc to exit"); + + row = 36 + 2*8 + (vid_line / VID_ROW_SIZE) * 8; + column = 8 + (vid_line % VID_ROW_SIZE) * 13*8; + + if (vid_line >= 3) + row += 3*8; + + M_DrawCharacter (column, row, 12+((int)(realtime*4)&1)); + } +} + + +/* +================ +VID_MenuKey +================ +*/ +void VID_MenuKey (int key) +{ + if (vid_testingmode) + return; + + switch (key) + { + case K_ESCAPE: + S_LocalSound ("misc/menu1.wav"); + M_Menu_Options_f (); + break; + + case K_LEFTARROW: + + S_LocalSound ("misc/menu1.wav"); + vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) + + ((vid_line + 2) % VID_ROW_SIZE); + + if (vid_line >= vid_wmodes) + vid_line = vid_wmodes - 1; + break; + + case K_RIGHTARROW: + S_LocalSound ("misc/menu1.wav"); + vid_line = ((vid_line / VID_ROW_SIZE) * VID_ROW_SIZE) + + ((vid_line + 4) % VID_ROW_SIZE); + + if (vid_line >= vid_wmodes) + vid_line = (vid_line / VID_ROW_SIZE) * VID_ROW_SIZE; + break; + + case K_UPARROW: + S_LocalSound ("misc/menu1.wav"); + vid_line -= VID_ROW_SIZE; + + if (vid_line < 0) + { + vid_line += ((vid_wmodes + (VID_ROW_SIZE - 1)) / + VID_ROW_SIZE) * VID_ROW_SIZE; + + while (vid_line >= vid_wmodes) + vid_line -= VID_ROW_SIZE; + } + break; + + case K_DOWNARROW: + S_LocalSound ("misc/menu1.wav"); + vid_line += VID_ROW_SIZE; + + if (vid_line >= vid_wmodes) + { + vid_line -= ((vid_wmodes + (VID_ROW_SIZE - 1)) / + VID_ROW_SIZE) * VID_ROW_SIZE; + + while (vid_line < 0) + vid_line += VID_ROW_SIZE; + } + break; + + case K_ENTER: + S_LocalSound ("misc/menu1.wav"); + VID_SetMode (modedescs[vid_line].modenum, vid_curpal); + break; + + case 'T': + case 't': + S_LocalSound ("misc/menu1.wav"); + // have to set this before setting the mode because WM_PAINT + // happens during the mode set and does a VID_Update, which + // checks vid_testingmode + vid_testingmode = 1; + vid_testendtime = realtime + 5.0; + + if (!VID_SetMode (modedescs[vid_line].modenum, vid_curpal)) + { + vid_testingmode = 0; + } + break; + + case 'D': + case 'd': + S_LocalSound ("misc/menu1.wav"); + firstupdate = 0; + Cvar_SetValue (_vid_default_mode_win, vid_modenum); + break; + + default: + break; + } +} + +void VID_SetCaption (char *text) +{ + SetWindowText(mainwindow,(LPSTR) text); +} + diff --git a/source/vid_svgalib.c b/source/vid_svgalib.c index 433ada3..915dd1f 100644 --- a/source/vid_svgalib.c +++ b/source/vid_svgalib.c @@ -1,9 +1,14 @@ /* vid_svgalib.c - @description@ + Linux SVGALib video routines Copyright (C) 1996-1997 Id Software, Inc. + Copyright (C) 1999-2000 Nelson Rush. + Copyright (C) 1999-2000 Marcus Sundberg [mackan@stacken.kth.se] + Copyright (C) 1999-2000 David Symonds [xoxus@usa.net] + Copyright (C) 1999,2000 contributors of the QuakeForge project + Please see the file "AUTHORS" for a list of contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -27,109 +32,69 @@ */ #ifdef HAVE_CONFIG_H -# include "config.h" +# include #endif - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "host.h" -#include "qargs.h" #include "d_local.h" -#include "client.h" -#include "qendian.h" -#include "keys.h" +#include "cvar.h" +#include "cmd.h" #include "sys.h" #include "console.h" +#include "host.h" +#include "input.h" +#include "qargs.h" +#include "qendian.h" -#define stringify(m) { #m, m } +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#if defined(HAVE_SYS_IO_H) +# include +#elif defined(HAVE_ASM_IO_H) +# include +#endif -unsigned short d_8to16table[256]; -static byte *vid_surfcache; -static int VID_highhunkmark; +#include -int num_modes; -vga_modeinfo *modes; -int current_mode; - -int num_shades=32; - -struct -{ - char *name; - int num; -} mice[] = -{ - stringify(MOUSE_MICROSOFT), - stringify(MOUSE_MOUSESYSTEMS), - stringify(MOUSE_MMSERIES), - stringify(MOUSE_LOGITECH), - stringify(MOUSE_BUSMOUSE), - stringify(MOUSE_PS2), -}; - -static unsigned char scantokey[128]; -static byte vid_current_palette[768]; - -int num_mice = sizeof (mice) / sizeof(mice[0]); - -int d_con_indirect = 0; - -int svgalib_inited=0; -int UseMouse = 1; -int UseDisplay = 1; -int UseKeyboard = 1; - -int mouserate = MOUSE_DEFAULTSAMPLERATE; - -cvar_t *vid_mode; -cvar_t *vid_redrawfull; -cvar_t *vid_waitforrefresh; - -char *framebuffer_ptr; - -cvar_t *mouse_button_commands[3]; - -int mouse_buttons; -int mouse_buttonstate; -int mouse_oldbuttonstate; -float mouse_x, mouse_y; -float old_mouse_x, old_mouse_y; -int mx, my; - -cvar_t *m_filter; - -static byte backingbuf[48*24]; - -int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; -byte *VGA_pagebase; void VGA_UpdatePlanarScreen (void *srcbuffer); -void -VID_InitCvars(void) -{ -} -void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +unsigned short d_8to16table[256]; +static byte *vid_surfcache; +static int VID_highhunkmark; + +static int num_modes, current_mode; +static vga_modeinfo *modes; + +static byte vid_current_palette[768]; + +static int svgalib_inited=0; +static int UseDisplay = 1; + +static cvar_t *vid_mode; +static cvar_t *vid_redrawfull; +static cvar_t *vid_waitforrefresh; + +static char *framebuffer_ptr; + + +static byte backingbuf[48*24]; + +int VGA_width, VGA_height, VGA_rowbytes, VGA_bufferrowbytes, VGA_planar; +byte *VGA_pagebase; + +int VID_options_items = 0; + + +void +D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { int i, j, k, plane, reps, repshift, offset, vidpage, off; if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return; - if (vid.aspect > 1.5) - { + if (vid.aspect > 1.5) { reps = 2; repshift = 1; } else { @@ -140,60 +105,56 @@ void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) vidpage = 0; vga_setpage(0); - if (VGA_planar) - { - for (plane=0 ; plane<4 ; plane++) - { - // select the correct plane for reading and writing + if (VGA_planar) { + for (plane=0 ; plane<4 ; plane++) { + /* Select the correct plane for reading and writing */ outb(0x02, 0x3C4); outb(1 << plane, 0x3C5); outb(4, 0x3CE); outb(plane, 0x3CF); - for (i=0 ; i<(height << repshift) ; i += reps) - { - for (k=0 ; k> 2) ; j++) - { + for (i=0 ; i<(height << repshift) ; i += reps) { + for (k=0 ; k> 2) ; j++) { backingbuf[(i + k) * 24 + (j << 2) + plane] = - vid.direct[(y + i + k) * VGA_rowbytes + + vid.direct[(y + i + k) * VGA_rowbytes + (x >> 2) + j]; vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] = - pbitmap[(i >> repshift) * 24 + - (j << 2) + plane]; + pbitmap[(i >> repshift) * 24 + + (j << 2) + plane]; } } } } } else { - for (i=0 ; i<(height << repshift) ; i += reps) - { - for (j=0 ; j> repshift)*width], width); + &pbitmap[(i >> repshift)*width], + width); } } } } -void D_EndDirectRect (int x, int y, int width, int height) + +void +D_EndDirectRect (int x, int y, int width, int height) { int i, j, k, plane, reps, repshift, offset, vidpage, off; if (!svgalib_inited || !vid.direct || !vga_oktowrite()) return; - if (vid.aspect > 1.5) - { + if (vid.aspect > 1.5) { reps = 2; repshift = 1; } else { @@ -204,100 +165,95 @@ void D_EndDirectRect (int x, int y, int width, int height) vidpage = 0; vga_setpage(0); - if (VGA_planar) - { - for (plane=0 ; plane<4 ; plane++) - { - // select the correct plane for writing + if (VGA_planar) { + for (plane=0 ; plane<4 ; plane++) { + /* Select the correct plane for writing */ outb(2, 0x3C4); outb(1 << plane, 0x3C5); outb(4, 0x3CE); outb(plane, 0x3CF); - for (i=0 ; i<(height << repshift) ; i += reps) - { - for (k=0 ; k> 2) ; j++) - { + for (i=0 ; i<(height << repshift) ; i += reps) { + for (k=0 ; k> 2) ; j++) { vid.direct[(y + i + k) * VGA_rowbytes + (x>>2) + j] = - backingbuf[(i + k) * 24 + (j << 2) + plane]; + backingbuf[(i + k) * 24 + (j << 2) + plane]; } } } } } else { - for (i=0 ; i<(height << repshift) ; i += reps) - { - for (j=0 ; j 255) - inf = 255; + if (inf < 0) inf = 0; + if (inf > 255) inf = 255; palette[i] = inf; } VID_SetPalette (palette); - vid.recalc_refdef = 1; // force a surface cache flush + /* Force a surface cache flush */ + vid.recalc_refdef = 1; + } +} +#endif + + +static void +VID_DescribeMode_f(void) +{ + int modenum; + + modenum = atoi (Cmd_Argv(1)); + if ((modenum >= num_modes) || (modenum < 0 ) || + !modes[modenum].width) { + Con_Printf("Invalid video mode: %d!\n", modenum); + } + Con_Printf("%d: %d x %d - ", modenum, + modes[modenum].width, modes[modenum].height); + if (modes[modenum].bytesperpixel == 0) { + Con_Printf("ModeX\n"); + } else { + Con_Printf("%d bpp\n", modes[modenum].bytesperpixel<<3); } } -void VID_DescribeMode_f (void) -{ - int modenum; - - modenum = atoi (Cmd_Argv(1)); - if ((modenum >= num_modes) || (modenum < 0 ) || !modes[modenum].width) - Con_Printf("Invalid video mode: %d!\n",modenum); - Con_Printf("%d: %d x %d - ",modenum,modes[modenum].width,modes[modenum].height); - if (modes[modenum].bytesperpixel == 0) - Con_Printf("ModeX\n"); - else - Con_Printf("%d bpp\n", modes[modenum].bytesperpixel<<3); -} -void VID_DescribeModes_f (void) +static void +VID_DescribeModes_f(void) { int i; - - for (i=0;i> 2; + } - if (UseDisplay && vga_oktowrite()) + if (UseDisplay && vga_oktowrite()) { vga_setpalvec(0, 256, tmppal); - + } } } -int VID_SetMode (int modenum, unsigned char *palette) + +int +VID_SetMode(int modenum, unsigned char *palette) { int bsize, zsize, tsize; + int err; + + if ((modenum >= num_modes) || (modenum < 0) || !modes[modenum].width){ + vid_mode->value = (float)current_mode; - if ((modenum >= num_modes) || (modenum < 0) || !modes[modenum].width) - { - Cvar_SetValue(vid_mode, (float)current_mode); - Con_Printf("No such video mode: %d\n",modenum); - + return 0; } - Cvar_SetValue(vid_mode, (float)modenum); - + vid_mode->value = (float)modenum; + current_mode=modenum; vid.width = modes[current_mode].width; @@ -525,11 +442,11 @@ int VID_SetMode (int modenum, unsigned char *palette) vid.conwidth = vid.width; vid.conheight = vid.height; vid.numpages = 1; - + vid.maxwarpwidth = WARP_WIDTH; vid.maxwarpheight = WARP_HEIGHT; - // alloc zbuffer and surface cache + /* alloc zbuffer and surface cache */ if (d_pzbuffer) { D_FlushCaches(); Hunk_FreeToHighMark (VID_highhunkmark); @@ -551,216 +468,126 @@ int VID_SetMode (int modenum, unsigned char *palette) D_InitCaches (vid_surfcache, tsize); -// get goin' - - vga_setmode(current_mode); + /* get goin' */ + err = vga_setmode(current_mode); + if (err) { + Sys_Error("Video mode failed: %d\n",modenum); + } VID_SetPalette(palette); VGA_pagebase = vid.direct = framebuffer_ptr = (char *) vga_getgraphmem(); -// if (vga_setlinearaddressing()>0) -// framebuffer_ptr = (char *) vga_getgraphmem(); - if (!framebuffer_ptr) +#if 0 + if (vga_setlinearaddressing() > 0) { + framebuffer_ptr = (char *) vga_getgraphmem(); + } +#endif + if (!framebuffer_ptr) { Sys_Error("This mode isn't hapnin'\n"); + } vga_setpage(0); - svgalib_inited=1; + svgalib_inited = 1; - vid.recalc_refdef = 1; // force a surface cache flush + /* Force a surface cache flush */ + vid.recalc_refdef = 1; - return 0; + return 1; } -void VID_Init(unsigned char *palette) + +void +VID_Init(unsigned char *palette) { - - int i; int w, h, d; + int err; - if (svgalib_inited) - return; + //plugin_load("in_svgalib.so"); -// Cmd_AddCommand ("gamma", VID_Gamma_f); + if (svgalib_inited) return; - if (UseDisplay) - { - vga_init(); +#if 0 + Cmd_AddCommand ("gamma", VID_Gamma_f); +#endif + + if (UseDisplay) { + err = vga_init(); + if (err) + Sys_Error("SVGALib failed to allocate a new VC\n"); VID_InitModes(); - vid_mode = Cvar_Get("vid_mode", "0", CVAR_NONE, "None"); - vid_redrawfull = Cvar_Get("vid_redrawfull", "0", CVAR_NONE, "None"); - vid_waitforrefresh = Cvar_Get("vid_waitforrefresh", "0", CVAR_ARCHIVE, "None"); - + vid_mode = Cvar_Get ("vid_mode","5",0,"None"); + vid_redrawfull = Cvar_Get ("vid_redrawfull","0",0,"None"); + vid_waitforrefresh = Cvar_Get ("vid_waitforrefresh","0", + CVAR_ARCHIVE,"None"); + Cmd_AddCommand("vid_nummodes", VID_NumModes_f); Cmd_AddCommand("vid_describemode", VID_DescribeMode_f); Cmd_AddCommand("vid_describemodes", VID_DescribeModes_f); Cmd_AddCommand("vid_debug", VID_Debug_f); - // interpret command-line params - + /* Interpret command-line params */ w = h = d = 0; - if (getenv("GSVGAMODE")) + if (getenv("GSVGAMODE")) { current_mode = get_mode(getenv("GSVGAMODE"), w, h, d); - else if (COM_CheckParm("-mode")) + } else if (COM_CheckParm("-mode")) { current_mode = get_mode(com_argv[COM_CheckParm("-mode")+1], w, h, d); - else if (COM_CheckParm("-w") || COM_CheckParm("-h") - || COM_CheckParm("-d")) - { - if (COM_CheckParm("-w")) + } else if (COM_CheckParm("-w") || COM_CheckParm("-h") + || COM_CheckParm("-d")) { + if (COM_CheckParm("-w")) { w = atoi(com_argv[COM_CheckParm("-w")+1]); - if (COM_CheckParm("-h")) + } + if (COM_CheckParm("-h")) { h = atoi(com_argv[COM_CheckParm("-h")+1]); - if (COM_CheckParm("-d")) + } + if (COM_CheckParm("-d")) { d = atoi(com_argv[COM_CheckParm("-d")+1]); + } current_mode = get_mode(0, w, h, d); - } - else + } else { current_mode = G320x200x256; + } - // set vid parameters + /* Set vid parameters */ VID_SetMode(current_mode, palette); VID_SetPalette(palette); - // we do want to run in the background when switched away - vga_runinbackground(1); - } - - if (COM_CheckParm("-nokbd")) UseKeyboard = 0; - - if (UseKeyboard) - { - for (i=0 ; i<128 ; i++) - scantokey[i] = ' '; - - scantokey[42] = K_SHIFT; - scantokey[54] = K_SHIFT; - scantokey[72] = K_UPARROW; - scantokey[103] = K_UPARROW; - scantokey[80] = K_DOWNARROW; - scantokey[108] = K_DOWNARROW; - scantokey[75] = K_LEFTARROW; - scantokey[105] = K_LEFTARROW; - scantokey[77] = K_RIGHTARROW; - scantokey[106] = K_RIGHTARROW; - scantokey[29] = K_CTRL; - scantokey[97] = K_CTRL; - scantokey[56] = K_ALT; - scantokey[100] = K_ALT; -// scantokey[58] = JK_CAPS; -// scantokey[69] = JK_NUM_LOCK; - scantokey[71] = K_HOME; - scantokey[73] = K_PGUP; - scantokey[79] = K_END; - scantokey[81] = K_PGDN; - scantokey[82] = K_INS; - scantokey[83] = K_DEL; - scantokey[1 ] = K_ESCAPE; - scantokey[28] = K_ENTER; - scantokey[15] = K_TAB; - scantokey[14] = K_BACKSPACE; - scantokey[119] = K_PAUSE; - scantokey[57] = ' '; - - scantokey[102] = K_HOME; - scantokey[104] = K_PGUP; - scantokey[107] = K_END; - scantokey[109] = K_PGDN; - scantokey[110] = K_INS; - scantokey[111] = K_DEL; - - scantokey[2] = '1'; - scantokey[3] = '2'; - scantokey[4] = '3'; - scantokey[5] = '4'; - scantokey[6] = '5'; - scantokey[7] = '6'; - scantokey[8] = '7'; - scantokey[9] = '8'; - scantokey[10] = '9'; - scantokey[11] = '0'; - scantokey[12] = '-'; - scantokey[13] = '='; - scantokey[41] = '`'; - scantokey[26] = '['; - scantokey[27] = ']'; - scantokey[39] = ';'; - scantokey[40] = '\''; - scantokey[51] = ','; - scantokey[52] = '.'; - scantokey[53] = '/'; - scantokey[43] = '\\'; - - scantokey[59] = K_F1; - scantokey[60] = K_F2; - scantokey[61] = K_F3; - scantokey[62] = K_F4; - scantokey[63] = K_F5; - scantokey[64] = K_F6; - scantokey[65] = K_F7; - scantokey[66] = K_F8; - scantokey[67] = K_F9; - scantokey[68] = K_F10; - scantokey[87] = K_F11; - scantokey[88] = K_F12; - scantokey[30] = 'a'; - scantokey[48] = 'b'; - scantokey[46] = 'c'; - scantokey[32] = 'd'; - scantokey[18] = 'e'; - scantokey[33] = 'f'; - scantokey[34] = 'g'; - scantokey[35] = 'h'; - scantokey[23] = 'i'; - scantokey[36] = 'j'; - scantokey[37] = 'k'; - scantokey[38] = 'l'; - scantokey[50] = 'm'; - scantokey[49] = 'n'; - scantokey[24] = 'o'; - scantokey[25] = 'p'; - scantokey[16] = 'q'; - scantokey[19] = 'r'; - scantokey[31] = 's'; - scantokey[20] = 't'; - scantokey[22] = 'u'; - scantokey[47] = 'v'; - scantokey[17] = 'w'; - scantokey[45] = 'x'; - scantokey[21] = 'y'; - scantokey[44] = 'z'; - - if (keyboard_init()) - Sys_Error("keyboard_init() failed"); - keyboard_seteventhandler(keyhandler); + /* XoXus: Running in background is just plain bad... */ + vga_runinbackground(0); } + /* XoXus: Why was input initialised here?!? */ + /* IN_Init(); */ } -void VID_Update(vrect_t *rects) + +void +VID_Update(vrect_t *rects) { - if (!svgalib_inited) + if (!svgalib_inited) return; + + if (!vga_oktowrite()) { + /* Can't update screen if it's not active */ return; + } - if (!vga_oktowrite()) - return; // can't update screen if it's not active - - if (vid_waitforrefresh->value) + if (vid_waitforrefresh->value) { vga_waitretrace(); + } - if (VGA_planar) - VGA_UpdatePlanarScreen (vid.buffer); - - else if (vid_redrawfull->value) { + if (VGA_planar) { + VGA_UpdatePlanarScreen(vid.buffer); + } else if (vid_redrawfull->value) { int total = vid.rowbytes * vid.height; int offset; for (offset=0;offset0x10000)?0x10000:(total-offset))); + memcpy(framebuffer_ptr, vid.buffer + offset, + ((total-offset>0x10000) + ? 0x10000 : (total-offset))); } } else { int ycount; @@ -769,232 +596,64 @@ void VID_Update(vrect_t *rects) vga_setpage(0); - while (rects) - { + while (rects) { ycount = rects->height; offset = rects->y * vid.rowbytes + rects->x; - while (ycount--) - { + while (ycount--) { register int i = offset % 0x10000; - + if ((offset / 0x10000) != vidpage) { vidpage=offset / 0x10000; vga_setpage(vidpage); } if (rects->width + i > 0x10000) { - memcpy(framebuffer_ptr + i, - vid.buffer + offset, + memcpy(framebuffer_ptr + i, + vid.buffer + offset, 0x10000 - i); vga_setpage(++vidpage); memcpy(framebuffer_ptr, - vid.buffer + offset + 0x10000 - i, + vid.buffer + offset + 0x10000 - i, rects->width - 0x10000 + i); - } else - memcpy(framebuffer_ptr + i, - vid.buffer + offset, - rects->width); + } else { + memcpy(framebuffer_ptr + i, + vid.buffer + offset, + rects->width); + } offset += vid.rowbytes; } - rects = rects->pnext; } } - - if (vid_mode->value != current_mode) + + if (vid_mode->value != current_mode) { VID_SetMode ((int)vid_mode->value, vid_current_palette); -} - -static int dither; - -void VID_DitherOn(void) -{ - if (dither == 0) - { -// R_ViewChanged (&vrect, sb_lines, vid.aspect); - dither = 1; - } -} - -void VID_DitherOff(void) -{ - if (dither) - { -// R_ViewChanged (&vrect, sb_lines, vid.aspect); - dither = 0; - } -} - -void IN_SendKeyEvents(void) -{ - if (!svgalib_inited) - return; - - if (UseKeyboard) - while (keyboard_update()); -} - -void Force_CenterView_f (void) -{ - cl.viewangles[PITCH] = 0; -} - - -void mousehandler(int buttonstate, int dx, int dy) -{ - mouse_buttonstate = buttonstate; - mx += dx; - my += dy; -} - -void IN_Init(void) -{ - - int mtype; - char *mousedev; - int mouserate; - - if (UseMouse) - { - - mouse_button_commands[0]=Cvar_Get("mouse1","+attack",CVAR_NONE,"None"); - mouse_button_commands[0]=Cvar_Get("mouse2","+strafe",CVAR_NONE,"None"); - mouse_button_commands[0]=Cvar_Get("mouse3","+forward",CVAR_NONE,"None"); - m_filter = Cvar_Get("m_filter", "0", CVAR_ARCHIVE, "None"); - Cmd_AddCommand ("force_centerview", Force_CenterView_f); - - mouse_buttons = 3; - - mtype = vga_getmousetype(); - - mousedev = "/dev/mouse"; - if (getenv("MOUSEDEV")) mousedev = getenv("MOUSEDEV"); - if (COM_CheckParm("-mdev")) - mousedev = com_argv[COM_CheckParm("-mdev")+1]; - - mouserate = 1200; - if (getenv("MOUSERATE")) mouserate = atoi(getenv("MOUSERATE")); - if (COM_CheckParm("-mrate")) - mouserate = atoi(com_argv[COM_CheckParm("-mrate")+1]); - -// printf("Mouse: dev=%s,type=%s,speed=%d\n", -// mousedev, mice[mtype].name, mouserate); - if (mouse_init(mousedev, mtype, mouserate)) - { - Con_Printf("No mouse found\n"); - UseMouse = 0; - } - else - mouse_seteventhandler(mousehandler); - - } - -} - -void IN_Shutdown(void) -{ - if (UseMouse) - mouse_close(); -} - -/* -=========== -IN_Commands -=========== -*/ -void IN_Commands (void) -{ - if (UseMouse && cls.state != ca_dedicated) - { - // poll mouse values - while (mouse_update()) - ; - - // perform button actions - if ((mouse_buttonstate & MOUSE_LEFTBUTTON) && - !(mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) - Key_Event (K_MOUSE1, true); - else if (!(mouse_buttonstate & MOUSE_LEFTBUTTON) && - (mouse_oldbuttonstate & MOUSE_LEFTBUTTON)) - Key_Event (K_MOUSE1, false); - - if ((mouse_buttonstate & MOUSE_RIGHTBUTTON) && - !(mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) - Key_Event (K_MOUSE2, true); - else if (!(mouse_buttonstate & MOUSE_RIGHTBUTTON) && - (mouse_oldbuttonstate & MOUSE_RIGHTBUTTON)) - Key_Event (K_MOUSE2, false); - - if ((mouse_buttonstate & MOUSE_MIDDLEBUTTON) && - !(mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) - Key_Event (K_MOUSE3, true); - else if (!(mouse_buttonstate & MOUSE_MIDDLEBUTTON) && - (mouse_oldbuttonstate & MOUSE_MIDDLEBUTTON)) - Key_Event (K_MOUSE3, false); - - mouse_oldbuttonstate = mouse_buttonstate; } } -/* -=========== -IN_Move -=========== -*/ -void IN_MouseMove (usercmd_t *cmd) + +static int dither = 0; + +void +VID_DitherOn(void) { - if (!UseMouse) - return; - - // poll mouse values - while (mouse_update()) - ; - - if (m_filter->value) - { - mouse_x = (mx + old_mouse_x) * 0.5; - mouse_y = (my + old_mouse_y) * 0.5; - } - else - { - mouse_x = mx; - mouse_y = my; - } - old_mouse_x = mx; - old_mouse_y = my; - mx = my = 0; // clear for next update - - mouse_x *= sensitivity->value; - mouse_y *= sensitivity->value; - -// add mouse X/Y movement to cmd - if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) - cmd->sidemove += m_side->value * mouse_x; - else - cl.viewangles[YAW] -= m_yaw->value * mouse_x; - - if (in_mlook.state & 1) - V_StopPitchDrift (); - - if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) - { - cl.viewangles[PITCH] += m_pitch->value * mouse_y; - if (cl.viewangles[PITCH] > 80) - cl.viewangles[PITCH] = 80; - if (cl.viewangles[PITCH] < -70) - cl.viewangles[PITCH] = -70; - } - else - { - if ((in_strafe.state & 1) && noclip_anglehack) - cmd->upmove -= m_forward->value * mouse_y; - else - cmd->forwardmove -= m_forward->value * mouse_y; + if (dither == 0) { +#if 0 + R_ViewChanged (&vrect, sb_lines, vid.aspect); +#endif + dither = 1; } } -void IN_Move (usercmd_t *cmd) + +void +VID_DitherOff(void) { - IN_MouseMove(cmd); + if (dither) { +#if 0 + R_ViewChanged (&vrect, sb_lines, vid.aspect); +#endif + dither = 0; + } } @@ -1003,24 +662,45 @@ void IN_Move (usercmd_t *cmd) VID_ModeInfo ================ */ -char *VID_ModeInfo (int modenum) +char * +VID_ModeInfo (int modenum) { - static char *badmodestr = "Bad mode number"; - static char modestr[40]; + static char *badmodestr = "Bad mode number"; + static char modestr[40]; - if (modenum == 0) - { - snprintf (modestr, sizeof(modestr), "%d x %d, %d bpp", - vid.width, vid.height, modes[current_mode].bytesperpixel*8); + if (modenum == 0) { + snprintf(modestr, sizeof(modestr), "%d x %d, %d bpp", + vid.width, vid.height, modes[current_mode].bytesperpixel*8); return (modestr); - } - else - { + } else { return (badmodestr); } } -void outb(unsigned char value, unsigned short port) + +void +VID_ExtraOptionDraw(unsigned int options_draw_cursor) +{ + /* No extra option menu items yet */ +} + + +void +VID_ExtraOptionCmd(int option_cursor) +{ +#if 0 + switch(option_cursor) { + case 1: // Always start with 1 + break; + } +#endif +} + +void VID_InitCvars () +{ + // It may not look like it, but this is important +} + +void VID_SetCaption (char *text) { - __asm__ __volatile__ ("outb %b0,%w1" : : "a" (value) , "Nd" (port)); } diff --git a/source/vid_wgl.c b/source/vid_wgl.c new file mode 100644 index 0000000..5dd8dda --- /dev/null +++ b/source/vid_wgl.c @@ -0,0 +1,1963 @@ +/* + vid_wgl.c + + Win32 WGL vid component + + Copyright (C) 1996-1997 Id Software, Inc. + + 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: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id$ +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include "quakedef.h" +#include "winquake.h" +#include "sys.h" +#include "resource.h" +#include "glquake.h" +#include "in_win.h" +#include +#include "screen.h" +#include "keys.h" +#include "qargs.h" +#include "cmd.h" +#include "qendian.h" +#include "draw.h" +#include "cdaudio.h" +#include "console.h" +#include "sbar.h" + +#define MAX_MODE_LIST 30 +#define VID_ROW_SIZE 3 +#define WARP_WIDTH 320 +#define WARP_HEIGHT 200 +#define MAXWIDTH 10000 +#define MAXHEIGHT 10000 +#define BASEWIDTH 320 +#define BASEHEIGHT 200 + +#define MODE_WINDOWED 0 +#define NO_MODE (MODE_WINDOWED - 1) +#define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1) + +typedef struct { + modestate_t type; + int width; + int height; + int modenum; + int dib; + int fullscreen; + int bpp; + int halfscreen; + char modedesc[17]; +} vmode_t; + +typedef struct { + int width; + int height; +} lmode_t; + +lmode_t lowresmodes[] = { + {320, 200}, + {320, 240}, + {400, 300}, + {512, 384}, +}; + +const char *gl_vendor; +const char *gl_renderer; +const char *gl_version; +const char *gl_extensions; + +qboolean DDActive; +qboolean scr_skipupdate; + +static vmode_t modelist[MAX_MODE_LIST]; +static int nummodes; +static vmode_t *pcurrentmode; +static vmode_t badmode; + +static DEVMODE gdevmode; +static qboolean vid_initialized = false; +static qboolean windowed, leavecurrentmode; +static qboolean vid_canalttab = false; +static qboolean vid_wassuspended = false; +static int windowed_mouse; +static HICON hIcon; + +int DIBWidth, DIBHeight; +RECT WindowRect; +DWORD WindowStyle, ExWindowStyle; + +HWND mainwindow, dibwindow; + +int vid_modenum = NO_MODE; +int vid_realmode; +int vid_default = MODE_WINDOWED; +static int windowed_default; +unsigned char vid_curpal[256*3]; +static qboolean fullsbardraw = true; + +HGLRC baseRC; +HDC maindc; + +glvert_t glv; + +HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); + +extern viddef_t vid; // global video state + +unsigned short d_8to16table[256]; +unsigned d_8to24table[256]; +unsigned char d_15to8table[65536]; + +float gldepthmin, gldepthmax; + +modestate_t modestate = MS_UNINIT; + +void VID_MenuDraw (void); +void VID_MenuKey (int key); + +LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +void AppActivate(BOOL fActive, BOOL minimize); +char *VID_GetModeDescription (int mode); +void ClearAllStates (void); +void VID_UpdateWindowStatus (void); +void GL_Init (void); + +PROC glArrayElementEXT; +PROC glColorPointerEXT; +PROC glTexCoordPointerEXT; +PROC glVertexPointerEXT; + +typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); +lp3DFXFUNC glColorTableEXT; +qboolean is8bit = false; +qboolean isPermedia = false; +int gl_mtex_enum = TEXTURE0_SGIS; +qboolean gl_arb_mtex = false; +qboolean gl_mtexable = false; + +//==================================== + +cvar_t *vid_mode; +cvar_t *_vid_default_mode; +cvar_t *_vid_default_mode_win; +cvar_t *vid_wait; +cvar_t *vid_nopageflip; +cvar_t *_vid_wait_override; +cvar_t *vid_config_x; +cvar_t *vid_config_y; +cvar_t *vid_stretch_by_2; +cvar_t *_windowed_mouse; + +int window_center_x, window_center_y, window_x, window_y, window_width, window_height; +RECT window_rect; + +/* +================ +VID_InitCvars +================ +*/ +void +VID_InitCvars () +{ + // It may not look like it, but this is important +} + +// direct draw software compatability stuff + +void VID_HandlePause (qboolean pause) +{ +} + +void VID_ForceLockState (int lk) +{ +} + +void VID_LockBuffer (void) +{ +} + +void VID_UnlockBuffer (void) +{ +} + +int VID_ForceUnlockedAndReturnState (void) +{ + return 0; +} + +void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) +{ +} + +void D_EndDirectRect (int x, int y, int width, int height) +{ +} + + +void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify) +{ + int CenterX, CenterY; + + CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; + CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; + if (CenterX > CenterY*2) + CenterX >>= 1; // dual screens + CenterX = (CenterX < 0) ? 0: CenterX; + CenterY = (CenterY < 0) ? 0: CenterY; + SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0, + SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); +} + +qboolean VID_SetWindowedMode (int modenum) +{ + HDC hdc; + int lastmodestate, width, height; + RECT rect; + + lastmodestate = modestate; + + WindowRect.top = WindowRect.left = 0; + + WindowRect.right = modelist[modenum].width; + WindowRect.bottom = modelist[modenum].height; + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | + WS_MINIMIZEBOX; + ExWindowStyle = 0; + + rect = WindowRect; + AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + // Create the DIB window + dibwindow = CreateWindowEx ( + ExWindowStyle, + "WinQuake", + "GLQuake", + WindowStyle, + rect.left, rect.top, + width, + height, + NULL, + NULL, + global_hInstance, + NULL); + + if (!dibwindow) + Sys_Error ("Couldn't create DIB window"); + + // Center and show the DIB window + CenterWindow(dibwindow, WindowRect.right - WindowRect.left, + WindowRect.bottom - WindowRect.top, false); + + ShowWindow (dibwindow, SW_SHOWDEFAULT); + UpdateWindow (dibwindow); + + modestate = MS_WINDOWED; + +// because we have set the background brush for the window to NULL +// (to avoid flickering when re-sizing the window on the desktop), +// we clear the window to black when created, otherwise it will be +// empty while Quake starts up. + hdc = GetDC(dibwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(dibwindow, hdc); + + if (vid.conheight > modelist[modenum].height) + vid.conheight = modelist[modenum].height; + if (vid.conwidth > modelist[modenum].width) + vid.conwidth = modelist[modenum].width; + vid.width = vid.conwidth; + vid.height = vid.conheight; + + vid.numpages = 2; + + mainwindow = dibwindow; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + + +qboolean VID_SetFullDIBMode (int modenum) +{ + HDC hdc; + int lastmodestate, width, height; + RECT rect; + + if (!leavecurrentmode) + { + gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; + gdevmode.dmBitsPerPel = modelist[modenum].bpp; + gdevmode.dmPelsWidth = modelist[modenum].width << + modelist[modenum].halfscreen; + gdevmode.dmPelsHeight = modelist[modenum].height; + gdevmode.dmSize = sizeof (gdevmode); + + if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) + Sys_Error ("Couldn't set fullscreen DIB mode"); + } + + lastmodestate = modestate; + modestate = MS_FULLDIB; + + WindowRect.top = WindowRect.left = 0; + + WindowRect.right = modelist[modenum].width; + WindowRect.bottom = modelist[modenum].height; + + DIBWidth = modelist[modenum].width; + DIBHeight = modelist[modenum].height; + + WindowStyle = WS_POPUP; + ExWindowStyle = 0; + + rect = WindowRect; + AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); + + width = rect.right - rect.left; + height = rect.bottom - rect.top; + + // Create the DIB window + dibwindow = CreateWindowEx ( + ExWindowStyle, + "WinQuake", + "GLQuake", + WindowStyle, + rect.left, rect.top, + width, + height, + NULL, + NULL, + global_hInstance, + NULL); + + if (!dibwindow) + Sys_Error ("Couldn't create DIB window"); + + ShowWindow (dibwindow, SW_SHOWDEFAULT); + UpdateWindow (dibwindow); + + // Because we have set the background brush for the window to NULL + // (to avoid flickering when re-sizing the window on the desktop), we + // clear the window to black when created, otherwise it will be + // empty while Quake starts up. + hdc = GetDC(dibwindow); + PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); + ReleaseDC(dibwindow, hdc); + + if (vid.conheight > modelist[modenum].height) + vid.conheight = modelist[modenum].height; + if (vid.conwidth > modelist[modenum].width) + vid.conwidth = modelist[modenum].width; + vid.width = vid.conwidth; + vid.height = vid.conheight; + + vid.numpages = 2; + +// needed because we're not getting WM_MOVE messages fullscreen on NT + window_x = 0; + window_y = 0; + + mainwindow = dibwindow; + + SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); + SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); + + return true; +} + + +int VID_SetMode (int modenum, unsigned char *palette) +{ + int original_mode, temp; + qboolean stat; + MSG msg; + + if ((windowed && (modenum != 0)) || + (!windowed && (modenum < 1)) || + (!windowed && (modenum >= nummodes))) + { + Sys_Error ("Bad video mode\n"); + } + +// so Con_Printfs don't mess us up by forcing vid and snd updates + temp = scr_disabled_for_loading; + scr_disabled_for_loading = true; + + CDAudio_Pause (); + + if (vid_modenum == NO_MODE) + original_mode = windowed_default; + else + original_mode = vid_modenum; + + // Set either the fullscreen or windowed mode + if (modelist[modenum].type == MS_WINDOWED) + { + if (_windowed_mouse->value && key_dest == key_game) + { + stat = VID_SetWindowedMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + IN_DeactivateMouse (); + IN_ShowMouse (); + stat = VID_SetWindowedMode(modenum); + } + } + else if (modelist[modenum].type == MS_FULLDIB) + { + stat = VID_SetFullDIBMode(modenum); + IN_ActivateMouse (); + IN_HideMouse (); + } + else + { + Sys_Error ("VID_SetMode: Bad mode type in modelist"); + } + + window_width = DIBWidth; + window_height = DIBHeight; + VID_UpdateWindowStatus (); + + CDAudio_Resume (); + scr_disabled_for_loading = temp; + + if (!stat) + { + Sys_Error ("Couldn't set video mode"); + } + +// now we try to make sure we get the focus on the mode switch, because +// sometimes in some systems we don't. We grab the foreground, then +// finish setting up, pump all our messages, and sleep for a little while +// to let messages finish bouncing around the system, then we put +// ourselves at the top of the z order, then grab the foreground again, +// Who knows if it helps, but it probably doesn't hurt + SetForegroundWindow (mainwindow); + VID_SetPalette (palette); + vid_modenum = modenum; + Cvar_SetValue (vid_mode, (float)vid_modenum); + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + + Sleep (100); + + SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, + SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | + SWP_NOCOPYBITS); + + SetForegroundWindow (mainwindow); + +// fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + if (!msg_suppress_1) + Con_SafePrintf ("Video mode %s initialized.\n", VID_GetModeDescription (vid_modenum)); + + VID_SetPalette (palette); + + vid.recalc_refdef = 1; + + return true; +} + + +/* +================ +VID_UpdateWindowStatus +================ +*/ +void VID_UpdateWindowStatus (void) +{ + + window_rect.left = window_x; + window_rect.top = window_y; + window_rect.right = window_x + window_width; + window_rect.bottom = window_y + window_height; + window_center_x = (window_rect.left + window_rect.right) / 2; + window_center_y = (window_rect.top + window_rect.bottom) / 2; + + IN_UpdateClipCursor (); +} + + + +void CheckArrayExtensions (void) +{ + char *tmp; + + /* check for texture extension */ + tmp = (unsigned char *)glGetString(GL_EXTENSIONS); + while (*tmp) + { + if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0) + { + if ( +((glArrayElementEXT = wglGetProcAddress("glArrayElementEXT")) == NULL) || +((glColorPointerEXT = wglGetProcAddress("glColorPointerEXT")) == NULL) || +((glTexCoordPointerEXT = wglGetProcAddress("glTexCoordPointerEXT")) == NULL) || +((glVertexPointerEXT = wglGetProcAddress("glVertexPointerEXT")) == NULL) ) + { + Sys_Error ("GetProcAddress for vertex extension failed"); + return; + } + return; + } + tmp++; + } + + Sys_Error ("Vertex array extension not present"); +} + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +//int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int texture_extension_number = 1; + +#ifdef _WIN32 +void CheckMultiTextureExtensions(void) +{ + Con_Printf("Checking for multitexture... "); + if (COM_CheckParm ("-nomtex")) + { + Con_Printf ("disabled\n"); + return; + } + if (strstr(gl_extensions, "GL_ARB_multitexture ")) + { + Con_Printf ("GL_ARB_multitexture\n"); + qglMTexCoord2f = + (void *)wglGetProcAddress("glMultiTexCoord2fARB"); + qglSelectTexture = + (void *)wglGetProcAddress("glActiveTextureARB"); + gl_mtex_enum = GL_TEXTURE0_ARB; + gl_mtexable = true; + gl_arb_mtex = true; + } else if (strstr(gl_extensions, "GL_SGIS_multitexture ")) + { + Con_Printf ("GL_SGIS_multitexture\n"); + qglMTexCoord2f = + (void *)wglGetProcAddress("glMTexCoord2fSGIS"); + qglSelectTexture = + (void *)wglGetProcAddress("glSelectTextureSGIS"); + gl_mtex_enum = TEXTURE0_SGIS; + gl_mtexable = true; + gl_arb_mtex = false; + } else if (strstr(gl_extensions, "GL_EXT_multitexture ")) + { + Con_Printf ("GL_EXT_multitexture\n"); + qglMTexCoord2f = + (void *)wglGetProcAddress("glMTexCoord2fEXT"); + qglSelectTexture = + (void *)wglGetProcAddress("glSelectTextureEXT"); + gl_mtex_enum = TEXTURE0_SGIS; + gl_mtexable = true; + gl_arb_mtex = false; + } else { + Con_Printf ("none found\n"); + } +} +#else +void CheckMultiTextureExtensions(void) +{ + gl_mtexable = true; +} +#endif + +/* +=============== +GL_Init +=============== +*/ +void GL_Init (void) +{ + gl_vendor = glGetString (GL_VENDOR); + Con_Printf ("GL_VENDOR: %s\n", gl_vendor); + gl_renderer = glGetString (GL_RENDERER); + Con_Printf ("GL_RENDERER: %s\n", gl_renderer); + + gl_version = glGetString (GL_VERSION); + Con_Printf ("GL_VERSION: %s\n", gl_version); + gl_extensions = glGetString (GL_EXTENSIONS); + Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); + +// Con_Printf ("%s %s\n", gl_renderer, gl_version); + + if (strnicmp(gl_renderer,"PowerVR",7)==0) + fullsbardraw = true; + + if (strnicmp(gl_renderer,"Permedia",8)==0) + isPermedia = true; + + CheckMultiTextureExtensions (); + + glClearColor (0,0,0,0); + glCullFace(GL_FRONT); + glEnable(GL_TEXTURE_2D); + + glEnable(GL_ALPHA_TEST); + glAlphaFunc(GL_GREATER, 0.666); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glShadeModel (GL_FLAT); + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + +#if 0 + CheckArrayExtensions (); + + glEnable (GL_VERTEX_ARRAY_EXT); + glEnable (GL_TEXTURE_COORD_ARRAY_EXT); + glVertexPointerEXT (3, GL_FLOAT, 0, 0, &glv.x); + glTexCoordPointerEXT (2, GL_FLOAT, 0, 0, &glv.s); + glColorPointerEXT (3, GL_FLOAT, 0, 0, &glv.r); +#endif +} + +/* +================= +GL_BeginRendering + +================= +*/ +void GL_BeginRendering (int *x, int *y, int *width, int *height) +{ + extern cvar_t *gl_clear; + + *x = *y = 0; + *width = WindowRect.right - WindowRect.left; + *height = WindowRect.bottom - WindowRect.top; + +// if (!wglMakeCurrent( maindc, baseRC )) +// Sys_Error ("wglMakeCurrent failed"); + +// glViewport (*x, *y, *width, *height); +} + + +void GL_EndRendering (void) +{ + if (!scr_skipupdate || block_drawing) + SwapBuffers(maindc); + +// handle the mouse state when windowed if that's changed + if (modestate == MS_WINDOWED) + { + if (!_windowed_mouse->value) { + if (windowed_mouse) { + IN_DeactivateMouse (); + IN_ShowMouse (); + windowed_mouse = false; + } + } else { + windowed_mouse = true; + if (key_dest == key_game && !mouseactive && ActiveApp) { + IN_ActivateMouse (); + IN_HideMouse (); + } else if (mouseactive && key_dest != key_game) { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + } + } + if (fullsbardraw) + Sbar_Changed(); +} + +void VID_SetPalette (unsigned char *palette) +{ + byte *pal; + unsigned r,g,b; + unsigned v; + int r1,g1,b1; + int k; + unsigned short i; + unsigned *table; + FILE *f; + char s[255]; + float dist, bestdist; + static qboolean palflag = false; + +// +// 8 8 8 encoding +// +// Con_Printf("Converting 8to24\n"); + + pal = palette; + table = d_8to24table; + for (i=0 ; i<256 ; i++) + { + r = pal[0]; + g = pal[1]; + b = pal[2]; + pal += 3; + +// v = (255<<24) + (r<<16) + (g<<8) + (b<<0); +// v = (255<<0) + (r<<8) + (g<<16) + (b<<24); + v = (255<<24) + (r<<0) + (g<<8) + (b<<16); + *table++ = v; + } + d_8to24table[255] &= 0; // 255 is transparent + + // JACK: 3D distance calcs - k is last closest, l is the distance. + // FIXME: Precalculate this and cache to disk. + if (palflag) + return; + palflag = true; + + COM_FOpenFile("glquake/15to8.pal", &f); + if (f) { + fread(d_15to8table, 1<<15, 1, f); + fclose(f); + } else { + for (i=0; i < (1<<15); i++) { + /* Maps + 000000000000000 + 000000000011111 = Red = 0x1F + 000001111100000 = Blue = 0x03E0 + 111110000000000 = Grn = 0x7C00 + */ + r = ((i & 0x1F) << 3)+4; + g = ((i & 0x03E0) >> 2)+4; + b = ((i & 0x7C00) >> 7)+4; + pal = (unsigned char *)d_8to24table; + for (v=0,k=0,bestdist=10000.0; v<256; v++,pal+=4) { + r1 = (int)r - (int)pal[0]; + g1 = (int)g - (int)pal[1]; + b1 = (int)b - (int)pal[2]; + dist = sqrt(((r1*r1)+(g1*g1)+(b1*b1))); + if (dist < bestdist) { + k=v; + bestdist = dist; + } + } + d_15to8table[i]=k; + } + snprintf(s, sizeof(s), "%s/glquake", com_gamedir); + Sys_mkdir (s); + snprintf(s, sizeof(s), "%s/glquake/15to8.pal", com_gamedir); + if ((f = fopen(s, "wb")) != NULL) { + fwrite(d_15to8table, 1<<15, 1, f); + fclose(f); + } + } +} + +BOOL gammaworks; + +void VID_ShiftPalette (unsigned char *palette) +{ + extern byte ramps[3][256]; + +// VID_SetPalette (palette); + +// gammaworks = SetDeviceGammaRamp (maindc, ramps); +} + + +void VID_SetDefaultMode (void) +{ + IN_DeactivateMouse (); +} + + +void VID_Shutdown (void) +{ + HGLRC hRC; + HDC hDC; + int i,temp[8192]; + + + if (vid_initialized) + { + vid_canalttab = false; + hRC = wglGetCurrentContext(); + hDC = wglGetCurrentDC(); + + wglMakeCurrent(NULL, NULL); + + // LordHavoc: free textures before closing (may help NVIDIA) + for (i = 0;i < 8192;i++) + temp[i] = i; + glDeleteTextures(8192, temp); + + if (hRC) + wglDeleteContext(hRC); + + if (hDC && dibwindow) + ReleaseDC(dibwindow, hDC); + + if (modestate == MS_FULLDIB) + ChangeDisplaySettings (NULL, 0); + + if (maindc && dibwindow) + ReleaseDC (dibwindow, maindc); + + AppActivate(false, false); + } +} + + +//========================================================================== + + +BOOL bSetupPixelFormat(HDC hDC) +{ + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW // support window + | PFD_SUPPORT_OPENGL // support OpenGL + | PFD_DOUBLEBUFFER , // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // 32-bit z-buffer + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + int pixelformat; + + if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) + { + MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); + return FALSE; + } + + if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE) + { + MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); + return FALSE; + } + + return TRUE; +} + + +//========================================================================== + +byte scantokey[128] = +{ +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', 13, K_CTRL, 'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', '/', K_SHIFT,KP_MULTIPLY, + K_ALT, ' ', K_CAPSLOCK,K_F1, K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE,K_SCRLCK,KP_HOME, + KP_UPARROW,KP_PGUP,KP_MINUS,KP_LEFTARROW,KP_5,KP_RIGHTARROW,KP_PLUS,KP_END, // 4 + KP_DOWNARROW,KP_PGDN,KP_INS,KP_DEL,0, 0, 0, K_F11, + K_F12, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +byte extscantokey[128] = +{ +// 0 1 2 3 4 5 6 7 +// 8 9 A B C D E F + 0 , 27, '1', '2', '3', '4', '5', '6', + '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 + 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', + 'o', 'p', '[', ']', KP_ENTER,K_CTRL,'a', 's', // 1 + 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', + '\'', '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 + 'b', 'n', 'm', ',', '.', KP_DIVIDE,K_SHIFT,'*', + K_ALT, ' ', K_CAPSLOCK,K_F1,K_F2, K_F3, K_F4, K_F5, // 3 + K_F6, K_F7, K_F8, K_F9, K_F10, KP_NUMLCK,0, K_HOME, + K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+', K_END, // 4 + K_DOWNARROW,K_PGDN,K_INS,K_DEL, 0, 0, 0, K_F11, + K_F12, 0, 0, 0, 0, 0, 0, 0, // 5 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + + +/* +======= +MapKey + +Map from windows to quake keynums +======= +*/ +int MapKey (int key) +{ + int extended; + + extended = (key >> 24) & 1; + + key = (key>>16)&255; + if (key > 127) + return 0; + + if (extended) + return extscantokey[key]; + else + return scantokey[key]; +} + + +/* +=================================================================== + +MAIN WINDOW + +=================================================================== +*/ + +extern void CL_ClearStates (); + +/* +================ +ClearAllStates +================ +*/ +void ClearAllStates (void) +{ + CL_ClearStates (); + Key_ClearStates (); + IN_ClearStates (); +} + +void AppActivate(BOOL fActive, BOOL minimize) +/**************************************************************************** +* +* Function: AppActivate +* Parameters: fActive - True if app is activating +* +* Description: If the application is activating, then swap the system +* into SYSPAL_NOSTATIC mode so that our palettes will display +* correctly. +* +****************************************************************************/ +{ + static BOOL sound_active; + + ActiveApp = fActive; + Minimized = minimize; + +// enable/disable sound on focus gain/loss + if (!ActiveApp && sound_active) + { + S_BlockSound (); + sound_active = false; + } + else if (ActiveApp && !sound_active) + { + S_UnblockSound (); + sound_active = true; + } + + if (fActive) + { + if (modestate == MS_FULLDIB) + { + IN_ActivateMouse (); + IN_HideMouse (); + if (vid_canalttab && vid_wassuspended) { + vid_wassuspended = false; + ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); + ShowWindow(mainwindow, SW_SHOWNORMAL); + } + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse->value && key_dest == key_game) + { + IN_ActivateMouse (); + IN_HideMouse (); + } + } + + if (!fActive) + { + if (modestate == MS_FULLDIB) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + if (vid_canalttab) { + ChangeDisplaySettings (NULL, 0); + vid_wassuspended = true; + } + } + else if ((modestate == MS_WINDOWED) && _windowed_mouse->value) + { + IN_DeactivateMouse (); + IN_ShowMouse (); + } + } +} + + +LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +/* main window procedure */ +LONG WINAPI MainWndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + int fActive, fMinimized, temp; + extern unsigned int uiWheelMessage; + + if ( uMsg == uiWheelMessage ) + uMsg = WM_MOUSEWHEEL; + + switch (uMsg) + { + case WM_KILLFOCUS: + if (modestate == MS_FULLDIB) + ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); + break; + + case WM_CREATE: + break; + + case WM_MOVE: + window_x = (int) LOWORD(lParam); + window_y = (int) HIWORD(lParam); + VID_UpdateWindowStatus (); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + Key_Event (MapKey(lParam), true); + break; + + case WM_KEYUP: + case WM_SYSKEYUP: + Key_Event (MapKey(lParam), false); + break; + + case WM_SYSCHAR: + // keep Alt-Space from happening + break; + + // this is complicated because Win32 seems to pack multiple mouse events into + // one update sometimes, so we always check all states and look for events + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_MOUSEMOVE: + temp = 0; + + if (wParam & MK_LBUTTON) + temp |= 1; + + if (wParam & MK_RBUTTON) + temp |= 2; + + if (wParam & MK_MBUTTON) + temp |= 4; + + IN_MouseEvent (temp); + + break; + + // JACK: This is the mouse wheel with the Intellimouse + // Its delta is either positive or neg, and we generate the proper + // Event. + case WM_MOUSEWHEEL: + if ((short) HIWORD(wParam) > 0) { + Key_Event(K_MWHEELUP, true); + Key_Event(K_MWHEELUP, false); + } else { + Key_Event(K_MWHEELDOWN, true); + Key_Event(K_MWHEELDOWN, false); + } + break; + + case WM_SIZE: + break; + + case WM_CLOSE: + if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", + MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) + { + Sys_Quit (); + } + + break; + + case WM_ACTIVATE: + fActive = LOWORD(wParam); + fMinimized = (BOOL) HIWORD(wParam); + AppActivate(!(fActive == WA_INACTIVE), fMinimized); + + // fix the leftover Alt from any Alt-Tab or the like that switched us away + ClearAllStates (); + + break; + + case WM_DESTROY: + { + if (dibwindow) + DestroyWindow (dibwindow); + + PostQuitMessage (0); + } + break; + + case MM_MCINOTIFY: + lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + + +/* +================= +VID_NumModes +================= +*/ +int VID_NumModes (void) +{ + return nummodes; +} + + +/* +================= +VID_GetModePtr +================= +*/ +vmode_t *VID_GetModePtr (int modenum) +{ + + if ((modenum >= 0) && (modenum < nummodes)) + return &modelist[modenum]; + else + return &badmode; +} + + +/* +================= +VID_GetModeDescription +================= +*/ +char *VID_GetModeDescription (int mode) +{ + char *pinfo; + vmode_t *pv; + static char temp[100]; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + if (!leavecurrentmode) + { + pv = VID_GetModePtr (mode); + pinfo = pv->modedesc; + } + else + { + snprintf (temp, sizeof(temp), "Desktop resolution (%dx%d)", + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height); + pinfo = temp; + } + + return pinfo; +} + + +// KJB: Added this to return the mode driver name in description for console + +char *VID_GetExtModeDescription (int mode) +{ + static char pinfo[40]; + vmode_t *pv; + + if ((mode < 0) || (mode >= nummodes)) + return NULL; + + pv = VID_GetModePtr (mode); + if (modelist[mode].type == MS_FULLDIB) + { + if (!leavecurrentmode) + { + snprintf (pinfo, sizeof(pinfo), "%s fullscreen", pv->modedesc); + } + else + { + snprintf (pinfo, sizeof(pinfo), "Desktop resolution (%dx%d)", + modelist[MODE_FULLSCREEN_DEFAULT].width, + modelist[MODE_FULLSCREEN_DEFAULT].height); + } + } + else + { + if (modestate == MS_WINDOWED) + snprintf (pinfo, sizeof(pinfo), "%s windowed", pv->modedesc); + else + snprintf (pinfo, sizeof(pinfo), "windowed"); + } + + return pinfo; +} + + +/* +================= +VID_DescribeCurrentMode_f +================= +*/ +void VID_DescribeCurrentMode_f (void) +{ + Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); +} + + +/* +================= +VID_NumModes_f +================= +*/ +void VID_NumModes_f (void) +{ + + if (nummodes == 1) + Con_Printf ("%d video mode is available\n", nummodes); + else + Con_Printf ("%d video modes are available\n", nummodes); +} + + +/* +================= +VID_DescribeMode_f +================= +*/ +void VID_DescribeMode_f (void) +{ + int t, modenum; + + modenum = atoi (Cmd_Argv(1)); + + t = leavecurrentmode; + leavecurrentmode = 0; + + Con_Printf ("%s\n", VID_GetExtModeDescription (modenum)); + + leavecurrentmode = t; +} + + +/* +================= +VID_DescribeModes_f +================= +*/ +void VID_DescribeModes_f (void) +{ + int i, lnummodes, t; + char *pinfo; + vmode_t *pv; + + lnummodes = VID_NumModes (); + + t = leavecurrentmode; + leavecurrentmode = 0; + + for (i=1 ; i8 bpp modes + originalnummodes = nummodes; + modenum = 0; + + do + { + stat = EnumDisplaySettings (NULL, modenum, &devmode); + + if ((devmode.dmBitsPerPel >= 15) && + (devmode.dmPelsWidth <= MAXWIDTH) && + (devmode.dmPelsHeight <= MAXHEIGHT) && + (nummodes < MAX_MODE_LIST)) + { + devmode.dmFields = DM_BITSPERPEL | + DM_PELSWIDTH | + DM_PELSHEIGHT; + + if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == + DISP_CHANGE_SUCCESSFUL) + { + modelist[nummodes].type = MS_FULLDIB; + modelist[nummodes].width = devmode.dmPelsWidth; + modelist[nummodes].height = devmode.dmPelsHeight; + modelist[nummodes].modenum = 0; + modelist[nummodes].halfscreen = 0; + modelist[nummodes].dib = 1; + modelist[nummodes].fullscreen = 1; + modelist[nummodes].bpp = devmode.dmBitsPerPel; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%dx%d", + devmode.dmPelsWidth, devmode.dmPelsHeight, + devmode.dmBitsPerPel); + + // if the width is more than twice the height, reduce it by half because this + // is probably a dual-screen monitor + if (!COM_CheckParm("-noadjustaspect")) + { + if (modelist[nummodes].width > (modelist[nummodes].height << 1)) + { + modelist[nummodes].width >>= 1; + modelist[nummodes].halfscreen = 1; + snprintf (modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%dx%d", + modelist[nummodes].width, + modelist[nummodes].height, + modelist[nummodes].bpp); + } + } + + for (i=originalnummodes, existingmode = 0 ; iwidth)/2, 4, p); + + vid_wmodes = 0; + lnummodes = VID_NumModes (); + + for (i=1 ; (i 0) + { + M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)"); + + column = 8; + row = 36+2*8; + + for (i=0 ; i"); + M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, + "and -bpp "); + M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, + "Select windowed mode with -window"); +} + + +/* +================ +VID_MenuKey +================ +*/ +void VID_MenuKey (int key) +{ + switch (key) + { + case K_ESCAPE: + S_LocalSound ("misc/menu1.wav"); + M_Menu_Options_f (); + break; + + default: + break; + } +} + +void VID_SetCaption (char *text) +{ + SetWindowText(mainwindow,(LPSTR) text); +}