/*==========================================================================
 *
 *  Copyright (C) 1995-1996 Microsoft Corporation. All Rights Reserved.
 *  Copyright (C) 1994-1995 ATI Technologies Inc. All Rights Reserved.
 *
 *  File:       winfox.c
 *  Content:    Windows fox sample game
 *
 ***************************************************************************/
#include "foxbear.h"
#include "rcids.h"      // for FOX_ICON

LPDIRECTDRAWSURFACE     lpFrontBuffer;
LPDIRECTDRAWSURFACE     lpBackBuffer;
LPDIRECTDRAWCLIPPER     lpClipper;
LPDIRECTDRAWSURFACE     lpStretchBuffer;
LPDIRECTDRAWSURFACE     lpFrameRate;
LPDIRECTDRAWSURFACE     lpInfo;
LPDIRECTDRAWPALETTE     lpPalette;
LPDIRECTDRAW            lpDD;
SHORT                   lastInput = 0;
HWND                    hWndMain;
RECT                    rcWindow;
BOOL                    bShowFrameCount=TRUE;
BOOL                    bIsActive;
BOOL                    bPaused;

BOOL                    bStretch;
BOOL                    bFullscreen=TRUE;
BOOL                    bStress=FALSE;     // just keep running if true
BOOL                    bHelp=FALSE;       // help requested
RECT                    GameRect;          // game rect
SIZE                    GameSize;          // game is this size
SIZE                    GameMode;          // display mode size
UINT                    GameBPP;           // the bpp we want
DWORD                   dwColorKey;        // our color key
DWORD                   AveFrameRate;
DWORD                   AveFrameRateCount;
BOOL                    bWantSound = TRUE;


#define OUR_APP_NAME  "Win Fox Application"

#define ODS OutputDebugString

BOOL InitGame(void);
void ExitGame(void);
void initNumSurface(void);
#ifndef DEBUG
void __cdecl Msg( LPSTR fmt, ... ) {};
#endif


/*
 * PauseGame()
 */
void PauseGame()
{
    Msg("**** PAUSE");
    bPaused = TRUE;
    InvalidateRect(hWndMain, NULL, TRUE);
}

/*
 * UnPauseGame()
 */
void UnPauseGame()
{
    if (GetForegroundWindow() == hWndMain)
    {
        Msg("**** UNPAUSE");
        bPaused = FALSE;
    }
}

/*
 * RestoreGame()
 */
BOOL RestoreGame()
{
    if (lpFrontBuffer == NULL || IDirectDrawSurface_Restore(lpFrontBuffer) != DD_OK)
    {
        Msg("***** cant restore FrontBuffer");
        return FALSE;
    }

    if (!bFullscreen)
    {
        if (lpBackBuffer == NULL || IDirectDrawSurface_Restore(lpBackBuffer) != DD_OK)
        {
            Msg("***** cant restore BackBuffer");
            return FALSE;
        }
    }

    if (lpStretchBuffer && IDirectDrawSurface_Restore(lpStretchBuffer) != DD_OK)
    {
        Msg("***** cant restore StretchBuffer");
        return FALSE;
    }

    if (lpFrameRate == NULL || lpInfo == NULL ||
        IDirectDrawSurface_Restore(lpFrameRate) != DD_OK ||
        IDirectDrawSurface_Restore(lpInfo) != DD_OK)
    {
        Msg("***** cant restore frame rate stuff");
        return FALSE;
    }
    initNumSurface();

    if (!gfxRestoreAll())
    {
        Msg("***** cant restore art");
        return FALSE;
    }

    return TRUE;
}

/*
 * ProcessFox
 */
BOOL ProcessFox(SHORT sInput)
{
    if ((lpFrontBuffer && IDirectDrawSurface_IsLost(lpFrontBuffer) == DDERR_SURFACELOST) ||
        (lpBackBuffer && IDirectDrawSurface_IsLost(lpBackBuffer) == DDERR_SURFACELOST))
    {
        if (!RestoreGame())
        {
            PauseGame();
            return FALSE;
        }
    }


    ProcessInput(sInput);
    NewGameFrame();
    return TRUE;

} /* ProcessFox */

