/*****************************************************************************
*   An Amiga driver.                                                         *
*                                                                            *
* Written by:  Kriton Kyrimis                                                *
*        and   Gershon Elber                         Ver 0.1, October 1993.  *
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>
#include <graphics/displayinfo.h>

#undef SIGN

#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 "iritgrap.h"
#include "irit_soc.h"

#ifdef __SASC
#include <dos/dos.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/layers.h>
#endif

#ifdef __GNUC__
#include <inline/dos.h>
#include <inline/exec.h>
#include <inline/intuition.h>
#include <inline/graphics.h>
#include <inline/layers.h>
#endif

/* Window coordinates for transformation window gadgetry */
#define L 24
#define R 162
#define S_O_TOP 11
#define S_O_BOT 25
#define O_P_TOP 32
#define O_P_BOT 46
#define O_PZ_TOP O_P_BOT
#define O_PZ_BOT 60
#define RX_TOP 77
#define RX_BOT 91
#define RY_TOP RX_BOT
#define RY_BOT 104
#define RZ_TOP RY_BOT
#define RZ_BOT 118
#define TX_TOP 136
#define TX_BOT 149
#define TY_TOP TX_BOT
#define TY_BOT 163
#define TZ_TOP TY_BOT
#define TZ_BOT 177
#define SCALE_TOP 194
#define SCALE_BOT 208
#define DQ_TOP 219
#define DQ_BOT 233
#define SAVE_TOP 243
#define SAVE_BOT 257
#define PUSH_TOP 267
#define PUSH_BOT 281
#define POP_TOP 288
#define POP_BOT 302
#define QUIT_TOP 314
#define QUIT_BOT 328

#define TWIDTH 188
#define THEIGHT 338

#define MAP_X_COORD(x) (int)(((RealType)(ViewWidth - 1) * (x + 1.0)) / 2.0)
#define MAP_Y_COORD(y) (int)(((RealType)(ViewHeight - 1) * (1.0 - y)) / 2.0)

struct GfxBase *GfxBase = NULL;
struct IntuitionBase *IntuitionBase = NULL;
struct Library *LayersBase = NULL;

static struct Screen *screen = NULL;
static struct Window *TransformWindow = NULL;
static struct RastPort *trp;
static struct Window *ViewWindow[2] = {NULL, NULL};
static struct RastPort *vrp;

static int CurrentWindow = 0;
static int HaveSocket = FALSE;

static int ViewWidth, ViewHeight,
	   CurrentXPosition = 0, CurrentYPosition = 0,
	   CurrentColor = IG_IRIT_WHITE;

static struct ColorSpec colors[] =
{
    { 0,  0,  0,  0},	/* 0. IG_IRIT_BLACK */
    { 1,  0,  0, 10},	/* 1. IG_IRIT_BLUE */
    { 2,  0, 10,  0},	/* 2. IG_IRIT_GREEN */
    { 3,  0, 10, 10},	/* 3. IG_IRIT_CYAN */
    { 4, 10,  0,  0},	/* 4. IG_IRIT_RED */
    { 5, 10,  0, 10},	/* 5. IG_IRIT_MAGENTA */
    { 6, 10, 10,  0},	/* 6. IG_IRIT_BROWN */
    { 7, 10, 10, 10},	/* 7. IG_IRIT_LIGHTGREY */
    { 8,  5,  5,  5},	/* 8. IG_IRIT_DARKGRAY */
    { 9,  5,  5, 15},	/* 9. IG_IRIT_LIGHTBLUE */
    {10,  5, 15,  5},	/* 10. IG_IRIT_LIGHTGREEN */
    {11,  5, 15, 15},	/* 11. IG_IRIT_LIGHTCYAN */
    {12, 15,  5,  5},	/* 12. IG_IRIT_LIGHTRED */
    {13, 15,  5, 15},	/* 13. IG_IRIT_LIGHTMAGENTA */
    {14, 15, 15,  5},	/* 14. IG_IRIT_YELLOW */
    {15, 15, 15, 15},	/* 15. IG_IRIT_WHITE */
    {-1,  0,  0,  0}	/* end */
};

static struct TextAttr font = { "topaz.font", 8, 0, 0 };

