/****************************************************************************

    PROGRAM:	Vlibdemo.exe

    PURPOSE:	To demostrate the usage of Visualib functions.
	    
    PROVIDER:	Visual Tech, Co.
	    
    DATE:	January, 1992

    FUNCTIONS:

	WinMain() - calls initialization function, processes message loop
	InitApplication() - initializes window data and registers window
	InitInstance() - saves instance handle and creates main window
	MainWndProc() - processes messages
	About() - processes messages for "About" dialog box

    COMMENTS:

****************************************************************************/

#include "windows.h"
#include "vlibdemo.h"
#include "visualib.h"

HANDLE hInst;
HVIEW	viewer21, viewer22, viewer31, viewer32, viewer33, viewer34, viewer35;
int demo_flag, demo_type, demo_item;

/****************************************************************************

    FUNCTION: WinMain (HANDLE, HANDLE, LPSTR, int)

    PURPOSE: calls initialization function, processes message loop

    COMMENTS:

        Windows recognizes this function by name as the initial entry point 
        for the program.  This function calls the application initialization 
        routine, if no other instance of the program is running, and always 
        calls the instance initialization routine.  It then executes a message
        retrieval and dispatch loop that is the top-level control structure 
        for the remainder of execution.  The loop is terminated when a WM_QUIT
        message is received, at which time this function exits the application
        instance by returning the value passed by PostQuitMessage().

        If this function must abort before entering the message loop, it 
        returns the conventional value NULL.  

****************************************************************************/

int PASCAL WinMain (hInstance, hPrevInstance, lpCmdLine, nCmdShow)
HANDLE hInstance;
HANDLE hPrevInstance;
LPSTR lpCmdLine;
int nCmdShow;
{
    MSG msg;

    if (!hPrevInstance)
	if (!InitApplication (hInstance))
	    return (FALSE);

    if (!InitInstance (hInstance, nCmdShow))
        return (FALSE);

    while (GetMessage (&msg, NULL, NULL, NULL))	{
	TranslateMessage (&msg);
	DispatchMessage (&msg);
    }
    return (msg.wParam);
}


/****************************************************************************

    FUNCTION: InitApplication (HANDLE)

    PURPOSE: Initializes window data and registers window class

    COMMENTS:

        This function is called at initialization time only if no other 
        instances of the application are running.  This function performs 
        initialization tasks that can be done once for any number of running 
        instances.  

        In this case, we initialize a window class by filling out a data 
        structure of type WNDCLASS and calling the Windows RegisterClass() 
        function.  Since all instances of this application use the same window
        class, we only need to do this when the first instance is initialized.

****************************************************************************/

BOOL InitApplication (hInstance)
HANDLE hInstance;
{
    WNDCLASS  wc;
    
    if (InitialGraphics2D (0, 0, 0)) {
	return (FALSE);
    }
    viewer21 = CreateViewer2D ("2D Objects", 10, 10, 100, 100);
    SetWindow2D (viewer21, -10, -10, 10, 10);
    viewer22 = CreateViewer2D ("U.S. Flag", 10, 10, 400, 217);
    SetWindow2D (viewer22, 0, 0, 1, (float) (13.0 / 24.0));
    if (InitialGraphics3D (0, 0, 0)) {
	return (FALSE);
    }
    viewer31 = CreateViewer3D ("View Motion", 120, 10, 100, 100);
    SetView3D (viewer31, 100, 100, 100, 0, 0, 0, 0);
    SetPerspective3D (viewer31, 45, 1, 1, 1000);
    viewer32 = CreateViewer3D ("Object Rotation", 230, 10, 100, 100);
    SetView3D (viewer32, 100, 100, 100, 0, 0, 0, 0);
    SetPerspective3D (viewer32, 45, 1, 1, 1000);

    viewer33 = CreateViewer3D ("View Zoom", 230, 130, 100, 100);
    SetPolarView3D (viewer33, 1, 1, 0, 20, 75, 45, 0);
    SetPerspective3D (viewer33, 90, 1, 1, 1000);

    viewer34 = CreateViewer3D ("Ortho Project", 120, 130, 100, 100);
    SetPolarView3D (viewer34, 1, 1, 0, 10, 45, 45, 0);
    SetOrthogonal3D (viewer34, -10, 10, -10, 10, 1, 100);

    viewer35 = CreateViewer3D ("Depth Clipping", 10, 130, 100, 100);
    SetPolarView3D (viewer35, 1, 1, 0, 20, 75, 45, 0);
    SetPerspective3D (viewer35, 90, 1, 1, 80);
    
    demo_flag = 1;
    demo_item = 1;
    demo_type = 1;
    
    wc.style = NULL;
    wc.lpfnWndProc = MainWndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject (WHITE_BRUSH); 
    wc.lpszMenuName =  "VlibDemo";
    wc.lpszClassName = "VlibDemoClass";

    return (RegisterClass (&wc));

}