static HFONT    hFont;

DWORD   dwFrameCount;
DWORD   dwFrameTime;
DWORD   dwFrames;
DWORD   dwFramesLast;
SIZE    sizeFPS;
SIZE    sizeINFO;
int     FrameRateX;
char    szFPS[]   = "FPS %02d";
char    szINFO[]  = "%dx%dx%d%s     F6=mode F8=x2 ALT+ENTER=Window";
char    szINFOW[] = "%dx%dx%d%s     F6=mode F8=x2 ALT+ENTER=Fullscreen";

char    szFrameRate[128];
char    szInfo[128];

COLORREF InfoColor      = RGB(0,152,245);
COLORREF FrameRateColor = RGB(255,255,0);
COLORREF BackColor      = RGB(255,255,255);

/*
 * initNumSurface
 */
void initNumSurface( void )
{
    HDC        hdc;
    RECT        rc;
    int         len;

    dwFramesLast = 0;

    len = wsprintf(szFrameRate, szFPS, 0, 0);

    if( lpFrameRate && IDirectDrawSurface_GetDC(lpFrameRate, &hdc ) == DD_OK )
    {
        SelectObject(hdc, hFont);
        SetTextColor(hdc, FrameRateColor);
        SetBkColor(hdc, BackColor);
        SetBkMode(hdc, OPAQUE);
        SetRect(&rc, 0, 0, 10000, 10000);
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szFrameRate, len, NULL);
        GetTextExtentPoint(hdc, szFrameRate, 4, &sizeFPS);
        FrameRateX = sizeFPS.cx;
        GetTextExtentPoint(hdc, szFrameRate, len, &sizeFPS);

        IDirectDrawSurface_ReleaseDC(lpFrameRate, hdc);
    }

    if (bFullscreen)
        len = wsprintf(szInfo, szINFO,
                       GameSize.cx, GameSize.cy, GameBPP,bStretch ? " x2" : "");
    else
        len = wsprintf(szInfo, szINFOW,
                       GameSize.cx, GameSize.cy, GameBPP,bStretch ? " x2" : "");

    if( lpInfo && IDirectDrawSurface_GetDC(lpInfo, &hdc ) == DD_OK )
    {
        SelectObject(hdc, hFont);
        SetTextColor(hdc, InfoColor);
        SetBkColor(hdc, BackColor);
        SetBkMode(hdc, OPAQUE);
        SetRect(&rc, 0, 0, 10000, 10000);
        ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, szInfo, len, NULL);
        GetTextExtentPoint(hdc, szInfo, len, &sizeINFO);

        IDirectDrawSurface_ReleaseDC(lpInfo, hdc);
    }

} /* initNumSurface */

/*
 * makeFontStuff
 */
