Quack 3: Arena

This commit is contained in:
Literally A Penguin
2024-09-25 15:40:36 -05:00
committed by GitHub
parent 0bf99969fd
commit 40035fa235
74 changed files with 36999 additions and 0 deletions

510
win32/cd_win.c Normal file
View File

@ -0,0 +1,510 @@
/*
Copyright (C) 1997-2001 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.
*/
// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All
// rights reserved.
#include <windows.h>
#include "../client/client.h"
extern HWND cl_hwnd;
static qboolean cdValid = false;
static qboolean playing = false;
static qboolean wasPlaying = false;
static qboolean initialized = false;
static qboolean enabled = false;
static qboolean playLooping = false;
static byte remap[100];
static byte cdrom;
static byte playTrack;
static byte maxTrack;
cvar_t *cd_nocd;
cvar_t *cd_loopcount;
cvar_t *cd_looptrack;
UINT wDeviceID;
int loopcounter;
void CDAudio_Pause(void);
static void CDAudio_Eject(void)
{
DWORD dwReturn;
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, (DWORD)NULL))
Com_DPrintf("MCI_SET_DOOR_OPEN failed (%i)\n", dwReturn);
}
static void CDAudio_CloseDoor(void)
{
DWORD dwReturn;
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, (DWORD)NULL))
Com_DPrintf("MCI_SET_DOOR_CLOSED failed (%i)\n", dwReturn);
}
static int CDAudio_GetAudioDiskInfo(void)
{
DWORD dwReturn;
MCI_STATUS_PARMS mciStatusParms;
cdValid = false;
mciStatusParms.dwItem = MCI_STATUS_READY;
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
if (dwReturn)
{
Com_DPrintf("CDAudio: drive ready test - get status failed\n");
return -1;
}
if (!mciStatusParms.dwReturn)
{
Com_DPrintf("CDAudio: drive not ready\n");
return -1;
}
mciStatusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
if (dwReturn)
{
Com_DPrintf("CDAudio: get tracks - status failed\n");
return -1;
}
if (mciStatusParms.dwReturn < 1)
{
Com_DPrintf("CDAudio: no music tracks\n");
return -1;
}
cdValid = true;
maxTrack = mciStatusParms.dwReturn;
return 0;
}
void CDAudio_Play2(int track, qboolean looping)
{
DWORD dwReturn;
MCI_PLAY_PARMS mciPlayParms;
MCI_STATUS_PARMS mciStatusParms;
if (!enabled)
return;
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
if (!cdValid)
return;
}
track = remap[track];
if (track < 1 || track > maxTrack)
{
CDAudio_Stop();
return;
}
// don't try to play a non-audio track
mciStatusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
mciStatusParms.dwTrack = track;
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
if (dwReturn)
{
Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
return;
}
if (mciStatusParms.dwReturn != MCI_CDA_TRACK_AUDIO)
{
Com_Printf("CDAudio: track %i is not audio\n", track);
return;
}
// get the length of the track to be played
mciStatusParms.dwItem = MCI_STATUS_LENGTH;
mciStatusParms.dwTrack = track;
dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK | MCI_WAIT, (DWORD) (LPVOID) &mciStatusParms);
if (dwReturn)
{
Com_DPrintf("MCI_STATUS failed (%i)\n", dwReturn);
return;
}
if (playing)
{
if (playTrack == track)
return;
CDAudio_Stop();
}
mciPlayParms.dwFrom = MCI_MAKE_TMSF(track, 0, 0, 0);
mciPlayParms.dwTo = (mciStatusParms.dwReturn << 8) | track;
mciPlayParms.dwCallback = (DWORD)cl_hwnd;
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_NOTIFY | MCI_FROM | MCI_TO, (DWORD)(LPVOID) &mciPlayParms);
if (dwReturn)
{
Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
return;
}
playLooping = looping;
playTrack = track;
playing = true;
if ( Cvar_VariableValue( "cd_nocd" ) )
CDAudio_Pause ();
}
void CDAudio_Play(int track, qboolean looping)
{
// set a loop counter so that this track will change to the
// looptrack later
loopcounter = 0;
CDAudio_Play2(track, looping);
}
void CDAudio_Stop(void)
{
DWORD dwReturn;
if (!enabled)
return;
if (!playing)
return;
if (dwReturn = mciSendCommand(wDeviceID, MCI_STOP, 0, (DWORD)NULL))
Com_DPrintf("MCI_STOP failed (%i)", dwReturn);
wasPlaying = false;
playing = false;
}
void CDAudio_Pause(void)
{
DWORD dwReturn;
MCI_GENERIC_PARMS mciGenericParms;
if (!enabled)
return;
if (!playing)
return;
mciGenericParms.dwCallback = (DWORD)cl_hwnd;
if (dwReturn = mciSendCommand(wDeviceID, MCI_PAUSE, 0, (DWORD)(LPVOID) &mciGenericParms))
Com_DPrintf("MCI_PAUSE failed (%i)", dwReturn);
wasPlaying = playing;
playing = false;
}
void CDAudio_Resume(void)
{
DWORD dwReturn;
MCI_PLAY_PARMS mciPlayParms;
if (!enabled)
return;
if (!cdValid)
return;
if (!wasPlaying)
return;
mciPlayParms.dwFrom = MCI_MAKE_TMSF(playTrack, 0, 0, 0);
mciPlayParms.dwTo = MCI_MAKE_TMSF(playTrack + 1, 0, 0, 0);
mciPlayParms.dwCallback = (DWORD)cl_hwnd;
dwReturn = mciSendCommand(wDeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD)(LPVOID) &mciPlayParms);
if (dwReturn)
{
Com_DPrintf("CDAudio: MCI_PLAY failed (%i)\n", dwReturn);
return;
}
playing = true;
}
static void CD_f (void)
{
char *command;
int ret;
int n;
if (Cmd_Argc() < 2)
return;
command = Cmd_Argv (1);
if (Q_strcasecmp(command, "on") == 0)
{
enabled = true;
return;
}
if (Q_strcasecmp(command, "off") == 0)
{
if (playing)
CDAudio_Stop();
enabled = false;
return;
}
if (Q_strcasecmp(command, "reset") == 0)
{
enabled = true;
if (playing)
CDAudio_Stop();
for (n = 0; n < 100; n++)
remap[n] = n;
CDAudio_GetAudioDiskInfo();
return;
}
if (Q_strcasecmp(command, "remap") == 0)
{
ret = Cmd_Argc() - 2;
if (ret <= 0)
{
for (n = 1; n < 100; n++)
if (remap[n] != n)
Com_Printf(" %u -> %u\n", n, remap[n]);
return;
}
for (n = 1; n <= ret; n++)
remap[n] = atoi(Cmd_Argv (n+1));
return;
}
if (Q_strcasecmp(command, "close") == 0)
{
CDAudio_CloseDoor();
return;
}
if (!cdValid)
{
CDAudio_GetAudioDiskInfo();
if (!cdValid)
{
Com_Printf("No CD in player.\n");
return;
}
}
if (Q_strcasecmp(command, "play") == 0)
{
CDAudio_Play(atoi(Cmd_Argv (2)), false);
return;
}
if (Q_strcasecmp(command, "loop") == 0)
{
CDAudio_Play(atoi(Cmd_Argv (2)), true);
return;
}
if (Q_strcasecmp(command, "stop") == 0)
{
CDAudio_Stop();
return;
}
if (Q_strcasecmp(command, "pause") == 0)
{
CDAudio_Pause();
return;
}
if (Q_strcasecmp(command, "resume") == 0)
{
CDAudio_Resume();
return;
}
if (Q_strcasecmp(command, "eject") == 0)
{
if (playing)
CDAudio_Stop();
CDAudio_Eject();
cdValid = false;
return;
}
if (Q_strcasecmp(command, "info") == 0)
{
Com_Printf("%u tracks\n", maxTrack);
if (playing)
Com_Printf("Currently %s track %u\n", playLooping ? "looping" : "playing", playTrack);
else if (wasPlaying)
Com_Printf("Paused %s track %u\n", playLooping ? "looping" : "playing", playTrack);
return;
}
}
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (lParam != wDeviceID)
return 1;
switch (wParam)
{
case MCI_NOTIFY_SUCCESSFUL:
if (playing)
{
playing = false;
if (playLooping)
{
// if the track has played the given number of times,
// go to the ambient track
if (++loopcounter >= cd_loopcount->value)
CDAudio_Play2(cd_looptrack->value, true);
else
CDAudio_Play2(playTrack, true);
}
}
break;
case MCI_NOTIFY_ABORTED:
case MCI_NOTIFY_SUPERSEDED:
break;
case MCI_NOTIFY_FAILURE:
Com_DPrintf("MCI_NOTIFY_FAILURE\n");
CDAudio_Stop ();
cdValid = false;
break;
default:
Com_DPrintf("Unexpected MM_MCINOTIFY type (%i)\n", wParam);
return 1;
}
return 0;
}
void CDAudio_Update(void)
{
if ( cd_nocd->value != !enabled )
{
if ( cd_nocd->value )
{
CDAudio_Stop();
enabled = false;
}
else
{
enabled = true;
CDAudio_Resume ();
}
}
}
int CDAudio_Init(void)
{
DWORD dwReturn;
MCI_OPEN_PARMS mciOpenParms;
MCI_SET_PARMS mciSetParms;
int n;
cd_nocd = Cvar_Get ("cd_nocd", "0", CVAR_ARCHIVE );
cd_loopcount = Cvar_Get ("cd_loopcount", "4", 0);
cd_looptrack = Cvar_Get ("cd_looptrack", "11", 0);
if ( cd_nocd->value)
return -1;
mciOpenParms.lpstrDeviceType = "cdaudio";
if (dwReturn = mciSendCommand(0, MCI_OPEN, MCI_OPEN_TYPE | MCI_OPEN_SHAREABLE, (DWORD) (LPVOID) &mciOpenParms))
{
Com_Printf("CDAudio_Init: MCI_OPEN failed (%i)\n", dwReturn);
return -1;
}
wDeviceID = mciOpenParms.wDeviceID;
// Set the time format to track/minute/second/frame (TMSF).
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD)(LPVOID) &mciSetParms))
{
Com_Printf("MCI_SET_TIME_FORMAT failed (%i)\n", dwReturn);
mciSendCommand(wDeviceID, MCI_CLOSE, 0, (DWORD)NULL);
return -1;
}
for (n = 0; n < 100; n++)
remap[n] = n;
initialized = true;
enabled = true;
if (CDAudio_GetAudioDiskInfo())
{
// Com_Printf("CDAudio_Init: No CD in player.\n");
cdValid = false;
enabled = false;
}
Cmd_AddCommand ("cd", CD_f);
Com_Printf("CD Audio Initialized\n");
return 0;
}
void CDAudio_Shutdown(void)
{
if (!initialized)
return;
CDAudio_Stop();
if (mciSendCommand(wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)NULL))
Com_DPrintf("CDAudio_Shutdown: MCI_CLOSE failed\n");
}
/*
===========
CDAudio_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void CDAudio_Activate (qboolean active)
{
if (active)
CDAudio_Resume ();
else
CDAudio_Pause ();
}

431
win32/conproc.c Normal file
View File

@ -0,0 +1,431 @@
/*
Copyright (C) 1997-2001 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.
*/
// conproc.c -- support for qhost
#include <stdio.h>
#include <process.h>
#include <windows.h>
#include "conproc.h"
#define CCOM_WRITE_TEXT 0x2
// Param1 : Text
#define CCOM_GET_TEXT 0x3
// Param1 : Begin line
// Param2 : End line
#define CCOM_GET_SCR_LINES 0x4
// No params
#define CCOM_SET_SCR_LINES 0x5
// Param1 : Number of lines
HANDLE heventDone;
HANDLE hfileBuffer;
HANDLE heventChildSend;
HANDLE heventParentSend;
HANDLE hStdout;
HANDLE hStdin;
unsigned _stdcall RequestProc (void *arg);
LPVOID GetMappedBuffer (HANDLE hfileBuffer);
void ReleaseMappedBuffer (LPVOID pBuffer);
BOOL GetScreenBufferLines (int *piLines);
BOOL SetScreenBufferLines (int iLines);
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine);
BOOL WriteText (LPCTSTR szText);
int CharToCode (char c);
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
int ccom_argc;
char **ccom_argv;
/*
================
CCheckParm
Returns the position (1 to argc-1) in the program's argument list
where the given parameter apears, or 0 if not present
================
*/
int CCheckParm (char *parm)
{
int i;
for (i=1 ; i<ccom_argc ; i++)
{
if (!ccom_argv[i])
continue;
if (!strcmp (parm,ccom_argv[i]))
return i;
}
return 0;
}
void InitConProc (int argc, char **argv)
{
unsigned threadAddr;
HANDLE hFile;
HANDLE heventParent;
HANDLE heventChild;
int t;
ccom_argc = argc;
ccom_argv = argv;
// give QHOST a chance to hook into the console
if ((t = CCheckParm ("-HFILE")) > 0)
{
if (t < argc)
hFile = (HANDLE)atoi (ccom_argv[t+1]);
}
if ((t = CCheckParm ("-HPARENT")) > 0)
{
if (t < argc)
heventParent = (HANDLE)atoi (ccom_argv[t+1]);
}
if ((t = CCheckParm ("-HCHILD")) > 0)
{
if (t < argc)
heventChild = (HANDLE)atoi (ccom_argv[t+1]);
}
// ignore if we don't have all the events.
if (!hFile || !heventParent || !heventChild)
{
printf ("Qhost not present.\n");
return;
}
printf ("Initializing for qhost.\n");
hfileBuffer = hFile;
heventParentSend = heventParent;
heventChildSend = heventChild;
// so we'll know when to go away.
heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!heventDone)
{
printf ("Couldn't create heventDone\n");
return;
}
if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
{
CloseHandle (heventDone);
printf ("Couldn't create QHOST thread\n");
return;
}
// save off the input/output handles.
hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
hStdin = GetStdHandle (STD_INPUT_HANDLE);
// force 80 character width, at least 25 character height
SetConsoleCXCY (hStdout, 80, 25);
}
void DeinitConProc (void)
{
if (heventDone)
SetEvent (heventDone);
}
unsigned _stdcall RequestProc (void *arg)
{
int *pBuffer;
DWORD dwRet;
HANDLE heventWait[2];
int iBeginLine, iEndLine;
heventWait[0] = heventParentSend;
heventWait[1] = heventDone;
while (1)
{
dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
// heventDone fired, so we're exiting.
if (dwRet == WAIT_OBJECT_0 + 1)
break;
pBuffer = (int *) GetMappedBuffer (hfileBuffer);
// hfileBuffer is invalid. Just leave.
if (!pBuffer)
{
printf ("Invalid hfileBuffer\n");
break;
}
switch (pBuffer[0])
{
case CCOM_WRITE_TEXT:
// Param1 : Text
pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
break;
case CCOM_GET_TEXT:
// Param1 : Begin line
// Param2 : End line
iBeginLine = pBuffer[1];
iEndLine = pBuffer[2];
pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
iEndLine);
break;
case CCOM_GET_SCR_LINES:
// No params
pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
break;
case CCOM_SET_SCR_LINES:
// Param1 : Number of lines
pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
break;
}
ReleaseMappedBuffer (pBuffer);
SetEvent (heventChildSend);
}
_endthreadex (0);
return 0;
}
LPVOID GetMappedBuffer (HANDLE hfileBuffer)
{
LPVOID pBuffer;
pBuffer = MapViewOfFile (hfileBuffer,
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
return pBuffer;
}
void ReleaseMappedBuffer (LPVOID pBuffer)
{
UnmapViewOfFile (pBuffer);
}
BOOL GetScreenBufferLines (int *piLines)
{
CONSOLE_SCREEN_BUFFER_INFO info;
BOOL bRet;
bRet = GetConsoleScreenBufferInfo (hStdout, &info);
if (bRet)
*piLines = info.dwSize.Y;
return bRet;
}
BOOL SetScreenBufferLines (int iLines)
{
return SetConsoleCXCY (hStdout, 80, iLines);
}
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
{
COORD coord;
DWORD dwRead;
BOOL bRet;
coord.X = 0;
coord.Y = iBeginLine;
bRet = ReadConsoleOutputCharacter(
hStdout,
pszText,
80 * (iEndLine - iBeginLine + 1),
coord,
&dwRead);
// Make sure it's null terminated.
if (bRet)
pszText[dwRead] = '\0';
return bRet;
}
BOOL WriteText (LPCTSTR szText)
{
DWORD dwWritten;
INPUT_RECORD rec;
char upper, *sz;
sz = (LPTSTR) szText;
while (*sz)
{
// 13 is the code for a carriage return (\n) instead of 10.
if (*sz == 10)
*sz = 13;
upper = toupper(*sz);
rec.EventType = KEY_EVENT;
rec.Event.KeyEvent.bKeyDown = TRUE;
rec.Event.KeyEvent.wRepeatCount = 1;
rec.Event.KeyEvent.wVirtualKeyCode = upper;
rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
rec.Event.KeyEvent.uChar.AsciiChar = *sz;
rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0;
WriteConsoleInput(
hStdin,
&rec,
1,
&dwWritten);
rec.Event.KeyEvent.bKeyDown = FALSE;
WriteConsoleInput(
hStdin,
&rec,
1,
&dwWritten);
sz++;
}
return TRUE;
}
int CharToCode (char c)
{
char upper;
upper = toupper(c);
switch (c)
{
case 13:
return 28;
default:
break;
}
if (isalpha(c))
return (30 + upper - 65);
if (isdigit(c))
return (1 + upper - 47);
return c;
}
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
{
CONSOLE_SCREEN_BUFFER_INFO info;
COORD coordMax;
coordMax = GetLargestConsoleWindowSize(hStdout);
if (cy > coordMax.Y)
cy = coordMax.Y;
if (cx > coordMax.X)
cx = coordMax.X;
if (!GetConsoleScreenBufferInfo(hStdout, &info))
return FALSE;
// height
info.srWindow.Left = 0;
info.srWindow.Right = info.dwSize.X - 1;
info.srWindow.Top = 0;
info.srWindow.Bottom = cy - 1;
if (cy < info.dwSize.Y)
{
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
return FALSE;
info.dwSize.Y = cy;
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
return FALSE;
}
else if (cy > info.dwSize.Y)
{
info.dwSize.Y = cy;
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
return FALSE;
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
return FALSE;
}
if (!GetConsoleScreenBufferInfo(hStdout, &info))
return FALSE;
// width
info.srWindow.Left = 0;
info.srWindow.Right = cx - 1;
info.srWindow.Top = 0;
info.srWindow.Bottom = info.dwSize.Y - 1;
if (cx < info.dwSize.X)
{
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
return FALSE;
info.dwSize.X = cx;
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
return FALSE;
}
else if (cx > info.dwSize.X)
{
info.dwSize.X = cx;
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
return FALSE;
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
return FALSE;
}
return TRUE;
}

24
win32/conproc.h Normal file
View File

@ -0,0 +1,24 @@
/*
Copyright (C) 1997-2001 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.
*/
// conproc.h -- support for qhost
void InitConProc (int argc, char **argv);
void DeinitConProc (void);

616
win32/glw_imp.c Normal file
View File

@ -0,0 +1,616 @@
/*
Copyright (C) 1997-2001 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.
*/
/*
** GLW_IMP.C
**
** This file contains ALL Win32 specific stuff having to do with the
** OpenGL refresh. When a port is being made the following functions
** must be implemented by the port:
**
** GLimp_EndFrame
** GLimp_Init
** GLimp_Shutdown
** GLimp_SwitchFullscreen
**
*/
#include <assert.h>
#include <windows.h>
#include "../ref_gl/gl_local.h"
#include "glw_win.h"
#include "winquake.h"
static qboolean GLimp_SwitchFullscreen( int width, int height );
qboolean GLimp_InitGL (void);
glwstate_t glw_state;
extern cvar_t *vid_fullscreen;
extern cvar_t *vid_ref;
static qboolean VerifyDriver( void )
{
char buffer[1024];
strcpy( buffer, qglGetString( GL_RENDERER ) );
strlwr( buffer );
if ( strcmp( buffer, "gdi generic" ) == 0 )
if ( !glw_state.mcd_accelerated )
return false;
return true;
}
/*
** VID_CreateWindow
*/
#define WINDOW_CLASS_NAME "Quake 2"
qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
{
WNDCLASS wc;
RECT r;
cvar_t *vid_xpos, *vid_ypos;
int stylebits;
int x, y, w, h;
int exstyle;
/* Register the frame class */
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)glw_state.wndproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = glw_state.hInstance;
wc.hIcon = 0;
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
wc.hbrBackground = (void *)COLOR_GRAYTEXT;
wc.lpszMenuName = 0;
wc.lpszClassName = WINDOW_CLASS_NAME;
if (!RegisterClass (&wc) )
ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
if (fullscreen)
{
exstyle = WS_EX_TOPMOST;
stylebits = WS_POPUP|WS_VISIBLE;
}
else
{
exstyle = 0;
stylebits = WINDOW_STYLE;
}
r.left = 0;
r.top = 0;
r.right = width;
r.bottom = height;
AdjustWindowRect (&r, stylebits, FALSE);
w = r.right - r.left;
h = r.bottom - r.top;
if (fullscreen)
{
x = 0;
y = 0;
}
else
{
vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
x = vid_xpos->value;
y = vid_ypos->value;
}
glw_state.hWnd = CreateWindowEx (
exstyle,
WINDOW_CLASS_NAME,
"Quake 2",
stylebits,
x, y, w, h,
NULL,
NULL,
glw_state.hInstance,
NULL);
if (!glw_state.hWnd)
ri.Sys_Error (ERR_FATAL, "Couldn't create window");
ShowWindow( glw_state.hWnd, SW_SHOW );
UpdateWindow( glw_state.hWnd );
// init all the gl stuff for the window
if (!GLimp_InitGL ())
{
ri.Con_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
return false;
}
SetForegroundWindow( glw_state.hWnd );
SetFocus( glw_state.hWnd );
// let the sound and input subsystems know about the new window
ri.Vid_NewWindow (width, height);
return true;
}
/*
** GLimp_SetMode
*/
rserr_t GLimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
{
int width, height;
const char *win_fs[] = { "W", "FS" };
ri.Con_Printf( PRINT_ALL, "Initializing OpenGL display\n");
ri.Con_Printf (PRINT_ALL, "...setting mode %d:", mode );
if ( !ri.Vid_GetModeInfo( &width, &height, mode ) )
{
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
return rserr_invalid_mode;
}
ri.Con_Printf( PRINT_ALL, " %d %d %s\n", width, height, win_fs[fullscreen] );
// destroy the existing window
if (glw_state.hWnd)
{
GLimp_Shutdown ();
}
// do a CDS if needed
if ( fullscreen )
{
DEVMODE dm;
ri.Con_Printf( PRINT_ALL, "...attempting fullscreen\n" );
memset( &dm, 0, sizeof( dm ) );
dm.dmSize = sizeof( dm );
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
if ( gl_bitdepth->value != 0 )
{
dm.dmBitsPerPel = gl_bitdepth->value;
dm.dmFields |= DM_BITSPERPEL;
ri.Con_Printf( PRINT_ALL, "...using gl_bitdepth of %d\n", ( int ) gl_bitdepth->value );
}
else
{
HDC hdc = GetDC( NULL );
int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
ri.Con_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );
ReleaseDC( 0, hdc );
}
ri.Con_Printf( PRINT_ALL, "...calling CDS: " );
if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
{
*pwidth = width;
*pheight = height;
gl_state.fullscreen = true;
ri.Con_Printf( PRINT_ALL, "ok\n" );
if ( !VID_CreateWindow (width, height, true) )
return rserr_invalid_mode;
return rserr_ok;
}
else
{
*pwidth = width;
*pheight = height;
ri.Con_Printf( PRINT_ALL, "failed\n" );
ri.Con_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );
dm.dmPelsWidth = width * 2;
dm.dmPelsHeight = height;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
if ( gl_bitdepth->value != 0 )
{
dm.dmBitsPerPel = gl_bitdepth->value;
dm.dmFields |= DM_BITSPERPEL;
}
/*
** our first CDS failed, so maybe we're running on some weird dual monitor
** system
*/
if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
{
ri.Con_Printf( PRINT_ALL, " failed\n" );
ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
ChangeDisplaySettings( 0, 0 );
*pwidth = width;
*pheight = height;
gl_state.fullscreen = false;
if ( !VID_CreateWindow (width, height, false) )
return rserr_invalid_mode;
return rserr_invalid_fullscreen;
}
else
{
ri.Con_Printf( PRINT_ALL, " ok\n" );
if ( !VID_CreateWindow (width, height, true) )
return rserr_invalid_mode;
gl_state.fullscreen = true;
return rserr_ok;
}
}
}
else
{
ri.Con_Printf( PRINT_ALL, "...setting windowed mode\n" );
ChangeDisplaySettings( 0, 0 );
*pwidth = width;
*pheight = height;
gl_state.fullscreen = false;
if ( !VID_CreateWindow (width, height, false) )
return rserr_invalid_mode;
}
return rserr_ok;
}
/*
** GLimp_Shutdown
**
** This routine does all OS specific shutdown procedures for the OpenGL
** subsystem. Under OpenGL this means NULLing out the current DC and
** HGLRC, deleting the rendering context, and releasing the DC acquired
** for the window. The state structure is also nulled out.
**
*/
void GLimp_Shutdown( void )
{
if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
if ( glw_state.hGLRC )
{
if ( qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
glw_state.hGLRC = NULL;
}
if (glw_state.hDC)
{
if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
ri.Con_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
glw_state.hDC = NULL;
}
if (glw_state.hWnd)
{
DestroyWindow ( glw_state.hWnd );
glw_state.hWnd = NULL;
}
if ( glw_state.log_fp )
{
fclose( glw_state.log_fp );
glw_state.log_fp = 0;
}
UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance);
if ( gl_state.fullscreen )
{
ChangeDisplaySettings( 0, 0 );
gl_state.fullscreen = false;
}
}
/*
** GLimp_Init
**
** This routine is responsible for initializing the OS specific portions
** of OpenGL. Under Win32 this means dealing with the pixelformats and
** doing the wgl interface stuff.
*/
qboolean GLimp_Init( void *hinstance, void *wndproc )
{
#define OSR2_BUILD_NUMBER 1111
OSVERSIONINFO vinfo;
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
glw_state.allowdisplaydepthchange = false;
if ( GetVersionEx( &vinfo) )
{
if ( vinfo.dwMajorVersion > 4 )
{
glw_state.allowdisplaydepthchange = true;
}
else if ( vinfo.dwMajorVersion == 4 )
{
if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
{
glw_state.allowdisplaydepthchange = true;
}
else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
{
if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
{
glw_state.allowdisplaydepthchange = true;
}
}
}
}
else
{
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
return false;
}
glw_state.hInstance = ( HINSTANCE ) hinstance;
glw_state.wndproc = wndproc;
return true;
}
qboolean GLimp_InitGL (void)
{
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
0, // no stencil buffer
0, // no auxiliary buffer
PFD_MAIN_PLANE, // main layer
0, // reserved
0, 0, 0 // layer masks ignored
};
int pixelformat;
cvar_t *stereo;
stereo = ri.Cvar_Get( "cl_stereo", "0", 0 );
/*
** set PFD_STEREO if necessary
*/
if ( stereo->value != 0 )
{
ri.Con_Printf( PRINT_ALL, "...attempting to use stereo\n" );
pfd.dwFlags |= PFD_STEREO;
gl_state.stereo_enabled = true;
}
else
{
gl_state.stereo_enabled = false;
}
/*
** figure out if we're running on a minidriver or not
*/
if ( strstr( gl_driver->string, "opengl32" ) != 0 )
glw_state.minidriver = false;
else
glw_state.minidriver = true;
/*
** Get a DC for the specified window
*/
if ( glw_state.hDC != NULL )
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );
if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
{
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
return false;
}
if ( glw_state.minidriver )
{
if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
return false;
}
if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
return false;
}
qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
}
else
{
if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
return false;
}
if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
return false;
}
DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
{
extern cvar_t *gl_allow_software;
if ( gl_allow_software->value )
glw_state.mcd_accelerated = true;
else
glw_state.mcd_accelerated = false;
}
else
{
glw_state.mcd_accelerated = true;
}
}
/*
** report if stereo is desired but unavailable
*/
if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) )
{
ri.Con_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
ri.Cvar_SetValue( "cl_stereo", 0 );
gl_state.stereo_enabled = false;
}
/*
** startup the OpenGL subsystem by creating a context and making
** it current
*/
if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");
goto fail;
}
if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
{
ri.Con_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");
goto fail;
}
if ( !VerifyDriver() )
{
ri.Con_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected\n" );
goto fail;
}
/*
** print out PFD specifics
*/
ri.Con_Printf( PRINT_ALL, "GL PFD: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );
return true;
fail:
if ( glw_state.hGLRC )
{
qwglDeleteContext( glw_state.hGLRC );
glw_state.hGLRC = NULL;
}
if ( glw_state.hDC )
{
ReleaseDC( glw_state.hWnd, glw_state.hDC );
glw_state.hDC = NULL;
}
return false;
}
/*
** GLimp_BeginFrame
*/
void GLimp_BeginFrame( float camera_separation )
{
if ( gl_bitdepth->modified )
{
if ( gl_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange )
{
ri.Cvar_SetValue( "gl_bitdepth", 0 );
ri.Con_Printf( PRINT_ALL, "gl_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
}
gl_bitdepth->modified = false;
}
if ( camera_separation < 0 && gl_state.stereo_enabled )
{
qglDrawBuffer( GL_BACK_LEFT );
}
else if ( camera_separation > 0 && gl_state.stereo_enabled )
{
qglDrawBuffer( GL_BACK_RIGHT );
}
else
{
qglDrawBuffer( GL_BACK );
}
}
/*
** GLimp_EndFrame
**
** Responsible for doing a swapbuffers and possibly for other stuff
** as yet to be determined. Probably better not to make this a GLimp
** function and instead do a call to GLimp_SwapBuffers.
*/
void GLimp_EndFrame (void)
{
int err;
err = qglGetError();
assert( err == GL_NO_ERROR );
if ( stricmp( gl_drawbuffer->string, "GL_BACK" ) == 0 )
{
if ( !qwglSwapBuffers( glw_state.hDC ) )
ri.Sys_Error( ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n" );
}
}
/*
** GLimp_AppActivate
*/
void GLimp_AppActivate( qboolean active )
{
if ( active )
{
SetForegroundWindow( glw_state.hWnd );
ShowWindow( glw_state.hWnd, SW_RESTORE );
}
else
{
if ( vid_fullscreen->value )
ShowWindow( glw_state.hWnd, SW_MINIMIZE );
}
}

47
win32/glw_win.h Normal file
View File

@ -0,0 +1,47 @@
/*
Copyright (C) 1997-2001 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.
*/
#ifndef _WIN32
# error You should not be including this file on this platform
#endif
#ifndef __GLW_WIN_H__
#define __GLW_WIN_H__
typedef struct
{
HINSTANCE hInstance;
void *wndproc;
HDC hDC; // handle to device context
HWND hWnd; // handle to window
HGLRC hGLRC; // handle to GL rendering context
HINSTANCE hinstOpenGL; // HINSTANCE for the OpenGL library
qboolean minidriver;
qboolean allowdisplaydepthchange;
qboolean mcd_accelerated;
FILE *log_fp;
} glwstate_t;
extern glwstate_t glw_state;
#endif

889
win32/in_win.c Normal file
View File

@ -0,0 +1,889 @@
/*
Copyright (C) 1997-2001 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.
*/
// in_win.c -- windows 95 mouse and joystick code
// 02/21/97 JCB Added extended DirectInput code to support external controllers.
#include "../client/client.h"
#include "winquake.h"
extern unsigned sys_msg_time;
// joystick defines and variables
// where should defines be moved?
#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick
#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball
#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V
#define JOY_AXIS_X 0
#define JOY_AXIS_Y 1
#define JOY_AXIS_Z 2
#define JOY_AXIS_R 3
#define JOY_AXIS_U 4
#define JOY_AXIS_V 5
enum _ControlList
{
AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn, AxisUp
};
DWORD dwAxisFlags[JOY_MAX_AXES] =
{
JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
};
DWORD dwAxisMap[JOY_MAX_AXES];
DWORD dwControlMap[JOY_MAX_AXES];
PDWORD pdwRawValue[JOY_MAX_AXES];
cvar_t *in_mouse;
cvar_t *in_joystick;
// none of these cvars are saved over a session
// this means that advanced controller configuration needs to be executed
// each time. this avoids any problems with getting back to a default usage
// or when changing from one controller to another. this way at least something
// works.
cvar_t *joy_name;
cvar_t *joy_advanced;
cvar_t *joy_advaxisx;
cvar_t *joy_advaxisy;
cvar_t *joy_advaxisz;
cvar_t *joy_advaxisr;
cvar_t *joy_advaxisu;
cvar_t *joy_advaxisv;
cvar_t *joy_forwardthreshold;
cvar_t *joy_sidethreshold;
cvar_t *joy_pitchthreshold;
cvar_t *joy_yawthreshold;
cvar_t *joy_forwardsensitivity;
cvar_t *joy_sidesensitivity;
cvar_t *joy_pitchsensitivity;
cvar_t *joy_yawsensitivity;
cvar_t *joy_upthreshold;
cvar_t *joy_upsensitivity;
qboolean joy_avail, joy_advancedinit, joy_haspov;
DWORD joy_oldbuttonstate, joy_oldpovstate;
int joy_id;
DWORD joy_flags;
DWORD joy_numbuttons;
static JOYINFOEX ji;
qboolean in_appactive;
// forward-referenced functions
void IN_StartupJoystick (void);
void Joy_AdvancedUpdate_f (void);
void IN_JoyMove (usercmd_t *cmd);
/*
============================================================
MOUSE CONTROL
============================================================
*/
// mouse variables
cvar_t *m_filter;
qboolean mlooking;
void IN_MLookDown (void) { mlooking = true; }
void IN_MLookUp (void) {
mlooking = false;
if (!freelook->value && lookspring->value)
IN_CenterView ();
}
int mouse_buttons;
int mouse_oldbuttonstate;
POINT current_pos;
int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
int old_x, old_y;
qboolean mouseactive; // false when not focus app
qboolean restore_spi;
qboolean mouseinitialized;
int originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
qboolean mouseparmsvalid;
int window_center_x, window_center_y;
RECT window_rect;
/*
===========
IN_ActivateMouse
Called when the window gains focus or changes in some way
===========
*/
void IN_ActivateMouse (void)
{
int width, height;
if (!mouseinitialized)
return;
if (!in_mouse->value)
{
mouseactive = false;
return;
}
if (mouseactive)
return;
mouseactive = true;
if (mouseparmsvalid)
restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
width = GetSystemMetrics (SM_CXSCREEN);
height = GetSystemMetrics (SM_CYSCREEN);
GetWindowRect ( cl_hwnd, &window_rect);
if (window_rect.left < 0)
window_rect.left = 0;
if (window_rect.top < 0)
window_rect.top = 0;
if (window_rect.right >= width)
window_rect.right = width-1;
if (window_rect.bottom >= height-1)
window_rect.bottom = height-1;
window_center_x = (window_rect.right + window_rect.left)/2;
window_center_y = (window_rect.top + window_rect.bottom)/2;
SetCursorPos (window_center_x, window_center_y);
old_x = window_center_x;
old_y = window_center_y;
SetCapture ( cl_hwnd );
ClipCursor (&window_rect);
while (ShowCursor (FALSE) >= 0)
;
}
/*
===========
IN_DeactivateMouse
Called when the window loses focus
===========
*/
void IN_DeactivateMouse (void)
{
if (!mouseinitialized)
return;
if (!mouseactive)
return;
if (restore_spi)
SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
mouseactive = false;
ClipCursor (NULL);
ReleaseCapture ();
while (ShowCursor (TRUE) < 0)
;
}
/*
===========
IN_StartupMouse
===========
*/
void IN_StartupMouse (void)
{
cvar_t *cv;
cv = Cvar_Get ("in_initmouse", "1", CVAR_NOSET);
if ( !cv->value )
return;
mouseinitialized = true;
mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
mouse_buttons = 3;
}
/*
===========
IN_MouseEvent
===========
*/
void IN_MouseEvent (int mstate)
{
int i;
if (!mouseinitialized)
return;
// perform button actions
for (i=0 ; i<mouse_buttons ; i++)
{
if ( (mstate & (1<<i)) &&
!(mouse_oldbuttonstate & (1<<i)) )
{
Key_Event (K_MOUSE1 + i, true, sys_msg_time);
}
if ( !(mstate & (1<<i)) &&
(mouse_oldbuttonstate & (1<<i)) )
{
Key_Event (K_MOUSE1 + i, false, sys_msg_time);
}
}
mouse_oldbuttonstate = mstate;
}
/*
===========
IN_MouseMove
===========
*/
void IN_MouseMove (usercmd_t *cmd)
{
int mx, my;
if (!mouseactive)
return;
// find mouse movement
if (!GetCursorPos (&current_pos))
return;
mx = current_pos.x - window_center_x;
my = current_pos.y - window_center_y;
#if 0
if (!mx && !my)
return;
#endif
if (m_filter->value)
{
mouse_x = (mx + old_mouse_x) * 0.5;
mouse_y = (my + old_mouse_y) * 0.5;
}
else
{
mouse_x = mx;
mouse_y = my;
}
old_mouse_x = mx;
old_mouse_y = my;
mouse_x *= sensitivity->value;
mouse_y *= sensitivity->value;
// add mouse X/Y movement to cmd
if ( (in_strafe.state & 1) || (lookstrafe->value && mlooking ))
cmd->sidemove += m_side->value * mouse_x;
else
cl.viewangles[YAW] -= m_yaw->value * mouse_x;
if ( (mlooking || freelook->value) && !(in_strafe.state & 1))
{
cl.viewangles[PITCH] += m_pitch->value * mouse_y;
}
else
{
cmd->forwardmove -= m_forward->value * mouse_y;
}
// force the mouse to the center, so there's room to move
if (mx || my)
SetCursorPos (window_center_x, window_center_y);
}
/*
=========================================================================
VIEW CENTERING
=========================================================================
*/
cvar_t *v_centermove;
cvar_t *v_centerspeed;
/*
===========
IN_Init
===========
*/
void IN_Init (void)
{
// mouse variables
m_filter = Cvar_Get ("m_filter", "0", 0);
in_mouse = Cvar_Get ("in_mouse", "1", CVAR_ARCHIVE);
// joystick variables
in_joystick = Cvar_Get ("in_joystick", "0", CVAR_ARCHIVE);
joy_name = Cvar_Get ("joy_name", "joystick", 0);
joy_advanced = Cvar_Get ("joy_advanced", "0", 0);
joy_advaxisx = Cvar_Get ("joy_advaxisx", "0", 0);
joy_advaxisy = Cvar_Get ("joy_advaxisy", "0", 0);
joy_advaxisz = Cvar_Get ("joy_advaxisz", "0", 0);
joy_advaxisr = Cvar_Get ("joy_advaxisr", "0", 0);
joy_advaxisu = Cvar_Get ("joy_advaxisu", "0", 0);
joy_advaxisv = Cvar_Get ("joy_advaxisv", "0", 0);
joy_forwardthreshold = Cvar_Get ("joy_forwardthreshold", "0.15", 0);
joy_sidethreshold = Cvar_Get ("joy_sidethreshold", "0.15", 0);
joy_upthreshold = Cvar_Get ("joy_upthreshold", "0.15", 0);
joy_pitchthreshold = Cvar_Get ("joy_pitchthreshold", "0.15", 0);
joy_yawthreshold = Cvar_Get ("joy_yawthreshold", "0.15", 0);
joy_forwardsensitivity = Cvar_Get ("joy_forwardsensitivity", "-1", 0);
joy_sidesensitivity = Cvar_Get ("joy_sidesensitivity", "-1", 0);
joy_upsensitivity = Cvar_Get ("joy_upsensitivity", "-1", 0);
joy_pitchsensitivity = Cvar_Get ("joy_pitchsensitivity", "1", 0);
joy_yawsensitivity = Cvar_Get ("joy_yawsensitivity", "-1", 0);
// centering
v_centermove = Cvar_Get ("v_centermove", "0.15", 0);
v_centerspeed = Cvar_Get ("v_centerspeed", "500", 0);
Cmd_AddCommand ("+mlook", IN_MLookDown);
Cmd_AddCommand ("-mlook", IN_MLookUp);
Cmd_AddCommand ("joy_advancedupdate", Joy_AdvancedUpdate_f);
IN_StartupMouse ();
IN_StartupJoystick ();
}
/*
===========
IN_Shutdown
===========
*/
void IN_Shutdown (void)
{
IN_DeactivateMouse ();
}
/*
===========
IN_Activate
Called when the main window gains or loses focus.
The window may have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void IN_Activate (qboolean active)
{
in_appactive = active;
mouseactive = !active; // force a new window check or turn off
}
/*
==================
IN_Frame
Called every frame, even if not generating commands
==================
*/
void IN_Frame (void)
{
if (!mouseinitialized)
return;
if (!in_mouse || !in_appactive)
{
IN_DeactivateMouse ();
return;
}
if ( !cl.refresh_prepped
|| cls.key_dest == key_console
|| cls.key_dest == key_menu)
{
// temporarily deactivate if in fullscreen
if (Cvar_VariableValue ("vid_fullscreen") == 0)
{
IN_DeactivateMouse ();
return;
}
}
IN_ActivateMouse ();
}
/*
===========
IN_Move
===========
*/
void IN_Move (usercmd_t *cmd)
{
IN_MouseMove (cmd);
if (ActiveApp)
IN_JoyMove (cmd);
}
/*
===================
IN_ClearStates
===================
*/
void IN_ClearStates (void)
{
mx_accum = 0;
my_accum = 0;
mouse_oldbuttonstate = 0;
}
/*
=========================================================================
JOYSTICK
=========================================================================
*/
/*
===============
IN_StartupJoystick
===============
*/
void IN_StartupJoystick (void)
{
int numdevs;
JOYCAPS jc;
MMRESULT mmr;
cvar_t *cv;
// assume no joystick
joy_avail = false;
// abort startup if user requests no joystick
cv = Cvar_Get ("in_initjoy", "1", CVAR_NOSET);
if ( !cv->value )
return;
// verify joystick driver is present
if ((numdevs = joyGetNumDevs ()) == 0)
{
// Com_Printf ("\njoystick not found -- driver not present\n\n");
return;
}
// cycle through the joystick ids for the first valid one
for (joy_id=0 ; joy_id<numdevs ; joy_id++)
{
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = JOY_RETURNCENTERED;
if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
break;
}
// abort startup if we didn't find a valid joystick
if (mmr != JOYERR_NOERROR)
{
Com_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
return;
}
// get the capabilities of the selected joystick
// abort startup if command fails
memset (&jc, 0, sizeof(jc));
if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
{
Com_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr);
return;
}
// save the joystick's number of buttons and POV status
joy_numbuttons = jc.wNumButtons;
joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
// old button and POV states default to no buttons pressed
joy_oldbuttonstate = joy_oldpovstate = 0;
// mark the joystick as available and advanced initialization not completed
// this is needed as cvars are not available during initialization
joy_avail = true;
joy_advancedinit = false;
Com_Printf ("\njoystick detected\n\n");
}
/*
===========
RawValuePointer
===========
*/
PDWORD RawValuePointer (int axis)
{
switch (axis)
{
case JOY_AXIS_X:
return &ji.dwXpos;
case JOY_AXIS_Y:
return &ji.dwYpos;
case JOY_AXIS_Z:
return &ji.dwZpos;
case JOY_AXIS_R:
return &ji.dwRpos;
case JOY_AXIS_U:
return &ji.dwUpos;
case JOY_AXIS_V:
return &ji.dwVpos;
}
}
/*
===========
Joy_AdvancedUpdate_f
===========
*/
void Joy_AdvancedUpdate_f (void)
{
// called once by IN_ReadJoystick and by user whenever an update is needed
// cvars are now available
int i;
DWORD dwTemp;
// initialize all the maps
for (i = 0; i < JOY_MAX_AXES; i++)
{
dwAxisMap[i] = AxisNada;
dwControlMap[i] = JOY_ABSOLUTE_AXIS;
pdwRawValue[i] = RawValuePointer(i);
}
if( joy_advanced->value == 0.0)
{
// default joystick initialization
// 2 axes only with joystick control
dwAxisMap[JOY_AXIS_X] = AxisTurn;
// dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
dwAxisMap[JOY_AXIS_Y] = AxisForward;
// dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
}
else
{
if (strcmp (joy_name->string, "joystick") != 0)
{
// notify user of advanced controller
Com_Printf ("\n%s configured\n\n", joy_name->string);
}
// advanced initialization here
// data supplied by user via joy_axisn cvars
dwTemp = (DWORD) joy_advaxisx->value;
dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisy->value;
dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisz->value;
dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisr->value;
dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisu->value;
dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
dwTemp = (DWORD) joy_advaxisv->value;
dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
}
// compute the axes to collect from DirectInput
joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
for (i = 0; i < JOY_MAX_AXES; i++)
{
if (dwAxisMap[i] != AxisNada)
{
joy_flags |= dwAxisFlags[i];
}
}
}
/*
===========
IN_Commands
===========
*/
void IN_Commands (void)
{
int i, key_index;
DWORD buttonstate, povstate;
if (!joy_avail)
{
return;
}
// loop through the joystick buttons
// key a joystick event or auxillary event for higher number buttons for each state change
buttonstate = ji.dwButtons;
for (i=0 ; i < joy_numbuttons ; i++)
{
if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (key_index + i, true, 0);
}
if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
{
key_index = (i < 4) ? K_JOY1 : K_AUX1;
Key_Event (key_index + i, false, 0);
}
}
joy_oldbuttonstate = buttonstate;
if (joy_haspov)
{
// convert POV information into 4 bits of state information
// this avoids any potential problems related to moving from one
// direction to another without going through the center position
povstate = 0;
if(ji.dwPOV != JOY_POVCENTERED)
{
if (ji.dwPOV == JOY_POVFORWARD)
povstate |= 0x01;
if (ji.dwPOV == JOY_POVRIGHT)
povstate |= 0x02;
if (ji.dwPOV == JOY_POVBACKWARD)
povstate |= 0x04;
if (ji.dwPOV == JOY_POVLEFT)
povstate |= 0x08;
}
// determine which bits have changed and key an auxillary event for each change
for (i=0 ; i < 4 ; i++)
{
if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
{
Key_Event (K_AUX29 + i, true, 0);
}
if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
{
Key_Event (K_AUX29 + i, false, 0);
}
}
joy_oldpovstate = povstate;
}
}
/*
===============
IN_ReadJoystick
===============
*/
qboolean IN_ReadJoystick (void)
{
memset (&ji, 0, sizeof(ji));
ji.dwSize = sizeof(ji);
ji.dwFlags = joy_flags;
if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
{
return true;
}
else
{
// read error occurred
// turning off the joystick seems too harsh for 1 read error,\
// but what should be done?
// Com_Printf ("IN_ReadJoystick: no response\n");
// joy_avail = false;
return false;
}
}
/*
===========
IN_JoyMove
===========
*/
void IN_JoyMove (usercmd_t *cmd)
{
float speed, aspeed;
float fAxisValue;
int i;
// complete initialization if first time in
// this is needed as cvars are not available at initialization time
if( joy_advancedinit != true )
{
Joy_AdvancedUpdate_f();
joy_advancedinit = true;
}
// verify joystick is available and that the user wants to use it
if (!joy_avail || !in_joystick->value)
{
return;
}
// collect the joystick data, if possible
if (IN_ReadJoystick () != true)
{
return;
}
if ( (in_speed.state & 1) ^ (int)cl_run->value)
speed = 2;
else
speed = 1;
aspeed = speed * cls.frametime;
// loop through the axes
for (i = 0; i < JOY_MAX_AXES; i++)
{
// get the floating point zero-centered, potentially-inverted data for the current axis
fAxisValue = (float) *pdwRawValue[i];
// move centerpoint to zero
fAxisValue -= 32768.0;
// convert range from -32768..32767 to -1..1
fAxisValue /= 32768.0;
switch (dwAxisMap[i])
{
case AxisForward:
if ((joy_advanced->value == 0.0) && mlooking)
{
// user wants forward control to become look control
if (fabs(fAxisValue) > joy_pitchthreshold->value)
{
// if mouse invert is on, invert the joystick pitch value
// only absolute control support here (joy_advanced is false)
if (m_pitch->value < 0.0)
{
cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
else
{
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
}
}
else
{
// user wants forward control to be forward control
if (fabs(fAxisValue) > joy_forwardthreshold->value)
{
cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value;
}
}
break;
case AxisSide:
if (fabs(fAxisValue) > joy_sidethreshold->value)
{
cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
}
break;
case AxisUp:
if (fabs(fAxisValue) > joy_upthreshold->value)
{
cmd->upmove += (fAxisValue * joy_upsensitivity->value) * speed * cl_upspeed->value;
}
break;
case AxisTurn:
if ((in_strafe.state & 1) || (lookstrafe->value && mlooking))
{
// user wants turn control to become side control
if (fabs(fAxisValue) > joy_sidethreshold->value)
{
cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value;
}
}
else
{
// user wants turn control to be turn control
if (fabs(fAxisValue) > joy_yawthreshold->value)
{
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value;
}
else
{
cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0;
}
}
}
break;
case AxisLook:
if (mlooking)
{
if (fabs(fAxisValue) > joy_pitchthreshold->value)
{
// pitch movement detected and pitch movement desired by user
if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
{
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value;
}
else
{
cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0;
}
}
}
break;
default:
break;
}
}
}

842
win32/net_wins.c Normal file
View File

@ -0,0 +1,842 @@
/*
Copyright (C) 1997-2001 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.
*/
// net_wins.c
#include "winsock.h"
#include "wsipx.h"
#include "../qcommon/qcommon.h"
#define MAX_LOOPBACK 4
typedef struct
{
byte data[MAX_MSGLEN];
int datalen;
} loopmsg_t;
typedef struct
{
loopmsg_t msgs[MAX_LOOPBACK];
int get, send;
} loopback_t;
cvar_t *net_shownet;
static cvar_t *noudp;
static cvar_t *noipx;
loopback_t loopbacks[2];
int ip_sockets[2];
int ipx_sockets[2];
char *NET_ErrorString (void);
//=============================================================================
void NetadrToSockadr (netadr_t *a, struct sockaddr *s)
{
memset (s, 0, sizeof(*s));
if (a->type == NA_BROADCAST)
{
((struct sockaddr_in *)s)->sin_family = AF_INET;
((struct sockaddr_in *)s)->sin_port = a->port;
((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST;
}
else if (a->type == NA_IP)
{
((struct sockaddr_in *)s)->sin_family = AF_INET;
((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip;
((struct sockaddr_in *)s)->sin_port = a->port;
}
else if (a->type == NA_IPX)
{
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
memcpy(((struct sockaddr_ipx *)s)->sa_netnum, &a->ipx[0], 4);
memcpy(((struct sockaddr_ipx *)s)->sa_nodenum, &a->ipx[4], 6);
((struct sockaddr_ipx *)s)->sa_socket = a->port;
}
else if (a->type == NA_BROADCAST_IPX)
{
((struct sockaddr_ipx *)s)->sa_family = AF_IPX;
memset(((struct sockaddr_ipx *)s)->sa_netnum, 0, 4);
memset(((struct sockaddr_ipx *)s)->sa_nodenum, 0xff, 6);
((struct sockaddr_ipx *)s)->sa_socket = a->port;
}
}
void SockadrToNetadr (struct sockaddr *s, netadr_t *a)
{
if (s->sa_family == AF_INET)
{
a->type = NA_IP;
*(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr;
a->port = ((struct sockaddr_in *)s)->sin_port;
}
else if (s->sa_family == AF_IPX)
{
a->type = NA_IPX;
memcpy(&a->ipx[0], ((struct sockaddr_ipx *)s)->sa_netnum, 4);
memcpy(&a->ipx[4], ((struct sockaddr_ipx *)s)->sa_nodenum, 6);
a->port = ((struct sockaddr_ipx *)s)->sa_socket;
}
}
qboolean NET_CompareAdr (netadr_t a, netadr_t b)
{
if (a.type != b.type)
return false;
if (a.type == NA_LOOPBACK)
return TRUE;
if (a.type == NA_IP)
{
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3] && a.port == b.port)
return true;
return false;
}
if (a.type == NA_IPX)
{
if ((memcmp(a.ipx, b.ipx, 10) == 0) && a.port == b.port)
return true;
return false;
}
}
/*
===================
NET_CompareBaseAdr
Compares without the port
===================
*/
qboolean NET_CompareBaseAdr (netadr_t a, netadr_t b)
{
if (a.type != b.type)
return false;
if (a.type == NA_LOOPBACK)
return TRUE;
if (a.type == NA_IP)
{
if (a.ip[0] == b.ip[0] && a.ip[1] == b.ip[1] && a.ip[2] == b.ip[2] && a.ip[3] == b.ip[3])
return true;
return false;
}
if (a.type == NA_IPX)
{
if ((memcmp(a.ipx, b.ipx, 10) == 0))
return true;
return false;
}
}
char *NET_AdrToString (netadr_t a)
{
static char s[64];
if (a.type == NA_LOOPBACK)
Com_sprintf (s, sizeof(s), "loopback");
else if (a.type == NA_IP)
Com_sprintf (s, sizeof(s), "%i.%i.%i.%i:%i", a.ip[0], a.ip[1], a.ip[2], a.ip[3], ntohs(a.port));
else
Com_sprintf (s, sizeof(s), "%02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%i", a.ipx[0], a.ipx[1], a.ipx[2], a.ipx[3], a.ipx[4], a.ipx[5], a.ipx[6], a.ipx[7], a.ipx[8], a.ipx[9], ntohs(a.port));
return s;
}
/*
=============
NET_StringToAdr
localhost
idnewt
idnewt:28000
192.246.40.70
192.246.40.70:28000
=============
*/
#define DO(src,dest) \
copy[0] = s[src]; \
copy[1] = s[src + 1]; \
sscanf (copy, "%x", &val); \
((struct sockaddr_ipx *)sadr)->dest = val
qboolean NET_StringToSockaddr (char *s, struct sockaddr *sadr)
{
struct hostent *h;
char *colon;
int val;
char copy[128];
memset (sadr, 0, sizeof(*sadr));
if ((strlen(s) >= 23) && (s[8] == ':') && (s[21] == ':')) // check for an IPX address
{
((struct sockaddr_ipx *)sadr)->sa_family = AF_IPX;
copy[2] = 0;
DO(0, sa_netnum[0]);
DO(2, sa_netnum[1]);
DO(4, sa_netnum[2]);
DO(6, sa_netnum[3]);
DO(9, sa_nodenum[0]);
DO(11, sa_nodenum[1]);
DO(13, sa_nodenum[2]);
DO(15, sa_nodenum[3]);
DO(17, sa_nodenum[4]);
DO(19, sa_nodenum[5]);
sscanf (&s[22], "%u", &val);
((struct sockaddr_ipx *)sadr)->sa_socket = htons((unsigned short)val);
}
else
{
((struct sockaddr_in *)sadr)->sin_family = AF_INET;
((struct sockaddr_in *)sadr)->sin_port = 0;
strcpy (copy, s);
// strip off a trailing :port if present
for (colon = copy ; *colon ; colon++)
if (*colon == ':')
{
*colon = 0;
((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1));
}
if (copy[0] >= '0' && copy[0] <= '9')
{
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy);
}
else
{
if (! (h = gethostbyname(copy)) )
return 0;
*(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0];
}
}
return true;
}
#undef DO
/*
=============
NET_StringToAdr
localhost
idnewt
idnewt:28000
192.246.40.70
192.246.40.70:28000
=============
*/
qboolean NET_StringToAdr (char *s, netadr_t *a)
{
struct sockaddr sadr;
if (!strcmp (s, "localhost"))
{
memset (a, 0, sizeof(*a));
a->type = NA_LOOPBACK;
return true;
}
if (!NET_StringToSockaddr (s, &sadr))
return false;
SockadrToNetadr (&sadr, a);
return true;
}
qboolean NET_IsLocalAddress (netadr_t adr)
{
return adr.type == NA_LOOPBACK;
}
/*
=============================================================================
LOOPBACK BUFFERS FOR LOCAL PLAYER
=============================================================================
*/
qboolean NET_GetLoopPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
{
int i;
loopback_t *loop;
loop = &loopbacks[sock];
if (loop->send - loop->get > MAX_LOOPBACK)
loop->get = loop->send - MAX_LOOPBACK;
if (loop->get >= loop->send)
return false;
i = loop->get & (MAX_LOOPBACK-1);
loop->get++;
memcpy (net_message->data, loop->msgs[i].data, loop->msgs[i].datalen);
net_message->cursize = loop->msgs[i].datalen;
memset (net_from, 0, sizeof(*net_from));
net_from->type = NA_LOOPBACK;
return true;
}
void NET_SendLoopPacket (netsrc_t sock, int length, void *data, netadr_t to)
{
int i;
loopback_t *loop;
loop = &loopbacks[sock^1];
i = loop->send & (MAX_LOOPBACK-1);
loop->send++;
memcpy (loop->msgs[i].data, data, length);
loop->msgs[i].datalen = length;
}
//=============================================================================
qboolean NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message)
{
int ret;
struct sockaddr from;
int fromlen;
int net_socket;
int protocol;
int err;
if (NET_GetLoopPacket (sock, net_from, net_message))
return true;
for (protocol = 0 ; protocol < 2 ; protocol++)
{
if (protocol == 0)
net_socket = ip_sockets[sock];
else
net_socket = ipx_sockets[sock];
if (!net_socket)
continue;
fromlen = sizeof(from);
ret = recvfrom (net_socket, net_message->data, net_message->maxsize
, 0, (struct sockaddr *)&from, &fromlen);
if (ret == -1)
{
err = WSAGetLastError();
if (err == WSAEWOULDBLOCK)
continue;
if (dedicated->value) // let dedicated servers continue after errors
Com_Printf ("NET_GetPacket: %s", NET_ErrorString());
else
Com_Error (ERR_DROP, "NET_GetPacket: %s", NET_ErrorString());
continue;
}
SockadrToNetadr (&from, net_from);
if (ret == net_message->maxsize)
{
Com_Printf ("Oversize packet from %s\n", NET_AdrToString (*net_from));
continue;
}
net_message->cursize = ret;
return true;
}
return false;
}
//=============================================================================
void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to)
{
int ret;
struct sockaddr addr;
int net_socket;
if ( to.type == NA_LOOPBACK )
{
NET_SendLoopPacket (sock, length, data, to);
return;
}
if (to.type == NA_BROADCAST)
{
net_socket = ip_sockets[sock];
if (!net_socket)
return;
}
else if (to.type == NA_IP)
{
net_socket = ip_sockets[sock];
if (!net_socket)
return;
}
else if (to.type == NA_IPX)
{
net_socket = ipx_sockets[sock];
if (!net_socket)
return;
}
else if (to.type == NA_BROADCAST_IPX)
{
net_socket = ipx_sockets[sock];
if (!net_socket)
return;
}
else
Com_Error (ERR_FATAL, "NET_SendPacket: bad address type");
NetadrToSockadr (&to, &addr);
ret = sendto (net_socket, data, length, 0, &addr, sizeof(addr) );
if (ret == -1)
{
int err = WSAGetLastError();
// wouldblock is silent
if (err == WSAEWOULDBLOCK)
return;
// some PPP links dont allow broadcasts
if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX)))
return;
if (dedicated->value) // let dedicated servers continue after errors
{
Com_Printf ("NET_SendPacket ERROR: %s\n", NET_ErrorString());
}
else
{
if (err == WSAEADDRNOTAVAIL)
{
Com_DPrintf ("NET_SendPacket Warning: %s : %s\n", NET_ErrorString(), NET_AdrToString (to));
}
else
{
Com_Error (ERR_DROP, "NET_SendPacket ERROR: %s\n", NET_ErrorString());
}
}
}
}
//=============================================================================
/*
====================
NET_Socket
====================
*/
int NET_IPSocket (char *net_interface, int port)
{
int newsocket;
struct sockaddr_in address;
qboolean _true = true;
int i = 1;
int err;
if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
err = WSAGetLastError();
if (err != WSAEAFNOSUPPORT)
Com_Printf ("WARNING: UDP_OpenSocket: socket: %s", NET_ErrorString());
return 0;
}
// make it non-blocking
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
{
Com_Printf ("WARNING: UDP_OpenSocket: ioctl FIONBIO: %s\n", NET_ErrorString());
return 0;
}
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) == -1)
{
Com_Printf ("WARNING: UDP_OpenSocket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
return 0;
}
if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost"))
address.sin_addr.s_addr = INADDR_ANY;
else
NET_StringToSockaddr (net_interface, (struct sockaddr *)&address);
if (port == PORT_ANY)
address.sin_port = 0;
else
address.sin_port = htons((short)port);
address.sin_family = AF_INET;
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
{
Com_Printf ("WARNING: UDP_OpenSocket: bind: %s\n", NET_ErrorString());
closesocket (newsocket);
return 0;
}
return newsocket;
}
/*
====================
NET_OpenIP
====================
*/
void NET_OpenIP (void)
{
cvar_t *ip;
int port;
int dedicated;
ip = Cvar_Get ("ip", "localhost", CVAR_NOSET);
dedicated = Cvar_VariableValue ("dedicated");
if (!ip_sockets[NS_SERVER])
{
port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
}
}
ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port);
if (!ip_sockets[NS_SERVER] && dedicated)
Com_Error (ERR_FATAL, "Couldn't allocate dedicated server IP port");
}
// dedicated servers don't need client ports
if (dedicated)
return;
if (!ip_sockets[NS_CLIENT])
{
port = Cvar_Get("ip_clientport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
if (!port)
port = PORT_ANY;
}
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, port);
if (!ip_sockets[NS_CLIENT])
ip_sockets[NS_CLIENT] = NET_IPSocket (ip->string, PORT_ANY);
}
}
/*
====================
IPX_Socket
====================
*/
int NET_IPXSocket (int port)
{
int newsocket;
struct sockaddr_ipx address;
int _true = 1;
int err;
if ((newsocket = socket (PF_IPX, SOCK_DGRAM, NSPROTO_IPX)) == -1)
{
err = WSAGetLastError();
if (err != WSAEAFNOSUPPORT)
Com_Printf ("WARNING: IPX_Socket: socket: %s\n", NET_ErrorString());
return 0;
}
// make it non-blocking
if (ioctlsocket (newsocket, FIONBIO, &_true) == -1)
{
Com_Printf ("WARNING: IPX_Socket: ioctl FIONBIO: %s\n", NET_ErrorString());
return 0;
}
// make it broadcast capable
if (setsockopt(newsocket, SOL_SOCKET, SO_BROADCAST, (char *)&_true, sizeof(_true)) == -1)
{
Com_Printf ("WARNING: IPX_Socket: setsockopt SO_BROADCAST: %s\n", NET_ErrorString());
return 0;
}
address.sa_family = AF_IPX;
memset (address.sa_netnum, 0, 4);
memset (address.sa_nodenum, 0, 6);
if (port == PORT_ANY)
address.sa_socket = 0;
else
address.sa_socket = htons((short)port);
if( bind (newsocket, (void *)&address, sizeof(address)) == -1)
{
Com_Printf ("WARNING: IPX_Socket: bind: %s\n", NET_ErrorString());
closesocket (newsocket);
return 0;
}
return newsocket;
}
/*
====================
NET_OpenIPX
====================
*/
void NET_OpenIPX (void)
{
int port;
int dedicated;
dedicated = Cvar_VariableValue ("dedicated");
if (!ipx_sockets[NS_SERVER])
{
port = Cvar_Get("ipx_hostport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("hostport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("port", va("%i", PORT_SERVER), CVAR_NOSET)->value;
}
}
ipx_sockets[NS_SERVER] = NET_IPXSocket (port);
}
// dedicated servers don't need client ports
if (dedicated)
return;
if (!ipx_sockets[NS_CLIENT])
{
port = Cvar_Get("ipx_clientport", "0", CVAR_NOSET)->value;
if (!port)
{
port = Cvar_Get("clientport", va("%i", PORT_CLIENT), CVAR_NOSET)->value;
if (!port)
port = PORT_ANY;
}
ipx_sockets[NS_CLIENT] = NET_IPXSocket (port);
if (!ipx_sockets[NS_CLIENT])
ipx_sockets[NS_CLIENT] = NET_IPXSocket (PORT_ANY);
}
}
/*
====================
NET_Config
A single player game will only use the loopback code
====================
*/
void NET_Config (qboolean multiplayer)
{
int i;
static qboolean old_config;
if (old_config == multiplayer)
return;
old_config = multiplayer;
if (!multiplayer)
{ // shut down any existing sockets
for (i=0 ; i<2 ; i++)
{
if (ip_sockets[i])
{
closesocket (ip_sockets[i]);
ip_sockets[i] = 0;
}
if (ipx_sockets[i])
{
closesocket (ipx_sockets[i]);
ipx_sockets[i] = 0;
}
}
}
else
{ // open sockets
if (! noudp->value)
NET_OpenIP ();
if (! noipx->value)
NET_OpenIPX ();
}
}
// sleeps msec or until net socket is ready
void NET_Sleep(int msec)
{
struct timeval timeout;
fd_set fdset;
extern cvar_t *dedicated;
int i;
if (!dedicated || !dedicated->value)
return; // we're not a server, just run full speed
FD_ZERO(&fdset);
i = 0;
if (ip_sockets[NS_SERVER]) {
FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket
i = ip_sockets[NS_SERVER];
}
if (ipx_sockets[NS_SERVER]) {
FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket
if (ipx_sockets[NS_SERVER] > i)
i = ipx_sockets[NS_SERVER];
}
timeout.tv_sec = msec/1000;
timeout.tv_usec = (msec%1000)*1000;
select(i+1, &fdset, NULL, NULL, &timeout);
}
//===================================================================
static WSADATA winsockdata;
/*
====================
NET_Init
====================
*/
void NET_Init (void)
{
WORD wVersionRequested;
int r;
wVersionRequested = MAKEWORD(1, 1);
r = WSAStartup (MAKEWORD(1, 1), &winsockdata);
if (r)
Com_Error (ERR_FATAL,"Winsock initialization failed.");
Com_Printf("Winsock Initialized\n");
noudp = Cvar_Get ("noudp", "0", CVAR_NOSET);
noipx = Cvar_Get ("noipx", "0", CVAR_NOSET);
net_shownet = Cvar_Get ("net_shownet", "0", 0);
}
/*
====================
NET_Shutdown
====================
*/
void NET_Shutdown (void)
{
NET_Config (false); // close sockets
WSACleanup ();
}
/*
====================
NET_ErrorString
====================
*/
char *NET_ErrorString (void)
{
int code;
code = WSAGetLastError ();
switch (code)
{
case WSAEINTR: return "WSAEINTR";
case WSAEBADF: return "WSAEBADF";
case WSAEACCES: return "WSAEACCES";
case WSAEDISCON: return "WSAEDISCON";
case WSAEFAULT: return "WSAEFAULT";
case WSAEINVAL: return "WSAEINVAL";
case WSAEMFILE: return "WSAEMFILE";
case WSAEWOULDBLOCK: return "WSAEWOULDBLOCK";
case WSAEINPROGRESS: return "WSAEINPROGRESS";
case WSAEALREADY: return "WSAEALREADY";
case WSAENOTSOCK: return "WSAENOTSOCK";
case WSAEDESTADDRREQ: return "WSAEDESTADDRREQ";
case WSAEMSGSIZE: return "WSAEMSGSIZE";
case WSAEPROTOTYPE: return "WSAEPROTOTYPE";
case WSAENOPROTOOPT: return "WSAENOPROTOOPT";
case WSAEPROTONOSUPPORT: return "WSAEPROTONOSUPPORT";
case WSAESOCKTNOSUPPORT: return "WSAESOCKTNOSUPPORT";
case WSAEOPNOTSUPP: return "WSAEOPNOTSUPP";
case WSAEPFNOSUPPORT: return "WSAEPFNOSUPPORT";
case WSAEAFNOSUPPORT: return "WSAEAFNOSUPPORT";
case WSAEADDRINUSE: return "WSAEADDRINUSE";
case WSAEADDRNOTAVAIL: return "WSAEADDRNOTAVAIL";
case WSAENETDOWN: return "WSAENETDOWN";
case WSAENETUNREACH: return "WSAENETUNREACH";
case WSAENETRESET: return "WSAENETRESET";
case WSAECONNABORTED: return "WSWSAECONNABORTEDAEINTR";
case WSAECONNRESET: return "WSAECONNRESET";
case WSAENOBUFS: return "WSAENOBUFS";
case WSAEISCONN: return "WSAEISCONN";
case WSAENOTCONN: return "WSAENOTCONN";
case WSAESHUTDOWN: return "WSAESHUTDOWN";
case WSAETOOMANYREFS: return "WSAETOOMANYREFS";
case WSAETIMEDOUT: return "WSAETIMEDOUT";
case WSAECONNREFUSED: return "WSAECONNREFUSED";
case WSAELOOP: return "WSAELOOP";
case WSAENAMETOOLONG: return "WSAENAMETOOLONG";
case WSAEHOSTDOWN: return "WSAEHOSTDOWN";
case WSASYSNOTREADY: return "WSASYSNOTREADY";
case WSAVERNOTSUPPORTED: return "WSAVERNOTSUPPORTED";
case WSANOTINITIALISED: return "WSANOTINITIALISED";
case WSAHOST_NOT_FOUND: return "WSAHOST_NOT_FOUND";
case WSATRY_AGAIN: return "WSATRY_AGAIN";
case WSANO_RECOVERY: return "WSANO_RECOVERY";
case WSANO_DATA: return "WSANO_DATA";
default: return "NO ERROR";
}
}