static UWORD pens[] =
{
    IG_IRIT_BLACK,		/* DETAILPEN */
    IG_IRIT_DARKGRAY,		/* BLOCKPEN */
    IG_IRIT_LIGHTGREY,		/* TEXTPEN */
    IG_IRIT_LIGHTGREY,		/* SHINEPEN */
    IG_IRIT_DARKGRAY,		/* SHADOWPEN */
    IG_IRIT_LIGHTGREY,		/* FILLPEN */
    IG_IRIT_LIGHTMAGENTA,	/* FILLTEXTPEN */
    IG_IRIT_BLACK,		/* BACKGROUNDPEN */
    IG_IRIT_WHITE,		/* HIGHLIGHTTEXTPEN */
    (UWORD) ~0			/* done */
};

static void Cleanup(void);
static void DrawTransformWindow(void);
static void Box(int, int, int, int);
static void PotBox(int, int, int, int);
static void CenterText(char *, int);
static void SideText(char *, int);
static int GetColorRGB(int *);
static int Hit(int, int, int, int);
static void RedrawViewWindow(void);
static IGGraphicEventType GetGraphicEvent(RealType *);
static void singlebuffer(void);
static void doublebuffer(void);
static void swapbuffers(void);

/****************************************************************************
* Pop up all windows, read input and display.                               *
****************************************************************************/
main(int argc, char *argv[])
{
    RealType ChangeFactor;
    IGGraphicEventType Event;

    atexit(Cleanup);   /* Absolutely, positively *must* clean up before exit */

    IGConfigureGlobals("amidrvs", argc, argv);

    if ((IntuitionBase = (struct IntuitionBase *)
	 OpenLibrary ("intuition.library", 37L)) == NULL){
	fprintf (stderr, "This program requires AmigaDOS 2.04 or higher\n");
	exit(RETURN_FAIL);
    }
    if ((GfxBase =
	 (struct GfxBase *) OpenLibrary ("graphics.library", 0L)) == NULL){
	fprintf (stderr, "Can't open graphics.library\n");
	exit(RETURN_FAIL);
    }
    if ((LayersBase = OpenLibrary ("layers.library", 0L)) == NULL){
	fprintf (stderr, "Can't open layers.library\n");
	exit(RETURN_FAIL);
    }

    screen = OpenScreenTags(NULL,
			    SA_Depth,	4,
			    SA_DisplayID,	HIRESLACE_KEY,
			    SA_Quiet,	TRUE,
			    SA_Title,	"Irit",
			    SA_Font,	&font,
			    SA_Pens,	&pens,
			    SA_Colors,	&colors,
			    TAG_END);
    if (!screen) {
	fprintf(stderr, "Can't open screen\n");
	exit(RETURN_FAIL);
    }

    TransformWindow = OpenWindowTags(NULL,
  				WA_CustomScreen,screen,
  				WA_Left,	screen->Width - TWIDTH,
  				WA_Top,		(screen->Height - THEIGHT) / 2,
				WA_Width,	TWIDTH,
				WA_Height,	THEIGHT,
				WA_IDCMP,	IDCMP_MOUSEBUTTONS,
				WA_RMBTrap,	TRUE,
  				TAG_END);
    if (!TransformWindow) {
	fprintf(stderr, "Can't open transform window\n");
	exit(RETURN_FAIL);
    }
    trp = TransformWindow -> RPort;

    DrawTransformWindow();

    ViewWidth = screen -> Width - TWIDTH;
    ViewHeight = screen -> Height;

    ViewWindow[0] = OpenWindowTags(NULL,
				   WA_CustomScreen, screen,
				   WA_Borderless,   TRUE,
				   WA_Width,	    ViewWidth,
				   WA_Height,	    ViewHeight,
				   WA_IDCMP,	    0,
				   WA_RMBTrap,	    TRUE,
				   TAG_END);

    if (!ViewWindow[0]) {
	fprintf(stderr, "Can't open view window\n");
	exit(RETURN_FAIL);
    }
    if (IGGlblDoDoubleBuffer) {
        doublebuffer();
    }else{
        singlebuffer();
    }
    RedrawViewWindow();

    if (!IGGlblStandAlone) {
	SocClientCreateSocket();
	HaveSocket = TRUE;
    }

    while ((Event = GetGraphicEvent(&ChangeFactor)) != IG_EVENT_QUIT) {
	if (IGProcessEvent(Event, ChangeFactor * IGGlblChangeFactor)) {
	    RedrawViewWindow();
	}
    }

    if (!IGGlblStandAlone) {
	SocClientCloseSocket();
	HaveSocket = FALSE;
    }

    exit(RETURN_OK);
}

