home *** CD-ROM | disk | FTP | other *** search
/ Magazyn Amiga 14 / MA_Cover_14.iso / source / c / q1source_amy / qw / client / sys_win.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-12-21  |  13.3 KB  |  699 lines

  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.h
  21.  
  22. #include "quakedef.h"
  23. #include "winquake.h"
  24. #include "resource.h"
  25. #include "errno.h"
  26. #include "fcntl.h"
  27. #include <limits.h>
  28.  
  29. #define MINIMUM_WIN_MEMORY    0x0c00000
  30. #define MAXIMUM_WIN_MEMORY    0x1000000
  31.  
  32. #define PAUSE_SLEEP        50                // sleep time on pause or minimization
  33. #define NOT_FOCUS_SLEEP    20                // sleep time when not focus
  34.  
  35. int        starttime;
  36. qboolean ActiveApp, Minimized;
  37. qboolean    WinNT;
  38.  
  39. HWND    hwnd_dialog;        // startup dialog box
  40.  
  41. static double        pfreq;
  42. static double        curtime = 0.0;
  43. static double        lastcurtime = 0.0;
  44. static int            lowshift;
  45. static HANDLE        hinput, houtput;
  46.  
  47. HANDLE        qwclsemaphore;
  48.  
  49. static HANDLE    tevent;
  50.  
  51. void Sys_InitFloatTime (void);
  52.  
  53. void MaskExceptions (void);
  54. void Sys_PopFPCW (void);
  55. void Sys_PushFPCW_SetHigh (void);
  56.  
  57. void Sys_DebugLog(char *file, char *fmt, ...)
  58. {
  59.     va_list argptr; 
  60.     static char data[1024];
  61.     int fd;
  62.     
  63.     va_start(argptr, fmt);
  64.     vsprintf(data, fmt, argptr);
  65.     va_end(argptr);
  66.     fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);
  67.     write(fd, data, strlen(data));
  68.     close(fd);
  69. };
  70.  
  71. /*
  72. ===============================================================================
  73.  
  74. FILE IO
  75.  
  76. ===============================================================================
  77. */
  78.  
  79. /*
  80. ================
  81. filelength
  82. ================
  83. */
  84. int filelength (FILE *f)
  85. {
  86.     int        pos;
  87.     int        end;
  88.  
  89.     pos = ftell (f);
  90.     fseek (f, 0, SEEK_END);
  91.     end = ftell (f);
  92.     fseek (f, pos, SEEK_SET);
  93.  
  94.     return end;
  95. }
  96.  
  97.  
  98. int    Sys_FileTime (char *path)
  99. {
  100.     FILE    *f;
  101.     int        t, retval;
  102.  
  103.     t = VID_ForceUnlockedAndReturnState ();
  104.     
  105.     f = fopen(path, "rb");
  106.  
  107.     if (f)
  108.     {
  109.         fclose(f);
  110.         retval = 1;
  111.     }
  112.     else
  113.     {
  114.         retval = -1;
  115.     }
  116.     
  117.     VID_ForceLockState (t);
  118.     return retval;
  119. }
  120.  
  121. void Sys_mkdir (char *path)
  122. {
  123.     _mkdir (path);
  124. }
  125.  
  126.  
  127. /*
  128. ===============================================================================
  129.  
  130. SYSTEM IO
  131.  
  132. ===============================================================================
  133. */
  134.  
  135. /*
  136. ================
  137. Sys_MakeCodeWriteable
  138. ================
  139. */
  140. void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
  141. {
  142.     DWORD  flOldProtect;
  143.  
  144. //@@@ copy on write or just read-write?
  145.     if (!VirtualProtect((LPVOID)startaddr, length, PAGE_READWRITE, &flOldProtect))
  146.            Sys_Error("Protection change failed\n");
  147. }
  148.  
  149.  
  150. /*
  151. ================
  152. Sys_Init
  153. ================
  154. */
  155. void Sys_Init (void)
  156. {
  157.     LARGE_INTEGER    PerformanceFreq;
  158.     unsigned int    lowpart, highpart;
  159.     OSVERSIONINFO    vinfo;
  160.  
  161. #ifndef SERVERONLY
  162.     // allocate a named semaphore on the client so the
  163.     // front end can tell if it is alive
  164.  
  165.     // mutex will fail if semephore allready exists
  166.     qwclsemaphore = CreateMutex(
  167.         NULL,         /* Security attributes */
  168.         0,            /* owner       */
  169.         "qwcl"); /* Semaphore name      */
  170.     if (!qwclsemaphore)
  171.         Sys_Error ("QWCL is already running on this system");
  172.     CloseHandle (qwclsemaphore);
  173.  
  174.     qwclsemaphore = CreateSemaphore(
  175.         NULL,         /* Security attributes */
  176.         0,            /* Initial count       */
  177.         1,            /* Maximum count       */
  178.         "qwcl"); /* Semaphore name      */
  179. #endif
  180.  
  181.     MaskExceptions ();
  182.     Sys_SetFPCW ();
  183.  
  184. #if 0
  185.     if (!QueryPerformanceFrequency (&PerformanceFreq))
  186.         Sys_Error ("No hardware timer available");
  187.  
  188. // get 32 out of the 64 time bits such that we have around
  189. // 1 microsecond resolution
  190.     lowpart = (unsigned int)PerformanceFreq.LowPart;
  191.     highpart = (unsigned int)PerformanceFreq.HighPart;
  192.     lowshift = 0;
  193.  
  194.     while (highpart || (lowpart > 2000000.0))
  195.     {
  196.         lowshift++;
  197.         lowpart >>= 1;
  198.         lowpart |= (highpart & 1) << 31;
  199.         highpart >>= 1;
  200.     }
  201.  
  202.     pfreq = 1.0 / (double)lowpart;
  203.  
  204.     Sys_InitFloatTime ();
  205. #endif
  206.  
  207.     // make sure the timer is high precision, otherwise
  208.     // NT gets 18ms resolution
  209.     timeBeginPeriod( 1 );
  210.  
  211.     vinfo.dwOSVersionInfoSize = sizeof(vinfo);
  212.  
  213.     if (!GetVersionEx (&vinfo))
  214.         Sys_Error ("Couldn't get OS info");
  215.  
  216.     if ((vinfo.dwMajorVersion < 4) ||
  217.         (vinfo.dwPlatformId == VER_PLATFORM_WIN32s))
  218.     {
  219.         Sys_Error ("QuakeWorld requires at least Win95 or NT 4.0");
  220.     }
  221.     
  222.     if (vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  223.         WinNT = true;
  224.     else
  225.         WinNT = false;
  226. }
  227.  
  228.  
  229. void Sys_Error (char *error, ...)
  230. {
  231.     va_list        argptr;
  232.     char        text[1024], text2[1024];
  233.     DWORD        dummy;
  234.  
  235.     Host_Shutdown ();
  236.  
  237.     va_start (argptr, error);
  238.     vsprintf (text, error, argptr);
  239.     va_end (argptr);
  240.  
  241.     MessageBox(NULL, text, "Error", 0 /* MB_OK */ );
  242.  
  243. #ifndef SERVERONLY
  244.     CloseHandle (qwclsemaphore);
  245. #endif
  246.  
  247.     exit (1);
  248. }
  249.  
  250. void Sys_Printf (char *fmt, ...)
  251. {
  252.     va_list        argptr;
  253.     char        text[1024];
  254.     DWORD        dummy;
  255.     
  256.     va_start (argptr,fmt);
  257.     vprintf (fmt, argptr);
  258.     va_end (argptr);
  259. }
  260.  
  261. void Sys_Quit (void)
  262. {
  263.     VID_ForceUnlockedAndReturnState ();
  264.  
  265.     Host_Shutdown();
  266. #ifndef SERVERONLY
  267.     if (tevent)
  268.         CloseHandle (tevent);
  269.  
  270.     if (qwclsemaphore)
  271.         CloseHandle (qwclsemaphore);
  272. #endif
  273.  
  274.     exit (0);
  275. }
  276.  
  277.  
  278. #if 0
  279. /*
  280. ================
  281. Sys_DoubleTime
  282. ================
  283. */
  284. double Sys_DoubleTime (void)
  285. {
  286.     static int            sametimecount;
  287.     static unsigned int    oldtime;
  288.     static int            first = 1;
  289.     LARGE_INTEGER        PerformanceCount;
  290.     unsigned int        temp, t2;
  291.     double                time;
  292.  
  293.     Sys_PushFPCW_SetHigh ();
  294.  
  295.     QueryPerformanceCounter (&PerformanceCount);
  296.  
  297.     temp = ((unsigned int)PerformanceCount.LowPart >> lowshift) |
  298.            ((unsigned int)PerformanceCount.HighPart << (32 - lowshift));
  299.  
  300.     if (first)
  301.     {
  302.         oldtime = temp;
  303.         first = 0;
  304.     }
  305.     else
  306.     {
  307.     // check for turnover or backward time
  308.         if ((temp <= oldtime) && ((oldtime - temp) < 0x10000000))
  309.         {
  310.             oldtime = temp;    // so we can't get stuck
  311.         }
  312.         else
  313.         {
  314.             t2 = temp - oldtime;
  315.  
  316.             time = (double)t2 * pfreq;
  317.             oldtime = temp;
  318.  
  319.             curtime += time;
  320.  
  321.             if (curtime == lastcurtime)
  322.             {
  323.                 sametimecount++;
  324.  
  325.                 if (sametimecount > 100000)
  326.                 {
  327.                     curtime += 1.0;
  328.                     sametimecount = 0;
  329.                 }
  330.             }
  331.             else
  332.             {
  333.                 sametimecount = 0;
  334.             }
  335.  
  336.             lastcurtime = curtime;
  337.         }
  338.     }
  339.  
  340.     Sys_PopFPCW ();
  341.  
  342.     return curtime;
  343. }
  344.  
  345. /*
  346. ================
  347. Sys_InitFloatTime
  348. ================
  349. */
  350. void Sys_InitFloatTime (void)
  351. {
  352.     int        j;
  353.  
  354.     Sys_DoubleTime ();
  355.  
  356.     j = COM_CheckParm("-starttime");
  357.  
  358.     if (j)
  359.     {
  360.         curtime = (double) (Q_atof(com_argv[j+1]));
  361.     }
  362.     else
  363.     {
  364.         curtime = 0.0;
  365.     }
  366.  
  367.     lastcurtime = curtime;
  368. }
  369.  
  370. #endif
  371.  
  372. double Sys_DoubleTime (void)
  373. {
  374.     static DWORD starttime;
  375.     static qboolean first = true;
  376.     DWORD now;
  377.     double t;
  378.  
  379.     now = timeGetTime();
  380.  
  381.     if (first) {
  382.         first = false;
  383.         starttime = now;
  384.         return 0.0;
  385.     }
  386.     
  387.     if (now < starttime) // wrapped?
  388.         return (now / 1000.0) + (LONG_MAX - starttime / 1000.0);
  389.  
  390.     if (now - starttime == 0)
  391.         return 0.0;
  392.  
  393.     return (now - starttime) / 1000.0;
  394. }
  395.  
  396. char *Sys_ConsoleInput (void)
  397. {
  398.     static char    text[256];
  399.     static int        len;
  400.     INPUT_RECORD    recs[1024];
  401.     int        count;
  402.     int        i, dummy;
  403.     int        ch, numread, numevents;
  404.     HANDLE    th;
  405.     char    *clipText, *textCopied;
  406.  
  407.     for ( ;; )
  408.     {
  409.         if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
  410.             Sys_Error ("Error getting # of console events");
  411.  
  412.         if (numevents <= 0)
  413.             break;
  414.  
  415.         if (!ReadConsoleInput(hinput, recs, 1, &numread))
  416.             Sys_Error ("Error reading console input");
  417.  
  418.         if (numread != 1)
  419.             Sys_Error ("Couldn't read console input");
  420.  
  421.         if (recs[0].EventType == KEY_EVENT)
  422.         {
  423.             if (!recs[0].Event.KeyEvent.bKeyDown)
  424.             {
  425.                 ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
  426.  
  427.                 switch (ch)
  428.                 {
  429.                     case '\r':
  430.                         WriteFile(houtput, "\r\n", 2, &dummy, NULL);    
  431.  
  432.                         if (len)
  433.                         {
  434.                             text[len] = 0;
  435.                             len = 0;
  436.                             return text;
  437.                         }
  438.                         break;
  439.  
  440.                     case '\b':
  441.                         WriteFile(houtput, "\b \b", 3, &dummy, NULL);    
  442.                         if (len)
  443.                         {
  444.                             len--;
  445.                             putch('\b');
  446.                         }
  447.                         break;
  448.  
  449.                     default:
  450.                         Con_Printf("Stupid: %d\n", recs[0].Event.KeyEvent.dwControlKeyState);
  451.                         if (((ch=='V' || ch=='v') && (recs[0].Event.KeyEvent.dwControlKeyState & 
  452.                             (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))) || ((recs[0].Event.KeyEvent.dwControlKeyState 
  453.                             & SHIFT_PRESSED) && (recs[0].Event.KeyEvent.wVirtualKeyCode
  454.                             ==VK_INSERT))) {
  455.                             if (OpenClipboard(NULL)) {
  456.                                 th = GetClipboardData(CF_TEXT);
  457.                                 if (th) {
  458.                                     clipText = GlobalLock(th);
  459.                                     if (clipText) {
  460.                                         textCopied = malloc(GlobalSize(th)+1);
  461.                                         strcpy(textCopied, clipText);
  462. /* Substitutes a NULL for every token */strtok(textCopied, "\n\r\b");
  463.                                         i = strlen(textCopied);
  464.                                         if (i+len>=256)
  465.                                             i=256-len;
  466.                                         if (i>0) {
  467.                                             textCopied[i]=0;
  468.                                             text[len]=0;
  469.                                             strcat(text, textCopied);
  470.                                             len+=dummy;
  471.                                             WriteFile(houtput, textCopied, i, &dummy, NULL);
  472.                                         }
  473.                                         free(textCopied);
  474.                                     }
  475.                                     GlobalUnlock(th);
  476.                                 }
  477.                                 CloseClipboard();
  478.                             }
  479.                         } else if (ch >= ' ')
  480.                         {
  481.                             WriteFile(houtput, &ch, 1, &dummy, NULL);    
  482.                             text[len] = ch;
  483.                             len = (len + 1) & 0xff;
  484.                         }
  485.  
  486.                         break;
  487.  
  488.                 }
  489.             }
  490.         }
  491.     }
  492.  
  493.     return NULL;
  494. }
  495.  
  496. void Sys_Sleep (void)
  497. {
  498. }
  499.  
  500.  
  501. void Sys_SendKeyEvents (void)
  502. {
  503.     MSG        msg;
  504.  
  505.     while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
  506.     {
  507.     // we always update if there are any event, even if we're paused
  508.         scr_skipupdate = 0;
  509.  
  510.         if (!GetMessage (&msg, NULL, 0, 0))
  511.             Sys_Quit ();
  512.           TranslateMessage (&msg);
  513.           DispatchMessage (&msg);
  514.     }
  515. }
  516.  
  517.  
  518.  
  519. /*
  520. ==============================================================================
  521.  
  522.  WINDOWS CRAP
  523.  
  524. ==============================================================================
  525. */
  526.  
  527. /*
  528. ==================
  529. WinMain
  530. ==================
  531. */
  532. void SleepUntilInput (int time)
  533. {
  534.  
  535.     MsgWaitForMultipleObjects(1, &tevent, FALSE, time, QS_ALLINPUT);
  536. }
  537.  
  538.  
  539.  
  540. /*
  541. ==================
  542. WinMain
  543. ==================
  544. */
  545. HINSTANCE    global_hInstance;
  546. int            global_nCmdShow;
  547. char        *argv[MAX_NUM_ARGVS];
  548. static char    *empty_string = "";
  549. HWND        hwnd_dialog;
  550.  
  551.  
  552. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  553. {
  554.     MSG                msg;
  555.     quakeparms_t    parms;
  556.     double            time, oldtime, newtime;
  557.     MEMORYSTATUS    lpBuffer;
  558.     static    char    cwd[1024];
  559.     int                t;
  560.     RECT            rect;
  561.  
  562.     /* previous instances do not exist in Win32 */
  563.     if (hPrevInstance)
  564.         return 0;
  565.  
  566.     global_hInstance = hInstance;
  567.     global_nCmdShow = nCmdShow;
  568.  
  569.     lpBuffer.dwLength = sizeof(MEMORYSTATUS);
  570.     GlobalMemoryStatus (&lpBuffer);
  571.  
  572.     if (!GetCurrentDirectory (sizeof(cwd), cwd))
  573.         Sys_Error ("Couldn't determine current directory");
  574.  
  575.     if (cwd[Q_strlen(cwd)-1] == '/')
  576.         cwd[Q_strlen(cwd)-1] = 0;
  577.  
  578.     parms.basedir = cwd;
  579.     parms.cachedir = NULL;
  580.  
  581.     parms.argc = 1;
  582.     argv[0] = empty_string;
  583.  
  584.     while (*lpCmdLine && (parms.argc < MAX_NUM_ARGVS))
  585.     {
  586.         while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
  587.             lpCmdLine++;
  588.  
  589.         if (*lpCmdLine)
  590.         {
  591.             argv[parms.argc] = lpCmdLine;
  592.             parms.argc++;
  593.  
  594.             while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
  595.                 lpCmdLine++;
  596.  
  597.             if (*lpCmdLine)
  598.             {
  599.                 *lpCmdLine = 0;
  600.                 lpCmdLine++;
  601.             }
  602.             
  603.         }
  604.     }
  605.  
  606.     parms.argv = argv;
  607.  
  608.     COM_InitArgv (parms.argc, parms.argv);
  609.  
  610.     parms.argc = com_argc;
  611.     parms.argv = com_argv;
  612.  
  613.     hwnd_dialog = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), NULL, NULL);
  614.  
  615.     if (hwnd_dialog)
  616.     {
  617.         if (GetWindowRect (hwnd_dialog, &rect))
  618.         {
  619.             if (rect.left > (rect.top * 2))
  620.             {
  621.                 SetWindowPos (hwnd_dialog, 0,
  622.                     (rect.left / 2) - ((rect.right - rect.left) / 2),
  623.                     rect.top, 0, 0,
  624.                     SWP_NOZORDER | SWP_NOSIZE);
  625.             }
  626.         }
  627.  
  628.         ShowWindow (hwnd_dialog, SW_SHOWDEFAULT);
  629.         UpdateWindow (hwnd_dialog);
  630.         SetForegroundWindow (hwnd_dialog);
  631.     }
  632.  
  633. // take the greater of all the available memory or half the total memory,
  634. // but at least 8 Mb and no more than 16 Mb, unless they explicitly
  635. // request otherwise
  636.     parms.memsize = lpBuffer.dwAvailPhys;
  637.  
  638.     if (parms.memsize < MINIMUM_WIN_MEMORY)
  639.         parms.memsize = MINIMUM_WIN_MEMORY;
  640.  
  641.     if (parms.memsize < (lpBuffer.dwTotalPhys >> 1))
  642.         parms.memsize = lpBuffer.dwTotalPhys >> 1;
  643.  
  644.     if (parms.memsize > MAXIMUM_WIN_MEMORY)
  645.         parms.memsize = MAXIMUM_WIN_MEMORY;
  646.  
  647.     if (COM_CheckParm ("-heapsize"))
  648.     {
  649.         t = COM_CheckParm("-heapsize") + 1;
  650.  
  651.         if (t < com_argc)
  652.             parms.memsize = Q_atoi (com_argv[t]) * 1024;
  653.     }
  654.  
  655.     parms.membase = malloc (parms.memsize);
  656.  
  657.     if (!parms.membase)
  658.         Sys_Error ("Not enough memory free; check disk space\n");
  659.  
  660.     tevent = CreateEvent(NULL, FALSE, FALSE, NULL);
  661.  
  662.     if (!tevent)
  663.         Sys_Error ("Couldn't create event");
  664.  
  665.     Sys_Init ();
  666.  
  667. // because sound is off until we become active
  668.     S_BlockSound ();
  669.  
  670.     Sys_Printf ("Host_Init\n");
  671.     Host_Init (&parms);
  672.  
  673.     oldtime = Sys_DoubleTime ();
  674.  
  675.     /* main window message loop */
  676.     while (1)
  677.     {
  678.     // yield the CPU for a little while when paused, minimized, or not the focus
  679.         if ((cl.paused && (!ActiveApp && !DDActive)) || Minimized || block_drawing)
  680.         {
  681.             SleepUntilInput (PAUSE_SLEEP);
  682.             scr_skipupdate = 1;        // no point in bothering to draw
  683.         }
  684.         else if (!ActiveApp && !DDActive)
  685.         {
  686.             SleepUntilInput (NOT_FOCUS_SLEEP);
  687.         }
  688.  
  689.         newtime = Sys_DoubleTime ();
  690.         time = newtime - oldtime;
  691.         Host_Frame (time);
  692.         oldtime = newtime;
  693.     }
  694.  
  695.     /* return success of application */
  696.     return TRUE;
  697. }
  698.  
  699.