BIN
win32/q2.aps Normal file

Binary file not shown.

BIN
win32/q2.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

72
win32/q2.rc Normal file
View File

@ -0,0 +1,72 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON DISCARDABLE "q2.ico"
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

215
win32/q_shwin.c Normal file
View File

@ -0,0 +1,215 @@
/*
Copyright (C) 1997-2001 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.
*/
#include "../qcommon/qcommon.h"
#include "winquake.h"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <direct.h>
#include <io.h>
#include <conio.h>
//===============================================================================
int hunkcount;
byte *membase;
int hunkmaxsize;
int cursize;
#define VIRTUAL_ALLOC
void *Hunk_Begin (int maxsize)
{
// reserve a huge chunk of memory, but don't commit any yet
cursize = 0;
hunkmaxsize = maxsize;
#ifdef VIRTUAL_ALLOC
membase = VirtualAlloc (NULL, maxsize, MEM_RESERVE, PAGE_NOACCESS);
#else
membase = malloc (maxsize);
memset (membase, 0, maxsize);
#endif
if (!membase)
Sys_Error ("VirtualAlloc reserve failed");
return (void *)membase;
}
void *Hunk_Alloc (int size)
{
void *buf;
// round to cacheline
size = (size+31)&~31;
#ifdef VIRTUAL_ALLOC
// commit pages as needed
// buf = VirtualAlloc (membase+cursize, size, MEM_COMMIT, PAGE_READWRITE);
buf = VirtualAlloc (membase, cursize+size, MEM_COMMIT, PAGE_READWRITE);
if (!buf)
{
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buf, 0, NULL);
Sys_Error ("VirtualAlloc commit failed.\n%s", buf);
}
#endif
cursize += size;
if (cursize > hunkmaxsize)
Sys_Error ("Hunk_Alloc overflow");
return (void *)(membase+cursize-size);
}
int Hunk_End (void)
{
// free the remaining unused virtual memory
#if 0
void *buf;
// write protect it
buf = VirtualAlloc (membase, cursize, MEM_COMMIT, PAGE_READONLY);
if (!buf)
Sys_Error ("VirtualAlloc commit failed");
#endif
hunkcount++;
//Com_Printf ("hunkcount: %i\n", hunkcount);
return cursize;
}
void Hunk_Free (void *base)
{
if ( base )
#ifdef VIRTUAL_ALLOC
VirtualFree (base, 0, MEM_RELEASE);
#else
free (base);
#endif
hunkcount--;
}
//===============================================================================
/*
================
Sys_Milliseconds
================
*/
int curtime;
int Sys_Milliseconds (void)
{
static int base;
static qboolean initialized = false;
if (!initialized)
{ // let base retain 16 bits of effectively random data
base = timeGetTime() & 0xffff0000;
initialized = true;
}
curtime = timeGetTime() - base;
return curtime;
}
void Sys_Mkdir (char *path)
{
_mkdir (path);
}
//============================================
char findbase[MAX_OSPATH];
char findpath[MAX_OSPATH];
int findhandle;
static qboolean CompareAttributes( unsigned found, unsigned musthave, unsigned canthave )
{
if ( ( found & _A_RDONLY ) && ( canthave & SFF_RDONLY ) )
return false;
if ( ( found & _A_HIDDEN ) && ( canthave & SFF_HIDDEN ) )
return false;
if ( ( found & _A_SYSTEM ) && ( canthave & SFF_SYSTEM ) )
return false;
if ( ( found & _A_SUBDIR ) && ( canthave & SFF_SUBDIR ) )
return false;
if ( ( found & _A_ARCH ) && ( canthave & SFF_ARCH ) )
return false;
if ( ( musthave & SFF_RDONLY ) && !( found & _A_RDONLY ) )
return false;
if ( ( musthave & SFF_HIDDEN ) && !( found & _A_HIDDEN ) )
return false;
if ( ( musthave & SFF_SYSTEM ) && !( found & _A_SYSTEM ) )
return false;
if ( ( musthave & SFF_SUBDIR ) && !( found & _A_SUBDIR ) )
return false;
if ( ( musthave & SFF_ARCH ) && !( found & _A_ARCH ) )
return false;
return true;
}
char *Sys_FindFirst (char *path, unsigned musthave, unsigned canthave )
{
struct _finddata_t findinfo;
if (findhandle)
Sys_Error ("Sys_BeginFind without close");
findhandle = 0;
COM_FilePath (path, findbase);
findhandle = _findfirst (path, &findinfo);
if (findhandle == -1)
return NULL;
if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
return NULL;
Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
return findpath;
}
char *Sys_FindNext ( unsigned musthave, unsigned canthave )
{
struct _finddata_t findinfo;
if (findhandle == -1)
return NULL;
if (_findnext (findhandle, &findinfo) == -1)
return NULL;
if ( !CompareAttributes( findinfo.attrib, musthave, canthave ) )
return NULL;
Com_sprintf (findpath, sizeof(findpath), "%s/%s", findbase, findinfo.name);
return findpath;
}
void Sys_FindClose (void)
{
if (findhandle != -1)
_findclose (findhandle);
findhandle = 0;
}
//============================================

