/*****************************************************************************
*   A Windows NT driver - Open GL graphics calls.			     *
*   The Pallete code was taken from the gengl open gl example in	     *
* /mstools/samples/opengl/demos/gengl. Ugly staff to create default pallete! *
******************************************************************************
* (C) Gershon Elber, Technion, Israel Institute of Technology                *
******************************************************************************
* Written by:  Gershon Elber				Ver 0.1, June 1994.  *
*****************************************************************************/

#include <windows.h>
#include <gl/gl.h>
#include <gl/glaux.h>

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "irit_sm.h"
#include "genmat.h"
#include "iritprsr.h"
#include "attribut.h"
#include "cagd_lib.h"
#include "symb_lib.h"
#include "iritgrap.h"
#include "irit_soc.h"
#include "wntdrvs.h"

/* Disable warnings for double <-> float conversions. */
#pragma warning(disable : 4244)
#pragma warning(disable : 4761)

/* Handle the positional as well as possible RGB attribute of a vertex. */
#define HANDLE_VERTEX(V) { char *Str; \
			   GLint Color[3]; \
			   if ((Str = AttrGetStrAttrib((V) -> Attrs, \
						       "RGB")) != NULL && \
			       sscanf(Str, "%d,%d,%d", \
				      &Color[0], &Color[1], &Color[2]) == 3) {\
			       glColor3b(Color[0] / 2, \
					 Color[1] / 2, \
					 Color[2] / 2); \
			   } \
			   glVertex3dv((V) -> Coord); \
			 }

static HPALETTE ghpalOld,
    ghPalette = (HPALETTE) 0;

static unsigned char ComponentFromIndex(int i, UINT NBits, UINT Shift);
static void CreateRGBPalette(HDC hDC);
static BOOL bSetupPixelFormat(HDC hDC);
static void SetColorIndex(int c);
static void SetColorRGB(int Color[3]);
static void ViewObject(IPObjectStruct *PObj, MatrixType Mat);

/*****************************************************************************
* DESCRIPTION:                                                               *
* The following three ugly routines (ComponentFromIndex, CreateRGBPalette    *
* and bSetupPixelFormat) were copied verbatim from the gengl example in      *
* /mstools/samples/opengl/demos/gengl. All they do is to figure out the      *
* color capability of the hardware and create a reasonablepallete for 8 bit  *
* per pixel devices to emulate true 24 bit colors. This should have been a   *
* service provided by the OS.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   i, NBits, Shift:   Dont ask me. I am not responsible for this mess	     *
*                                                                            *
* RETURN VALUE:                                                              *
*   unsigned:          Same!                                                 *
*****************************************************************************/
static unsigned char ComponentFromIndex(int i, UINT NBits, UINT Shift)
{
    static unsigned char
	ThreeTo8[8] = {
	    0, 0111>>1, 0222>>1, 0333>>1, 0444>>1, 0555>>1, 0666>>1, 0377
	},
	TwoTo8[4] = {
	    0, 0x55, 0xaa, 0xff
	},
	OneTo8[2] = {
	    0, 255
	};
    unsigned char
	Val = (unsigned char) (i >> Shift);

    switch (NBits) {
	case 1:
	    Val &= 0x1;
	    return OneTo8[Val];
	case 2:
	    Val &= 0x3;
	    return TwoTo8[Val];
	case 3:
	    Val &= 0x7;
	    return ThreeTo8[Val];
	default:
	    return 0;
    }
}