/*****************************************************************************
* Routine to make some sound.                                                *
*****************************************************************************/
void IGIritBeep(void)
{
    DisplayBeep(screen);
}

/*****************************************************************************
* Construct global pop up menu.                                              *
*****************************************************************************/
void IGCreateStateMenu(void)
{
}

/****************************************************************************
* Routine to move in 2D normalized (-1..1) view space.                      *
****************************************************************************/
void IGMoveTo2D(RealType X, RealType Y)
{
    CurrentXPosition = MAP_X_COORD(X);
    CurrentYPosition = MAP_Y_COORD(Y);
}

/****************************************************************************
* Routine to draw in 2D normalized (-1..1) view space.                      *
****************************************************************************/
void IGLineTo2D(RealType X, RealType Y)
{
    int NewX, NewY, i;

    NewX = MAP_X_COORD(X);
    NewY = MAP_Y_COORD(Y);
    Move(vrp, CurrentXPosition, CurrentYPosition);
    Draw(vrp, NewX, NewY);
    if (IGGlblLineWidth > 1) {
	for (i=1; i<IGGlblLineWidth; i++) {
	    Move(vrp, CurrentXPosition + i, CurrentYPosition);
	    Draw(vrp, NewX + i, NewY);
	    Move(vrp, CurrentXPosition, CurrentYPosition - i);
	    Draw(vrp, NewX, NewY - i);
	}
	Move(vrp, NewX, NewY);
	
	RectFill(vrp, NewX, NewY - IGGlblLineWidth + 1,
		      NewX + IGGlblLineWidth - 1, NewY);
    }
    CurrentXPosition = NewX;
    CurrentYPosition = NewY;
}

/****************************************************************************
* Routine to set the intensity of a color (high or low).                    *
****************************************************************************/
void IGSetColorIntensity(int High)
{
  if (High) {
      CurrentColor |= 8;
  } else {
      CurrentColor &= ~8;
  }
  SetAPen(vrp, CurrentColor);
  IGGlblIntensityHighState = High;
}

/****************************************************************************
* Routine to set the color according to the given object's color.           *
****************************************************************************/
void IGSetColorObj(IPObjectStruct *PObj)
{
    int c, Color[3];
    if (AttrGetObjectRGBColor(PObj, &Color[0], &Color[1], &Color[2])) {
        CurrentColor = GetColorRGB(Color);
    }
    else if ((c = AttrGetObjectColor(PObj)) != IP_ATTR_NO_COLOR) {
        CurrentColor = c;
    }
    else {
        /* Use white as default color: */
        CurrentColor = IG_IRIT_WHITE;
    }
    SetAPen(vrp, c | 8);
    IGGlblIntensityHighState = TRUE;
}

/****************************************************************************
* Routine to find the closest color to a given RGB combination             *
****************************************************************************/
static int GetColorRGB(int *Color)
{
    int r, g, b;
    int dist, mindist = MAXINT;
    int bestcolor = IG_IRIT_WHITE;
    int i;

    r = Color[0] >> 4;
    g = Color[1] >> 4;
    b = Color[2] >> 4;

    for (i = 8; i <= 15; i++) {	    /* Only consider high intensity colors */
	dist = colors[i].Red * colors[i].Red - r * r
	     + colors[i].Green * colors[i].Green - g * g
	     + colors[i].Blue * colors[i].Blue - b * b;
	if (dist < 0)
	    dist = -dist;
	if (dist < mindist) {
	    mindist = dist;
	    bestcolor = i;
	}
    }
    return bestcolor;
}

/******************************************************************************
* Handle the event of a pop up window.                                        *
******************************************************************************/
int IGHandleState(int State, int Refresh)
{
    int UpdateView = TRUE;

    switch (State) {
	case IG_STATE_DEPTH_CUE:
	    CenterText((IGGlblDepthCue ? "  Depth Cue  "
				       : "No Depth Cue"), DQ_BOT);
	    break;
	case IG_STATE_DOUBLE_BUFFER:
	    IGGlblDoDoubleBuffer = !IGGlblDoDoubleBuffer;
	    if (IGGlblDoDoubleBuffer) {
	        doublebuffer();
	    }else{
	        singlebuffer();
	    }
	    break;
	case IG_STATE_WIDER_LINES:
	    IGGlblLineWidth *= 2;
	    break;
	case IG_STATE_NARROW_LINES:
	    IGGlblLineWidth /= 2;
	    if (IGGlblLineWidth < 1) {
		IGGlblLineWidth = 1;
	    }
	    break;
	default:
	    UpdateView = IGDefaultStateHandler(State, Refresh);
	    break;
    }

    IGCreateStateMenu();

    return UpdateView;
}

