/* problem demo */

#ifdef WIN32
#  include <windows.h>                     
#endif

#include <GL/glut.h>
#include "../XGL/xgl.h"

#include <math.h>
#include <stdio.h>

/*
#include "GLUTkey.h"
#include "fg_init.h"
#include "views.h"

#include "../Include/constants.h"
#include "../Include/general.h"

#include "../Aircraft/aircraft.h"
#include "../Cockpit/cockpit.h"
#include "../Joystick/joystick.h"
#include "../Math/fg_geodesy.h"
#include "../Math/mat3.h"
#include "../Math/polar.h"
#include "../Scenery/mesh.h"
#include "../Scenery/moon.h"
#include "../Scenery/scenery.h"
#include "../Scenery/sky.h"
#include "../Scenery/stars.h"
#include "../Scenery/sun.h"
#include "../Time/fg_time.h"
#include "../Time/fg_timer.h"
#include "../Time/sunpos.h"
#include "../Weather/weather.h"
*/


/* This is a record containing global housekeeping information */
/* struct fgGENERAL general; */

/* view parameters */
static GLfloat win_ratio = 1.0;

/* fog color */
GLfloat fog_color[4] =   {1.0, 0.0, 0.0, 1.0};
GLfloat sky_color[4] =    {0.0, 0.0, 1.0, 1.0};
GLfloat sun_vec[4] =      {0.0, 0.0, 1.0, 0.0};

/* temporary hack */
/* pointer to scenery structure */
/* static GLint scenery, runway; */

/* double Simtime; */

/* Another hack */
/* int use_signals = 0; */

/* Yet another hack. This one used by the HUD code. Michele */
/* int show_hud; */


/* in meters of course */
#define CENTER_ELEV    5000.0
#define INNER_RADIUS  50000.0
#define INNER_ELEV     4000.0
#define MIDDLE_RADIUS 70000.0
#define MIDDLE_ELEV    2000.0
#define OUTER_RADIUS  80000.0
#define OUTER_ELEV        0.0

#define DEG_TO_RAD       0.017453292          /* deg*pi/180 = rad */
#define RAD_TO_DEG       57.29577951          /* rad*180/pi = deg */

static float sky_inner[12][3];
static float sky_middle[12][3];
static float sky_outer[12][3];

/* Calculate the sky structure verticies */
void fgSkyInit() {
    float theta;
    int i;

    printf("Generating the sky dome vertices.\n");

    for ( i = 0; i < 12; i++ ) {
	theta = (i * 30.0) * DEG_TO_RAD;
	
	sky_inner[i][0] = cos(theta) * INNER_RADIUS;
	sky_inner[i][1] = sin(theta) * INNER_RADIUS;
	sky_inner[i][2] = INNER_ELEV;
	
	printf(" %.2f %.2f\n", cos(theta) * INNER_RADIUS, 
	       sin(theta) * INNER_RADIUS);

	sky_middle[i][0] = cos((double)theta) * MIDDLE_RADIUS;
	sky_middle[i][1] = sin((double)theta) * MIDDLE_RADIUS;
	sky_middle[i][2] = MIDDLE_ELEV;
	    
	sky_outer[i][0] = cos((double)theta) * OUTER_RADIUS;
	sky_outer[i][1] = sin((double)theta) * OUTER_RADIUS;
	sky_outer[i][2] = OUTER_ELEV;
	    
    }
}


/* Draw the Sky */
void fgSkyRender() {
    float inner_color[4], middle_color[4], diff;
    int i;


    printf("Rendering the sky.\n");

    /* calculate transition colors between sky and fog */
    for ( i = 0; i < 3; i++ ) {
	diff = sky_color[i] - fog_color[i];
	inner_color[i] = sky_color[i] - diff * 0.3;
	middle_color[i] = sky_color[i] - diff * 0.7;
    }
    inner_color[3] = middle_color[3] = sky_color[3];

    xglPushMatrix();

    /* Draw inner/center section of sky*/
    xglBegin( GL_TRIANGLE_FAN );
    xglColor4fv(sky_color);
    xglVertex3f(0.0, 0.0, CENTER_ELEV);
    xglColor4f(0.2, 0.2, 0.8, 1.0);
    for ( i = 0; i < 12; i++ ) {
	xglVertex3fv( sky_inner[i] );
    }
    xglVertex3fv( sky_inner[0] );
    xglEnd();

    /* Draw the middle ring */
    xglBegin( GL_TRIANGLE_STRIP );
    for ( i = 0; i < 12; i++ ) {
	xglColor4fv( middle_color );
	xglVertex3fv( sky_middle[i] );
	xglColor4fv( inner_color );
	xglVertex3fv( sky_inner[i] );
    }
    xglColor4fv( middle_color );
    xglVertex3fv( sky_middle[0] );
    xglColor4fv( inner_color );
    xglVertex3fv( sky_inner[0] );
    xglEnd();

    /* Draw the outer ring */
    xglBegin( GL_TRIANGLE_STRIP );
    for ( i = 0; i < 12; i++ ) {
	xglColor4fv( fog_color );
	xglVertex3fv( sky_outer[i] );
	xglColor4fv( middle_color );
	xglVertex3fv( sky_middle[i] );
    }
    xglColor4fv( fog_color );
    xglVertex3fv( sky_outer[0] );
    xglColor4fv( middle_color );
    xglVertex3fv( sky_middle[0] );
    xglEnd();

    xglPopMatrix();
}


