POLY.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*---------------------------------------------------------------------------*\
| POLYBEZIER MODULE
| This module contains the routines for demo
\*---------------------------------------------------------------------------*/

#include <windows.h>
#include "gdidemo.h"
#include "poly.h"

/*---------------------------------------------------------------------------*\
| CREATE BEZIER WINDOW PROCEDURE
| Create the bezier MDI-child window.
\*---------------------------------------------------------------------------*/
HWND FAR CreatePolyWindow(HWND hWndClient, int nItem)
{
HANDLE hInstance;
MDICREATESTRUCT mcs;
static char buffer[256];


hInstance = GETINSTANCE(hWndClient);
LoadString (hInstance, POLYTITLE, buffer, 256);

/*
** Initialize the MDI create struct for creation of the
** test window.
*/
mcs.szClass = POLYCLASS;
mcs.szTitle = buffer;
mcs.hOwner = hInstance;
mcs.x = CW_USEDEFAULT;
mcs.y = CW_USEDEFAULT;
mcs.cx = CW_USEDEFAULT;
mcs.cy = CW_USEDEFAULT;
mcs.style = 0l;
mcs.lParam = (LONG)nItem;

return((HWND)SendMessage(hWndClient,WM_MDICREATE,0,(LONG)(LPMDICREATESTRUCT)&mcs));
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER WINDOW PROCEDURE
| This is the main window function for the polybezier demo window.
\*---------------------------------------------------------------------------*/
LONG APIENTRY PolyProc(HWND hWnd, UINT wMsg, WPARAM wParam, LONG lParam)
{
switch(wMsg)
{
case WM_CREATE:
PolyCreateProc(hWnd);
break;


case WM_COMMAND:
PolyCommandProc(hWnd,wParam,lParam);
break;

case WM_MOVE:
PolyRedraw(hWnd);
break;


case WM_TIMER:
PolyDrawBez(hWnd);
break;


case WM_PAINT:
PolyPaintProc(hWnd);
break;


case WM_DESTROY:
PolyDestroyProc(hWnd);
break;


default:
return(DefMDIChildProc(hWnd,wMsg,wParam,lParam));
}
return(0l);
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER CREATE PROCEDURE
| Create the polybezier window for the demo application. This is a child
| of the MDI client window. Allocate the extra object information for
| handling of the polybezier demo.
\*---------------------------------------------------------------------------*/
BOOL PolyCreateProc(HWND hWnd)
{
PPOLYDATA ppd;


if(AllocWindowInfo(hWnd,sizeof(POLYDATA)))
{
if(ppd = (PPOLYDATA)LockWindowInfo(hWnd))
{
ppd->nBezTotal = 20;
ppd->nBezCurr = 0;
ppd->nColor = 0;
ppd->hBezBuffer = GlobalAlloc(GHND,(DWORD)(sizeof(BEZBUFFER) * MAX_BEZIER));

UnlockWindowInfo(hWnd);

PolyInitPoints(hWnd);

SetTimer(hWnd,1,50,NULL);
return(TRUE);
}
FreeWindowInfo(hWnd);
}
return(FALSE);
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER COMMAND PROCEDURE
| Process polybezier commands. This is a NOP for now. But who knows what
| tomorrow may bring.
\*---------------------------------------------------------------------------*/
BOOL PolyCommandProc(HWND hWnd, WPARAM wParam, LONG lParam)
{
hWnd = hWnd;
wParam = wParam;
lParam = lParam;

return(TRUE);
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER PAINT PROCEDURE
| Repaint the bezier window. All we really do here is validate our window,
| and reset the array of bezier objects.
\*---------------------------------------------------------------------------*/
VOID PolyPaintProc(HWND hWnd)
{
HDC hDC;
PAINTSTRUCT ps;


if(hDC = BeginPaint(hWnd,&ps))
EndPaint(hWnd,&ps);

PolyRedraw(hWnd);

return;
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER DESTROY PROCEDURE
| Kill the polybezier demo. Free up the resources allocated on behalf of
| this object.
\*---------------------------------------------------------------------------*/
VOID PolyDestroyProc(HWND hWnd)
{
PPOLYDATA ppd;


KillTimer(hWnd,1);
if(ppd = (PPOLYDATA)LockWindowInfo(hWnd))
{
GlobalFree(ppd->hBezBuffer);
UnlockWindowInfo(hWnd);
}
FreeWindowInfo(hWnd);

return;
}


/*---------------------------------------------------------------------------*\
| GET NEW VELOCITY
| This routine creates a new velocity for the bezier points. Each bezier
| point is randomly chosen. The two inside points should have a speed
| less then the endpoints (most of the time-better effect).
\*---------------------------------------------------------------------------*/
int PolyNewVel(int i)
{
int nRet;


if ((i == 1) || (i == 2))
nRet = (int)((lRandom() % VELMAX) / 3) + VELMIN;
else
nRet = (int)(lRandom() % VELMAX) + VELMIN;

return((nRet < 0) ? -nRet : nRet);
}


/*---------------------------------------------------------------------------*\
| INITIALIZE POLYBEZIER POINTS
| This routine initializes the polybezier points for the first object. This
| is performed on startup of the window.
\*---------------------------------------------------------------------------*/
VOID PolyInitPoints(HWND hWnd)
{
PPOLYDATA ppd;
LPBEZBUFFER lpBez;
int idx;
RECT rect;


if(ppd = (PPOLYDATA)LockWindowInfo(hWnd))
{
if(lpBez = (LPBEZBUFFER)GlobalLock(ppd->hBezBuffer))
{
GetClientRect(hWnd,&rect);

for(idx=0; idx < BEZ_PTS-1; idx++)
{
lpBez->pPts[idx].x = lRandom() % rect.right;
lpBez->pPts[idx].y = lRandom() % rect.bottom;

ppd->pVel[idx].x = PolyNewVel(idx);
ppd->pVel[idx].y = PolyNewVel(idx);
}
GlobalUnlock(ppd->hBezBuffer);
}
UnlockWindowInfo(hWnd);
}
return;
}


/*---------------------------------------------------------------------------*\
| POLYBEZIER REDRAW
| This routine resets the bezier curves and redraws the poly-bezier client
| area.
\*---------------------------------------------------------------------------*/
VOID PolyRedraw(HWND hWnd)
{
PPOLYDATA ppd;
LPBEZBUFFER lpBez,lpCurr;
HDC hDC;
int i,j;
RECT rect;


if(ppd = (PPOLYDATA)LockWindowInfo(hWnd))
{
if(lpBez = (LPBEZBUFFER)GlobalLock(ppd->hBezBuffer))
{
if(hDC = GetDC(hWnd))
{
/*
** Save the current bezier. Set the first bezier in the
** array to that curve, and use it as a basis for the next
** series.
*/
lpCurr = lpBez+ppd->nBezCurr;
*lpBez = *lpCurr;
ppd->nBezCurr = 0;


/*
** Clean the curves (all but the first curve).
*/
for(j=1; j < ppd->nBezTotal; j++)
{
for(i=0; i < BEZ_PTS; i++)
{
(lpBez+j)->pPts[i].x = -1;
(lpBez+j)->pPts[i].y = 0;
}
}



/*
** Clear the display.
*/
GetClientRect(hWnd,&rect);
BitBlt(hDC,0,0,rect.right, rect.bottom,(HDC)0,0,0,0);


/*
** Draw the first curve in the bezier array.
*/
#if defined(_WIN32) && defined(WIN32)
PolyBezier(hDC,lpBez->pPts,BEZ_PTS);
#else
Polyline(hDC,lpBez->pPts,BEZ_PTS);
#endif
ReleaseDC(hWnd,hDC);
}
GlobalUnlock(ppd->hBezBuffer);
}
UnlockWindowInfo(hWnd);
}
return;
}




VOID PolyDrawBez(HWND hWnd)
{
PPOLYDATA ppd;
LPBEZBUFFER lpBez,lpCurr,lpPrev;
int idx,x,y;
RECT rect;
HDC hDC;
HPEN hPen;

static COLORREF crColor[] = {0x000000FF,0x0000FF00,0x00FF0000,0x0000FFFF,
0x00FF00FF,0x00FFFF00,0x00FFFFFF,0x00000080,
0x00008000,0x00800000,0x00008080,0x00800080,
0x00808000,0x00808080,0x000000FF,0x0000FF00,
0x00FF0000,0x0000FFFF,0x00FF00FF,0x00FFFF00};


if(ppd = (PPOLYDATA)LockWindowInfo(hWnd))
{
if(lpBez = (LPBEZBUFFER)GlobalLock(ppd->hBezBuffer))
{
if(hDC = GetDC(hWnd))
{
GetClientRect(hWnd,&rect);

lpPrev = lpBez+ppd->nBezCurr;

ppd->nBezCurr += 1;

if(ppd->nBezCurr >= ppd->nBezTotal)
{
ppd->nBezCurr = 0;
ppd->nColor = (++ppd->nColor % 20);
}
lpCurr = lpBez+ppd->nBezCurr;


if(lpCurr->pPts[0].x != -1)
{
hPen = SelectObject(hDC,GetStockObject(BLACK_PEN));
#if defined(_WIN32) && defined(WIN32)
PolyBezier(hDC,lpCurr->pPts,BEZ_PTS);
#else
Polyline(hDC,lpCurr->pPts,BEZ_PTS);
#endif
SelectObject(hDC,hPen);
}

for(idx=0; idx < BEZ_PTS; idx++)
{
x = lpPrev->pPts[idx].x;
y = lpPrev->pPts[idx].y;
x += ppd->pVel[idx].x;
y += ppd->pVel[idx].y;

if(x >= rect.right)
{
x = rect.right - ((x - rect.right)+1);
ppd->pVel[idx].x = -PolyNewVel(idx);
}

if(x <= rect.left)
{
x = rect.left + ((rect.left - x)+1);
ppd->pVel[idx].x = PolyNewVel(idx);
}

if(y >= rect.bottom)
{
y = rect.bottom - ((y - rect.bottom)+1);
ppd->pVel[idx].y = -PolyNewVel(idx);
}

if(y <= rect.top)
{
y = rect.top + ((rect.top - y)+1);
ppd->pVel[idx].y = PolyNewVel(idx);
}

lpCurr->pPts[idx].x = x;
lpCurr->pPts[idx].y = y;

}

hPen = SelectObject(hDC,CreatePen(PS_SOLID,1,crColor[ppd->nColor]));
#if defined(_WIN32) && defined(WIN32)
PolyBezier(hDC,lpCurr->pPts,BEZ_PTS);
#else
Polyline(hDC,lpCurr->pPts,BEZ_PTS);
#endif
DeleteObject(SelectObject(hDC,hPen));

#if defined(_WIN32) && defined(WIN32)
SetROP2(hDC,R2_COPYPEN);
#endif
ReleaseDC(hWnd,hDC);
}
GlobalUnlock(ppd->hBezBuffer);
}
UnlockWindowInfo(hWnd);
}
}