/*
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 the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
// vid_win.c -- Win32 video driver

#include "quakedef.h"
#include "winquake.h"
#include "d_local.h"
#include "resource.h"

#define MAX_MODE_LIST	30
#define VID_ROW_SIZE	3

qboolean	dibonly = true;

extern int		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;
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; // removed
static qboolean	palette_changed, syscolchg, vid_mode_set, hide_window, pal_is_nostatic;
static HICON	hIcon;

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 + 7)

// Note that 0 is MODE_WINDOWED
cvar_t		vid_mode = {"vid_mode","0", false};
// Note that 0 is MODE_WINDOWED
cvar_t		_vid_default_mode = {"_vid_default_mode","0", true};
// Note that 7 is MODE_FULLSCREEN_DEFAULT //Edited was 3
cvar_t		_vid_default_mode_win = {"_vid_default_mode_win","7", true};
cvar_t		vid_wait = {"vid_wait","0"};
cvar_t		vid_nopageflip = {"vid_nopageflip","0", true};
cvar_t		_vid_wait_override = {"_vid_wait_override", "0", true};
cvar_t		vid_config_x = {"vid_config_x","800", true};
cvar_t		vid_config_y = {"vid_config_y","600", true};
cvar_t		vid_stretch_by_2 = {"vid_stretch_by_2","1", true};
//cvar_t		_windowed_mouse = {"_windowed_mouse","0", true}; // removed
cvar_t		vid_fullscreen_mode = {"vid_fullscreen_mode","3", true};
cvar_t		vid_windowed_mode = {"vid_windowed_mode","1", true};
cvar_t		block_switch = {"block_switch","0", true};
cvar_t		vid_window_x = {"vid_window_x", "0", true};
cvar_t		vid_window_y = {"vid_window_y", "0", true};

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 int	d_8to24table[256];

int     driver = grDETECT,mode;
bool    useWinDirect = true, useDirectDraw = true;
//MGLDC	*mgldc = NULL,*memdc = NULL,*dibdc = NULL,*windc = NULL;
HDC			g_hMemDC	=	0;
HBITMAP		g_hBmp		=	0;
unsigned int* g_pBufferC	=	0;
pixel_t* g_pBufferB	=	0;











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;
static vmode_t	*pcurrentmode;

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_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();
}


/*
================
ClearAllStates
================
*/
void ClearAllStates(void)
{
    int		i;

// send an up event for each key, to make sure the server clears them all
    for (i=0 ; i<256 ; i++) {
        Key_Event(i, false);
    }

    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);
}


int VID_Suspend(MGLDC *dc,m_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

    //		return MGL_NO_SUSPEND_APP;
        }
        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;
        } // warning fix
        return MGL_NO_SUSPEND_APP;
    //	} // warning fix
    */
}


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, vMode, lowres, curmode, temp;
        int			lowstretchedres, stretchedmode, 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;
                    sprintf (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;
                sprintf (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;
    int				i;

    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 = "Makaqu"; // WinQuake // edited

    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 = 0;
    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 = 0;
    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, cmodes, existingmode, originalnummodes, lowestres;
    int		numlowresmodes, bpp, done;
    int		cstretch, istretch, mstretch;
    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;
                    sprintf (modelist[nummodes].modedesc, "%dx%d",
                             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;
                            sprintf (modelist[nummodes].modedesc, "%dx%d",
                                     modelist[nummodes].width,
                                     modelist[nummodes].height);
                        }
                    }

                    for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++)
                    {
                        if ((modelist[nummodes].width == modelist[i].width) &&
                                (modelist[nummodes].height == modelist[i].height))
                        {
                            existingmode = 1;
                            break;
                        }
                    }

                    if (!existingmode)
                    {
                        if (modelist[nummodes].width < lowestres)
                            lowestres = modelist[nummodes].width;

                        nummodes++;
                    }
                }
            }

            modenum++;
        }
        while (stat);
    	*/