/****************************************************************************

    FUNCTION:  InitInstance (HANDLE, int)

    PURPOSE:  Saves instance handle and creates main window

    COMMENTS:

        This function is called at initialization time for every instance of 
        this application.  This function performs initialization tasks that 
        cannot be shared by multiple instances.  

        In this case, we save the instance handle in a static variable and 
        create and display the main program window.  
        
****************************************************************************/

BOOL InitInstance (hInstance, nCmdShow)
HANDLE	hInstance;
int	nCmdShow;
{
    HWND            hWnd;
    int	sw, sh, ww, wh;

    sw = GetSystemMetrics (0);
    sh = GetSystemMetrics (1);
    hInst = hInstance;

    ww = (int) (sw * 0.666);
    wh = (int) (sh * 0.666);
    sw = (int) (sw * 0.167);
    sh = (int) (sh * 0.167);
    hWnd = CreateWindow ("VlibDemoClass",
        "Visualib 1.0 (C) Demonstration",
        WS_OVERLAPPEDWINDOW, sw, sh, ww, wh,
        NULL, NULL, hInstance, NULL);

    if (!hWnd)
        return (FALSE);

    ShowWindow (hWnd, nCmdShow);
    UpdateWindow (hWnd);
    
    return (TRUE);
}

HANDLE GetPrinterDC ()
{
    char	pPrintInfo[80];
    LPSTR	lpTemp;
    LPSTR	lpPrintType;
    LPSTR	lpPrintDriver;
    LPSTR	lpPrintPort;

    if (!GetProfileString ("windows", "Device", (LPSTR)"", pPrintInfo, 80))
        return (NULL);
    lpTemp = lpPrintType = pPrintInfo;
    lpPrintDriver = lpPrintPort = 0;
    while (*lpTemp) {
        if (*lpTemp == ',') {
            *lpTemp++ = 0;
            while (*lpTemp == ' ')
                lpTemp = AnsiNext (lpTemp);
            if (!lpPrintDriver)
                lpPrintDriver = lpTemp;
            else {
                lpPrintPort = lpTemp;
                break;
            }
        }
        else
            lpTemp = AnsiNext (lpTemp);
    }

    return (CreateDC (lpPrintDriver, lpPrintType, lpPrintPort, (LPSTR) NULL));
}

