/*
	Rogue Trader.
	Copyright (c) 2007, Darragh Coy.
	All rights reserved.
	Original work(s), source code & author(s) details available at: http://www.darraghcoy.com

	Redistribution and use in source and binary forms, with or without modification, are permitted 
	provided that the following conditions are met:

		* 	Redistributions of source code must retain the above copyright notice, this list of 
			conditions and the following disclaimer.
		* 	Redistributions in binary form must reproduce the above copyright notice, this list of 
			conditions and the following disclaimer in the documentation.
		* 	Neither the name of the author nor the names of contributors may be used to endorse or 
			promote products derived from this software without specific prior written permission.
		* 	The use of any third party libraries, modules or data files provided with the source 
			form of the program must follow and respect the individual licensing terms of these 
			components. You do not have permission to modify or circumvent the licensing terms for 
			provided third party components unless the third party licenses specifically allow this. 
			If you do not agree to the terms of provided third party components then you do not have 
			permission to use them in your derived work(s).
		* 	The terms of this license do not apply to separate (but related) distributions if supplied 
			by the author(s), only to the contents of this source distribution, derived works, and the 
			binaries produced by either modified or unmodified versions of the source code. The terms 
			of this license do not also apply to any third party libraries or components provided with 
			the source distribution. Such third party elements are licensed under their own separate 
			agreements.

	THIS SOFTWARE IS PROVIDED BY DARRAGH COY ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, 
	BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
	ARE DISCLAIMED. IN NO EVENT SHALL DARRAGH COY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
	OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
	OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
	IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Class Name:   BackgroundScene
// Purpose:      Class that represents a background scene. Randomnly generates
//               a space background and dust particles that inhabit the scene.
//               Handles drawing and creation of all these things. This class
//               is one of the base classes that contribute to the GameScene
//               class.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "BackgroundScene.h"

//------------------------------------------------------------------------------
// Constant initialisation
//------------------------------------------------------------------------------

// Settings for the billboarded sprites that represent the planet and the sun

const float BackgroundScene::PLANET_SIZE    = 8;    // size of the planet sprite
const float BackgroundScene::PLANET_POS_X   = -32;  // planet sprite position: x
const float BackgroundScene::PLANET_POS_Y   = 0;    // planet sprite position: y
const float BackgroundScene::PLANET_POS_Z   = -64;  // planet sprite position: z

const float BackgroundScene::STAR_SIZE      = 8;    // size of the star sprite
const float BackgroundScene::STAR_POS_X     = 16;   // star sprite position: x
const float BackgroundScene::STAR_POS_Y     = 0;    // star sprite position: y
const float BackgroundScene::STAR_POS_Z     = 32;   // star sprite position: z

// Settings for the light directions of the light given off by the planet and the star

const float BackgroundScene::PLANET_LIGHT_DIR_X = -0.5f;
const float BackgroundScene::PLANET_LIGHT_DIR_Y = -0.1f;
const float BackgroundScene::PLANET_LIGHT_DIR_Z = -1.0f;

const float BackgroundScene::STAR_LIGHT_DIR_X   =  0.5f;
const float BackgroundScene::STAR_LIGHT_DIR_Y   =  0.1f;
const float BackgroundScene::STAR_LIGHT_DIR_Z   =  1.0f;

// Dust particle settings

const unsigned  BackgroundScene::NUM_DUST_PARTICLES = 256;         // number of dust particles a dust 'box'
const float     BackgroundScene::DUST_BOX_SIZE      = 4096.0f;     // size of the 'box' the dust particles are contained in

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::BackgroundScene()
Purpose:  Constructor. Generates a space sky box and sets up the random dust
          particles that inhabit the background scene.
Params:   Sun color, planet light color, planet texture
Returns:  n/a

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

BackgroundScene::BackgroundScene( float * starColor , float * planetLightColor , const GLTexture * planetTexture )
{
    //--------------------------------------------------------------------------
    // Save the planet and sun infromation given:
    //--------------------------------------------------------------------------

    // Save the colors

    this->starColor[0] = starColor[0];
    this->starColor[1] = starColor[1];
    this->starColor[2] = starColor[2];

    this->planetLightColor[0] = planetLightColor[0];
    this->planetLightColor[1] = planetLightColor[1];
    this->planetLightColor[2] = planetLightColor[2];

    // Set the planet texture:

    this->texPlanet = planetTexture;

    // Get the star texture from the texture manager:

    this->texStar = GLTextureManager::getTexStar();

    //--------------------------------------------------------------------------
    // Settings for the skybox to generate: the sky box scene is generated by
    // taking a certain number of upright quads (billboards) and randomnly rotating
    // them about the origin and mapping certain textures to them. The billboards
    // are then all rendered from 6 different angles with additive blending applied
    // to generate the skybox texture.
    //--------------------------------------------------------------------------

    #define NUM_BILLBOARDS 120  // number of billboards to use for the skybox
    #define TEX1_END 5          // 1 billboard past the last billboard to render with star texture 1
    #define TEX2_END 110        // 1 billboard past the last billboard to render with star texture 2
    #define TEX3_END 115        // 1 billboard past the last billboard to render with star texture 3
    #define TEX4_END 120        // 1 billboard past the last billboard to render with star texture 4

    //--------------------------------------------------------------------------
    // Generate the billboard vertex and texture coordinate arrays: these are
    // only temporary mind!
    //--------------------------------------------------------------------------

    float * bbVA = new float[ NUM_BILLBOARDS * 12 ];    // allocate mem for a vertex array for the billboards
    float * bbTA = new float[ NUM_BILLBOARDS * 8  ];    // allocate mem for a tex coord array for the billboards

    // Generate each billboard

    for ( unsigned i = 0 ; i < NUM_BILLBOARDS ; i ++ )
    {
        //----------------------------------------------------------------------
        // define points for a 16x16 square upright quad at 16 units (z) from origin
        //----------------------------------------------------------------------

        float p1[3] = { -16 , +16 , -48 };
        float p2[3] = { +16 , +16 , -48 };
        float p3[3] = { +16 , -16 , -48 };
        float p4[3] = { -16 , -16 , -48 };

        //----------------------------------------------------------------------
        // Randomnly rotate the points about all three axes
        //----------------------------------------------------------------------

        float xrot = mlRandomFloat() * PI2;
        float yrot = mlRandomFloat() * PI2;
        float zrot = mlRandomFloat() * PI2;

        mlRotate3dX( p1 , xrot );
        mlRotate3dX( p2 , xrot );
        mlRotate3dX( p3 , xrot );
        mlRotate3dX( p4 , xrot );

        mlRotate3dY( p1 , yrot );
        mlRotate3dY( p2 , yrot );
        mlRotate3dY( p3 , yrot );
        mlRotate3dY( p4 , yrot );

        mlRotate3dZ( p1 , zrot );
        mlRotate3dZ( p2 , zrot );
        mlRotate3dZ( p3 , zrot );
        mlRotate3dZ( p4 , zrot );

        //----------------------------------------------------------------------
        // Now save the point's coordinates to the vertex array
        //----------------------------------------------------------------------

        bbVA[ i * 12 + 0  ] = p1[0];
        bbVA[ i * 12 + 1  ] = p1[1];
        bbVA[ i * 12 + 2  ] = p1[2];

        bbVA[ i * 12 + 3  ] = p2[0];
        bbVA[ i * 12 + 4  ] = p2[1];
        bbVA[ i * 12 + 5  ] = p2[2];

        bbVA[ i * 12 + 6  ] = p3[0];
        bbVA[ i * 12 + 7  ] = p3[1];
        bbVA[ i * 12 + 8  ] = p3[2];

        bbVA[ i * 12 + 9  ] = p4[0];
        bbVA[ i * 12 + 10 ] = p4[1];
        bbVA[ i * 12 + 11 ] = p4[2];

        //----------------------------------------------------------------------
        // Save the texture coordinates for the billboard to the array, these
        // are always constant for each billboard
        //----------------------------------------------------------------------

        bbTA[ i * 8 + 0 ] = 0;
        bbTA[ i * 8 + 1 ] = 0;

        bbTA[ i * 8 + 2 ] = 1;
        bbTA[ i * 8 + 3 ] = 0;

        bbTA[ i * 8 + 4 ] = 1;
        bbTA[ i * 8 + 5 ] = 1;

        bbTA[ i * 8 + 6 ] = 0;
        bbTA[ i * 8 + 7 ] = 1;

        //----------------------------------------------------------------------
        // Now randomnly swap the texture coordinates around
        //----------------------------------------------------------------------

        if ( mlRandomInt() & 1 )
        {
            //------------------------------------------------------------------
            // Swap the coords of points 1 & 2 with 4 & 3 respectively
            //------------------------------------------------------------------

            float u;    // temporary swap variable
            float v;    // temporary swap variable

            // Swap coords at point 1 with coords at point 4

            u = bbTA[ i * 8 + 0 ];
            v = bbTA[ i * 8 + 1 ];

            bbTA[ i * 8 + 0 ] = bbTA[ i * 8 + 6 ];
            bbTA[ i * 8 + 1 ] = bbTA[ i * 8 + 7 ];

            bbTA[ i * 8 + 6 ] = u;
            bbTA[ i * 8 + 7 ] = v;

            // Swap coords at point 2 with coords at point 3

            u = bbTA[ i * 8 + 2 ];
            v = bbTA[ i * 8 + 3 ];

            bbTA[ i * 8 + 2 ] = bbTA[ i * 8 + 4 ];
            bbTA[ i * 8 + 3 ] = bbTA[ i * 8 + 5 ];

            bbTA[ i * 8 + 4 ] = u;
            bbTA[ i * 8 + 5 ] = v;
        }

        if ( mlRandomInt() & 1 )
        {
            //------------------------------------------------------------------
            // Swap the coords of points 1 & 4 with 2 & 3 respectively
            //------------------------------------------------------------------

            float u;    // temporary swap variable
            float v;    // temporary swap variable

            // Swap coords at point 1 with coords at point 2

            u = bbTA[ i * 8 + 0 ];
            v = bbTA[ i * 8 + 1 ];

            bbTA[ i * 8 + 0 ] = bbTA[ i * 8 + 2 ];
            bbTA[ i * 8 + 1 ] = bbTA[ i * 8 + 3 ];

            bbTA[ i * 8 + 2 ] = u;
            bbTA[ i * 8 + 3 ] = v;

            // Swap coords at point 4 with coords at point 3

            u = bbTA[ i * 8 + 6 ];
            v = bbTA[ i * 8 + 7 ];

            bbTA[ i * 8 + 6 ] = bbTA[ i * 8 + 4 ];
            bbTA[ i * 8 + 7 ] = bbTA[ i * 8 + 5 ];

            bbTA[ i * 8 + 4 ] = u;
            bbTA[ i * 8 + 5 ] = v;
        }


    }   // end of generate billboard loop

    //--------------------------------------------------------------------------
    // Now setup the openGL state for rendering a skybox texture
    //--------------------------------------------------------------------------

    glColor4f   (1,1,1,1);          // set color to full opaque white
    glClearColor(0,0,0,1);          // set clear color to opaque black

    glReadBuffer(GL_BACK);          // set the buffer to read from as the back buffer

    glEnable    (GL_TEXTURE_2D );   // enables
    glEnable    (GL_BLEND      );

    glDisable   (GL_CULL_FACE  );   // disables
    glDisable   (GL_LIGHTING   );
    glDisable   (GL_DEPTH_TEST );

    glBlendFunc( GL_ONE, GL_ONE );  // use additive blending
    glShadeModel(GL_FLAT);          // only need flat shading
    glDepthMask (GL_FALSE);         // no z buffer writes

    glEnableClientState( GL_VERTEX_ARRAY );         // enable vertex arrays
    glEnableClientState( GL_TEXTURE_COORD_ARRAY );  // enable texture coordinate arrays

    glVertexPointer  (3,GL_FLOAT,0,bbVA);   // set the vertex array pointer
    glTexCoordPointer(2,GL_FLOAT,0,bbTA);   // set the texture coordinate array pointer

    // Setup the viewport and projection for rendering the skybox

    glViewport(0,0,512,512);            // viewport will be sized at 512x512
    glMatrixMode( GL_PROJECTION );      // switch to projection matrix
    glLoadIdentity();                   // load the identity transform
    gluPerspective(90,1,1,4096);        // setup perspective projection
    glMatrixMode( GL_MODELVIEW  );      // switch back to modelview matrix

    //--------------------------------------------------------------------------
    // Declare a 512x512 image to hold rendered scenes in
    //--------------------------------------------------------------------------

    unsigned * renderedImage = new unsigned[512*512];

    //--------------------------------------------------------------------------
    // Load the four textures to use for the billboards
    //--------------------------------------------------------------------------

    GLTexture * tex1 = new GLTexture("gfx\\stars1.tga");
    GLTexture * tex2 = new GLTexture("gfx\\stars2.tga");
    GLTexture * tex3 = new GLTexture("gfx\\stars3.tga");
    GLTexture * tex4 = new GLTexture("gfx\\stars4.tga");

    //--------------------------------------------------------------------------
    // Now render the 1st skybox texture: the back face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the back skybox texture and save

    texSkyBoxBk = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now render the 2nd skybox texture: the front face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform
    glRotatef(180,0,1,0);           // face the front skybox face

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the front skybox texture and save

    texSkyBoxFr = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now render the 3rd skybox texture: the left face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform
    glRotatef(-90,0,1,0);            // face the left skybox face

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the left skybox texture and save

    texSkyBoxLr = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now render the 4th skybox texture: the right face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform
    glRotatef(90,0,1,0);            // face the right skybox face

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the left skybox texture and save

    texSkyBoxRt = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now render the 5th skybox texture: the top face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform
    glRotatef(90,1,0,0);            // face the top skybox face

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the left skybox texture and save

    texSkyBoxTp = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now render the 6th skybox texture: the bottom face
    //--------------------------------------------------------------------------

    glClear(GL_COLOR_BUFFER_BIT);   // clear the screen
    glLoadIdentity();               // load the identity transform
    glRotatef(-90,1,0,0);           // face the bottom skybox face

    // Draw each of the four types of textured billboards:

    tex1->bind(); glDrawArrays( GL_QUADS , 0            , TEX1_END * 4 );
    tex2->bind(); glDrawArrays( GL_QUADS , TEX1_END * 4 , TEX2_END * 4 - TEX1_END * 4 );
    tex3->bind(); glDrawArrays( GL_QUADS , TEX2_END * 4 , TEX3_END * 4 - TEX2_END * 4 );
    tex4->bind(); glDrawArrays( GL_QUADS , TEX3_END * 4 , TEX4_END * 4 - TEX3_END * 4 );

    // make sure all the rendering is done

    glFlush();

    // Now grab the scene from openGL and save as a texture

    glReadPixels(0,0,512,512,GL_RGBA,GL_UNSIGNED_BYTE,renderedImage);

    // Declare the left skybox texture and save

    texSkyBoxBt = new GLTexture(renderedImage,512,512);

    //--------------------------------------------------------------------------
    // Now generate a display list for all the dust particles in the scene.
    // Dust is created randomnly within a predefined 'box' of a certain size.
    //--------------------------------------------------------------------------

    dlistDust = glGenLists(1);    // Generate the dust display list

    // Begin compiling the dust display list

    glNewList( dlistDust , GL_COMPILE );

    // Make sure the dust color is white

    glColor4f(1,1,1,1);

    // Make sure point size is 1

    glPointSize(1);

    // Begin drawing points

    glBegin(GL_POINTS);

    // Draw the dust particles: randomnly scattering them about in a box

    for ( unsigned i = 0 ; i < NUM_DUST_PARTICLES ; i++ )
    {
        glVertex3f
        (
            mlRandomFloat() * DUST_BOX_SIZE - DUST_BOX_SIZE / 2,
            mlRandomFloat() * DUST_BOX_SIZE - DUST_BOX_SIZE / 2,
            mlRandomFloat() * DUST_BOX_SIZE - DUST_BOX_SIZE / 2
        );
    }

    // Finish up drawing

    glEnd();

    // End compiling the dust display list

    glEndList();

    //--------------------------------------------------------------------------
    // Cleanup: delete the temporary billboard data arrays, textures used and the
    // array used to hold the rendered image.
    //--------------------------------------------------------------------------

    delete bbVA;
    delete bbTA;
    delete renderedImage;
    delete tex1;
    delete tex2;
    delete tex3;
    delete tex4;

    //--------------------------------------------------------------------------
    // Undefine these macros
    //--------------------------------------------------------------------------

    #undef NUM_BILLBOARDS
    #undef TEX1_END
    #undef TEX2_END
    #undef TEX3_END
    #undef TEX4_END
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::~BackgroundScene()
Purpose:  Destructor. Frees resources used.
Params:   n/a
Returns:  n/a

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

BackgroundScene::~BackgroundScene()
{
    // Free up the skybox textures allocated

    delete texSkyBoxFr;
    delete texSkyBoxBk;
    delete texSkyBoxLr;
    delete texSkyBoxRt;
    delete texSkyBoxTp;
    delete texSkyBoxBt;
	
    // Finally, delete the dust display list

    glDeleteLists(dlistDust,1);
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::getStarColor()
Purpose:  Saves the color of the backgrounds sun to the array given
Params:   array to save rgb components to
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::getStarColor( float * color )
{
    // Abort on null pointer

    if ( color == 0 ) return;

    // Otherwise save sun color

    color[0] = starColor[0];
    color[1] = starColor[1];
    color[2] = starColor[2];
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::getPlanetLightColor()
Purpose:  Saves the color of the backgrounds planet to the array given
Params:   array to save rgb components to
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::getPlanetLightColor( float * color )
{
    // Abort on null pointer

    if ( color == 0 ) return;

    // Otherwise save planet color

    color[0] = planetLightColor[0];
    color[1] = planetLightColor[1];
    color[2] = planetLightColor[2];
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::getStarLightDir()
Purpose:  Saves the backgrounds sun light direction to array given
Params:   array to save xyz components to
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::getStarLightDir( float * direction )
{
    // Abort on null pointer

    if ( direction == 0 ) return;

    // Otherwise save direction of the light

    direction[0] = STAR_LIGHT_DIR_X;
    direction[1] = STAR_LIGHT_DIR_Y;
    direction[2] = STAR_LIGHT_DIR_Z;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::getPlanetLightDir()
Purpose:  Saves the planet's light direction to array given
Params:   array to save xyz components to
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::getPlanetLightDir( float * direction )
{
    // Abort on null pointer

    if ( direction == 0 ) return;

    // Otherwise save direction of the light

    direction[0] = PLANET_LIGHT_DIR_X;
    direction[1] = PLANET_LIGHT_DIR_Y;
    direction[2] = PLANET_LIGHT_DIR_Z;
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::drawBackground()
Purpose:  Draws the background from the perspective of a given camera. Camera
          position is actually irrelevant, orientation only matters.
Params:   Camera to view background from
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::drawBackground( Camera * camera )
{
    //--------------------------------------------------------------------------
    // Abort on null camera pointer
    //--------------------------------------------------------------------------

    if ( camera == 0 ) return;

    //--------------------------------------------------------------------------
    // Setup the gl state for drawing the background
    //--------------------------------------------------------------------------

    glEnable    (GL_TEXTURE_2D );   // enables

    glDisable   (GL_CULL_FACE  );   // disables
    glDisable   (GL_LIGHTING   );
    glDisable   (GL_DEPTH_TEST );
    glDisable   (GL_BLEND      );

    glShadeModel(GL_FLAT       );   // only need flat shading
    glDepthMask (GL_FALSE      );   // no z buffer writes
    glMatrixMode(GL_MODELVIEW  );   // make sure modeview matrix is selected

    //--------------------------------------------------------------------------
    // Save the current openGL transformation matrix
    //--------------------------------------------------------------------------

    glPushMatrix();

    //--------------------------------------------------------------------------
    // Setup a new transform matrix, based on the camera's orientation
    //--------------------------------------------------------------------------

    // Declare an array to hold a transformation matrix

    float matrix[16];

    // Get the camera's orientation matrix:

    float orientation[9]; camera->getOrientationMatrix(orientation);

    // Now fill in the values in the transform matrix: camera position is ignored for this matrix

    matrix[0 ] = orientation[0];
    matrix[1 ] = orientation[1];
    matrix[2 ] = orientation[2];
    matrix[3 ] = 0;

    matrix[4 ] = orientation[3];
    matrix[5 ] = orientation[4];
    matrix[6 ] = orientation[5];
    matrix[7 ] = 0;

    matrix[8 ] = orientation[6];
    matrix[9 ] = orientation[7];
    matrix[10] = orientation[8];
    matrix[11] = 0;

    matrix[12] = 0;
    matrix[13] = 0;
    matrix[14] = 0;
    matrix[15] = 1;

    // Load the modified matrix with openGL

    glLoadMatrixf(matrix);

    //--------------------------------------------------------------------------
    // Draw the pre-rendered skybox
    //--------------------------------------------------------------------------

    // Set render color first

    glColor4f(1,1,1,1);

    // Draw the back face

    texSkyBoxBk->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( - 48 , + 48 , - 48 );
        glTexCoord2f(1,0);  glVertex3f( + 48 , + 48 , - 48 );
        glTexCoord2f(1,1);  glVertex3f( + 48 , - 48 , - 48 );
        glTexCoord2f(0,1);  glVertex3f( - 48 , - 48 , - 48 );

    glEnd();

    // Draw the front face

    texSkyBoxFr->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( + 48 , + 48  , + 48 );
        glTexCoord2f(1,0);  glVertex3f( - 48 , + 48  , + 48 );
        glTexCoord2f(1,1);  glVertex3f( - 48 , - 48  , + 48 );
        glTexCoord2f(0,1);  glVertex3f( + 48 , - 48  , + 48 );

    glEnd();

    // Draw the left face

    texSkyBoxLr->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( - 48 , + 48 , + 48 );
        glTexCoord2f(1,0);  glVertex3f( - 48 , + 48 , - 48 );
        glTexCoord2f(1,1);  glVertex3f( - 48 , - 48 , - 48 );
        glTexCoord2f(0,1);  glVertex3f( - 48 , - 48 , + 48 );

    glEnd();

    // Draw the right face

    texSkyBoxRt->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( + 48 , + 48 , - 48 );
        glTexCoord2f(1,0);  glVertex3f( + 48 , + 48 , + 48 );
        glTexCoord2f(1,1);  glVertex3f( + 48 , - 48 , + 48 );
        glTexCoord2f(0,1);  glVertex3f( + 48 , - 48 , - 48 );

    glEnd();

    // Draw the top face

    texSkyBoxTp->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( - 48 , + 48 , + 48 );
        glTexCoord2f(1,0);  glVertex3f( + 48 , + 48 , + 48 );
        glTexCoord2f(1,1);  glVertex3f( + 48 , + 48 , - 48 );
        glTexCoord2f(0,1);  glVertex3f( - 48 , + 48 , - 48 );

    glEnd();

    // Draw the bottom face

    texSkyBoxBt->bind();

    glBegin(GL_QUADS);

        glTexCoord2f(0,0);  glVertex3f( - 48 , - 48 , - 48 );
        glTexCoord2f(1,0);  glVertex3f( + 48 , - 48 , - 48 );
        glTexCoord2f(1,1);  glVertex3f( + 48 , - 48 , + 48 );
        glTexCoord2f(0,1);  glVertex3f( - 48 , - 48 , + 48 );

    glEnd();

    //--------------------------------------------------------------------------
    // Now for drawing the planet and sun load the identity transform and manually
    // transform the sprites positions.
    //--------------------------------------------------------------------------

    // Enable blending first by alpha before we draw anything

    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

    // Load the identity transform with openGL

    glLoadIdentity();

    //--------------------------------------------------------------------------
    // Draw the planet
    //--------------------------------------------------------------------------

    {
        // Makeup a homegenous vector with the planets position

        float position[] = { PLANET_POS_X , PLANET_POS_Y , PLANET_POS_Z , 1 };

        // Now transform that position by the homogenous transformation matrix we created earlier

        mlTransform4d( position , matrix );

        // Bind the planet texture

        texPlanet->bind();

        // Draw the planet at its translated position but facing the camera

        glBegin(GL_QUADS);

            glTexCoord2f(0,0);  glVertex3f( position[0] - PLANET_SIZE , position[1] + PLANET_SIZE, position[2] );
            glTexCoord2f(1,0);  glVertex3f( position[0] + PLANET_SIZE , position[1] + PLANET_SIZE, position[2] );
            glTexCoord2f(1,1);  glVertex3f( position[0] + PLANET_SIZE , position[1] - PLANET_SIZE, position[2] );
            glTexCoord2f(0,1);  glVertex3f( position[0] - PLANET_SIZE , position[1] - PLANET_SIZE, position[2] );

        glEnd();

    }

    //--------------------------------------------------------------------------
    // Draw the star
    //--------------------------------------------------------------------------

    {
        // Makeup a homegenous vector with the star's position

        float position[] = { STAR_POS_X , STAR_POS_Y , STAR_POS_Z , 1 };

        // Now transform that position by the homogenous transformation matrix we created earlier

        mlTransform4d( position , matrix );

        // Bind the star texture

        texStar->bind();

        // Set the drawing color to the star color

        glColor4f( starColor[0] , starColor[1] , starColor[2] , 1 );

        // Draw the star at its translated position but facing the camera

        glBegin(GL_QUADS);

            glTexCoord2f(0,0);  glVertex3f( position[0] - STAR_SIZE , position[1] + STAR_SIZE, position[2] );
            glTexCoord2f(1,0);  glVertex3f( position[0] + STAR_SIZE , position[1] + STAR_SIZE, position[2] );
            glTexCoord2f(1,1);  glVertex3f( position[0] + STAR_SIZE , position[1] - STAR_SIZE, position[2] );
            glTexCoord2f(0,1);  glVertex3f( position[0] - STAR_SIZE , position[1] - STAR_SIZE, position[2] );

        glEnd();

    }

    //--------------------------------------------------------------------------
    // Restore the saved transformation matrix
    //--------------------------------------------------------------------------

    glPopMatrix();
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::drawDust()
Purpose:  Draws the dust part of the background. Dust should be drawn after
          everything else in the scene. In order to create the illusion of infinite
          dust in the scene the camera's position is restrict to in between fixed
          intervals of the same size as each dust box. Then a number of dust boxes
          are drawn around the camera spaced apart by the dust box size (27 boxes to be exact).
          When the camera reaches the end of the interval it wraps back around to the start.
          Because all the boxes are the same the player still sees the same box when the
          wrap-around occurs. To complete the illusion then fog is applied to fade out
          the dust at a certain distance and so the player does not notice the abrupt
          change in the dust being viewed ahead.
Params:   Camera to view background from
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::drawDust( Camera * camera )
{
    //--------------------------------------------------------------------------
    // Setup the gl state for drawing the background
    //--------------------------------------------------------------------------

    glEnable    (GL_BLEND      );   // enables
    glEnable    (GL_FOG        );
    glEnable    (GL_DEPTH_TEST );

    glDisable   (GL_CULL_FACE  );   // disables
    glDisable   (GL_LIGHTING   );

    glDisable   (GL_TEXTURE_2D );   // dont need texturing
    glShadeModel(GL_FLAT       );   // only need flat shading
    glDepthMask (GL_FALSE      );   // no z buffer writes

    glMatrixMode(GL_MODELVIEW  );   // make sure modeview matrix is selected

    glBlendFunc (GL_ONE , GL_ONE ); // use additive blending for the dust particles

    // Setup the fog

    float fogColor[] = { 0,0,0,0 };

    glFogi  ( GL_FOG_MODE   , GL_LINEAR         );  // linear fog
    glFogfv ( GL_FOG_COLOR  , fogColor          );  // set fog color to black
    glFogf  ( GL_FOG_START  , 0                 );  // set fog start
    glFogf  ( GL_FOG_END    , DUST_BOX_SIZE / 2 );  // set fog end

    //--------------------------------------------------------------------------
    // Save the current openGL transformation matrix
    //--------------------------------------------------------------------------

    glPushMatrix();

    //--------------------------------------------------------------------------
    // Setup the openGL transformation matrix
    //--------------------------------------------------------------------------

    // Get the camera's 3x3 orientation matrix

    float orientation[9]; camera->getOrientationMatrix(orientation);

    // Get the cameras position in the world

    float position[3]; camera->getPosition(position);

    // Now makeup a 4x4 matrix to transform world by the cameras position.
    // Restrict camera movement to intervals of the dust box size.

    float translate[16];

    translate[0 ] = 1;
    translate[1 ] = 0;
    translate[2 ] = 0;
    translate[3 ] = 0;

    translate[4 ] = 0;
    translate[5 ] = 1;
    translate[6 ] = 0;
    translate[7 ] = 0;

    translate[8 ] = 0;
    translate[9 ] = 0;
    translate[10] = 1;
    translate[11] = 0;

    translate[12] = -fmod( position[0] , DUST_BOX_SIZE );
    translate[13] = -fmod( position[1] , DUST_BOX_SIZE );
    translate[14] = -fmod( position[2] , DUST_BOX_SIZE );
    translate[15] = 1;

    // Now makeup another 4x4 matrix to transform world by camera's orientation.

    float rotate[16];

    rotate[0 ] = orientation[0];
    rotate[1 ] = orientation[1];
    rotate[2 ] = orientation[2];
    rotate[3 ] = 0;

    rotate[4 ] = orientation[3];
    rotate[5 ] = orientation[4];
    rotate[6 ] = orientation[5];
    rotate[7 ] = 0;

    rotate[8 ] = orientation[6];
    rotate[9 ] = orientation[7];
    rotate[10] = orientation[8];
    rotate[11] = 0;

    rotate[12] = 0;
    rotate[13] = 0;
    rotate[14] = 0;
    rotate[15] = 1;

    // Combine the rotation and translation transforms, doing translation first

    mlMatrixMult4x4( translate , rotate );

    // Load the combined transforms with opengl

    glLoadMatrixf( rotate );

    //--------------------------------------------------------------------------
    // Draw a 27 dust boxes: each spaced apart by the dust box size
    //--------------------------------------------------------------------------

    for ( int x = -1 ; x <= 1 ; x++ )
    for ( int y = -1 ; y <= 1 ; y++ )
    for ( int z = -1 ; z <= 1 ; z++ )
    {
        // Translate camera to this dust box's position

        glTranslated( x * DUST_BOX_SIZE , -y * DUST_BOX_SIZE , z * DUST_BOX_SIZE );

        // Draw the dust box

        glCallList(dlistDust);

        // Undo previous translation

        glTranslated( -x * DUST_BOX_SIZE , y * DUST_BOX_SIZE , -z * DUST_BOX_SIZE );
    }

    //--------------------------------------------------------------------------
    // Restore the saved transformation matrix
    //--------------------------------------------------------------------------

    glPopMatrix();

    //--------------------------------------------------------------------------
    // Finally disable fog
    //--------------------------------------------------------------------------

    glDisable(GL_FOG);
}

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

Name:     BackgroundScene::drawLensFlare()
Purpose:  Draws the sun's lens flare
Params:   Camera that the world is viewed from
Returns:  none

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*/

void BackgroundScene::drawLensFlare( Camera * camera )
{
    //--------------------------------------------------------------------------
    // Setup the opengl state for drawing flares
    //--------------------------------------------------------------------------

    glDisable(GL_LIGHTING);
    glDisable(GL_CULL_FACE);

    glDisable(GL_DEPTH_TEST);
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_BLEND);

    glBlendFunc( GL_SRC_ALPHA , GL_ONE );
    glDepthMask( GL_FALSE );

    //--------------------------------------------------------------------------
    // Save the current modelview matrix
    //--------------------------------------------------------------------------

    // Go into the modelview matrix, save and load identity:

    glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity();

    //--------------------------------------------------------------------------
    // Get the position of the sun and save to a homogenous vector:
    //--------------------------------------------------------------------------

    float star[3] =
    {
        STAR_POS_X,
        STAR_POS_Y,
        STAR_POS_Z,
    };

    //--------------------------------------------------------------------------
    // Get cameras orientation
    //--------------------------------------------------------------------------

    // Save camera orientation here:

    float orientation[9]; camera->getOrientationMatrix(orientation);

    //--------------------------------------------------------------------------
    // Now transform the suns position:
    //--------------------------------------------------------------------------

    // Rotate the sun:

    mlTransform3d( star , orientation );

    //--------------------------------------------------------------------------
    // Get a normalised vector going from the suns position to the origin, but
    // reverse the x and y components to make the lens flare go in the opposite
    // direction to the camera orienation.
    //--------------------------------------------------------------------------

    // Get this vector

    float flareVector[3] =
    {
         star[0],
         star[1],
        -star[2]
    };

    // Normalise this vector

    mlNormalise3d(flareVector);

    //--------------------------------------------------------------------------
    // Lens flare settings
    //--------------------------------------------------------------------------

    #define FLARE_SIZE     24.0f   // Size of the lens flare
    #define FLARE_1_DIST   4.0f    // Distance of flare 1 from the sun
    #define FLARE_2_DIST   8.0f    // Distance of flare 2 from the sun
    #define FLARE_3_DIST   28.0f   // Distance of flare 3 from the sun
    #define FLARE_4_DIST   32.0f   // Distance of flare 4 from the sun

    //--------------------------------------------------------------------------
    // Lens flare settings: set the flare color to the sun color
    //--------------------------------------------------------------------------

    glColor4f
    (
        starColor[0],
        starColor[1],
        starColor[2],
        1
    );

    //--------------------------------------------------------------------------
    // Draw the 1st lens flare
    //--------------------------------------------------------------------------

    GLTextureManager::getTexLens2()->bind();

    glBegin( GL_QUADS );

        glTexCoord2f( 0 , 0 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_1_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_1_DIST,
            star[2]              + flareVector[2] * FLARE_1_DIST
        );

        glTexCoord2f( 1 , 0 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_1_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_1_DIST,
            star[2]              + flareVector[2] * FLARE_1_DIST
        );

        glTexCoord2f( 1 , 1 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_1_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_1_DIST,
            star[2]              + flareVector[2] * FLARE_1_DIST
        );

        glTexCoord2f( 0 , 1 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_1_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_1_DIST,
            star[2]              + flareVector[2] * FLARE_1_DIST
        );

    glEnd();

    //--------------------------------------------------------------------------
    // Draw the 2nd lens flare
    //--------------------------------------------------------------------------

    GLTextureManager::getTexLens1()->bind();

    glBegin( GL_QUADS );


        glTexCoord2f( 0 , 0 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_2_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_2_DIST,
            star[2]              + flareVector[2] * FLARE_2_DIST
        );

        glTexCoord2f( 1 , 0 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_2_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_2_DIST,
            star[2]              + flareVector[2] * FLARE_2_DIST
        );

        glTexCoord2f( 1 , 1 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_2_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_2_DIST,
            star[2]              + flareVector[2] * FLARE_2_DIST
        );

        glTexCoord2f( 0 , 1 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_2_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_2_DIST,
            star[2]              + flareVector[2] * FLARE_2_DIST
        );

    glEnd();

    //--------------------------------------------------------------------------
    // Draw the 3rd lens flare
    //--------------------------------------------------------------------------

    GLTextureManager::getTexLens1()->bind();

    glBegin( GL_QUADS );

        glTexCoord2f( 0 , 0 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_3_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_3_DIST,
            star[2]              + flareVector[2] * FLARE_3_DIST
        );

        glTexCoord2f( 1 , 0 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_3_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_3_DIST,
            star[2]              + flareVector[2] * FLARE_3_DIST
        );

        glTexCoord2f( 1 , 1 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_3_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_3_DIST,
            star[2]              + flareVector[2] * FLARE_3_DIST
        );

        glTexCoord2f( 0 , 1 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_3_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_3_DIST,
            star[2]              + flareVector[2] * FLARE_3_DIST
        );

    glEnd();

    //--------------------------------------------------------------------------
    // Draw the 4th lens flare
    //--------------------------------------------------------------------------

    GLTextureManager::getTexLens2()->bind();

    glBegin( GL_QUADS );

        glTexCoord2f( 0 , 0 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_4_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_4_DIST,
            star[2]              + flareVector[2] * FLARE_4_DIST
        );

        glTexCoord2f( 1 , 0 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_4_DIST,
            star[1] + FLARE_SIZE + flareVector[1] * FLARE_4_DIST,
            star[2]              + flareVector[2] * FLARE_4_DIST
        );

        glTexCoord2f( 1 , 1 );

        glVertex3f
        (
            star[0] + FLARE_SIZE + flareVector[0] * FLARE_4_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_4_DIST,
            star[2]              + flareVector[2] * FLARE_4_DIST
        );

        glTexCoord2f( 0 , 1 );

        glVertex3f
        (
            star[0] - FLARE_SIZE + flareVector[0] * FLARE_4_DIST,
            star[1] - FLARE_SIZE + flareVector[1] * FLARE_4_DIST,
            star[2]              + flareVector[2] * FLARE_4_DIST
        );

    glEnd();

    //--------------------------------------------------------------------------
    // Restore the modelview matrix
    //--------------------------------------------------------------------------

    // Restore the modelview matrix

    glPopMatrix();

}