// see if any of them were actually settable; if so, this is our mode list,
// else enumerate all modes; our mode list is whichever ones are settable
// with > 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_WINDOWED;
                    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;
                    sprintf(modelist[nummodes].modedesc, "%dx%d",
                            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;
                            sprintf(modelist[nummodes].modedesc, "%dx%d",
                                    modelist[nummodes].width,
                                    modelist[nummodes].height);
                        }
                    }

                    for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++) {
                        if ((modelist[nummodes].width == modelist[i].width) &&
                                (modelist[nummodes].height == modelist[i].height)) {
                            // pick the lowest available bpp
                            if (modelist[nummodes].bpp < modelist[i].bpp) {
                                modelist[i] = modelist[nummodes];
                            }

                            existingmode = 1;
                            break;
                        }
                    }

                    if (!existingmode) {
                        if (modelist[nummodes].width < lowestres) {
                            lowestres = modelist[nummodes].width;
                        }

                        nummodes++;
                    }
                }
            }

            modenum++;
        } while (stat);
    }

// see if there are any low-res modes that aren't being reported
    numlowresmodes = sizeof(lowresmodes) / sizeof(lowresmodes[0]);
    bpp = 8;
    done = 0;

// first make sure the driver doesn't just answer yes to all tests
    devmode.dmBitsPerPel = 8;
    devmode.dmPelsWidth = 42;
    devmode.dmPelsHeight = 37;
    devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

    if (ChangeDisplaySettings(&devmode, CDS_TEST | CDS_FULLSCREEN) ==
            DISP_CHANGE_SUCCESSFUL) {
        done = 1;
    }

    while (!done) {
        for (j=0 ; (j<numlowresmodes) && (nummodes < MAX_MODE_LIST) ; j++) {
            devmode.dmBitsPerPel = bpp;
            devmode.dmPelsWidth = lowresmodes[j].width;
            devmode.dmPelsHeight = lowresmodes[j].height;
            devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

            if (ChangeDisplaySettings(&devmode, CDS_TEST | CDS_FULLSCREEN) ==
                    DISP_CHANGE_SUCCESSFUL) {
                modelist[nummodes].type = MS_WINDOWED;
                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;
                sprintf(modelist[nummodes].modedesc, "%dx%d",
                        devmode.dmPelsWidth, devmode.dmPelsHeight);

                // we only want the lowest-bpp version of each mode
                for (i=originalnummodes, existingmode = 0 ; i<nummodes ; i++) {
                    if ((modelist[nummodes].width == modelist[i].width)   &&
                            (modelist[nummodes].height == modelist[i].height) &&
                            (modelist[nummodes].bpp >= 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<nummodes ; i++) {
            if (((modelist[i].width >> 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 = 0;
            sprintf(modelist[istretch].modedesc, "%dx%d",
                    modelist[istretch].width, modelist[istretch].height);
        }
    }

    vid_default	=	0;
    //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;
        sprintf(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) {
        sprintf(pinfo,"%s fullscreen", pv->modedesc);
    } else if (modelist[mode].type == MS_WINDOWED) {
        sprintf(pinfo,"%s fullscreen", pv->modedesc);
    } else {
        sprintf(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)
        {
            sprintf(pinfo,"%s fullscreen %s",pv->modedesc,
                    MGL_modeDriverName(pv->modenum));
        }
        else if (modelist[mode].type == MS_FULLDIB)
        {
            sprintf(pinfo,"%s fullscreen DIB", pv->modedesc);
        }
        else
        {
            sprintf(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;
    LONG			wlong;
    BITMAPINFO 		bmi;
    DWORD 			dw;
    LPVOID 			lpMsgBuf;
    LPVOID 			lpDisplayBuf;

    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;
    }

    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,
                         "Makaqu", // WinQuake // edited
                         "Makaqu", // WinQuake // edited
                         WindowStyle,
                         0, 0,
                         WindowRect.right - WindowRect.left,
                         WindowRect.bottom - WindowRect.top,
                         NULL,
                         NULL,
                         global_hInstance,
                         NULL);

        if (!mainwindow) {
            dw = GetLastError();
            FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
                          FORMAT_MESSAGE_FROM_SYSTEM |
                          FORMAT_MESSAGE_IGNORE_INSERTS,
                          NULL,
                          dw,
                          MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
                          (LPTSTR) &lpMsgBuf,
                          0, NULL);

            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,
                      240, 160,
                      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);
    if (g_hMemDC) {
        DeleteDC(g_hMemDC);
    }
    g_hMemDC=0;

    if (!g_hMemDC) {
        g_hMemDC = CreateCompatibleDC(hdc);

        ZeroMemory(&bmi, sizeof(BITMAPINFO));
        bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth = DIBWidth;
        bmi.bmiHeader.biHeight = DIBHeight;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
        bmi.bmiHeader.biSizeImage = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 4;

        g_hBmp = CreateDIBSection(g_hMemDC, &bmi, DIB_RGB_COLORS, (void**)&g_pBufferC, NULL, 0);
        free(g_pBufferB);
        g_pBufferB	=	malloc(DIBWidth*DIBHeight*sizeof(pixel_t));
        SelectObject(g_hMemDC,g_hBmp);
    }
    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);
    */
    memset(g_pBufferB,0xff,DIBWidth*DIBHeight*sizeof(pixel_t));
    vid.buffer = vid.conbuffer = vid.direct = g_pBufferB;
    vid.rowbytes = vid.conrowbytes = DIBWidth*sizeof(pixel_t);
    vid.numpages = 1;
//	vid.maxwarpwidth = WARP_WIDTH; // hi-res waterwarp - removed
//	vid.maxwarpheight = WARP_HEIGHT; // hi-res waterwarp - removed
    vid.height = vid.conheight = DIBHeight;
    vid.width = vid.conwidth = DIBWidth;
    vid.maxwarpwidth = vid.width; // hi-res waterwarp
    vid.maxwarpheight = vid.height; // hi-res waterwarp
    /*	// buffered video - begin
    	vid_card_buffer = dibdc->surface;
    	if (vid_buffer)
    	{
    		free(vid_buffer);
    		vid_buffer = NULL;
    	}
    	vid_buffer = (byte  *)malloc((int)(vid.rowbytes*vid.height));
    	vid.buffer = vid.conbuffer = vid.direct = vid_buffer;
    */	// buffered video - end
    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_card_buffer = NULL;
        // buffered video - end
        vid.buffer = vid.conbuffer = vid.direct = NULL; // buffered video - removed
    //	vid.maxwarpwidth = WARP_WIDTH; // hi-res waterwarp - removed
    //	vid.maxwarpheight = WARP_HEIGHT; // hi-res waterwarp - removed
        DIBHeight = vid.height = vid.conheight = modelist[modenum].height;
        DIBWidth = vid.width = vid.conwidth = modelist[modenum].width;
        vid.maxwarpwidth = vid.width; // hi-res waterwarp
        vid.maxwarpheight = vid.height; // hi-res waterwarp
        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;
    BITMAPINFO bmi;

    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_WINDOWED;
    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);
    */
    if (!g_hMemDC) {
        g_hMemDC = CreateCompatibleDC(hdc);

        ZeroMemory(&bmi, sizeof(BITMAPINFO));
        bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth = WindowRect.right;
        bmi.bmiHeader.biHeight = WindowRect.bottom;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;
        bmi.bmiHeader.biCompression = BI_RGB;
        bmi.bmiHeader.biSizeImage = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 4;

        g_hBmp = CreateDIBSection(g_hMemDC, &bmi, DIB_RGB_COLORS, (void**)&g_pBufferC, NULL, 0);
        SelectObject(g_hMemDC,g_hBmp);
        free(g_pBufferB);
        g_pBufferB	=	malloc(DIBWidth*DIBHeight*sizeof(pixel_t));
    }

    vid.buffer = vid.conbuffer = vid.direct = g_pBufferB; // buffered video - removed
    vid.rowbytes = vid.conrowbytes = WindowRect.right*sizeof(pixel_t);
    vid.numpages = 1;
//	vid.maxwarpwidth = WARP_WIDTH; // hi-res waterwarp - removed
//	vid.maxwarpheight = WARP_HEIGHT; // hi-res waterwarp - removed
    vid.height = vid.conheight = DIBHeight;
    vid.width = vid.conwidth = DIBWidth;
    vid.maxwarpwidth = vid.width; // hi-res waterwarp
    vid.maxwarpheight = vid.height; // hi-res waterwarp
    /*	// buffered video - begin
    	vid_card_buffer = dibdc->surface;
    	if (vid_buffer)
    	{
    		free(vid_buffer);
    		vid_buffer = NULL;
    	}
    	vid_buffer = (byte  *)malloc((int)(vid.rowbytes*vid.height));
    	vid.buffer = vid.conbuffer = vid.direct = vid_buffer;
    */	// buffered video - end
    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, dummy;
    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 (key_dest != key_menu && !cl.paused) { // edited
            stat = VID_SetWindowedMode(modenum);
            IN_ActivateMouse();
            IN_HideMouse();
        } else {
            IN_DeactivateMouse();
            IN_ShowMouse();
            stat = VID_SetWindowedMode(modenum);
        }
    } else if (modelist[modenum].type == MS_WINDOWED) {
        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 ("%s\n", VID_GetModeDescription (vid_modenum));

    VID_SetPalette(palette);

    in_mode_set = false;
    vid.recalc_refdef = 1;
    SCR_Adjust(); // screen positioning

    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; // buffered video - removed
            //	vid_card_buffer = memdc->surface; // buffered video
            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; // buffered video - removed
            //	vid_card_buffer = mgldc->surface; // buffered video
            vid.rowbytes = vid.conrowbytes = mgldc->mi.bytesPerLine;
        }
        // buffered video - begin
    //	vid.buffer = vid.conbuffer = vid.direct = vid_buffer;
    //	vid.buffer = vid.conbuffer = vid.direct = vid_buffer = vid_card_buffer;
    //	vid.buffer = vid.conbuffer = vid.direct = vid_card_buffer;
        // buffered video - end

    //	if (r_dowarp) // buffered video (bloody hack) - removed
        d_viewbuffer = r_warpbuffer;
    //	else // buffered video (bloody hack) - removed
    //		d_viewbuffer = (void *)(byte *)vid.buffer; // buffered video (bloody hack) - removed
    //		d_viewbuffer = vid_buffer; // não funciona
    //	Con_Printf("r_warpbuffer %u\n", &r_warpbuffer);
    //	Con_Printf("vid_buffer %u\n", &vid_buffer);

    //	if (r_dowarp) // buffered video (bloody hack) - removed
        screenwidth = vid.width;//WARP_WIDTH; // hi-res waterwarp - edited
    //	else // buffered video (bloody hack) - removed
    //		screenwidth = vid.rowbytes; // buffered video (bloody hack) - removed

        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_card_buffer = NULL; // buffered video
        vid.buffer = vid.conbuffer = vid.direct = d_viewbuffer = NULL; // buffered video - removed
    */
}


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 a,b;
    unsigned int Pal[256];
    for (a=0; a<256; a++) {
        b		=	(*(int*)&(palette[a*3]))&0xffffff;
        b		=	((b&0xff)<<16)|((b&0xff00))|((b&0xff0000)>>16);
        Pal[a]	=	b;
    }
    Pal[255]	=	0xdeadbeaf;	//transparent color, used by particles and sprites
    memcpy(d_8to24table,Pal,sizeof(d_8to24table));
    /*
        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 = Q_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 ; i<lnummodes ; i++) {
        pv = VID_GetModePtr(i);
        pinfo = VID_GetExtModeDescription(i);

        if (VID_CheckAdequateMem(pv->width, 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 = Q_atoi(Cmd_Argv(1));

        if (VID_SetMode(modenum, vid_curpal)) {
            vid_testingmode = 1;
            testduration = Q_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;
    double	testduration;

    if (!vid_testingmode) {
        modenum = Q_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, bestmatchmetric, t, dr, dg, db;
    int		basenummodes;
    byte	*ptmp;

    Cvar_RegisterVariable(&vid_mode);
    Cvar_RegisterVariable(&vid_wait);
    Cvar_RegisterVariable(&vid_nopageflip);
    Cvar_RegisterVariable(&_vid_wait_override);
    Cvar_RegisterVariable(&_vid_default_mode);
    Cvar_RegisterVariable(&_vid_default_mode_win);
    Cvar_RegisterVariable(&vid_config_x);
    Cvar_RegisterVariable(&vid_config_y);
    Cvar_RegisterVariable(&vid_stretch_by_2);
//	Cvar_RegisterVariable (&_windowed_mouse); // removed
    Cvar_RegisterVariable(&vid_fullscreen_mode);
    Cvar_RegisterVariable(&vid_windowed_mode);
    Cvar_RegisterVariable(&block_switch);
    Cvar_RegisterVariable(&vid_window_x);
    Cvar_RegisterVariable(&vid_window_y);

    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 = 320;//WARP_WIDTH; // hi-res waterwarp - edited
    vid.maxwarpheight = 200;//WARP_HEIGHT; // hi-res waterwarp - edited
    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)
{
    /*
        HDC				hdc;
        int				dummy;

        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)
{
    PAINTSTRUCT ps;
    HDC hdc;
    int a,x,y;
    DWORD 			dw;
    LPVOID 			lpMsgBuf;
    LPVOID 			lpDisplayBuf;

    if (!g_hMemDC) {
        return;
    }
    hdc = GetDC(mainwindow);//BeginPaint(mainwindow, &ps);

    for (y=0; y<DIBHeight; y++)
        for (x=0; x<DIBWidth; x++) {
            a	=	g_pBufferB[x+(DIBHeight-y-1)*DIBWidth];
            g_pBufferC[x+y*DIBWidth]=a;
        }

    //for(y=0;y<DIBHeight;y++)
    //for(x=DIBWidth-1;x>=0;x--)
    //	g_pBuffer[x+y*DIBWidth]	=	((byte*)g_pBuffer)[x+y*DIBWidth];


    BitBlt(hdc,0,0,DIBWidth,DIBHeight,g_hMemDC,0,0,SRCCOPY);

//	EndPaint(mainwindow, &ps);
//	InvalidateRect(mainwindow,0,true);

    /*    HRESULT		ddrval;

        // 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 = &rect;
    }

    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);
        }
    }
    /*	// buffered video - begin
    	// copy buffer to video
    //	VID_LockBuffer();
    	D_EnableBackBufferAccess ();
    	if (vid_card_buffer && vid_buffer)
    	{
    	int		i;
    	byte	*src;
    	byte	*dest;
    	src = vid_buffer;
    	dest = vid_card_buffer;
    //	dest = vid_card_buffer + scr_vrect.y * vid.rowbytes + scr_vrect.x;

    //	for (i=0 ; i<scr_vrect.height ; i++, src += vid.width, dest += vid.rowbytes)
    	for (i=0 ; i<vid.height ; i++, src += vid.width, dest += vid.rowbytes)
    		Q_memcpy(dest, src, vid.width);
    	}
    	D_DisableBackBufferAccess ();
    //	VID_UnlockBuffer();
    */	// buffered video - end

    // 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 != windowed_mouse) // edited
        {
            if (key_dest != key_menu && !cl.paused) { // edited
                IN_ActivateMouse();
                IN_HideMouse();
            } else {
                IN_DeactivateMouse();
                IN_ShowMouse();
            }

//			windowed_mouse = _windowed_mouse; // edited
        }
    }
}


/*
================
D_BeginDirectRect
================
*/

void D_BeginDirectRect(int x, int y, byte *pbitmap, int width, int height)
{
#if 0 // Edited
    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");
        }

        // begin
#if 0
        {
            byte t;
            for (i=0 ; i<(height << repshift) ; i += reps)
                for (j=0 ; j<width ; j++) {
                    t = pbitmap[(i >> repshift) * width + j];
                    if (t != TRANSPARENT_COLOR) {
                        backingbuf[i*24 + j] = vid.direct[((y<<repshift)+i)*(width*vid.rowbytes) + x+j];
                        vid.direct[((y<<repshift)+i)*(width*vid.rowbytes) + x+j] = t;
                    }
                }
        }
#else
        // end
        for (i=0 ; i<(height << repshift) ; i += reps) {
            for (j=0 ; j<reps ; j++) {
                memcpy(&backingbuf[(i + j) * 24],
                       vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
                       width);
                memcpy(vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
                       &pbitmap[(i >> repshift) * width],
                       width);
            }
        }
#endif

        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
        // begin
#if 0
        {
            byte *pdest, t;
            pdest = (byte *)mgldc->surface;
            for (i=0 ; i<(height << repshift) ; i += reps)
                for (j=0 ; j<width ; j++) {
                    t = pbitmap[(i >> repshift) * width + j];
                    if (t != TRANSPARENT_COLOR) {
                        backingbuf[i*24 + j] = pdest[((y<<repshift)+i)*(width*mgldc->mi.bytesPerLine) + x+j];
                        pdest[((y<<repshift)+i)*(width*mgldc->mi.bytesPerLine) + x+j] = t;
                    }
                }
        }
#else
        // end
        for (i=0 ; i<(height << repshift) ; i += reps) {
            for (j=0 ; j<reps ; j++) {
                memcpy(&backingbuf[(i + j) * 24],
                       (byte *)mgldc->surface + 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);
            }
        }
#endif

        // 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();
        }
    }
