#include <v_lib.h>

/*
 *	OpenGL feedback demo
 */

/* -------------------------------------------------------------------- */

struct dev_s
{
	gl_tl_callbacks_t cbs;
	FILE *out;
	int count;
};

void
dump_tl(FILE *out,vec3_t v,color4b_t c,vec2_t uv)
{
	fprintf(out,
		"[%3.2f,%3.2f,%3.2f]-(%d,%d,%d,%d)-{%3.2f,%3.2f}",
		v[0],v[1],v[2],
		c[0],c[1],c[2],c[4],
		uv[0],uv[1]);
}

void	V_CALL 
point(void *dev,vec3_t v,color4b_t c,vec2_t uv)
{
	struct dev_s *self=(struct dev_s*)dev;
	fprintf(self->out,"POINT {\n\t");
	dump_tl(self->out,v,c,uv);
	fprintf(self->out,"\n}\n");
}

void	V_CALL
line(void *dev,vec3_t v1,color4b_t c1,vec2_t uv1,
	vec3_t v2,color4b_t c2,vec2_t uv2)
{
	struct dev_s *self=(struct dev_s*)dev;
	fprintf(self->out,"LINE {\n\t");
	dump_tl(self->out,v1,c1,uv1);
	fprintf(self->out,"\n\t");
	dump_tl(self->out,v2,c2,uv2);
	fprintf(self->out,"\n}\n");
}

void	V_CALL
begin_polygon(void *dev,int n)
{
	struct dev_s *self=(struct dev_s*)dev;
	self->count=n;
	fprintf(self->out,"POLYGON(%d) {\n",n);
}

void	V_CALL
polygon_vertex(void *dev,vec3_t v,color4b_t c,vec2_t uv)
{
	struct dev_s *self=(struct dev_s*)dev;
	fprintf(self->out,"\t");
	dump_tl(self->out,v,c,uv);
	fprintf(self->out,"\n");
	if(!--self->count)
		fprintf(self->out,"}\n");
}

void	V_CALL
pass_through(void *dev,vec_t v)
{
	struct dev_s *self=(struct dev_s*)dev;
	fprintf(self->out,"PASS_THROUGH { %g }\n",v);
}

struct dev_s dev =
{
	{
		point,
		line,
		begin_polygon,
		polygon_vertex,
		pass_through
	},
	NULL,
	0
};

/* -------------------------------------------------------------------- */

#define	WIDTH		128
#define	HEIGHT		128

void draw(int mode)
{
	glBegin(mode);
		glColor4f(1,1,0,.5f);
		glTexCoord2f(0,0);
		glVertex3f(-0.2f,	.5f,	1.0f);
		
		glColor4f(0,1,1,.5f);
		glTexCoord2f(2,0);
		glVertex3f(.9f, .1f, 0);
		
		glColor4f(1,0,1,.5f);
		glTexCoord2f(2,0);
		glVertex3f(.9f,.9f, 0);
	glEnd();
}

void redraw(void)
{
	u8_t image[16]=
	{
		0x80,0x90,0xff,0xff,0xff,0xe0,0xd0,0xc0,
		0xc0,0xd0,0xe0,0xff,0xff,0xff,0x90,0x80
	};

	glClearColor(.5f,.6f,.6f,0);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0,1,1,0,-1,1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	glClear(GL_COLOR_BUFFER_BIT);
	
	glTexImage1D(GL_TEXTURE_1D,0,1,16,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,
		image);
	glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_1D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexEnvf(GL_TEXTURE_1D,GL_TEXTURE_ENV_MODE,GL_DECAL);
	glTexEnvf(GL_TEXTURE_1D,GL_TEXTURE_WRAP_T,GL_REPEAT);
	glTexEnvf(GL_TEXTURE_1D,GL_TEXTURE_WRAP_S,GL_REPEAT);

	glEnable(GL_TEXTURE_1D);
	glPassThrough(1);
	draw(GL_TRIANGLES);	/* there will be two triangles after clipping */
	glDisable(GL_TEXTURE_1D);
	glLineWidth(2.0f);
	glPassThrough(2);
	draw(GL_LINE_LOOP);
	glPointSize(4.0f);
	glEnable(GL_POINT_SMOOTH);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	glPassThrough(3);
	draw(GL_POINTS); /* first point will be clipped out */

	vglSwapBuffers();
}

void mem_stats(char *at)
{
	u32_t amount, blocks, handles;
	memStats(&amount,&blocks,&handles);
	printf("AT '%s': total %u, blocks %d, handles %u\n",
		at,amount,blocks,handles);
}

int main()
{
	GLfloat *fb;
	u32_t num;
	u8_t *ptr;
	
	dev.out=fopen("out.txt","wb");
	fprintf(dev.out,"# FORMAT: [geometry vertex]-(RGBA vertex)-{UV vertex}\n");
	
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
	/* Draw image to file */
	vglCreateMappedWindow(WIDTH,HEIGHT);
	redraw();
	ptr=vglReadPixels(NULL,NULL);
	tgaSave("out.tga",WIDTH,HEIGHT,ptr);
	memFree(ptr);
	
	/* capture lit & clipped triangles */
	fb=vglBeginFeedback(1000);
	redraw();
	vglEndFeedback(&num);
	vglDecodeFeedback(&dev.cbs,&dev,fb,num);
	memFree(fb);

	vglDestroyWindow(vglGetCurrentWindow());

	fclose(dev.out);
	
	logStopConsoleLog();
	
	mem_stats("exit");
	return 0;
}
