1
0
Fork 0
forked from fte/fteqw
fteqw/engine/sw/sw_vidwin.c
Spoike 5d2ff1286d first version with dtls support. disabled for now.
schannel (ie: windows native) works as a client, not a server.
gnutls provides both client+server support. servers need to load a pre-generated cert from disk.
tweaked gamepads to actually work in the web target.
tweak gamepads a bit. added gp_* bind aliases. xinput+sdl+web should all use the same key mappings.
finally added the itemtimer glsl.
tweaked software renderer to not be quite so buggy, but you probably won't realise that if you try it.
disabled the ill-fated QWOVERQ3 feature.
don't do the oldorigin thing in quakeworld mods. hopefully this'll fix cspree's weird stuck-in-floor issue.
dpp7 is buggy serverside. disabled for now. I'm part way through rewriting its deltas.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5103 fc73d0e0-1445-4013-8a0c-d673dee63da5
2017-05-18 10:24:09 +00:00

802 lines
17 KiB
C

#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 );
*/
}
static int window_width;
static 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 (vid.activeapp == fActive && Minimized == minimize)
return false; //so windows doesn't crash us over and over again.
vid.activeapp = fActive;
Minimized = minimize;
// enable/disable sound on focus gain/loss
if (!vid.activeapp && sound_active)
{
S_BlockSound ();
sound_active = false;
}
else if (vid.activeapp && !sound_active)
{
S_UnblockSound ();
sound_active = true;
}
INS_UpdateGrabs(false, vid.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;
#ifdef HAVE_CDPLAYER
case MM_MCINOTIFY:
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
break;
#endif
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, vid.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 int gammarampsize, unsigned short *ramps)
{
return false;
}
char *SW_VID_GetRGBInfo(int *bytestride, int *truevidwidth, int *truevidheight, enum uploadfmt *fmt)
{
char *buf = NULL;
char *src, *dst;
int w, h;
buf = BZ_Malloc((vid.pixelwidth * vid.pixelheight * 3));
dst = buf;
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];
}
}
*bytestride = vid.pixelwidth*3;
*truevidwidth = vid.pixelwidth;
*truevidheight = vid.pixelheight;
*fmt = TF_BGR24;
return buf;
}
void SW_VID_SetWindowCaption(const char *msg)
{
}
#endif