/* gl.c */

#include <stdio.h>

#include <Xm/Xm.h>
#ifdef SUN
#include <Sgm/GlxMDraw.h>
#else /*SUN*/
#ifdef LINUX
#include <Xm/DrawingA.h>

#define Object	VOGL_Object
#define Boolean	VOGL_Boolean
#define String	VOGL_String
#include "vogl.h"
#define GL_VERTEX VERTEX
#undef VERTEX

extern XVisualInfo		best_visual;
extern XStandardColormap	std_cmap;

#endif /*LINUX*/
#endif /*SUN*/

static int glinited = 0;

#define GL_MATERIAL MATERIAL
#undef MATERIAL

#include "render.h"
#include "canvas.h"
#include "camera.h"
#include "scene.h"
#include "tvertelim.h"
#include "error.h"
#include "Memory.h"
#include "globals.h"

static float maximpoverarea;	/* nodig voor importance herschaling */

typedef struct RENDEROPTIONS {
	char	gouraud_shading,  /* True voor Gouraudshading, False voor flat shading */
		draw_outlines,	  /* True om randjes van facetten te tekenen */
	        showlinks,	  /* True om ook de links te laten zien */
	        backface_culling, /* True om backface_culling te doen */
	        mode;		  /* REFLECTIVITY, RADIOSITY, ... */
	RGB 	outline_color,	  /* kleur waarin randjes van facetten getekend worden */
	        link_color;	  /* kleur waarin links geteknd moeten worden */
} RENDEROPTIONS;

static COLOR ambient_radiance;

static RENDEROPTIONS renderopts;

void RenderSetOptions(char gouraud_shading, 
		      char backface_culling,
		      char draw_outlines, 
		      RGB *outline_color,
		      char showlinks,
		      RGB *link_color)
{
	renderopts.gouraud_shading = gouraud_shading;
	renderopts.backface_culling = backface_culling;
	renderopts.draw_outlines = draw_outlines;
	renderopts.outline_color = *outline_color;
	renderopts.showlinks = showlinks;
	renderopts.link_color = *link_color;
}

void RenderSetGouraudShading(char gouraud_shading)
{
	renderopts.gouraud_shading = gouraud_shading;	
}

void RenderSetBackfaceCulling(char backface_culling)
{
	renderopts.backface_culling = backface_culling;
}

void RenderSetOutlineDrawing(char draw_outlines)
{
	renderopts.draw_outlines = draw_outlines;
}

void RenderSetOutlineColor(RGB *outline_color)
{
	renderopts.outline_color = *outline_color;
}

void RenderShowLinks(char showlinks)
{
	renderopts.showlinks = showlinks;
}

void RenderSetLinkColor(RGB *link_color)
{
	renderopts.link_color = *link_color;
}

void RenderSetMode(char mode)
{
	renderopts.mode = mode;
}

char RenderGetMode(void)
{
	return renderopts.mode;
}

void RenderSetAmbientRadiance(COLOR *ambient)
{
	ambient_radiance = *ambient;
}

static long zmax;	/* Z value to clear Z buffer with */

static Matrix idmat = {{1.0, 0.0, 0.0, 0.0},
                       {0.0, 1.0, 0.0, 0.0},
                       {0.0, 0.0, 1.0, 0.0},
                       {0.0, 0.0, 0.0, 1.0}};

void RenderClearWindow(void)
{
	long bkgcolor;

	bkgcolor =  (unsigned char)(Camera.background.r * 255.) |
		   ((unsigned char)(Camera.background.g * 255.) << 8 ) |
		   ((unsigned char)(Camera.background.b * 255.) << 16);

	czclear(bkgcolor, zmax);
}

/* bepaal afstand tot front- en backclipping plane */
void RenderGetNearFar(float *near, float *far)
{
	BOUNDINGBOX bounds;
	VECTOR b[2], d;
	int i, j, k;
	float z;

	if (!World) {
		*far = 10.; *near = 0.1;	/* zomaar iets */
		return;
	}
	GeomListBounds(World, bounds);

	b[0] = *(VECTOR *)&bounds[MIN_X];
	b[1] = *(VECTOR *)&bounds[MAX_X];

	*far = -HUGE; *near = HUGE;
	for (i=0; i<=1; i++)
		for (j=0; j<=1; j++)
			for (k=0; k<=1; k++) {
				VECTORSET(d, b[i].x, b[j].y, b[k].z);
				VECTORSUBSTRACT(d, Camera.eyep, d);
				z = VECTORDOTPRODUCT(d, Camera.Z);

				if (z > *far) *far = z;
				if (z < *near) *near = z;
			}

/* 2% naar voor erbij nemen omdat op SUN contouren van polygonen wat naar voor verschoven
 * worden om alias effecten te vermijden (zie verder RenderElementOutline() */
	*far += EPSILON; *near -= 0.02 * (*near);
	if (*far < EPSILON) *far = Camera.viewdist;
	if (*near < EPSILON) *near = Camera.viewdist/100.;
}