void	USFlag (HDC hDC)
{
    short	i, j;
    float	x1, y1, x2, y2;
    float	width, height;

    width = 1;
    height = (float) 13 / 24;
    x1 = 0;
    x2 = width;
    y1 = 0;
    y2 = height / 13;
    BrushColor (hDC, WVRED);
    PenColor (hDC, WVRED);
    for (i = 0; i < 7; i ++) {
	Rectangle2D (hDC, x1, y1, x2, y2);
	y1 += height * 2 / 13;
	y2 += height * 2 / 13;
    }
    
    BrushColor (hDC, WVWHITE);
    PenColor (hDC, WVWHITE);
    y1 = height / 13;
    y2 = height * 2 / 13 - 0.001;
    for (i = 0; i < 6; i ++) {
	Rectangle2D (hDC, x1, y1, x2, y2);
	y1 += height * 2 / 13;
	y2 += height * 2 / 13;
    }

    BrushColor (hDC, WVBLUE);
    PenColor (hDC, WVBLUE);
    x2 = 10 * width / 24;
    y1 = 6 * height / 13;
    y2 = height;
    Rectangle2D (hDC, x1, y1, x2, y2);

    BrushColor (hDC, WVWHITE);
    PenColor (hDC, WVWHITE);
    x2 /= 6;
    x1 = 0.5 * x2;
    y2 = height * 7 / 13 / 5;
    for (i = 0; i < 6 ; i ++) {
	y1 = height - 0.5 * y2;
	for (j = 0; j < 5; j ++) {
	    NsideStar2D (hDC, x1, y1, 0.01, 5);
	    y1 -= y2;
	}
	x1 = x1 + x2;
    }
    x1 = x2;
    for (i = 0; i < 5; i ++) {
	y1 = height - y2;
	for (j = 0; j < 4; j ++) {
	    NsideStar2D (hDC, x1, y1, 0.01, 5);
	    y1 -= y2;
	}
	x1 = x1 + x2;
    }
}

void	heart (HDC hdc)
{
    POINT2D p[20] = {{0, 0, 1}, {0.4, 0.8, 1}, {2, 1.4, 1},
		{2.5, -1, 1}, {1, -2, 1}, {0, -3, 1},
		{-1, -2, 1}, {-2.5, -1, 1}, {-2, 1.4, 1},
		{-0.4, 0.8, 1}, {0, 0, 1}};
		
    float knot[20] = {0, 0, 0, 1, 2, 3, 3, 3,
		4, 5, 6, 6, 6};
	
    NURBSCurve2D (hdc, p, 11, knot);
}

void	logo (HDC hdc)
{
    MoveTo3D (hdc, 0, 0, 0);
    LineTo3D (hdc, 1, 1, -1);
    LineTo3D (hdc, 1, 1, 1);
    LineTo3D (hdc, -1, -1, 1);
    LineTo3D (hdc, -1, 1, -1);
    LineTo3D (hdc, 1, -1, -1);
    LineTo3D (hdc, 1, 1, 1);
    LineTo3D (hdc, 1, -1, 1);
    LineTo3D (hdc, -1, -1, 1);
    LineTo3D (hdc, -1, 1, 1);
    LineTo3D (hdc, -1, 1, -1);
    LineTo3D (hdc, -1, -1, -1);
    LineTo3D (hdc, 1, -1, -1);
    LineTo3D (hdc, 1, 1, -1);
    LineTo3D (hdc, -1, 1, 1);
    LineTo3D (hdc, 0, 0, 0);
    LineTo3D (hdc, 1, -1, 1);
    LineTo3D (hdc, -1, -1, -1);
    LineTo3D (hdc, 0, 0, 0);
}

POINT3D circ[]= {
	{1, 0, 0, 1},
	{0.66666667, 0.57735027, 0.074074074, 0.66666667},
	{0.16666667, 0.86602540, 0.148148148, 0.66666667},
	{-0.5, 0.86602540, 0.33333333, 1}
};

void	spring (HDC hdc)
{
    PushMatrix3D ();
    BSplineCurve3D (hdc, circ, 4);
    Translate3D (0, 0, 0.33333333);
    Rotate3D (120, 'z');
    BSplineCurve3D (hdc, circ, 4);
    Translate3D (0, 0, 0.33333333);
    Rotate3D (120, 'z');
    BSplineCurve3D (hdc, circ, 4);
    Translate3D (0, 0, 0.33333333);
    Rotate3D (120, 'z');
    BSplineCurve3D (hdc, circ, 4);
    Translate3D (0, 0, 0.33333333);
    Rotate3D (120, 'z');
    BSplineCurve3D (hdc, circ, 4);
    Translate3D (0, 0, 0.33333333);
    Rotate3D (120, 'z');
    BSplineCurve3D (hdc, circ, 4);
    PopMatrix3D ();
}


