/* ballblt.cpp  Animated drawing with BitBlt()--preserving background */

#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 */
HDC     _hDC, _hMemDC;      /* global screen and memory DC--used by drawball() & WndProc() */

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          = 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","Ballblt", 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 on */
         }
}

LRESULT CALLBACK WndProc (HWND hWnd, UINT wMessage,
                           WPARAM wParam, LPARAM lParam)
{
static HBITMAP hBitmap, hBitmap1;

         switch (wMessage)          /* process windows messages */
         {
                case WM_CREATE: /* application starting, turn drawing 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 off */
                                                DeleteDC(_hMemDC); /* get rid of DCs and bitmaps */
                                                ReleaseDC(hWnd, _hDC);
                                                DeleteObject(hBitmap);
                                                DeleteObject(hBitmap1);
                                        }
                                        else
                                        {
                                                _bDrawOn = TRUE ; /* toggle drawing on */
                                    /* set up DC, mem DC, and bitmaps for each */  
                                                _hDC=GetDC(hWnd);
                                                _hMemDC=CreateCompatibleDC(_hDC);
                                                hBitmap=CreateCompatibleBitmap(_hDC,_nXSize,_nYSize);
                                                hBitmap1=CreateCompatibleBitmap(_hDC,_nXSize,_nYSize);
                                                SelectObject(_hMemDC,hBitmap);
                                                SelectObject(_hDC,hBitmap1);
                                        }
                                        break ;

                                case IDM_QUIT:
                                        DestroyWindow (hWnd) ;
                                        break ;
                                }

                                break ;

                case WM_DESTROY:
                        if (_bDrawOn == TRUE)
                                {
                                DeleteDC(_hMemDC); /* get rid of DCs & bitmaps */
                                ReleaseDC(hWnd,_hDC);
                                DeleteObject(hBitmap);
                                DeleteObject(hBitmap1); 
                                }
                        PostQuitMessage (0) ;
                        break ;
                default:
                        return DefWindowProc (hWnd, wMessage, wParam, lParam) ;
         }
         return (0) ;
}

/* DrawBall() draws a red ball and a blue crosshatched background */
/* on an offscreen bitmap and BitBlts the bitmap to the screen */
/* each time the function is called.  The ball is BALLRAD in radius. */
/* Motion is as in the ball.cpp program */

void DrawBall (HWND hWnd)
{
        HBRUSH                  hBrush ;
        static  int             nX = 2 * BALLRAD, nY = 2 * BALLRAD, /* starting X,Y */
                                        nVelX = VELOCITY, nVelY = VELOCITY; /* X,Y velocity */

        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 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 ;

        /* Create blue hatched brush for background */
        hBrush = CreateHatchBrush (HS_DIAGCROSS, RGB (0, 0, 255)) ;
        SelectObject (_hMemDC, hBrush) ;        /* select into memory DC */
        /* Tile brush across the offscreen bitmap */
        PatBlt(_hMemDC, 0, 0, _nXSize, _nYSize, PATCOPY);
        /* Delete the brush */
        SelectObject(_hMemDC, GetStockObject(WHITE_BRUSH));
        DeleteObject(hBrush); 

        hBrush = CreateSolidBrush(RGB(255,0,0));   /* red brush for ball */
        SelectObject(_hMemDC, hBrush);

        /* draw ball in new location on off-screen bitmap */
        Ellipse (_hMemDC, nX-BALLRAD, nY-BALLRAD, nX+BALLRAD, nY+BALLRAD) ;

        /* BitBlt to screen--note only one access to screen */
        BitBlt(_hDC, 0, 0, _nXSize, _nYSize, _hMemDC, 0, 0, SRCCOPY);

        /* Slow things down a bit */
        Sleep(10) ;

        /* delete objects */
        SelectObject (_hMemDC, GetStockObject(WHITE_BRUSH)) ;
        DeleteObject (hBrush) ;
}