/*****************************************************************************
*   Determines visibility of curves using SGI's Z buffer.		     *
*									     *
* Written by:  Gershon Elber				Ver 0.1, June 1993.  *
*****************************************************************************/

#include <gl/gl.h>
#include <gl/device.h>

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#ifdef _AIX
#    include <fcntl.h>
#else
#    include <sys/fcntl.h>
#endif
#include "irit_sm.h"
#include "genmat.h"
#include "iritprsr.h"
#include "allocate.h"
#include "attribut.h"
#include "ip_cnvrt.h"
#include "cagd_lib.h"
#include "symb_lib.h"
#include "iritgrap.h"
#include "xgldrvs.h"
#include "irit_soc.h"

/* Interactive menu setup structure: */
#define INTERACT_NUM_OF_STRINGS		4
#define INTERACT_NUM_OF_SUB_WNDWS	16

typedef struct InteractString {
    RealType X, Y;
    int Color;
    char *Str;
} InteractString;
typedef struct InteractSubWindow {
    RealType X, Y;					   /* Center points. */
    int Color;
    IGGraphicEventType Event;
    int TextInside; /* If TRUE, Str will be in window, otherwise left to it. */
    char *Str;
} InteractSubWindow;
typedef struct InteractWindowStruct {	 /* The interactive menu structures. */
    /* Rotate, Translate, Scale strings: */
    InteractString Strings[INTERACT_NUM_OF_STRINGS];
    InteractSubWindow SubWindows[INTERACT_NUM_OF_SUB_WNDWS];
} InteractWindowStruct;

#define INTERACT_SUB_WINDOW_WIDTH  0.8		 /* Relative to window size. */
#define INTERACT_SUB_WINDOW_HEIGHT 0.04

static int
    GlblStateMenu = 0;
static long
    TransWinID = 0,
    TransWinWidth = 100,
    TransWinWidth2 = 50,
    TransWinHeight = 100,
    TransWinLow = 0,
    TransWinLeft = 0;
static RealType
    GlblWidthScale = 0.1;

/* Interactive mode menu set up structure is define below: */
static InteractWindowStruct InteractMenu = {
    { { 0.5, 0.81, IG_IRIT_RED,		"Rotate" },
      { 0.5, 0.65, IG_IRIT_GREEN,	"Translate" },
      { 0.5, 0.49, IG_IRIT_CYAN,	"Scale" },
      { 0.5, 0.41, IG_IRIT_LIGHTGREEN,	"Clip Plane" },
    },
    { { 0.5, 0.93, IG_IRIT_YELLOW, IG_EVENT_SCR_OBJ_TGL,	TRUE,  "Screen Coords." },
      { 0.5, 0.87, IG_IRIT_BLUE,   IG_EVENT_PERS_ORTHO_TGL,TRUE,  "Perspective" },
      { 0.5, 0.83, IG_IRIT_BLUE,   IG_EVENT_PERS_ORTHO_Z,	FALSE, "Z" },
      { 0.5, 0.75, IG_IRIT_RED,    IG_EVENT_ROTATE_X,		FALSE, "X" }, /* Rot */
      { 0.5, 0.71, IG_IRIT_RED,    IG_EVENT_ROTATE_Y,		FALSE, "Y" },
      { 0.5, 0.67, IG_IRIT_RED,    IG_EVENT_ROTATE_Z,		FALSE, "Z" },
      { 0.5, 0.59, IG_IRIT_GREEN,  IG_EVENT_TRANSLATE_X,	FALSE, "X" }, /* Trans */
      { 0.5, 0.55, IG_IRIT_GREEN,  IG_EVENT_TRANSLATE_Y,	FALSE, "Y" },
      { 0.5, 0.51, IG_IRIT_GREEN,  IG_EVENT_TRANSLATE_Z,	FALSE, "Z" },
      { 0.5, 0.43, IG_IRIT_CYAN,   IG_EVENT_SCALE,		FALSE, "" },  /* Scale */
      { 0.5, 0.35, IG_IRIT_LIGHTGREEN, IG_EVENT_NEAR_CLIP,	FALSE,  "" },
      { 0.5, 0.31, IG_IRIT_LIGHTGREEN, IG_EVENT_FAR_CLIP,	FALSE,  "" },

      { 0.5, 0.20, IG_IRIT_YELLOW, IG_EVENT_SAVE_MATRIX,	TRUE,  "Save Matrix" },
      { 0.5, 0.13, IG_IRIT_YELLOW, IG_EVENT_PUSH_MATRIX,	TRUE,  "Push Matrix" },
      { 0.5, 0.09, IG_IRIT_YELLOW, IG_EVENT_POP_MATRIX,		TRUE,  "Pop Matrix" },
      { 0.5, 0.03, IG_IRIT_WHITE,  IG_EVENT_QUIT,		TRUE,  "Quit" },
    }
};

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 */
};

