#include <v_lib.h>

/*
 * Port from glos-lvga.c
 */

/*
#define HIRES
*/

#define MEDRES

/*
 * Resolution of graphical screen - the only four lines to change:
 */
#if     defined(HIRES)

/*
 * Use desktop default dimensions
 */
#define WIDTH           0
#define HEIGHT          0
#define	REFRESH			100

#elif   defined(MEDRES)

#define WIDTH           640
#define HEIGHT          480
#define	REFRESH			100

#else

#define WIDTH           320
#define HEIGHT          240
#define	REFRESH			75

#endif

#define	NUM_PTS	20000

unsigned flips_counter;

void rotate_quad()
{
	int i;
	for(i=0;i<100;i++)
	{
		glClear(GL_COLOR_BUFFER_BIT);

		glBegin(GL_QUADS);
			glColor3f(1,1,1);
			glTexCoord2f(-1,-1);
			glVertex2f(1,1);
			glColor3f(1,1,0);
			glTexCoord2f(1,-1);
			glVertex2f(-1,1);
			glColor3f(1,0,1);
			glTexCoord2f(1,1);
			glVertex2f(-1,-1);
			glColor3f(0,1,1);
			glTexCoord2f(-1,1);
			glVertex2f(1,-1);
		glEnd();

		glRotatef(2,1,0,0);
		glRotatef(1,0,1,0);
		glMatrixMode(GL_TEXTURE);
		glRotatef(1,0,0,1);
		glMatrixMode(GL_MODELVIEW);

		flips_counter++;
		vglSwapBuffers();
	}
}

void load_and_enable_texture()
{
	int i,j,cell_x, cell_y;
	unsigned char nr, ng, nb,luma,rgba_texels[16][16][4];
	/* Generate 2x2 rgba checker texture */
	/* Note: instead, we can use luminance+alpha texture, but Mesa (4.0)
	 * implementation works better with RGBA */
	for(i=0;i<16;i++)
	{
		cell_y = i >> 3;
		for(j=0;j<16;j++)
		{
			cell_x = j >> 3;
			luma = (u8_t)((cell_y + cell_x) & 1 ? 80 : 200);
			if(luma > 0x7F)
			{
				/* cyan noise */
				nr = 0;
				ng = (u8_t)(30 - (rand() % 40));
				nb = ng;
			}
			else
			{
				/* bright green noise */
				nr = nb = 0;
				ng = (u8_t)(50 - (rand() % 40));
			}
			rgba_texels[i][j][0]=(u8_t)(nr + luma);
			rgba_texels[i][j][1]=(u8_t)(ng + luma);
			rgba_texels[i][j][2]=(u8_t)(nb + luma);
			rgba_texels[i][j][3]=(u8_t)(luma > 0x80 ? 255 : 0);
		}
	}
	/* Load texture and set texture parameters */
	glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,16,16,0,
		GL_RGBA,GL_UNSIGNED_BYTE,rgba_texels);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	glEnable(GL_TEXTURE_2D);
}

GLfloat float_rand(GLfloat range_min,GLfloat range_max)
{
	GLfloat num = (GLfloat)(rand() >> 1);
	GLfloat rn = num / (GLfloat)(RAND_MAX >> 1);
	return range_min + rn * (range_max - range_min);
}

GLuint create_starfield(GLfloat radius)
{
	int i;
	GLfloat x,y,z;
	/* Create set of points distributed inside sphere */
	GLuint starfield=glGenLists(1);
	glNewList(starfield,GL_COMPILE);
	glBegin(GL_POINTS);
	{
		glColor4f(1,1,1,.5f);
		for(i=0;i<NUM_PTS;)
		{
			x=float_rand(-radius, radius);
			y=float_rand(-radius, radius);
			z=float_rand(-radius, radius);
			if((x*x + y*y + z*z) <= radius * radius)
			{
				glVertex3f(x,y,z);
				i++;
			}
		}
	}
	glEnd();
	glEndList();
	return starfield;
}

unsigned get_time_milliseconds(void)
{
	return timeTickCount();
}

unsigned start_time;

void before_test()
{
	start_time = get_time_milliseconds();
	flips_counter = 0;
}

void after_test(char *test_name)
{
	start_time = get_time_milliseconds() - start_time;
	printf("Test '%s' complete: %u ms, %4.2f fps.\n",test_name,
		start_time,
		1000 * (float)flips_counter / (float)start_time);
}

int main()
{
	int i;
	GLuint starfield;
	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	/*
	if(vglCreateFullscreenWindow("Simple perf test",WIDTH,HEIGHT,0,REFRESH) == LIBV_INVALID_HANDLE)
		return -1;
	*/
	if(vglCreateWindow("Simple perf test",0,0,WIDTH,HEIGHT) == LIBV_INVALID_HANDLE)
		return -1;
	glClearColor(0.3f,0,.4f,.5f);
	/* Test 1 - starfield */
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(-4.0/3.0,4.0/3.0,-1,1,-1,1);
	starfield = create_starfield(1);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
	glEnable(GL_POINT_SMOOTH);
	glPointSize(2);
	glScalef(.8f,.8f,.8f);
	before_test();
	for(i=0;i<100;i++)
	{
		glClear(GL_COLOR_BUFFER_BIT);
		glCallList(starfield);
		glRotatef(1,1,0,0);
		glRotatef(2,0,1,0);

		flips_counter++;
		vglSwapBuffers();
	}
	after_test("points");
	glDisable(GL_POINT_SMOOTH);
	glDisable(GL_BLEND);
	/* Test 2 - Gouraud - shaded quad */
	glLoadIdentity();
	glScalef(.7f,.7f,.7f);
	before_test();
	rotate_quad();
	after_test("smooth-shaded quad");
	/* Test 3 - Textured quad */
	load_and_enable_texture();
	before_test();
	rotate_quad();
	after_test("textured quad");
	/* Test 3 - Texture - modulated quad */
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	before_test();
	rotate_quad();
	after_test("textured GL_MODULATEd quad");
	/* Same as above, but with linear filtering */
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
	before_test();
	rotate_quad();
	after_test("linear-filtered textured quad");
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
	before_test();
	rotate_quad();
	after_test("linear-filtered textured GL_MODULATEd quad");
	/* wait for Enter */
	{ input_record_t rc;
	do {
		
		for(vglNextEvent(&rc);;vglNextEvent(&rc))
			if(rc.event == ev_key_down)
				break;
	} while(rc.event != ev_key_down); }
	glDeleteLists(starfield,1);
	vglDestroyWindow(vglGetCurrentWindow());
	return 0;
}
