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

#ifdef	ARCH_WINDOWING_SUPPORTED

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->wnd->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->wnd->cn->dpy, None, NULL);
		glXDestroyContext(ctx->wnd->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 i;
	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;
	width = ctx->wnd->width;
	height = ctx->wnd->height;
	archWinShow(ctx->wnd, true);
	XFlush(cn->dpy);
	if(fullscreen)
	{
		for(i = 0; i < ctx->wnd->cn->num_vidmodes; i++)
		{
			vidmode_p mode = ctx->wnd->cn->vidmodes + i;
			if((int)mode->width == width && (int)mode->height == height)
			{
				if(!archWinSetVidMode(ctx->wnd, i))
				{
					ARCH_ERROR("archWinSetVidMode() failed");
					goto err_exit;
				}
				break;
			}
		}
		if(i == ctx->wnd->cn->num_vidmodes)
		{
			ARCH_ERROR("required video mode not found");
			goto err_exit;
		}
	}
	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));
#ifdef	ARCH_VERBOSE
	conlPrintf(LOG_TRACE,"%s(): %s OpenGL on %s ver. %s.\n",
		arch_caller_name,ctx->vendor,ctx->renderer,ctx->version);
#endif	/* ARCH_VERBOSE */
	archWinPoll(ctx->wnd, false);
	aspect = (GLfloat)ctx->wnd->width / (GLfloat)ctx->wnd->height;
	glViewport(0, 0, ctx->wnd->width, ctx->wnd->height);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-aspect, aspect, -1, 1, 1, 3);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	GetThreadData()->gl_context = ctx;
	return true;

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

#endif	/* ARCH_WINDOWING_SUPPORTED */