/******************************************************************************
* Handle input events                                                         *
******************************************************************************/
static IGGraphicEventType GetGraphicEvent(RealType *ChangeFactor)
{
    ULONG class;
    USHORT code;
    SHORT x, y;
    struct IntuiMessage *message;
    static int LastX;

    while (TRUE) {
	/* Maybe we have something in communication socket. */
	if (!IGGlblStandAlone &&
	    IGReadObjectsFromSocket(IGGlblViewMode, &IGGlblDisplayList)) {
	    RedrawViewWindow();
	}

	if (message = (struct IntuiMessage *)
				    GetMsg(TransformWindow -> UserPort)) {
	    class = message -> Class;
	    code = message -> Code;
	    x = message -> MouseX;
	    y = message -> MouseY;
	    ReplyMsg((struct Message *) message);
	    if (class == IDCMP_MOUSEBUTTONS && code == SELECTDOWN) {
		LastX = x;
	        ModifyIDCMP(TransformWindow,
			    IDCMP_MOUSEBUTTONS | IDCMP_INTUITICKS);
	        *ChangeFactor = (RealType)((x - L - 1) - ((R - L - 1) / 2))
	    		      / (RealType)((R - L - 1) / 2);
		if (Hit(x, y, S_O_TOP, S_O_BOT)) {
		    IGGlblTransformMode =
			IGGlblTransformMode == IG_TRANS_OBJECT ?
					       IG_TRANS_SCREEN :
					       IG_TRANS_OBJECT;
		    CenterText((IGGlblTransformMode == IG_TRANS_OBJECT ?
			       "Object": "Screen"), S_O_BOT);
		    return IG_EVENT_SCR_OBJ_TGL;
		}
		if (Hit(x, y, O_P_TOP, O_P_BOT)) {
		    IGGlblViewMode =
			IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
					  IG_VIEW_ORTHOGRAPHIC :
					  IG_VIEW_PERSPECTIVE;
		    CenterText((IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
			       " Perspective " : "Orthographic"), O_P_BOT);
		    return IG_EVENT_PERS_ORTHO_TGL;
		}
		if (Hit(x, y, O_PZ_TOP, O_PZ_BOT)) {
		    return IG_EVENT_PERS_ORTHO_Z;
		}
		if (Hit(x, y, RX_TOP, RX_BOT)) {
		    return IG_EVENT_ROTATE_X;
		}
		if (Hit(x, y, RY_TOP, RY_BOT)) {
		    return IG_EVENT_ROTATE_Y;
		}
		if (Hit(x, y, RZ_TOP, RZ_BOT)) {
		    return IG_EVENT_ROTATE_Z;
		}
		if (Hit(x, y, TX_TOP, TX_BOT)) {
		    return IG_EVENT_TRANSLATE_X;
		}
		if (Hit(x, y, TY_TOP, TY_BOT)) {
		    return IG_EVENT_TRANSLATE_Y;
		}
		if (Hit(x, y, TZ_TOP, TZ_BOT)) {
		    return IG_EVENT_TRANSLATE_Z;
		}
		if (Hit(x, y, SCALE_TOP, SCALE_BOT)) {
		    return IG_EVENT_SCALE;
		}
		if (Hit(x, y, DQ_TOP, DQ_BOT)) {
		    IGGlblDepthCue = !IGGlblDepthCue;
		    CenterText((IGGlblDepthCue ?
			       "  Depth Cue  ": "No Depth Cue"), DQ_BOT);
		    return IG_EVENT_DEPTH_CUE;
		}
		if (Hit(x, y, SAVE_TOP, SAVE_BOT)) {
		    return IG_EVENT_SAVE_MATRIX;
		}
		if (Hit(x, y, PUSH_TOP, PUSH_BOT)) {
		    return IG_EVENT_PUSH_MATRIX;
		}
		if (Hit(x, y, POP_TOP, POP_BOT)) {
		    return IG_EVENT_POP_MATRIX;
		}
		if (Hit(x, y, QUIT_TOP, QUIT_BOT)) {
		    return IG_EVENT_QUIT;
		}
	    }
	    if (class == IDCMP_MOUSEBUTTONS && code == SELECTUP) {
	        ModifyIDCMP(TransformWindow, IDCMP_MOUSEBUTTONS);
	    }
	    if (class == IDCMP_INTUITICKS) {
		/* We may get events of movement in Y which are ignored. */
		if (x - LastX == 0) {
		    continue;
		}
		*ChangeFactor = (RealType) (x - LastX) /
				(RealType) ((R - L - 1) / 2);
		LastX = x;

		if (Hit(x, y, O_PZ_TOP, O_PZ_BOT)) {
		    return IG_EVENT_PERS_ORTHO_Z;
		}
		if (Hit(x, y, RX_TOP, RX_BOT)) {
		    return IG_EVENT_ROTATE_X;
		}
		if (Hit(x, y, RY_TOP, RY_BOT)) {
		    return IG_EVENT_ROTATE_Y;
		}
		if (Hit(x, y, RY_TOP, RY_BOT)) {
		    return IG_EVENT_ROTATE_Y;
		}
		if (Hit(x, y, RZ_TOP, RZ_BOT)) {
		    return IG_EVENT_ROTATE_Z;
		}
		if (Hit(x, y, TX_TOP, TX_BOT)) {
		    return IG_EVENT_TRANSLATE_X;
		}
		if (Hit(x, y, TY_TOP, TY_BOT)) {
		    return IG_EVENT_TRANSLATE_Y;
		}
		if (Hit(x, y, TZ_TOP, TZ_BOT)) {
		    return IG_EVENT_TRANSLATE_Z;
		}
		if (Hit(x, y, SCALE_TOP, SCALE_BOT)) {
		    return IG_EVENT_SCALE;
		}
	    }
	}
    }
}

