//
// Simple test for ObjLoader class
//
// Author: Alex V. Boreskoff <alexboreskoff@mtu-net.ru>, <steps3d@narod.ru>
//

#include	"libExt.h"
#include	<glut.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	"libTexture.h"
#include	"Mesh.h"
#include	"MeshUtils.h"
#include	"MeshNode.h"
#include	"ObjLoader.h"
#include	"Data.h"

Vector3D	eye   ( 7, 5, 7 );			// camera position
Vector3D	light ( 5, 0, 4 );			// light position
float	 	angle = 0;
Vector3D	rot ( 0, 0, 0 );
int			mouseOldX = 0;
int			mouseOldY = 0;
unsigned	decalMap;

MeshNode * root;

/////////////////////////////////////////////////////////////////////////////////

void init ()
{
	glClearColor ( 0.0, 0.0, 0.0, 1.0 );
	glEnable     ( GL_DEPTH_TEST );
	glDepthFunc  ( GL_LEQUAL );

	glHint ( GL_POLYGON_SMOOTH_HINT,         GL_NICEST );
	glHint ( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
}

void display ()
{
	glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	glMatrixMode   ( GL_MODELVIEW );
	glPushMatrix   ();

    glRotatef    ( rot.x, 1, 0, 0 );
    glRotatef    ( rot.y, 0, 1, 0 );
    glRotatef    ( rot.z, 0, 0, 1 );

	glActiveTextureARB ( GL_TEXTURE0_ARB );
	glEnable           ( GL_TEXTURE_2D );
	glBindTexture      ( GL_TEXTURE_2D, decalMap );

	root -> render ();

    glPopMatrix ();

	glutSwapBuffers ();
}

void reshape ( int w, int h )
{
   glViewport     ( 0, 0, (GLsizei)w, (GLsizei)h );
   glMatrixMode   ( GL_PROJECTION );
   											// factor all camera ops into projection matrix
   glLoadIdentity ();
   gluPerspective ( 60.0, (GLfloat)w/(GLfloat)h, 1.0, 60.0 );
   gluLookAt      ( eye.x, eye.y, eye.z,	// eye
					0, 0, 0,				// center
					0.0, 0.0, 1.0 );		// up

   glMatrixMode   ( GL_MODELVIEW );
   glLoadIdentity ();
}

void motion ( int x, int y )
{
    rot.y -= ((mouseOldY - y) * 180.0f) / 200.0f;
    rot.z -= ((mouseOldX - x) * 180.0f) / 200.0f;
    rot.x  = 0;

    if ( rot.z > 360 )
		rot.z -= 360;

	if ( rot.z < -360 )
		rot.z += 360;

    if ( rot.y > 360 )
		rot.y -= 360;

	if ( rot.y < -360 )
        rot.y += 360;

    mouseOldX = x;
    mouseOldY = y;

	glutPostRedisplay ();
}

void mouse ( int button, int state, int x, int y )
{
    if ( state == GLUT_DOWN )
    {
        mouseOldX = x;
        mouseOldY = y;
	}
}

void key ( unsigned char key, int x, int y )
{
	if ( key == 27 || key == 'q' || key == 'Q' )	//	quit requested
    	exit ( 0 );
}

int main ( int argc, char * argv [] )
{
								// initialize glut
	glutInit            ( &argc, argv );
	glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
	glutInitWindowSize  ( 500, 500 );


								// create window
	glutCreateWindow ( "Simple test for ObjLoader" );

								// register handlers
	glutDisplayFunc  ( display );
	glutReshapeFunc  ( reshape );
	glutKeyboardFunc ( key     );
	glutMouseFunc    ( mouse   );
	glutMotionFunc   ( motion  );

	init           ();
	initExtensions ();
	printfInfo     ();

    if ( !isExtensionSupported ( "GL_ARB_vertex_buffer_object" ) )
    {
        printf ( "ARB_vertex_buffer_object not supported" );

        return 3;
    }

	root = ObjLoader ().load ( &Data ( "../../models/Foot.obj" ) );

	if ( root == NULL )
	{
		printf ( "Error loading ase file\n" );

		exit ( 1 );
	}

	addSearchPath ( "../../models" );

	Material	mat;

	mat.diffuse.mapName = "bone.bmp";

//	decalMap = createTexture2D ( true, "bone.bmp" );

    for ( MeshNode :: Links :: const_iterator it = root -> begin (); it != root -> end (); ++it )
	{
		Mesh * mesh = (*it) -> node -> getMesh ();

		mesh -> createBuffers      ();
		mesh -> setMaterial        ( mat );
//		mesh -> getMaterial        ().diffuse.bindToUnit ( 0 );
		mesh -> getMaterial        ().load       ();

		mesh -> addCoordAssignment ( Mesh :: tagVertex,   Mesh :: tagVertex );
		mesh -> addCoordAssignment ( Mesh :: tagNormal,   Mesh :: tagNormal );
		mesh -> addCoordAssignment ( Mesh :: tagTexCoord, Mesh :: tagTex0   );
	}

    glutMainLoop ();

	return 0;
}