static BOOL makeFontStuff( void )
{
    DDCOLORKEY          ddck;
    HDC                 hdc;

    if (hFont != NULL)
    {
        DeleteObject(hFont);
    }

    hFont = CreateFont(
        GameSize.cx <= 320 ? 12 : 24,
        0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
        ANSI_CHARSET,
        OUT_DEFAULT_PRECIS,
        CLIP_DEFAULT_PRECIS,
        NONANTIALIASED_QUALITY, // DEFAULT_QUALITY,
        VARIABLE_PITCH,
        "Arial" );

    /*
     * make a sample string so we can measure it with the current font.
     */
    initNumSurface();

    hdc = GetDC(NULL);
    SelectObject(hdc, hFont);
    GetTextExtentPoint(hdc, szFrameRate, lstrlen(szFrameRate), &sizeFPS);
    GetTextExtentPoint(hdc, szInfo, lstrlen(szInfo), &sizeINFO);
    ReleaseDC(NULL, hdc);

    /*
     * Create a surface to copy our bits to.
     */
    lpFrameRate = DDCreateSurface(sizeFPS.cx, sizeFPS.cy, FALSE,TRUE);
    lpInfo = DDCreateSurface(sizeINFO.cx, sizeINFO.cy, FALSE,TRUE);

    if( lpFrameRate == NULL || lpInfo == NULL )
    {
        return FALSE;
    }

    /*
     * now set the color key, we use a totaly different color than
     * the rest of the app, just to be different so drivers dont always
     * get white or black as the color key...
     *
     * dont forget when running on a dest colorkey device, we need
     * to use the same color key as the rest of the app.
     */
    if( bTransDest )
        BackColor = RGB(255,255,255);
    else
        BackColor = RGB(128,64,255);

    ddck.dwColorSpaceLowValue  = DDColorMatch(lpInfo, BackColor);
    ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;

    IDirectDrawSurface_SetColorKey( lpInfo, DDCKEY_SRCBLT, &ddck);
    IDirectDrawSurface_SetColorKey( lpFrameRate, DDCKEY_SRCBLT, &ddck);

    /*
     * now draw the text for real
     */
    initNumSurface();

    return TRUE;
}

/*
 * DisplayFrameRate
 */
void DisplayFrameRate( void )
{
    DWORD               time2;
    char                buff[256];
    HDC                 hdc;
    HRESULT             ddrval;
    RECT                rc;
    DWORD               dw;

    if( !bShowFrameCount )
    {
        return;
    }

    dwFrameCount++;
    time2 = timeGetTime() - dwFrameTime;
    if( time2 > 1000 )
    {
        dwFrames = (dwFrameCount*1000)/time2;
        dwFrameTime = timeGetTime();
        dwFrameCount = 0;

        AveFrameRate += dwFrames;
        AveFrameRateCount++;
    }

    if( dwFrames == 0 )
    {
        return;
    }

    if( dwFrames != dwFramesLast )
    {
        dwFramesLast = dwFrames;

        if( IDirectDrawSurface_GetDC(lpFrameRate, &hdc ) == DD_OK )
        {
            buff[0] = (char)((dwFrames / 10) + '0');
            buff[1] = (char)((dwFrames % 10) + '0');

            SelectObject(hdc, hFont);
            SetTextColor(hdc, FrameRateColor);
            SetBkColor(hdc, BackColor);
            TextOut(hdc, FrameRateX, 0, buff, 2);

            IDirectDrawSurface_ReleaseDC(lpFrameRate, hdc);
        }
    }

    /*
     * put the text on the back buffer.
     */
    if (bTransDest)
        dw = DDBLTFAST_DESTCOLORKEY | DDBLTFAST_WAIT;
    else
        dw = DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT;

    SetRect(&rc, 0, 0, sizeFPS.cx, sizeFPS.cy);
    ddrval = IDirectDrawSurface_BltFast(lpBackBuffer,
           GameRect.left + (GameSize.cx - sizeFPS.cx)/2, GameRect.top + 20,
           lpFrameRate, &rc, dw);

    SetRect(&rc, 0, 0, sizeINFO.cx, sizeINFO.cy);
    ddrval = IDirectDrawSurface_BltFast(lpBackBuffer,
           GameRect.left + 10, GameRect.bottom - sizeINFO.cy - 10,
           lpInfo, &rc, dw);

} /* DisplayFrameRate */

/*
 * MainWndProc
 *
 * Callback for all Windows messages
 */