static void ClearViewArea(void);
static void SetColorIndex(int color);
static void SetColorRGB(int Color[3]);
static void SetTransformWindow(void);
static void RedrawTransformWindow(void);
static IGGraphicEventType GetGraphicEvent(RealType *ChangeFactor);
static void DrawText(char *Str, long PosX, long PosY);

/*****************************************************************************
* DESCRIPTION:                                                               M
* Main module of zbufcrvs (modified from xgldrvs).	          	     M
*                                                                            *
* PARAMETERS:                                                                M
*   argc, argv:  Command line.                                               M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:         Exit code.                                                  M
*                                                                            *
* KEYWORDS:                                                                  M
*   main                                                                     M
*****************************************************************************/
void main(int argc, char **argv)
{
    RealType ChangeFactor;
    IGGraphicEventType Event;
    IPObjectStruct *PObjects, *PObj;
    Matrix CrntView;
    int i, j, k;

    /* Default here is not to cache polygons and polylines. */
    IGGlblCacheGeom = FALSE;
    IGGlblDrawSolid = TRUE;
    IGGlblDoDoubleBuffer = FALSE;
    IGGlblTransPrefPos = "   0,  220, 520, 1024",
    IGGlblViewPrefPos =  " 260, 1280,   0, 1024",
    IGGlblAntiAliasing = FALSE;

    IGConfigureGlobals("zbufcrvs", argc, argv);

    GlblWidthScale = IGGlblNormalLen / 1000.0;

    SetViewWindow(argc, argv);
    SetTransformWindow();

    qdevice(LEFTMOUSE);
    qdevice(MIDDLEMOUSE);
    qdevice(RIGHTMOUSE);

    /* The default drawing window is the view window. */
    winset(ViewWinID);

    setbell(1);						   /* Make it short. */

    IGCreateStateMenu();

    ClearViewArea();

    if (IGGlblViewMode == IG_VIEW_PERSPECTIVE) {
	for (i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++) {
		CrntView[i][j] = 0;
		for (k = 0; k < 4; k++)
		    CrntView[i][j] += IritPrsrViewMat[i][k] *
				      IritPrsrPrspMat[k][j];
	    }
    }
    else {
	for (i = 0; i < 4; i++)
	    for (j = 0; j < 4; j++)
		CrntView[i][j] = IritPrsrViewMat[i][j];
    }
    loadmatrix(CrntView);

    /* First, render all freeforms into the Z-buffer. */
    for (PObj = IGGlblDisplayList; PObj != NULL; PObj = PObj -> Pnext) {
	if (IP_IS_GEOM_OBJ(PObj) && IP_IS_SRF_OBJ(PObj)) {
	    AttrSetObjectRGBColor(PObj, 255, 0, 0);
	    AttrSetObjectColor(PObj, IG_IRIT_RED);
	    IGDrawObject(PObj);
	}
    }

    /* Now, for each curve, determine and dump only visible portion. */
    for (PObj = IGGlblDisplayList; PObj != NULL; PObj = PObj -> Pnext) {
	if (IP_IS_CRV_OBJ(PObj)) {
	    if (AttrGetObjectObjAttrib(PObj, "VarWidth") != NULL)
		AttrSetObjectRealAttrib(PObj, "_WidthScale", GlblWidthScale);

	    IGDrawObject(PObj);
	}
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Clears the viewing area.						     *
*                                                                            *
* PARAMETERS:                                                                *
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void ClearViewArea(void)
{
    SetColorRGB(IGGlblBackGroundColor);
    clear();
    mmode(MVIEWING);

    if (APX_EQ(IGGlblZMinClip, IGGlblZMaxClip))
        IGGlblZMaxClip += EPSILON;
    ortho(-1.0, 1.0, -1.0, 1.0, IGGlblZMinClip, IGGlblZMaxClip);

    if (winget() == ViewWinID) {
	/* activate zbuffer only if we are in solid drawing mode. */
	if (IGGlblDrawSolid) {
	    /* Define necessary staff for Lighting. */
	    lmbind(MATERIAL, 1);
	    lmbind(LMODEL, 1);
	    lmbind(LIGHT1, 1);
	    lmbind(LIGHT2, 2);

	    zbuffer(TRUE);
	    zclear();
	}
	else {
	    zbuffer(FALSE);
	}
    }
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Optionally construct a state pop up menu for the driver, if has one.       M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGCreateStateMenu                                                        M
*****************************************************************************/
void IGCreateStateMenu(void)
{
    if (GlblStateMenu) 
        freepup(GlblStateMenu);

    GlblStateMenu = newpup();

    addtopup(GlblStateMenu, " Set Up %t", 0);
    addtopup(GlblStateMenu, "Oops!%l", 0);
    addtopup(GlblStateMenu, "More Sensitive", 0);
    addtopup(GlblStateMenu, "Less Sensitive%l", 0);
    addtopup(GlblStateMenu, IGGlblTransformMode == IG_TRANS_SCREEN ?
				"Screen Trans." : "Object Trans", 0);
    addtopup(GlblStateMenu, IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
				"Perspective" : "Orthographic", 0);
    addtopup(GlblStateMenu,
	     IGGlblDepthCue ? "Depth Cue" : "No Depth Cue", 0);
    addtopup(GlblStateMenu,
	     IGGlblCacheGeom ? "Cache Geom" : "No Geom Cache", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawSolid ? "Draw Solid" : "Draw Wireframe", 0);
    addtopup(GlblStateMenu,
	     IGGlblBackFaceCull ? "Cull Back Face" : "No Cull Back Face", 0);
    addtopup(GlblStateMenu,
	     IGGlblDoDoubleBuffer ? "Double Buffer" : "Single Buffer", 0);
    addtopup(GlblStateMenu,
	     IGGlblAntiAliasing ? "Anti Aliasing" : "No Anti Aliasing", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawInternal ? "Draw Internal Edges" : "No Internal Edges", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawVNormal ? "Draw Vrtx Normals" :  "No Vrtx Normals", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawPNormal ? "Draw Poly Normals" :  "No Poly Normals", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawSurfaceMesh ? "Draw Surface Mesh" : "No Surface Mesh", 0);
    addtopup(GlblStateMenu,
	     IGGlblDrawSurfacePoly ? "Surface Polygons" : "Surface Isolines", 0);
    addtopup(GlblStateMenu,
	     IGGlblFourPerFlat ? "Four Per Flat%l" : "Two Per Flat%l", 0);
    addtopup(GlblStateMenu, "More Isolines", 0);
    addtopup(GlblStateMenu, "Less Isolines%l", 0);
    addtopup(GlblStateMenu, "Finer approx.", 0);
    addtopup(GlblStateMenu, "Coarser approx.%l", 0);
    addtopup(GlblStateMenu, "Longer Vectors.", 0);
    addtopup(GlblStateMenu, "Shorter Vectors", 0);
    addtopup(GlblStateMenu, "Wider Lines", 0);
    addtopup(GlblStateMenu, "Narrow Lines", 0);
    addtopup(GlblStateMenu, "Front View", 0);
    addtopup(GlblStateMenu, "Size View", 0);
    addtopup(GlblStateMenu, "Top View", 0);
    addtopup(GlblStateMenu, "Isometry View", 0);
    addtopup(GlblStateMenu, "Clear View Area", 0);
}

/*****************************************************************************
* 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 color)
{
    int Color[3];

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

    Color[0] = Colors[color][0];
    Color[1] = Colors[color][1];
    Color[2] = Colors[color][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])
{
    c3i((long *) Color);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Sets up and draw a transformation window.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void SetTransformWindow(void)
{
    long PrefPos[4];

#ifndef _AIX
    foreground();
#endif

    if (sscanf(IGGlblTransPrefPos, "%ld,%ld,%ld,%ld",
	       &PrefPos[0], &PrefPos[1], &PrefPos[2], &PrefPos[3]) == 4)
	prefposition(PrefPos[0], PrefPos[1], PrefPos[2], PrefPos[3]);
    else if (sscanf(IGGlblTransPrefPos, "%ld,%ld",
		    &PrefPos[0], &PrefPos[1]) == 2)
	prefsize(PrefPos[0], PrefPos[1]);
    winopen("Poly3dTrans");
    winconstraints();
    wintitle("xGLdrvs");
    RGBmode();
    gconfig();
    getorigin(&TransWinLeft, &TransWinLow);
    getsize(&TransWinWidth, &TransWinHeight);
    TransWinWidth2 = TransWinWidth / 2;
    TransWinID = winget();

    SetColorRGB(IGGlblBackGroundColor);
    clear();

    /* This is wierd. without the sleep the gl get mixed up between the two  */
    /* windows. If you have any idea why, let me know...		     */
    sleep(1);
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Redraws the transformation window.					     *
*                                                                            *
* PARAMETERS:                                                                *
*   None                                                                     *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*                                                                            *
* KEYWORDS:                                                                  *
*   RedrawTransformWindow                                                    *
*****************************************************************************/
static void RedrawTransformWindow(void)
{
    int i;
    long SubTransPosX, SubTransPosY, SubTransWidth, SubTransHeight;

    /* Make sure the menu is consistent with internatal data. */
    InteractMenu.SubWindows[0].Str =
	IGGlblTransformMode == IG_TRANS_OBJECT ? "Object Coords."
					     : "Screen Coords.";
    InteractMenu.SubWindows[1].Str =
	IGGlblViewMode == IG_VIEW_PERSPECTIVE ? "Perspective" : "Orthographic";

    winset(TransWinID);                /* Draw in the transformation window. */

    SubTransWidth = (int) (TransWinWidth * INTERACT_SUB_WINDOW_WIDTH);
    SubTransHeight = (int) (TransWinHeight * INTERACT_SUB_WINDOW_HEIGHT);
    SubTransPosX = (TransWinWidth - SubTransWidth) / 2;

    SetColorRGB(IGGlblBackGroundColor);
    clear();

    for (i = 0; i < INTERACT_NUM_OF_SUB_WNDWS; i++) {
	SetColorIndex(InteractMenu.SubWindows[i].Color);
	SubTransPosY = (int) (TransWinHeight * InteractMenu.SubWindows[i].Y);

	move2i(SubTransPosX, SubTransPosY);
	draw2i(SubTransPosX + SubTransWidth, SubTransPosY);
	draw2i(SubTransPosX + SubTransWidth, SubTransPosY + SubTransHeight);
	draw2i(SubTransPosX, SubTransPosY + SubTransHeight);
	draw2i(SubTransPosX, SubTransPosY);
	if (InteractMenu.SubWindows[i].TextInside) {
	    DrawText(InteractMenu.SubWindows[i].Str,
		     TransWinWidth / 2,
		     SubTransPosY + SubTransHeight / 2);
	}
	else {
	    DrawText(InteractMenu.SubWindows[i].Str,
		     (TransWinWidth - SubTransWidth) / 3,
		     SubTransPosY + SubTransHeight / 2);
	    move2i(SubTransPosX + SubTransWidth / 2, SubTransPosY);
	    draw2i(SubTransPosX + SubTransWidth / 2,
		   SubTransPosY + SubTransHeight);
	}
    }

    for (i = 0; i < INTERACT_NUM_OF_STRINGS; i++) {
	SetColorIndex(InteractMenu.Strings[i].Color);
	DrawText(InteractMenu.Strings[i].Str,
		 (int) (InteractMenu.Strings[i].X * TransWinWidth),
		 (int) (InteractMenu.Strings[i].Y * TransWinHeight));
    }

    winset(ViewWinID);             /* Go back to the default drawing window. */
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Handles input events                                                       *
*                                                                            *
* PARAMETERS:                                                                *
*   ChangeFactor:        A continuous numeric value between -1 and 1. This   *
*			 value will be used to set amount of event such as   *
*			 rotation or translation.			     *
*                                                                            *
* RETURN VALUE:                                                              *
*   IGGraphicEventType:  Type of new event.                                  *
*****************************************************************************/
static IGGraphicEventType GetGraphicEvent(RealType *ChangeFactor)
{
    static IGGraphicEventType
	LastEvent = IG_EVENT_NONE;
    static long
	LastX = -1;
    int i, TransformRequest,
        LeftButtonIsPressed = getbutton(LEFTMOUSE) == 1;
    IGGraphicEventType
	RetVal = IG_EVENT_NONE;
    short data;
    long x, y, dev;
    RealType XPos, YPos;

    /* Allow continuous drag on following events only: */
    if (LeftButtonIsPressed && !IG_IS_DRAG_EVENT(LastEvent)) {
	while (getbutton(LEFTMOUSE) == 1);
	LeftButtonIsPressed = FALSE;
    }

    if (LeftButtonIsPressed) {
	/* Allow leaving the Trans window if still pressed, and use last     */
	/* event as the returned event.	Note we wait until current position  */
	/* is different from last one to make sure we do something.          */
	while((x = getvaluator(MOUSEX) - TransWinLeft) == LastX &&
	      getbutton(LEFTMOUSE) == 1);
	if (x != LastX) {
	    *ChangeFactor = (((RealType) x) - LastX) / TransWinWidth2;
	    LastX = x;
	    return LastEvent;
	}
	else
	    LeftButtonIsPressed = FALSE;
    }

    LastEvent = IG_EVENT_NONE;

    while (RetVal == IG_EVENT_NONE) {
	/* Wait for left button to be pressed in the Trans window. Note this */
	/* is the loop we are going to cycle in idle time.		     */
	for (TransformRequest = FALSE; !TransformRequest;) {
	    x = getvaluator(MOUSEX);
	    y = getvaluator(MOUSEY);

	    if (qtest()) {	              /* Any external event occured? */
		switch (dev = qread(&data)) {
		    case REDRAW:
			if (data == ViewWinID) {
			    getorigin(&ViewWinLeft, &ViewWinLow);
			    getsize(&ViewWinWidth, &ViewWinHeight);
			    ViewWinWidth2 = ViewWinWidth / 2;
			    ViewWinHeight2 = ViewWinHeight / 2;
			    reshapeviewport();
			    ortho2(-0.5, ViewWinWidth - 0.5,
				   -0.5, ViewWinHeight - 0.5);
			    IGRedrawViewWindow();
			}
			else if (data == TransWinID) {
			    winset(TransWinID);
			    getorigin(&TransWinLeft, &TransWinLow);
			    getsize(&TransWinWidth, &TransWinHeight);
			    reshapeviewport();
			    ortho2(-0.5, TransWinWidth - 0.5,
				   -0.5, TransWinHeight - 0.5);
			    TransWinWidth2 = TransWinWidth / 2;
			    RedrawTransformWindow();
			    winset(ViewWinID);
			}
			break;
		    case RIGHTMOUSE:
			if (data &&
			    IGHandleState(dopup(GlblStateMenu), FALSE)) {
			    *ChangeFactor = 0.0;
			    return IG_EVENT_STATE;
			}
			break;
		    case LEFTMOUSE:
			TransformRequest = data;
			break;
		}
		continue;
	    }

	    /* Maybe we have something in communication socket. */
	    if (!IGGlblStandAlone &&
		IGReadObjectsFromSocket(IGGlblViewMode, &IGGlblDisplayList))
		IGRedrawViewWindow();

	    IritSleep(10);	       /* So we do not use all CPU on idle. */
	}

	x -= TransWinLeft;
	y -= TransWinLow;

	XPos = ((RealType) x) / TransWinWidth;
	YPos = ((RealType) y) / TransWinHeight;

	/* Make sure we are in bound in the X direction. */
	if (XPos < (1.0 - INTERACT_SUB_WINDOW_WIDTH) / 2.0 ||
	    XPos > 1.0 - (1.0 - INTERACT_SUB_WINDOW_WIDTH) / 2.0)
	    continue;

	/* Now search the sub window the event occured in. */
	for (i = 0; i < INTERACT_NUM_OF_SUB_WNDWS; i++) {
	    if (InteractMenu.SubWindows[i].Y <= YPos &&
		InteractMenu.SubWindows[i].Y + INTERACT_SUB_WINDOW_HEIGHT >=
									YPos) {
		RetVal = InteractMenu.SubWindows[i].Event;
		break;
	    }
	}
	if (i == INTERACT_NUM_OF_SUB_WNDWS)
	    continue;

	/* Take care of special cases in which the window should be updated. */
	switch (RetVal) {
	    case IG_EVENT_SCR_OBJ_TGL:
		IGGlblTransformMode = IGGlblTransformMode == IG_TRANS_OBJECT ?
							     IG_TRANS_SCREEN :
							     IG_TRANS_OBJECT;
		RedrawTransformWindow();
		break;
	    case IG_EVENT_PERS_ORTHO_TGL:
	        IGGlblViewMode = IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
					           IG_VIEW_ORTHOGRAPHIC :
					           IG_VIEW_PERSPECTIVE;
		RedrawTransformWindow();
		break;
	    case IG_EVENT_QUIT:
		break;
	}

	*ChangeFactor = (((RealType) x) - TransWinWidth2) / TransWinWidth2;
    }

    LastEvent = RetVal;
    LastX = x;

    return RetVal;
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Handles the events of the pop up window.                                   M
*                                                                            *
* PARAMETERS:                                                                M
*   State:      Event to handle.                                             M
*   Refresh:    Do we need to refresh the screen according to what we know   M
*		on entry.						     M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:        TRUE, if we need to refresh the screen.                      M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGHandleState                                                            M
*****************************************************************************/
int IGHandleState(int State, int Refresh)
{
    int UpdateView = TRUE;

    switch (State) {
	case IG_STATE_SCR_OBJ_TGL:
	    IGGlblTransformMode = IGGlblTransformMode == IG_TRANS_OBJECT ?
							 IG_TRANS_SCREEN :
							 IG_TRANS_OBJECT;
	    RedrawTransformWindow();
	    UpdateView = FALSE;
	    break;
	case IG_STATE_PERS_ORTHO_TGL:
	    IGGlblViewMode = IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
					       IG_VIEW_ORTHOGRAPHIC :
					       IG_VIEW_PERSPECTIVE;
	    RedrawTransformWindow();
	    break;
	case IG_STATE_DRAW_SOLID:
	    IGGlblDrawSolid = !IGGlblDrawSolid;
	    /* And fall thru to disable the depth cueing. */
	    IGGlblDepthCue = TRUE; 
	case IG_STATE_DEPTH_CUE:
	    IGGlblDepthCue = !IGGlblDepthCue;
	    if (IGGlblDepthCue) {
#		ifndef _AIX
		    glcompat(GLC_ZRANGEMAP, 1);
#		endif /* _AIX */
		lRGBrange(0, 0, 0, 255, 255, 255,
			  0x0, 0x7fffff);
		depthcue(IGGlblDepthCue);
	    }
	    else
		depthcue(FALSE);
	    break;
	case IG_STATE_DOUBLE_BUFFER:
	    IGGlblDoDoubleBuffer = !IGGlblDoDoubleBuffer;
	    winset(ViewWinID);
	    if (IGGlblDoDoubleBuffer)
		doublebuffer();
	    else
		singlebuffer();
	    gconfig();
	    break;
	case IG_STATE_ANTI_ALIASING:
	    IGGlblAntiAliasing = !IGGlblAntiAliasing;
#	    ifndef _AIX
		if (getgdesc(GD_PNTSMOOTH_CMODE) == 0 ||
		    getgdesc(GD_BITS_NORM_DBL_CMODE) < 8)
		    IGGlblAntiAliasing = FALSE;
		else
		    subpixel(IGGlblAntiAliasing);
#	    endif /* _AIX */
	    break;
	default:
	    UpdateView = IGDefaultStateHandler(State, Refresh);
	    break;
    }

    IGCreateStateMenu();

    return UpdateView;
}

/*****************************************************************************
* DESCRIPTION:                                                               *
* Draws text centered at the given position.				     *
*                                                                            *
* PARAMETERS:                                                                *
*   Str:        String to draw.                                              *
*   PosX, PosY: Location to draw at.                                         *
*                                                                            *
* RETURN VALUE:                                                              *
*   void                                                                     *
*****************************************************************************/
static void DrawText(char *Str, long PosX, long PosY)
{
    long Width = strwidth(Str);

    cmov2s(PosX - Width / 2, PosY - (getheight() / 2 - getdescender()));
    charstr(Str);
}

/*****************************************************************************
* DESCRIPTION:                                                               M
* Make some sound.                                                           M
*                                                                            *
* PARAMETERS:                                                                M
*   None                                                                     M
*                                                                            *
* RETURN VALUE:                                                              M
*   void                                                                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   IGIritBeep                                                               M
*****************************************************************************/
void IGIritBeep(void)
{
    ringbell();
}

/*****************************************************************************
* DESCRIPTION:                                                               M
*   Should we stop this animation. Senses the event queue of X11.            M
*                                                                            *
* PARAMETERS:                                                                M
*   Anim:     The animation to abort.                                        M
*                                                                            *
* RETURN VALUE:                                                              M
*   int:      TRUE if we need to abort, FALSE otherwise.                     M
*                                                                            *
* KEYWORDS:                                                                  M
*   AnimCheckInterrupt                                                       M
*****************************************************************************/
int AnimCheckInterrupt(AnimationStruct *Anim)
{
    return FALSE;
}