#endif // Edited
}


/*
================
D_EndDirectRect
================
*/
void D_EndDirectRect(int x, int y, int width, int height)
{
#if 0 // Edited
    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<reps ; j++) {
                memcpy(vid.direct + x + ((y << repshift) + i + j) * vid.rowbytes,
                       &backingbuf[(i + j) * 24],
                       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();

        // restore to the screen
        for (i=0 ; i<(height << repshift) ; i += reps) {
            for (j=0 ; j<reps ; j++) {
                memcpy((byte *)mgldc->surface + 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();
        }
    }
#endif // Edited
}


//==========================================================================

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,'*',
    K_ALT,' ',   0  ,    K_F1, K_F2, K_F3, K_F4, K_F5,   // 3
    K_F6, K_F7, K_F8, K_F9, K_F10,  K_PAUSE,    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,        // 6
    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0,
    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0  ,    0         // 7
};

/*
=======
MapKey

Map from windows to quake keynums
=======
*/
int MapKey(int key)
{
    key = (key>>16)&255;
    if (key > 127) {
        return 0;
    }

    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) && key_dest != key_menu && !cl.paused) // edited
                {
                    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) && key_dest != key_menu && !cl.paused) // edited
                {
                    IN_DeactivateMouse ();
                    IN_ShowMouse ();
                }
            }
        }
    */
}


