#include <../arch/arch.h>

GLOBAL_STRING(gl_context_name,"GLX context")

void V_GLOBAL
vglSwap()
{
	CALLER_NAME(vglSwap)
	gl_context_p ctx;
	IF_NO_GLCONTEXT(ctx)
		return;
	glXSwapBuffers(ctx->cn->dpy, ctx->wnd->wnd);
}

V_LOCAL u32_t V_CALL
x11_destroy_context(vhandle_t handle)
{
	gl_context_p ctx = (gl_context_p)handle;
	UNREF_EXIT(ctx);
	if(ctx->glx_context)
	{
		glXMakeCurrent(ctx->cn->dpy, None, NULL);
		glXDestroyContext(ctx->cn->dpy, ctx->glx_context);
		ctx->glx_context = NULL;
	}
	if(ctx->visual_info)
	{
		XFree(ctx->visual_info);
		ctx->visual_info = NULL;
	}
	ARCH_CLEAR_COMMON_GL_CONTEXT_FIELDS(ctx);
	x11_close_connection();
	memFreeObject(ctx);
	return 0;
}

void V_GLOBAL
vglDestroy(void)
{
	CALLER_NAME(vglDestroy)
	thread_data_p td = GetThreadData();
	vhandle_t ctx = td->gl_context;
	td->gl_context = NULL;
	if(ctx != LIBV_INVALID_HANDLE)
		libvCloseHandle(ctx,caller_name,gl_context_name,GL_CONTEXT_MAGIC);
}

V_LOCAL gl_context_p
alloc_context(void)
{
	gl_context_p ctx;
	ALLOC_OBJECT(ctx,gl_context_t,0,GL_CONTEXT_MAGIC);
	return ctx;
}

vboolean
vglInit(
	char *caption,
	int x, int y, int width, int height,
	vboolean fullscreen,
	vboolean can_resize,
	vboolean need_depth,
	vboolean need_stencil,
	vboolean need_dst_alpha)
{
	ARCH_CALLER_NAME(vglInit)
	GLfloat aspect;
	gl_context_p ctx = NULL;
	int visinfo_class;
	int attrib[64], *aptr = attrib;
	x11_display_connection_p cn;
	vglDestroy();
	ctx = alloc_context();
	if(ctx == LIBV_INVALID_HANDLE)
		return false;
	ctx->base.destroy = x11_destroy_context;
	cn = x11_open_connection();
	if(!cn)
	{
		memFreeObject(ctx);
		return false;
	}
	*aptr++ = GLX_RGBA;
	*aptr++ = GLX_DOUBLEBUFFER;
	*aptr++ = GLX_RED_SIZE;
	*aptr++ = 1;
	*aptr++ = GLX_GREEN_SIZE;
	*aptr++ = 1;
	*aptr++ = GLX_BLUE_SIZE;
	*aptr++ = 1;
	*aptr = None;
	if(need_depth)
	{
		*aptr++ = GLX_DEPTH_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	if(need_stencil)
	{
		*aptr++ = GLX_STENCIL_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	if(need_dst_alpha)
	{
		*aptr++ = GLX_ALPHA_SIZE;
		*aptr++ = 1;
		*aptr = None;
	}
	ctx->visual_info = glXChooseVisual(cn->dpy, cn->scrnum, attrib);
	if(!ctx->visual_info)
	{
		ARCH_ERROR("glXChooseVisual() failed");
		goto err_exit;
	}
#if defined(__cplusplus) || defined(c_plusplus)
	visinfo_class = ctx->visual_info->c_class;
#else
	visinfo_class = ctx->visual_info->class;
#endif
	if(visinfo_class != DirectColor && visinfo_class != TrueColor)
	{
		ARCH_ERROR("DirectColor or TrueColor visual required");
		goto err_exit;
	}
	ctx->glx_context =
		glXCreateContext(cn->dpy, ctx->visual_info, NULL, True);
	if(!ctx->glx_context)
	{
		ARCH_ERROR("glXCreateContext() failed");
		goto err_exit;
	}
	ctx->wnd = archWinOpenNP(NULL, ctx->visual_info,
		caption, x, y, width, height, !fullscreen, can_resize);
	if(!ctx->wnd)
		goto err_exit;
	archWinShow(ctx->wnd, true);
	XFlush(cn->dpy);
	if(!glXMakeCurrent(cn->dpy, ctx->wnd->wnd, ctx->glx_context))
	{
		ARCH_ERROR("glXMakeCurrent() failed");
		goto err_exit;
	}
	ctx->vendor = strDup((char_p)glGetString(GL_VENDOR));
	ctx->renderer = strDup((char_p)glGetString(GL_RENDERER));
	ctx->version = strDup((char_p)glGetString(GL_VERSION));
	ctx->extensions = strDup((char_p)glGetString(GL_EXTENSIONS));
	archWinPoll(ctx->wnd, false);
	aspect = (GLfloat)gl_context->wnd->width /
		(GLfloat)gl_context->wnd->height;
	glViewport(0, 0, gl_context->wnd->width, gl_context->wnd->height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-aspect, aspect, -1, 1, 1, 3);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	ctx->cn = cn;
	GetThreadData()->gl_context = ctx;
	return true;

err_exit:;
	x11_destroy_context(ctx);
	return false;
}