long FAR PASCAL MainWndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
    PAINTSTRUCT ps;
    HDC         hdc;
    int         i;

    switch( message )
    {
    case WM_SIZE:
    case WM_MOVE:
        if (IsIconic(hWnd))
        {
            Msg("FoxBear is minimized, pausing");
            PauseGame();
        }

        if (bFullscreen)
        {
            SetRect(&rcWindow, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN));
        }
        else
        {
            GetClientRect(hWnd, &rcWindow);
            ClientToScreen(hWnd, (LPPOINT)&rcWindow);
            ClientToScreen(hWnd, (LPPOINT)&rcWindow+1);
        }
        Msg("WINDOW RECT: [%d,%d,%d,%d]", rcWindow.left, rcWindow.top, rcWindow.right, rcWindow.bottom);
        break;

    case WM_ACTIVATEAPP:
        bIsActive = (BOOL)wParam && GetForegroundWindow() == hWnd && !IsIconic(hWnd);

        if (bIsActive)
            Msg("FoxBear is active");
        else
            Msg("FoxBear is not active");

        //
        // while we were not-active something bad happened that caused us
        // to pause, like a surface restore failing or we got a palette
        // changed, now that we are active try to fix things
        //
        if (bPaused && bIsActive)
        {
            if (RestoreGame())
            {
                UnPauseGame();
            }
            else
            {
               if (GetForegroundWindow() == hWnd)
               {
                    //
                    //  we are unable to restore, this can happen when
                    //  the screen resolution or bitdepth has changed
                    //  we just reload all the art again and re-create
                    //  the front and back buffers.  this is a little
                    //  overkill we could handle a screen res change by
                    //  just recreating the front and back buffers we dont
                    //  need to redo the art, but this is way easier.
                    //
                    if (InitGame())
                    {
                        UnPauseGame();
                    }
                }
            }
        }
        break;

    case WM_QUERYNEWPALETTE:
        //
        //  we are getting the palette focus, select our palette
        //
        if (!bFullscreen && lpPalette && lpFrontBuffer)
        {
            HRESULT ddrval;

            ddrval = IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
            if( ddrval == DDERR_SURFACELOST )
            {
                IDirectDrawSurface_Restore( lpFrontBuffer );

                ddrval= IDirectDrawSurface_SetPalette(lpFrontBuffer,lpPalette);
                if( ddrval == DDERR_SURFACELOST )
                {
                   Msg("  Failed to restore palette after second try");
                }
            }

            //
            // Restore normal title if palette is ours
            //

            if( ddrval == DD_OK )
            {
                SetWindowText( hWnd, OUR_APP_NAME );
            }
        }
        break;

    case WM_PALETTECHANGED:
        //
        //  if another app changed the palette we dont have full control
        //  of the palette. NOTE this only applies for FoxBear in a window
        //  when we are fullscreen we get all the palette all of the time.
        //
        if ((HWND)wParam != hWnd)
        {
            if( !bFullscreen )
            {
                if( !bStress ) 
                {
                    Msg("***** PALETTE CHANGED, PAUSING GAME");
                    PauseGame();
                }
                else
                {
                    Msg("Lost palette but continuing");
                    SetWindowText( hWnd, OUR_APP_NAME 
                                 " - palette changed COLORS PROBABLY WRONG" );
                }
            }
        }
        break;

    case WM_DISPLAYCHANGE:
        break;

    case WM_CREATE:
        break;

    case WM_SETCURSOR:
        if (bFullscreen && bIsActive)
        {
            SetCursor(NULL);
            return TRUE;
        }
        break;

    case WM_SYSKEYUP:
        switch( wParam )
        {
        // handle ALT+ENTER (fullscreen)
        case VK_RETURN:
            bFullscreen = !bFullscreen;
            ExitGame();
            DDDisable(TRUE);        // destroy DirectDraw object
            InitGame();
            break;
        }
        break;
 
    case WM_KEYDOWN:
        switch( wParam )
        {
        case VK_NUMPAD5:
            lastInput=KEY_STOP;
            break;
        case VK_DOWN:
        case VK_NUMPAD2:
            lastInput=KEY_DOWN;
            break;
        case VK_LEFT:
        case VK_NUMPAD4:
            lastInput=KEY_LEFT;
            break;
        case VK_RIGHT:
        case VK_NUMPAD6:
            lastInput=KEY_RIGHT;
            break;
        case VK_UP:
        case VK_NUMPAD8:
            lastInput=KEY_UP;
            break;
        case VK_HOME:
        case VK_NUMPAD7:
            lastInput=KEY_JUMP;
            break;
        case VK_NUMPAD3:
            lastInput=KEY_THROW;
            break;
        case VK_F5:
            bShowFrameCount = !bShowFrameCount;
            if( bShowFrameCount )
            {
                dwFrameCount = 0;
                dwFrameTime = timeGetTime();
            }
            break;

        case VK_F6:
            //
            // find our current mode in the mode list
            //
                        if(bFullscreen)
                        {
                    for (i=0; i<NumModes; i++)
                    {
                        if (ModeList[i].bpp == (int)GameBPP &&
                            ModeList[i].w   == GameSize.cx &&
                            ModeList[i].h   == GameSize.cy)
                        {
                            break;
                        }
                    }
                    }else
                        {
                    for (i=0; i<NumModes; i++)
                    {
                        if (ModeList[i].w   == GameSize.cx &&
                            ModeList[i].h   == GameSize.cy)
                        {
                            break;
                        }
                    }
            }
            //
                // now step to the next mode, wrapping to the first one.
            //
                if (++i >= NumModes)
                i = 0;
Msg("ModeList %d %d",i,NumModes);
            GameMode.cx = ModeList[i].w;
            GameMode.cy = ModeList[i].h;
            GameBPP     = ModeList[i].bpp;
            bStretch    = FALSE;
            InitGame();
            break;

        case VK_F7:
            GameBPP = GameBPP == 8 ? 16 : 8;
            InitGame();
            break;

        case VK_F8:
            if (bFullscreen)
            {
                bStretch = !bStretch;
                InitGame();
            }
            else
            {
                RECT rc;

                GetClientRect(hWnd, &rc);

                bStretch = (rc.right  != GameSize.cx) ||
                           (rc.bottom != GameSize.cy);

                if (bStretch = !bStretch)
                    SetRect(&rc, 0, 0, GameMode.cx*2, GameMode.cy*2);
                else
                    SetRect(&rc, 0, 0, GameMode.cx, GameMode.cy);

                AdjustWindowRectEx(&rc,
                    GetWindowStyle(hWnd),
                    GetMenu(hWnd) != NULL,
                    GetWindowExStyle(hWnd));

                SetWindowPos(hWnd, NULL, 0, 0, rc.right-rc.left, rc.bottom-rc.top,
                    SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
            }
            break;

        case VK_F4:
            // treat F4 like ALT+ENTER (fullscreen)
            PostMessage(hWnd, WM_SYSKEYUP, VK_RETURN, 0);
            break;

        case VK_F3:
            bPaused = !bPaused;
            break;

        case VK_ESCAPE:
        case VK_F12:
            PostMessage(hWnd, WM_CLOSE, 0, 0);
            return 0;
        }
        break;

    case WM_PAINT:
        hdc = BeginPaint( hWnd, &ps );
        if (bPaused)
        {
            char *sz = "Game is paused, this is not a bug.";
            TextOut(ps.hdc, 0, 0, sz, lstrlen(sz));
        }
        EndPaint( hWnd, &ps );
        return 1;

    case WM_DESTROY:
        hWndMain = NULL;
        lastInput=0;
        DestroyGame();          // end of game
        DDDisable(TRUE);        // destroy DirectDraw object
        PostQuitMessage( 0 );
        break;
    }

    return DefWindowProc(hWnd, message, wParam, lParam);

} /* MainWndProc */