POINT3D surf[16] = {
	{-3, 0, 1, 1},
	{1, 4, -1, 1},
	{5, -2, 0, 1},
	{8, 0, -2, 1},
	{-2, 0, -3, 1},
	{1, 4, 0, 1},
	{5, -2, 1, 1},
	{7, 0.6, 1, 1},
	{-2, 2, 3, 1},
	{1, 4, 3.5, 1},
	{5, -2, 2, 1},
	{7.5, 0.7, 3, 1},
	{-2, 1, 6, 1},
	{1, 4, 4, 1},
	{5, -1, 4, 1},
	{8, 0.5, 6.6, 1}
};

float sknot[20] = {0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4};
float tknot[20] = {0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 4, 4};

void	Object2D (HDC hdc)
{
    short	i;

    DisplayViewerFrame2D (hdc, viewer21, WVRED);
    DisplayViewerName2D (hdc, viewer21, WVBLUE, 0);

    BeginDoubleBuffer2D (&hdc, viewer21);

    SelectViewer2D (viewer21);
    PenColor (hdc, WVRED);

    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer2D (hdc, viewer21, WVGRAY);
	BrushColor (hdc, WVGREEN);
	NsideFlower2D (hdc, 0, 0, 6, 4.5, 10);
	BrushColor (hdc, WVRED);
	NsideStar2D (hdc, 0, 0, 4, 5);
	Rotate2D (6);
	UpdateBuffer2D (hdc, viewer21);
    }
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer2D (hdc, viewer21, WVGRAY);
	BrushColor (hdc, WVGREEN);
	NsideFlower2D (hdc, 0, 0, 6, 4.5, 10);
	BrushColor (hdc, WVRED);
	NsideStar2D (hdc, 0, 0, 4, 5);
	MoveViewer2D (viewer21, 0.25, 0);
	UpdateBuffer2D (hdc, viewer21);
    }

    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer2D (hdc, viewer21, WVGRAY);
	BrushColor (hdc, WVGREEN);
	NsideFlower2D (hdc, 0, 0, 6, 4.5, 10);
	BrushColor (hdc, WVRED);
	NsideStar2D (hdc, 0, 0, 4, 5);
	Scale2D (1.06, 1.06);
	UpdateBuffer2D (hdc, viewer21);
    }

    EndDoubleBuffer2D (&hdc, viewer21);
}

void	ViewerMotion3D (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer31, WVBLUE);
    DisplayViewerName3D (hdc, viewer31, WVBLUE, 0);

    BeginDoubleBuffer3D (&hdc, viewer31);

    SelectViewer3D (viewer31);
    BrushColor (hdc, WVRED);
    for (i = 0; i < 5*demo_type; i ++) {
	MoveViewer3D (viewer31, 0, 0, -10);
	ClearViewer3D (hdc, viewer31, WVGRAY);
	Box3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }
    BrushColor (hdc, WVGREEN);
    for (i = 0; i < 5*demo_type; i ++) {
	MoveViewer3D (viewer31, 0, 5, 0);
	ClearViewer3D (hdc, viewer31, WVGRAY);
	Box3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }
    BrushColor (hdc, WVBLUE);
    for (i = 0; i < 5*demo_type; i ++) {
	MoveViewer3D (viewer31, 5, 0, 0);
	ClearViewer3D (hdc, viewer31, WVGRAY);
	Cube3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }
    BrushColor (hdc, WVYELLOW);
    for (i = 0; i < 5*demo_type; i ++) {
	RotateWorld3D (viewer31, 0, 0, 6);
	ClearViewer3D (hdc, viewer31, WVGRAY);
	Cube3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }
    BrushColor (hdc, WVLIGHTBLUE);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer31, WVGRAY);
	RotateWorld3D (viewer31, 0, 6, 0);
	Cube3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }
    BrushColor (hdc, WVBROWN);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer31, WVGRAY);
	RotateWorld3D (viewer31, 6, 0, 0);
	Cube3D (hdc, -50, -50, 0, 50, 50, 50);
	UpdateBuffer3D (hdc, viewer31);
    }

    EndDoubleBuffer3D (&hdc, viewer31);

}