/**************************************************************************
 * fgInitVisuals() -- Initialize various GL/view parameters
 **************************************************************************/

static void fgInitVisuals() {
    /* If enabled, normal vectors specified with glNormal are scaled
       to unit length after transformation.  See glNormal. */
    xglEnable( GL_NORMALIZE );

    xglEnable( GL_LIGHTING );
    xglEnable( GL_LIGHT0 );
    xglLightfv( GL_LIGHT0, GL_POSITION, sun_vec );

    xglFogi (GL_FOG_MODE, GL_LINEAR);
    xglFogf (GL_FOG_END, 45000.0);
    xglFogfv (GL_FOG_COLOR, fog_color);
}


/**************************************************************************
 * Update the view volume, position, and orientation
 **************************************************************************/

static void fgUpdateViewParams() {
    double x_2, x_4, x_8, x_10;
    double light, ambient, diffuse, sky_brightness;
    /* if the 4th field is 0.0, this specifies a direction ... */
    /* clear color (sky) */

    /* Tell GL we are about to modify the projection parameters */
    xglMatrixMode(GL_PROJECTION);
    xglLoadIdentity();
    printf("gluPerspective()\n");
    gluPerspective(55.0, 1.0/win_ratio, 1.0, 100000.0);

    xglMatrixMode(GL_MODELVIEW);
    xglLoadIdentity();
    
    /* set up our view volume */
    printf("gluLookAt()\n");
    gluLookAt(0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0);

    /* set the sun position */
    xglLightfv( GL_LIGHT0, GL_POSITION, sun_vec );

    xglFogfv (GL_FOG_COLOR, fog_color);
}


/**************************************************************************
 * Update all Visuals (redraws anything graphics related)
 **************************************************************************/

static void fgUpdateVisuals( void ) {
    double angle;

    /* update view volume parameters */
    fgUpdateViewParams();

    xglClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );

    /* Tell GL we are switching to model view parameters */
    xglMatrixMode(GL_MODELVIEW);
    /* xglLoadIdentity(); */

    /* draw sky */
    xglDisable( GL_DEPTH_TEST );
    xglDisable( GL_LIGHTING );
    xglDisable( GL_CULL_FACE );
    xglEnable( GL_FOG );
    xglShadeModel( GL_SMOOTH );
    fgSkyRender();

    /* setup transformation for drawing astronomical objects */
    xglPushMatrix();

    /* draw stars and planets */
    /* fgStarsRender(); */

    /* draw the sun */
    /* fgSunRender(); */

    /* render the moon */
    xglEnable( GL_LIGHTING );
    xglEnable( GL_CULL_FACE );
    /* fgMoonRender(); */

    xglPopMatrix();

    /* draw scenery */
    xglShadeModel( GL_FLAT ); 
    xglEnable( GL_DEPTH_TEST );
    xglEnable( GL_FOG );
    /* fgSceneryRender();*/

    /* display HUD */
    /* if( show_hud )
     	fgCockpitUpdate(); */

    xglutSwapBuffers();
}


/* What should we do when we have nothing else to do?  How about get
 * ready for the next move and update the display? */
static void fgMainLoop( void ) {
    /* redraw display */
    fgUpdateVisuals();
}


/**************************************************************************
 * Handle new window size or exposure
 **************************************************************************/

static void fgReshape( int width, int height ) {
    /* Do this so we can call fgReshape(0,0) ourselves without having to know
     * what the values of width & height are. */
    if ( (height > 0) && (width > 0) ) {
	win_ratio = (GLfloat) height / (GLfloat) width;
    }

    /* Inform gl of our view window size */
    xglViewport(0, 0, (GLint)width, (GLint)height);

    fgUpdateViewParams();
    
    /* xglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); */
}


/* Handle keyboard events */
void GLUTkey(unsigned char k, int x, int y) {
    switch (k)
	{
	case 27: /* ESC */
	    exit(0);
	}
}

/* Handle "special" keyboard events */
void GLUTspecialkey(int k, int x, int y) {
    switch (k)
	{
	case 27: /* ESC */
	    exit(0);
	}
}


/**************************************************************************
 * Main ...
 **************************************************************************/

int main( int argc, char *argv[] ) {
    /**********************************************************************
     * Initialize the Window/Graphics environment.
     **********************************************************************/

    /* initialize GLUT */
    xglutInit(&argc, argv);

    /* Define Display Parameters */
    xglutInitDisplayMode( GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE );

    /* Define initial window size */
    xglutInitWindowSize(640, 480);

    /* Initialize windows */
    xglutCreateWindow("Problem Demo");

    /* Initialize the "sky" */
    fgSkyInit();

    /* setup view parameters, only makes GL calls */
    fgInitVisuals();

    /**********************************************************************
     * Initialize the Event Handlers.
     **********************************************************************/

    /* call fgReshape() on window resizes */
    xglutReshapeFunc( fgReshape );

    /* call key() on keyboard event */
    xglutKeyboardFunc( GLUTkey );
    glutSpecialFunc( GLUTspecialkey );

    /* call fgMainLoop() whenever there is nothing else to do */
    xglutIdleFunc( fgMainLoop );

    /* draw the scene */
    xglutDisplayFunc( fgUpdateVisuals );

    /* pass control off to the GLUT event handler */
    glutMainLoop();

    return(0);
}