/*
 * initApplication
 *
 * Do that Windows initialization stuff...
 */
static BOOL initApplication( HINSTANCE hInstance, int nCmdShow )
{
    WNDCLASS wc;
    BOOL     rc;

    wc.style = CS_DBLCLKS;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon( hInstance, MAKEINTATOM(FOX_ICON));
    wc.hCursor = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName =  NULL;
    wc.lpszClassName = "WinFoxClass";
    rc = RegisterClass( &wc );
    if( !rc )
    {
        return FALSE;
    }
    

    hWndMain = CreateWindowEx(
        WS_EX_APPWINDOW,
        "WinFoxClass",
        OUR_APP_NAME,
        WS_VISIBLE |    // so we dont have to call ShowWindow
        WS_SYSMENU |    // so we get a icon in in our tray button
        WS_POPUP,
        0,
        0,
        GetSystemMetrics(SM_CXSCREEN),
        GetSystemMetrics(SM_CYSCREEN),
        NULL,
        NULL,
        hInstance,
        NULL );

    if( !hWndMain )
    {
        return FALSE;
    }

    UpdateWindow( hWndMain );
    SetFocus( hWndMain );

    return TRUE;

} /* initApplication */

/*
 * ExitGame
 *
 * Exiting current game, clean up
 */