void	ObjectMotion3D (HDC hdc)
{
    short	i;
	
    DisplayViewerName3D (hdc, viewer32, WVBLUE, 0);
    DisplayViewerFrame3D (hdc, viewer32, WVBLUE);

    BeginDoubleBuffer3D (&hdc, viewer32);
    SelectViewer3D (viewer32);

    BrushColor (hdc, WVRED);
    for (i = 0; i <= 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer32, WVGRAY);
	Cylinder3D (hdc, 0, 0, 0, 30, 50);
	Rotate3D (3, 'z');
	Rotate3D (6, 'x');
	Rotate3D (3, 'y');
	UpdateBuffer3D (hdc, viewer32);
    }
    EndDoubleBuffer3D (&hdc, viewer32);
}

void	ViewerZoom3D (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer33, WVRED);
    DisplayViewerName3D (hdc, viewer33, WVBLUE, 0);

    BeginDoubleBuffer3D (&hdc, viewer33);
    SelectViewer3D (viewer33);

    BrushColor (hdc, WVGREEN);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer33, WVGRAY);
	MarkPosition3D (hdc, 0, 0, 0, 5);
	Cone3D (hdc, 0, 0, 0, 3, 10);
	ZoomViewer3D (viewer33, 1.05);
	UpdateBuffer3D (hdc, viewer33);
    }
    EndDoubleBuffer3D (&hdc, viewer33);
}

void	OrthoProject3D (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer34, WVRED);
    DisplayViewerName3D (hdc, viewer34, WVBLUE, 0);
    SelectViewer3D (viewer34);
    BrushColor (hdc, WVGREEN);
    Sphere3D (hdc, 3, -1, -4, 3, 20, 10);
}

void	ViewerClip3D (HDC hdc)
{
    short	i;
	
    DisplayViewerFrame3D (hdc, viewer35, WVRED);
    DisplayViewerName3D (hdc, viewer35, WVBLUE, 0);

    BeginDoubleBuffer3D (&hdc, viewer35);
    SelectViewer3D (viewer35);
    BrushColor (hdc, WVBLUE);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer35, WVGRAY);
	NsideStar3D (hdc, 0, 0, 0, 5, 20, 5);
	MoveViewer3D (viewer35, 0, 0, -0.5);
	Rotate3D (6 * i, 'z');
	UpdateBuffer3D (hdc, viewer35);
    }
    EndDoubleBuffer3D (&hdc, viewer35);
}

void Flag(HDC hdc)
{
    short	i;
    short	x, y, w, h;

    SelectViewer2D (viewer22);
    GetViewport2D (viewer22, &x, &y, &w, &h);
    USFlag (hdc);
    DisplayViewerFrame2D (hdc, viewer22, WVBLACK);
    DisplayViewerName2D (hdc, viewer22, WVBLUE, 1);
    SetViewport2D (viewer22, 350, 230, 60, 30);
    USFlag (hdc);
    DisplayViewerFrame2D (hdc, viewer22, WVBLACK);
    SetViewport2D (viewer22, x, y, w, h);
}

