]> icculus.org git repositories - divverent/darkplaces.git/blob - sys_win.c
changed Host_Init to execute configs only once
[divverent/darkplaces.git] / sys_win.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sys_win.c -- Win32 system interface code
21
22 #include "quakedef.h"
23 #include <windows.h>
24 #include <dsound.h>
25 #include "errno.h"
26 #include "resource.h"
27 #include "conproc.h"
28 #include "direct.h"
29
30 extern void S_BlockSound (void);
31
32 cvar_t sys_usetimegettime = {CVAR_SAVE, "sys_usetimegettime", "1"};
33
34 HANDLE                          hinput, houtput;
35
36 static HANDLE   tevent;
37 static HANDLE   hFile;
38 static HANDLE   heventParent;
39 static HANDLE   heventChild;
40
41
42 /*
43 ===============================================================================
44
45 SYSTEM IO
46
47 ===============================================================================
48 */
49
50 void Sys_Error (const char *error, ...)
51 {
52         va_list         argptr;
53         char            text[1024];
54         static int      in_sys_error0 = 0;
55         static int      in_sys_error1 = 0;
56         static int      in_sys_error2 = 0;
57         static int      in_sys_error3 = 0;
58
59         va_start (argptr, error);
60         dpvsnprintf (text, sizeof (text), error, argptr);
61         va_end (argptr);
62
63         Con_Printf ("Quake Error: %s\n", text);
64
65         // close video so the message box is visible, unless we already tried that
66         if (!in_sys_error0 && cls.state != ca_dedicated)
67         {
68                 in_sys_error0 = 1;
69                 VID_Shutdown();
70         }
71
72         if (!in_sys_error3 && cls.state != ca_dedicated)
73         {
74                 in_sys_error3 = true;
75                 MessageBox(NULL, text, "Quake Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
76         }
77
78         if (!in_sys_error1)
79         {
80                 in_sys_error1 = 1;
81                 Host_Shutdown ();
82         }
83
84 // shut down QHOST hooks if necessary
85         if (!in_sys_error2)
86         {
87                 in_sys_error2 = 1;
88                 Sys_Shutdown ();
89         }
90
91         exit (1);
92 }
93
94 void Sys_Shutdown (void)
95 {
96         if (tevent)
97                 CloseHandle (tevent);
98
99         if (cls.state == ca_dedicated)
100                 FreeConsole ();
101
102 // shut down QHOST hooks if necessary
103         DeinitConProc ();
104 }
105
106 void Sys_PrintToTerminal(const char *text)
107 {
108         DWORD dummy;
109         extern HANDLE houtput;
110         if (cls.state == ca_dedicated)
111                 WriteFile(houtput, text, strlen (text), &dummy, NULL);
112 }
113
114 /*
115 ================
116 Sys_DoubleTime
117 ================
118 */
119 double Sys_DoubleTime (void)
120 {
121         static int first = true;
122         static double oldtime = 0.0, curtime = 0.0;
123         double newtime;
124         // LordHavoc: note to people modifying this code, DWORD is specifically defined as an unsigned 32bit number, therefore the 65536.0 * 65536.0 is fine.
125         if (sys_usetimegettime.integer)
126         {
127                 static int firsttimegettime = true;
128                 // timeGetTime
129                 // platform:
130                 // Windows 95/98/ME/NT/2000/XP
131                 // features:
132                 // reasonable accuracy (millisecond)
133                 // issues:
134                 // wraps around every 47 days or so (but this is non-fatal to us, odd times are rejected, only causes a one frame stutter)
135
136                 // make sure the timer is high precision, otherwise different versions of windows have varying accuracy
137                 if (firsttimegettime)
138                 {
139                         timeBeginPeriod (1);
140                         firsttimegettime = false;
141                 }
142
143                 newtime = (double) timeGetTime () / 1000.0;
144         }
145         else
146         {
147                 // QueryPerformanceCounter
148                 // platform:
149                 // Windows 95/98/ME/NT/2000/XP
150                 // features:
151                 // very accurate (CPU cycles)
152                 // known issues:
153                 // does not necessarily match realtime too well (tends to get faster and faster in win98)
154                 // wraps around occasionally on some platforms (depends on CPU speed and probably other unknown factors)
155                 double timescale;
156                 LARGE_INTEGER PerformanceFreq;
157                 LARGE_INTEGER PerformanceCount;
158
159                 if (!QueryPerformanceFrequency (&PerformanceFreq))
160                         Sys_Error ("No hardware timer available");
161                 QueryPerformanceCounter (&PerformanceCount);
162
163                 #ifdef __BORLANDC__
164                 timescale = 1.0 / ((double) PerformanceFreq.u.LowPart + (double) PerformanceFreq.u.HighPart * 65536.0 * 65536.0);
165                 newtime = ((double) PerformanceCount.u.LowPart + (double) PerformanceCount.u.HighPart * 65536.0 * 65536.0) * timescale;
166                 #else
167                 timescale = 1.0 / ((double) PerformanceFreq.LowPart + (double) PerformanceFreq.HighPart * 65536.0 * 65536.0);
168                 newtime = ((double) PerformanceCount.LowPart + (double) PerformanceCount.HighPart * 65536.0 * 65536.0) * timescale;
169                 #endif
170         }
171
172         if (first)
173         {
174                 first = false;
175                 oldtime = newtime;
176         }
177
178         if (newtime < oldtime)
179         {
180                 // warn if it's significant
181                 if (newtime - oldtime < -0.01)
182                         Con_Printf("Sys_DoubleTime: time stepped backwards (went from %f to %f, difference %f)\n", oldtime, newtime, newtime - oldtime);
183         }
184         else
185                 curtime += newtime - oldtime;
186         oldtime = newtime;
187
188         return curtime;
189 }
190
191
192 char *Sys_ConsoleInput (void)
193 {
194         static char text[256];
195         static int len;
196         INPUT_RECORD recs[1024];
197         int ch;
198         DWORD numread, numevents, dummy;
199
200         if (cls.state != ca_dedicated)
201                 return NULL;
202
203
204         for ( ;; )
205         {
206                 if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
207                         Sys_Error ("Error getting # of console events");
208
209                 if (numevents <= 0)
210                         break;
211
212                 if (!ReadConsoleInput(hinput, recs, 1, &numread))
213                         Sys_Error ("Error reading console input");
214
215                 if (numread != 1)
216                         Sys_Error ("Couldn't read console input");
217
218                 if (recs[0].EventType == KEY_EVENT)
219                 {
220                         if (!recs[0].Event.KeyEvent.bKeyDown)
221                         {
222                                 ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
223
224                                 switch (ch)
225                                 {
226                                         case '\r':
227                                                 WriteFile(houtput, "\r\n", 2, &dummy, NULL);
228
229                                                 if (len)
230                                                 {
231                                                         text[len] = 0;
232                                                         len = 0;
233                                                         return text;
234                                                 }
235
236                                                 break;
237
238                                         case '\b':
239                                                 WriteFile(houtput, "\b \b", 3, &dummy, NULL);
240                                                 if (len)
241                                                 {
242                                                         len--;
243                                                 }
244                                                 break;
245
246                                         default:
247                                                 if (ch >= ' ')
248                                                 {
249                                                         WriteFile(houtput, &ch, 1, &dummy, NULL);
250                                                         text[len] = ch;
251                                                         len = (len + 1) & 0xff;
252                                                 }
253
254                                                 break;
255
256                                 }
257                         }
258                 }
259         }
260
261         return NULL;
262 }
263
264 void Sys_Sleep(int milliseconds)
265 {
266         if (milliseconds < 1)
267                 milliseconds = 1;
268         Sleep(milliseconds);
269 }
270
271 char *Sys_GetClipboardData (void)
272 {
273         char *data = NULL;
274         char *cliptext;
275
276         if (OpenClipboard (NULL) != 0)
277         {
278                 HANDLE hClipboardData;
279
280                 if ((hClipboardData = GetClipboardData (CF_TEXT)) != 0)
281                 {
282                         if ((cliptext = GlobalLock (hClipboardData)) != 0)
283                         {
284                                 data = malloc (GlobalSize(hClipboardData)+1);
285                                 strcpy (data, cliptext);
286                                 GlobalUnlock (hClipboardData);
287                         }
288                 }
289                 CloseClipboard ();
290         }
291         return data;
292 }
293
294 void Sys_InitConsole (void)
295 {
296         // initialize the windows dedicated server console if needed
297         tevent = CreateEvent(NULL, false, false, NULL);
298
299         if (!tevent)
300                 Sys_Error ("Couldn't create event");
301
302         // LordHavoc: can't check cls.state because it hasn't been initialized yet
303         // if (cls.state == ca_dedicated)
304         if (COM_CheckParm("-dedicated"))
305         {
306                 if (!AllocConsole ())
307                         Sys_Error ("Couldn't create dedicated server console");
308
309                 hinput = GetStdHandle (STD_INPUT_HANDLE);
310                 houtput = GetStdHandle (STD_OUTPUT_HANDLE);
311
312         // give QHOST a chance to hook into the console
313                 if ((t = COM_CheckParm ("-HFILE")) > 0)
314                 {
315                         if (t < com_argc)
316                                 hFile = (HANDLE)atoi (com_argv[t+1]);
317                 }
318
319                 if ((t = COM_CheckParm ("-HPARENT")) > 0)
320                 {
321                         if (t < com_argc)
322                                 heventParent = (HANDLE)atoi (com_argv[t+1]);
323                 }
324
325                 if ((t = COM_CheckParm ("-HCHILD")) > 0)
326                 {
327                         if (t < com_argc)
328                                 heventChild = (HANDLE)atoi (com_argv[t+1]);
329                 }
330
331                 InitConProc (hFile, heventParent, heventChild);
332         }
333
334 // because sound is off until we become active
335         S_BlockSound ();
336 }
337
338 void Sys_Init_Commands (void)
339 {
340         Cvar_RegisterVariable(&sys_usetimegettime);
341 }
342
343 /*
344 ==============================================================================
345
346 WINDOWS CRAP
347
348 ==============================================================================
349 */
350
351
352 /*
353 ==================
354 WinMain
355 ==================
356 */
357 HINSTANCE       global_hInstance;
358 const char      *argv[MAX_NUM_ARGVS];
359 char            program_name[MAX_OSPATH];
360
361 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
362 {
363         double frameoldtime, framenewtime;
364         MEMORYSTATUS lpBuffer;
365         int t;
366
367         /* previous instances do not exist in Win32 */
368         if (hPrevInstance)
369                 return 0;
370
371         global_hInstance = hInstance;
372
373         lpBuffer.dwLength = sizeof(MEMORYSTATUS);
374         GlobalMemoryStatus (&lpBuffer);
375
376         program_name[sizeof(program_name)-1] = 0;
377         GetModuleFileNameA(NULL, program_name, sizeof(program_name) - 1);
378
379         com_argc = 1;
380         com_argv = argv;
381         argv[0] = program_name;
382
383         // FIXME: this tokenizer is rather redundent, call a more general one
384         while (*lpCmdLine && (com_argc < MAX_NUM_ARGVS))
385         {
386                 while (*lpCmdLine && *lpCmdLine <= ' ')
387                         lpCmdLine++;
388
389                 if (!*lpCmdLine)
390                         break;
391
392                 if (*lpCmdLine == '\"')
393                 {
394                         // quoted string
395                         lpCmdLine++;
396                         argv[com_argc] = lpCmdLine;
397                         com_argc++;
398                         while (*lpCmdLine && (*lpCmdLine != '\"'))
399                                 lpCmdLine++;
400                 }
401                 else
402                 {
403                         // unquoted word
404                         argv[com_argc] = lpCmdLine;
405                         com_argc++;
406                         while (*lpCmdLine && *lpCmdLine > ' ')
407                                 lpCmdLine++;
408                 }
409
410                 if (*lpCmdLine)
411                 {
412                         *lpCmdLine = 0;
413                         lpCmdLine++;
414                 }
415         }
416
417         Host_Init ();
418
419         frameoldtime = Sys_DoubleTime ();
420
421         /* main window message loop */
422         while (1)
423         {
424                 framenewtime = Sys_DoubleTime ();
425                 Host_Frame (framenewtime - frameoldtime);
426                 frameoldtime = framenewtime;
427         }
428
429         /* return success of application */
430         return true;
431 }