#include "device.h"

/**********************************************************/

#include <X11/Xatom.h>
#include <X11/Xmu/StdCmap.h>



/*implementation for Xlib*/

#define REAL            double
#define ROUND(x)        ((int)((x)+0.5))
#define MAXPOLYGON      20

static XPoint thePolygon[MAXPOLYGON];
static int  polySize;
static GC   gc;
 Display *display;
static int screen;
static int depth;
static Window rootWindow,currentWindow;
static XStandardColormap *TheColourMap;
static unsigned long whitePixel,blackPixel;
static XFontStruct *currentFont;

/********************************************************************/
void G_Initialise()
{
	int count;
	display = XOpenDisplay(NULL);
	screen = DefaultScreen(display);
	rootWindow = DefaultRootWindow(display);
	blackPixel = BlackPixel(display,screen);
	whitePixel = WhitePixel(display,screen);
	gc = DefaultGC(display,screen);
	XmuAllStandardColormaps(display);
	if(
	    XGetRGBColormaps(display,
				  rootWindow,
				  &TheColourMap,
				  &count,
				  XA_RGB_BEST_MAP)
	==0)
	printf("couldn't allocate standard colourmap\n");
}
/********************************************************************/

#define RELEASE_4


#ifdef RELEASE_4

Window G_CreateWin(posx,posy,width,height)
int posx,posy,width,height;
{
	Window newWindow;
	XTextProperty win_name,icon_name;
	XSizeHints hints;
	XEvent event;
	XSetWindowAttributes attr;
	int border = 10;
	char *win_title = "3D";
	char *icon_title = "3D";

	/*create the new window*/
	newWindow = XCreateSimpleWindow(display,rootWindow,
					posx,posy,width,height,border,
					blackPixel,whitePixel);

	/*convert the names each to a TextProperty*/
	XStringListToTextProperty(&win_title,1,&win_name);
	XStringListToTextProperty(&icon_title,1,&icon_name);

	/*set the name of the window and icon*/
	XSetWMName(display,newWindow,&win_name);
	XSetWMIconName(display,newWindow,&icon_name);

	hints.flags = PSize;
	hints.base_width = width;
	hints.base_height = height;
	XSetWMNormalHints(display,newWindow,&hints);

	/*make sure that this window accepts exposure events*/
	XSelectInput(display,newWindow,ExposureMask|ButtonPressMask|KeyPressMask);

	/*map the window and wait for an expose event*/
	XMapWindow(display,newWindow);
	while(True){
		XNextEvent(display,&event);
		if((event.type==Expose)&&(event.xexpose.window==newWindow))
			break;
	}


	/*set the window attributes - to always use backing store*/
	attr.backing_store = Always;
	/*change the colourmap*/
	attr.colormap = TheColourMap->colormap;
	/*means that there will be an attempt to repaint window contents
	  on Expose events, but there is no guarantee*/
	XChangeWindowAttributes(display,newWindow,CWBackingStore|CWColormap,&attr);
	/*Note that if the window is resized then the contents may not
	  be restored. In any case there will be an Expose event generated
	  and the client should be prepared to handle this*/

	return(newWindow);
}

#else /*RELEASE_3*/

Window G_CreateWin(posx,posy,width,height)
int posx,posy,width,height;
{

	Window theWindow;
	unsigned int border = 10;
	XSizeHints hints;
	char **argv;
	int argc = 0;
	XWMHints wmhints;
	XSetWindowAttributes attr;
	XEvent event;

	theWindow = XCreateSimpleWindow(display,rootWindow,posx,posy,
			     width,height,border,blackPixel,whitePixel);
	hints.flags = (PPosition | PSize);
	hints.height = height;
	hints.width = width;
	hints.x = posx;
	hints.y = posy;
	XSetStandardProperties(display,theWindow,"SPIRIT",
			  "SPIRIT",None,argv,argc,&hints);

	wmhints.flags = (InputHint | StateHint);
	wmhints.input = False;
	wmhints.initial_state = NormalState;
	wmhints.icon_pixmap = 0;
	wmhints.icon_window = 0;
	wmhints.icon_x = wmhints.icon_y = 0;
	wmhints.icon_mask = 0;
	wmhints.window_group = 0;
	XSetWMHints(display,theWindow,&wmhints);

	/*set up default colour map*/
	attr.colormap = DefaultColormap(display,screen);
	attr.bit_gravity = CenterGravity;
	XChangeWindowAttributes(display,theWindow,
				      (CWColormap|CWBitGravity),&attr);


	XSelectInput(display,theWindow,ExposureMask);

	XMapWindow(display,theWindow);

	while(True){
		XNextEvent(display,&event);
		if((event.type==Expose)&&(event.xexpose.window==theWindow))
			break;
	}
	return(theWindow);
}