void	ViewerReset ()
{
    SetViewerName2D (viewer21, "2D Objects");
    SetViewport2D(viewer21, 10, 10, 100, 100);
    SetWindow2D (viewer21, -10, -10, 10, 10);
    
    SetViewerName2D (viewer22, "U.S. Flag");
    SetViewport2D(viewer22, 10, 10, 400, 217);
    SetWindow2D (viewer22, 0, 0, 1, (float) (13.0 / 24.0));

    SetViewerName3D (viewer31, "View Motion");
    SetViewport3D(viewer31, 120, 10, 100, 100);
    SetView3D (viewer31, 100, 100, 100, 0, 0, 0, 0);
    SetPerspective3D (viewer31, 45, 1, 1, 1000);
    
    SetViewerName3D (viewer32, "Object Rotation");
    SetViewport3D(viewer32, 230, 10, 100, 100);
    SetView3D (viewer32, 100, 100, 100, 0, 0, 0, 0);
    SetPerspective3D (viewer32, 45, 1, 1, 1000);

    SetViewerName3D (viewer33, "View Zoom");
    SetViewport3D(viewer33, 230, 130, 100, 100);
    SetPolarView3D (viewer33, 1, 1, 0, 20, 75, 45, 0);
    SetPerspective3D (viewer33, 90, 1, 1, 1000);

    SetViewerName3D (viewer34, "Ortho Project");
    SetViewport3D(viewer34, 120, 130, 100, 100);
    SetPolarView3D (viewer34, 1, 1, 0, 10, 45, 45, 0);
    SetOrthogonal3D (viewer34, -10, 10, -10, 10, 1, 100);

    SetViewerName3D (viewer35, "Depth Clipping");
    SetViewport3D(viewer35, 10, 130, 100, 100);
    SetPolarView3D (viewer35, 1, 1, 0, 20, 75, 45, 0);
    SetPerspective3D (viewer35, 90, 1, 1, 80);
}

void	RotateSpring (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer31, WVBLUE);
    SetViewerName3D(viewer31, "3D Curve");
    BeginDoubleBuffer3D (&hdc, viewer31);
    SelectViewer3D (viewer31);
    Scale3D (20, 20, 20);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer31, WVGRAY);
	PenColor (hdc, WVRED);
	spring (hdc);
	Translate3D (0.05, 0, 0);
	Rotate3D (-6, 'y');
	PushMatrix3D ();
        PenColor (hdc, WVBLACK);
        BrushColor (hdc, WVRED);
	Rotate3D (6 * i, 'z');
	Translate3D (0, 2, 0);
	Rotate3D (3, 'y');
	Tetrahedron (hdc, 1);
	PushMatrix3D ();
	BrushColor (hdc, WVGREEN);
	Rotate3D (6, 'x');
	Translate3D (0, 0, 2);
	Rotate3D (3 * i, 'z');
	Octahedron (hdc, 1);
	PopMatrix3D ();
	PopMatrix3D ();
	UpdateBuffer3D (hdc, viewer31);
    }
    EndDoubleBuffer3D (&hdc, viewer31);
}

void	RotateLogo (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer32, WVBLUE);
    SelectViewer3D (viewer32);
    BeginDoubleBuffer3D (&hdc, viewer32);
    PenColor (hdc, WVBLUE);
    Scale3D (30, 30, 30);
    for ( i = 0; i < 5*demo_type; i++) {
	ClearViewer3D (hdc, viewer32, WVGRAY);
	logo (hdc);
	Rotate3D (6, 'z');
	UpdateBuffer3D (hdc, viewer32);
    }
    EndDoubleBuffer3D (&hdc, viewer32);
}