void ExitGame( void )
{
    if( lpFrameRate )
    {
        IDirectDrawSurface_Release(lpFrameRate);
        lpFrameRate = NULL;
    }

    if( lpInfo )
    {
        IDirectDrawSurface_Release(lpInfo);
        lpInfo = NULL;
    }

    if( lpPalette )
    {
        IDirectDrawSurface_Release(lpPalette);
        lpPalette = NULL;
    }

    DestroyGame();

} /* ExitGame */

/*
 * InitGame
 *
 * Initializing current game
 */
BOOL InitGame( void )
{
    ExitGame();

    GameSize = GameMode;

    /*
     * initialize sound
     */
    InitSound( hWndMain );

    /*
     * init DirectDraw, set mode, ...
     * NOTE GameMode might be set to 640x480 if we cant get the asked for mode.
     */
    if( !PreInitializeGame() )
    {
        return FALSE;
    }

    if (bStretch && bFullscreen)
    {
        GameSize.cx     = GameMode.cx / 2;
        GameSize.cy     = GameMode.cy / 2;
        GameRect.left   = GameMode.cx - GameSize.cx;
        GameRect.top    = GameMode.cy - GameSize.cy;
        GameRect.right  = GameMode.cx;
        GameRect.bottom = GameMode.cy;

        if (lpStretchBuffer)
            Msg("Stretching using a system-memory stretch buffer");
        else
            Msg("Stretching using a VRAM->VRAM blt");
    }
    else
    {
        GameRect.left   = (GameMode.cx - GameSize.cx) / 2;
        GameRect.top    = (GameMode.cy - GameSize.cy) / 2;
        GameRect.right  = GameRect.left + GameSize.cx;
        GameRect.bottom = GameRect.top + GameSize.cy;
    }

    /*
     * setup our palette
     */
    if( GameBPP == 8 )
    {
        lpPalette = ReadPalFile( NULL );        // create a 332 palette

        if( lpPalette == NULL )
        {
            Msg( "Palette create failed" );
            return FALSE;
        }

        IDirectDrawSurface_SetPalette( lpFrontBuffer, lpPalette );
    }

    /*
     *  load all the art and things.
     */
    if( !InitializeGame() )
    {
        return FALSE;
    }

    /*
     * init our code to draw the FPS
     */
    makeFontStuff();

    /*
     * spew some stats
     */
    {
        DDCAPS  ddcaps;
        ddcaps.dwSize = sizeof( ddcaps );
        IDirectDraw_GetCaps( lpDD, &ddcaps, NULL );
        Msg( "Total=%ld, Free VRAM=%ld", ddcaps.dwVidMemTotal, ddcaps.dwVidMemFree );
        Msg( "Used = %ld", ddcaps.dwVidMemTotal- ddcaps.dwVidMemFree );
    }

    return TRUE;

} /* InitGame */

#define IS_NUM(c)     ((c) >= '0' && (c) <= '9')
#define IS_SPACE(c)   ((c) == ' ' || (c) == '\r' || (c) == '\n' || (c) == '\t' || (c) == 'x')