BIN
win32/qe3.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

4133
win32/qgl_win.c Normal file

File diff suppressed because it is too large Load Diff

16
win32/resource.h Normal file
View File

@ -0,0 +1,16 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by q2.rc
//
#define IDI_ICON1 101
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

556
win32/rw_ddraw.c Normal file
View File

@ -0,0 +1,556 @@
/*
Copyright (C) 1997-2001 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.
*/
/*
** RW_DDRAW.C
**
** This handles DirecTDraw management under Windows.
*/
#ifndef _WIN32
# error You should not be compiling this file on this platform
#endif
#include <float.h>
#include "..\ref_soft\r_local.h"
#define INITGUID
#include "rw_win.h"
static const char *DDrawError( int code );
/*
** DDRAW_Init
**
** Builds our DDRAW stuff
*/
qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch )
{
HRESULT ddrval;
DDSURFACEDESC ddsd;
DDSCAPS ddscaps;
PALETTEENTRY palentries[256];
int i;
extern cvar_t *sw_allow_modex;
HRESULT (WINAPI *QDirectDrawCreate)( GUID FAR *lpGUID, LPDIRECTDRAW FAR * lplpDDRAW, IUnknown FAR * pUnkOuter );
ri.Con_Printf( PRINT_ALL, "Initializing DirectDraw\n");
for ( i = 0; i < 256; i++ )
{
palentries[i].peRed = ( d_8to24table[i] >> 0 ) & 0xff;
palentries[i].peGreen = ( d_8to24table[i] >> 8 ) & 0xff;
palentries[i].peBlue = ( d_8to24table[i] >> 16 ) & 0xff;
}
/*
** load DLL and fetch pointer to entry point
*/
if ( !sww_state.hinstDDRAW )
{
ri.Con_Printf( PRINT_ALL, "...loading DDRAW.DLL: ");
if ( ( sww_state.hinstDDRAW = LoadLibrary( "ddraw.dll" ) ) == NULL )
{
ri.Con_Printf( PRINT_ALL, "failed\n" );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
}
if ( ( QDirectDrawCreate = ( HRESULT (WINAPI *)( GUID FAR *, LPDIRECTDRAW FAR *, IUnknown FAR * ) ) GetProcAddress( sww_state.hinstDDRAW, "DirectDrawCreate" ) ) == NULL )
{
ri.Con_Printf( PRINT_ALL, "*** DirectDrawCreate == NULL ***\n" );
goto fail;
}
/*
** create the direct draw object
*/
ri.Con_Printf( PRINT_ALL, "...creating DirectDraw object: ");
if ( ( ddrval = QDirectDrawCreate( NULL, &sww_state.lpDirectDraw, NULL ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
/*
** see if linear modes exist first
*/
sww_state.modex = false;
ri.Con_Printf( PRINT_ALL, "...setting exclusive mode: ");
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
sww_state.hWnd,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n",DDrawError (ddrval) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
/*
** try changing the display mode normally
*/
ri.Con_Printf( PRINT_ALL, "...finding display mode\n" );
ri.Con_Printf( PRINT_ALL, "...setting linear mode: " );
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) == DD_OK )
{
ri.Con_Printf( PRINT_ALL, "ok\n" );
}
/*
** if no linear mode found, go for modex if we're trying 320x240
*/
else if ( ( sw_mode->value == 0 ) && sw_allow_modex->value )
{
ri.Con_Printf( PRINT_ALL, "failed\n" );
ri.Con_Printf( PRINT_ALL, "...attempting ModeX 320x240: ");
/*
** reset to normal cooperative level
*/
sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
sww_state.hWnd,
DDSCL_NORMAL );
/*
** set exclusive mode
*/
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw,
sww_state.hWnd,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_NOWINDOWCHANGES | DDSCL_ALLOWMODEX ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed SCL - %s\n",DDrawError (ddrval) );
goto fail;
}
/*
** change our display mode
*/
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->SetDisplayMode( sww_state.lpDirectDraw, vid.width, vid.height, 8 ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed SDM - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
sww_state.modex = true;
}
else
{
ri.Con_Printf( PRINT_ALL, "failed\n" );
goto fail;
}
/*
** create our front buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
ddsd.dwBackBufferCount = 1;
ri.Con_Printf( PRINT_ALL, "...creating front buffer: ");
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsFrontBuffer, NULL ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
/*
** see if we're a ModeX mode
*/
sww_state.lpddsFrontBuffer->lpVtbl->GetCaps( sww_state.lpddsFrontBuffer, &ddscaps );
if ( ddscaps.dwCaps & DDSCAPS_MODEX )
ri.Con_Printf( PRINT_ALL, "...using ModeX\n" );
/*
** create our back buffer
*/
ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
ri.Con_Printf( PRINT_ALL, "...creating back buffer: " );
if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->GetAttachedSurface( sww_state.lpddsFrontBuffer, &ddsd.ddsCaps, &sww_state.lpddsBackBuffer ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
/*
** create our rendering buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.dwHeight = vid.height;
ddsd.dwWidth = vid.width;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
ri.Con_Printf( PRINT_ALL, "...creating offscreen buffer: " );
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreateSurface( sww_state.lpDirectDraw, &ddsd, &sww_state.lpddsOffScreenBuffer, NULL ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
/*
** create our DIRECTDRAWPALETTE
*/
ri.Con_Printf( PRINT_ALL, "...creating palette: " );
if ( ( ddrval = sww_state.lpDirectDraw->lpVtbl->CreatePalette( sww_state.lpDirectDraw,
DDPCAPS_8BIT | DDPCAPS_ALLOW256,
palentries,
&sww_state.lpddpPalette,
NULL ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
ri.Con_Printf( PRINT_ALL, "...setting palette: " );
if ( ( ddrval = sww_state.lpddsFrontBuffer->lpVtbl->SetPalette( sww_state.lpddsFrontBuffer,
sww_state.lpddpPalette ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
DDRAW_SetPalette( ( const unsigned char * ) sw_state.currentpalette );
/*
** lock the back buffer
*/
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
ri.Con_Printf( PRINT_ALL, "...locking backbuffer: " );
if ( ( ddrval = sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL ) ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "failed - %s\n", DDrawError( ddrval ) );
goto fail;
}
ri.Con_Printf( PRINT_ALL, "ok\n" );
*ppbuffer = ddsd.lpSurface;
*ppitch = ddsd.lPitch;
for ( i = 0; i < vid.height; i++ )
{
memset( *ppbuffer + i * *ppitch, 0, *ppitch );
}
sww_state.palettized = true;
return true;
fail:
ri.Con_Printf( PRINT_ALL, "*** DDraw init failure ***\n" );
DDRAW_Shutdown();
return false;
}
/*
** DDRAW_SetPalette
**
** Sets the color table in our DIB section, and also sets the system palette
** into an identity mode if we're running in an 8-bit palettized display mode.
**
** The palette is expected to be 1024 bytes, in the format:
**
** R = offset 0
** G = offset 1
** B = offset 2
** A = offset 3
*/
void DDRAW_SetPalette( const unsigned char *pal )
{
PALETTEENTRY palentries[256];
int i;
if (!sww_state.lpddpPalette)
return;
for ( i = 0; i < 256; i++, pal += 4 )
{
palentries[i].peRed = pal[0];
palentries[i].peGreen = pal[1];
palentries[i].peBlue = pal[2];
palentries[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
}
if ( sww_state.lpddpPalette->lpVtbl->SetEntries( sww_state.lpddpPalette,
0,
0,
256,
palentries ) != DD_OK )
{
ri.Con_Printf( PRINT_ALL, "DDRAW_SetPalette() - SetEntries failed\n" );
}
}
/*
** DDRAW_Shutdown
*/
void DDRAW_Shutdown( void )
{
if ( sww_state.lpddsOffScreenBuffer )
{
ri.Con_Printf( PRINT_ALL, "...releasing offscreen buffer\n");
sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer );
sww_state.lpddsOffScreenBuffer->lpVtbl->Release( sww_state.lpddsOffScreenBuffer );
sww_state.lpddsOffScreenBuffer = NULL;
}
if ( sww_state.lpddsBackBuffer )
{
ri.Con_Printf( PRINT_ALL, "...releasing back buffer\n");
sww_state.lpddsBackBuffer->lpVtbl->Release( sww_state.lpddsBackBuffer );
sww_state.lpddsBackBuffer = NULL;
}
if ( sww_state.lpddsFrontBuffer )
{
ri.Con_Printf( PRINT_ALL, "...releasing front buffer\n");
sww_state.lpddsFrontBuffer->lpVtbl->Release( sww_state.lpddsFrontBuffer );
sww_state.lpddsFrontBuffer = NULL;
}
if (sww_state.lpddpPalette)
{
ri.Con_Printf( PRINT_ALL, "...releasing palette\n");
sww_state.lpddpPalette->lpVtbl->Release ( sww_state.lpddpPalette );
sww_state.lpddpPalette = NULL;
}
if ( sww_state.lpDirectDraw )
{
ri.Con_Printf( PRINT_ALL, "...restoring display mode\n");
sww_state.lpDirectDraw->lpVtbl->RestoreDisplayMode( sww_state.lpDirectDraw );
ri.Con_Printf( PRINT_ALL, "...restoring normal coop mode\n");
sww_state.lpDirectDraw->lpVtbl->SetCooperativeLevel( sww_state.lpDirectDraw, sww_state.hWnd, DDSCL_NORMAL );
ri.Con_Printf( PRINT_ALL, "...releasing lpDirectDraw\n");
sww_state.lpDirectDraw->lpVtbl->Release( sww_state.lpDirectDraw );
sww_state.lpDirectDraw = NULL;
}
if ( sww_state.hinstDDRAW )
{
ri.Con_Printf( PRINT_ALL, "...freeing library\n");
FreeLibrary( sww_state.hinstDDRAW );
sww_state.hinstDDRAW = NULL;
}
}
static const char *DDrawError (int code)
{
switch(code) {
case DD_OK:
return "DD_OK";
case DDERR_ALREADYINITIALIZED:
return "DDERR_ALREADYINITIALIZED";
case DDERR_BLTFASTCANTCLIP:
return "DDERR_BLTFASTCANTCLIP";
case DDERR_CANNOTATTACHSURFACE:
return "DDER_CANNOTATTACHSURFACE";
case DDERR_CANNOTDETACHSURFACE:
return "DDERR_CANNOTDETACHSURFACE";
case DDERR_CANTCREATEDC:
return "DDERR_CANTCREATEDC";
case DDERR_CANTDUPLICATE:
return "DDER_CANTDUPLICATE";
case DDERR_CLIPPERISUSINGHWND:
return "DDER_CLIPPERUSINGHWND";
case DDERR_COLORKEYNOTSET:
return "DDERR_COLORKEYNOTSET";
case DDERR_CURRENTLYNOTAVAIL:
return "DDERR_CURRENTLYNOTAVAIL";
case DDERR_DIRECTDRAWALREADYCREATED:
return "DDERR_DIRECTDRAWALREADYCREATED";
case DDERR_EXCEPTION:
return "DDERR_EXCEPTION";
case DDERR_EXCLUSIVEMODEALREADYSET:
return "DDERR_EXCLUSIVEMODEALREADYSET";
case DDERR_GENERIC:
return "DDERR_GENERIC";
case DDERR_HEIGHTALIGN:
return "DDERR_HEIGHTALIGN";
case DDERR_HWNDALREADYSET:
return "DDERR_HWNDALREADYSET";
case DDERR_HWNDSUBCLASSED:
return "DDERR_HWNDSUBCLASSED";
case DDERR_IMPLICITLYCREATED:
return "DDERR_IMPLICITLYCREATED";
case DDERR_INCOMPATIBLEPRIMARY:
return "DDERR_INCOMPATIBLEPRIMARY";
case DDERR_INVALIDCAPS:
return "DDERR_INVALIDCAPS";
case DDERR_INVALIDCLIPLIST:
return "DDERR_INVALIDCLIPLIST";
case DDERR_INVALIDDIRECTDRAWGUID:
return "DDERR_INVALIDDIRECTDRAWGUID";
case DDERR_INVALIDMODE:
return "DDERR_INVALIDMODE";
case DDERR_INVALIDOBJECT:
return "DDERR_INVALIDOBJECT";
case DDERR_INVALIDPARAMS:
return "DDERR_INVALIDPARAMS";
case DDERR_INVALIDPIXELFORMAT:
return "DDERR_INVALIDPIXELFORMAT";
case DDERR_INVALIDPOSITION:
return "DDERR_INVALIDPOSITION";
case DDERR_INVALIDRECT:
return "DDERR_INVALIDRECT";
case DDERR_LOCKEDSURFACES:
return "DDERR_LOCKEDSURFACES";
case DDERR_NO3D:
return "DDERR_NO3D";
case DDERR_NOALPHAHW:
return "DDERR_NOALPHAHW";
case DDERR_NOBLTHW:
return "DDERR_NOBLTHW";
case DDERR_NOCLIPLIST:
return "DDERR_NOCLIPLIST";
case DDERR_NOCLIPPERATTACHED:
return "DDERR_NOCLIPPERATTACHED";
case DDERR_NOCOLORCONVHW:
return "DDERR_NOCOLORCONVHW";
case DDERR_NOCOLORKEY:
return "DDERR_NOCOLORKEY";
case DDERR_NOCOLORKEYHW:
return "DDERR_NOCOLORKEYHW";
case DDERR_NOCOOPERATIVELEVELSET:
return "DDERR_NOCOOPERATIVELEVELSET";
case DDERR_NODC:
return "DDERR_NODC";
case DDERR_NODDROPSHW:
return "DDERR_NODDROPSHW";
case DDERR_NODIRECTDRAWHW:
return "DDERR_NODIRECTDRAWHW";
case DDERR_NOEMULATION:
return "DDERR_NOEMULATION";
case DDERR_NOEXCLUSIVEMODE:
return "DDERR_NOEXCLUSIVEMODE";
case DDERR_NOFLIPHW:
return "DDERR_NOFLIPHW";
case DDERR_NOGDI:
return "DDERR_NOGDI";
case DDERR_NOHWND:
return "DDERR_NOHWND";
case DDERR_NOMIRRORHW:
return "DDERR_NOMIRRORHW";
case DDERR_NOOVERLAYDEST:
return "DDERR_NOOVERLAYDEST";
case DDERR_NOOVERLAYHW:
return "DDERR_NOOVERLAYHW";
case DDERR_NOPALETTEATTACHED:
return "DDERR_NOPALETTEATTACHED";
case DDERR_NOPALETTEHW:
return "DDERR_NOPALETTEHW";
case DDERR_NORASTEROPHW:
return "Operation could not be carried out because there is no appropriate raster op hardware present or available.\0";
case DDERR_NOROTATIONHW:
return "Operation could not be carried out because there is no rotation hardware present or available.\0";
case DDERR_NOSTRETCHHW:
return "Operation could not be carried out because there is no hardware support for stretching.\0";
case DDERR_NOT4BITCOLOR:
return "DirectDrawSurface is not in 4 bit color palette and the requested operation requires 4 bit color palette.\0";
case DDERR_NOT4BITCOLORINDEX:
return "DirectDrawSurface is not in 4 bit color index palette and the requested operation requires 4 bit color index palette.\0";
case DDERR_NOT8BITCOLOR:
return "DDERR_NOT8BITCOLOR";
case DDERR_NOTAOVERLAYSURFACE:
return "Returned when an overlay member is called for a non-overlay surface.\0";
case DDERR_NOTEXTUREHW:
return "Operation could not be carried out because there is no texture mapping hardware present or available.\0";
case DDERR_NOTFLIPPABLE:
return "DDERR_NOTFLIPPABLE";
case DDERR_NOTFOUND:
return "DDERR_NOTFOUND";
case DDERR_NOTLOCKED:
return "DDERR_NOTLOCKED";
case DDERR_NOTPALETTIZED:
return "DDERR_NOTPALETTIZED";
case DDERR_NOVSYNCHW:
return "DDERR_NOVSYNCHW";
case DDERR_NOZBUFFERHW:
return "Operation could not be carried out because there is no hardware support for zbuffer blitting.\0";
case DDERR_NOZOVERLAYHW:
return "Overlay surfaces could not be z layered based on their BltOrder because the hardware does not support z layering of overlays.\0";
case DDERR_OUTOFCAPS:
return "The hardware needed for the requested operation has already been allocated.\0";
case DDERR_OUTOFMEMORY:
return "DDERR_OUTOFMEMORY";
case DDERR_OUTOFVIDEOMEMORY:
return "DDERR_OUTOFVIDEOMEMORY";
case DDERR_OVERLAYCANTCLIP:
return "The hardware does not support clipped overlays.\0";
case DDERR_OVERLAYCOLORKEYONLYONEACTIVE:
return "Can only have ony color key active at one time for overlays.\0";
case DDERR_OVERLAYNOTVISIBLE:
return "Returned when GetOverlayPosition is called on a hidden overlay.\0";
case DDERR_PALETTEBUSY:
return "DDERR_PALETTEBUSY";
case DDERR_PRIMARYSURFACEALREADYEXISTS:
return "DDERR_PRIMARYSURFACEALREADYEXISTS";
case DDERR_REGIONTOOSMALL:
return "Region passed to Clipper::GetClipList is too small.\0";
case DDERR_SURFACEALREADYATTACHED:
return "DDERR_SURFACEALREADYATTACHED";
case DDERR_SURFACEALREADYDEPENDENT:
return "DDERR_SURFACEALREADYDEPENDENT";
case DDERR_SURFACEBUSY:
return "DDERR_SURFACEBUSY";
case DDERR_SURFACEISOBSCURED:
return "Access to surface refused because the surface is obscured.\0";
case DDERR_SURFACELOST:
return "DDERR_SURFACELOST";
case DDERR_SURFACENOTATTACHED:
return "DDERR_SURFACENOTATTACHED";
case DDERR_TOOBIGHEIGHT:
return "Height requested by DirectDraw is too large.\0";
case DDERR_TOOBIGSIZE:
return "Size requested by DirectDraw is too large, but the individual height and width are OK.\0";
case DDERR_TOOBIGWIDTH:
return "Width requested by DirectDraw is too large.\0";
case DDERR_UNSUPPORTED:
return "DDERR_UNSUPPORTED";
case DDERR_UNSUPPORTEDFORMAT:
return "FOURCC format requested is unsupported by DirectDraw.\0";
case DDERR_UNSUPPORTEDMASK:
return "Bitmask in the pixel format requested is unsupported by DirectDraw.\0";
case DDERR_VERTICALBLANKINPROGRESS:
return "Vertical blank is in progress.\0";
case DDERR_WASSTILLDRAWING:
return "DDERR_WASSTILLDRAWING";
case DDERR_WRONGMODE:
return "This surface can not be restored because it was created in a different mode.\0";
case DDERR_XALIGN:
return "Rectangle provided was not horizontally aligned on required boundary.\0";
default:
return "UNKNOWN\0";
}
}

375
win32/rw_dib.c Normal file
View File

@ -0,0 +1,375 @@
/*
Copyright (C) 1997-2001 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.
*/
/*
** RW_DIB.C
**
** This handles DIB section management under Windows.
**
*/
#include "..\ref_soft\r_local.h"
#include "rw_win.h"
#ifndef _WIN32
# error You should not be trying to compile this file on this platform
#endif
static qboolean s_systemcolors_saved;
static HGDIOBJ previously_selected_GDI_obj;
static int s_syspalindices[] =
{
COLOR_ACTIVEBORDER,
COLOR_ACTIVECAPTION,
COLOR_APPWORKSPACE,
COLOR_BACKGROUND,
COLOR_BTNFACE,
COLOR_BTNSHADOW,
COLOR_BTNTEXT,
COLOR_CAPTIONTEXT,
COLOR_GRAYTEXT,
COLOR_HIGHLIGHT,
COLOR_HIGHLIGHTTEXT,
COLOR_INACTIVEBORDER,
COLOR_INACTIVECAPTION,
COLOR_MENU,
COLOR_MENUTEXT,
COLOR_SCROLLBAR,
COLOR_WINDOW,
COLOR_WINDOWFRAME,
COLOR_WINDOWTEXT
};
#define NUM_SYS_COLORS ( sizeof( s_syspalindices ) / sizeof( int ) )
static int s_oldsyscolors[NUM_SYS_COLORS];
typedef struct dibinfo
{
BITMAPINFOHEADER header;
RGBQUAD acolors[256];
} dibinfo_t;
typedef struct
{
WORD palVersion;
WORD palNumEntries;
PALETTEENTRY palEntries[256];
} identitypalette_t;
static identitypalette_t s_ipal;
static void DIB_SaveSystemColors( void );
static void DIB_RestoreSystemColors( void );
/*
** DIB_Init
**
** Builds our DIB section
*/
qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch )
{
dibinfo_t dibheader;
BITMAPINFO *pbmiDIB = ( BITMAPINFO * ) &dibheader;
int i;
memset( &dibheader, 0, sizeof( dibheader ) );
/*
** grab a DC
*/
if ( !sww_state.hDC )
{
if ( ( sww_state.hDC = GetDC( sww_state.hWnd ) ) == NULL )
return false;
}
/*
** figure out if we're running in an 8-bit display mode
*/
if ( GetDeviceCaps( sww_state.hDC, RASTERCAPS ) & RC_PALETTE )
{
sww_state.palettized = true;
// save system colors
if ( !s_systemcolors_saved )
{
DIB_SaveSystemColors();
s_systemcolors_saved = true;
}
}
else
{
sww_state.palettized = false;
}
/*
** fill in the BITMAPINFO struct
*/
pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmiDIB->bmiHeader.biWidth = vid.width;
pbmiDIB->bmiHeader.biHeight = vid.height;
pbmiDIB->bmiHeader.biPlanes = 1;
pbmiDIB->bmiHeader.biBitCount = 8;
pbmiDIB->bmiHeader.biCompression = BI_RGB;
pbmiDIB->bmiHeader.biSizeImage = 0;
pbmiDIB->bmiHeader.biXPelsPerMeter = 0;
pbmiDIB->bmiHeader.biYPelsPerMeter = 0;
pbmiDIB->bmiHeader.biClrUsed = 256;
pbmiDIB->bmiHeader.biClrImportant = 256;
/*
** fill in the palette
*/
for ( i = 0; i < 256; i++ )
{
dibheader.acolors[i].rgbRed = ( d_8to24table[i] >> 0 ) & 0xff;
dibheader.acolors[i].rgbGreen = ( d_8to24table[i] >> 8 ) & 0xff;
dibheader.acolors[i].rgbBlue = ( d_8to24table[i] >> 16 ) & 0xff;
}
/*
** create the DIB section
*/
sww_state.hDIBSection = CreateDIBSection( sww_state.hDC,
pbmiDIB,
DIB_RGB_COLORS,
&sww_state.pDIBBase,
NULL,
0 );
if ( sww_state.hDIBSection == NULL )
{
ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateDIBSection failed\n" );
goto fail;
}
if ( pbmiDIB->bmiHeader.biHeight > 0 )
{
// bottom up
*ppbuffer = sww_state.pDIBBase + ( vid.height - 1 ) * vid.width;
*ppitch = -vid.width;
}
else
{
// top down
*ppbuffer = sww_state.pDIBBase;
*ppitch = vid.width;
}
/*
** clear the DIB memory buffer
*/
memset( sww_state.pDIBBase, 0xff, vid.width * vid.height );
if ( ( sww_state.hdcDIBSection = CreateCompatibleDC( sww_state.hDC ) ) == NULL )
{
ri.Con_Printf( PRINT_ALL, "DIB_Init() - CreateCompatibleDC failed\n" );
goto fail;
}
if ( ( previously_selected_GDI_obj = SelectObject( sww_state.hdcDIBSection, sww_state.hDIBSection ) ) == NULL )
{
ri.Con_Printf( PRINT_ALL, "DIB_Init() - SelectObject failed\n" );
goto fail;
}
return true;
fail:
DIB_Shutdown();
return false;
}
/*
** DIB_SetPalette
**
** Sets the color table in our DIB section, and also sets the system palette
** into an identity mode if we're running in an 8-bit palettized display mode.
**
** The palette is expected to be 1024 bytes, in the format:
**
** R = offset 0
** G = offset 1
** B = offset 2
** A = offset 3
*/
void DIB_SetPalette( const unsigned char *_pal )
{
const unsigned char *pal = _pal;
LOGPALETTE *pLogPal = ( LOGPALETTE * ) &s_ipal;
RGBQUAD colors[256];
int i;
int ret;
HDC hDC = sww_state.hDC;
/*
** set the DIB color table
*/
if ( sww_state.hdcDIBSection )
{
for ( i = 0; i < 256; i++, pal += 4 )
{
colors[i].rgbRed = pal[0];
colors[i].rgbGreen = pal[1];
colors[i].rgbBlue = pal[2];
colors[i].rgbReserved = 0;
}
colors[0].rgbRed = 0;
colors[0].rgbGreen = 0;
colors[0].rgbBlue = 0;
colors[255].rgbRed = 0xff;
colors[255].rgbGreen = 0xff;
colors[255].rgbBlue = 0xff;
if ( SetDIBColorTable( sww_state.hdcDIBSection, 0, 256, colors ) == 0 )
{
ri.Con_Printf( PRINT_ALL, "DIB_SetPalette() - SetDIBColorTable failed\n" );
}
}
/*
** for 8-bit color desktop modes we set up the palette for maximum
** speed by going into an identity palette mode.
*/
if ( sww_state.palettized )
{
int i;
HPALETTE hpalOld;
if ( SetSystemPaletteUse( hDC, SYSPAL_NOSTATIC ) == SYSPAL_ERROR )
{
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SetSystemPaletteUse() failed\n" );
}
/*
** destroy our old palette
*/
if ( sww_state.hPal )
{
DeleteObject( sww_state.hPal );
sww_state.hPal = 0;
}
/*
** take up all physical palette entries to flush out anything that's currently
** in the palette
*/
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = 256;
for ( i = 0, pal = _pal; i < 256; i++, pal += 4 )
{
pLogPal->palPalEntry[i].peRed = pal[0];
pLogPal->palPalEntry[i].peGreen = pal[1];
pLogPal->palPalEntry[i].peBlue = pal[2];
pLogPal->palPalEntry[i].peFlags = PC_RESERVED | PC_NOCOLLAPSE;
}
pLogPal->palPalEntry[0].peRed = 0;
pLogPal->palPalEntry[0].peGreen = 0;
pLogPal->palPalEntry[0].peBlue = 0;
pLogPal->palPalEntry[0].peFlags = 0;
pLogPal->palPalEntry[255].peRed = 0xff;
pLogPal->palPalEntry[255].peGreen = 0xff;
pLogPal->palPalEntry[255].peBlue = 0xff;
pLogPal->palPalEntry[255].peFlags = 0;
if ( ( sww_state.hPal = CreatePalette( pLogPal ) ) == NULL )
{
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - CreatePalette failed(%x)\n", GetLastError() );
}
if ( ( hpalOld = SelectPalette( hDC, sww_state.hPal, FALSE ) ) == NULL )
{
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - SelectPalette failed(%x)\n",GetLastError() );
}
if ( sww_state.hpalOld == NULL )
sww_state.hpalOld = hpalOld;
if ( ( ret = RealizePalette( hDC ) ) != pLogPal->palNumEntries )
{
ri.Sys_Error( ERR_FATAL, "DIB_SetPalette() - RealizePalette set %d entries\n", ret );
}
}
}
/*
** DIB_Shutdown
*/
void DIB_Shutdown( void )
{
if ( sww_state.palettized && s_systemcolors_saved )
DIB_RestoreSystemColors();
if ( sww_state.hPal )
{
DeleteObject( sww_state.hPal );
sww_state.hPal = 0;
}
if ( sww_state.hpalOld )
{
SelectPalette( sww_state.hDC, sww_state.hpalOld, FALSE );
RealizePalette( sww_state.hDC );
sww_state.hpalOld = NULL;
}
if ( sww_state.hdcDIBSection )
{
SelectObject( sww_state.hdcDIBSection, previously_selected_GDI_obj );
DeleteDC( sww_state.hdcDIBSection );
sww_state.hdcDIBSection = NULL;
}
if ( sww_state.hDIBSection )
{
DeleteObject( sww_state.hDIBSection );
sww_state.hDIBSection = NULL;
sww_state.pDIBBase = NULL;
}
if ( sww_state.hDC )
{
ReleaseDC( sww_state.hWnd, sww_state.hDC );
sww_state.hDC = 0;
}
}
/*
** DIB_Save/RestoreSystemColors
*/
static void DIB_RestoreSystemColors( void )
{
SetSystemPaletteUse( sww_state.hDC, SYSPAL_STATIC );
SetSysColors( NUM_SYS_COLORS, s_syspalindices, s_oldsyscolors );
}
static void DIB_SaveSystemColors( void )
{
int i;
for ( i = 0; i < NUM_SYS_COLORS; i++ )
s_oldsyscolors[i] = GetSysColor( s_syspalindices[i] );
}

471
win32/rw_imp.c Normal file
View File

@ -0,0 +1,471 @@
/*
Copyright (C) 1997-2001 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.
*/
/*
** RW_IMP.C
**
** This file contains ALL Win32 specific stuff having to do with the
** software refresh. When a port is being made the following functions
** must be implemented by the port:
**
** SWimp_EndFrame
** SWimp_Init
** SWimp_SetPalette
** SWimp_Shutdown
*/
#include "..\ref_soft\r_local.h"
#include "rw_win.h"
#include "winquake.h"
// Console variables that we need to access from this module
swwstate_t sww_state;
/*
** VID_CreateWindow
*/
#define WINDOW_CLASS_NAME "Quake 2"
void VID_CreateWindow( int width, int height, int stylebits )
{
WNDCLASS wc;
RECT r;
cvar_t *vid_xpos, *vid_ypos, *vid_fullscreen;
int x, y, w, h;
int exstyle;
vid_xpos = ri.Cvar_Get ("vid_xpos", "0", 0);
vid_ypos = ri.Cvar_Get ("vid_ypos", "0", 0);
vid_fullscreen = ri.Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE );
if ( vid_fullscreen->value )
exstyle = WS_EX_TOPMOST;
else
exstyle = 0;
/* Register the frame class */
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)sww_state.wndproc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = sww_state.hInstance;
wc.hIcon = 0;
wc.hCursor = LoadCursor (NULL,IDC_ARROW);
wc.hbrBackground = (void *)COLOR_GRAYTEXT;
wc.lpszMenuName = 0;
wc.lpszClassName = WINDOW_CLASS_NAME;
if (!RegisterClass (&wc) )
ri.Sys_Error (ERR_FATAL, "Couldn't register window class");
r.left = 0;
r.top = 0;
r.right = width;
r.bottom = height;
AdjustWindowRect (&r, stylebits, FALSE);
w = r.right - r.left;
h = r.bottom - r.top;
x = vid_xpos->value;
y = vid_ypos->value;
sww_state.hWnd = CreateWindowEx (
exstyle,
WINDOW_CLASS_NAME,
"Quake 2",
stylebits,
x, y, w, h,
NULL,
NULL,
sww_state.hInstance,
NULL);
if (!sww_state.hWnd)
ri.Sys_Error (ERR_FATAL, "Couldn't create window");
ShowWindow( sww_state.hWnd, SW_SHOWNORMAL );
UpdateWindow( sww_state.hWnd );
SetForegroundWindow( sww_state.hWnd );
SetFocus( sww_state.hWnd );
// let the sound and input subsystems know about the new window
ri.Vid_NewWindow (width, height);
}
/*
** SWimp_Init
**
** This routine is responsible for initializing the implementation
** specific stuff in a software rendering subsystem.
*/
int SWimp_Init( void *hInstance, void *wndProc )
{
sww_state.hInstance = ( HINSTANCE ) hInstance;
sww_state.wndproc = wndProc;
return true;
}
/*
** SWimp_InitGraphics
**
** This initializes the software refresh's implementation specific
** graphics subsystem. In the case of Windows it creates DIB or
** DDRAW surfaces.
**
** The necessary width and height parameters are grabbed from
** vid.width and vid.height.
*/
static qboolean SWimp_InitGraphics( qboolean fullscreen )
{
// free resources in use
SWimp_Shutdown ();
// create a new window
VID_CreateWindow (vid.width, vid.height, WINDOW_STYLE);
// initialize the appropriate subsystem
if ( !fullscreen )
{
if ( !DIB_Init( &vid.buffer, &vid.rowbytes ) )
{
vid.buffer = 0;
vid.rowbytes = 0;
return false;
}
}
else
{
if ( !DDRAW_Init( &vid.buffer, &vid.rowbytes ) )
{
vid.buffer = 0;
vid.rowbytes = 0;
return false;
}
}
return true;
}
/*
** SWimp_EndFrame
**
** This does an implementation specific copy from the backbuffer to the
** front buffer. In the Win32 case it uses BitBlt or BltFast depending
** on whether we're using DIB sections/GDI or DDRAW.
*/
void SWimp_EndFrame (void)
{
if ( !sw_state.fullscreen )
{
if ( sww_state.palettized )
{
// holdpal = SelectPalette(hdcScreen, hpalDIB, FALSE);
// RealizePalette(hdcScreen);
}
BitBlt( sww_state.hDC,
0, 0,
vid.width,
vid.height,
sww_state.hdcDIBSection,
0, 0,
SRCCOPY );
if ( sww_state.palettized )
{
// SelectPalette(hdcScreen, holdpal, FALSE);
}
}
else
{
RECT r;
HRESULT rval;
DDSURFACEDESC ddsd;
r.left = 0;
r.top = 0;
r.right = vid.width;
r.bottom = vid.height;
sww_state.lpddsOffScreenBuffer->lpVtbl->Unlock( sww_state.lpddsOffScreenBuffer, vid.buffer );
if ( sww_state.modex )
{
if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
0, 0,
sww_state.lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
{
sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsBackBuffer );
sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsBackBuffer,
0, 0,
sww_state.lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT );
}
if ( ( rval = sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer,
NULL, DDFLIP_WAIT ) ) == DDERR_SURFACELOST )
{
sww_state.lpddsFrontBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
sww_state.lpddsFrontBuffer->lpVtbl->Flip( sww_state.lpddsFrontBuffer, NULL, DDFLIP_WAIT );
}
}
else
{
if ( ( rval = sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
0, 0,
sww_state.lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT ) ) == DDERR_SURFACELOST )
{
sww_state.lpddsBackBuffer->lpVtbl->Restore( sww_state.lpddsFrontBuffer );
sww_state.lpddsBackBuffer->lpVtbl->BltFast( sww_state.lpddsFrontBuffer,
0, 0,
sww_state.lpddsOffScreenBuffer,
&r,
DDBLTFAST_WAIT );
}
}
memset( &ddsd, 0, sizeof( ddsd ) );
ddsd.dwSize = sizeof( ddsd );
sww_state.lpddsOffScreenBuffer->lpVtbl->Lock( sww_state.lpddsOffScreenBuffer, NULL, &ddsd, DDLOCK_WAIT, NULL );
vid.buffer = ddsd.lpSurface;
vid.rowbytes = ddsd.lPitch;
}
}
/*
** SWimp_SetMode
*/
rserr_t SWimp_SetMode( int *pwidth, int *pheight, int mode, qboolean fullscreen )
{
const char *win_fs[] = { "W", "FS" };
rserr_t retval = rserr_ok;
ri.Con_Printf (PRINT_ALL, "setting mode %d:", mode );
if ( !ri.Vid_GetModeInfo( pwidth, pheight, mode ) )
{
ri.Con_Printf( PRINT_ALL, " invalid mode\n" );
return rserr_invalid_mode;
}
ri.Con_Printf( PRINT_ALL, " %d %d %s\n", *pwidth, *pheight, win_fs[fullscreen] );
sww_state.initializing = true;
if ( fullscreen )
{
if ( !SWimp_InitGraphics( 1 ) )
{
if ( SWimp_InitGraphics( 0 ) )
{
// mode is legal but not as fullscreen
fullscreen = 0;
retval = rserr_invalid_fullscreen;
}
else
{
// failed to set a valid mode in windowed mode
retval = rserr_unknown;
}
}
}
else
{
// failure to set a valid mode in windowed mode
if ( !SWimp_InitGraphics( fullscreen ) )
{
sww_state.initializing = true;
return rserr_unknown;
}
}
sw_state.fullscreen = fullscreen;
#if 0
if ( retval != rserr_unknown )
{
if ( retval == rserr_invalid_fullscreen ||
( retval == rserr_ok && !fullscreen ) )
{
SetWindowLong( sww_state.hWnd, GWL_STYLE, WINDOW_STYLE );
}
}
#endif
R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
sww_state.initializing = true;
return retval;
}
/*
** SWimp_SetPalette
**
** System specific palette setting routine. A NULL palette means
** to use the existing palette. The palette is expected to be in
** a padded 4-byte xRGB format.
*/
void SWimp_SetPalette( const unsigned char *palette )
{
// MGL - what the fuck was kendall doing here?!
// clear screen to black and change palette
// for (i=0 ; i<vid.height ; i++)
// memset (vid.buffer + i*vid.rowbytes, 0, vid.width);
if ( !palette )
palette = ( const unsigned char * ) sw_state.currentpalette;
if ( !sw_state.fullscreen )
{
DIB_SetPalette( ( const unsigned char * ) palette );
}
else
{
DDRAW_SetPalette( ( const unsigned char * ) palette );
}
}
/*
** SWimp_Shutdown
**
** System specific graphics subsystem shutdown routine. Destroys
** DIBs or DDRAW surfaces as appropriate.
*/
void SWimp_Shutdown( void )
{
ri.Con_Printf( PRINT_ALL, "Shutting down SW imp\n" );
DIB_Shutdown();
DDRAW_Shutdown();
if ( sww_state.hWnd )
{
ri.Con_Printf( PRINT_ALL, "...destroying window\n" );
ShowWindow( sww_state.hWnd, SW_SHOWNORMAL ); // prevents leaving empty slots in the taskbar
DestroyWindow (sww_state.hWnd);
sww_state.hWnd = NULL;
UnregisterClass (WINDOW_CLASS_NAME, sww_state.hInstance);
}
}
/*
** SWimp_AppActivate
*/
void SWimp_AppActivate( qboolean active )
{
if ( active )
{
if ( sww_state.hWnd )
{
SetForegroundWindow( sww_state.hWnd );
ShowWindow( sww_state.hWnd, SW_RESTORE );
}
}
else
{
if ( sww_state.hWnd )
{
if ( sww_state.initializing )
return;
if ( vid_fullscreen->value )
ShowWindow( sww_state.hWnd, SW_MINIMIZE );
}
}
}
//===============================================================================
/*
================
Sys_MakeCodeWriteable
================
*/
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
{
DWORD flOldProtect;
if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
ri.Sys_Error(ERR_FATAL, "Protection change failed\n");
}
/*
** Sys_SetFPCW
**
** For reference:
**
** 1
** 5 0
** xxxxRRPP.xxxxxxxx
**
** PP = 00 = 24-bit single precision
** PP = 01 = reserved
** PP = 10 = 53-bit double precision
** PP = 11 = 64-bit extended precision
**
** RR = 00 = round to nearest
** RR = 01 = round down (towards -inf, floor)
** RR = 10 = round up (towards +inf, ceil)
** RR = 11 = round to zero (truncate/towards 0)
**
*/
#if !id386
void Sys_SetFPCW (void)
{
}
#else
unsigned fpu_ceil_cw, fpu_chop_cw, fpu_full_cw, fpu_cw, fpu_pushed_cw;
unsigned fpu_sp24_cw, fpu_sp24_ceil_cw;
void Sys_SetFPCW( void )
{
__asm xor eax, eax
__asm fnstcw word ptr fpu_cw
__asm mov ax, word ptr fpu_cw
__asm and ah, 0f0h
__asm or ah, 003h ; round to nearest mode, extended precision
__asm mov fpu_full_cw, eax
__asm and ah, 0f0h
__asm or ah, 00fh ; RTZ/truncate/chop mode, extended precision
__asm mov fpu_chop_cw, eax
__asm and ah, 0f0h
__asm or ah, 00bh ; ceil mode, extended precision
__asm mov fpu_ceil_cw, eax
__asm and ah, 0f0h ; round to nearest, 24-bit single precision
__asm mov fpu_sp24_cw, eax
__asm and ah, 0f0h ; ceil mode, 24-bit single precision
__asm or ah, 008h ;
__asm mov fpu_sp24_ceil_cw, eax
}
#endif