#endif

/********************************************************************/
/*the following functions must be defined*/

DRAWABLE newDrawable(posx,posy,width,height)
int posx,posy,width,height;
{
	return(G_CreateWin(posx,SCREEN_MAX-posy-height,width,height));
}

void setDrawable(drawable)
DRAWABLE drawable;
{
	currentWindow = drawable;
}

void initialiseDrawables()
/*do whatever is necessary to start up*/
{
	G_Initialise();
}

void newPolygonOnDrawable()
/*do whatever is necessary to start up a new polygon*/
{
	polySize = 0;
}

void startPolygonOnDrawable(x,y)
int x,y;
{
	thePolygon[0].x = x;
	thePolygon[0].y = y;
	++polySize;
}

void addToPolygonOnDrawable(x,y)
int x,y;
{
	thePolygon[polySize].x = x;
	thePolygon[polySize].y = y;
	++polySize;
}

#define ADJUST_LT(c)    {if((c)<0.0) (c) = 0.0;}
#define ADJUST_GT(c)    {if((c)>1.0) (c) = 1.0;}
#define ADJUST(c)       {ADJUST_LT((c)); ADJUST_GT((c));}

static adjustColour(red,green,blue)
REAL *red,*green,*blue;
{
	ADJUST(*red);
	ADJUST(*green);
	ADJUST(*blue);
}
/*
void setColourOnDrawable(red,green,blue)
REAL red,green,blue;
{
	XColor colour;

	adjustColour(&red,&green,&blue);

	colour.red = ROUND(65535.0*red);
	colour.green = ROUND(65535.0*green);
	colour.blue = ROUND(65535.0*blue);
	colour.flags = DoRed|DoGreen|DoBlue;
	XAllocColor(display,DefaultColormap(display,screen),&colour);

	XSetForeground(display,gc,colour.pixel);
}
*/

#define PIXEL(C,r,g,b) (C->base_pixel + \
		((unsigned long)(0.5+(r*C->red_max))*C->red_mult)+\
		((unsigned long)(0.5+(g*C->green_max))*C->green_mult)+\
		((unsigned long)(0.5+(b*C->blue_max))*C->blue_mult))

void setColourOnDrawable(red,green,blue)
REAL red,green,blue;
{
	unsigned long int pixel;

	adjustColour(&red,&green,&blue);

	pixel = PIXEL(TheColourMap,red,green,blue);
	XSetForeground(display,gc,pixel);
}

void displayPolygonOnDrawable()
{
	XFillPolygon(display,currentWindow,gc,
		     thePolygon,polySize,Convex,CoordModeOrigin);
}

void clearDrawable()
{
	XClearWindow(display,currentWindow);
}



void flushDrawable()
{
	XSync(display,False);
}

void delayOnDrawable(d)
DRAWABLE d;
{
	XEvent event;
	while(1){
		XNextEvent(display,&event);
		if(event.type == ButtonPress) break;
	}
}

void getGeometryOfDrawable(drawable,posx,posy,width,height)
DRAWABLE drawable;
int *posx,*posy,*width,*height;
{
	Window root;
	int x_ret,y_ret;
	unsigned int w,h,border,depth;

	XGetGeometry(display,drawable,&root,
			&x_ret,&y_ret,&w,&h,
			&border,&depth);

	*posx = x_ret;
	*posy = y_ret;
	*width = w;
	*height = h;
}