int getint(char**p, int def)
{
    int i=0;

    while (IS_SPACE(**p))
        (*p)++;

    if (!IS_NUM(**p))
        return def;

    while (IS_NUM(**p))
        i = i*10 + *(*p)++ - '0';

    while (IS_SPACE(**p))
        (*p)++;

    return i;
}

/*
 * WinMain
 */
int PASCAL WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
                        int nCmdShow )
{
    MSG                 msg;

    while( lpCmdLine[0] == '-' )
    {
        lpCmdLine++;

        switch (*lpCmdLine++)
        {
        case 'e':
            bUseEmulation = TRUE;
            break;
        case 'w':
            bFullscreen = FALSE;
            break;
        case 'f':
            bFullscreen = TRUE;
            break;
        case '1':
            CmdLineBufferCount = 1;
            break;
        case '2':
        case 'd':
            CmdLineBufferCount = 2;
            break;
        case '3':
            CmdLineBufferCount = 3;
            break;
        case 's':
            bStretch = TRUE;
            break;
        case 'S':
            bWantSound = FALSE;
            break;
        case 'x':
            bStress= TRUE;
            break;
        case '?':
            bHelp= TRUE;
            bFullscreen= FALSE;  // give help in windowed mode
            break;
        }

        while( IS_SPACE(*lpCmdLine) )
        {
            lpCmdLine++;
        }
    }

    GameMode.cx = getint(&lpCmdLine, 640);
    GameMode.cy = getint(&lpCmdLine, 480);
    GameBPP = getint(&lpCmdLine, 8);

    /*
     * create window and other windows things
     */
    if( !initApplication(hInstance, nCmdShow) )
    {
        return FALSE;
    }

    /*
     * Give user help if asked for
     *
     * This is ugly for now because the whole screen is black
     * except for the popup box.  This could be fixed with some
     * work to get the window size right when it was created instead
     * of delaying that work. see ddraw.c
     *
     */

    if( bHelp )
    {
        MessageBox(hWndMain,
                   "F12 - Quit\n"
                   "NUMPAD 2  - crouch\n"
                   "NUMPAD 3  - apple\n"
                   "NUMPAD 4  - right\n"
                   "NUMPAD 5  - stop\n"
                   "NUMPAD 6  - left\n"
                   "NUMPAD 7  - jump\n"
                   "\n"
                   "Command line parameters\n"
                   "\n"
                    "-e   Use emulator\n"
                    "-S   No Sound\n"
                    "-1   No backbuffer\n"
                    "-2   One backbuffer\n"
                    "-4   Three backbuffers\n"
                    "-s   Use stretch\n"
                    "-x   Demo or stress mode\n",
                   OUR_APP_NAME, MB_OK );
    }

    /*
     * initialize for game play
     */
    if( !InitGame() )
    {
        return FALSE;
    }

    dwFrameTime = timeGetTime();
   
    while( 1 )
    {
        if (PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE))
        {
            if (!GetMessage( &msg, NULL, 0, 0))
            { 
                break;
            }
            TranslateMessage(&msg); 
            DispatchMessage(&msg);
        }
        else if (!bPaused && (bIsActive || !bFullscreen))
        {
            ProcessFox(lastInput);
            lastInput=0;
        }
        else
        {
            WaitMessage();
        }
    }

    if (AveFrameRateCount)
    {
        AveFrameRate = AveFrameRate / AveFrameRateCount;
        Msg("Average frame rate: %d", AveFrameRate);
    }

    return msg.wParam;

} /* WinMain */

#ifdef DEBUG

/*
 * Msg
 */
void __cdecl Msg( LPSTR fmt, ... )
{
    char        buff[256];
    va_list va;

    //
    // format message with header
    //

    lstrcpy( buff, "FOXBEAR:" );

    va_start(va, fmt);
    wvsprintf(&buff[lstrlen(buff)], fmt, va);
    va_end(va);
    lstrcat( buff, "\r\n" );

    //
    // To the debugger unless we need to be quiet
    //

    if( !bStress )
    {
        OutputDebugString( buff );
    }

} /* Msg */

#endif
