/* ball.cpp   Demonstrates animated drawing */

#include <windows.h>    
#include "ball.h"  /* constants: VELOCITY, BALLRAD, MINRAD */

BOOL    _bDrawOn = FALSE ;  /* global to track if drawing is on or off */
int     _nXSize, _nYSize ;  /* window width and height */

int PASCAL WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                                LPSTR lpszCmdLine, int nCmdShow)
{
    HWND        hWnd ;      /* the window's "handle" */
    MSG         msg ;       /* a message structure */
    WNDCLASS    wndclass ;  /* window class structure */

        wndclass.style          = CS_HREDRAW | CS_VREDRAW ;
        wndclass.lpfnWndProc    = WndProc ;
        wndclass.cbClsExtra     = 0 ;
        wndclass.cbWndExtra     = 0 ;
        wndclass.hInstance      = hInstance ;
        wndclass.hIcon          = LoadIcon (NULL, NULL) ;
        wndclass.hCursor        = LoadCursor (NULL, IDC_ARROW) ;
        wndclass.hbrBackground  = (HBRUSH)GetStockObject (WHITE_BRUSH) ;
        wndclass.lpszMenuName   = "MYMENU" ;
        wndclass.lpszClassName  = "MyClass" ;
        if (!RegisterClass (&wndclass))
            return 0 ;

    hWnd = CreateWindow ("MyClass","Ball", WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
        NULL, NULL, hInstance, NULL) ;
    ShowWindow (hWnd, nCmdShow) ;
    UpdateWindow (hWnd) ;
    while (TRUE)                        /* peek message loop */
    {
        if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
        {
            if (msg.message == WM_QUIT) /* if WM_QUIT, quit! */
                return msg.wParam ;
            else                        /* else, process message */
            {
                TranslateMessage (&msg) ;
                DispatchMessage (&msg) ;    
            }
        }   
        else if (_bDrawOn)           /*no msg so paint ball..*/
            DrawBall (hWnd) ;        /*if drawing enabled */
    }
}

LRESULT CALLBACK WndProc (HWND hWnd, UINT wMessage,
                                         WPARAM wParam, LPARAM lParam)
{
    switch (wMessage)          /* process windows messages */
    {
        case WM_CREATE:        /* application starting, turn draw off */
            _bDrawOn = FALSE ;
            break ;
        case WM_SIZE :         /* get window client area size */
            _nXSize = LOWORD (lParam) ;
            _nYSize = HIWORD (lParam) ;
            break ;
        case WM_COMMAND:       /* menu items selected */
            switch (LOWORD(wParam))
            {
                case IDM_SHOW:          
                    if (_bDrawOn)
                        _bDrawOn = FALSE ;  /* toggle drawing on/off */
                    else
                        _bDrawOn = TRUE ;
                    break ;
                case IDM_QUIT:
                    DestroyWindow (hWnd) ;
                    break ;
            }
            break ;
        case WM_DESTROY:
            PostQuitMessage (0) ;
            break ;
        default:
            return DefWindowProc (hWnd, wMessage, wParam, lParam) ;
    }
    return (0) ;
}

/* DrawBall() draws a red ball on the window hWnd every time the */
/* function is called.  The ball is BALLRAD in radius.  The walls */
/* (client area size) are from 0,0 to nXSize,nYsize.  The location */
/* is moved each time by VELOCITY units. The signs of the X and Y */
/* velocity terms nVelX,nVelY are reversed each time the ball gets */
/* within MINRAD units of a wall.  This causes the ball to appear */
/* to bounce off the wall.  Drawing the ball at the new location */
/* causes the old ball to be erased, as the ball is drawn using a */
/* white pen for the outline that is 1.5 * VELOCITY in width.  The */
/* white pen ends up painting over any portion of the ball that is */
/* otherwise visible from the previous location. */

void DrawBall (HWND hWnd)
{
    HDC             hDC ;   
    HPEN            hPen, hOldPen ;
    HBRUSH          hBrush, hOldBrush ;
    static  int     nX = 2 * BALLRAD, nY = 2 * BALLRAD, /* starting X,Y */
                    nVelX = VELOCITY, nVelY = VELOCITY; /* X,Y velocity */
    int             i, j;  /* delay loop counters */

    nX = nX + nVelX ;       /* compute new center X,Y of ball */
    nY = nY + nVelY ;
    if (nY > _nYSize)        /* check if user moved walls and hid ball */
        nY = 2 * BALLRAD ;  /* put the ball back at the starting.. */
    if (nX > _nXSize)        /* position if it is not going to be.. */
        nX = 2 * BALLRAD ;  /* visible with the new window size */

    if (nY < MINRAD || nY > _nYSize - MINRAD)  /* check if ball hit wall */
        nVelY = -1 * nVelY ;                  /* if so, change direction */
    if (nX < MINRAD || nX > _nXSize - MINRAD)
        nVelX = -1 * nVelX ;

    hDC = GetDC (hWnd) ;    /* get the device context handle */

    /* Create a thick white pen and a red brush */
    hPen = CreatePen (PS_SOLID, VELOCITY + VELOCITY/2, RGB(255,255,255) );
    hBrush = CreateSolidBrush (RGB (255, 0, 0)) ;
    hOldPen = (HPEN)SelectObject (hDC, hPen) ;      /* select into the DC */
    hOldBrush = (HBRUSH)SelectObject (hDC, hBrush) ;
 
    /* draw the ball in the new location */
    /* the outline pen erases around ball */
    Ellipse (hDC, nX - BALLRAD, nY - BALLRAD, nX + BALLRAD, nY + BALLRAD) ;

    /* wait for a while to slow things down */
    Sleep(10) ;
        
    /* delete all objects and free DC */
    SelectObject (hDC, hOldPen) ;  
    DeleteObject (hPen) ;
    SelectObject (hDC, hOldBrush) ;
    DeleteObject (hBrush) ;
    ReleaseDC (hWnd, hDC) ;
}