/*
	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:   Mesh
// Purpose:      Serves as a base class for all mesh objects. Defines the format
//               and layout for mesh data (vertices, texcoords and normals).
//               Also provides a handy function for generating surface normals
//               based on vertex data.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "Mesh.h"

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

Name:     Mesh::Mesh()
Purpose:  Default constructor. Initialises all pointers and mesh memory to zero
Params:   none
Returns:  none

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

Mesh::Mesh()
{
    // Use the memset command for easyness sake:

    memset( this , 0 , sizeof( Mesh ) );
}

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

Name:     Mesh::Mesh()
Purpose:  Mesh destructor. Frees mesh vertex arrays and skin
Params:   none
Returns:  none

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

Mesh::~Mesh()
{
    // Free all the arrays

    if ( vertexArray		) delete[] vertexArray;
    if ( normalArray		) delete[] normalArray;
    if ( edgeArray			) delete[] edgeArray;
    if ( edgeNormalArray	) delete[] edgeNormalArray;
    if ( texCoordArray		) delete[] texCoordArray;

    // Delete the mesh skin

    if ( meshSkin ) delete meshSkin;
}

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

Name:     Mesh::generateNormals()
Purpose:  Generates the surface normals for every vertex in the model. Does not
          attempt to smooth normals across triangles, because I want a sharp
          contrast between sides of the model.
Params:   none
Returns:  none

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

void Mesh::generateNormals()
{
    //--------------------------------------------------------------------------
    // Create the array of normals
    //--------------------------------------------------------------------------

    normalArray = new float[ numTriangles * 9 ];

    //--------------------------------------------------------------------------
    // Generate per triangle normals for every triange in the model
    //--------------------------------------------------------------------------

    for ( unsigned t = 0 ; t < numTriangles ; t++ )
    {
        //----------------------------------------------------------------------
        // Get vertices 2 and 3 relative to vertex 1 in the triangle
        //----------------------------------------------------------------------

        float v2_x = vertexArray[ t * 9 + 3 ] - vertexArray[ t * 9 + 0 ];
        float v2_y = vertexArray[ t * 9 + 4 ] - vertexArray[ t * 9 + 1 ];
        float v2_z = vertexArray[ t * 9 + 5 ] - vertexArray[ t * 9 + 2 ];

        float v3_x = vertexArray[ t * 9 + 6 ] - vertexArray[ t * 9 + 0 ];
        float v3_y = vertexArray[ t * 9 + 7 ] - vertexArray[ t * 9 + 1 ];
        float v3_z = vertexArray[ t * 9 + 8 ] - vertexArray[ t * 9 + 2 ];

        //----------------------------------------------------------------------
        // Do a vector cross product of v2 against v3 to get an unormalised
        // normal vector.
        //----------------------------------------------------------------------

        float normal_x = v2_y * v3_z - v3_y * v2_z;
        float normal_y = v2_z * v3_x - v3_z * v2_x;
        float normal_z = v2_x * v3_y - v3_x * v2_y;

        //----------------------------------------------------------------------
        // Get the lenght of the normal vector
        //----------------------------------------------------------------------

        float nLenght = sqrt
        (
            normal_x * normal_x
            +
            normal_y * normal_y
            +
            normal_z * normal_z
        );

        //----------------------------------------------------------------------
        // Normalise the normal components
        //----------------------------------------------------------------------

        if ( nLenght != 0 )
        {
            normal_x /= nLenght;
            normal_y /= nLenght;
            normal_z /= nLenght;
        }

        //----------------------------------------------------------------------
        // Now save this normal as the normal for all 3 verts of the triangle
        //----------------------------------------------------------------------

        normalArray[ t * 9 + 0 ] = normal_x;
        normalArray[ t * 9 + 1 ] = normal_y;
        normalArray[ t * 9 + 2 ] = normal_z;

        normalArray[ t * 9 + 3 ] = normal_x;
        normalArray[ t * 9 + 4 ] = normal_y;
        normalArray[ t * 9 + 5 ] = normal_z;

        normalArray[ t * 9 + 6 ] = normal_x;
        normalArray[ t * 9 + 7 ] = normal_y;
        normalArray[ t * 9 + 8 ] = normal_z;
    }

}

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

Name:     Mesh::generateEdges()
Purpose:  Generates the vectors for each edge. Assumes vertex array is initialised.
Params:   none
Returns:  none

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

void Mesh::generateEdges()
{
    //--------------------------------------------------------------------------
    // Create the array of edge vectors
    //--------------------------------------------------------------------------

    edgeArray = new float[ numTriangles * 9 ];

    //--------------------------------------------------------------------------
    // Generate all the edge vectors for each triangle
    //--------------------------------------------------------------------------

    for ( unsigned t = 0 ; t < numTriangles ; t++ )
    {
        // Edge 1: vertex 2 - vertex 1

        edgeArray[ t * 9 + 0 ] = vertexArray[ t * 9 + 3 ] - vertexArray[ t * 9 + 0 ];
        edgeArray[ t * 9 + 1 ] = vertexArray[ t * 9 + 4 ] - vertexArray[ t * 9 + 1 ];
        edgeArray[ t * 9 + 2 ] = vertexArray[ t * 9 + 5 ] - vertexArray[ t * 9 + 2 ];

        // Edge 2: vertex 3 - vertex 2

        edgeArray[ t * 9 + 3 ] = vertexArray[ t * 9 + 6 ] - vertexArray[ t * 9 + 3 ];
        edgeArray[ t * 9 + 4 ] = vertexArray[ t * 9 + 7 ] - vertexArray[ t * 9 + 4 ];
        edgeArray[ t * 9 + 5 ] = vertexArray[ t * 9 + 8 ] - vertexArray[ t * 9 + 5 ];

        // Edge 2: vertex 1 - vertex 3

        edgeArray[ t * 9 + 6 ] = vertexArray[ t * 9 + 0 ] - vertexArray[ t * 9 + 6 ];
        edgeArray[ t * 9 + 7 ] = vertexArray[ t * 9 + 1 ] - vertexArray[ t * 9 + 7 ];
        edgeArray[ t * 9 + 8 ] = vertexArray[ t * 9 + 2 ] - vertexArray[ t * 9 + 8 ];
    }
}

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

Name:     Mesh::generateEdgeNormals()
Purpose:  Generates the edge normal vectors for each edge. Assumes edge and normal
          arrays are intialised.
Params:   none
Returns:  none

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

void Mesh::generateEdgeNormals()
{
    //--------------------------------------------------------------------------
    // Create the array of edge normals
    //--------------------------------------------------------------------------

    edgeNormalArray = new float[ numTriangles * 9 ];

    //--------------------------------------------------------------------------
    // Generate all the edge normal vectors for each triangle
    //--------------------------------------------------------------------------

    for ( unsigned t = 0 ; t < numTriangles ; t++ )
    {
        // Edge normal 1: cross product of edge1 with triangle normal

        mlCross3d
        (
            normalArray     + t * 9 + 0,
            edgeArray       + t * 9 + 0 ,
            edgeNormalArray + t * 9 + 0
        );

        // Edge normal 2: cross product of edge2 with triangle normal

        mlCross3d
        (
            normalArray     + t * 9 + 3,
            edgeArray       + t * 9 + 3 ,
            edgeNormalArray + t * 9 + 3
        );

        // Edge normal 3: cross product of edge3 with triangle normal

        mlCross3d
        (
            normalArray     + t * 9 + 6,
            edgeArray       + t * 9 + 6 ,
            edgeNormalArray + t * 9 + 6
        );

        // Normalise the edge normal vectors

        mlNormalise3d( edgeNormalArray + t * 9 + 0 );
        mlNormalise3d( edgeNormalArray + t * 9 + 3 );
        mlNormalise3d( edgeNormalArray + t * 9 + 6 );
    }
}

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

Name:     Mesh::generateBoundingSphere()
Purpose:  Decides on a center and radius for a bounding sphere to fit around the mesh.
Params:   none
Returns:  none

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

void Mesh::generateBoundingSphere()
{
    //--------------------------------------------------------------------------
    // If the mesh has no vertices set bounding sphere to default:
    //--------------------------------------------------------------------------

    if ( numVertices == 0 )
    {
        //----------------------------------------------------------------------
        // No model vertices.. What else can be done but this ?
        //----------------------------------------------------------------------

        sphereCenterX   = 0;
        sphereCenterY   = 0;
        sphereCenterZ   = 0;
        sphereRadius    = 1;
    }
    else
    {

        //----------------------------------------------------------------------
        // Model has vertices
        //----------------------------------------------------------------------

        // Hold here the minimum and maximum xyz values

        float minX , maxX;
        float minY , maxY;
        float minZ , maxZ;

        //----------------------------------------------------------------------
        // Set the minimums and maximums to equal the coordinates of the first vertex
        //----------------------------------------------------------------------

        minX = vertexArray[0];
        maxX = vertexArray[0];

        minY = vertexArray[1];
        maxY = vertexArray[1];

        minZ = vertexArray[2];
        maxZ = vertexArray[2];

        //----------------------------------------------------------------------
        // Now get a pointer to one vertex past the start of the array
        //----------------------------------------------------------------------

        float * coordinate = vertexArray;

        //----------------------------------------------------------------------
        // Find the minimum and maximum xyz values for the model
        //----------------------------------------------------------------------

        for ( unsigned i = numVertices - 1 ; i != 0 ; i-- )
        {
            //------------------------------------------------------------------
            // Check x coordinate of this vertex to see if it is a new minimum / maximum
            //------------------------------------------------------------------

            if ( * coordinate < minX )
            {
                // New minimum

                minX = * coordinate;
            }
            else if ( * coordinate > maxX )
            {
                // New maximum

                maxX = * coordinate;
            }

            // Move onto y coordinate

            coordinate++;

            //------------------------------------------------------------------
            // Check y coordinate of this vertex to see if it is a new minimum / maximum
            //------------------------------------------------------------------

            if ( * coordinate < minY )
            {
                // New minimum

                minY = * coordinate;
            }
            else if ( * coordinate > maxY )
            {
                // New maximum

                maxY = * coordinate;
            }

            // Move onto z coordinate

            coordinate++;

            //------------------------------------------------------------------
            // Check z coordinate of this vertex to see if it is a new minimum / maximum
            //------------------------------------------------------------------

            if ( * coordinate < minZ )
            {
                // New minimum

                minZ = * coordinate;
            }
            else if ( * coordinate > maxZ )
            {
                // New maximum

                maxZ = * coordinate;
            }

            // Move onto x coordinate of next vertex

            coordinate++;

        } // end for every vertex past the first in the vertex array

        //----------------------------------------------------------------------
        // Now that we have established the minimum and maximum coordinates,
        // find the center for the bounding sphere.
        //----------------------------------------------------------------------

        sphereCenterX = minX * 0.5f + maxX * 0.5f;
        sphereCenterY = minY * 0.5f + maxY * 0.5f;
        sphereCenterZ = minZ * 0.5f + maxZ * 0.5f;

        //----------------------------------------------------------------------
        // Make the bounding sphere radius the distance from the sphere center
        // to the first point in the vertex array:
        //----------------------------------------------------------------------

        // Create a array to hold sphere center

        float center[3] =
        {
            sphereCenterX,
            sphereCenterY,
            sphereCenterZ
        };

        // Set the radius as the distance from this to the first point in the vertex array

        sphereRadius = mlDistance3d( center , vertexArray );

        //----------------------------------------------------------------------
        // Now for every point in the vertex array see if the distance between
        // it and the sphere center is greater than the current radius. If so
        // the new distance becomes the new radius:
        //----------------------------------------------------------------------

        for ( unsigned i = 1 ; i < numVertices  ; i ++ )
        {
            // Get the distance from the sphere center to this point:

            float distance = mlDistance3d( center , vertexArray + ( i * 3 ) );

            // If the distance is greater than the current sphere radius, then
            // make the new sphere radius:

            if ( distance > sphereRadius ) sphereRadius = distance;
        }

    } // end if there are vertices

}

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

Name:     Mesh::draw()
Purpose:  Draws the mesh.
Params:   Position and orientation (3x3 matrix) of the mesh to draw.
Returns:  none

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

void Mesh::draw
(
    float   pos_x,
    float   pos_y,
    float   pos_z,
    float * orientation

) const
{
    // Get the current openGL transformation matrix

    float matrix[16]; glGetFloatv( GL_MODELVIEW_MATRIX , matrix );

    // Save the current OpenGL transform matrix

    glPushMatrix();

    // Makeup two 4x4 matrices to translate by both objects position and orientation

    float rotation    [16];
    float translation [16];

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

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

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

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

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

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

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

    translation[12] = pos_x;
    translation[13] = pos_y;
    translation[14] = pos_z;
    translation[15] = 1;

    // Combine the rotation and translation transforms, doing rotation first. Save to translation matrix.

    mlMatrixMult4x4( rotation , translation );

    // Now combine the object transforms with the world transforms, or the previously gotten transfrom matrix

    mlMatrixMult4x4( translation , matrix );

    // Load the modified matrix with openGL

    glLoadMatrixf( matrix );

    // Set the vertex, normal and texture coordinate pointers to this meshes data

    glVertexPointer     ( 3 , GL_FLOAT , 0 , this->vertexArray     );
    glNormalPointer     (     GL_FLOAT , 0 , this->normalArray     );
    glTexCoordPointer   ( 2 , GL_FLOAT , 0 , this->texCoordArray   );

    // Bind the model's texture

    meshSkin->bind();

    // Draw the model

    glDrawArrays( GL_TRIANGLES , 0 , this->numVertices );

    // Restore the previous OpenGL transform matrix

    glPopMatrix();
}

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

Name:     Mesh::drawNormals()
Purpose:  Draws the meshes normal vectors.
Params:   Position and orientation (3x3 matrix) of the mesh to draw.
Returns:  none

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

void Mesh::drawNormals
(
    float   pos_x,
    float   pos_y,
    float   pos_z,
    float * orientation

) const
{
    // Get the current openGL transformation matrix

    float matrix[16]; glGetFloatv( GL_MODELVIEW_MATRIX , matrix );

    // Save the current OpenGL transform matrix

    glPushMatrix();

    // Makeup two 4x4 matrices to translate by both objects position and orientation

    float rotation     [16];
    float translation  [16];

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

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

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

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

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

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

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

    translation[12] = pos_x;
    translation[13] = pos_y;
    translation[14] = pos_z;
    translation[15] = 1;

    // Combine the rotation and translation transforms, doing rotation first. Save to translation matrix.

    mlMatrixMult4x4( rotation , translation );

    // Now combine the object transforms with the world transforms, or the previously gotten transfrom matrix

    mlMatrixMult4x4( translation , matrix );

    // Load the modified matrix with openGL

    glLoadMatrixf( matrix );

    // Save the state of all enables

    glPushAttrib( GL_ENABLE_BIT );

    // Disable lighting and texturing

    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);

    // Normal lenght and thickness:

    #define NORMAL_LENGHT 10
    #define LINE_SIZE 2

    // Set line width

    glLineWidth(LINE_SIZE);

    // Set draw color to white

    glColor4f(1,1,1,1);

    //--------------------------------------------------------------------------
    // Begin drawing a normal line for each polygon
    //--------------------------------------------------------------------------

    // Begin drawing lines

    glBegin(GL_LINES);

    // Draw each normal

    for ( unsigned i = 0 ; i < numTriangles ; i++ )
    {
        // Get the medium point of this triangle

        float mediumX =
        {
            vertexArray[ i * 9 + 0 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 3 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 6 ] * 0.333333333f
        };

        float mediumY =
        {
            vertexArray[ i * 9 + 1 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 4 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 7 ] * 0.333333333f
        };

        float mediumZ =
        {
            vertexArray[ i * 9 + 2 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 5 ] * 0.333333333f
            +
            vertexArray[ i * 9 + 8 ] * 0.333333333f
        };

        // Now draw a line going from center point out in normal direction

        glVertex3f( mediumX , mediumY , mediumZ );

        glVertex3f
        (
            mediumX + normalArray[ i * 9 + 0 ] * NORMAL_LENGHT,
            mediumY + normalArray[ i * 9 + 1 ] * NORMAL_LENGHT,
            mediumZ + normalArray[ i * 9 + 2 ] * NORMAL_LENGHT
        );
    }

    // End drawing lines

    glEnd();

    // Restore all enables states

    glPopAttrib();

    // Restore the previous OpenGL transform matrix

    glPopMatrix();
}

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

Name:     Mesh::drawBoundingSphere()
Purpose:  Draws the meshes bounding sphere
Params:   Position and orientation (3x3 matrix) of the mesh to draw.
Returns:  none

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

void Mesh::drawBoundingSphere
(
    float   pos_x,
    float   pos_y,
    float   pos_z,
    float * orientation

) const
{
    // Get the current openGL transformation matrix

    float matrix[16]; glGetFloatv( GL_MODELVIEW_MATRIX , matrix );

    // Save the current OpenGL transform matrix

    glPushMatrix();

    // Makeup two 4x4 matrices to translate by both objects position and orientation

    float rotation    [16];
    float translation [16];

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

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

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

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

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

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

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

    translation[12] = pos_x;
    translation[13] = pos_y;
    translation[14] = pos_z;
    translation[15] = 1;

    // Combine the rotation and translation transforms, doing rotation first. Save to translation matrix.

    mlMatrixMult4x4( rotation , translation );

    // Now combine the object transforms with the world transforms, or the previously gotten transfrom matrix

    mlMatrixMult4x4( translation , matrix );

    // Load the modified matrix with openGL

    glLoadMatrixf( matrix );

    // Save the state of all enables

    glPushAttrib( GL_ENABLE_BIT );

    // Disable lighting and texturing

    glDisable(GL_LIGHTING);
    glDisable(GL_TEXTURE_2D);

    // Normal lenght and thickness:

    #define NORMAL_LENGHT 10
    #define LINE_SIZE 2

    // Set line width

    glLineWidth(LINE_SIZE);

    // Set draw color to white

    glColor4f(1,1,1,1);

    //--------------------------------------------------------------------------
    // Create a quadric and set its draw style to lines
    //--------------------------------------------------------------------------

    // Create the quadric

    GLUquadric * sphere = gluNewQuadric();

    // Set the draw style to lines

    gluQuadricDrawStyle( sphere , GLU_LINE );

    // Draw the quadric

    gluSphere( sphere , sphereRadius , 32 , 32 );

    // Delete the quadric

    gluDeleteQuadric(sphere);

    // Restore the previous OpenGL transform matrix

    glPopMatrix();
}

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

Name:     Mesh::defaultMesh()
Purpose:  Constructs a default cube model for the mesh. used by derived mesh classes
          when a specific model cannot be loaded from a file.
Params:   none
Returns:  none

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

void Mesh::defaultMesh()
{
    //--------------------------------------------------------------------------
    // Size of the default mesh
    //--------------------------------------------------------------------------

    #define DEF_MESH_SIZE 256

    //--------------------------------------------------------------------------
    // Set the number of triangles and vertices in the default mesh
    //--------------------------------------------------------------------------

    numTriangles = 12;
    numVertices  = numTriangles * 3;

    //--------------------------------------------------------------------------
    // Create the arrays for the default mesh: simple cube with 12 tris
    //--------------------------------------------------------------------------

    vertexArray     = new float[ numVertices * 3 ];
    texCoordArray   = new float[ numVertices * 2 ];

    //--------------------------------------------------------------------------
    // Fill in the data !
    //--------------------------------------------------------------------------

    // Front face

        // Triangle 1

        vertexArray[0] = -DEF_MESH_SIZE;    texCoordArray[0] = 0;
        vertexArray[1] =  DEF_MESH_SIZE;    texCoordArray[1] = 0;
        vertexArray[2] =  DEF_MESH_SIZE;

        vertexArray[3] = -DEF_MESH_SIZE;    texCoordArray[2] = 0;
        vertexArray[4] = -DEF_MESH_SIZE;    texCoordArray[3] = 1;
        vertexArray[5] =  DEF_MESH_SIZE;

        vertexArray[6] =  DEF_MESH_SIZE;    texCoordArray[4] = 1;
        vertexArray[7] =  DEF_MESH_SIZE;    texCoordArray[5] = 0;
        vertexArray[8] =  DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[9]  = -DEF_MESH_SIZE;    texCoordArray[6] = 0;
        vertexArray[10] = -DEF_MESH_SIZE;    texCoordArray[7] = 1;
        vertexArray[11] =  DEF_MESH_SIZE;

        vertexArray[12] =  DEF_MESH_SIZE;    texCoordArray[8] = 1;
        vertexArray[13] = -DEF_MESH_SIZE;    texCoordArray[9] = 1;
        vertexArray[14] =  DEF_MESH_SIZE;

        vertexArray[15] =  DEF_MESH_SIZE;    texCoordArray[10] = 1;
        vertexArray[16] =  DEF_MESH_SIZE;    texCoordArray[11] = 0;
        vertexArray[17] =  DEF_MESH_SIZE;

    // Back face

        // Triangle 1

        vertexArray[18] = -DEF_MESH_SIZE;    texCoordArray[12] = 0;
        vertexArray[19] =  DEF_MESH_SIZE;    texCoordArray[13] = 0;
        vertexArray[20] = -DEF_MESH_SIZE;

        vertexArray[21] =  DEF_MESH_SIZE;    texCoordArray[14] = 1;
        vertexArray[22] =  DEF_MESH_SIZE;    texCoordArray[15] = 0;
        vertexArray[23] = -DEF_MESH_SIZE;

        vertexArray[24] = -DEF_MESH_SIZE;    texCoordArray[16] = 0;
        vertexArray[25] = -DEF_MESH_SIZE;    texCoordArray[17] = 1;
        vertexArray[26] = -DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[27] = -DEF_MESH_SIZE;    texCoordArray[18] = 0;
        vertexArray[28] = -DEF_MESH_SIZE;    texCoordArray[19] = 1;
        vertexArray[29] = -DEF_MESH_SIZE;

        vertexArray[30] =  DEF_MESH_SIZE;    texCoordArray[20] = 1;
        vertexArray[31] =  DEF_MESH_SIZE;    texCoordArray[21] = 0;
        vertexArray[32] = -DEF_MESH_SIZE;

        vertexArray[33] =  DEF_MESH_SIZE;    texCoordArray[22] = 1;
        vertexArray[34] = -DEF_MESH_SIZE;    texCoordArray[23] = 1;
        vertexArray[35] = -DEF_MESH_SIZE;

    // Left face

        // Triangle 1

        vertexArray[36] = -DEF_MESH_SIZE;    texCoordArray[24] = 0;
        vertexArray[37] =  DEF_MESH_SIZE;    texCoordArray[25] = 0;
        vertexArray[38] = -DEF_MESH_SIZE;

        vertexArray[39] = -DEF_MESH_SIZE;    texCoordArray[26] = 0;
        vertexArray[40] = -DEF_MESH_SIZE;    texCoordArray[27] = 1;
        vertexArray[41] = -DEF_MESH_SIZE;

        vertexArray[42] = -DEF_MESH_SIZE;    texCoordArray[28] = 1;
        vertexArray[43] =  DEF_MESH_SIZE;    texCoordArray[29] = 0;
        vertexArray[44] =  DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[45] = -DEF_MESH_SIZE;    texCoordArray[30] = 0;
        vertexArray[46] = -DEF_MESH_SIZE;    texCoordArray[31] = 1;
        vertexArray[47] = -DEF_MESH_SIZE;

        vertexArray[48] = -DEF_MESH_SIZE;    texCoordArray[32] = 1;
        vertexArray[49] = -DEF_MESH_SIZE;    texCoordArray[33] = 1;
        vertexArray[50] =  DEF_MESH_SIZE;

        vertexArray[51] = -DEF_MESH_SIZE;    texCoordArray[34] = 1;
        vertexArray[52] =  DEF_MESH_SIZE;    texCoordArray[35] = 0;
        vertexArray[53] =  DEF_MESH_SIZE;

    // Right face

        // Triangle 1

        vertexArray[54] =  DEF_MESH_SIZE;    texCoordArray[36] = 0;
        vertexArray[55] =  DEF_MESH_SIZE;    texCoordArray[37] = 0;
        vertexArray[56] = -DEF_MESH_SIZE;

        vertexArray[57] =  DEF_MESH_SIZE;    texCoordArray[38] = 1;
        vertexArray[58] =  DEF_MESH_SIZE;    texCoordArray[39] = 0;
        vertexArray[59] =  DEF_MESH_SIZE;

        vertexArray[60] =  DEF_MESH_SIZE;    texCoordArray[40] = 0;
        vertexArray[61] = -DEF_MESH_SIZE;    texCoordArray[41] = 1;
        vertexArray[62] = -DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[63] =  DEF_MESH_SIZE;    texCoordArray[42] = 0;
        vertexArray[64] = -DEF_MESH_SIZE;    texCoordArray[43] = 1;
        vertexArray[65] = -DEF_MESH_SIZE;

        vertexArray[66] =  DEF_MESH_SIZE;    texCoordArray[44] = 1;
        vertexArray[67] =  DEF_MESH_SIZE;    texCoordArray[45] = 0;
        vertexArray[68] =  DEF_MESH_SIZE;

        vertexArray[69] =  DEF_MESH_SIZE;    texCoordArray[46] = 1;
        vertexArray[70] = -DEF_MESH_SIZE;    texCoordArray[47] = 1;
        vertexArray[71] =  DEF_MESH_SIZE;

    // Top face

        // Triangle 1

        vertexArray[72] = -DEF_MESH_SIZE;    texCoordArray[48] = 0;
        vertexArray[73] =  DEF_MESH_SIZE;    texCoordArray[49] = 0;
        vertexArray[74] = -DEF_MESH_SIZE;

        vertexArray[75] = -DEF_MESH_SIZE;    texCoordArray[50] = 0;
        vertexArray[76] =  DEF_MESH_SIZE;    texCoordArray[51] = 1;
        vertexArray[77] =  DEF_MESH_SIZE;

        vertexArray[78] =  DEF_MESH_SIZE;    texCoordArray[52] = 1;
        vertexArray[79] =  DEF_MESH_SIZE;    texCoordArray[53] = 0;
        vertexArray[80] = -DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[81] = -DEF_MESH_SIZE;    texCoordArray[54] = 0;
        vertexArray[82] =  DEF_MESH_SIZE;    texCoordArray[55] = 1;
        vertexArray[83] =  DEF_MESH_SIZE;

        vertexArray[84] =  DEF_MESH_SIZE;    texCoordArray[56] = 1;
        vertexArray[85] =  DEF_MESH_SIZE;    texCoordArray[57] = 1;
        vertexArray[86] =  DEF_MESH_SIZE;

        vertexArray[87] =  DEF_MESH_SIZE;    texCoordArray[58] = 1;
        vertexArray[88] =  DEF_MESH_SIZE;    texCoordArray[59] = 0;
        vertexArray[89] = -DEF_MESH_SIZE;

    // Bottom face

        // Triangle 1

        vertexArray[90] = -DEF_MESH_SIZE;    texCoordArray[60] = 0;
        vertexArray[91] = -DEF_MESH_SIZE;    texCoordArray[61] = 0;
        vertexArray[92] = -DEF_MESH_SIZE;

        vertexArray[93] =  DEF_MESH_SIZE;    texCoordArray[62] = 1;
        vertexArray[94] = -DEF_MESH_SIZE;    texCoordArray[63] = 0;
        vertexArray[95] = -DEF_MESH_SIZE;

        vertexArray[96] = -DEF_MESH_SIZE;    texCoordArray[64] = 0;
        vertexArray[97] = -DEF_MESH_SIZE;    texCoordArray[65] = 1;
        vertexArray[98] =  DEF_MESH_SIZE;

        // Triangle 2

        vertexArray[99]  = -DEF_MESH_SIZE;    texCoordArray[66] = 0;
        vertexArray[100] = -DEF_MESH_SIZE;    texCoordArray[67] = 1;
        vertexArray[101] =  DEF_MESH_SIZE;

        vertexArray[102] =  DEF_MESH_SIZE;    texCoordArray[68] = 1;
        vertexArray[103] = -DEF_MESH_SIZE;    texCoordArray[69] = 0;
        vertexArray[104] = -DEF_MESH_SIZE;

        vertexArray[105] =  DEF_MESH_SIZE;    texCoordArray[70] = 1;
        vertexArray[106] = -DEF_MESH_SIZE;    texCoordArray[71] = 1;
        vertexArray[107] =  DEF_MESH_SIZE;

    //--------------------------------------------------------------------------
    // Generate mesh normals, edges and edge normals
    //--------------------------------------------------------------------------

    generateNormals();
    generateEdges();
    generateEdgeNormals();

    //--------------------------------------------------------------------------
    // Generate mesh bounding sphere
    //--------------------------------------------------------------------------

    generateBoundingSphere();

    //--------------------------------------------------------------------------
    // Undo this macro
    //--------------------------------------------------------------------------

    #undef DEF_MESH_SIZE
}