/******************************************************************************
* Determine if point (x,y) is inside rectangle (L,y1) (R,y2)                  *
******************************************************************************/
static int Hit(int x, int y, int y1, int y2)
{
    return (x > L && x < R && y > y1 && y < y2);
}

/******************************************************************************
* Deallocate resources                                                        *
******************************************************************************/
static void Cleanup(void)
{
    if (HaveSocket) {
	SocClientCloseSocket();
    }
    if (ViewWindow[0]) {
	CloseWindow(ViewWindow[0]);
	ViewWindow[0] = NULL;
    }
    if (ViewWindow[1]) {
	CloseWindow(ViewWindow[1]);
	ViewWindow[1] = NULL;
    }
    if (TransformWindow) {
	CloseWindow(TransformWindow);
	TransformWindow = NULL;
    }
    if (screen) {
	CloseScreen(screen);
	screen = NULL;
    }
    if (IntuitionBase){
	CloseLibrary((struct Library *)IntuitionBase);
	IntuitionBase = NULL;
    }
    if (GfxBase){
	CloseLibrary((struct Library *)GfxBase);
	GfxBase = NULL;
    }
    if (LayersBase){
	CloseLibrary(LayersBase);
	GfxBase = NULL;
    }
}

/****************************************************************************
* Draw a box in the transform window given two opposite corners             *
****************************************************************************/
static void Box(int x1, int y1, int x2, int y2)
{
    Move(trp, x1, y1);
    Draw(trp, x2, y1);
    Draw(trp, x2, y2);
    Draw(trp, x1, y2);
    Draw(trp, x1, y1);
}

/****************************************************************************
* Same as above, but with a vertical line in the middle                     *
****************************************************************************/
static void PotBox(int x1, int y1, int x2, int y2)
{
    Box(x1, y1, x2, y2);
    Move(trp, (x1 + x2) / 2, y1);
    Draw(trp, (x1 + x2) / 2, y2);
}