static void CreateRGBPalette(HDC hDC)
{
    PIXELFORMATDESCRIPTOR pfd;
    LOGPALETTE *pPal;
    int n, i;
    static int defaultOverride[13] = {
	0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91
    };
    static PALETTEENTRY defaultPalEntry[20] = {
	{ 0,   0,   0,    0 },
	{ 0x80,0,   0,    0 },
	{ 0,   0x80,0,    0 },
	{ 0x80,0x80,0,    0 },
	{ 0,   0,   0x80, 0 },
	{ 0x80,0,   0x80, 0 },
	{ 0,   0x80,0x80, 0 },
	{ 0xC0,0xC0,0xC0, 0 },

	{ 192, 220, 192,  0 },
	{ 166, 202, 240,  0 },
	{ 255, 251, 240,  0 },
	{ 160, 160, 164,  0 },

	{ 0x80,0x80,0x80, 0 },
	{ 0xFF,0,   0,    0 },
	{ 0,   0xFF,0,    0 },
	{ 0xFF,0xFF,0,    0 },
	{ 0,   0,   0xFF, 0 },
	{ 0xFF,0,   0xFF, 0 },
	{ 0,   0xFF,0xFF, 0 },
	{ 0xFF,0xFF,0xFF, 0 }
    };

    n = GetPixelFormat(hDC);
    DescribePixelFormat(hDC, n, sizeof(PIXELFORMATDESCRIPTOR), &pfd);

    if (pfd.dwFlags & PFD_NEED_PALETTE) {
        n = 1 << pfd.cColorBits;
        pPal = (PLOGPALETTE) LocalAlloc(LMEM_FIXED, sizeof(LOGPALETTE) +
                n * sizeof(PALETTEENTRY));
        pPal -> palVersion = 0x300;
        pPal -> palNumEntries = n;
        for (i=0; i<n; i++) {
            pPal -> palPalEntry[i].peRed =
                    ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift);
            pPal -> palPalEntry[i].peGreen =
                    ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift);
            pPal -> palPalEntry[i].peBlue =
                    ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift);
            pPal -> palPalEntry[i].peFlags = 0;
        }

        /* Fix up the palette to include the default GDI palette. */
        if ((pfd.cColorBits == 8)                           &&
            (pfd.cRedBits   == 3) && (pfd.cRedShift   == 0) &&
            (pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) &&
            (pfd.cBlueBits  == 2) && (pfd.cBlueShift  == 6)) {
            for (i = 1 ; i <= 12 ; i++)
                pPal -> palPalEntry[defaultOverride[i]] = defaultPalEntry[i];
        }

        ghPalette = CreatePalette(pPal);
        LocalFree(pPal);

        ghpalOld = SelectPalette(hDC, ghPalette, FALSE);
        n = RealizePalette(hDC);
    }
}

static BOOL bSetupPixelFormat(HDC hDC)
{
    static PIXELFORMATDESCRIPTOR pfd = {
	sizeof(PIXELFORMATDESCRIPTOR),	/* Size of this pfd. */
	1,				/* Version number. */
	PFD_DRAW_TO_WINDOW |		/* Support window. */
	  PFD_SUPPORT_OPENGL |		/* Support OpenGL. */
	  PFD_DOUBLEBUFFER,		/* Double buffered. */
	PFD_TYPE_RGBA,			/* RGBA type. */
	24,				/* 24-bit color depth. */
	0, 0, 0, 0, 0, 0,		/* Color bits ignored. */
	0,				/* No alpha buffer. */
	0,				/* Shift bit ignored. */
	0,				/* No accumulation buffer. */
	0, 0, 0, 0, 			/* Accum bits ignored. */
	32,				/* 32-bit z-buffer. */
	0,				/* No stencil buffer. */
	0,				/* No auxiliary buffer. */
	PFD_MAIN_PLANE,			/* Main layer. */
	0,				/* Reserved. */
	0, 0, 0				/* Layer masks ignored. */
    };
    int PixelFormat, i;

    if ((PixelFormat = ChoosePixelFormat(hDC, &pfd)) == 0) {
	i = GetLastError();
        MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK);
        return FALSE;
    }

    if (SetPixelFormat(hDC, PixelFormat, &pfd) == FALSE) {
	i = GetLastError();
        MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK);
        return FALSE;
    }

    CreateRGBPalette(hDC);

    return TRUE;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Draw a single Point/Vector object using current modes and transformations. M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     A point/vector object to draw.                                 M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGDrawPtVec                                                              M
