
#include "glwin.h"

GLWin::GLWin() {

	_dpy = NULL;
	_win = 0;
	_cx = 0;
	_db = _z = False;

	_name = "GLWin";
	_x = DEFAULT_X;
	_y = DEFAULT_Y;
}

GLWin::GLWin(int x, int y, const JLString &s) {

	_dpy = NULL;
	_win = 0;
	_cx = 0;
	_db = _z = False;

	_name = s;
	_x = x;
	_y = y;
}

GLWin::GLWin(const GLWin &w) {

	_dpy = NULL;
	_win = 0;
	_cx = 0;
	_db = w._db;
	_z = w._z;

	_name = w._name;
	_x = w._x;
	_y = w._y;

	if (w._dpy)
		Open();
}

GLWin::~GLWin() {

	if (_dpy)
		Close();
}


GLWin& GLWin::SetSize(int x, int y) {

	if (x>0) _x = x;
	if (y>0) _y = y;

#if 0
	if (_ID) {
		long ox, oy;
		long sx, sy;
		MakeCurrent();
		getorigin(&ox, &oy);
		getsize(&sx, &sy);
		winposition(ox, ox+x-1, oy+sy-y-2, oy+sy-1);
		reshapeviewport();
	}
#else
	XResizeWindow (_dpy, _win, x, y);
#endif
	return *this;
}



static int snglBuf_no_z[] = {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
							 GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 0,
							 None};

static int dblBuf_no_z[] =  {GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
							 GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 0,
							 GLX_DOUBLEBUFFER,
							 None};

static int snglBuf_z[] =	{GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
							 GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12,
							 None};

static int dblBuf_z[] =		{GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
							 GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 12,
							 GLX_DOUBLEBUFFER,
							 None};

GLWin& GLWin::Open(int additional_events_mask) {

	// code taken from glxsimple.c by Mark J. Kilgard

	if (_dpy)
		return *this;


	XVisualInfo				*vi;
	Colormap				cmap;
	XSetWindowAttributes	swa;
	int						dummy;


	_dpy = XOpenDisplay(NULL);
	if (!_dpy) {
		cerr << "GLWin: could not open display" << endl;
		exit(-1);
	}

	if (!glXQueryExtension(_dpy, &dummy, &dummy)) {
		cerr << "GLWin: X server has no OpenGL GLX extension" << endl;
		exit(-1);
	}

	if (_z) {
		if (_db) {
                        cerr << "goin' for double buffered Z visual" << endl;
			vi = glXChooseVisual(_dpy, DefaultScreen(_dpy), dblBuf_z);
			if (!vi) {
				cerr << "GLWin: no RGB visual with depth and double buffer"
					 << endl;
				exit(-1);
			}
		}
		else {
                        cerr << "goin' for single buffered Z visual" << endl;
			vi = glXChooseVisual(_dpy, DefaultScreen(_dpy), snglBuf_z);
			if (!vi) {
				cerr << "GLWin: no RGB visual with depth buffer" << endl;
				exit(-1);
			}
		}

	}
	else {
		if (_db) {
                        cerr << "goin' for double buffered non-Z visual" << endl;
			vi = glXChooseVisual(_dpy, DefaultScreen(_dpy), dblBuf_no_z);
			if (!vi) {
				cerr << "GLWin: no RGB visual with double buffer" << endl;
				exit(-1);
			}
		}
		else {
                        cerr << "goin' for single buffered non-Z visual" << endl;
			vi = glXChooseVisual(_dpy, DefaultScreen(_dpy), snglBuf_no_z);
			if (!vi) {
				cerr << "GLWin: no RGB visual" << endl;
				exit(-1);
			}
		}

	}

	if (vi->c_class != TrueColor) {
		cerr << "GLWin: no TrueColor visual" << endl;
		exit(-1);
	}

	_cx = glXCreateContext(_dpy, vi,
			/* No sharing of display lists */ None,
			/* Direct rendering if possible */ True);
	if (!_cx) {
		cerr << "GLWin: could not create rendering context" << endl;
		exit(-1);
	}

	cmap = XCreateColormap(_dpy,
						   RootWindow(_dpy, vi->screen),
						   vi->visual,
						   AllocNone);
	swa.colormap = cmap;
	swa.border_pixel = 0;
	swa.event_mask = ExposureMask | ButtonPressMask | StructureNotifyMask |
					 KeyPressMask | additional_events_mask;

	_win = XCreateWindow(_dpy,
						 RootWindow(_dpy, vi->screen),
						 0, 0, _x, _y, 0, vi->depth,
						 InputOutput, vi->visual,
						 CWBorderPixel | CWColormap | CWEventMask,
						 &swa);

	XSetStandardProperties(_dpy, _win,
						   _name.GetString(),
						   _name.GetString(),
						   None, NULL, 0, NULL);

	MakeCurrent();

	XMapWindow(_dpy, _win);

	XEvent event;
	int ready = 0;
	while (!ready) {
		NextEvent(event);
		if (event.type == ConfigureNotify) {
			glViewport(0, 0, event.xconfigure.width, event.xconfigure.height);
			ready = 1;
		}
	}

	if (_z)
		glEnable(GL_DEPTH_TEST);

	return *this;
}

GLWin& GLWin::Close() {

	if (_dpy) {
		cerr << "GLWin::Close() not implemented" << endl;
	}

	return *this;
}

void GLWin::Clear(float r, float g, float b) {

	MakeCurrent();

	glClearColor(r, g, b, 1);
	glClear(GL_COLOR_BUFFER_BIT | (GL_DEPTH_BUFFER_BIT * _z));

}

void GLWin::Clear(long c) {

	float r = (c & 0x00FF);
	c >>= 8;
	float g = (c & 0x00FF);
	c >>= 8;
	float b = (c & 0x00FF);

	Clear(r, g, b);
}

ostream& operator<<(ostream &co, const GLWin &W) {

	co << "GLWin:" << endl;
	co << " name: " << W._name << endl;
	co << " size: " << W._x << ", " << W._y << endl;

	return co;
}
