/* vid_wgl.c OpenGL low-level video driver for Windows NT/9x Copyright (C) 1996-1997 Id Software, Inc. Copyright (C) 1999,2000 Nelson Rush. Copyright (C) 1999,2000 contributors of the QuakeForge project Please see the file "AUTHORS" for a list of contributors This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to: Free Software Foundation, Inc. 59 Temple Place - Suite 330 Boston, MA 02111-1307, USA $Id$ */ #include #include #include #include #include #include #include #include #include #include #include #define MAX_MODE_LIST 30 #define VID_ROW_SIZE 3 #define WARP_WIDTH 320 #define WARP_HEIGHT 200 #define MAXWIDTH 10000 #define MAXHEIGHT 10000 #define BASEWIDTH 320 #define BASEHEIGHT 200 #define MODE_WINDOWED 0 #define NO_MODE (MODE_WINDOWED - 1) #define MODE_FULLSCREEN_DEFAULT (MODE_WINDOWED + 1) typedef struct { modestate_t type; int width; int height; int modenum; int dib; int fullscreen; int bpp; int halfscreen; char modedesc[17]; } vmode_t; typedef struct { int width; int height; } lmode_t; lmode_t lowresmodes[] = { {320, 200}, {320, 240}, {400, 300}, {512, 384}, }; const char *gl_vendor; const char *gl_renderer; const char *gl_version; const char *gl_extensions; qboolean DDActive; qboolean scr_skipupdate; static vmode_t modelist[MAX_MODE_LIST]; static int nummodes; static vmode_t *pcurrentmode; static vmode_t badmode; static DEVMODE gdevmode; static qboolean vid_initialized = false; static qboolean windowed, leavecurrentmode; static qboolean vid_canalttab = false; static qboolean vid_wassuspended = false; static int windowed_mouse; extern qboolean mouseactive; // from in_win.c static HICON hIcon; int DIBWidth, DIBHeight; RECT WindowRect; DWORD WindowStyle, ExWindowStyle; HWND mainwindow, dibwindow; int vid_modenum = NO_MODE; int vid_realmode; int vid_default = MODE_WINDOWED; static int windowed_default; unsigned char vid_curpal[256*3]; static qboolean fullsbardraw = false; static float vid_gamma = 1.0; int VID_options_items = 1; HGLRC baseRC; HDC maindc; glvert_t glv; HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); extern viddef_t vid; // global video state unsigned short d_8to16table[256]; unsigned d_8to24table[256]; unsigned char d_15to8table[65536]; float gldepthmin, gldepthmax; modestate_t modestate = MS_UNINIT; void VID_MenuDraw (void); void VID_MenuKey (int key); LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void AppActivate(BOOL fActive, BOOL minimize); char *VID_GetModeDescription (int mode); void ClearAllStates (void); void VID_UpdateWindowStatus (void); void GL_Init (void); PROC glArrayElementEXT; PROC glColorPointerEXT; PROC glTexCoordPointerEXT; PROC glVertexPointerEXT; typedef void (GLAPIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); lp3DFXFUNC glColorTableEXT; qboolean is8bit = false; qboolean isPermedia = false; qboolean gl_mtexable = false; //==================================== cvar_t *gl_ztrick; cvar_t *vid_mode; // Note that 0 is MODE_WINDOWED cvar_t *_vid_default_mode; // Note that 3 is MODE_FULLSCREEN_DEFAULT cvar_t *_vid_default_mode_win; cvar_t *vid_wait; cvar_t *vid_nopageflip; cvar_t *_vid_wait_override; cvar_t *vid_config_x; cvar_t *vid_config_y; cvar_t *vid_stretch_by_2; cvar_t *in_grab; int window_center_x, window_center_y, window_x, window_y, window_width, window_height; RECT window_rect; // direct draw software compatability stuff void VID_HandlePause (qboolean pause) { } void VID_ForceLockState (int lk) { } int VID_ForceUnlockedAndReturnState (void) { return 0; } void D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height) { } void D_EndDirectRect (int x, int y, int width, int height) { } void CenterWindow(HWND hWndCenter, int width, int height, BOOL lefttopjustify) { RECT rect; int CenterX, CenterY; CenterX = (GetSystemMetrics(SM_CXSCREEN) - width) / 2; CenterY = (GetSystemMetrics(SM_CYSCREEN) - height) / 2; if (CenterX > CenterY*2) CenterX >>= 1; // dual screens CenterX = (CenterX < 0) ? 0: CenterX; CenterY = (CenterY < 0) ? 0: CenterY; SetWindowPos (hWndCenter, NULL, CenterX, CenterY, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW | SWP_DRAWFRAME); } qboolean VID_SetWindowedMode (int modenum) { HDC hdc; int lastmodestate, width, height; RECT rect; lastmodestate = modestate; WindowRect.top = WindowRect.left = 0; WindowRect.right = modelist[modenum].width; WindowRect.bottom = modelist[modenum].height; DIBWidth = modelist[modenum].width; DIBHeight = modelist[modenum].height; WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; ExWindowStyle = 0; rect = WindowRect; AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); width = rect.right - rect.left; height = rect.bottom - rect.top; // Create the DIB window dibwindow = CreateWindowEx ( ExWindowStyle, "WinQuake", "GLQuake", WindowStyle, rect.left, rect.top, width, height, NULL, NULL, global_hInstance, NULL); if (!dibwindow) Sys_Error ("Couldn't create DIB window"); // Center and show the DIB window CenterWindow(dibwindow, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, false); ShowWindow (dibwindow, SW_SHOWDEFAULT); UpdateWindow (dibwindow); modestate = MS_WINDOWED; // because we have set the background brush for the window to NULL // (to avoid flickering when re-sizing the window on the desktop), // we clear the window to black when created, otherwise it will be // empty while Quake starts up. hdc = GetDC(dibwindow); PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); ReleaseDC(dibwindow, hdc); if (vid.conheight > modelist[modenum].height) vid.conheight = modelist[modenum].height; if (vid.conwidth > modelist[modenum].width) vid.conwidth = modelist[modenum].width; vid.width = vid.conwidth; vid.height = vid.conheight; vid.numpages = 2; mainwindow = dibwindow; SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); return true; } qboolean VID_SetFullDIBMode (int modenum) { HDC hdc; int lastmodestate, width, height; RECT rect; if (!leavecurrentmode) { gdevmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; gdevmode.dmBitsPerPel = modelist[modenum].bpp; gdevmode.dmPelsWidth = modelist[modenum].width << modelist[modenum].halfscreen; gdevmode.dmPelsHeight = modelist[modenum].height; gdevmode.dmSize = sizeof (gdevmode); if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) Sys_Error ("Couldn't set fullscreen DIB mode"); } lastmodestate = modestate; modestate = MS_FULLDIB; WindowRect.top = WindowRect.left = 0; WindowRect.right = modelist[modenum].width; WindowRect.bottom = modelist[modenum].height; DIBWidth = modelist[modenum].width; DIBHeight = modelist[modenum].height; WindowStyle = WS_POPUP; ExWindowStyle = 0; rect = WindowRect; AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); width = rect.right - rect.left; height = rect.bottom - rect.top; // Create the DIB window dibwindow = CreateWindowEx ( ExWindowStyle, "WinQuake", "GLQuake", WindowStyle, rect.left, rect.top, width, height, NULL, NULL, global_hInstance, NULL); if (!dibwindow) Sys_Error ("Couldn't create DIB window"); ShowWindow (dibwindow, SW_SHOWDEFAULT); UpdateWindow (dibwindow); // Because we have set the background brush for the window to NULL // (to avoid flickering when re-sizing the window on the desktop), we // clear the window to black when created, otherwise it will be // empty while Quake starts up. hdc = GetDC(dibwindow); PatBlt(hdc,0,0,WindowRect.right,WindowRect.bottom,BLACKNESS); ReleaseDC(dibwindow, hdc); if (vid.conheight > modelist[modenum].height) vid.conheight = modelist[modenum].height; if (vid.conwidth > modelist[modenum].width) vid.conwidth = modelist[modenum].width; vid.width = vid.conwidth; vid.height = vid.conheight; vid.numpages = 2; // needed because we're not getting WM_MOVE messages fullscreen on NT window_x = 0; window_y = 0; mainwindow = dibwindow; SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); return true; } int VID_SetMode (int modenum, unsigned char *palette) { int original_mode, temp; qboolean stat; MSG msg; HDC hdc; if ((windowed && (modenum != 0)) || (!windowed && (modenum < 1)) || (!windowed && (modenum >= nummodes))) { Sys_Error ("Bad video mode\n"); } // so Con_Printfs don't mess us up by forcing vid and snd updates temp = scr_disabled_for_loading; scr_disabled_for_loading = true; CDAudio_Pause (); if (vid_modenum == NO_MODE) original_mode = windowed_default; else original_mode = vid_modenum; // Set either the fullscreen or windowed mode if (modelist[modenum].type == MS_WINDOWED) { if (in_grab->value && key_dest == key_game) { stat = VID_SetWindowedMode(modenum); IN_ActivateMouse (); IN_HideMouse (); } else { IN_DeactivateMouse (); IN_ShowMouse (); stat = VID_SetWindowedMode(modenum); } } else if (modelist[modenum].type == MS_FULLDIB) { stat = VID_SetFullDIBMode(modenum); IN_ActivateMouse (); IN_HideMouse (); } else { Sys_Error ("VID_SetMode: Bad mode type in modelist"); } window_width = DIBWidth; window_height = DIBHeight; VID_UpdateWindowStatus (); CDAudio_Resume (); scr_disabled_for_loading = temp; if (!stat) { Sys_Error ("Couldn't set video mode"); } // now we try to make sure we get the focus on the mode switch, because // sometimes in some systems we don't. We grab the foreground, then // finish setting up, pump all our messages, and sleep for a little while // to let messages finish bouncing around the system, then we put // ourselves at the top of the z order, then grab the foreground again, // Who knows if it helps, but it probably doesn't hurt SetForegroundWindow (mainwindow); VID_SetPalette (palette); vid_modenum = modenum; vid_mode->value = (float)vid_modenum; while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage (&msg); DispatchMessage (&msg); } Sleep (100); SetWindowPos (mainwindow, HWND_TOP, 0, 0, 0, 0, SWP_DRAWFRAME | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOCOPYBITS); SetForegroundWindow (mainwindow); // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); if (!msg_suppress_1) Con_SafePrintf ("Video mode %s initialized.\n", VID_GetModeDescription (vid_modenum)); VID_SetPalette (palette); vid.recalc_refdef = 1; return true; } /* ================ VID_UpdateWindowStatus ================ */ void VID_UpdateWindowStatus (void) { window_rect.left = window_x; window_rect.top = window_y; window_rect.right = window_x + window_width; window_rect.bottom = window_y + window_height; window_center_x = (window_rect.left + window_rect.right) / 2; window_center_y = (window_rect.top + window_rect.bottom) / 2; IN_UpdateClipCursor (); } //==================================== BINDTEXFUNCPTR bindTexFunc; #define TEXTURE_EXT_STRING "GL_EXT_texture_object" void CheckTextureExtensions (void) { char *tmp; qboolean texture_ext; HINSTANCE hInstGL; texture_ext = FALSE; /* check for texture extension */ tmp = (unsigned char *)glGetString(GL_EXTENSIONS); while (*tmp) { if (strncmp((const char*)tmp, TEXTURE_EXT_STRING, strlen(TEXTURE_EXT_STRING)) == 0) texture_ext = TRUE; tmp++; } if (!texture_ext || COM_CheckParm ("-gl11") ) { hInstGL = LoadLibrary("opengl32.dll"); if (hInstGL == NULL) Sys_Error ("Couldn't load opengl32.dll\n"); bindTexFunc = (void *)GetProcAddress(hInstGL,"glBindTexture"); if (!bindTexFunc) Sys_Error ("No texture objects!"); return; } /* load library and get procedure adresses for texture extension API */ if ((bindTexFunc = (BINDTEXFUNCPTR) wglGetProcAddress((LPCSTR) "glBindTextureEXT")) == NULL) { Sys_Error ("GetProcAddress for BindTextureEXT failed"); return; } } void CheckArrayExtensions (void) { char *tmp; /* check for texture extension */ tmp = (unsigned char *)glGetString(GL_EXTENSIONS); while (*tmp) { if (strncmp((const char*)tmp, "GL_EXT_vertex_array", strlen("GL_EXT_vertex_array")) == 0) { if ( ((glArrayElementEXT = wglGetProcAddress("glArrayElementEXT")) == NULL) || ((glColorPointerEXT = wglGetProcAddress("glColorPointerEXT")) == NULL) || ((glTexCoordPointerEXT = wglGetProcAddress("glTexCoordPointerEXT")) == NULL) || ((glVertexPointerEXT = wglGetProcAddress("glVertexPointerEXT")) == NULL) ) { Sys_Error ("GetProcAddress for vertex extension failed"); return; } return; } tmp++; } Sys_Error ("Vertex array extension not present"); } //int texture_mode = GL_NEAREST; //int texture_mode = GL_NEAREST_MIPMAP_NEAREST; //int texture_mode = GL_NEAREST_MIPMAP_LINEAR; int texture_mode = GL_LINEAR; //int texture_mode = GL_LINEAR_MIPMAP_NEAREST; //int texture_mode = GL_LINEAR_MIPMAP_LINEAR; int texture_extension_number = 1; #ifdef _WIN32 void CheckMultiTextureExtensions(void) { if (strstr(gl_extensions, "GL_SGIS_multitexture ") && !COM_CheckParm("-nomtex")) { Con_Printf("Multitexture extensions found.\n"); qglMTexCoord2fSGIS = (void *) wglGetProcAddress("glMTexCoord2fSGIS"); qglSelectTextureSGIS = (void *) wglGetProcAddress("glSelectTextureSGIS"); gl_mtexable = true; } } #else void CheckMultiTextureExtensions(void) { gl_mtexable = true; } #endif /* =============== GL_Init =============== */ void GL_Init (void) { gl_vendor = glGetString (GL_VENDOR); Con_Printf ("GL_VENDOR: %s\n", gl_vendor); gl_renderer = glGetString (GL_RENDERER); Con_Printf ("GL_RENDERER: %s\n", gl_renderer); gl_version = glGetString (GL_VERSION); Con_Printf ("GL_VERSION: %s\n", gl_version); gl_extensions = glGetString (GL_EXTENSIONS); Con_Printf ("GL_EXTENSIONS: %s\n", gl_extensions); // Con_Printf ("%s %s\n", gl_renderer, gl_version); if (strnicmp(gl_renderer,"PowerVR",7)==0) fullsbardraw = true; if (strnicmp(gl_renderer,"Permedia",8)==0) isPermedia = true; CheckTextureExtensions (); CheckMultiTextureExtensions (); glClearColor (1,0,0,0); glCullFace(GL_FRONT); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.666); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); glShadeModel (GL_FLAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); #if 0 CheckArrayExtensions (); glEnable (GL_VERTEX_ARRAY_EXT); glEnable (GL_TEXTURE_COORD_ARRAY_EXT); glVertexPointerEXT (3, GL_FLOAT, 0, 0, &glv.x); glTexCoordPointerEXT (2, GL_FLOAT, 0, 0, &glv.s); glColorPointerEXT (3, GL_FLOAT, 0, 0, &glv.r); #endif } /* ================= GL_BeginRendering ================= */ void GL_BeginRendering (int *x, int *y, int *width, int *height) { extern cvar_t *gl_clear; *x = *y = 0; *width = WindowRect.right - WindowRect.left; *height = WindowRect.bottom - WindowRect.top; // if (!wglMakeCurrent( maindc, baseRC )) // Sys_Error ("wglMakeCurrent failed"); // glViewport (*x, *y, *width, *height); } void GL_EndRendering (void) { if (!scr_skipupdate || block_drawing) SwapBuffers(maindc); // handle the mouse state when windowed if that's changed if (modestate == MS_WINDOWED) { if (!in_grab->value) { if (windowed_mouse) { IN_DeactivateMouse (); IN_ShowMouse (); windowed_mouse = false; } } else { windowed_mouse = true; if (key_dest == key_game && !mouseactive && ActiveApp) { IN_ActivateMouse (); IN_HideMouse (); } else if (mouseactive && key_dest != key_game) { IN_DeactivateMouse (); IN_ShowMouse (); } } } if (fullsbardraw) Sbar_Changed(); } void VID_SetPalette (unsigned char *palette) { byte *pal; unsigned r,g,b; unsigned v; int r1,g1,b1; int j,k,l,m; unsigned short i; unsigned *table; QFile *f; char s[255]; HWND hDlg, hProgress; float gamma; // // 8 8 8 encoding // pal = palette; table = d_8to24table; for (i=0 ; i<256 ; i++) { r = pal[0]; g = pal[1]; b = pal[2]; pal += 3; // v = (255<<24) + (r<<16) + (g<<8) + (b<<0); // v = (255<<0) + (r<<8) + (g<<16) + (b<<24); v = (255<<24) + (r<<0) + (g<<8) + (b<<16); *table++ = v; } d_8to24table[255] &= 0xffffff; // 255 is transparent // JACK: 3D distance calcs - k is last closest, l is the distance. // FIXME: Precalculate this and cache to disk. for (i=0; i < (1<<15); i++) { /* Maps 000000000000000 000000000011111 = Red = 0x1F 000001111100000 = Blue = 0x03E0 111110000000000 = Grn = 0x7C00 */ r = ((i & 0x1F) << 3)+4; g = ((i & 0x03E0) >> 2)+4; b = ((i & 0x7C00) >> 7)+4; pal = (unsigned char *)d_8to24table; for (v=0,k=0,l=10000*10000; v<256; v++,pal+=4) { r1 = r-pal[0]; g1 = g-pal[1]; b1 = b-pal[2]; j = (r1*r1)+(g1*g1)+(b1*b1); if (j> 24) & 1; key = (key>>16)&255; if (key > 127) return 0; if (extended) return extscantokey[key]; else return scantokey[key]; } /* =================================================================== MAIN WINDOW =================================================================== */ extern qboolean keydown[256]; /* ================ 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++) { if (keydown[i]) Key_Event (i, false); } Key_ClearStates (); IN_ClearStates (); } void AppActivate(BOOL fActive, BOOL minimize) /**************************************************************************** * * Function: AppActivate * Parameters: fActive - True if app is activating * * Description: If the application is activating, then swap the system * into SYSPAL_NOSTATIC mode so that our palettes will display * correctly. * ****************************************************************************/ { MSG msg; HDC hdc; int i, t; static BOOL sound_active; ActiveApp = fActive; Minimized = minimize; // enable/disable sound on focus gain/loss if (!ActiveApp && sound_active) { S_BlockSound (); sound_active = false; } else if (ActiveApp && !sound_active) { S_UnblockSound (); sound_active = true; } if (fActive) { if (modestate == MS_FULLDIB) { IN_ActivateMouse (); IN_HideMouse (); if (vid_canalttab && vid_wassuspended) { vid_wassuspended = false; ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); ShowWindow(mainwindow, SW_SHOWNORMAL); } } else if ((modestate == MS_WINDOWED) && in_grab->value && key_dest == key_game) { IN_ActivateMouse (); IN_HideMouse (); } } if (!fActive) { if (modestate == MS_FULLDIB) { IN_DeactivateMouse (); IN_ShowMouse (); if (vid_canalttab) { ChangeDisplaySettings (NULL, 0); vid_wassuspended = true; } } else if ((modestate == MS_WINDOWED) && in_grab->value) { IN_DeactivateMouse (); IN_ShowMouse (); } } } /* main window procedure */ LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LONG lRet = 1; int fwKeys, xPos, yPos, fActive, fMinimized, temp; extern unsigned int uiWheelMessage; if ( uMsg == uiWheelMessage ) uMsg = WM_MOUSEWHEEL; switch (uMsg) { case WM_KILLFOCUS: if (modestate == MS_FULLDIB) ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); break; case WM_CREATE: break; case WM_MOVE: window_x = (int) LOWORD(lParam); window_y = (int) HIWORD(lParam); VID_UpdateWindowStatus (); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: Key_Event (MapKey(lParam), true); break; case WM_KEYUP: case WM_SYSKEYUP: Key_Event (MapKey(lParam), false); break; case WM_SYSCHAR: // keep Alt-Space from happening break; // this is complicated because Win32 seems to pack multiple mouse events into // one update sometimes, so we always check all states and look for events case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: case WM_RBUTTONUP: case WM_MBUTTONDOWN: case WM_MBUTTONUP: case WM_MOUSEMOVE: temp = 0; if (wParam & MK_LBUTTON) temp |= 1; if (wParam & MK_RBUTTON) temp |= 2; if (wParam & MK_MBUTTON) temp |= 4; IN_MouseEvent (temp); break; // JACK: This is the mouse wheel with the Intellimouse // Its delta is either positive or neg, and we generate the proper // Event. case WM_MOUSEWHEEL: if ((short) HIWORD(wParam) > 0) { Key_Event(K_MWHEELUP, true); Key_Event(K_MWHEELUP, false); } else { Key_Event(K_MWHEELDOWN, true); Key_Event(K_MWHEELDOWN, false); } break; case WM_SIZE: break; case WM_CLOSE: if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) { Sys_Quit (); } break; case WM_ACTIVATE: fActive = LOWORD(wParam); fMinimized = (BOOL) HIWORD(wParam); AppActivate(!(fActive == WA_INACTIVE), fMinimized); // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); break; case WM_DESTROY: { if (dibwindow) DestroyWindow (dibwindow); PostQuitMessage (0); } break; case MM_MCINOTIFY: lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); break; default: /* pass all unhandled messages to DefWindowProc */ lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); break; } /* return 1 if handled message, 0 if not */ return lRet; } /* ================= VID_NumModes ================= */ int VID_NumModes (void) { return nummodes; } /* ================= VID_GetModePtr ================= */ vmode_t *VID_GetModePtr (int modenum) { if ((modenum >= 0) && (modenum < nummodes)) return &modelist[modenum]; else return &badmode; } /* ================= VID_GetModeDescription ================= */ char *VID_GetModeDescription (int mode) { char *pinfo; vmode_t *pv; static char temp[100]; if ((mode < 0) || (mode >= nummodes)) return NULL; if (!leavecurrentmode) { pv = VID_GetModePtr (mode); pinfo = pv->modedesc; } else { snprintf(temp, sizeof(temp), "Desktop resolution (%dx%d)", modelist[MODE_FULLSCREEN_DEFAULT].width, modelist[MODE_FULLSCREEN_DEFAULT].height); pinfo = temp; } return pinfo; } // KJB: Added this to return the mode driver name in description for console char *VID_GetExtModeDescription (int mode) { static char pinfo[40]; vmode_t *pv; if ((mode < 0) || (mode >= nummodes)) return NULL; pv = VID_GetModePtr (mode); if (modelist[mode].type == MS_FULLDIB) { if (!leavecurrentmode) { snprintf(pinfo, sizeof(pinfo),"%s fullscreen", pv->modedesc); } else { snprintf(pinfo, sizeof(pinfo), "Desktop resolution (%dx%d)", modelist[MODE_FULLSCREEN_DEFAULT].width, modelist[MODE_FULLSCREEN_DEFAULT].height); } } else { if (modestate == MS_WINDOWED) snprintf(pinfo, sizeof(pinfo), "%s windowed", pv->modedesc); else snprintf(pinfo, sizeof(pinfo), "windowed"); } return pinfo; } /* ================= VID_DescribeCurrentMode_f ================= */ void VID_DescribeCurrentMode_f (void) { Con_Printf ("%s\n", VID_GetExtModeDescription (vid_modenum)); } /* ================= VID_NumModes_f ================= */ void VID_NumModes_f (void) { if (nummodes == 1) Con_Printf ("%d video mode is available\n", nummodes); else Con_Printf ("%d video modes are available\n", nummodes); } /* ================= VID_DescribeMode_f ================= */ void VID_DescribeMode_f (void) { int t, modenum; modenum = Q_atoi (Cmd_Argv(1)); t = leavecurrentmode; leavecurrentmode = 0; Con_Printf ("%s\n", VID_GetExtModeDescription (modenum)); leavecurrentmode = t; } /* ================= VID_DescribeModes_f ================= */ void VID_DescribeModes_f (void) { int i, lnummodes, t; char *pinfo; vmode_t *pv; lnummodes = VID_NumModes (); t = leavecurrentmode; leavecurrentmode = 0; for (i=1 ; i8 bpp modes originalnummodes = nummodes; modenum = 0; do { stat = EnumDisplaySettings (NULL, modenum, &devmode); if ((devmode.dmBitsPerPel >= 15) && (devmode.dmPelsWidth <= MAXWIDTH) && (devmode.dmPelsHeight <= MAXHEIGHT) && (nummodes < MAX_MODE_LIST)) { devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; if (ChangeDisplaySettings (&devmode, CDS_TEST | CDS_FULLSCREEN) == DISP_CHANGE_SUCCESSFUL) { modelist[nummodes].type = MS_FULLDIB; modelist[nummodes].width = devmode.dmPelsWidth; modelist[nummodes].height = devmode.dmPelsHeight; modelist[nummodes].modenum = 0; modelist[nummodes].halfscreen = 0; modelist[nummodes].dib = 1; modelist[nummodes].fullscreen = 1; modelist[nummodes].bpp = devmode.dmBitsPerPel; snprintf(modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel); // if the width is more than twice the height, reduce it by half because this // is probably a dual-screen monitor if (!COM_CheckParm("-noadjustaspect")) { if (modelist[nummodes].width > (modelist[nummodes].height << 1)) { modelist[nummodes].width >>= 1; modelist[nummodes].halfscreen = 1; snprintf(modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%dx%d", modelist[nummodes].width, modelist[nummodes].height, modelist[nummodes].bpp); } } for (i=originalnummodes, existingmode = 0 ; i 255) inf = 255; palette[i] = inf; } memcpy (pal, palette, sizeof(palette)); } /* =================== VID_Init =================== */ void VID_Init (unsigned char *palette) { int i, existingmode; int basenummodes, width, height, bpp, findbpp, done; byte *ptmp; char gldir[MAX_OSPATH]; HDC hdc; DEVMODE devmode; plugin_load("input"); IN->Init(); memset(&devmode, 0, sizeof(devmode)); vid_mode = Cvar_Get ("vid_mode","0",0,"None"); vid_wait = Cvar_Get ("vid_wait","0",0,"None"); vid_nopageflip = Cvar_Get ("_vid_nopageflip","0",CVAR_ARCHIVE,"None"); _vid_wait_override = Cvar_Get ("_vid_wait_override","0",CVAR_ARCHIVE, "None"); _vid_default_mode = Cvar_Get ("_vid_default_mode","0",CVAR_ARCHIVE, "None"); _vid_default_mode_win = Cvar_Get ("_vid_default_mode_win","0", CVAR_ARCHIVE,"None"); vid_config_x = Cvar_Get ("vid_config_x","800",CVAR_ARCHIVE,"None"); vid_config_y = Cvar_Get ("vid_config_y","600",CVAR_ARCHIVE,"None"); vid_stretch_by_2 = Cvar_Get ("vid_stretch_by_2","1",CVAR_ARCHIVE, "None"); in_grab = Cvar_Get ("in_grab","1",CVAR_ARCHIVE,"None"); gl_ztrick = Cvar_Get ("gl_ztrick","1",CVAR_ARCHIVE,"None"); 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); hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2)); InitCommonControls(); VID_InitDIB (global_hInstance); basenummodes = nummodes = 1; VID_InitFullDIB (global_hInstance); if (COM_CheckParm("-window")) { hdc = GetDC (NULL); if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) { Sys_Error ("Can't run in non-RGB mode"); } ReleaseDC (NULL, hdc); windowed = true; vid_default = MODE_WINDOWED; } else { if (nummodes == 1) Sys_Error ("No RGB fullscreen modes available"); windowed = false; if (COM_CheckParm("-mode")) { vid_default = Q_atoi(com_argv[COM_CheckParm("-mode")+1]); } else { if (COM_CheckParm("-current")) { modelist[MODE_FULLSCREEN_DEFAULT].width = GetSystemMetrics (SM_CXSCREEN); modelist[MODE_FULLSCREEN_DEFAULT].height = GetSystemMetrics (SM_CYSCREEN); vid_default = MODE_FULLSCREEN_DEFAULT; leavecurrentmode = 1; } else { if (COM_CheckParm("-width")) { width = Q_atoi(com_argv[COM_CheckParm("-width")+1]); } else { width = 640; } if (COM_CheckParm("-bpp")) { bpp = Q_atoi(com_argv[COM_CheckParm("-bpp")+1]); findbpp = 0; } else { bpp = 15; findbpp = 1; } if (COM_CheckParm("-height")) height = Q_atoi(com_argv[COM_CheckParm("-height")+1]); // if they want to force it, add the specified mode to the list if (COM_CheckParm("-force") && (nummodes < MAX_MODE_LIST)) { modelist[nummodes].type = MS_FULLDIB; modelist[nummodes].width = width; modelist[nummodes].height = height; modelist[nummodes].modenum = 0; modelist[nummodes].halfscreen = 0; modelist[nummodes].dib = 1; modelist[nummodes].fullscreen = 1; modelist[nummodes].bpp = bpp; snprintf(modelist[nummodes].modedesc, sizeof(modelist[nummodes].modedesc), "%dx%dx%d", devmode.dmPelsWidth, devmode.dmPelsHeight, devmode.dmBitsPerPel); for (i=nummodes, existingmode = 0 ; iwidth)/2,4,p); vid_wmodes = 0; lnummodes = VID_NumModes (); for (i=1 ; (i 0) { M_Print (2*8, 36+0*8, "Fullscreen Modes (WIDTHxHEIGHTxBPP)"); column = 8; row = 36+2*8; for (i=0 ; i"); M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*4, "and -bpp "); M_Print (3*8, 36 + MODE_AREA_HEIGHT * 8 + 8*6, "Select windowed mode with -window"); } /* VID_MenuKey Process menu keystrokes */ void VID_MenuKey ( int key ) { switch (key) { case K_ESCAPE: S_LocalSound ("misc/menu1.wav"); M_Menu_Options_f (); break; default: break; } } void VID_ExtraOptionDraw ( unsigned int options_draw_cursor ) { // Windowed Mouse M_Print (16, options_draw_cursor+=8, " Use Mouse"); M_DrawCheckbox (220, options_draw_cursor, in_grab->value); } void VID_ExtraOptionCmd ( int option_cursor ) { switch(option_cursor) { case 1: // in_grab in_grab->value = !in_grab->value; break; } } void VID_InitCvars( void ) { // It may not look it, but this is important } void VID_LockBuffer ( void ) { // Empty function, locking not necessary here. } void VID_UnlockBuffer ( void ) { // Empty function, locking not necessary here. }