68
win32/rw_win.h Normal file
View File

@ -0,0 +1,68 @@
/*
Copyright (C) 1997-2001 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.
*/
#ifndef __RW_WIN_H__
#define __RW_WIN_H__
#include <windows.h>
#include <ddraw.h>
typedef struct
{
HINSTANCE hInstance;
void *wndproc;
HDC hDC; // global DC we're using
HWND hWnd; // HWND of parent window
HDC hdcDIBSection; // DC compatible with DIB section
HBITMAP hDIBSection; // DIB section
unsigned char *pDIBBase; // DIB base pointer, NOT used directly for rendering!
HPALETTE hPal; // palette we're using
HPALETTE hpalOld; // original system palette
COLORREF oldsyscolors[20]; // original system colors
HINSTANCE hinstDDRAW; // library instance for DDRAW.DLL
LPDIRECTDRAW lpDirectDraw; // pointer to DirectDraw object
LPDIRECTDRAWSURFACE lpddsFrontBuffer; // video card display memory front buffer
LPDIRECTDRAWSURFACE lpddsBackBuffer; // system memory backbuffer
LPDIRECTDRAWSURFACE lpddsOffScreenBuffer; // system memory backbuffer
LPDIRECTDRAWPALETTE lpddpPalette; // DirectDraw palette
qboolean palettized; // true if desktop is paletted
qboolean modex;
qboolean initializing;
} swwstate_t;
extern swwstate_t sww_state;
/*
** DIB code
*/
qboolean DIB_Init( unsigned char **ppbuffer, int *ppitch );
void DIB_Shutdown( void );
void DIB_SetPalette( const unsigned char *palette );
qboolean DDRAW_Init( unsigned char **ppbuffer, int *ppitch );
void DDRAW_Shutdown( void );
void DDRAW_SetPalette( const unsigned char *palette );
#endif