static void RenderFixUpTransform(void)
{
	float d, t;
	VECTOR up=Camera.updir;
	VectorNormalize(&up);

/* push the transforms in reverse order */
	t = acos(up.y) * 180. / M_PI;
	rot(t, 'z');

	d = 1. - up.y*up.y;
	if (d > EPSILON) {
		t = acos(up.x/sqrt(d)) * 180. / M_PI;
		if (up.z < 0.)
			t = -t;
		rot(t, 'y');
	}
}

static void RenderFixUpPoint(POINT *src, POINT *dest)
{
	POINT tmp;
	float d, t;
	VECTOR up=Camera.updir;
	VectorNormalize(&up);

	d = 1. - up.y*up.y;
	if (d > EPSILON) {
		t = acos(up.x/sqrt(d));
		if (up.z < 0.)
			t = -t;

/*		rot(t, 'y'); */
		tmp.z = cos(t) * src->z - sin(t) * src->x;
		tmp.x = sin(t) * src->z + cos(t) * src->x;
		tmp.y = src->y;
	} else
		tmp = *src;

	t = acos(up.y);
/*	rot(t, 'z'); */
	dest->x = cos(t) * tmp.x - sin(t) * tmp.y;
	dest->y = sin(t) * tmp.x + cos(t) * tmp.y;
	dest->z = tmp.z;
}

void RenderSetCamera(void)
{
	POINT eyep, lookp;

	RenderClearWindow();

	loadmatrix(idmat);	/* dan staat er zeker iets zinnigs op de matrix stack */

/* viewport instellen: het volledige window gebruiken */
	viewport(0, Camera.hres-1, 0, Camera.vres-1);

/* bepaald afstand tot front- en backclipping vlak */
	RenderGetNearFar(&Camera.near, &Camera.far);

/* fov * 2 omdat GL een ander gedacht heeft over fov dan wij en *10 omdat perspective() 
 * fov in tienden van graden wil: fov=450 = 45 graden */
	perspective(Camera.vfov*20., (float)Camera.hres/(float)Camera.vres,
		    Camera.near, Camera.far); 

/* GL assumes that up is along the positive Y axis, convert our idea of up */
	RenderFixUpPoint(&Camera.eyep, &eyep);
	RenderFixUpPoint(&Camera.lookp, &lookp);

	lookat(eyep.x, eyep.y ,eyep.z,
	       lookp.x, lookp.y, lookp.z,
	       0.0);

	RenderFixUpTransform();
}

static void GLinitCallback(Widget canvas, XtPointer client_data, XtPointer call_data)
{
#ifndef LINUX
	float lmprops[4];
#endif /*LINUX*/

#ifdef LINUX
	if (!votc_xt_window(XtDisplay(canvas), XtWindow(canvas), &best_visual, &std_cmap, Camera.hres, Camera.vres)) {
		fprintf(stderr, "Failed to initialize the X11TC driver.\n");
		exit(1);
	}

	ginit();
	RGBmode();
	doublebuffer();
	vsetflush(0);
fprintf(stderr, "vogl initialized.\n");
#endif /*LINUX*/

	zfunction(ZF_LEQUAL);
	zmax = getgdesc(GD_ZMAX);  /* waarde waarmee Z buffer gewist wordt */

	zbuffer(1);		/* Z buffering aanzetten */
	frontbuffer(1);		/* teken tegelijk ook in de zichtbare buffer - voor bvb
				   uitvoer tijdens berekeningen. */

#ifndef LINUX
/* belichtingsmodel voor visualisatie van radiositeitsscenes is heel eenvoudig:
 * enkel een ambiente lichtbron met intensiteit (1,1,1) gebruiken */
	lmprops[0] = AMBIENT;
	lmprops[1] = 1.0;
	lmprops[2] = 1.0;
	lmprops[3] = 1.0;
	lmdef(DEFLMODEL, 1, 4, lmprops);
	lmbind(LMODEL, 1);
#endif /*LINUX*/

#ifdef LINUX
	XtRemoveCallback(canvas, XmNexposeCallback, GLinitCallback, (XtPointer)NULL);
#endif /*LINUX*/

	glinited = 1;
}