/****************************************************************************
* Draw the transform window                                                 *
****************************************************************************/
static void DrawTransformWindow(void)
{
    SetAPen(trp, IG_IRIT_LIGHTGREY);
    SetDrMd(trp, JAM2);

    Box(L, S_O_TOP, R, S_O_BOT);			   /* Screen/Object */
    CenterText((IGGlblTransformMode == IG_TRANS_OBJECT ?
		"Object": "Screen"), S_O_BOT);

    Box(L, O_P_TOP, R, O_P_BOT);		/* Orthographic/Perspective */
    CenterText((IGGlblViewMode == IG_VIEW_PERSPECTIVE ?
		" Perspective " : "Orthographic"), O_P_BOT);
    PotBox(L, O_PZ_TOP, R, O_PZ_BOT);
    SideText("Z", O_PZ_BOT);

    PotBox(L, RX_TOP, R, RX_BOT);				  /* Rotate */
    PotBox(L, RY_TOP, R, RY_BOT);
    PotBox(L, RZ_TOP, R, RZ_BOT);
    CenterText("Rotate", RX_TOP);
    SideText("X", RX_BOT);
    SideText("Y", RY_BOT);
    SideText("Z", RZ_BOT);

    PotBox(L, TX_TOP, R, TX_BOT);			       /* Translate */
    PotBox(L, TY_TOP, R, TY_BOT);
    PotBox(L, TZ_TOP, R, TZ_BOT);
    CenterText("Translate", TX_TOP);
    SideText("X", TX_BOT);
    SideText("Y", TY_BOT);
    SideText("Z", TZ_BOT);

    PotBox(L, SCALE_TOP, R, SCALE_BOT);				  /* Scale */
    CenterText("Scale", SCALE_TOP);

    Box(L, DQ_TOP, R, DQ_BOT);			 /* Depth Cue/No Cepth Que */
    CenterText((IGGlblDepthCue ? "  Depth Cue  ": "No Depth Cue"), DQ_BOT);

    Box(L, SAVE_TOP, R, SAVE_BOT);			    /* Save Matrix */
    CenterText("Save Matrix", SAVE_BOT);

    Box(L, PUSH_TOP, R, PUSH_BOT);			    /* Push Matrix */
    CenterText("Push Matrix", PUSH_BOT);

    Box(L, POP_TOP, R, POP_BOT);			     /* Pop Matrix */
    CenterText("Pop Matrix", POP_BOT);

    Box(L, QUIT_TOP, R, QUIT_BOT);				   /* Quit */
    CenterText("Quit", QUIT_BOT);
}

/****************************************************************************
* Draw some centered text in the transform window                           *
****************************************************************************/
static void CenterText(char *txt, int y)
{
    int len;

    Move(trp, L, y - 5);
    len = TextLength(trp, txt, strlen(txt));
    Move(trp, L + 1 + (R - L - 1 - len) / 2, y - 5);
    Text(trp, txt, strlen(txt));
}

/****************************************************************************
* Draw some text next to a transform in the button window                   *
****************************************************************************/
static void SideText(char *txt, int y)
{
    Move(trp, L - 10, y - 4);
    Text(trp, txt, strlen(txt));
}

/*****************************************************************************
* Redraw the view window.                                                    *
*****************************************************************************/
static void RedrawViewWindow(void)
{
    IPObjectStruct *PObj;

    Move(vrp, 0L, 0L);
    ClearScreen(vrp);

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

     for (PObj = IGGlblDisplayList; PObj != NULL; PObj = PObj -> Pnext)
         IGDrawObject(PObj);

     if (IGGlblDoDoubleBuffer) {
         swapbuffers();
     }
}

static void
singlebuffer(void)
{
    if (ViewWindow[!CurrentWindow]) {
	CloseWindow(ViewWindow[!CurrentWindow]);
	ViewWindow[!CurrentWindow] = NULL;
    }
    vrp = ViewWindow[CurrentWindow]->RPort;
}

static void
doublebuffer(void)
{
    if (!ViewWindow[!CurrentWindow]) {
	ViewWindow[!CurrentWindow] =
	    OpenWindowTags(NULL, WA_CustomScreen, screen,
				 WA_Borderless,   TRUE,
				 WA_Width,	  ViewWidth,
				 WA_Height,	  ViewHeight,
				 WA_IDCMP,	  0,
				 WA_RMBTrap,	  TRUE,
				 TAG_END);
	if (!ViewWindow[!CurrentWindow]) {
	    fprintf(stderr, "Can't open second view window\n");
	    exit(RETURN_FAIL);
	}

	MoveWindowInFrontOf(ViewWindow[!CurrentWindow],
	 		    ViewWindow[CurrentWindow]);
    }
    vrp = ViewWindow[CurrentWindow]->RPort;
}

static void
swapbuffers(void)
{
/* Intuition may take up to 1/10th sec to rearrange the windows if we use
   MoveWindowInFrontOf, causing severe flicker when swapping windows
   containing simple scenes. We avoid this by manipulating the layers
   ourselves.
 */
    MoveLayerInFrontOf(ViewWindow[CurrentWindow]->WLayer,
		       ViewWindow[!CurrentWindow]->WLayer);
    CurrentWindow = !CurrentWindow;
    vrp = ViewWindow[CurrentWindow]->RPort;
}
