#include "quakedef.h" #ifdef SWQUAKE #include "sw.h" #include "winquake.h" /*Fixup outdated windows headers*/ #ifndef WM_XBUTTONDOWN #define WM_XBUTTONDOWN 0x020B #define WM_XBUTTONUP 0x020C #endif #ifndef MK_XBUTTON1 #define MK_XBUTTON1 0x0020 #endif #ifndef MK_XBUTTON2 #define MK_XBUTTON2 0x0040 #endif // copied from DarkPlaces in an attempt to grab more buttons #ifndef MK_XBUTTON3 #define MK_XBUTTON3 0x0080 #endif #ifndef MK_XBUTTON4 #define MK_XBUTTON4 0x0100 #endif #ifndef MK_XBUTTON5 #define MK_XBUTTON5 0x0200 #endif #ifndef MK_XBUTTON6 #define MK_XBUTTON6 0x0400 #endif #ifndef MK_XBUTTON7 #define MK_XBUTTON7 0x0800 #endif #ifndef WM_INPUT #define WM_INPUT 255 #endif typedef struct dibinfo { BITMAPINFOHEADER header; RGBQUAD acolors[256]; } dibinfo_t; //struct //{ HBITMAP hDIBSection; qbyte *pDIBBase; HDC mainhDC; HDC hdcDIBSection; HGDIOBJ previously_selected_GDI_obj; int framenumber; void *screenbuffer; qintptr_t screenpitch; int window_x, window_y; unsigned int *depthbuffer; struct { qboolean isfullscreen; } w32sw; HWND mainwindow; void DIB_Shutdown(void) { if (depthbuffer) { BZ_Free(depthbuffer); depthbuffer = NULL; } if (hdcDIBSection) { SelectObject(hdcDIBSection, previously_selected_GDI_obj); DeleteDC(hdcDIBSection); hdcDIBSection = NULL; } if (hDIBSection) { DeleteObject(hDIBSection); hDIBSection = NULL; pDIBBase = NULL; } if (mainhDC) { ReleaseDC(mainwindow, mainhDC); mainhDC = 0; } } qboolean DIB_Init(void) { dibinfo_t dibheader; BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader; int i; memset( &dibheader, 0, sizeof( dibheader ) ); /* ** grab a DC */ if ( !mainhDC ) { if ( ( mainhDC = GetDC( mainwindow ) ) == NULL ) return false; } /* ** fill in the BITMAPINFO struct */ pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); pbmiDIB->bmiHeader.biWidth = vid.pixelwidth; pbmiDIB->bmiHeader.biHeight = vid.pixelheight; pbmiDIB->bmiHeader.biPlanes = 1; pbmiDIB->bmiHeader.biBitCount = 32; pbmiDIB->bmiHeader.biCompression = BI_RGB; pbmiDIB->bmiHeader.biSizeImage = 0; pbmiDIB->bmiHeader.biXPelsPerMeter = 0; pbmiDIB->bmiHeader.biYPelsPerMeter = 0; pbmiDIB->bmiHeader.biClrUsed = 0; pbmiDIB->bmiHeader.biClrImportant = 0; /* ** fill in the palette */ for ( i = 0; i < 256; i++ ) { dibheader.acolors[i].rgbRed = ( d_8to24rgbtable[i] >> 0 ) & 0xff; dibheader.acolors[i].rgbGreen = ( d_8to24rgbtable[i] >> 8 ) & 0xff; dibheader.acolors[i].rgbBlue = ( d_8to24rgbtable[i] >> 16 ) & 0xff; } /* ** create the DIB section */ hDIBSection = CreateDIBSection( mainhDC, pbmiDIB, DIB_RGB_COLORS, (void**)&pDIBBase, NULL, 0 ); if ( hDIBSection == NULL ) { Con_Printf( "DIB_Init() - CreateDIBSection failed\n" ); goto fail; } if (pbmiDIB->bmiHeader.biHeight < 0) { // bottom up screenbuffer = pDIBBase + ( vid.pixelheight - 1 ) * vid.pixelwidth * 4; screenpitch = -(int)vid.pixelwidth; } else { // top down screenbuffer = pDIBBase; screenpitch = vid.pixelwidth; } /* ** clear the DIB memory buffer */ memset( pDIBBase, 0, vid.pixelwidth * vid.pixelheight * 4); if ( ( hdcDIBSection = CreateCompatibleDC( mainhDC ) ) == NULL ) { Con_Printf( "DIB_Init() - CreateCompatibleDC failed\n" ); goto fail; } if ( ( previously_selected_GDI_obj = SelectObject( hdcDIBSection, hDIBSection ) ) == NULL ) { Con_Printf( "DIB_Init() - SelectObject failed\n" ); goto fail; } depthbuffer = BZ_Malloc(vid.pixelwidth * vid.pixelheight * sizeof(*depthbuffer)); if (depthbuffer) return true; fail: DIB_Shutdown(); return false; } void DIB_SwapBuffers(void) { // extern float usingstretch; // if (usingstretch == 1) BitBlt( mainhDC, 0, 0, vid.pixelwidth, vid.pixelheight, hdcDIBSection, 0, 0, SRCCOPY ); /* else StretchBlt( mainhDC, //Why is StretchBlt not optimised for a scale of 2? Surly that would be a frequently used quantity? 0, 0, vid.width*usingstretch, vid.height*usingstretch, hdcDIBSection, 0, 0, vid.width, vid.height, SRCCOPY ); */ } extern int window_width; extern int window_height; void SWV_UpdateWindowStatus(void) { POINT p; RECT nr; RECT WindowRect; GetClientRect(mainwindow, &nr); //if its bad then we're probably minimised if (nr.right <= nr.left) return; if (nr.bottom <= nr.top) return; WindowRect = nr; p.x = 0; p.y = 0; ClientToScreen(mainwindow, &p); window_x = p.x; window_y = p.y; window_width = WindowRect.right - WindowRect.left; window_height = WindowRect.bottom - WindowRect.top; 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; INS_UpdateClipCursor (); } qboolean SWAppActivate(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; if (ActiveApp == fActive && Minimized == minimize) return false; //so windows doesn't crash us over and over again. 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; } INS_UpdateGrabs(false, ActiveApp); /* if (fActive) { if (modestate != MS_WINDOWED) { if (vid_canalttab && vid_wassuspended) { vid_wassuspended = false; ChangeDisplaySettings (&gdevmode, CDS_FULLSCREEN); ShowWindow(mainwindow, SW_SHOWNORMAL); } } } if (!fActive) { if (modestate != MS_WINDOWED) { if (vid_canalttab) { ChangeDisplaySettings (NULL, 0); vid_wassuspended = true; } } } */ return true; } LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LONG lRet = 0; int fActive, fMinimized, temp; HDC hdc; PAINTSTRUCT ps; extern unsigned int uiWheelMessage; // static int recursiveflag; if ( uMsg == uiWheelMessage ) { uMsg = WM_MOUSEWHEEL; wParam <<= 16; } switch (uMsg) { case WM_CREATE: break; case WM_SYSCOMMAND: // Check for maximize being hit switch (wParam & ~0x0F) { case SC_MAXIMIZE: Cbuf_AddText("vid_fullscreen 1;vid_restart\n", RESTRICT_LOCAL); // 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 (w32sw.isfullscreen) { // 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 (!vid_initializing) // { // S_BlockSound (); // } lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); // if (!vid_initializing) // { // S_UnblockSound (); // } } break; case WM_MOVE: SWV_UpdateWindowStatus (); // if ((modestate == MS_WINDOWED) && !in_mode_set && !Minimized) // VID_RememberWindowPos (); break; case WM_SIZE: SWV_UpdateWindowStatus (); /* Minimized = false; if (!(wParam & SIZE_RESTORED)) { if (wParam & SIZE_MINIMIZED) Minimized = true; } if (!Minimized && !w32sw.isfullscreen) { int nt, nl; int nw, nh; qboolean move = false; RECT r; GetClientRect (hWnd, &r); nw = (int)(r.right - r.left)&~3; nh = (int)(r.bottom - r.top)&~3; window_width = nw; window_height = nh; VID2_UpdateWindowStatus(); if (nw < 320) { move = true; nw = 320; } if (nh < 200) { move = true; nh = 200; } if (nh > MAXHEIGHT) { move = true; nh = MAXHEIGHT; } if ((r.right - r.left) & 3) move = true; if ((r.bottom - r.top) & 3) move = true; GetWindowRect (hWnd, &r); nl = r.left; nt = r.top; r.left =0; r.top = 0; r.right = nw*usingstretch; r.bottom = nh*usingstretch; AdjustWindowRectEx(&r, WS_OVERLAPPEDWINDOW, FALSE, 0); if (move) MoveWindow(hWnd, nl, nt, r.right - r.left, r.bottom - r.top, true); else { if (vid.width != nw || vid.height != nh) { M_RemoveAllMenus(); //can cause probs DIB_Shutdown(); vid.conwidth = vid.width = nw;//vid_stretch.value; vid.conheight = vid.height = nh;///vid_stretch.value; DIB_Init( &vid.buffer, &vid.rowbytes ); vid.conbuffer = vid.buffer; vid.conrowbytes = vid.rowbytes; if (VID_AllocBuffers(vid.width, vid.height, r_pixbytes)) D_InitCaches (vid_surfcache, vid_surfcachesize); SCR_UpdateWholeScreen(); } else SCR_UpdateWholeScreen(); } } */ break; case WM_SYSCHAR: // keep Alt-Space from happening break; case WM_ACTIVATE: fActive = LOWORD(wParam); fMinimized = (BOOL) HIWORD(wParam); SWAppActivate(!(fActive == WA_INACTIVE), fMinimized); // fix the leftover Alt from any Alt-Tab or the like that switched us away // ClearAllStates (); 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 (!vid_initializing) INS_TranslateKeyEvent(wParam, lParam, true, 0, false); break; case WM_KEYUP: case WM_SYSKEYUP: // if (!vid_initializing) INS_TranslateKeyEvent(wParam, lParam, false, 0, 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: case WM_XBUTTONDOWN: case WM_XBUTTONUP: // if (!vid_initializing) { temp = 0; if (wParam & MK_LBUTTON) temp |= 1; if (wParam & MK_RBUTTON) temp |= 2; if (wParam & MK_MBUTTON) temp |= 4; // extra buttons 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; INS_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(0, K_MWHEELUP, 0, true); Key_Event(0, K_MWHEELUP, 0, false); } else { Key_Event(0, K_MWHEELDOWN, 0, true); Key_Event(0, K_MWHEELDOWN, 0, false); } } break; case WM_INPUT: // raw input handling INS_RawInput_Read((HANDLE)lParam); 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 (!vid_initializing) { if (MessageBox (mainwindow, "Are you sure you want to quit?", "Confirm Exit", MB_YESNO | MB_SETFOREGROUND | MB_ICONQUESTION) == IDYES) { Cbuf_AddText("\nquit\n", RESTRICT_LOCAL); } } 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; } /* ** VID_CreateWindow */ #define WINDOW_CLASS_NAME FULLENGINENAME #define WINDOW_TITLE_NAME FULLENGINENAME void VID_CreateWindow(int width, int height, qboolean fullscreen) { WNDCLASS wc; RECT r; int x, y, w, h; int exstyle; int stylebits; if (fullscreen) { exstyle = WS_EX_TOPMOST; stylebits = WS_POPUP; } else { exstyle = 0; stylebits = WS_OVERLAPPEDWINDOW; } /* Register the frame class */ wc.style = 0; wc.lpfnWndProc = (WNDPROC)MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = global_hInstance; wc.hIcon = 0; wc.hCursor = LoadCursor (NULL,IDC_ARROW); wc.hbrBackground = (void *)COLOR_GRAYTEXT; wc.lpszMenuName = 0; wc.lpszClassName = WINDOW_CLASS_NAME; RegisterClass(&wc); r.left = 0; r.top = 0; r.right = width; r.bottom = height; AdjustWindowRectEx (&r, stylebits, FALSE, exstyle); window_rect = r; w = r.right - r.left; h = r.bottom - r.top; x = 0;//vid_xpos.value; y = 0;//vid_ypos.value; mainwindow = CreateWindowEx( exstyle, WINDOW_CLASS_NAME, WINDOW_TITLE_NAME, stylebits, x, y, w, h, NULL, NULL, global_hInstance, NULL); if (!mainwindow) Sys_Error("Couldn't create window"); ShowWindow(mainwindow, SW_SHOWNORMAL); UpdateWindow(mainwindow); SetForegroundWindow(mainwindow); SetFocus(mainwindow); SWV_UpdateWindowStatus(); } void SW_VID_UpdateViewport(wqcom_t *com) { com->viewport.cbuf = screenbuffer; com->viewport.dbuf = depthbuffer; com->viewport.width = vid.pixelwidth; com->viewport.height = vid.pixelheight; com->viewport.stride = screenpitch; com->viewport.framenum = framenumber; } void SW_VID_SwapBuffers(void) { extern cvar_t vid_conautoscale; DIB_SwapBuffers(); framenumber++; INS_UpdateGrabs(false, ActiveApp); // memset( pDIBBase, 0, vid.pixelwidth * vid.pixelheight * 4); if (window_width != vid.pixelwidth || window_height != vid.pixelheight) { DIB_Shutdown(); vid.pixelwidth = window_width; vid.pixelheight = window_height; if (!DIB_Init()) Sys_Error("resize reinitialization error"); Cvar_ForceCallback(&vid_conautoscale); } } qboolean SW_VID_Init(rendererstate_t *info, unsigned char *palette) { vid.pixelwidth = info->width; vid.pixelheight = info->height; if (info->fullscreen) //don't do this with d3d - d3d should set it's own video mode. { //make windows change res. DEVMODE gdevmode; gdevmode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; if (info->bpp) gdevmode.dmFields |= DM_BITSPERPEL; if (info->rate) gdevmode.dmFields |= DM_DISPLAYFREQUENCY; gdevmode.dmBitsPerPel = info->bpp; if (info->bpp && (gdevmode.dmBitsPerPel < 15)) { Con_Printf("Forcing at least 16bpp\n"); gdevmode.dmBitsPerPel = 16; } 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", (int)gdevmode.dmPelsWidth, (int)gdevmode.dmPelsHeight, (int)gdevmode.dmBitsPerPel, (int)gdevmode.dmDisplayFrequency); return false; } } VID_CreateWindow(vid.pixelwidth, vid.pixelheight, info->fullscreen); if (!DIB_Init()) return false; return true; } void SW_VID_DeInit(void) { Image_Shutdown(); DIB_Shutdown(); DestroyWindow(mainwindow); ChangeDisplaySettings (NULL, 0); } qboolean SW_VID_ApplyGammaRamps (unsigned short *ramps) { return false; } char *SW_VID_GetRGBInfo(int prepad, int *truevidwidth, int *truevidheight) { char *buf = NULL; char *src, *dst; int w, h; buf = BZ_Malloc(prepad + (vid.pixelwidth * vid.pixelheight * 3)); dst = buf + prepad; for (h = 0; h < vid.pixelheight; h++) { for (w = 0, src = (char*)screenbuffer + (h * vid.pixelwidth*4); w < vid.pixelwidth; w++, dst += 3, src += 4) { dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; } } *truevidwidth = vid.pixelwidth; *truevidheight = vid.pixelheight; return buf; } void SW_VID_SetWindowCaption(char *msg) { } #endif