/* 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. */ // gl_vidnt.c -- NT GL vid component #include "quakedef.h" #ifdef RGLQUAKE #include "glquake.h" #include "winquake.h" #include "resource.h" #include #ifndef CDS_FULLSCREEN #define CDS_FULLSCREEN 4 #endif #ifndef WM_XBUTTONDOWN #define WM_XBUTTONDOWN 0x020B #define WM_XBUTTONUP 0x020C #endif #ifndef MK_XBUTTON1 #define MK_XBUTTON1 0x0020 #define MK_XBUTTON2 0x0040 // copied from DarkPlaces in an attempt to grab more buttons #define MK_XBUTTON3 0x0080 #define MK_XBUTTON4 0x0100 #define MK_XBUTTON5 0x0200 #define MK_XBUTTON6 0x0400 #define MK_XBUTTON7 0x0800 #endif #ifndef WM_INPUT #define WM_INPUT 255 #endif extern cvar_t vid_conwidth; #define WINDOW_CLASS_NAME "WinQuake" #define MAX_MODE_LIST 128 #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 typedef enum {MS_WINDOWED, MS_FULLSCREEN, MS_FULLDIB, MS_UNINIT} modestate_t; #ifdef USE_D3D void D3DInitialize(void); void d3dSetMode(int fullscreen, int width, int height, int bpp, int zbpp); #endif BOOL bSetupPixelFormat(HDC hDC); //qboolean VID_SetWindowedMode (int modenum); //qboolean VID_SetFullDIBMode (int modenum); qboolean VID_SetWindowedMode (rendererstate_t *info); //-1 on bpp or hz for default. qboolean VID_SetFullDIBMode (rendererstate_t *info); //-1 on bpp or hz for default. qboolean DDActive; qboolean scr_skipupdate; static DEVMODE gdevmode; static qboolean vid_initialized = false; static qboolean leavecurrentmode= true; static qboolean vid_canalttab = false; static qboolean vid_wassuspended = false; static int windowed_mouse; extern qboolean mouseactive; // from in_win.c static HICON hIcon; extern qboolean vid_isfullscreen; unsigned short originalgammaramps[3][256]; #ifdef SWQUAKE extern #endif qboolean vid_initializing; qboolean VID_AttachGL (rendererstate_t *info); int DIBWidth, DIBHeight; RECT WindowRect; DWORD WindowStyle, ExWindowStyle; HWND mainwindow, dibwindow; unsigned char vid_curpal[256*3]; float vid_gamma = 1.0; HGLRC baseRC; HDC maindc; glvert_t glv; HWND WINAPI InitializeWindow (HINSTANCE hInstance, int nCmdShow); viddef_t vid; // global video state //unsigned short d_8to16rgbtable[256]; //unsigned d_8to24rgbtable[256]; //unsigned short d_8to16bgrtable[256]; //unsigned d_8to24bgrtable[256]; modestate_t modestate = MS_UNINIT; LONG WINAPI GLMainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void GLAppActivate(BOOL fActive, BOOL minimize); char *VID_GetModeDescription (int mode); void ClearAllStates (void); void VID_UpdateWindowStatus (void); void GL_Init(void *(*getglfunction) (char *name)); typedef void (APIENTRY *lp3DFXFUNC) (int, int, int, int, int, const void*); lp3DFXFUNC qglColorTableEXT; qboolean is8bit = false; qboolean isPermedia = false; //==================================== // Note that 0 is MODE_WINDOWED extern cvar_t vid_mode; extern cvar_t _vid_default_mode; // Note that 3 is MODE_FULLSCREEN_DEFAULT extern cvar_t _vid_default_mode_win; extern cvar_t vid_wait; extern cvar_t vid_nopageflip; extern cvar_t _vid_wait_override; extern cvar_t vid_stretch_by_2; extern cvar_t _windowed_mouse; extern cvar_t vid_hardwaregamma; extern cvar_t gl_lateswap; int window_center_x, window_center_y, window_x, window_y, window_width, window_height; RECT window_rect; HMODULE hInstGL = NULL; HMODULE hInstwgl = NULL; char opengldllname[MAX_OSPATH]; //just GetProcAddress with a safty net. void *getglfunc(char *name) { FARPROC proc; proc = qwglGetProcAddress?qwglGetProcAddress(name):NULL; if (!proc) { proc = GetProcAddress(hInstGL, name); TRACE(("dbg: getglfunc: gpa %s: success %i\n", name, !!proc)); return proc; } TRACE(("dbg: getglfunc: glgpa %s: success %i\n", name, !!proc)); return proc; } void *getwglfunc(char *name) { FARPROC proc; TRACE(("dbg: getwglfunc: %s: getting\n", name)); proc = GetProcAddress(hInstGL, name); if (!proc) { if (!hInstwgl) { TRACE(("dbg: getwglfunc: explicitly loading opengl32.dll\n", name)); hInstwgl = LoadLibrary("opengl32.dll"); } TRACE(("dbg: getwglfunc: %s: wglgetting\n", name)); proc = GetProcAddress(hInstwgl, name); TRACE(("dbg: getwglfunc: gpa %s: success %i\n", name, !!proc)); if (!proc) Sys_Error("GL function %s was not found in %s\nPossibly you do not have a full enough gl implementation", name, opengldllname); } TRACE(("dbg: getwglfunc: glgpa %s: success %i\n", name, !!proc)); return proc; } HGLRC (WINAPI *qwglCreateContext)(HDC); BOOL (WINAPI *qwglDeleteContext)(HGLRC); HGLRC (WINAPI *qwglGetCurrentContext)(VOID); HDC (WINAPI *qwglGetCurrentDC)(VOID); PROC (WINAPI *qwglGetProcAddress)(LPCSTR); BOOL (WINAPI *qwglMakeCurrent)(HDC, HGLRC); BOOL (WINAPI *qSwapBuffers)(HDC); BOOL (WINAPI *qwglSwapIntervalEXT) (int); qboolean GLInitialise (char *renderer) { if (hInstGL) FreeModule(hInstGL); if (hInstwgl) FreeModule(hInstwgl); hInstwgl=NULL; strcpy(opengldllname, renderer); if (*renderer) { Con_DPrintf ("Loading renderer dll \"%s\"", renderer); hInstGL = LoadLibrary(opengldllname); if (hInstGL) Con_DPrintf (" Success\n"); else Con_DPrintf (" Failed\n"); } else hInstGL = NULL; if (!hInstGL) { strcpy(opengldllname, "opengl32"); Con_DPrintf ("Loading renderer dll \"%s\"", opengldllname); hInstGL = LoadLibrary(opengldllname); if (hInstGL) Con_DPrintf (" Success\n"); else Con_DPrintf (" Failed\n"); } if (!hInstGL) { if (*renderer) Con_Printf ("Couldn't load %s or %s\n", renderer, opengldllname); else Con_Printf ("Couldn't load %s\n", opengldllname); return false; } Con_DPrintf ("Loaded renderer dll %s\n", opengldllname); // windows dependant qwglCreateContext = (void *)getwglfunc("wglCreateContext"); qwglDeleteContext = (void *)getwglfunc("wglDeleteContext"); qwglGetCurrentContext = (void *)getwglfunc("wglGetCurrentContext"); qwglGetCurrentDC = (void *)getwglfunc("wglGetCurrentDC"); qwglGetProcAddress = (void *)getwglfunc("wglGetProcAddress"); qwglMakeCurrent = (void *)getwglfunc("wglMakeCurrent"); qSwapBuffers = SwapBuffers; TRACE(("dbg: GLInitialise: got wgl funcs\n")); return true; } // direct draw software compatability stuff void GLVID_HandlePause (qboolean pause) { } void GLVID_ForceLockState (int lk) { } void GLVID_LockBuffer (void) { } void GLVID_UnlockBuffer (void) { } int GLVID_ForceUnlockedAndReturnState (void) { return 0; } void GLD_BeginDirectRect (int x, int y, qbyte *pbitmap, int width, int height) { } void GLD_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 (rendererstate_t *info) //qboolean VID_SetWindowedMode (int modenum) { int i; HDC hdc; int lastmodestate, wwidth, wheight; RECT rect; hdc = GetDC(NULL); if (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) { ReleaseDC(NULL, hdc); Con_Printf("Can't run GL in non-RGB mode\n"); return false; } ReleaseDC(NULL, hdc); lastmodestate = modestate; WindowRect.top = WindowRect.left = 0; WindowRect.right = info->width; WindowRect.bottom = info->height; DIBWidth = info->width; DIBHeight = info->height; WindowStyle = WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX; ExWindowStyle = 0; WindowStyle |= WS_SIZEBOX | WS_MAXIMIZEBOX; rect = WindowRect; AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); wwidth = rect.right - rect.left; wheight = rect.bottom - rect.top; // Create the DIB window dibwindow = CreateWindowEx ( ExWindowStyle, WINDOW_CLASS_NAME, "FTE QuakeWorld", WindowStyle, rect.left, rect.top, wwidth, wheight, NULL, NULL, global_hInstance, NULL); if (!dibwindow) { Con_Printf ("Couldn't create DIB window"); return false; } // 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 ((i = COM_CheckParm("-conwidth")) != 0) vid.conwidth = Q_atoi(com_argv[i+1]); else { vid.conwidth = 640; vid_conwidth.modified = true; //make it reapplied } vid.conwidth &= 0xfff8; // make it a multiple of eight if (vid.conwidth < 320) vid.conwidth = 320; // pick a conheight that matches with correct aspect vid.conheight = vid.conwidth*3 / 4; if ((i = COM_CheckParm("-conheight")) != 0) vid.conheight = Q_atoi(com_argv[i+1]); if (vid.conheight < 200) vid.conheight = 200; if (vid.conheight > info->height) vid.conheight = info->height; if (vid.conwidth > info->width) vid.conwidth = info->width; vid.width = vid.conwidth; vid.height = vid.conheight; vid.numpages = 2; mainwindow = dibwindow; vid_isfullscreen=false; SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); return true; } qboolean VID_SetFullDIBMode (rendererstate_t *info) { int i; HDC hdc; int lastmodestate, wwidth, wheight; RECT rect; if (leavecurrentmode && Q_strcasecmp(info->glrenderer, "D3D")) //don't do this with d3d - d3d should set it's own video mode. { //make windows change res. gdevmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if (info->bpp) gdevmode.dmFields |= DM_BITSPERPEL; if (info->rate) gdevmode.dmFields |= DM_DISPLAYFREQUENCY; gdevmode.dmBitsPerPel = info->bpp; gdevmode.dmDisplayFrequency = info->rate; gdevmode.dmPelsWidth = info->width; gdevmode.dmPelsHeight = info->height; gdevmode.dmSize = sizeof (gdevmode); if (ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL) { Con_SafePrintf((gdevmode.dmFields&DM_DISPLAYFREQUENCY)?"Windows rejected mode %i*%i*%i*%i\n":"Windows rejected mode %i*%i*%i\n", gdevmode.dmPelsWidth, gdevmode.dmPelsHeight, gdevmode.dmBitsPerPel, gdevmode.dmDisplayFrequency); return false; } } lastmodestate = modestate; modestate = MS_FULLDIB; WindowRect.top = WindowRect.left = 0; WindowRect.right = info->width; WindowRect.bottom = info->height; DIBWidth = info->width; DIBHeight = info->height; WindowStyle = WS_POPUP; ExWindowStyle = 0; rect = WindowRect; AdjustWindowRectEx(&rect, WindowStyle, FALSE, 0); wwidth = rect.right - rect.left; wheight = rect.bottom - rect.top; // Create the DIB window dibwindow = CreateWindowEx ( ExWindowStyle, WINDOW_CLASS_NAME, "FTE QuakeWorld", WindowStyle, rect.left, rect.top, wwidth, wheight, 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 ((i = COM_CheckParm("-conwidth")) != 0) vid.conwidth = Q_atoi(com_argv[i+1]); else vid.conwidth = 640; vid.conwidth &= 0xfff8; // make it a multiple of eight if (vid.conwidth < 320) vid.conwidth = 320; // pick a conheight that matches with correct aspect vid.conheight = vid.conwidth*3 / 4; if ((i = COM_CheckParm("-conheight")) != 0) vid.conheight = Q_atoi(com_argv[i+1]); if (vid.conheight < 200) vid.conheight = 200; if (vid.conheight > info->height) vid.conheight = info->height; if (vid.conwidth > info->width) vid.conwidth = info->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; vid_isfullscreen=true; mainwindow = dibwindow; SendMessage (mainwindow, WM_SETICON, (WPARAM)TRUE, (LPARAM)hIcon); SendMessage (mainwindow, WM_SETICON, (WPARAM)FALSE, (LPARAM)hIcon); return true; } int GLVID_SetMode (rendererstate_t *info, unsigned char *palette) { int temp; qboolean stat; MSG msg; // HDC hdc; TRACE(("dbg: GLVID_SetMode\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 (); // Set either the fullscreen or windowed mode if (!info->fullscreen) { if (_windowed_mouse.value && (key_dest == key_game || key_dest == key_menu)) { TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode\n")); stat = VID_SetWindowedMode(info); IN_ActivateMouse (); IN_HideMouse (); } else { IN_DeactivateMouse (); IN_ShowMouse (); TRACE(("dbg: GLVID_SetMode: VID_SetWindowedMode 2\n")); stat = VID_SetWindowedMode(info); } } else { TRACE(("dbg: GLVID_SetMode: VID_SetFullDIBMode\n")); stat = VID_SetFullDIBMode(info); IN_ActivateMouse (); IN_HideMouse (); } if (!stat) { TRACE(("dbg: GLVID_SetMode: VID_Set... failed\n")); return false; } window_width = DIBWidth; window_height = DIBHeight; VID_UpdateWindowStatus (); CDAudio_Resume (); scr_disabled_for_loading = temp; // 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); 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 (); GLVID_SetPalette (palette); vid.recalc_refdef = 1; maindc = GetDC(mainwindow); GetDeviceGammaRamp(maindc, originalgammaramps); TRACE(("dbg: GLVID_SetMode: attaching gl\n")); if (!VID_AttachGL(info)) { TRACE(("dbg: GLVID_SetMode: attaching gl failed\n")); return false; } TRACE(("dbg: GLVID_SetMode: attaching gl okay\n")); return true; } void VID_UnSetMode (void) { HGLRC hRC; HDC hDC = NULL; if (mainwindow && vid_initialized) { GLAppActivate(false, false); vid_canalttab = false; if (qwglGetCurrentContext) { hRC = qwglGetCurrentContext(); hDC = qwglGetCurrentDC(); qwglMakeCurrent(NULL, NULL); if (hRC) qwglDeleteContext(hRC); } qwglGetCurrentContext=NULL; if (hDC && dibwindow) ReleaseDC(dibwindow, hDC); if (modestate == MS_FULLDIB) ChangeDisplaySettings (NULL, 0); if (maindc && dibwindow) ReleaseDC (dibwindow, maindc); } if (mainwindow) { dibwindow=NULL; // SendMessage(mainwindow, WM_CLOSE, 0, 0); DestroyWindow(mainwindow); mainwindow = NULL; } if (hInstGL) { FreeLibrary(hInstGL); hInstGL = NULL; } } /* ================ 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 (); } //==================================== qboolean VID_AttachGL (rendererstate_t *info) { //make sure we can get a valid renderer. do { #ifdef USE_D3D if (!Q_strcasecmp(info->glrenderer, "D3D")) { extern cvar_t gl_ztrick; int zbpp = info->bpp > 16 ? 24 : 16; gl_canstencil = false; TRACE(("dbg: VID_AttachGL: D3DInitialize\n")); D3DInitialize(); //replacement of GLInitialise, to get the function pointers set up. if (COM_CheckParm("-zbpp")) { zbpp = Q_atoi(com_argv[COM_CheckParm("-zbpp")+1]); } TRACE(("dbg: VID_AttachGL: d3dSetMode\n")); d3dSetMode(info->fullscreen, info->width, info->height, info->bpp, zbpp); //d3d cheats to get it's dimensions and stuff... One that we can currently live with though. gl_ztrickdisabled |= 2; //ztrick does funny things. Cvar_Set(&gl_ztrick, "0"); maindc = GetDC(mainwindow); Con_Printf(S_COLOR_GREEN"OpenGL to Direct3D wrapper enabled\n"); //green to make it show. break; } #endif gl_ztrickdisabled &= ~2; TRACE(("dbg: VID_AttachGL: GLInitialise\n")); if (GLInitialise(info->glrenderer)) { maindc = GetDC(mainwindow); TRACE(("dbg: VID_AttachGL: bSetupPixelFormat\n")); bSetupPixelFormat(maindc); break; } if (!*info->glrenderer || !stricmp(info->glrenderer, "opengl32.dll") || !stricmp(info->glrenderer, "opengl32")) //go for windows system dir if we failed with the default. Should help to avoid the 3dfx problem. { char systemgl[MAX_OSPATH+1]; GetSystemDirectory(systemgl, sizeof(systemgl)-1); strncat(systemgl, "\\", sizeof(systemgl)-1); if (*info->glrenderer) strncat(systemgl, info->glrenderer, sizeof(systemgl)-1); else strncat(systemgl, "opengl32.dll", sizeof(systemgl)-1); TRACE(("dbg: VID_AttachGL: GLInitialise (system dir specific)\n")); if (GLInitialise(systemgl)) { maindc = GetDC(mainwindow); TRACE(("dbg: VID_AttachGL: bSetupPixelFormat\n")); bSetupPixelFormat(maindc); break; } } TRACE(("dbg: VID_AttachGL: failed to find a valid dll\n")); return false; } while(1); TRACE(("dbg: VID_AttachGL: qwglCreateContext\n")); baseRC = qwglCreateContext( maindc ); if (!baseRC) { Con_SafePrintf(S_COLOR_RED"Could not initialize GL (wglCreateContext failed).\n\nMake sure you in are 65535 color mode, and try running -window.\n"); //green to make it show. return false; } TRACE(("dbg: VID_AttachGL: qwglMakeCurrent\n")); if (!qwglMakeCurrent( maindc, baseRC )) { Con_SafePrintf(S_COLOR_RED"wglMakeCurrent failed\n"); //green to make it show. return false; } TRACE(("dbg: VID_AttachGL: GL_Init\n")); GL_Init(getglfunc); qwglSwapIntervalEXT = getglfunc("wglSwapIntervalEXT"); if (qwglSwapIntervalEXT && _vid_wait_override.value>=0) { TRACE(("dbg: VID_AttachGL: qwglSwapIntervalEXT\n")); qwglSwapIntervalEXT(_vid_wait_override.value); } _vid_wait_override.modified = false; TRACE(("dbg: VID_AttachGL: qSwapBuffers\n")); qglClearColor(0, 0, 0, 0); qglClear(GL_COLOR_BUFFER_BIT); qSwapBuffers(maindc); return true; } /* ================= GL_BeginRendering ================= */ void GL_BeginRendering (int *x, int *y, int *width, int *height) { *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); } qboolean screenflush; void GL_DoSwap (void) { extern int mouseusedforgui; if (!screenflush) return; screenflush = 0; if (!scr_skipupdate || block_drawing) qSwapBuffers(maindc); if (_vid_wait_override.modified && qwglSwapIntervalEXT && _vid_wait_override.value>=0) { qwglSwapIntervalEXT(_vid_wait_override.value); _vid_wait_override.modified = false; } // handle the mouse state when windowed if that's changed if (modestate == MS_WINDOWED) { if (!_windowed_mouse.value) { if (windowed_mouse) { IN_DeactivateMouse (); IN_ShowMouse (); windowed_mouse = false; } } else { windowed_mouse = true; if ((key_dest == key_game||mouseusedforgui) && !mouseactive && ActiveApp) { IN_ActivateMouse (); IN_HideMouse (); } else if (mouseactive && !(key_dest == key_game || mouseusedforgui)) { IN_DeactivateMouse (); IN_ShowMouse (); } } } } void GL_EndRendering (void) { screenflush = true; if (!gl_lateswap.value) GL_DoSwap(); } void GLVID_SetPalette (unsigned char *palette) { qbyte *pal; unsigned r,g,b; unsigned v; unsigned short i; unsigned *table; extern qbyte gammatable[256]; // // 8 8 8 encoding // if (vid_hardwaregamma.value) { // don't built in the gamma table pal = palette; table = d_8to24rgbtable; 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_8to24rgbtable[255] &= 0xffffff; // 255 is transparent } else { //computer has no hardware gamma (poor suckers) increase table accordingly pal = palette; table = d_8to24rgbtable; for (i=0 ; i<256 ; i++) { r = gammatable[pal[0]]; g = gammatable[pal[1]]; b = gammatable[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_8to24rgbtable[255] &= 0xffffff; // 255 is transparent } } extern gammaworks; void GLVID_ShiftPalette (unsigned char *palette) { extern unsigned short ramps[3][256]; // VID_SetPalette (palette); if (ActiveApp && vid_hardwaregamma.value) //this is needed because ATI drivers don't work properly (or when task-switched out). { if (gammaworks) { //we have hardware gamma applied - if we're doing a BF, we don't want to reset to the default gamma (yuck) SetDeviceGammaRamp (maindc, ramps); return; } gammaworks = !!SetDeviceGammaRamp (maindc, ramps); } else gammaworks = false; } void VID_SetDefaultMode (void) { IN_DeactivateMouse (); } void GLVID_Shutdown (void) { SetDeviceGammaRamp(maindc, originalgammaramps); gammaworks = false; VID_UnSetMode(); } //========================================================================== BOOL bSetupPixelFormat(HDC hDC) { static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number PFD_DRAW_TO_WINDOW // support window | PFD_SUPPORT_OPENGL // support OpenGL | PFD_DOUBLEBUFFER , // double buffered PFD_TYPE_RGBA, // RGBA type 24, // 24-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 0, // no alpha buffer 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 32, // 32-bit z-buffer 8, // stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; int pixelformat; TRACE(("dbg: bSetupPixelFormat: ChoosePixelFormat\n")); if ((pixelformat = ChoosePixelFormat(hDC, &pfd))) { TRACE(("dbg: ChoosePixelFormat 1: worked\n")); if (SetPixelFormat(hDC, pixelformat, &pfd)) { TRACE(("dbg: bSetupPixelFormat: we can use the stencil buffer. woot\n")); gl_canstencil = pfd.cStencilBits; return TRUE; } } TRACE(("dbg: ChoosePixelFormat 1: no stencil buffer for us\n")); pfd.cStencilBits = 0; gl_canstencil = false; if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) { Con_Printf("bSetupPixelFormat: ChoosePixelFormat failed\n"); return FALSE; } if (SetPixelFormat(hDC, pixelformat, &pfd) == FALSE) { Con_Printf("bSetupPixelFormat: SetPixelFormat failed\n"); return FALSE; } return TRUE; } /* =================================================================== MAIN WINDOW =================================================================== */ /* ================ 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 (); } void GLAppActivate(BOOL fActive, BOOL minimize) /**************************************************************************** * * Function: AppActivate * Parameters: fActive - True if app is activating * * Description: If the application is activating, then swap the system * into SYSPAL_NOSTATIC mode so that our palettes will display * correctly. * ****************************************************************************/ { static BOOL sound_active; ActiveApp = fActive; Minimized = minimize; // enable/disable sound on focus gain/loss if (!ActiveApp && sound_active) { S_BlockSound (); sound_active = false; } else if (ActiveApp && !sound_active) { S_UnblockSound (); sound_active = true; } if (fActive) { if (modestate == MS_FULLDIB) { IN_ActivateMouse (); IN_HideMouse (); if (vid_canalttab && vid_wassuspended) { vid_wassuspended = false; ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); ShowWindow(mainwindow, SW_SHOWNORMAL); // Fix for alt-tab bug in NVidia drivers MoveWindow (mainwindow, 0, 0, gdevmode.dmPelsWidth, gdevmode.dmPelsHeight, false); } } else if ((modestate == MS_WINDOWED) && _windowed_mouse.value && (key_dest == key_game || key_dest == key_menu)) { IN_ActivateMouse (); IN_HideMouse (); } v_gamma.modified = true; //so that we can start doing palette flashes and things } if (!fActive) { if (modestate == MS_FULLDIB) { IN_DeactivateMouse (); IN_ShowMouse (); if (vid_canalttab) { ChangeDisplaySettings (NULL, 0); vid_wassuspended = true; } } else if ((modestate == MS_WINDOWED) && _windowed_mouse.value) { IN_DeactivateMouse (); IN_ShowMouse (); } v_gamma.modified = true; //wham bam thanks. SetDeviceGammaRamp(maindc, originalgammaramps); gammaworks = false; } } /* main window procedure */ LONG WINAPI GLMainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LONG lRet = 1; int fActive, fMinimized, temp; extern unsigned int uiWheelMessage; if ( uMsg == uiWheelMessage ) uMsg = WM_MOUSEWHEEL; switch (uMsg) { case WM_KILLFOCUS: if (modestate == MS_FULLDIB) ShowWindow(mainwindow, SW_SHOWMINNOACTIVE); break; case WM_CREATE: break; case WM_MOVE: window_x = (int) LOWORD(lParam); window_y = (int) HIWORD(lParam); VID_UpdateWindowStatus (); break; case WM_KEYDOWN: case WM_SYSKEYDOWN: if (!vid_initializing) Key_Event (MapKey(lParam), true); break; case WM_KEYUP: case WM_SYSKEYUP: if (!vid_initializing) 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: case WM_XBUTTONDOWN: case WM_XBUTTONUP: temp = 0; if (wParam & MK_LBUTTON) temp |= 1; if (wParam & MK_RBUTTON) temp |= 2; if (wParam & MK_MBUTTON) temp |= 4; if (wParam & MK_XBUTTON1) temp |= 8; if (wParam & MK_XBUTTON2) temp |= 16; if (wParam & MK_XBUTTON3) temp |= 32; if (wParam & MK_XBUTTON4) temp |= 64; if (wParam & MK_XBUTTON5) temp |= 128; if (wParam & MK_XBUTTON6) temp |= 256; if (wParam & MK_XBUTTON7) temp |= 512; if (!vid_initializing) 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 (!vid_initializing) { 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_INPUT: // raw input handling IN_RawInput_MouseRead((HANDLE)lParam); break; case WM_SIZE: if (!vid_initializing) { WindowRect.right = ((short*)&lParam)[0] - WindowRect.left; WindowRect.bottom = ((short*)&lParam)[1] - WindowRect.top; if (modestate != MS_FULLDIB) //fullscreen doesn't have the RIGHT to respond to this. Apply to the Court of M$ if you want this changed... { vid_conwidth.modified = true; //make it reapplied } } break; case WM_CLOSE: if (!vid_initializing) 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); GLAppActivate(!(fActive == WA_INACTIVE), fMinimized); if (modestate == MS_FULLDIB) ShowWindow(mainwindow, SW_SHOWNORMAL); // fix the leftover Alt from any Alt-Tab or the like that switched us away ClearAllStates (); break; case WM_DESTROY: { if (dibwindow) DestroyWindow (dibwindow); } break; case MM_MCINOTIFY: lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam); break; case WM_MWHOOK: if (!vid_initializing) MW_Hook_Message (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; } qboolean GLVID_Is8bit() { return is8bit; } #define GL_SHARED_TEXTURE_PALETTE_EXT 0x81FB void VID_Init8bitPalette() { // Check for 8bit Extensions and initialize them. int i; char thePalette[256*3]; char *oldPalette, *newPalette; qglColorTableEXT = (void *)qwglGetProcAddress("glColorTableEXT"); if (!qglColorTableEXT || strstr(gl_extensions, "GL_EXT_shared_texture_palette") || COM_CheckParm("-no8bit")) return; Con_SafePrintf("8-bit GL extensions enabled.\n"); qglEnable( GL_SHARED_TEXTURE_PALETTE_EXT ); oldPalette = (char *) d_8to24rgbtable; //d_8to24table3dfx; newPalette = thePalette; for (i=0;i<256;i++) { *newPalette++ = *oldPalette++; *newPalette++ = *oldPalette++; *newPalette++ = *oldPalette++; oldPalette++; } qglColorTableEXT(GL_SHARED_TEXTURE_PALETTE_EXT, GL_RGB, 256, GL_RGB, GL_UNSIGNED_BYTE, (void *) thePalette); is8bit = TRUE; } static void Check_Gamma (unsigned char *pal, float usegammaval) { // float f, inf; // unsigned char palette[768]; // int i; /* if (usegammaval) vid_gamma = usegammaval; else if ((i = COM_CheckParm("-gamma")) == 0) { if ((gl_renderer && strstr(gl_renderer, "Voodoo")) || (gl_vendor && strstr(gl_vendor, "3Dfx"))) vid_gamma = 1; else vid_gamma = 0.7; // default to 0.7 on non-3dfx hardware } else vid_gamma = Q_atof(com_argv[i+1]); for (i=0 ; i<768 ; i++) { f = pow ( (pal[i]+1)/256.0 , vid_gamma ); inf = f*255 + 0.5; if (inf < 0) inf = 0; if (inf > 255) inf = 255; palette[i] = inf; } memcpy (pal, palette, sizeof(palette)); */ } void GLVID_DeInit (void) { GLVID_Shutdown(); UnregisterClass(WINDOW_CLASS_NAME, global_hInstance); } /* =================== VID_Init =================== */ qboolean GLVID_Init (rendererstate_t *info, unsigned char *palette) { // qbyte *ptmp; DEVMODE devmode; WNDCLASS wc; memset(&devmode, 0, sizeof(devmode)); /* Register the frame class */ wc.style = 0; wc.lpfnWndProc = (WNDPROC)GLMainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = global_hInstance; wc.hIcon = 0; wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = 0; wc.lpszClassName = WINDOW_CLASS_NAME; if (!RegisterClass (&wc) ) { Con_Print("^1Couldn't register window class\n"); return false; } hIcon = LoadIcon (global_hInstance, MAKEINTRESOURCE (IDI_ICON2)); vid_initialized = false; vid_initializing = true; vid.maxwarpwidth = WARP_WIDTH; vid.maxwarpheight = WARP_HEIGHT; vid.colormap = host_colormap; if (hwnd_dialog) DestroyWindow (hwnd_dialog); Check_Gamma(palette, 0); VID_SetPalette (palette); if (!GLVID_SetMode (info, palette)) { VID_UnSetMode(); return false; } // Check for 3DFX Extensions and initialize them. VID_Init8bitPalette(); vid_canalttab = true; S_Restart_f(); vid_initialized = true; vid_initializing = false; return true; } #endif