//
// Simple camera class test
//
// 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    "TypeDefs.h"
#include    "Vector3D.h"
#include    "Vector2D.h"
#include    "boxes.h"
#include    "Camera.h"

Vector3D    eye   ( -0.5, -0.5, 1.5 );  // camera position
unsigned    decalMap;                   // decal (diffuse) texture
unsigned    stoneMap;
unsigned    teapotMap;
float       angle     = 0;

float	yaw   = 0;
float	pitch = 0;
float	roll  = 0;

Camera		camera ( eye, 0, 0, 0 );	// camera to be used

void init ()
{
    glClearColor ( 0.0, 0.0, 0.0, 1.0 );
    glEnable     ( GL_DEPTH_TEST );
    glEnable     ( GL_TEXTURE_2D );
    glDepthFunc  ( GL_LEQUAL     );

    glHint ( GL_POLYGON_SMOOTH_HINT,         GL_NICEST );
    glHint ( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
}

void displayBoxes ()
{
    glMatrixMode ( GL_MODELVIEW );
    glPushMatrix ();

    drawBox  ( Vector3D ( -5, -5, 0 ), Vector3D ( 10, 10, 3 ), stoneMap, false );
    drawBox  ( Vector3D ( 3, 2, 0.5 ), Vector3D ( 1,  2,  2 ), decalMap );

    glBindTexture   ( GL_TEXTURE_2D, teapotMap );

    glPushMatrix ();
    glTranslatef ( 0.2, 1, 1.5 );

    glRotatef    ( angle * 45.3, 1, 0, 0 );
   	glRotatef    ( angle * 57.2, 0, 1, 0 );

    glutSolidTeapot ( 0.3 );

    glPopMatrix ();
    glPopMatrix ();
}

void display ()
{
    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

	camera.apply ();

    displayBoxes ();

    glutSwapBuffers ();
}

void reshape ( int w, int h )
{
	camera.setViewSize ( w, h, 60 );
	camera.apply       ();
}

void key ( unsigned char key, int x, int y )
{
    if ( key == 27 || key == 'q' || key == 'Q' )        // quit requested
        exit ( 0 );
    else
   	if ( key == 'w' || key == 'W' )
   		camera.moveBy ( camera.getViewDir () * 0.2 );
   	else
   	if ( key == 'x' || key == 'X' )
   		camera.moveBy ( -camera.getViewDir () * 0.2 );
   	else
   	if ( key == 'a' || key == 'A' )
   		camera.moveBy ( -camera.getSideDir () * 0.2 );
   	else
   	if ( key == 'd' || key == 'D' )
   		camera.moveBy ( camera.getSideDir () * 0.2 );

   	glutPostRedisplay ();
}

void    specialKey ( int key, int x, int y )
{
    if ( key == GLUT_KEY_UP )
        yaw += M_PI / 90;
    else
    if ( key == GLUT_KEY_DOWN )
        yaw -= M_PI / 90;
	else
    if ( key == GLUT_KEY_RIGHT )
        roll += M_PI / 90;
    else
    if ( key == GLUT_KEY_LEFT )
        roll -= M_PI / 90;

	camera.setEulerAngles ( yaw, pitch, roll );

    glutPostRedisplay ();
}

void	mouseFunc ( int x, int y )
{
	static	int	lastX = -1;
	static	int	lastY = -1;

	if ( lastX == -1 )				// not initialized
	{
		lastX = x;
		lastY = y;
	}

	yaw  -= (y - lastY) * 0.02;
	roll += (x - lastX) * 0.02;

	lastX = x;
	lastY = y;

	camera.setEulerAngles ( yaw, pitch, roll );

	glutPostRedisplay ();
}

void    animate ()
{
	static	float	lastTime = 0.0;
	float			time     = 0.001f * glutGet ( GLUT_ELAPSED_TIME );

    angle += 2 * (time - lastTime);

    lastTime = time;

    glutPostRedisplay ();
}

int main ( int argc, char * argv [] )
{
                                // initialize glut
    glutInit            ( &argc, argv );
    glutInitDisplayMode ( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutInitWindowSize  ( 512, 512 );


                                // create window
    glutCreateWindow ( "OpenGL camera test" );

                                // register handlers
    glutDisplayFunc  ( display    );
    glutReshapeFunc  ( reshape    );
    glutKeyboardFunc ( key        );
    glutSpecialFunc  ( specialKey );
    glutPassiveMotionFunc ( mouseFunc );
    glutIdleFunc     ( animate    );

    init           ();
    initExtensions ();

    decalMap  = createTexture2D ( true, "../../Textures/oak.bmp" );
    stoneMap  = createTexture2D ( true, "../../Textures/block.bmp" );
    teapotMap = createTexture2D ( true, "../../Textures/Oxidated.jpg" );

	camera.setRightHanded ( false );

    glutMainLoop ();

    return 0;
}