861
win32/snd_win.c Normal file
View File

@ -0,0 +1,861 @@
/*
Copyright (C) 1997-2001 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.
*/
#include <float.h>
#include "../client/client.h"
#include "../client/snd_loc.h"
#include "winquake.h"
#define iDirectSoundCreate(a,b,c) pDirectSoundCreate(a,b,c)
HRESULT (WINAPI *pDirectSoundCreate)(GUID FAR *lpGUID, LPDIRECTSOUND FAR *lplpDS, IUnknown FAR *pUnkOuter);
// 64K is > 1 second at 16-bit, 22050 Hz
#define WAV_BUFFERS 64
#define WAV_MASK 0x3F
#define WAV_BUFFER_SIZE 0x0400
#define SECONDARY_BUFFER_SIZE 0x10000
typedef enum {SIS_SUCCESS, SIS_FAILURE, SIS_NOTAVAIL} sndinitstat;
cvar_t *s_wavonly;
static qboolean dsound_init;
static qboolean wav_init;
static qboolean snd_firsttime = true, snd_isdirect, snd_iswave;
static qboolean primary_format_set;
// starts at 0 for disabled
static int snd_buffer_count = 0;
static int sample16;
static int snd_sent, snd_completed;
/*
* Global variables. Must be visible to window-procedure function
* so it can unlock and free the data block after it has been played.
*/
HANDLE hData;
HPSTR lpData, lpData2;
HGLOBAL hWaveHdr;
LPWAVEHDR lpWaveHdr;
HWAVEOUT hWaveOut;
WAVEOUTCAPS wavecaps;
DWORD gSndBufSize;
MMTIME mmstarttime;
LPDIRECTSOUND pDS;
LPDIRECTSOUNDBUFFER pDSBuf, pDSPBuf;
HINSTANCE hInstDS;
qboolean SNDDMA_InitDirect (void);
qboolean SNDDMA_InitWav (void);
void FreeSound( void );
static const char *DSoundError( int error )
{
switch ( error )
{
case DSERR_BUFFERLOST:
return "DSERR_BUFFERLOST";
case DSERR_INVALIDCALL:
return "DSERR_INVALIDCALLS";
case DSERR_INVALIDPARAM:
return "DSERR_INVALIDPARAM";
case DSERR_PRIOLEVELNEEDED:
return "DSERR_PRIOLEVELNEEDED";
}
return "unknown";
}
/*
** DS_CreateBuffers
*/
static qboolean DS_CreateBuffers( void )
{
DSBUFFERDESC dsbuf;
DSBCAPS dsbcaps;
WAVEFORMATEX pformat, format;
DWORD dwWrite;
memset (&format, 0, sizeof(format));
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = dma.channels;
format.wBitsPerSample = dma.samplebits;
format.nSamplesPerSec = dma.speed;
format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
format.cbSize = 0;
format.nAvgBytesPerSec = format.nSamplesPerSec*format.nBlockAlign;
Com_Printf( "Creating DS buffers\n" );
Com_DPrintf("...setting EXCLUSIVE coop level: " );
if ( DS_OK != pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_EXCLUSIVE ) )
{
Com_Printf ("failed\n");
FreeSound ();
return false;
}
Com_DPrintf("ok\n" );
// get access to the primary buffer, if possible, so we can set the
// sound hardware format
memset (&dsbuf, 0, sizeof(dsbuf));
dsbuf.dwSize = sizeof(DSBUFFERDESC);
dsbuf.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbuf.dwBufferBytes = 0;
dsbuf.lpwfxFormat = NULL;
memset(&dsbcaps, 0, sizeof(dsbcaps));
dsbcaps.dwSize = sizeof(dsbcaps);
primary_format_set = false;
Com_DPrintf( "...creating primary buffer: " );
if (DS_OK == pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSPBuf, NULL))
{
pformat = format;
Com_DPrintf( "ok\n" );
if (DS_OK != pDSPBuf->lpVtbl->SetFormat (pDSPBuf, &pformat))
{
if (snd_firsttime)
Com_DPrintf ("...setting primary sound format: failed\n");
}
else
{
if (snd_firsttime)
Com_DPrintf ("...setting primary sound format: ok\n");
primary_format_set = true;
}
}
else
Com_Printf( "failed\n" );
if ( !primary_format_set || !s_primary->value)
{
// create the secondary buffer we'll actually work with
memset (&dsbuf, 0, sizeof(dsbuf));
dsbuf.dwSize = sizeof(DSBUFFERDESC);
dsbuf.dwFlags = DSBCAPS_CTRLFREQUENCY | DSBCAPS_LOCSOFTWARE;
dsbuf.dwBufferBytes = SECONDARY_BUFFER_SIZE;
dsbuf.lpwfxFormat = &format;
memset(&dsbcaps, 0, sizeof(dsbcaps));
dsbcaps.dwSize = sizeof(dsbcaps);
Com_DPrintf( "...creating secondary buffer: " );
if (DS_OK != pDS->lpVtbl->CreateSoundBuffer(pDS, &dsbuf, &pDSBuf, NULL))
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
dma.channels = format.nChannels;
dma.samplebits = format.wBitsPerSample;
dma.speed = format.nSamplesPerSec;
if (DS_OK != pDSBuf->lpVtbl->GetCaps (pDSBuf, &dsbcaps))
{
Com_Printf ("*** GetCaps failed ***\n");
FreeSound ();
return false;
}
Com_Printf ("...using secondary sound buffer\n");
}
else
{
Com_Printf( "...using primary buffer\n" );
Com_DPrintf( "...setting WRITEPRIMARY coop level: " );
if (DS_OK != pDS->lpVtbl->SetCooperativeLevel (pDS, cl_hwnd, DSSCL_WRITEPRIMARY))
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
if (DS_OK != pDSPBuf->lpVtbl->GetCaps (pDSPBuf, &dsbcaps))
{
Com_Printf ("*** GetCaps failed ***\n");
return false;
}
pDSBuf = pDSPBuf;
}
// Make sure mixer is active
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
if (snd_firsttime)
Com_Printf(" %d channel(s)\n"
" %d bits/sample\n"
" %d bytes/sec\n",
dma.channels, dma.samplebits, dma.speed);
gSndBufSize = dsbcaps.dwBufferBytes;
/* we don't want anyone to access the buffer directly w/o locking it first. */
lpData = NULL;
pDSBuf->lpVtbl->Stop(pDSBuf);
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmstarttime.u.sample, &dwWrite);
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
dma.samples = gSndBufSize/(dma.samplebits/8);
dma.samplepos = 0;
dma.submission_chunk = 1;
dma.buffer = (unsigned char *) lpData;
sample16 = (dma.samplebits/8) - 1;
return true;
}
/*
** DS_DestroyBuffers
*/
static void DS_DestroyBuffers( void )
{
Com_DPrintf( "Destroying DS buffers\n" );
if ( pDS )
{
Com_DPrintf( "...setting NORMAL coop level\n" );
pDS->lpVtbl->SetCooperativeLevel( pDS, cl_hwnd, DSSCL_NORMAL );
}
if ( pDSBuf )
{
Com_DPrintf( "...stopping and releasing sound buffer\n" );
pDSBuf->lpVtbl->Stop( pDSBuf );
pDSBuf->lpVtbl->Release( pDSBuf );
}
// only release primary buffer if it's not also the mixing buffer we just released
if ( pDSPBuf && ( pDSBuf != pDSPBuf ) )
{
Com_DPrintf( "...releasing primary buffer\n" );
pDSPBuf->lpVtbl->Release( pDSPBuf );
}
pDSBuf = NULL;
pDSPBuf = NULL;
dma.buffer = NULL;
}
/*
==================
FreeSound
==================
*/
void FreeSound (void)
{
int i;
Com_DPrintf( "Shutting down sound system\n" );
if ( pDS )
DS_DestroyBuffers();
if ( hWaveOut )
{
Com_DPrintf( "...resetting waveOut\n" );
waveOutReset (hWaveOut);
if (lpWaveHdr)
{
Com_DPrintf( "...unpreparing headers\n" );
for (i=0 ; i< WAV_BUFFERS ; i++)
waveOutUnprepareHeader (hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR));
}
Com_DPrintf( "...closing waveOut\n" );
waveOutClose (hWaveOut);
if (hWaveHdr)
{
Com_DPrintf( "...freeing WAV header\n" );
GlobalUnlock(hWaveHdr);
GlobalFree(hWaveHdr);
}
if (hData)
{
Com_DPrintf( "...freeing WAV buffer\n" );
GlobalUnlock(hData);
GlobalFree(hData);
}
}
if ( pDS )
{
Com_DPrintf( "...releasing DS object\n" );
pDS->lpVtbl->Release( pDS );
}
if ( hInstDS )
{
Com_DPrintf( "...freeing DSOUND.DLL\n" );
FreeLibrary( hInstDS );
hInstDS = NULL;
}
pDS = NULL;
pDSBuf = NULL;
pDSPBuf = NULL;
hWaveOut = 0;
hData = 0;
hWaveHdr = 0;
lpData = NULL;
lpWaveHdr = NULL;
dsound_init = false;
wav_init = false;
}
/*
==================
SNDDMA_InitDirect
Direct-Sound support
==================
*/
sndinitstat SNDDMA_InitDirect (void)
{
DSCAPS dscaps;
HRESULT hresult;
dma.channels = 2;
dma.samplebits = 16;
if (s_khz->value == 44)
dma.speed = 44100;
if (s_khz->value == 22)
dma.speed = 22050;
else
dma.speed = 11025;
Com_Printf( "Initializing DirectSound\n");
if ( !hInstDS )
{
Com_DPrintf( "...loading dsound.dll: " );
hInstDS = LoadLibrary("dsound.dll");
if (hInstDS == NULL)
{
Com_Printf ("failed\n");
return SIS_FAILURE;
}
Com_DPrintf ("ok\n");
pDirectSoundCreate = (void *)GetProcAddress(hInstDS,"DirectSoundCreate");
if (!pDirectSoundCreate)
{
Com_Printf ("*** couldn't get DS proc addr ***\n");
return SIS_FAILURE;
}
}
Com_DPrintf( "...creating DS object: " );
while ( ( hresult = iDirectSoundCreate( NULL, &pDS, NULL ) ) != DS_OK )
{
if (hresult != DSERR_ALLOCATED)
{
Com_Printf( "failed\n" );
return SIS_FAILURE;
}
if (MessageBox (NULL,
"The sound hardware is in use by another app.\n\n"
"Select Retry to try to start sound again or Cancel to run Quake with no sound.",
"Sound not available",
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
{
Com_Printf ("failed, hardware already in use\n" );
return SIS_NOTAVAIL;
}
}
Com_DPrintf( "ok\n" );
dscaps.dwSize = sizeof(dscaps);
if ( DS_OK != pDS->lpVtbl->GetCaps( pDS, &dscaps ) )
{
Com_Printf ("*** couldn't get DS caps ***\n");
}
if ( dscaps.dwFlags & DSCAPS_EMULDRIVER )
{
Com_DPrintf ("...no DSound driver found\n" );
FreeSound();
return SIS_FAILURE;
}
if ( !DS_CreateBuffers() )
return SIS_FAILURE;
dsound_init = true;
Com_DPrintf("...completed successfully\n" );
return SIS_SUCCESS;
}
/*
==================
SNDDM_InitWav
Crappy windows multimedia base
==================
*/
qboolean SNDDMA_InitWav (void)
{
WAVEFORMATEX format;
int i;
HRESULT hr;
Com_Printf( "Initializing wave sound\n" );
snd_sent = 0;
snd_completed = 0;
dma.channels = 2;
dma.samplebits = 16;
if (s_khz->value == 44)
dma.speed = 44100;
if (s_khz->value == 22)
dma.speed = 22050;
else
dma.speed = 11025;
memset (&format, 0, sizeof(format));
format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = dma.channels;
format.wBitsPerSample = dma.samplebits;
format.nSamplesPerSec = dma.speed;
format.nBlockAlign = format.nChannels
*format.wBitsPerSample / 8;
format.cbSize = 0;
format.nAvgBytesPerSec = format.nSamplesPerSec
*format.nBlockAlign;
/* Open a waveform device for output using window callback. */
Com_DPrintf ("...opening waveform device: ");
while ((hr = waveOutOpen((LPHWAVEOUT)&hWaveOut, WAVE_MAPPER,
&format,
0, 0L, CALLBACK_NULL)) != MMSYSERR_NOERROR)
{
if (hr != MMSYSERR_ALLOCATED)
{
Com_Printf ("failed\n");
return false;
}
if (MessageBox (NULL,
"The sound hardware is in use by another app.\n\n"
"Select Retry to try to start sound again or Cancel to run Quake 2 with no sound.",
"Sound not available",
MB_RETRYCANCEL | MB_SETFOREGROUND | MB_ICONEXCLAMATION) != IDRETRY)
{
Com_Printf ("hw in use\n" );
return false;
}
}
Com_DPrintf( "ok\n" );
/*
* Allocate and lock memory for the waveform data. The memory
* for waveform data must be globally allocated with
* GMEM_MOVEABLE and GMEM_SHARE flags.
*/
Com_DPrintf ("...allocating waveform buffer: ");
gSndBufSize = WAV_BUFFERS*WAV_BUFFER_SIZE;
hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, gSndBufSize);
if (!hData)
{
Com_Printf( " failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
Com_DPrintf ("...locking waveform buffer: ");
lpData = GlobalLock(hData);
if (!lpData)
{
Com_Printf( " failed\n" );
FreeSound ();
return false;
}
memset (lpData, 0, gSndBufSize);
Com_DPrintf( "ok\n" );
/*
* Allocate and lock memory for the header. This memory must
* also be globally allocated with GMEM_MOVEABLE and
* GMEM_SHARE flags.
*/
Com_DPrintf ("...allocating waveform header: ");
hWaveHdr = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE,
(DWORD) sizeof(WAVEHDR) * WAV_BUFFERS);
if (hWaveHdr == NULL)
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
Com_DPrintf( "ok\n" );
Com_DPrintf ("...locking waveform header: ");
lpWaveHdr = (LPWAVEHDR) GlobalLock(hWaveHdr);
if (lpWaveHdr == NULL)
{
Com_Printf( "failed\n" );
FreeSound ();
return false;
}
memset (lpWaveHdr, 0, sizeof(WAVEHDR) * WAV_BUFFERS);
Com_DPrintf( "ok\n" );
/* After allocation, set up and prepare headers. */
Com_DPrintf ("...preparing headers: ");
for (i=0 ; i<WAV_BUFFERS ; i++)
{
lpWaveHdr[i].dwBufferLength = WAV_BUFFER_SIZE;
lpWaveHdr[i].lpData = lpData + i*WAV_BUFFER_SIZE;
if (waveOutPrepareHeader(hWaveOut, lpWaveHdr+i, sizeof(WAVEHDR)) !=
MMSYSERR_NOERROR)
{
Com_Printf ("failed\n");
FreeSound ();
return false;
}
}
Com_DPrintf ("ok\n");
dma.samples = gSndBufSize/(dma.samplebits/8);
dma.samplepos = 0;
dma.submission_chunk = 512;
dma.buffer = (unsigned char *) lpData;
sample16 = (dma.samplebits/8) - 1;
wav_init = true;
return true;
}
/*
==================
SNDDMA_Init
Try to find a sound device to mix for.
Returns false if nothing is found.
==================
*/
int SNDDMA_Init(void)
{
sndinitstat stat;
memset ((void *)&dma, 0, sizeof (dma));
s_wavonly = Cvar_Get ("s_wavonly", "0", 0);
dsound_init = wav_init = 0;
stat = SIS_FAILURE; // assume DirectSound won't initialize
/* Init DirectSound */
if (!s_wavonly->value)
{
if (snd_firsttime || snd_isdirect)
{
stat = SNDDMA_InitDirect ();
if (stat == SIS_SUCCESS)
{
snd_isdirect = true;
if (snd_firsttime)
Com_Printf ("dsound init succeeded\n" );
}
else
{
snd_isdirect = false;
Com_Printf ("*** dsound init failed ***\n");
}
}
}
// if DirectSound didn't succeed in initializing, try to initialize
// waveOut sound, unless DirectSound failed because the hardware is
// already allocated (in which case the user has already chosen not
// to have sound)
if (!dsound_init && (stat != SIS_NOTAVAIL))
{
if (snd_firsttime || snd_iswave)
{
snd_iswave = SNDDMA_InitWav ();
if (snd_iswave)
{
if (snd_firsttime)
Com_Printf ("Wave sound init succeeded\n");
}
else
{
Com_Printf ("Wave sound init failed\n");
}
}
}
snd_firsttime = false;
snd_buffer_count = 1;
if (!dsound_init && !wav_init)
{
if (snd_firsttime)
Com_Printf ("*** No sound device initialized ***\n");
return 0;
}
return 1;
}
/*
==============
SNDDMA_GetDMAPos
return the current sample position (in mono samples read)
inside the recirculating dma buffer, so the mixing code will know
how many sample are required to fill it up.
===============
*/
int SNDDMA_GetDMAPos(void)
{
MMTIME mmtime;
int s;
DWORD dwWrite;
if (dsound_init)
{
mmtime.wType = TIME_SAMPLES;
pDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &mmtime.u.sample, &dwWrite);
s = mmtime.u.sample - mmstarttime.u.sample;
}
else if (wav_init)
{
s = snd_sent * WAV_BUFFER_SIZE;
}
s >>= sample16;
s &= (dma.samples-1);
return s;
}
/*
==============
SNDDMA_BeginPainting
Makes sure dma.buffer is valid
===============
*/
DWORD locksize;
void SNDDMA_BeginPainting (void)
{
int reps;
DWORD dwSize2;
DWORD *pbuf, *pbuf2;
HRESULT hresult;
DWORD dwStatus;
if (!pDSBuf)
return;
// if the buffer was lost or stopped, restore it and/or restart it
if (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DS_OK)
Com_Printf ("Couldn't get sound buffer status\n");
if (dwStatus & DSBSTATUS_BUFFERLOST)
pDSBuf->lpVtbl->Restore (pDSBuf);
if (!(dwStatus & DSBSTATUS_PLAYING))
pDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);
// lock the dsound buffer
reps = 0;
dma.buffer = NULL;
while ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &locksize,
&pbuf2, &dwSize2, 0)) != DS_OK)
{
if (hresult != DSERR_BUFFERLOST)
{
Com_Printf( "S_TransferStereo16: Lock failed with error '%s'\n", DSoundError( hresult ) );
S_Shutdown ();
return;
}
else
{
pDSBuf->lpVtbl->Restore( pDSBuf );
}
if (++reps > 2)
return;
}
dma.buffer = (unsigned char *)pbuf;
}
/*
==============
SNDDMA_Submit
Send sound to device if buffer isn't really the dma buffer
Also unlocks the dsound buffer
===============
*/
void SNDDMA_Submit(void)
{
LPWAVEHDR h;
int wResult;
if (!dma.buffer)
return;
// unlock the dsound buffer
if (pDSBuf)
pDSBuf->lpVtbl->Unlock(pDSBuf, dma.buffer, locksize, NULL, 0);
if (!wav_init)
return;
//
// find which sound blocks have completed
//
while (1)
{
if ( snd_completed == snd_sent )
{
Com_DPrintf ("Sound overrun\n");
break;
}
if ( ! (lpWaveHdr[ snd_completed & WAV_MASK].dwFlags & WHDR_DONE) )
{
break;
}
snd_completed++; // this buffer has been played
}
//Com_Printf ("completed %i\n", snd_completed);
//
// submit a few new sound blocks
//
while (((snd_sent - snd_completed) >> sample16) < 8)
{
h = lpWaveHdr + ( snd_sent&WAV_MASK );
if (paintedtime/256 <= snd_sent)
break; // Com_Printf ("submit overrun\n");
//Com_Printf ("send %i\n", snd_sent);
snd_sent++;
/*
* Now the data block can be sent to the output device. The
* waveOutWrite function returns immediately and waveform
* data is sent to the output device in the background.
*/
wResult = waveOutWrite(hWaveOut, h, sizeof(WAVEHDR));
if (wResult != MMSYSERR_NOERROR)
{
Com_Printf ("Failed to write block to device\n");
FreeSound ();
return;
}
}
}
/*
==============
SNDDMA_Shutdown
Reset the sound device for exiting
===============
*/
void SNDDMA_Shutdown(void)
{
FreeSound ();
}
/*
===========
S_Activate
Called when the main window gains or loses focus.
The window have been destroyed and recreated
between a deactivate and an activate.
===========
*/
void S_Activate (qboolean active)
{
if ( active )
{
if ( pDS && cl_hwnd && snd_isdirect )
{
DS_CreateBuffers();
}
}
else
{
if ( pDS && cl_hwnd && snd_isdirect )
{
DS_DestroyBuffers();
}
}
}