void	RotateSurface (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer35, WVBLUE);
    SetViewerName3D(viewer35, "NURBS Surface");
    DisplayViewerName3D(hdc, viewer35, WVBLUE, 0);
    BeginDoubleBuffer3D (&hdc, viewer35);
    SelectViewer3D (viewer35);
    Scale3D (2, 2, 2);
    PenColor (hdc, WVMAGENTA);
    for (i = 0; i < 5*demo_type; i++) {
	ClearViewer3D (hdc, viewer35, WVGRAY);
	NURBSSurface3D (hdc, surf, 4, 4, sknot, tknot, 6, 6);
	Rotate3D (6, 'z');
	Rotate3D (12, 'x');
	Rotate3D (3, 'y');
	UpdateBuffer3D (hdc, viewer35);
    }
    EndDoubleBuffer3D (&hdc, viewer35);
}

void	RotateDodecahedron (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer33, WVRED);
    SetViewerName3D(viewer33, "Dodecahedron");
    DisplayViewerName3D(hdc, viewer33, WVBLUE, 0);
    BeginDoubleBuffer3D (&hdc, viewer33);
    SelectViewer3D (viewer33);
    Scale3D (6, 6, 6);
    BrushColor (hdc, WVBROWN);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer33, WVGRAY);
	Dodecahedron (hdc, 0.5);
	Translate3D (0, 0.1, 0);
	Rotate3D (6, 'z');
	UpdateBuffer3D (hdc, viewer33);
    }
    EndDoubleBuffer3D (&hdc, viewer33);
}

void	RotateIcosahedron (HDC hdc)
{
    short	i;

    DisplayViewerFrame3D (hdc, viewer34, WVRED);
    SetViewerName3D(viewer34, "Icosahedron");
    DisplayViewerName3D(hdc, viewer34, WVBLUE, 0);
    BeginDoubleBuffer3D (&hdc, viewer34);
    SelectViewer3D (viewer34);
    Scale3D (3, 3, 3);
    BrushColor (hdc, WVYELLOW);
    for (i = 0; i < 5*demo_type; i ++) {
	ClearViewer3D (hdc, viewer34, WVGRAY);
	Icosahedron (hdc, 1);
	Rotate3D (3, 'y');
	Translate3D (0.1, 0, 0);
	Rotate3D (6, 'z');
	UpdateBuffer3D (hdc, viewer34);
    }
    EndDoubleBuffer3D (&hdc, viewer34);
}

void	Heart2D (HDC hdc)
{
    DisplayViewerFrame2D (hdc, viewer21, WVRED);
    SetViewerName2D(viewer21, "2D NURBS curve");
    DisplayViewerName2D (hdc, viewer21, WVBLUE, 0);
    SelectViewer2D (viewer21);
    ClearViewer2D (hdc, viewer21, WVGRAY);
    Scale2D (2, 2);
    heart (hdc);
}

void	Display (HDC hdc)
{
        switch (demo_item) {
	  case 1:
	    Object2D (hdc);
	    break;
	  case 2:
	    ViewerMotion3D (hdc);
	    break;
	  case 3:
	    ObjectMotion3D (hdc);
	    break;
	  case 4:
	    ViewerZoom3D (hdc);
	    break;
	  case 5:
	    OrthoProject3D (hdc);
	    break;
	  case 6:
	    ViewerClip3D (hdc);
	    break;
	  case 7:
	    Heart2D (hdc);
	    break;
	  case 8:
	    RotateSpring (hdc);
	    break;
	  case 9:
	    RotateLogo (hdc);
	    break;
	  case 10:
	    RotateSurface (hdc);
	    break;
	  case 11:
	    RotateDodecahedron (hdc);
	    break;
	  case 12:
	    RotateIcosahedron (hdc);
	    break;
	  case 13:
	    Flag (hdc);
	    break;
	  default:
	    ViewerReset ();
	    demo_item = 0;
	    break;
	}
}

void	ProcessWindowPaint (HWND hwnd)
{
    PAINTSTRUCT	ps;
    HDC		hdc;

    hdc = BeginPaint (hwnd, &ps);
    if (demo_flag) {
        Display (hdc);
        if (demo_item == 12) {
	    InvalidateRect(hwnd, NULL, TRUE);
	} else if (demo_item) {
	    InvalidateRect(hwnd, NULL, FALSE);
        }
        demo_item++;
    }
    EndPaint (hwnd, &ps);
}