/* open window for rendering */
Widget RenderCreateWindow(Widget parent)
{
	Widget canvas;
	Dimension hres, vres;
#ifndef LINUX
	static GLXconfig sdesc[] = {
	{GLX_NORMAL, GLX_DOUBLE	, True},	/* window met double buffering */
	{GLX_NORMAL, GLX_RGB	, True},	/* window in RGB kleurenmode */
	{GLX_NORMAL, GLX_ZSIZE	, GLX_NOCONFIG},	/* max. aantal Z planes */
	{0         , 0		, 0}
	};
	Arg args[2];

	XtSetArg(args[0], GlxNglxConfig, sdesc);

	canvas = GlxCreateMDraw(parent, "canvas", args, 1);
	XtManageChild(canvas);
#else /*LINUX*/
	canvas = XtVaCreateManagedWidget("canvas",
					 xmDrawingAreaWidgetClass,
					 parent,
					 NULL);
#endif /*LINUX*/

	XtVaGetValues(canvas,
		      XmNwidth, &hres,
		      XmNheight, &vres,
		      NULL);
	Camera.hres = hres;
	Camera.vres = vres;

#ifndef LINUX
/* window wordt gecreeerd */
	XtAddCallback(canvas, GlxNginitCallback, GLinitCallback, (XtPointer)NULL);
#else /*LINUX*/
	XtAddCallback(canvas, XmNexposeCallback, GLinitCallback, (XtPointer)NULL);
#endif /*LINUX*/

/* window wordt zichbaar */
	XtAddCallback(canvas, XmNexposeCallback, CanvasExposeCallback, (XtPointer)NULL);

/* window resizes */
	XtAddCallback(canvas, XmNresizeCallback, CanvasResizeCallback, (XtPointer)NULL);

#ifdef NEVER
	XtAddEventHandler(canvas, 
			  ExposureMask,
			  False,	/* geen non-maskable event */
			  (XtEventHandler)CanvasExposeEvent,
			  (XtPointer)NULL);	/* client_data */
#endif

/* muis bewegingen */
	XtAddEventHandler(canvas, 
			  ButtonPressMask | ButtonReleaseMask | ButtonMotionMask,
			  False,	/* geen non-maskable event */
			  (XtEventHandler)CanvasMouseEvent,
			  (XtPointer)NULL);	/* client_data */

	return canvas;
}

/* deze routines zetten geen kleur waarin getekend moet worden */
void RenderElementOutline(PATCH *patch)
{
#ifndef SUN
	int i;

	c3f((float *)&renderopts.outline_color);
	bgnclosedline();
	for (i=0; i<patch->nrvertices; i++) 
		v3f((float *)patch->vertex[i]->point);
	endclosedline();
#else /*SUN*/
	int i;
	POINT tmp; VECTOR dir;

	c3f((float *)&renderopts.outline_color);
	bgnclosedline();
	for (i=0; i<patch->nrvertices; i++) {
		VECTORSUBSTRACT(Camera.eyep, *patch->vertex[i]->point, dir);
		VECTORSUMSCALED(*patch->vertex[i]->point, 0.01, dir, tmp);
		v3f((float *)&tmp);
	}
	endclosedline();
#endif /*SUN*/
}

void RenderElementSolid(PATCH *patch)
{
	int i;

	bgnpolygon();
	for (i=0; i<patch->nrvertices; i++) 
		v3f((float *)patch->vertex[i]->point);
	endpolygon();
}

void RenderElementSolidOutline(PATCH *patch)
{
#ifndef SUN
	zwritemask(0x0);
#endif /*SUN*/
	RenderElementSolid(patch);
	RenderElementOutline(patch);
#ifndef SUN
#ifndef LINUX
	zwritemask(0xffffff);
#else
	zwritemask(0xffffffff);
#endif
	wmpack(0x0);

	RenderElementSolid(patch);

	wmpack(0xffffffff);
#endif /*SUN*/
}

