46c63cbedb
device ids with rawinput and xinput are now assigned only on the first event. this means the ordering is easily controllable, thus helping splitscreen usability. fix compile errors with the nolegacy builds. client updates "chat" userinfo to match ezquake. does not display them still. server now forwards them correctly for ezquake. android can now switch gles version. a bit crashy with it though. android: gyroscope is now available to csqc. android: added vid_dpi_x/y cvars. will be 0 on other platforms, for now. added screenshot_vr command, for 360-degree stereoscopic screenshots. fix a potential crash from frag parsing. added m_accel_style and friends, for nicer mouse acceleration. fixed const-correctness in a few places. added friendly spectate button to the server browser display a warning if an mdl has dodgy seam values. this won't affect fte, but can crash winquake. qcc: fix struct fields to at least appear to work. qcc: -I is finally implemented. qccgui: options now has tooltips, so people might have a chance of actually figuring out what each option does. menusys: game configs menu now scans for files rather than listing specific ones. should probably be tested more. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4998 fc73d0e0-1445-4013-8a0c-d673dee63da5
799 lines
18 KiB
C
799 lines
18 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 );
|
|
*/
|
|
}
|
|
|
|
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 (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;
|
|
|
|
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, 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 short *ramps)
|
|
{
|
|
return false;
|
|
}
|
|
char *SW_VID_GetRGBInfo(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];
|
|
}
|
|
}
|
|
*truevidwidth = vid.pixelwidth;
|
|
*truevidheight = vid.pixelheight;
|
|
*fmt = TF_BGR24;
|
|
return buf;
|
|
}
|
|
void SW_VID_SetWindowCaption(char *msg)
|
|
{
|
|
}
|
|
#endif
|