void	ProcessPrint (void)
{
    HDC		hPr;
    short	x1, y1, x2, y2;

    GetViewport2D (viewer22, &x1, &y1, &x2, &y2);
    hPr = GetPrinterDC ();
    if (hPr != NULL) {
	Escape (hPr, STARTDOC, 9, (LPSTR) "Graphics", 0L);
	SetViewport2D (viewer22, 10, 10, 1920, 580);
	SelectViewer2D (viewer22);
	DisplayViewerFrame2D (hPr, viewer22, WVBLACK);
	USFlag (hPr);
	SetViewport2D (viewer22, x1, y1, x2, y2);
	Escape (hPr, NEWFRAME, 0, 0L, 0L);
	Escape (hPr, ENDDOC, 0, 0L, 0L);
	DeleteDC(hPr);
    }
}

/****************************************************************************

    FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG)

    PURPOSE:  Processes messages

    MESSAGES:

	WM_COMMAND    - application menu (About dialog box)
	WM_DESTROY    - destroy window

    COMMENTS:

	To process the IDM_ABOUT message, call MakeProcInstance() to get the
	current instance address of the About() function.  Then call Dialog
	box which will create the box according to the information in your
	vlibdemo.rc file and turn control over to the About() function.	When
	it returns, free the intance address.

****************************************************************************/

long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;
unsigned message;
WORD wParam;
LONG lParam;
{
    FARPROC lpProcAbout;

    switch (message) {
	case WM_COMMAND:
	    switch (wParam) {
	      case IDM_EXIT:
		ExitGraphics();
	        PostQuitMessage(0);
		break;
	      case IDM_ABOUT:
		lpProcAbout = MakeProcInstance (About, hInst);
		DialogBox (hInst, "AboutBox", hWnd, lpProcAbout);
		FreeProcInstance (lpProcAbout);
		break;
	      case IDM_STOP:
	        demo_flag = 0;
		break;
              case IDM_CONTINUE:
	        demo_flag = demo_type;
		if (demo_item == 1)
			InvalidateRect(hWnd, NULL, TRUE);
		else
			InvalidateRect(hWnd, NULL, FALSE);
		break;
	      case IDM_SHORT:
		demo_type = 1;
	        break;
	      case IDM_LONG:
		demo_type = 10;
	        break;
	      case IDM_PRINT:
		ProcessPrint ();
		break;
	      case IDM_HELP:
		demo_flag = 0;
		WinHelp(hWnd, "visualib.hlp", HELP_INDEX, 0);
		break;
	      default:
	        return (DefWindowProc (hWnd, message, wParam, lParam));
	    }
            break;
	case WM_DESTROY:
	    ExitGraphics ();
	    PostQuitMessage (0);
	    break;

	case WM_PAINT:
	    ProcessWindowPaint (hWnd);
	    break;

	default:
	    return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (NULL);
}

/****************************************************************************

    FUNCTION: About (HWND, unsigned, WORD, LONG)

    PURPOSE:  Processes messages for "About" dialog box

    MESSAGES:

	WM_INITDIALOG - initialize dialog box
	WM_COMMAND    - Input received

    COMMENTS:

	No initialization is needed for this particular dialog box, but TRUE
	must be returned to Windows.

	Wait for user to click on "Ok" button, then close the dialog box.

****************************************************************************/

BOOL FAR PASCAL About (hDlg, message, wParam, lParam)
HWND hDlg;
unsigned message;
WORD wParam;
LONG lParam;
{
    switch (message) {
	case WM_INITDIALOG:
	    return (TRUE);

	case WM_COMMAND:
	    if (wParam == IDOK || wParam == IDCANCEL) {
		EndDialog (hDlg, TRUE);
		return (TRUE);
	    }
	    break;
    }
    return (FALSE);
}