void RenderTElementGouraud(TPATCH *tpatch)
{
#ifndef LINUX
	bgntmesh();
#else
	bgnpolygon();
#endif
	c3f((float *)&tpatch->tvertex[0]->color);
	v3f((float *)tpatch->tvertex[0]->point);
	c3f((float *)&tpatch->tvertex[1]->color);
	v3f((float *)tpatch->tvertex[1]->point);
	c3f((float *)&tpatch->tvertex[2]->color);
	v3f((float *)tpatch->tvertex[2]->point);
#ifndef LINUX
	endtmesh();
#else
	endpolygon();
#endif
}

/* kleur van de vertices zijn vooraf bepaald */
void RenderElementGouraud(PATCH *patch)
{
	int i, j;

	if (patch->Tpatches && GetTVertexElimination() == TRUE) {
		TPatchListIterate(patch->Tpatches, RenderTElementGouraud);
		return;
	}

#ifndef LINUX
/* teken veelhoek als reeks aansluitende driehoekjes (triangle mesh) om
 * shading artefacten met >3-hoeken te vermijden - werkt niet voor niet-convexe
 * veelhoeken !! */
	bgntmesh();
	switch (patch->nrvertices) {
	case 3:
		c3f((float *)&patch->vertex[0]->color);
		v3f((float *)patch->vertex[0]->point);
		c3f((float *)&patch->vertex[1]->color);
		v3f((float *)patch->vertex[1]->point);
		c3f((float *)&patch->vertex[2]->color);
		v3f((float *)patch->vertex[2]->point);
		break;
	case 4:
		c3f((float *)&patch->vertex[0]->color);
		v3f((float *)patch->vertex[0]->point);
		c3f((float *)&patch->vertex[1]->color);
		v3f((float *)patch->vertex[1]->point);
		c3f((float *)&patch->vertex[3]->color);
		v3f((float *)patch->vertex[3]->point);
		c3f((float *)&patch->vertex[2]->color);
		v3f((float *)patch->vertex[2]->point);
		break;
	default:
		for (i=0, j=patch->nrvertices-1; i<j; i++, j--) {
			c3f((float *)&patch->vertex[i]->color);
			v3f((float *)patch->vertex[i]->point);

			if (i < j) {
				c3f((float *)&patch->vertex[j]->color);
				v3f((float *)patch->vertex[j]->point);
			}
		}
	}
	endtmesh();
#else /*LINUX*/
	bgnpolygon();
	for (i=0; i<patch->nrvertices; i++) {
		c3f((float *)&patch->vertex[i]->color);
		v3f((float *)patch->vertex[i]->point);
	}
	endpolygon();
#endif /*LINUX*/
}

void RenderElementGouraudOutline(PATCH *patch)
{
#ifndef SUN
	zwritemask(0x0);
#endif /*SUN*/
	RenderElementGouraud(patch);

	c3f((float *)&renderopts.outline_color);
	RenderElementOutline(patch);
#ifndef SUN
#ifndef LINUX
	zwritemask(0xffffff);
#else
	zwritemask(0xffffffff);
#endif
	wmpack(0x0);

	RenderElementSolid(patch);

	wmpack(0xffffffff);
#endif /*SUN*/
}

/* onderstaande routines bepalen wel zelf de kleur waarin getekend moet worden */
void RenderSetColor(PATCH *patch)
{
	static RGB rgb;
	static COLOR color;

	switch (renderopts.mode) {
	case RENDER_REFLECTIVITY:
		color = patch->surface->material->Kd;
		ColorToRGB(color, &rgb);
		RGBGammaCorrect(&rgb);
		c3f((float *)&rgb);
		break;
	case RENDER_ID:
		cpack((unsigned long)patch->id&0xffffff);
		break;
	case RENDER_RADIANCE:
		color = patch->basis->GetPower(patch);
		COLORABS(color, color);
		COLORSCALEINVERSE(M_PI*patch->area, color, color);
		if (render_ambient) {
			COLOR a;
			COLORPROD(patch->surface->material->Kd, ambient_radiance, a);
			COLORADD(color, a, color);
		}
		c3f((float *)RadianceToRGB(color, &rgb));
		break;
	case RENDER_IMPORTANCE:
		color = patch->basis->GetImportance(patch);
		COLORABS(color, color);
		COLORSCALEINVERSE(patch->area, color, color);
		c3f((float *)RadianceToRGB(color, &rgb));
		break;
	case RENDER_UNSHOT_RADIANCE:	
		color = patch->basis->GetUnshotPower(patch);
		COLORABS(color, color);
		COLORSCALEINVERSE(M_PI*patch->area, color, color);
		c3f((float *)RadianceToRGB(color, &rgb));
		break;
	case RENDER_UNSHOT_IMPORTANCE:
		color = patch->basis->GetUnshotImportance(patch);
		COLORABS(color, color);
		COLORSCALEINVERSE(patch->area, color, color);
		c3f((float *)RadianceToRGB(color, &rgb));
		break;
	default:
		Fatal(3, "RenderSetColor", "Invalid rendering mode");
	}
}