/*
================
VID_HandlePause
================
*/
void VID_HandlePause(qboolean pause)
{

    if ((modestate == MS_WINDOWED)) // edited
        if (key_dest != key_menu) { // Edited
            if (pause) {
                IN_DeactivateMouse();
                IN_ShowMouse();
            } else {
                IN_ActivateMouse();
                IN_HideMouse();
            }
        }
}


/*
===================================================================

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				fwKeys, xPos, yPos, fActive, fMinimized, temp;
    HDC				hdc;
    PAINTSTRUCT		ps;
    static int		recursiveflag;

    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_Video_f(void);  // edited
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);

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;
    char		temp[100];
    vmode_t		*pv;
    modedesc_t	tmodedesc;

    p = Draw_CachePic("gfx/vidmodes.lmp");
    M_DrawTransPic((320-p->width)/2, 4, p);   // edited

    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 ; i<lnummodes ; i++) {
        ptr = VID_GetModeDescriptionMemCheck(i);
        pv = VID_GetModePtr(i);

        // we only have room for 15 fullscreen modes, so don't allow
        // 360-wide modes, because if there are 5 320-wide modes and
        // 5 360-wide modes, we'll run out of space
        if (ptr && ((pv->width != 360) || COM_CheckParm("-allow360"))) {
            dup = 0;

            for (j=3 ; j<vid_wmodes ; j++) {
                if (!strcmp(modedescs[j].desc, ptr)) {
                    dup = 1;
                    dupmode = j;
                    break;
                }
            }

            if (dup || (vid_wmodes < MAX_MODEDESCS)) {
                if (!dup || !modedescs[dupmode].ismode13 || COM_CheckParm("-noforcevga")) {
                    if (dup) {
                        k = dupmode;
                    } else {
                        k = vid_wmodes;
                    }

                    modedescs[k].modenum = i;
                    modedescs[k].desc = ptr;
                    modedescs[k].ismode13 = pv->mode13;
                    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<vid_wmodes ; j++) {
            if (modedescs[i].width > 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 ; i<vid_wmodes ; i++) {
            if (modedescs[i].iscur) {
                M_PrintWhite(column, row, modedescs[i].desc);
            } else {
                M_Print(column, row, modedescs[i].desc);
            }

            column += 13*8;

            if (((i - 3) % VID_ROW_SIZE) == (VID_ROW_SIZE - 1)) {
                column = 16;
                row += 8;
            }
        }
    }

// line cursor
    if (vid_testingmode) {
        sprintf(temp, "TESTING %s",
                modedescs[vid_line].desc);
        M_Print(13*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, temp);
        M_Print(9*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6,
                "Please wait 5 seconds...");
    } else {
        M_Print(9*8, 36 + MODE_AREA_HEIGHT * 8 + 8,
                "Press Enter to set mode");
        M_Print(6*8, 36 + MODE_AREA_HEIGHT * 8 + 8*3,
                "T to test mode for 5 seconds");
        ptr = VID_GetModeDescription2(vid_modenum);

        if (ptr) {
            sprintf(temp, "D to set default: %s", ptr);
            M_Print(2*8, 36 + MODE_AREA_HEIGHT * 8 + 8*5, temp);
        }

        ptr = VID_GetModeDescription2((int)_vid_default_mode_win.value);

        if (ptr) {
            sprintf(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_Video_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;
    }
}
