home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / directx / foxbear / foxbear.c < prev    next >
C/C++ Source or Header  |  1997-07-14  |  27KB  |  1,056 lines

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *  Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
  5.  *
  6.  *  File:    winfox.c
  7.  *  Content:    Windows fox sample game
  8.  *
  9.  ***************************************************************************/
  10. #include "foxbear.h"
  11. #include "rcids.h"      // for FOX_ICON
  12.  
  13. LPDIRECTDRAWSURFACE     lpFrontBuffer;
  14. LPDIRECTDRAWSURFACE     lpBackBuffer;
  15. LPDIRECTDRAWCLIPPER     lpClipper;
  16. LPDIRECTDRAWSURFACE     lpStretchBuffer;
  17. LPDIRECTDRAWSURFACE     lpFrameRate;
  18. LPDIRECTDRAWSURFACE     lpInfo;
  19. LPDIRECTDRAWPALETTE     lpPalette;
  20. LPDIRECTDRAW            lpDD;
  21. LPDIRECTDRAW2           lpDD2;
  22. SHORT                   lastInput = 0;
  23. HWND                    hWndMain;
  24. RECT                    rcWindow;
  25. BOOL                    bShowFrameCount=TRUE;
  26. BOOL                    bIsActive;
  27. BOOL                    bPaused;
  28.  
  29. BOOL                    bStretch;
  30. BOOL                    bFullscreen=TRUE;
  31. BOOL                    bStress=FALSE;     // just keep running if true
  32. BOOL                    bHelp=FALSE;       // help requested
  33. RECT                    GameRect;          // game rect
  34. SIZE                    GameSize;          // game is this size
  35. SIZE                    GameMode;          // display mode size
  36. UINT                    GameBPP;           // the bpp we want
  37. DWORD                   dwColorKey;        // our color key
  38. DWORD                   AveFrameRate;
  39. DWORD                   AveFrameRateCount;
  40. BOOL                    bWantSound = TRUE;
  41.  
  42. extern int              DevIndex;
  43. extern int              MaxDevIndex;
  44.  
  45. #define OUR_APP_NAME  "Win Fox Application"
  46.  
  47. #define ODS OutputDebugString
  48.  
  49. BOOL InitGame(void);
  50. void ExitGame(void);
  51. void initNumSurface(void);
  52. #ifndef DEBUG
  53. void __cdecl Msg( LPSTR fmt, ... ) { }
  54. #endif
  55.  
  56.  
  57. /*
  58.  * PauseGame()
  59.  */
  60. void PauseGame()
  61. {
  62.     Msg("**** PAUSE");
  63.     bPaused = TRUE;
  64.     InvalidateRect(hWndMain, NULL, TRUE);
  65. }
  66.  
  67. /*
  68.  * UnPauseGame()
  69.  */
  70. void UnPauseGame()
  71. {
  72.     if (GetForegroundWindow() == hWndMain)
  73.     {
  74.         Msg("**** UNPAUSE");
  75.         bPaused = FALSE;
  76.     }
  77. }
  78.  
  79. /*
  80.  * RestoreGame()
  81.  */
  82. BOOL RestoreGame()
  83. {
  84.     if (lpFrontBuffer == NULL || IDirectDrawSurface_Restore(lpFrontBuffer) != DD_OK)
  85.     {
  86.         Msg("***** cant restore FrontBuffer");
  87.         return FALSE;
  88.     }
  89.  
  90.     if (!bFullscreen)
  91.     {
  92.         if (lpBackBuffer == NULL || IDirectDrawSurface_Restore(lpBackBuffer) != DD_OK)
  93.         {
  94.             Msg("***** cant restore BackBuffer");
  95.             return FALSE;
  96.         }
  97.     }
  98.  
  99.     if (lpStretchBuffer && IDirectDrawSurface_Restore(lpStretchBuffer) != DD_OK)
  100.     {
  101.         Msg("***** cant restore StretchBuffer");
  102.         return FALSE;
  103.     }
  104.  
  105.     if (lpFrameRate == NULL || lpInfo == NULL ||
  106.         IDirectDrawSurface_Restore(lpFrameRate) != DD_OK ||
  107.         IDirectDrawSurface_Restore(lpInfo) != DD_OK)
  108.     {
  109.         Msg("***** cant restore frame rate stuff");
  110.         return FALSE;
  111.     }
  112.     initNumSurface();
  113.  
  114.     if (!gfxRestoreAll())
  115.     {
  116.         Msg("***** cant restore art");
  117.         return FALSE;
  118.     }
  119.  
  120.     return TRUE;
  121. }
  122.  
  123. /*
  124.  * ProcessFox
  125.  */
  126. BOOL ProcessFox(SHORT sInput)
  127. {
  128.     if ((lpFrontBuffer && IDirectDrawSurface_IsLost(lpFrontBuffer) == DDERR_SURFACELOST) ||
  129.         (lpBackBuffer && IDirectDrawSurface_IsLost(lpBackBuffer) == DDERR_SURFACELOST))
  130.     {
  131.         if (!RestoreGame())
  132.         {
  133.             PauseGame();
  134.             return FALSE;
  135.         }
  136.     }
  137.  
  138.  
  139.     ProcessInput(sInput);
  140.     NewGameFrame();
  141.     return TRUE;
  142.  
  143. } /* ProcessFox */
  144.  
  145. static HFONT    hFont;
  146.  
  147. DWORD   dwFrameCount;
  148. DWORD    dwFrameTime;
  149. DWORD    dwFrames;
  150. DWORD   dwFramesLast;
  151. SIZE    sizeFPS;
  152. SIZE    sizeINFO;
  153. int    FrameRateX;
  154. char    szFPS[]   = "FPS %02d";
  155. char    szINFO[]  = "%dx%dx%d%s     F6=mode F8=x2 ALT+ENTER=Window";
  156. char    szINFOW[] = "%dx%dx%d%s     F6=mode F8=x2 ALT+ENTER=Fullscreen";
  157.  
  158. char    szFrameRate[128];
  159. char    szInfo[128];
  160.  
  161. COLORREF InfoColor      = RGB(0,152,245);
  162. COLORREF FrameRateColor = RGB(255,255,0);
  163. COLORREF BackColor    = RGB(255,255,255);
  164.  
  165. /*
  166.  * initNumSurface
  167.  */
  168. void initNumSurface( void )
  169. {
  170.     HDC        hdc;
  171.     RECT        rc;
  172.     int         len;
  173.  
  174.     dwFramesLast = 0;
  175.  
  176.     len = wsprintf(szFrameRate, szFPS, 0, 0);
  177.  
  178.     if( lpFrameRate && IDirectDrawSurface_GetDC(lpFrameRate, &hdc ) == DD_OK )
  179.     {
  180.         SelectObject(hdc, hFont);
  181.         SetTextColor(hdc, FrameRateColor);
  182.         SetBkColor(hdc, BackColor);
  183.         SetBkMode(hdc, OPAQUE);
  184.         SetRect(&rc, 0, 0, 10000, 10000);
  185.         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szFrameRate, len, NULL);
  186.         GetTextExtentPoint(hdc, szFrameRate, 4, &sizeFPS);
  187.         FrameRateX = sizeFPS.cx;
  188.         GetTextExtentPoint(hdc, szFrameRate, len, &sizeFPS);
  189.  
  190.         IDirectDrawSurface_ReleaseDC(lpFrameRate, hdc);
  191.     }
  192.  
  193.     if (bFullscreen)
  194.         len = wsprintf(szInfo, szINFO,
  195.                        GameSize.cx, GameSize.cy, GameBPP,bStretch ? " x2" : "");
  196.     else
  197.         len = wsprintf(szInfo, szINFOW,
  198.                        GameSize.cx, GameSize.cy, GameBPP,bStretch ? " x2" : "");
  199.  
  200.     if( lpInfo && IDirectDrawSurface_GetDC(lpInfo, &hdc ) == DD_OK )
  201.     {
  202.         SelectObject(hdc, hFont);
  203.         SetTextColor(hdc, InfoColor);
  204.         SetBkColor(hdc, BackColor);
  205.         SetBkMode(hdc, OPAQUE);
  206.         SetRect(&rc, 0, 0, 10000, 10000);
  207.         ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szInfo, len, NULL);
  208.         GetTextExtentPoint(hdc, szInfo, len, &sizeINFO);
  209.  
  210.         IDirectDrawSurface_ReleaseDC(lpInfo, hdc);
  211.     }
  212.  
  213. } /* initNumSurface */
  214.  
  215. /*
  216.  * makeFontStuff
  217.  */
  218. static BOOL makeFontStuff( void )
  219. {
  220.     DDCOLORKEY          ddck;
  221.     HDC                 hdc;
  222.  
  223.     if (hFont != NULL)
  224.     {
  225.         DeleteObject(hFont);
  226.     }
  227.  
  228.     hFont = CreateFont(
  229.         GameSize.cx <= 512 ? 12 : 24,
  230.         0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
  231.         ANSI_CHARSET,
  232.         OUT_DEFAULT_PRECIS,
  233.         CLIP_DEFAULT_PRECIS,
  234.         NONANTIALIASED_QUALITY, // DEFAULT_QUALITY,
  235.         VARIABLE_PITCH,
  236.         "Arial" );
  237.  
  238.     /*
  239.      * make a sample string so we can measure it with the current font.
  240.      */
  241.     if( hFont != NULL)
  242.     {
  243.         initNumSurface();
  244.  
  245.         hdc = GetDC(NULL);
  246.         SelectObject(hdc, hFont);
  247.         GetTextExtentPoint(hdc, szFrameRate, lstrlen(szFrameRate), &sizeFPS);
  248.         GetTextExtentPoint(hdc, szInfo, lstrlen(szInfo), &sizeINFO);
  249.         ReleaseDC(NULL, hdc);
  250.     }
  251.     /*
  252.      * Create a surface to copy our bits to.
  253.      */
  254.     lpFrameRate = DDCreateSurface(sizeFPS.cx, sizeFPS.cy, FALSE,TRUE);
  255.     lpInfo = DDCreateSurface(sizeINFO.cx, sizeINFO.cy, FALSE,TRUE);
  256.  
  257.     if( lpFrameRate == NULL || lpInfo == NULL )
  258.     {
  259.      return FALSE;
  260.     }
  261.  
  262.     /*
  263.      * now set the color key, we use a totaly different color than
  264.      * the rest of the app, just to be different so drivers dont always
  265.      * get white or black as the color key...
  266.      *
  267.      * dont forget when running on a dest colorkey device, we need
  268.      * to use the same color key as the rest of the app.
  269.      */
  270.     if( bTransDest )
  271.         BackColor = RGB(255,255,255);
  272.     else
  273.         BackColor = RGB(128,64,255);
  274.  
  275.     ddck.dwColorSpaceLowValue  = DDColorMatch(lpInfo, BackColor);
  276.     ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
  277.  
  278.     IDirectDrawSurface_SetColorKey( lpInfo, DDCKEY_SRCBLT, &ddck);
  279.     IDirectDrawSurface_SetColorKey( lpFrameRate, DDCKEY_SRCBLT, &ddck);
  280.  
  281.     /*
  282.      * now draw the text for real
  283.      */
  284.     initNumSurface();
  285.  
  286.     return TRUE;
  287. }
  288.  
  289. /*
  290.  * DisplayFrameRate
  291.  */
  292. void DisplayFrameRate( void )
  293. {
  294.     DWORD               time2;
  295.     char                buff[256];
  296.     HDC                 hdc;
  297.     HRESULT             ddrval;
  298.     RECT                rc;
  299.     DWORD               dw;
  300.  
  301.     if( !bShowFrameCount )
  302.     {
  303.         return;
  304.     }
  305.  
  306.     dwFrameCount++;
  307.     time2 = timeGetTime() - dwFrameTime;
  308.     if( time2 > 1000 )
  309.     {
  310.         dwFrames = (dwFrameCount*1000)/time2;
  311.         dwFrameTime = timeGetTime();
  312.         dwFrameCount = 0;
  313.  
  314.         AveFrameRate += dwFrames;
  315.         AveFrameRateCount++;
  316.     }
  317.  
  318.     if( dwFrames == 0 )
  319.     {
  320.         return;
  321.     }
  322.  
  323.     if( dwFrames != dwFramesLast )
  324.     {
  325.         dwFramesLast = dwFrames;
  326.  
  327.         if( IDirectDrawSurface_GetDC(lpFrameRate, &hdc ) == DD_OK )
  328.         {
  329.             buff[0] = (char)((dwFrames / 10) + '0');
  330.             buff[1] = (char)((dwFrames % 10) + '0');
  331.             if(hFont != NULL)
  332.             {
  333.                 SelectObject(hdc, hFont);
  334.                 SetTextColor(hdc, FrameRateColor);
  335.                 SetBkColor(hdc, BackColor);
  336.                 TextOut(hdc, FrameRateX, 0, buff, 2);
  337.             }
  338.             IDirectDrawSurface_ReleaseDC(lpFrameRate, hdc);
  339.         }
  340.     }
  341.  
  342.     /*
  343.      * put the text on the back buffer.
  344.      */
  345.     if (bTransDest)
  346.         dw = DDBLTFAST_DESTCOLORKEY | DDBLTFAST_WAIT;
  347.     else
  348.         dw = DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT;
  349.  
  350.     SetRect(&rc, 0, 0, sizeFPS.cx, sizeFPS.cy);
  351.     ddrval = IDirectDrawSurface_BltFast(lpBackBuffer,
  352.            GameRect.left + (GameSize.cx - sizeFPS.cx)/2, GameRect.top + 20,
  353.            lpFrameRate, &rc, dw);
  354.  
  355.     SetRect(&rc, 0, 0, sizeINFO.cx, sizeINFO.cy);
  356.     ddrval = IDirectDrawSurface_BltFast(lpBackBuffer,
  357.            GameRect.left + 10, GameRect.bottom - sizeINFO.cy - 10,
  358.            lpInfo, &rc, dw);
  359.  
  360. } /* DisplayFrameRate */
  361.  
  362. /*
  363.  * MainWndProc
  364.  *
  365.  * Callback for all Windows messages
  366.  */
  367. long FAR PASCAL MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
  368. {
  369.     PAINTSTRUCT ps;
  370.     HDC         hdc;
  371.  
  372.     switch( message )
  373.     {
  374.     case WM_SIZE:
  375.     case WM_MOVE:
  376.         if (IsIconic(hWnd))
  377.         {
  378.             Msg("FoxBear is minimized, pausing");
  379.             PauseGame();
  380.         }
  381.  
  382.         if (bFullscreen)
  383.         {
  384.             SetRect(&rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
  385.         }
  386.         else
  387.         {
  388.             GetClientRect(hWnd, &rcWindow);
  389.             ClientToScreen(hWnd, (LPPOINT)&rcWindow);
  390.             ClientToScreen(hWnd, (LPPOINT)&rcWindow+1);
  391.         }
  392.         Msg("WINDOW RECT: [%d,%d,%d,%d]", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
  393.         break;
  394.  
  395.     case WM_ACTIVATEAPP:
  396.         bIsActive = (BOOL)wParam && GetForegroundWindow() == hWnd;
  397.  
  398.         if (bIsActive)
  399.             Msg("FoxBear is active");
  400.         else
  401.             Msg("FoxBear is not active");
  402.  
  403.         //
  404.         // while we were not-active something bad happened that caused us
  405.         // to pause, like a surface restore failing or we got a palette
  406.         // changed, now that we are active try to fix things
  407.         //
  408.         if (bPaused && bIsActive)
  409.         {
  410.             if (RestoreGame())
  411.             {
  412.                 UnPauseGame();
  413.             }
  414.             else
  415.             {
  416.                if (GetForegroundWindow() == hWnd)
  417.                {
  418.                     //
  419.                     //  we are unable to restore, this can happen when
  420.                     //  the screen resolution or bitdepth has changed
  421.                     //  we just reload all the art again and re-create
  422.                     //  the front and back buffers.  this is a little
  423.                     //  overkill we could handle a screen res change by
  424.                     //  just recreating the front and back buffers we dont
  425.                     //  need to redo the art, but this is way easier.
  426.                     //
  427.                     if (InitGame())
  428.                     {
  429.                         UnPauseGame();
  430.                     }
  431.                 }
  432.             }
  433.         }
  434.         break;
  435.  
  436.     case WM_QUERYNEWPALETTE:
  437.         //
  438.         //  we are getting the palette focus, select our palette
  439.         //
  440.         if (!bFullscreen && lpPalette && lpFrontBuffer)
  441.         {
  442.             HRESULT ddrval;
  443.  
  444.             ddrval = IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
  445.             if( ddrval == DDERR_SURFACELOST )
  446.             {
  447.                 IDirectDrawSurface_Restore( lpFrontBuffer );
  448.  
  449.                 ddrval= IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
  450.                 if( ddrval == DDERR_SURFACELOST )
  451.                 {
  452.                    Msg("  Failed to restore palette after second try");
  453.                 }
  454.             }
  455.  
  456.             //
  457.             // Restore normal title if palette is ours
  458.             //
  459.  
  460.             if( ddrval == DD_OK )
  461.             {
  462.                 SetWindowText( hWnd, OUR_APP_NAME );
  463.             }
  464.         }
  465.         break;
  466.  
  467.     case WM_PALETTECHANGED:
  468.         //
  469.         //  if another app changed the palette we dont have full control
  470.         //  of the palette. NOTE this only applies for FoxBear in a window
  471.         //  when we are fullscreen we get all the palette all of the time.
  472.         //
  473.         if ((HWND)wParam != hWnd)
  474.         {
  475.             if( !bFullscreen )
  476.             {
  477.                 if( !bStress ) 
  478.                 {
  479.                     Msg("***** PALETTE CHANGED, PAUSING GAME");
  480.                     PauseGame();
  481.                 }
  482.                 else
  483.                 {
  484.                     Msg("Lost palette but continuing");
  485.                     SetWindowText( hWnd, OUR_APP_NAME 
  486.                                  " - palette changed COLORS PROBABLY WRONG" );
  487.                 }
  488.             }
  489.         }
  490.         break;
  491.  
  492.     case WM_DISPLAYCHANGE:
  493.         break;
  494.  
  495.     case WM_CREATE:
  496.         break;
  497.  
  498.     case WM_SETCURSOR:
  499.         if (bFullscreen && bIsActive)
  500.         {
  501.             SetCursor(NULL);
  502.             return TRUE;
  503.         }
  504.         break;
  505.  
  506.     case WM_SYSKEYUP:
  507.         switch( wParam )
  508.         {
  509.         // handle ALT+ENTER (fullscreen)
  510.         case VK_RETURN:
  511.             bFullscreen = !bFullscreen;
  512.             ExitGame();
  513.             DDDisable(TRUE);        // destroy DirectDraw object
  514.             GameMode.cx = 320;
  515.             GameMode.cy = 200;
  516.             InitGame();
  517.             break;
  518.         }
  519.         break;
  520.  
  521.     case WM_KEYDOWN:
  522.         switch( wParam )
  523.         {
  524.         case VK_NUMPAD5:
  525.             lastInput=KEY_STOP;
  526.             break;
  527.         case VK_DOWN:
  528.         case VK_NUMPAD2:
  529.             lastInput=KEY_DOWN;
  530.             break;
  531.         case VK_LEFT:
  532.         case VK_NUMPAD4:
  533.             lastInput=KEY_LEFT;
  534.             break;
  535.         case VK_RIGHT:
  536.         case VK_NUMPAD6:
  537.             lastInput=KEY_RIGHT;
  538.             break;
  539.         case VK_UP:
  540.         case VK_NUMPAD8:
  541.             lastInput=KEY_UP;
  542.             break;
  543.         case VK_HOME:
  544.         case VK_NUMPAD7:
  545.             lastInput=KEY_JUMP;
  546.             break;
  547.         case VK_NUMPAD3:
  548.             lastInput=KEY_THROW;
  549.             break;
  550.         case VK_F5:
  551.             bShowFrameCount = !bShowFrameCount;
  552.             if( bShowFrameCount )
  553.             {
  554.               dwFrameCount = 0;
  555.               dwFrameTime = timeGetTime();
  556.             }
  557.         break;
  558.  
  559.         case VK_F6:
  560.             {
  561.             static i;
  562.             //
  563.             // find our current mode in the mode list
  564.             //
  565.             if(bFullscreen)
  566.             {
  567.                 for (i=0; i<NumModes; i++)
  568.                 {
  569.                     if (ModeList[i].bpp == (int)GameBPP &&
  570.                         ModeList[i].w   == GameSize.cx &&
  571.                         ModeList[i].h   == GameSize.cy)
  572.                     {
  573.                         break;
  574.                     }
  575.                 }
  576.             }else
  577.             {
  578.                 for (i=0; i<NumModes; i++)
  579.                 {
  580.                     if (ModeList[i].w   == GameSize.cx &&
  581.                         ModeList[i].h   == GameSize.cy)
  582.                     {
  583.                         break;
  584.                     }
  585.                 }
  586.             }
  587.             //
  588.             // now step to the next mode, wrapping to the first one.
  589.             //
  590.             if (++i >= NumModes)
  591.             {
  592.                 i = 0;
  593.             }
  594.             Msg("ModeList %d %d",i,NumModes);
  595.             GameMode.cx = ModeList[i].w;
  596.             GameMode.cy = ModeList[i].h;
  597.             GameBPP     = ModeList[i].bpp;
  598.             bStretch    = FALSE;
  599.             InitGame();
  600.             }
  601.             break;
  602.         case VK_F7:
  603.             GameBPP = GameBPP == 8 ? 16 : 8;
  604.             InitGame();
  605.             break;
  606.  
  607.         case VK_F8:
  608.             if (bFullscreen)
  609.             {
  610.                 bStretch = !bStretch;
  611.                 InitGame();
  612.             }
  613.             else
  614.             {
  615.                 RECT rc;
  616.  
  617.                 GetClientRect(hWnd, &rc);
  618.  
  619.                 bStretch = (rc.right  != GameSize.cx) ||
  620.                            (rc.bottom != GameSize.cy);
  621.  
  622.                 if (bStretch = !bStretch)
  623.                     SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
  624.                 else
  625.                     SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);
  626.  
  627.                 AdjustWindowRectEx(&rc,
  628.                     GetWindowStyle(hWnd),
  629.                     GetMenu(hWnd) != NULL,
  630.                     GetWindowExStyle(hWnd));
  631.  
  632.                 SetWindowPos(hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
  633.                     SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
  634.             }
  635.             break;
  636.         case VK_F9:
  637.             DevIndex ++;
  638.             bUseEmulation = FALSE;
  639.             if (DevIndex >= MaxDevIndex)
  640.                 DevIndex = 0;
  641.  
  642.             ExitGame();
  643.             DDDisable(TRUE);        // destroy DirectDraw object
  644.             InitGame();
  645.             break;
  646.         case VK_F4:
  647.             // treat F4 like ALT+ENTER (fullscreen)
  648.             PostMessage(hWnd, WM_SYSKEYUP, VK_RETURN, 0);
  649.             break;
  650.  
  651.         case VK_F3:
  652.             bPaused = !bPaused;
  653.             break;
  654.  
  655.         case VK_ESCAPE:
  656.         case VK_F12:
  657.             PostMessage(hWnd, WM_CLOSE, 0, 0);
  658.             return 0;
  659.         }
  660.         break;
  661.  
  662.     case WM_PAINT:
  663.         hdc = BeginPaint( hWnd, &ps );
  664.         if (bPaused)
  665.         {
  666.             char *sz = "Game is paused, this is not a bug.";
  667.             TextOut(ps.hdc, 0, 0, sz, lstrlen(sz));
  668.         }
  669.         EndPaint( hWnd, &ps );
  670.         return 1;
  671.  
  672.     case WM_DESTROY:
  673.         hWndMain = NULL;
  674.         lastInput=0;
  675.         DestroyGame();          // end of game
  676.         DDDisable(TRUE);        // destroy DirectDraw object
  677.         PostQuitMessage( 0 );
  678.         break;
  679.     }
  680.  
  681.     return DefWindowProc(hWnd, message, wParam, lParam);
  682.  
  683. } /* MainWndProc */
  684.  
  685. /*
  686.  * initApplication
  687.  *
  688.  * Do that Windows initialization stuff...
  689.  */
  690. static BOOL initApplication( HINSTANCE hInstance, int nCmdShow )
  691. {
  692.     WNDCLASS wc;
  693.     BOOL     rc;
  694.  
  695.     wc.style = CS_DBLCLKS;
  696.     wc.lpfnWndProc = MainWndProc;
  697.     wc.cbClsExtra = 0;
  698.     wc.cbWndExtra = 0;
  699.     wc.hInstance = hInstance;
  700.     wc.hIcon = LoadIcon( hInstance, MAKEINTATOM(FOX_ICON));
  701.     wc.hCursor = LoadCursor( NULL, IDC_ARROW );
  702.     wc.hbrBackground = GetStockObject(BLACK_BRUSH);
  703.     wc.lpszMenuName =  NULL;
  704.     wc.lpszClassName = "WinFoxClass";
  705.     rc = RegisterClass( &wc );
  706.     if( !rc )
  707.     {
  708.         return FALSE;
  709.     }
  710.     
  711.  
  712.     hWndMain = CreateWindowEx(
  713.         WS_EX_APPWINDOW,
  714.         "WinFoxClass",
  715.         OUR_APP_NAME,
  716.         WS_VISIBLE |    // so we dont have to call ShowWindow
  717.         WS_SYSMENU |    // so we get a icon in in our tray button
  718.         WS_POPUP,
  719.         0,
  720.         0,
  721.         GetSystemMetrics(SM_CXSCREEN),
  722.         GetSystemMetrics(SM_CYSCREEN),
  723.         NULL,
  724.         NULL,
  725.         hInstance,
  726.         NULL );
  727.  
  728.     if( !hWndMain )
  729.     {
  730.         return FALSE;
  731.     }
  732.  
  733.     UpdateWindow( hWndMain );
  734.     SetFocus( hWndMain );
  735.  
  736.     return TRUE;
  737.  
  738. } /* initApplication */
  739.  
  740. /*
  741.  * ExitGame
  742.  *
  743.  * Exiting current game, clean up
  744.  */
  745. void ExitGame( void )
  746. {
  747.     if( lpFrameRate )
  748.     {
  749.         IDirectDrawSurface_Release(lpFrameRate);
  750.         lpFrameRate = NULL;
  751.     }
  752.  
  753.     if( lpInfo )
  754.     {
  755.         IDirectDrawSurface_Release(lpInfo);
  756.         lpInfo = NULL;
  757.     }
  758.  
  759.     if( lpPalette )
  760.     {
  761.         IDirectDrawSurface_Release(lpPalette);
  762.         lpPalette = NULL;
  763.     }
  764.  
  765.     DestroyGame();
  766.  
  767. } /* ExitGame */
  768.  
  769. /*
  770.  * InitGame
  771.  *
  772.  * Initializing current game
  773.  */
  774. BOOL InitGame( void )
  775. {
  776.     ExitGame();
  777.  
  778.     GameSize = GameMode;
  779.  
  780.     /*
  781.      * initialize sound
  782.      */
  783.     InitSound( hWndMain );
  784.  
  785.     /*
  786.      * init DirectDraw, set mode, ...
  787.      * NOTE GameMode might be set to 640x480 if we cant get the asked for mode.
  788.      */
  789.     if( !PreInitializeGame() )
  790.     {
  791.         return FALSE;
  792.     }
  793.  
  794.     if (bStretch && bFullscreen)
  795.     {
  796.         GameSize.cx     = GameMode.cx / 2;
  797.         GameSize.cy     = GameMode.cy / 2;
  798.         GameRect.left   = GameMode.cx - GameSize.cx;
  799.         GameRect.top    = GameMode.cy - GameSize.cy;
  800.         GameRect.right  = GameMode.cx;
  801.         GameRect.bottom = GameMode.cy;
  802.  
  803.         if (lpStretchBuffer)
  804.             Msg("Stretching using a system-memory stretch buffer");
  805.         else
  806.             Msg("Stretching using a VRAM->VRAM blt");
  807.     }
  808.     else
  809.     {
  810.         GameRect.left   = (GameMode.cx - GameSize.cx) / 2;
  811.         GameRect.top    = (GameMode.cy - GameSize.cy) / 2;
  812.         GameRect.right  = GameRect.left + GameSize.cx;
  813.         GameRect.bottom = GameRect.top + GameSize.cy;
  814.     }
  815.  
  816.     /*
  817.      * setup our palette
  818.      */
  819.     if( GameBPP == 8 )
  820.     {
  821.         lpPalette = ReadPalFile( NULL );        // create a 332 palette
  822.  
  823.         if( lpPalette == NULL )
  824.         {
  825.             Msg( "Palette create failed" );
  826.             return FALSE;
  827.         }
  828.  
  829.         IDirectDrawSurface_SetPalette( lpFrontBuffer, lpPalette );
  830.     }
  831.  
  832.     /*
  833.      *  load all the art and things.
  834.      */
  835.     if( !InitializeGame() )
  836.     {
  837.         return FALSE;
  838.     }
  839.  
  840.     /*
  841.      * init our code to draw the FPS
  842.      */
  843.     makeFontStuff();
  844.  
  845.     /*
  846.      * spew some stats
  847.      */
  848.     {
  849.         DDCAPS    ddcaps;
  850.         ddcaps.dwSize = sizeof( ddcaps );
  851.         IDirectDraw_GetCaps( lpDD, &ddcaps, NULL );
  852.         Msg( "Total=%ld, Free VRAM=%ld", ddcaps.dwVidMemTotal, ddcaps.dwVidMemFree );
  853.         Msg( "Used = %ld", ddcaps.dwVidMemTotal- ddcaps.dwVidMemFree );
  854.     }
  855.  
  856.     return TRUE;
  857.  
  858. } /* InitGame */
  859.  
  860. #define IS_NUM(c)     ((c) >= '0' && (c) <= '9')
  861. #define IS_SPACE(c)   ((c) == ' ' || (c) == '\r' || (c) == '\n' || (c) == '\t' || (c) == 'x')
  862.  
  863. int getint(char**p, int def)
  864. {
  865.     int i=0;
  866.  
  867.     while (IS_SPACE(**p))
  868.         (*p)++;
  869.  
  870.     if (!IS_NUM(**p))
  871.         return def;
  872.  
  873.     while (IS_NUM(**p))
  874.         i = i*10 + *(*p)++ - '0';
  875.  
  876.     while (IS_SPACE(**p))
  877.         (*p)++;
  878.  
  879.     return i;
  880. }
  881.  
  882. /*
  883.  * WinMain
  884.  */
  885. int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
  886.                     int nCmdShow )
  887. {
  888.     MSG            msg;
  889.  
  890.     DDInit();
  891.     while( lpCmdLine[0] == '-' || lpCmdLine[0] == '/')
  892.     {
  893.         lpCmdLine++;
  894.  
  895.         switch (*lpCmdLine++)
  896.         {
  897.         case 'e':
  898.             bUseEmulation = TRUE;
  899.             break;
  900.         case 'w':
  901.             bFullscreen = FALSE;
  902.             break;
  903.         case 'f':
  904.             bFullscreen = TRUE;
  905.             break;
  906.         case '1':
  907.             CmdLineBufferCount = 1;
  908.             break;
  909.         case '2':
  910.         case 'd':
  911.             CmdLineBufferCount = 2;
  912.             break;
  913.         case '3':
  914.             CmdLineBufferCount = 3;
  915.             break;
  916.         case 's':
  917.             bStretch = TRUE;
  918.             break;
  919.         case 'S':
  920.             bWantSound = FALSE;
  921.             break;
  922.         case 'x':
  923.             bStress= TRUE;
  924.             break;
  925.         case '?':
  926.             bHelp= TRUE;
  927.             bFullscreen= FALSE;  // give help in windowed mode
  928.             break;
  929.         }
  930.  
  931.         while( IS_SPACE(*lpCmdLine) )
  932.         {
  933.             lpCmdLine++;
  934.         }
  935.     }
  936.  
  937.     GameMode.cx = getint(&lpCmdLine, 640);
  938.     GameMode.cy = getint(&lpCmdLine, 480);
  939.     GameBPP = getint(&lpCmdLine, 8);
  940.  
  941.     /*
  942.      * create window and other windows things
  943.      */
  944.     if( !initApplication(hInstance, nCmdShow) )
  945.     {
  946.         return FALSE;
  947.     }
  948.  
  949.     /*
  950.      * Give user help if asked for
  951.      *
  952.      * This is ugly for now because the whole screen is black
  953.      * except for the popup box.  This could be fixed with some
  954.      * work to get the window size right when it was created instead
  955.      * of delaying that work. see ddraw.c
  956.      *
  957.      */
  958.  
  959.     if( bHelp )
  960.     {
  961.         MessageBox(hWndMain,
  962.                    "F12 - Quit\n"
  963.                    "NUMPAD 2  - crouch\n"
  964.                    "NUMPAD 3  - apple\n"
  965.                    "NUMPAD 4  - right\n"
  966.                    "NUMPAD 5  - stop\n"
  967.                    "NUMPAD 6  - left\n"
  968.                    "NUMPAD 7  - jump\n"
  969.                    "\n"
  970.                    "Command line parameters\n"
  971.                    "\n"
  972.                     "-e   Use emulator\n"
  973.                     "-S   No Sound\n"
  974.                     "-1   No backbuffer\n"
  975.                     "-2   One backbuffer\n"
  976.                     "-4   Three backbuffers\n"
  977.                     "-s   Use stretch\n"
  978.                     "-x   Demo or stress mode\n",
  979.                    OUR_APP_NAME, MB_OK );
  980.     }
  981.  
  982.     /*
  983.      * initialize for game play
  984.      */
  985.  
  986.     if( !InitGame() )
  987.     {
  988.         return FALSE;
  989.     }
  990.     dwFrameTime = timeGetTime();
  991.    
  992.     while( 1 )
  993.     {
  994.         if (PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
  995.         {
  996.             if (!GetMessage( &msg, NULL, 0, 0))
  997.             { 
  998.                 break;
  999.             }
  1000.             TranslateMessage(&msg); 
  1001.             DispatchMessage(&msg);
  1002.         }
  1003.         else if (!bPaused && (bIsActive || !bFullscreen))
  1004.         {
  1005.             ProcessFox(lastInput);
  1006.             lastInput=0;
  1007.         }
  1008.         else
  1009.         {
  1010.             WaitMessage();
  1011.         }
  1012.     }
  1013.  
  1014.     if (AveFrameRateCount)
  1015.     {
  1016.         AveFrameRate = AveFrameRate / AveFrameRateCount;
  1017.         Msg("Average frame rate: %d", AveFrameRate);
  1018.     }
  1019.  
  1020.     return msg.wParam;
  1021.  
  1022. } /* WinMain */
  1023.  
  1024. #ifdef DEBUG
  1025.  
  1026. /*
  1027.  * Msg
  1028.  */
  1029. void __cdecl Msg( LPSTR fmt, ... )
  1030. {
  1031.     char    buff[256];
  1032.     va_list  va;
  1033.  
  1034.     va_start(va, fmt);
  1035.  
  1036.     //
  1037.     // format message with header
  1038.     //
  1039.  
  1040.     lstrcpy( buff, "FOXBEAR:" );
  1041.     wvsprintf( &buff[lstrlen(buff)], fmt, va );
  1042.     lstrcat( buff, "\r\n" );
  1043.  
  1044.     //
  1045.     // To the debugger unless we need to be quiet
  1046.     //
  1047.  
  1048.     if( !bStress )
  1049.     {
  1050.         OutputDebugString( buff );
  1051.     }
  1052.  
  1053. } /* Msg */
  1054.  
  1055. #endif
  1056.