void RenderElementFlat(PATCH *patch)
{
	RenderSetColor(patch);
	RenderElementSolid(patch);
}

void RenderElementFlatOutline(PATCH *patch)
{
	RenderSetColor(patch);
	RenderElementSolidOutline(patch);
}

/* filled in in RenderScene() */
void (*RenderElement)(PATCH *) = RenderElementFlat;
void (*RenderPatch)(PATCH *) = RenderElementFlat;

void RenderPatchRecursive(PATCH *patch)
{
	if (!patch->subpatches) 
		RenderElement(patch);
	else
		PatchListIterate(patch->subpatches, RenderPatchRecursive);
}

/* switches backfaceculling off before rendering and on after for twosided patches */
static void DoRenderPatch(PATCH *patch)
{
	if (patch->twosided)
		backface(FALSE);

	RenderPatch(patch);

	if (patch->twosided)
		backface(renderopts.backface_culling ? TRUE : FALSE);
}

void RenderLink(INTERACTION *PQ)
{
	PATCH *P = PQ->P, *Q = PQ->Q;

	move(P->midpoint.x, P->midpoint.y, P->midpoint.z);
	draw(Q->midpoint.x, Q->midpoint.y, Q->midpoint.z);
}

void PatchRenderLinks(PATCH *patch)
{
	c3f((float *)&renderopts.link_color);
	InteractionListIterate(patch->interactions, RenderLink);
	PatchListIterate(patch->subpatches, PatchRenderLinks);
}

void RenderLinks(void)
{
	PatchListIterate(Patches, PatchRenderLinks);
}

/* nodig voor importance herschaling */
static void RenderSetImportanceRescaleFactor(void)
{
	PATCHLIST *patches = Patches;
	PATCH *P;
	float impoverarea;
	COLOR imp;

	maximpoverarea = 0;
	while ((P = PatchListNext(&patches))) {
		imp = P->basis->GetImportance(P);
		impoverarea = COLORMAXCOMPONENT(imp)/P->area;
		if (impoverarea > maximpoverarea)
			maximpoverarea = impoverarea;
	}

/* kan gebeuren als geen importance gebruikt wordt en een
 * gebruiker vraagt toch importance te renderen */
	if (maximpoverarea < EPSILON) maximpoverarea = 1.;
	SetRadianceRescaleFactor(maximpoverarea/2.);
}

/* nodig voor radiantie herschaling */
static void RenderSetRadianceRescaleFactor(void)
{
/* radiance_rescale is gedefinieerd in globals.[hc] en wordt
 * berekend in InitRadianceComputation() in radiance.c onmiddelijk
 * na het inladen van een scene */
	SetRadianceRescaleFactor(radiance_rescale);
}