*****************************************************************************/
void IGDrawPtVec(IPObjectStruct *PObj)
{
    int i;
    PointType Ends[6], Zero;
    RealType
	*Pt = PObj -> U.Pt;

    IGSetColorObj(PObj);

    for (i = 0; i < 6; i++)
	PT_COPY(Ends[i], Pt);

    Ends[0][0] -= IGGlblPointWidth;
    Ends[1][0] += IGGlblPointWidth;
    Ends[2][1] -= IGGlblPointWidth;
    Ends[3][1] += IGGlblPointWidth;
    Ends[4][2] -= IGGlblPointWidth;
    Ends[5][2] += IGGlblPointWidth;

    for (i = 0; i < 6; i += 2) {
	glBegin(GL_LINES);
	glVertex3dv(Ends[i]);
	glVertex3dv(Ends[i+1]);
	glEnd();
    }

    if (IP_IS_VEC_OBJ(PObj)) {
	glBegin(GL_LINES);
	glVertex3dv(Pt);
	Zero[0] = Zero[1] = Zero[2] = 0.0;
	glVertex3dv(Zero);
	glEnd();
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Draw a single Poly object using current modes and transformations.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:     A poly object to draw.                                         M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGDrawPoly                                                               M
*****************************************************************************/
void IGDrawPoly(IPObjectStruct *PObj)
{
    IPVertexStruct *V;
    IPPolygonStruct
	*Pl = PObj -> U.Pl;

    IGSetColorObj(PObj);

    if (IP_IS_POLYLINE_OBJ(PObj)) {
	for (; Pl != NULL; Pl = Pl -> Pnext) {
	    glBegin(GL_LINE_STRIP);
	    for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {
		HANDLE_VERTEX(V);
	    }
	    glEnd();
	}
    }
    else if (IP_IS_POINTLIST_OBJ(PObj)) {
	for (; Pl != NULL; Pl = Pl -> Pnext) {
	    for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {
		int i;
		PointType Ends[6];
		RealType
		    *Pt = V -> Coord;

		for (i = 0; i < 6; i++)
		    PT_COPY(Ends[i], Pt);

		Ends[0][0] -= IGGlblPointWidth;
		Ends[1][0] += IGGlblPointWidth;
		Ends[2][1] -= IGGlblPointWidth;
		Ends[3][1] += IGGlblPointWidth;
		Ends[4][2] -= IGGlblPointWidth;
		Ends[5][2] += IGGlblPointWidth;

		for (i = 0; i < 6; i += 2) {
		    glBegin(GL_LINES);
		    glVertex3dv(Ends[i]);
		    glVertex3dv(Ends[i+1]);
		    glEnd();
		}
	    }
	}
    }
    else if (IP_IS_POLYGON_OBJ(PObj)) {
	int i, j,
	    NumOfVertices;
	PointType PNormal, VNormal;

	for (; Pl != NULL; Pl = Pl -> Pnext) {
	    if (IGGlblDrawPNormal) {
		NumOfVertices = 0;
		PNormal[0] = PNormal[1] = PNormal[2] = 0.0;
	    }

	    if (IGGlblDrawSolid) {
		glBegin(GL_POLYGON);
		for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {

		    switch (IGGlblShadingModel) {
			case IG_SHADING_NONE:
			    break;
			case IG_SHADING_FLAT:
			    glNormal3dv(Pl -> Plane);
			    break;
			case IG_SHADING_GOURAUD:
			case IG_SHADING_PHONG:
			    glNormal3dv(V -> Normal);
			    break;
		    }
		    HANDLE_VERTEX(V);

		    if (IGGlblDrawPNormal) {
			for (j = 0; j < 3; j++)
			    PNormal[j] += V -> Coord[j];
			NumOfVertices++;
		    }
		}
		glEnd();
	    }
	    else {
		glBegin(GL_LINE_STRIP);
		for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {
		    HANDLE_VERTEX(V);
		    if (IP_IS_INTERNAL_VRTX(V) && !IGGlblDrawInternal) {
			glEnd();
			glBegin(GL_LINE_STRIP);
		    }

		    if (IGGlblDrawPNormal) {
			for (j = 0; j < 3; j++)
			    PNormal[j] += V -> Coord[j];
			NumOfVertices++;
		    }
		}
		HANDLE_VERTEX(Pl -> PVertex);
		glEnd();
	    }

	    if (IGGlblDrawPNormal && IP_HAS_PLANE_POLY(Pl)) {
		glBegin(GL_LINES);
		for (i = 0; i < 3; i++)
		    PNormal[i] /= NumOfVertices;
		glVertex3dv(PNormal);
		for (i = 0; i < 3; i++)
		    PNormal[i] += Pl -> Plane[i] * IGGlblNormalLen;
		glVertex3dv(PNormal);
		glEnd();
	    }

	    if (IGGlblDrawVNormal) {
		for (V = Pl -> PVertex; V != NULL; V = V -> Pnext) {
		    if (IP_HAS_NORMAL_VRTX(V)) {
			for (j = 0; j < 3; j++)
			    VNormal[j] = V -> Coord[j] +
				         V -> Normal[j] * IGGlblNormalLen;
			glBegin(GL_LINES);
			glVertex3dv(V -> Coord);
			glVertex3dv(VNormal);
			glEnd();
		    }
		}
	    }
	}
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Sets the color of an object according to its color/rgb attributes.	     M
*   If object has an RGB attribute it will be used. Otherwise, if the object M
* has a COLOR attribute it will use. Otherwise, WHITE will be used.	     M
*                                                                            *
* PARAMETERS:                                                                M
*   PObj:      To set the drawing color to its color.                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGSetColorObj                                                            M
*****************************************************************************/
void IGSetColorObj(IPObjectStruct *PObj)
{
    int c, Color[3];

    if (AttrGetObjectRGBColor(PObj, &Color[0], &Color[1], &Color[2])) {
	SetColorRGB(Color);
    }
    else if ((c = AttrGetObjectColor(PObj)) != IP_ATTR_NO_COLOR) {
	SetColorIndex(c);
    }
    else {
	/* Use white as default color: */
	SetColorIndex(IG_IRIT_WHITE);
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Sets the line width to draw the given object, in pixels.		     M
*                                                                            *
* PARAMETERS:                                                                M
*   Width:    In pixels of lines to draw with.                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGSetWidthObj                                                            M
*****************************************************************************/
void IGSetWidthObj(int Width)
{
    glLineWidth(IGGlblLineWidth);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Sets the color according to the given color index.		    	     *
*                                                                            *
* PARAMETERS:                                                                *
*   color:     Index of color to use. Must be between 0 and IG_MAX_COLOR.    *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void SetColorIndex(int c)
{
    int Color[3];
    static short Colors[IG_MAX_COLOR + 1][3] = {
	{ 0,   0,   0   },  /* 0. BLACK */
	{ 0,   0,   170 },  /* 1. BLUE */
	{ 0,   170, 0   },  /* 2. GREEN */
	{ 0,   170, 170 },  /* 3. CYAN */
	{ 170, 0,   0   },  /* 4. RED */
	{ 170, 0,   170 },  /* 5. MAGENTA */
	{ 170, 170, 0   },  /* 6. BROWN */
	{ 170, 170, 170 },  /* 7. LIGHTGREY */
	{ 85,  85,  85  },  /* 8. DARKGRAY */
	{ 85,  85,  255 },  /* 9. LIGHTBLUE */
	{ 85,  255, 85  },  /* 10. LIGHTGREEN */
	{ 85,  255, 255 },  /* 11. LIGHTCYAN */
	{ 255, 85,  85  },  /* 12. LIGHTRED */
	{ 255, 85,  255 },  /* 13. LIGHTMAGENTA */
	{ 255, 255, 85  },  /* 14. YELLOW */
	{ 255, 255, 255 }   /* 15. WHITE */
    };

    if (c < 0 || c > IG_MAX_COLOR)
        c = IG_IRIT_WHITE;

    Color[0] = Colors[c][0];
    Color[1] = Colors[c][1];
    Color[2] = Colors[c][2];

    SetColorRGB(Color);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Sets the color according to the given RGB values.			     *
*                                                                            *
* PARAMETERS:                                                                *
*   Color:      An RGB vector of integer values between 0 and 255.           *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void SetColorRGB(int Color[3])
{
    int i;

    if (IGGlblDrawSolid) {
	GLfloat MatAmbient[4], MatDiffuse[4], MatSpecular[4];
	static GLfloat
	    MatShininess[] = { 50.0 };

	for (i = 0; i < 3; i++) {
	    MatAmbient[i] = 0.2 * Color[0] / 255.0;
	    MatDiffuse[i] = 0.4 * Color[i] / 255.0;
	    MatSpecular[i] = Color[i] / 255.0;
	}
	MatAmbient[3] = MatDiffuse[3] = MatSpecular[3] = 1.0;

	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, MatAmbient);
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MatDiffuse);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MatSpecular);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, MatShininess);
    }
    else
	glColor3f(Color[0] / 255.0, Color[1] / 255.0, Color[2] / 255.0);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Redraw the viewing window.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   None	                                                             M
*                                                                            *
* RETURN VALUE:                                                              M
*   void	                                                             M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGRedrawViewWindow                                                       M
*****************************************************************************/
void IGRedrawViewWindow(void)
{
    IGPredefinedAnimation();

    InvalidateRect(IGhWndView, NULL, FALSE);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Redraw the viewing window.						     M
*                                                                            *
* PARAMETERS:                                                                M
*   hWnd:     Handle on window to draw to.                                   M
*   wMsg:     Event to handle.                                               M
*   wParam:   Some parameters of event.                                      M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:      Window's condition.                                            M
*                                                                            *
* KEYWORDS:                                                                  M
*   RedrawViewWindow                                                         M
*****************************************************************************/
int RedrawViewWindow(HWND hWnd, UINT wMsg, WPARAM wParam)
{
    MatrixType IritView;
    PAINTSTRUCT ps;

    switch (wMsg) {
	case WM_CREATE:
	    {
		HDC hDC;
		HGLRC hRC;

		hDC = GetDC(hWnd);
		bSetupPixelFormat(hDC);

		hRC = wglCreateContext(hDC);
		wglMakeCurrent(hDC, hRC);

		glClearColor(IGGlblBackGroundColor[0] / 255.0,
			     IGGlblBackGroundColor[1] / 255.0,
			     IGGlblBackGroundColor[2] / 255.0,
			     1.0);
		glClearDepth(1.0);

		glMatrixMode(GL_MODELVIEW);
	    }
	    break;
	case WM_PAINT:
	    if (IGCurrenthDC = BeginPaint(hWnd, &ps)) {
	        RECT rect;
		static int
		    FirstTimeSolid = TRUE;

		GetClientRect(hWnd, &rect);

		if (rect.right > rect.bottom) {
		    int i = (rect.right - rect.bottom) / 2;

		    glViewport(0, -i, rect.right, rect.right);
		}
		else {
		    int i = (rect.bottom - rect.right) / 2;

		    glViewport(-i, 0, rect.bottom, rect.bottom);
		}

		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();

		glDrawBuffer(IGGlblDoDoubleBuffer ? GL_BACK : GL_FRONT);

		/* Clear viewing area. */
		glClear(GL_COLOR_BUFFER_BIT |
			(IGGlblDrawSolid ? GL_DEPTH_BUFFER_BIT : 0));

		/* activate zbuffer only if we are in solid drawing mode. */
		if (IGGlblDrawSolid) {
		    if (FirstTimeSolid) {
			static GLfloat
			    TwoSides[1] = { 1.0 },
			    LightPositions[4][4] =
			               { {   1.0,   2.0,  10.0, 0.0 },
					 { -15.0,  -1.0 , -3.0, 0.0 },
					 {  -5.0,  -1.0, -10.0, 0.0 },
					 {   5.0, -10.0,   1.0, 0.0 } },
			    LightAmbient[] = { 0.1, 0.1, 0.1, 1.0 },
			    LightDiffuse[] = { 0.5, 0.5, 0.5, 1.0 },
			    LightSpecular[] = { 3.0, 3.0, 3.0, 1.0 },
			    LModelAmbient[] = { 0.2, 0.2, 0.2, 1.0 };
			int i;

			for (i = 0; i < 4; i++)
			    LightPositions[0][i] = IGGlblLightSrcPos[i];

			for (i = 0; i < 4; i++) {
			    glLightfv(GL_LIGHT0 + i, GL_POSITION,
				      LightPositions[i]);
			    glLightfv(GL_LIGHT0 + i, GL_AMBIENT,
				      LightAmbient);
			    glLightfv(GL_LIGHT0 + i, GL_DIFFUSE,
				      LightDiffuse);
			    glLightfv(GL_LIGHT0 + i, GL_SPECULAR,
				      LightSpecular);
			}
 
			glLightModelfv(GL_LIGHT_MODEL_AMBIENT, LModelAmbient);
			glDepthFunc(GL_GREATER);
			glClearDepth(0.0);

			FirstTimeSolid = FALSE;
			
			for (i = 0; i < 4; i++)
			    glEnable(GL_LIGHT0 + i);

			glDisable(GL_FOG);
		    }

		    glEnable(GL_LIGHTING);
		    glEnable(GL_DEPTH_TEST);
		}
		else {
		    int i;
		    GLfloat fogColor[4];

		    FirstTimeSolid = TRUE;

		    for (i = 0; i < 3; i++)
			fogColor[i] = (float) IGGlblBackGroundColor[i] / 255.0;
		    fogColor[3] = (float) 1.0;

		    glFogi(GL_FOG_MODE, GL_LINEAR);
		    glHint(GL_FOG_HINT, GL_NICEST);
		    glFogf(GL_FOG_START, (float) IGGlblZMinClip);
		    glFogf(GL_FOG_END, (float) IGGlblZMaxClip);
		    glFogfv(GL_FOG_COLOR, fogColor);

		    if (IGGlblDepthCue)
			glEnable(GL_FOG);
		    else
			glDisable(GL_FOG);

		    for (i = 0; i < 4; i++)
			glDisable(GL_LIGHT0 + i);

		    glDisable(GL_LIGHTING);
		    glDisable(GL_DEPTH_TEST);
		}

		switch (IGGlblViewMode) {       /* Update the current view. */
		    case IG_VIEW_ORTHOGRAPHIC:
		        GEN_COPY(IritView, IritPrsrViewMat,
				 sizeof(MatrixType));
			break;
		    case IG_VIEW_PERSPECTIVE:
			MatMultTwo4by4(IritView, IritPrsrViewMat,
				       IritPrsrPrspMat);
			break;
		}

		IPTraverseObjListHierarchy(IGGlblDisplayList,
					   IritView, ViewObject);

		glFlush();

		if (IGGlblDoDoubleBuffer) {
		    HDC hDC2 = wglGetCurrentDC();

		    SwapBuffers(hDC2);
		}

		EndPaint(hWnd, &ps);
	    }
	    break;
	case WM_QUERYNEWPALETTE:
	    {
		HDC     hDC;

		if (ghPalette) {
		    hDC = GetDC(hWnd);

		    ghpalOld = SelectPalette(hDC, ghPalette, FALSE);
		    RealizePalette(hDC);

		    InvalidateRect(hWnd, NULL, TRUE);
		    UpdateWindow(hWnd);

		    if (ghpalOld)
			SelectPalette(hDC, ghpalOld, FALSE);

		    ReleaseDC(hWnd, hDC);

		    return TRUE;
		}

		return FALSE;
	    }
	case WM_PALETTECHANGED:
	    {
		HDC	 hDC;

		if (ghPalette) {
		    
		    if (wParam != (WPARAM) hWnd)
		    {
			hDC = GetDC(hWnd);

			ghpalOld = SelectPalette(hDC, ghPalette, FALSE);
			RealizePalette(hDC);

			UpdateColors(hDC);

			if (ghpalOld)
			    SelectPalette(hDC, ghpalOld, FALSE);

			ReleaseDC(hWnd, hDC);
		    }
		}
		break;
	    }
    }

    return FALSE;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
*   Call back function of the IPTraverseObjListHierarchy above.              *
*                                                                            *
* PARAMETERS:                                                                *
*   PObj:      Object to display.                                            *
*   Mat:       Viewing matrix of object.                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void ViewObject(IPObjectStruct *PObj, MatrixType Mat)
{
    int i, j;
    GLdouble CrntView[16];

    for (i = 0; i < 4; i++)
        for (j = 0; j < 4; j++)
	    CrntView[i * 4 + j] = Mat[i][j];

    if (IGGlblDrawSolid) {
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
        glMatrixMode(GL_PROJECTION);
    }
    else {
        glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode(GL_MODELVIEW);
    }
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, IGGlblZMaxClip, IGGlblZMinClip);
    glMultMatrixd(CrntView);
    glMatrixMode(GL_MODELVIEW);

    IGDrawObject(PObj);
}