663
win32/sys_win.c Normal file
View File

@ -0,0 +1,663 @@
/*
Copyright (C) 1997-2001 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.
*/
// sys_win.h
#include "../qcommon/qcommon.h"
#include "winquake.h"
#include "resource.h"
#include <errno.h>
#include <float.h>
#include <fcntl.h>
#include <stdio.h>
#include <direct.h>
#include <io.h>
#include <conio.h>
#include "../win32/conproc.h"
#define MINIMUM_WIN_MEMORY 0x0a00000
#define MAXIMUM_WIN_MEMORY 0x1000000
//#define DEMO
qboolean s_win95;
int starttime;
int ActiveApp;
qboolean Minimized;
static HANDLE hinput, houtput;
unsigned sys_msg_time;
unsigned sys_frame_time;
static HANDLE qwclsemaphore;
#define MAX_NUM_ARGVS 128
int argc;
char *argv[MAX_NUM_ARGVS];
/*
===============================================================================
SYSTEM IO
===============================================================================
*/
void Sys_Error (char *error, ...)
{
va_list argptr;
char text[1024];
CL_Shutdown ();
Qcommon_Shutdown ();
va_start (argptr, error);
vsprintf (text, error, argptr);
va_end (argptr);
MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
if (qwclsemaphore)
CloseHandle (qwclsemaphore);
// shut down QHOST hooks if necessary
DeinitConProc ();
exit (1);
}
void Sys_Quit (void)
{
timeEndPeriod( 1 );
CL_Shutdown();
Qcommon_Shutdown ();
CloseHandle (qwclsemaphore);
if (dedicated && dedicated->value)
FreeConsole ();
// shut down QHOST hooks if necessary
DeinitConProc ();
exit (0);
}
void WinError (void)
{
LPVOID lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
// Display the string.
MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
// Free the buffer.
LocalFree( lpMsgBuf );
}
//================================================================
/*
================
Sys_ScanForCD
================
*/
char *Sys_ScanForCD (void)
{
static char cddir[MAX_OSPATH];
static qboolean done;
#ifndef DEMO
char drive[4];
FILE *f;
char test[MAX_QPATH];
if (done) // don't re-check
return cddir;
// no abort/retry/fail errors
SetErrorMode (SEM_FAILCRITICALERRORS);
drive[0] = 'c';
drive[1] = ':';
drive[2] = '\\';
drive[3] = 0;
done = true;
// scan the drives
for (drive[0] = 'c' ; drive[0] <= 'z' ; drive[0]++)
{
// where activision put the stuff...
sprintf (cddir, "%sinstall\\data", drive);
sprintf (test, "%sinstall\\data\\quake2.exe", drive);
f = fopen(test, "r");
if (f)
{
fclose (f);
if (GetDriveType (drive) == DRIVE_CDROM)
return cddir;
}
}
#endif
cddir[0] = 0;
return NULL;
}
/*
================
Sys_CopyProtect
================
*/
void Sys_CopyProtect (void)
{
#ifndef DEMO
char *cddir;
cddir = Sys_ScanForCD();
if (!cddir[0])
Com_Error (ERR_FATAL, "You must have the Quake2 CD in the drive to play.");
#endif
}
//================================================================
/*
================
Sys_Init
================
*/
void Sys_Init (void)
{
OSVERSIONINFO vinfo;
#if 0
// allocate a named semaphore on the client so the
// front end can tell if it is alive
// mutex will fail if semephore already exists
qwclsemaphore = CreateMutex(
NULL, /* Security attributes */
0, /* owner */
"qwcl"); /* Semaphore name */
if (!qwclsemaphore)
Sys_Error ("QWCL is already running on this system");
CloseHandle (qwclsemaphore);
qwclsemaphore = CreateSemaphore(
NULL, /* Security attributes */
0, /* Initial count */
1, /* Maximum count */
"qwcl"); /* Semaphore name */
#endif
timeBeginPeriod( 1 );
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
if (!GetVersionEx (&vinfo))
Sys_Error ("Couldn't get OS info");
if (vinfo.dwMajorVersion < 4)
Sys_Error ("Quake2 requires windows version 4 or greater");
if (vinfo.dwPlatformId == VER_PLATFORM_WIN32s)
Sys_Error ("Quake2 doesn't run on Win32s");
else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
s_win95 = true;
if (dedicated->value)
{
if (!AllocConsole ())
Sys_Error ("Couldn't create dedicated server console");
hinput = GetStdHandle (STD_INPUT_HANDLE);
houtput = GetStdHandle (STD_OUTPUT_HANDLE);
// let QHOST hook in
InitConProc (argc, argv);
}
}
static char console_text[256];
static int console_textlen;
/*
================
Sys_ConsoleInput
================
*/
char *Sys_ConsoleInput (void)
{
INPUT_RECORD recs[1024];
int dummy;
int ch, numread, numevents;
if (!dedicated || !dedicated->value)
return NULL;
for ( ;; )
{
if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
Sys_Error ("Error getting # of console events");
if (numevents <= 0)
break;
if (!ReadConsoleInput(hinput, recs, 1, &numread))
Sys_Error ("Error reading console input");
if (numread != 1)
Sys_Error ("Couldn't read console input");
if (recs[0].EventType == KEY_EVENT)
{
if (!recs[0].Event.KeyEvent.bKeyDown)
{
ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
switch (ch)
{
case '\r':
WriteFile(houtput, "\r\n", 2, &dummy, NULL);
if (console_textlen)
{
console_text[console_textlen] = 0;
console_textlen = 0;
return console_text;
}
break;
case '\b':
if (console_textlen)
{
console_textlen--;
WriteFile(houtput, "\b \b", 3, &dummy, NULL);
}
break;
default:
if (ch >= ' ')
{
if (console_textlen < sizeof(console_text)-2)
{
WriteFile(houtput, &ch, 1, &dummy, NULL);
console_text[console_textlen] = ch;
console_textlen++;
}
}
break;
}
}
}
}
return NULL;
}
/*
================
Sys_ConsoleOutput
Print text to the dedicated console
================
*/
void Sys_ConsoleOutput (char *string)
{
int dummy;
char text[256];
if (!dedicated || !dedicated->value)
return;
if (console_textlen)
{
text[0] = '\r';
memset(&text[1], ' ', console_textlen);
text[console_textlen+1] = '\r';
text[console_textlen+2] = 0;
WriteFile(houtput, text, console_textlen+2, &dummy, NULL);
}
WriteFile(houtput, string, strlen(string), &dummy, NULL);
if (console_textlen)
WriteFile(houtput, console_text, console_textlen, &dummy, NULL);
}
/*
================
Sys_SendKeyEvents
Send Key_Event calls
================
*/
void Sys_SendKeyEvents (void)
{
MSG msg;
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage (&msg, NULL, 0, 0))
Sys_Quit ();
sys_msg_time = msg.time;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
// grab frame time
sys_frame_time = timeGetTime(); // FIXME: should this be at start?
}
/*
================
Sys_GetClipboardData
================
*/
char *Sys_GetClipboardData( void )
{
char *data = NULL;
char *cliptext;
if ( OpenClipboard( NULL ) != 0 )
{
HANDLE hClipboardData;
if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 )
{
if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 )
{
data = malloc( GlobalSize( hClipboardData ) + 1 );
strcpy( data, cliptext );
GlobalUnlock( hClipboardData );
}
}
CloseClipboard();
}
return data;
}
/*
==============================================================================
WINDOWS CRAP
==============================================================================
*/
/*
=================
Sys_AppActivate
=================
*/
void Sys_AppActivate (void)
{
ShowWindow ( cl_hwnd, SW_RESTORE);
SetForegroundWindow ( cl_hwnd );
}
/*
========================================================================
GAME DLL
========================================================================
*/
static HINSTANCE game_library;
/*
=================
Sys_UnloadGame
=================
*/
void Sys_UnloadGame (void)
{
if (!FreeLibrary (game_library))
Com_Error (ERR_FATAL, "FreeLibrary failed for game library");
game_library = NULL;
}
/*
=================
Sys_GetGameAPI
Loads the game dll
=================
*/
void *Sys_GetGameAPI (void *parms)
{
void *(*GetGameAPI) (void *);
char name[MAX_OSPATH];
char *path;
char cwd[MAX_OSPATH];
#if defined _M_IX86
const char *gamename = "gamex86.dll";
#ifdef NDEBUG
const char *debugdir = "release";
#else
const char *debugdir = "debug";
#endif
#elif defined _M_ALPHA
const char *gamename = "gameaxp.dll";
#ifdef NDEBUG
const char *debugdir = "releaseaxp";
#else
const char *debugdir = "debugaxp";
#endif
#endif
if (game_library)
Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
// check the current debug directory first for development purposes
_getcwd (cwd, sizeof(cwd));
Com_sprintf (name, sizeof(name), "%s/%s/%s", cwd, debugdir, gamename);
game_library = LoadLibrary ( name );
if (game_library)
{
Com_DPrintf ("LoadLibrary (%s)\n", name);
}
else
{
// check the current directory for other development purposes
Com_sprintf (name, sizeof(name), "%s/%s", cwd, gamename);
game_library = LoadLibrary ( name );
if (game_library)
{
Com_DPrintf ("LoadLibrary (%s)\n", name);
}
else
{
// now run through the search paths
path = NULL;
while (1)
{
path = FS_NextPath (path);
if (!path)
return NULL; // couldn't find one anywhere
Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
game_library = LoadLibrary (name);
if (game_library)
{
Com_DPrintf ("LoadLibrary (%s)\n",name);
break;
}
}
}
}
GetGameAPI = (void *)GetProcAddress (game_library, "GetGameAPI");
if (!GetGameAPI)
{
Sys_UnloadGame ();
return NULL;
}
return GetGameAPI (parms);
}
//=======================================================================
/*
==================
ParseCommandLine
==================
*/
void ParseCommandLine (LPSTR lpCmdLine)
{
argc = 1;
argv[0] = "exe";
while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
{
while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
lpCmdLine++;
if (*lpCmdLine)
{
argv[argc] = lpCmdLine;
argc++;
while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
lpCmdLine++;
if (*lpCmdLine)
{
*lpCmdLine = 0;
lpCmdLine++;
}
}
}
}
/*
==================
WinMain
==================
*/
HINSTANCE global_hInstance;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MSG msg;
int time, oldtime, newtime;
char *cddir;
/* previous instances do not exist in Win32 */
if (hPrevInstance)
return 0;
global_hInstance = hInstance;
ParseCommandLine (lpCmdLine);
// if we find the CD, add a +set cddir xxx command line
cddir = Sys_ScanForCD ();
if (cddir && argc < MAX_NUM_ARGVS - 3)
{
int i;
// don't override a cddir on the command line
for (i=0 ; i<argc ; i++)
if (!strcmp(argv[i], "cddir"))
break;
if (i == argc)
{
argv[argc++] = "+set";
argv[argc++] = "cddir";
argv[argc++] = cddir;
}
}
Qcommon_Init (argc, argv);
oldtime = Sys_Milliseconds ();
/* main window message loop */
while (1)
{
// if at a full screen console, don't update unless needed
if (Minimized || (dedicated && dedicated->value) )
{
Sleep (1);
}
while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (!GetMessage (&msg, NULL, 0, 0))
Com_Quit ();
sys_msg_time = msg.time;
TranslateMessage (&msg);
DispatchMessage (&msg);
}
do
{
newtime = Sys_Milliseconds ();
time = newtime - oldtime;
} while (time < 1);
// Con_Printf ("time:%5.2f - %5.2f = %5.2f\n", newtime, oldtime, time);
// _controlfp( ~( _EM_ZERODIVIDE /*| _EM_INVALID*/ ), _MCW_EM );
_controlfp( _PC_24, _MCW_PC );
Qcommon_Frame (time);
oldtime = newtime;
}
// never gets here
return TRUE;
}