void RenderScene(void)
{
	if (!glinited) 
		return;

	CanvasPushMode(CANVASMODE_RENDER);

	backbuffer(1);
	frontbuffer(0);	/* alleen in onzichtbare buffer renderen */

	RenderSetCamera();

	shademodel(renderopts.gouraud_shading ? GOURAUD : FLAT);
	backface(renderopts.backface_culling ? TRUE : FALSE);

	switch (renderopts.mode) {
	case RENDER_REFLECTIVITY:
		shademodel(FLAT);
		RenderPatch = renderopts.draw_outlines ? 
			RenderElementFlatOutline :
			RenderElementFlat;
		break;
	case RENDER_IMPORTANCE:
	case RENDER_UNSHOT_IMPORTANCE:
		shademodel(FLAT);
		RenderPatch = renderopts.draw_outlines ? 
			RenderElementFlatOutline :
			RenderElementFlat;
		RenderSetImportanceRescaleFactor();
		break;
	case RENDER_ID:
		shademodel(FLAT);
		RenderPatch = RenderPatchRecursive;
		RenderElement = renderopts.draw_outlines ? 
			RenderElementFlatOutline :
			RenderElementFlat;
		break;
	case RENDER_UNSHOT_RADIANCE:
		shademodel(FLAT);
		RenderPatch = RenderPatchRecursive;
		RenderElement = renderopts.draw_outlines ? 
			RenderElementFlatOutline :
			RenderElementFlat;
		RenderSetRadianceRescaleFactor();
		break;
	case RENDER_RADIANCE:
		RenderPatch = RenderPatchRecursive;
		RenderElement = renderopts.gouraud_shading ?
			(renderopts.draw_outlines ? RenderElementGouraudOutline :
			                            RenderElementGouraud) :
			(renderopts.draw_outlines ? RenderElementFlatOutline :
			                            RenderElementFlat);
		RenderSetRadianceRescaleFactor();
		break;
	default:
		Fatal(3, NULL, "Invalid rendering mode.\n");
	}

	PatchListIterate(Patches, DoRenderPatch);

	if (renderopts.showlinks)
		RenderLinks();

	swapbuffers(); 

	backbuffer(0);
	frontbuffer(1);	/* alles wat buiten RenderScene() getekend wordt, wordt enkel in 
			   de zictbare buffer gerenderd */

	CanvasPullMode();
}

void RenderPixels(int x, int y, int n, RGB *rgb)
{
	int i;
	unsigned long *c;

	c = (unsigned long *)Alloc(n * sizeof(unsigned long));

	for (i=0; i<n; i++) {
		c[i] = ((unsigned char)(rgb[i].r * 255.)) |
		      (((unsigned char)(rgb[i].g * 255.)) << 8) |
		      (((unsigned char)(rgb[i].b * 255.)) << 16);
	}

	lrectwrite(x, y, x+n-1, y, c);

	Free((char *)c, n * sizeof(unsigned long *));
}

unsigned long *GetScreenBuffer(long *x, long *y)
{
	unsigned long *screen;

	getsize(x, y);
	screen = (unsigned long *)Alloc((*x) * (*y) * sizeof(unsigned long));
	lrectread(0, 0, *x-1, *y-1, screen);
	return screen;
}

void SaveScreen(FILE *fp)
{
	unsigned long *screen, *pixel;
	long i, j, x, y;

	readsource(SRC_FRONT);
	screen = GetScreenBuffer(&x, &y);

	fprintf(fp, "P6\n%ld %ld\n255\n", x, y);
	for (j=y-1; j>=0; j--) 
		for (i=0, pixel=screen+j*x; i<x; i++, pixel++) {
			putc((*pixel)&0xff, fp);
			putc(((*pixel)&0xff00)>>8, fp);
			putc(((*pixel)&0xff0000)>>16, fp);
		}

	Free((char *)screen, x * y * sizeof(unsigned long));
}

static void RenderPatchID(PATCH *patch)
{
	if (!patch->subpatches) { 
		cpack(((unsigned long)patch->id)&0xffffff);
		RenderElementSolid(patch);
	} else
		PatchListIterate(patch->subpatches, RenderPatchID); 
}

unsigned long *GetIDs(long *x, long *y)
{
	unsigned long *ids;

#ifdef NEVER
/* laat het hele gedoe zien in demo mode, maar doe het onzichtbaar indien
 * niet in demo mode */
	if (demo) {
		backbuffer(0);
		frontbuffer(1);	/* alleen in zichtbare buffer renderen */
	} else {
#endif
		backbuffer(1);
		frontbuffer(0);	/* alleen in onzichtbare buffer renderen */
#ifdef NEVER
	}
#endif

	RenderSetCamera();

	shademodel(FLAT);
	backface(TRUE);

	PatchListIterate(Patches, RenderPatchID);

#ifdef NEVER
	if (demo) 
		readsource(SRC_FRONT);
	else
#endif
		readsource(SRC_BACK);
	ids = GetScreenBuffer(x, y);

	backbuffer(0);
	frontbuffer(1);	/* alleen in zichtbare buffer renderen */

	return ids;
}





