#include <v_lib.h>

void upload()
{
	static GLfloat tex[] = {
		1,.5f,1,.6f,
		.3f,1,.2f,1,
		1,.2f,1,.3f,
		.6f,1,.5f,1
	};
	glTexImage2D(GL_TEXTURE_2D,0,1,4,4,0,GL_LUMINANCE,GL_FLOAT,tex);
	glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
}

GLuint quad, cube;

vboolean init()
{
	if(!vglInit("Multitexture: separate texture matrices",
			0,0,800,600,true,false,true,false,false))
		return false;
	vglGetVersionString(); /* FIXME */
	V_ASSERT(glActiveTextureARB); /* BUGBUG */

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glFrustum(-133,133,-100,100,200,600);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glActiveTextureARB(GL_TEXTURE0_ARB);
	upload();
	glEnable(GL_TEXTURE_2D);

	glActiveTextureARB(GL_TEXTURE1_ARB);
	upload();
	glEnable(GL_TEXTURE_2D);

	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
	glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);

	quad = glGenLists(1);
	cube = glGenLists(1);
	
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	
	glNewList(quad,GL_COMPILE);
		glColor3f(0.95f,0.8f,1);
		glActiveTextureARB(GL_TEXTURE0_ARB);
		glEnable(GL_TEXTURE_2D);
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glEnable(GL_TEXTURE_2D);
		glBegin(GL_QUADS);
			/*
			 * The texcoords are _idential_ for both units.
			 */
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB,-1,-1);
			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,-1,-1);
			glVertex2f(1,1);
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB,1,-1);
			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,1,-1);
			glVertex2f(-1,1);
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB,1,1);
			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,1,1);
			glVertex2f(-1,-1);
			glMultiTexCoord2fARB(GL_TEXTURE0_ARB,-1,1);
			glMultiTexCoord2fARB(GL_TEXTURE1_ARB,-1,1);
			glVertex2f(1,-1);
		glEnd();
	glEndList();

	glNewList(cube,GL_COMPILE);
		glPushMatrix();
		glPushMatrix();
		
		glTranslatef(0,0,1);
		glCallList(quad);
		glTranslatef(0,0,-2);
		glRotatef(180,1,0,0);
		glCallList(quad);
		glRotatef(90,1,0,0);
		glTranslatef(0,-1,1);
		glCallList(quad);
		glRotatef(90,0,1,0);
		glTranslatef(1,0,1);
		glCallList(quad);
		glTranslatef(0,0,-2);
		glRotatef(180,0,1,0);
		glCallList(quad);
		glRotatef(270,0,1,0);
		glTranslatef(-1,0,1);
		glCallList(quad);
		
		glPopMatrix();
		
		glScalef(1.1f,1.1f,1.1f);
		glColor3f(1,1,1);
		glActiveTextureARB(GL_TEXTURE0_ARB);
		glDisable(GL_TEXTURE_2D);
		glActiveTextureARB(GL_TEXTURE1_ARB);
		glDisable(GL_TEXTURE_2D);

		glBegin(GL_LINE_LOOP);
			glVertex3f(1,1,1);
			glVertex3f(-1,1,1);
			glVertex3f(-1,-1,1);
			glVertex3f(1,-1,1);
		glEnd();
		
		glColor3f(1,0,1);
		glBegin(GL_LINE_LOOP);
			glVertex3f(1,1,-1);
			glVertex3f(-1,1,-1);
			glVertex3f(-1,-1,-1);
			glVertex3f(1,-1,-1);
		glEnd();

		glColor4f(1,1,1,0.5);
		glLineWidth(2);

		glBegin(GL_LINES);
			glColor3f(1,1,1);
			glVertex3f(1,1,1);
			glColor3f(1,0,1);
			glVertex3f(1,1,-1);

			glColor3f(1,1,1);
			glVertex3f(-1,1,1);
			glColor3f(1,0,1);
			glVertex3f(-1,1,-1);

			glColor3f(1,1,1);
			glVertex3f(-1,-1,1);
			glColor3f(1,0,1);
			glVertex3f(-1,-1,-1);
			
			glColor3f(1,1,1);
			glVertex3f(1,-1,1);
			glColor3f(1,0,1);
			glVertex3f(1,-1,-1);
		glEnd();
		
		glPopMatrix();
		
	glEndList();

	return true;
}

vboolean autoplay = false;
static GLfloat theta = 0, phi = 0, zoom = 100;
static GLfloat alpha = 0, scale_phase = 0;

void draw()
{

	GLfloat sine, scale;

	sine = (GLfloat)(sin(scale_phase) * 0.5);

	glMatrixMode(GL_TEXTURE);
	
	glActiveTextureARB(GL_TEXTURE0_ARB);
	glLoadIdentity();
	scale = 1 + sine;
	glScalef(scale,scale,scale);
	glRotatef(alpha,0,0,1);
	
	glActiveTextureARB(GL_TEXTURE1_ARB);
	glLoadIdentity();
	scale = 1 - sine;
	glScalef(scale,scale,scale);
	glRotatef(-alpha / 5,0,0,1);


	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0,0,-400);
	glScalef(zoom,zoom,zoom);
	glRotatef(theta,1,0,0);
	glRotatef(phi,0,1,0);

	glCallList(cube);

	vglSwap();

	if(autoplay)
	{
		alpha += 0.1f;
		scale_phase += 0.1f * ANGLE_1;
		theta += 0.05f;
		phi += 0.1f;
	}
}

int main()
{
	ui_event_t ev;
	vboolean aw = false;

	logStartConsoleLog();
	logUpperLevel(LOG_TRACE);
	
	if(!init())
		return -1;

	for(;;)
	{
		while(uiPending())
		{
			uiNextEvent(&ev);
			switch(ev.type)
			{
				case ui_key_event:
					switch(ev.key.scan)
					{
						case sc_escape:
							if(!ev.key.press)
								goto outer_break;
							break;
						case sc_equal:
						case sc_wheelup:
							if(ev.key.press)
								zoom *= 1.1f;
							break;
						case sc_minus:
						case sc_wheeldown:
							if(ev.key.press)
								zoom *= 0.9f;
							break;
						case sc_space:
							if(!ev.key.press)
								autoplay = !autoplay;
							break;
						case sc_w:
							if(ev.key.press)
								uiAutoWarp(aw = !aw);
						default:
							break;
					}
					break;
				case ui_pointer_motion_event:
					if((aw && !(ev.button & UI_RBUTTON_MASK))
						|| ev.button & UI_LBUTTON_MASK)
					{
						phi += 0.2f * ev.client_dx;
						theta += 0.2f * ev.client_dy;
					}
					if(ev.button & UI_RBUTTON_MASK)
					{
						alpha += 0.1f * ev.client_dx;
						scale_phase += 0.01f * ev.client_dy;
					}
					break;
				default:
					break;
			}
		}
		draw();
	}
outer_break:;

	glDeleteLists(quad,1);
	glDeleteLists(cube,1);
	vglDestroy();
	
	return 0;
}