760
win32/vid_dll.c Normal file
View File

@ -0,0 +1,760 @@
/*
Copyright (C) 1997-2001 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.
*/
// Main windowed and fullscreen graphics interface module. This module
// is used for both the software and OpenGL rendering versions of the
// Quake refresh engine.
#include <assert.h>
#include <float.h>
#include "..\client\client.h"
#include "winquake.h"
//#include "zmouse.h"
// Structure containing functions exported from refresh DLL
refexport_t re;
cvar_t *win_noalttab;
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL (WM_MOUSELAST+1) // message that will be supported by the OS
#endif
static UINT MSH_MOUSEWHEEL;
// Console variables that we need to access from this module
cvar_t *vid_gamma;
cvar_t *vid_ref; // Name of Refresh DLL loaded
cvar_t *vid_xpos; // X coordinate of window position
cvar_t *vid_ypos; // Y coordinate of window position
cvar_t *vid_fullscreen;
// Global variables used internally by this module
viddef_t viddef; // global video state; used by other modules
HINSTANCE reflib_library; // Handle to refresh DLL
qboolean reflib_active = 0;
HWND cl_hwnd; // Main window handle for life of program
#define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] ) )
LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
static qboolean s_alttab_disabled;
extern unsigned sys_msg_time;
/*
** WIN32 helper functions
*/
extern qboolean s_win95;
static void WIN_DisableAltTab( void )
{
if ( s_alttab_disabled )
return;
if ( s_win95 )
{
BOOL old;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 1, &old, 0 );
}
else
{
RegisterHotKey( 0, 0, MOD_ALT, VK_TAB );
RegisterHotKey( 0, 1, MOD_ALT, VK_RETURN );
}
s_alttab_disabled = true;
}
static void WIN_EnableAltTab( void )
{
if ( s_alttab_disabled )
{
if ( s_win95 )
{
BOOL old;
SystemParametersInfo( SPI_SCREENSAVERRUNNING, 0, &old, 0 );
}
else
{
UnregisterHotKey( 0, 0 );
UnregisterHotKey( 0, 1 );
}
s_alttab_disabled = false;
}
}
/*
==========================================================================
DLL GLUE
==========================================================================
*/
#define MAXPRINTMSG 4096
void VID_Printf (int print_level, char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
static qboolean inupdate;
va_start (argptr,fmt);
vsprintf (msg,fmt,argptr);
va_end (argptr);
if (print_level == PRINT_ALL)
{
Com_Printf ("%s", msg);
}
else if ( print_level == PRINT_DEVELOPER )
{
Com_DPrintf ("%s", msg);
}
else if ( print_level == PRINT_ALERT )
{
MessageBox( 0, msg, "PRINT_ALERT", MB_ICONWARNING );
OutputDebugString( msg );
}
}
void VID_Error (int err_level, char *fmt, ...)
{
va_list argptr;
char msg[MAXPRINTMSG];
static qboolean inupdate;
va_start (argptr,fmt);
vsprintf (msg,fmt,argptr);
va_end (argptr);
Com_Error (err_level,"%s", msg);
}
//==========================================================================
byte scantokey[128] =
{
// 0 1 2 3 4 5 6 7
// 8 9 A B C D E F
0 , 27, '1', '2', '3', '4', '5', '6',
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i',
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';',
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*',
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3
K_F6, K_F7, K_F8, K_F9, K_F10, K_PAUSE, 0 , K_HOME,
K_UPARROW,K_PGUP,K_KP_MINUS,K_LEFTARROW,K_KP_5,K_RIGHTARROW, K_KP_PLUS,K_END, //4
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11,
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0,
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7
};
/*
=======
MapKey
Map from windows to quake keynums
=======
*/
int MapKey (int key)
{
int result;
int modified = ( key >> 16 ) & 255;
qboolean is_extended = false;
if ( modified > 127)
return 0;
if ( key & ( 1 << 24 ) )
is_extended = true;
result = scantokey[modified];
if ( !is_extended )
{
switch ( result )
{
case K_HOME:
return K_KP_HOME;
case K_UPARROW:
return K_KP_UPARROW;
case K_PGUP:
return K_KP_PGUP;
case K_LEFTARROW:
return K_KP_LEFTARROW;
case K_RIGHTARROW:
return K_KP_RIGHTARROW;
case K_END:
return K_KP_END;
case K_DOWNARROW:
return K_KP_DOWNARROW;
case K_PGDN:
return K_KP_PGDN;
case K_INS:
return K_KP_INS;
case K_DEL:
return K_KP_DEL;
default:
return result;
}
}
else
{
switch ( result )
{
case 0x0D:
return K_KP_ENTER;
case 0x2F:
return K_KP_SLASH;
case 0xAF:
return K_KP_PLUS;
}
return result;
}
}
void AppActivate(BOOL fActive, BOOL minimize)
{
Minimized = minimize;
Key_ClearStates();
// we don't want to act like we're active if we're minimized
if (fActive && !Minimized)
ActiveApp = true;
else
ActiveApp = false;
// minimize/restore mouse-capture on demand
if (!ActiveApp)
{
IN_Activate (false);
CDAudio_Activate (false);
S_Activate (false);
if ( win_noalttab->value )
{
WIN_EnableAltTab();
}
}
else
{
IN_Activate (true);
CDAudio_Activate (true);
S_Activate (true);
if ( win_noalttab->value )
{
WIN_DisableAltTab();
}
}
}
/*
====================
MainWndProc
main window procedure
====================
*/
LONG WINAPI MainWndProc (
HWND hWnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)
{
LONG lRet = 0;
if ( uMsg == MSH_MOUSEWHEEL )
{
if ( ( ( int ) wParam ) > 0 )
{
Key_Event( K_MWHEELUP, true, sys_msg_time );
Key_Event( K_MWHEELUP, false, sys_msg_time );
}
else
{
Key_Event( K_MWHEELDOWN, true, sys_msg_time );
Key_Event( K_MWHEELDOWN, false, sys_msg_time );
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
switch (uMsg)
{
case WM_MOUSEWHEEL:
/*
** this chunk of code theoretically only works under NT4 and Win98
** since this message doesn't exist under Win95
*/
if ( ( short ) HIWORD( wParam ) > 0 )
{
Key_Event( K_MWHEELUP, true, sys_msg_time );
Key_Event( K_MWHEELUP, false, sys_msg_time );
}
else
{
Key_Event( K_MWHEELDOWN, true, sys_msg_time );
Key_Event( K_MWHEELDOWN, false, sys_msg_time );
}
break;
case WM_HOTKEY:
return 0;
case WM_CREATE:
cl_hwnd = hWnd;
MSH_MOUSEWHEEL = RegisterWindowMessage("MSWHEEL_ROLLMSG");
return DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_PAINT:
SCR_DirtyScreen (); // force entire screen to update next frame
return DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_DESTROY:
// let sound and input know about this?
cl_hwnd = NULL;
return DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_ACTIVATE:
{
int fActive, fMinimized;
// KJB: Watch this for problems in fullscreen modes with Alt-tabbing.
fActive = LOWORD(wParam);
fMinimized = (BOOL) HIWORD(wParam);
AppActivate( fActive != WA_INACTIVE, fMinimized);
if ( reflib_active )
re.AppActivate( !( fActive == WA_INACTIVE ) );
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_MOVE:
{
int xPos, yPos;
RECT r;
int style;
if (!vid_fullscreen->value)
{
xPos = (short) LOWORD(lParam); // horizontal position
yPos = (short) HIWORD(lParam); // vertical position
r.left = 0;
r.top = 0;
r.right = 1;
r.bottom = 1;
style = GetWindowLong( hWnd, GWL_STYLE );
AdjustWindowRect( &r, style, FALSE );
Cvar_SetValue( "vid_xpos", xPos + r.left);
Cvar_SetValue( "vid_ypos", yPos + r.top);
vid_xpos->modified = false;
vid_ypos->modified = false;
if (ActiveApp)
IN_Activate (true);
}
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
// 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:
{
int temp;
temp = 0;
if (wParam & MK_LBUTTON)
temp |= 1;
if (wParam & MK_RBUTTON)
temp |= 2;
if (wParam & MK_MBUTTON)
temp |= 4;
IN_MouseEvent (temp);
}
break;
case WM_SYSCOMMAND:
if ( wParam == SC_SCREENSAVE )
return 0;
return DefWindowProc (hWnd, uMsg, wParam, lParam);
case WM_SYSKEYDOWN:
if ( wParam == 13 )
{
if ( vid_fullscreen )
{
Cvar_SetValue( "vid_fullscreen", !vid_fullscreen->value );
}
return 0;
}
// fall through
case WM_KEYDOWN:
Key_Event( MapKey( lParam ), true, sys_msg_time);
break;
case WM_SYSKEYUP:
case WM_KEYUP:
Key_Event( MapKey( lParam ), false, sys_msg_time);
break;
case MM_MCINOTIFY:
{
LONG CDAudio_MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
lRet = CDAudio_MessageHandler (hWnd, uMsg, wParam, lParam);
}
break;
default: // pass all unhandled messages to DefWindowProc
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
/* return 0 if handled message, 1 if not */
return DefWindowProc( hWnd, uMsg, wParam, lParam );
}
/*
============
VID_Restart_f
Console command to re-start the video mode and refresh DLL. We do this
simply by setting the modified flag for the vid_ref variable, which will
cause the entire video mode and refresh DLL to be reset on the next frame.
============
*/
void VID_Restart_f (void)
{
vid_ref->modified = true;
}
void VID_Front_f( void )
{
SetWindowLong( cl_hwnd, GWL_EXSTYLE, WS_EX_TOPMOST );
SetForegroundWindow( cl_hwnd );
}
/*
** VID_GetModeInfo
*/
typedef struct vidmode_s
{
const char *description;
int width, height;
int mode;
} vidmode_t;
vidmode_t vid_modes[] =
{
{ "Mode 0: 320x240", 320, 240, 0 },
{ "Mode 1: 400x300", 400, 300, 1 },
{ "Mode 2: 512x384", 512, 384, 2 },
{ "Mode 3: 640x480", 640, 480, 3 },
{ "Mode 4: 800x600", 800, 600, 4 },
{ "Mode 5: 960x720", 960, 720, 5 },
{ "Mode 6: 1024x768", 1024, 768, 6 },
{ "Mode 7: 1152x864", 1152, 864, 7 },
{ "Mode 8: 1280x960", 1280, 960, 8 },
{ "Mode 9: 1600x1200", 1600, 1200, 9 }
};
qboolean VID_GetModeInfo( int *width, int *height, int mode )
{
if ( mode < 0 || mode >= VID_NUM_MODES )
return false;
*width = vid_modes[mode].width;
*height = vid_modes[mode].height;
return true;
}
/*
** VID_UpdateWindowPosAndSize
*/
void VID_UpdateWindowPosAndSize( int x, int y )
{
RECT r;
int style;
int w, h;
r.left = 0;
r.top = 0;
r.right = viddef.width;
r.bottom = viddef.height;
style = GetWindowLong( cl_hwnd, GWL_STYLE );
AdjustWindowRect( &r, style, FALSE );
w = r.right - r.left;
h = r.bottom - r.top;
MoveWindow( cl_hwnd, vid_xpos->value, vid_ypos->value, w, h, TRUE );
}
/*
** VID_NewWindow
*/
void VID_NewWindow ( int width, int height)
{
viddef.width = width;
viddef.height = height;
cl.force_refdef = true; // can't use a paused refdef
}
void VID_FreeReflib (void)
{
if ( !FreeLibrary( reflib_library ) )
Com_Error( ERR_FATAL, "Reflib FreeLibrary failed" );
memset (&re, 0, sizeof(re));
reflib_library = NULL;
reflib_active = false;
}
/*
==============
VID_LoadRefresh
==============
*/
qboolean VID_LoadRefresh( char *name )
{
refimport_t ri;
GetRefAPI_t GetRefAPI;
if ( reflib_active )
{
re.Shutdown();
VID_FreeReflib ();
}
Com_Printf( "------- Loading %s -------\n", name );
if ( ( reflib_library = LoadLibrary( name ) ) == 0 )
{
Com_Printf( "LoadLibrary(\"%s\") failed\n", name );
return false;
}
ri.Cmd_AddCommand = Cmd_AddCommand;
ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
ri.Cmd_Argc = Cmd_Argc;
ri.Cmd_Argv = Cmd_Argv;
ri.Cmd_ExecuteText = Cbuf_ExecuteText;
ri.Con_Printf = VID_Printf;
ri.Sys_Error = VID_Error;
ri.FS_LoadFile = FS_LoadFile;
ri.FS_FreeFile = FS_FreeFile;
ri.FS_Gamedir = FS_Gamedir;
ri.Cvar_Get = Cvar_Get;
ri.Cvar_Set = Cvar_Set;
ri.Cvar_SetValue = Cvar_SetValue;
ri.Vid_GetModeInfo = VID_GetModeInfo;
ri.Vid_MenuInit = VID_MenuInit;
ri.Vid_NewWindow = VID_NewWindow;
if ( ( GetRefAPI = (void *) GetProcAddress( reflib_library, "GetRefAPI" ) ) == 0 )
Com_Error( ERR_FATAL, "GetProcAddress failed on %s", name );
re = GetRefAPI( ri );
if (re.api_version != API_VERSION)
{
VID_FreeReflib ();
Com_Error (ERR_FATAL, "%s has incompatible api_version", name);
}
if ( re.Init( global_hInstance, MainWndProc ) == -1 )
{
re.Shutdown();
VID_FreeReflib ();
return false;
}
Com_Printf( "------------------------------------\n");
reflib_active = true;
//======
//PGM
vidref_val = VIDREF_OTHER;
if(vid_ref)
{
if(!strcmp (vid_ref->string, "gl"))
vidref_val = VIDREF_GL;
else if(!strcmp(vid_ref->string, "soft"))
vidref_val = VIDREF_SOFT;
}
//PGM
//======
return true;
}
/*
============
VID_CheckChanges
This function gets called once just before drawing each frame, and it's sole purpose in life
is to check to see if any of the video mode parameters have changed, and if they have to
update the rendering DLL and/or video mode to match.
============
*/
void VID_CheckChanges (void)
{
char name[100];
if ( win_noalttab->modified )
{
if ( win_noalttab->value )
{
WIN_DisableAltTab();
}
else
{
WIN_EnableAltTab();
}
win_noalttab->modified = false;
}
if ( vid_ref->modified )
{
cl.force_refdef = true; // can't use a paused refdef
S_StopAllSounds();
}
while (vid_ref->modified)
{
/*
** refresh has changed
*/
vid_ref->modified = false;
vid_fullscreen->modified = true;
cl.refresh_prepped = false;
cls.disable_screen = true;
Com_sprintf( name, sizeof(name), "ref_%s.dll", vid_ref->string );
if ( !VID_LoadRefresh( name ) )
{
if ( strcmp (vid_ref->string, "soft") == 0 )
Com_Error (ERR_FATAL, "Couldn't fall back to software refresh!");
Cvar_Set( "vid_ref", "soft" );
/*
** drop the console if we fail to load a refresh
*/
if ( cls.key_dest != key_console )
{
Con_ToggleConsole_f();
}
}
cls.disable_screen = false;
}
/*
** update our window position
*/
if ( vid_xpos->modified || vid_ypos->modified )
{
if (!vid_fullscreen->value)
VID_UpdateWindowPosAndSize( vid_xpos->value, vid_ypos->value );
vid_xpos->modified = false;
vid_ypos->modified = false;
}
}
/*
============
VID_Init
============
*/
void VID_Init (void)
{
/* Create the video variables so we know how to start the graphics drivers */
vid_ref = Cvar_Get ("vid_ref", "soft", CVAR_ARCHIVE);
vid_xpos = Cvar_Get ("vid_xpos", "3", CVAR_ARCHIVE);
vid_ypos = Cvar_Get ("vid_ypos", "22", CVAR_ARCHIVE);
vid_fullscreen = Cvar_Get ("vid_fullscreen", "0", CVAR_ARCHIVE);
vid_gamma = Cvar_Get( "vid_gamma", "1", CVAR_ARCHIVE );
win_noalttab = Cvar_Get( "win_noalttab", "0", CVAR_ARCHIVE );
/* Add some console commands that we want to handle */
Cmd_AddCommand ("vid_restart", VID_Restart_f);
Cmd_AddCommand ("vid_front", VID_Front_f);
/*
** this is a gross hack but necessary to clamp the mode for 3Dfx
*/
#if 0
{
cvar_t *gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
cvar_t *gl_mode = Cvar_Get( "gl_mode", "3", 0 );
if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
{
Cvar_SetValue( "gl_mode", 3 );
viddef.width = 640;
viddef.height = 480;
}
}
#endif
/* Disable the 3Dfx splash screen */
putenv("FX_GLIDE_NO_SPLASH=0");
/* Start the graphics mode and load refresh DLL */
VID_CheckChanges();
}
/*
============
VID_Shutdown
============
*/
void VID_Shutdown (void)
{
if ( reflib_active )
{
re.Shutdown ();
VID_FreeReflib ();
}
}

473
win32/vid_menu.c Normal file
View File

@ -0,0 +1,473 @@
/*
Copyright (C) 1997-2001 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.
*/
#include "../client/client.h"
#include "../client/qmenu.h"
#define REF_SOFT 0
#define REF_OPENGL 1
#define REF_3DFX 2
#define REF_POWERVR 3
#define REF_VERITE 4
extern cvar_t *vid_ref;
extern cvar_t *vid_fullscreen;
extern cvar_t *vid_gamma;
extern cvar_t *scr_viewsize;
static cvar_t *gl_mode;
static cvar_t *gl_driver;
static cvar_t *gl_picmip;
static cvar_t *gl_ext_palettedtexture;
static cvar_t *gl_finish;
static cvar_t *sw_mode;
static cvar_t *sw_stipplealpha;
extern void M_ForceMenuOff( void );
/*
====================================================================
MENU INTERACTION
====================================================================
*/
#define SOFTWARE_MENU 0
#define OPENGL_MENU 1
static menuframework_s s_software_menu;
static menuframework_s s_opengl_menu;
static menuframework_s *s_current_menu;
static int s_current_menu_index;
static menulist_s s_mode_list[2];
static menulist_s s_ref_list[2];
static menuslider_s s_tq_slider;
static menuslider_s s_screensize_slider[2];
static menuslider_s s_brightness_slider[2];
static menulist_s s_fs_box[2];
static menulist_s s_stipple_box;
static menulist_s s_paletted_texture_box;
static menulist_s s_finish_box;
static menuaction_s s_cancel_action[2];
static menuaction_s s_defaults_action[2];
static void DriverCallback( void *unused )
{
s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
if ( s_ref_list[s_current_menu_index].curvalue == 0 )
{
s_current_menu = &s_software_menu;
s_current_menu_index = 0;
}
else
{
s_current_menu = &s_opengl_menu;
s_current_menu_index = 1;
}
}
static void ScreenSizeCallback( void *s )
{
menuslider_s *slider = ( menuslider_s * ) s;
Cvar_SetValue( "viewsize", slider->curvalue * 10 );
}
static void BrightnessCallback( void *s )
{
menuslider_s *slider = ( menuslider_s * ) s;
if ( s_current_menu_index == SOFTWARE_MENU )
s_brightness_slider[1].curvalue = s_brightness_slider[0].curvalue;
else
s_brightness_slider[0].curvalue = s_brightness_slider[1].curvalue;
if ( stricmp( vid_ref->string, "soft" ) == 0 )
{
float gamma = ( 0.8 - ( slider->curvalue/10.0 - 0.5 ) ) + 0.5;
Cvar_SetValue( "vid_gamma", gamma );
}
}
static void ResetDefaults( void *unused )
{
VID_MenuInit();
}
static void ApplyChanges( void *unused )
{
float gamma;
/*
** make values consistent
*/
s_fs_box[!s_current_menu_index].curvalue = s_fs_box[s_current_menu_index].curvalue;
s_brightness_slider[!s_current_menu_index].curvalue = s_brightness_slider[s_current_menu_index].curvalue;
s_ref_list[!s_current_menu_index].curvalue = s_ref_list[s_current_menu_index].curvalue;
/*
** invert sense so greater = brighter, and scale to a range of 0.5 to 1.3
*/
gamma = ( 0.8 - ( s_brightness_slider[s_current_menu_index].curvalue/10.0 - 0.5 ) ) + 0.5;
Cvar_SetValue( "vid_gamma", gamma );
Cvar_SetValue( "sw_stipplealpha", s_stipple_box.curvalue );
Cvar_SetValue( "gl_picmip", 3 - s_tq_slider.curvalue );
Cvar_SetValue( "vid_fullscreen", s_fs_box[s_current_menu_index].curvalue );
Cvar_SetValue( "gl_ext_palettedtexture", s_paletted_texture_box.curvalue );
Cvar_SetValue( "gl_finish", s_finish_box.curvalue );
Cvar_SetValue( "sw_mode", s_mode_list[SOFTWARE_MENU].curvalue );
Cvar_SetValue( "gl_mode", s_mode_list[OPENGL_MENU].curvalue );
switch ( s_ref_list[s_current_menu_index].curvalue )
{
case REF_SOFT:
Cvar_Set( "vid_ref", "soft" );
break;
case REF_OPENGL:
Cvar_Set( "vid_ref", "gl" );
Cvar_Set( "gl_driver", "opengl32" );
break;
case REF_3DFX:
Cvar_Set( "vid_ref", "gl" );
Cvar_Set( "gl_driver", "3dfxgl" );
break;
case REF_POWERVR:
Cvar_Set( "vid_ref", "gl" );
Cvar_Set( "gl_driver", "pvrgl" );
break;
case REF_VERITE:
Cvar_Set( "vid_ref", "gl" );
Cvar_Set( "gl_driver", "veritegl" );
break;
}
/*
** update appropriate stuff if we're running OpenGL and gamma
** has been modified
*/
if ( stricmp( vid_ref->string, "gl" ) == 0 )
{
if ( vid_gamma->modified )
{
vid_ref->modified = true;
if ( stricmp( gl_driver->string, "3dfxgl" ) == 0 )
{
char envbuffer[1024];
float g;
vid_ref->modified = true;
g = 2.00 * ( 0.8 - ( vid_gamma->value - 0.5 ) ) + 1.0F;
Com_sprintf( envbuffer, sizeof(envbuffer), "SSTV2_GAMMA=%f", g );
putenv( envbuffer );
Com_sprintf( envbuffer, sizeof(envbuffer), "SST_GAMMA=%f", g );
putenv( envbuffer );
vid_gamma->modified = false;
}
}
if ( gl_driver->modified )
vid_ref->modified = true;
}
M_ForceMenuOff();
}
static void CancelChanges( void *unused )
{
extern void M_PopMenu( void );
M_PopMenu();
}
/*
** VID_MenuInit
*/
void VID_MenuInit( void )
{
static const char *resolutions[] =
{
"[320 240 ]",
"[400 300 ]",
"[512 384 ]",
"[640 480 ]",
"[800 600 ]",
"[960 720 ]",
"[1024 768 ]",
"[1152 864 ]",
"[1280 960 ]",
"[1600 1200]",
0
};
static const char *refs[] =
{
"[software ]",
"[default OpenGL]",
"[3Dfx OpenGL ]",
"[PowerVR OpenGL]",
// "[Rendition OpenGL]",
0
};
static const char *yesno_names[] =
{
"no",
"yes",
0
};
int i;
if ( !gl_driver )
gl_driver = Cvar_Get( "gl_driver", "opengl32", 0 );
if ( !gl_picmip )
gl_picmip = Cvar_Get( "gl_picmip", "0", 0 );
if ( !gl_mode )
gl_mode = Cvar_Get( "gl_mode", "3", 0 );
if ( !sw_mode )
sw_mode = Cvar_Get( "sw_mode", "0", 0 );
if ( !gl_ext_palettedtexture )
gl_ext_palettedtexture = Cvar_Get( "gl_ext_palettedtexture", "1", CVAR_ARCHIVE );
if ( !gl_finish )
gl_finish = Cvar_Get( "gl_finish", "0", CVAR_ARCHIVE );
if ( !sw_stipplealpha )
sw_stipplealpha = Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
s_mode_list[SOFTWARE_MENU].curvalue = sw_mode->value;
s_mode_list[OPENGL_MENU].curvalue = gl_mode->value;
if ( !scr_viewsize )
scr_viewsize = Cvar_Get ("viewsize", "100", CVAR_ARCHIVE);
s_screensize_slider[SOFTWARE_MENU].curvalue = scr_viewsize->value/10;
s_screensize_slider[OPENGL_MENU].curvalue = scr_viewsize->value/10;
if ( strcmp( vid_ref->string, "soft" ) == 0 )
{
s_current_menu_index = SOFTWARE_MENU;
s_ref_list[0].curvalue = s_ref_list[1].curvalue = REF_SOFT;
}
else if ( strcmp( vid_ref->string, "gl" ) == 0 )
{
s_current_menu_index = OPENGL_MENU;
if ( strcmp( gl_driver->string, "3dfxgl" ) == 0 )
s_ref_list[s_current_menu_index].curvalue = REF_3DFX;
else if ( strcmp( gl_driver->string, "pvrgl" ) == 0 )
s_ref_list[s_current_menu_index].curvalue = REF_POWERVR;
else if ( strcmp( gl_driver->string, "opengl32" ) == 0 )
s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
else
// s_ref_list[s_current_menu_index].curvalue = REF_VERITE;
s_ref_list[s_current_menu_index].curvalue = REF_OPENGL;
}
s_software_menu.x = viddef.width * 0.50;
s_software_menu.nitems = 0;
s_opengl_menu.x = viddef.width * 0.50;
s_opengl_menu.nitems = 0;
for ( i = 0; i < 2; i++ )
{
s_ref_list[i].generic.type = MTYPE_SPINCONTROL;
s_ref_list[i].generic.name = "driver";
s_ref_list[i].generic.x = 0;
s_ref_list[i].generic.y = 0;
s_ref_list[i].generic.callback = DriverCallback;
s_ref_list[i].itemnames = refs;
s_mode_list[i].generic.type = MTYPE_SPINCONTROL;
s_mode_list[i].generic.name = "video mode";
s_mode_list[i].generic.x = 0;
s_mode_list[i].generic.y = 10;
s_mode_list[i].itemnames = resolutions;
s_screensize_slider[i].generic.type = MTYPE_SLIDER;
s_screensize_slider[i].generic.x = 0;
s_screensize_slider[i].generic.y = 20;
s_screensize_slider[i].generic.name = "screen size";
s_screensize_slider[i].minvalue = 3;
s_screensize_slider[i].maxvalue = 12;
s_screensize_slider[i].generic.callback = ScreenSizeCallback;
s_brightness_slider[i].generic.type = MTYPE_SLIDER;
s_brightness_slider[i].generic.x = 0;
s_brightness_slider[i].generic.y = 30;
s_brightness_slider[i].generic.name = "brightness";
s_brightness_slider[i].generic.callback = BrightnessCallback;
s_brightness_slider[i].minvalue = 5;
s_brightness_slider[i].maxvalue = 13;
s_brightness_slider[i].curvalue = ( 1.3 - vid_gamma->value + 0.5 ) * 10;
s_fs_box[i].generic.type = MTYPE_SPINCONTROL;
s_fs_box[i].generic.x = 0;
s_fs_box[i].generic.y = 40;
s_fs_box[i].generic.name = "fullscreen";
s_fs_box[i].itemnames = yesno_names;
s_fs_box[i].curvalue = vid_fullscreen->value;
s_defaults_action[i].generic.type = MTYPE_ACTION;
s_defaults_action[i].generic.name = "reset to defaults";
s_defaults_action[i].generic.x = 0;
s_defaults_action[i].generic.y = 90;
s_defaults_action[i].generic.callback = ResetDefaults;
s_cancel_action[i].generic.type = MTYPE_ACTION;
s_cancel_action[i].generic.name = "cancel";
s_cancel_action[i].generic.x = 0;
s_cancel_action[i].generic.y = 100;
s_cancel_action[i].generic.callback = CancelChanges;
}
s_stipple_box.generic.type = MTYPE_SPINCONTROL;
s_stipple_box.generic.x = 0;
s_stipple_box.generic.y = 60;
s_stipple_box.generic.name = "stipple alpha";
s_stipple_box.curvalue = sw_stipplealpha->value;
s_stipple_box.itemnames = yesno_names;
s_tq_slider.generic.type = MTYPE_SLIDER;
s_tq_slider.generic.x = 0;
s_tq_slider.generic.y = 60;
s_tq_slider.generic.name = "texture quality";
s_tq_slider.minvalue = 0;
s_tq_slider.maxvalue = 3;
s_tq_slider.curvalue = 3-gl_picmip->value;
s_paletted_texture_box.generic.type = MTYPE_SPINCONTROL;
s_paletted_texture_box.generic.x = 0;
s_paletted_texture_box.generic.y = 70;
s_paletted_texture_box.generic.name = "8-bit textures";
s_paletted_texture_box.itemnames = yesno_names;
s_paletted_texture_box.curvalue = gl_ext_palettedtexture->value;
s_finish_box.generic.type = MTYPE_SPINCONTROL;
s_finish_box.generic.x = 0;
s_finish_box.generic.y = 80;
s_finish_box.generic.name = "sync every frame";
s_finish_box.curvalue = gl_finish->value;
s_finish_box.itemnames = yesno_names;
Menu_AddItem( &s_software_menu, ( void * ) &s_ref_list[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_mode_list[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_screensize_slider[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_brightness_slider[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_fs_box[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_stipple_box );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_ref_list[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_mode_list[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_screensize_slider[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_brightness_slider[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_fs_box[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_tq_slider );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_paletted_texture_box );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_finish_box );
Menu_AddItem( &s_software_menu, ( void * ) &s_defaults_action[SOFTWARE_MENU] );
Menu_AddItem( &s_software_menu, ( void * ) &s_cancel_action[SOFTWARE_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_defaults_action[OPENGL_MENU] );
Menu_AddItem( &s_opengl_menu, ( void * ) &s_cancel_action[OPENGL_MENU] );
Menu_Center( &s_software_menu );
Menu_Center( &s_opengl_menu );
s_opengl_menu.x -= 8;
s_software_menu.x -= 8;
}
/*
================
VID_MenuDraw
================
*/
void VID_MenuDraw (void)
{
int w, h;
if ( s_current_menu_index == 0 )
s_current_menu = &s_software_menu;
else
s_current_menu = &s_opengl_menu;
/*
** draw the banner
*/
re.DrawGetPicSize( &w, &h, "m_banner_video" );
re.DrawPic( viddef.width / 2 - w / 2, viddef.height /2 - 110, "m_banner_video" );
/*
** move cursor to a reasonable starting position
*/
Menu_AdjustCursor( s_current_menu, 1 );
/*
** draw the menu
*/
Menu_Draw( s_current_menu );
}
/*
================
VID_MenuKey
================
*/
const char *VID_MenuKey( int key )
{
menuframework_s *m = s_current_menu;
static const char *sound = "misc/menu1.wav";
switch ( key )
{
case K_ESCAPE:
ApplyChanges( 0 );
return NULL;
case K_KP_UPARROW:
case K_UPARROW:
m->cursor--;
Menu_AdjustCursor( m, -1 );
break;
case K_KP_DOWNARROW:
case K_DOWNARROW:
m->cursor++;
Menu_AdjustCursor( m, 1 );
break;
case K_KP_LEFTARROW:
case K_LEFTARROW:
Menu_SlideItem( m, -1 );
break;
case K_KP_RIGHTARROW:
case K_RIGHTARROW:
Menu_SlideItem( m, 1 );
break;
case K_KP_ENTER:
case K_ENTER:
if ( !Menu_SelectItem( m ) )
ApplyChanges( NULL );
break;
}
return sound;
}

BIN
win32/winquake.aps Normal file

Binary file not shown.

44
win32/winquake.h Normal file
View File

@ -0,0 +1,44 @@
/*
Copyright (C) 1997-2001 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.
*/
// winquake.h: Win32-specific Quake header file
#pragma warning( disable : 4229 ) // mgraph gets this
#include <windows.h>
#include <dsound.h>
#define WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE)
extern HINSTANCE global_hInstance;
extern LPDIRECTSOUND pDS;
extern LPDIRECTSOUNDBUFFER pDSBuf;
extern DWORD gSndBufSize;
extern HWND cl_hwnd;
extern qboolean ActiveApp, Minimized;
void IN_Activate (qboolean active);
void IN_MouseEvent (int mstate);
extern int window_center_x, window_center_y;
extern RECT window_rect;

98
win32/winquake.rc Normal file
View File

@ -0,0 +1,98 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON1 ICON DISCARDABLE "q2.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DIALOG1 DIALOGEX 0, 0, 62, 21
STYLE DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_CENTER | WS_POPUP |
WS_VISIBLE
EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE
FONT 16, "Times New Roman", 0, 0, 0x1
BEGIN
CTEXT "Starting QW...",IDC_STATIC,4,6,54,8
END
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_STRING1 "WinQuake"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED