mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-10 07:12:07 +00:00
Add windows/system.c
This files contains most support functions for windows and the main loop. It was taken from Icculus Quake II and cleaned up. This early version may still have bugs.
This commit is contained in:
parent
ce3d61ef61
commit
4adc6a2ca2
1 changed files with 573 additions and 0 deletions
573
src/windows/system.c
Normal file
573
src/windows/system.c
Normal file
|
@ -0,0 +1,573 @@
|
|||
/*
|
||||
* 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.
|
||||
*
|
||||
* =======================================================================
|
||||
*
|
||||
* This file is the starting point of the program and implements
|
||||
* several support functions and the main loop.
|
||||
*
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <float.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#include <conio.h>
|
||||
|
||||
#include "../common/header/common.h"
|
||||
#include "conproc.h"
|
||||
#include "resource.h"
|
||||
#include "winquake.h"
|
||||
|
||||
#define MAX_NUM_ARGVS 128
|
||||
|
||||
int starttime;
|
||||
int ActiveApp;
|
||||
qboolean Minimized;
|
||||
|
||||
static HANDLE hinput, houtput;
|
||||
static HANDLE qwclsemaphore;
|
||||
|
||||
HINSTANCE global_hInstance;
|
||||
static HINSTANCE game_library;
|
||||
|
||||
unsigned int sys_msg_time;
|
||||
unsigned int sys_frame_time;
|
||||
|
||||
static char console_text[256];
|
||||
static int console_textlen;
|
||||
|
||||
int argc;
|
||||
char *argv[MAX_NUM_ARGVS];
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
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),
|
||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
|
||||
/* Display the string. */
|
||||
MessageBox(NULL, lpMsgBuf, "GetLastError", MB_OK | MB_ICONINFORMATION);
|
||||
|
||||
/* Free the buffer. */
|
||||
LocalFree(lpMsgBuf);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
char *
|
||||
Sys_ScanForCD(void)
|
||||
{
|
||||
static char cddir[MAX_OSPATH];
|
||||
static qboolean done;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cddir[0] = 0;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
Sys_Init(void)
|
||||
{
|
||||
OSVERSIONINFO vinfo;
|
||||
|
||||
timeBeginPeriod(1);
|
||||
vinfo.dwOSVersionInfoSize = sizeof(vinfo);
|
||||
|
||||
if (!GetVersionEx(&vinfo))
|
||||
{
|
||||
Sys_Error("Couldn't get OS info");
|
||||
}
|
||||
|
||||
/* While Quake II should run on older versions,
|
||||
limit Yamagi Quake II to Windows XP and
|
||||
above. Testing older version would be a
|
||||
PITA. */
|
||||
if (!(vinfo.dwMajorVersion > 5) ||
|
||||
((vinfo.dwMajorVersion == 5) &&
|
||||
(vinfo.dwMinorVersion >= 1)))
|
||||
{
|
||||
Sys_Error("Yamagi Quake II needs Windows XP or higher!\n");
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
Sys_AppActivate(void)
|
||||
{
|
||||
ShowWindow(cl_hwnd, SW_RESTORE);
|
||||
SetForegroundWindow(cl_hwnd);
|
||||
}
|
||||
|
||||
/* ================================================================ */
|
||||
|
||||
void
|
||||
Sys_UnloadGame(void)
|
||||
{
|
||||
if (!FreeLibrary(game_library))
|
||||
{
|
||||
Com_Error(ERR_FATAL, "FreeLibrary failed for game library");
|
||||
}
|
||||
|
||||
game_library = NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
Sys_GetGameAPI(void *parms)
|
||||
{
|
||||
void *(*GetGameAPI)(void *);
|
||||
const char *gamename = "game.dll";
|
||||
char name[MAX_OSPATH];
|
||||
char *path = NULL;
|
||||
char cwd[MAX_OSPATH];
|
||||
|
||||
if (game_library)
|
||||
{
|
||||
Com_Error(ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
|
||||
}
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* ======================================================================= */
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Windows main function. Containts the
|
||||
* initialization code and the main loop
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/* Make the current instance global */
|
||||
global_hInstance = hInstance;
|
||||
|
||||
/* Parse the command line arguments */
|
||||
ParseCommandLine(lpCmdLine);
|
||||
|
||||
/* Search the CD (for partial installations) */
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the initialization code */
|
||||
Qcommon_Init(argc, argv);
|
||||
|
||||
/* Save our time */
|
||||
oldtime = Sys_Milliseconds();
|
||||
|
||||
/* The legendary main 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);
|
||||
|
||||
_controlfp(_PC_24, _MCW_PC);
|
||||
Qcommon_Frame(time);
|
||||
|
||||
oldtime = newtime;
|
||||
}
|
||||
|
||||
/* never gets here */
|
||||
return TRUE;
|
||||
}
|
||||
|
Loading…
Reference in a new issue