/*
	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:   Camera
// Purpose:      Class that describes a position and orientation of a camera.
//               Also contains functions for manipulating that view. The camera
//               rotation functions are completely 6 degrees of freedom and are
//               not constrained by the camera's current orientation. This sort
//               of movement is required for an outdoor space game like this.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

#include "Camera.h"

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

Name:     Camera::Camera()
Purpose:  Default constructor for the camera object. Initialises the view in
          the default orientation and position.
Params:   none
Returns:  n/a

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

Camera::Camera()
{
    // Initialise the camera posiiton and orientation

    reset();
}

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

Name:     Camera::reset()
Purpose:  Resets the camera's position and orientation.
Params:   none
Returns:  none

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

void Camera::reset()
{
    // Reset camera's orientation matrix to identity:

    resetOrientation();

    // Reset camera position

    pos_x = 0;
    pos_y = 0;
    pos_z = 0;

    // Set the camera as not following any object

    followObject = 0;
}

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

Name:     Camera::resetOrientation()
Purpose:  Resets the camera's orientation
Params:   none
Returns:  none

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

void Camera::resetOrientation()
{
    // Reset camera's orientation matrix to view scene default orientation

    matrix[0] = 1;  matrix[1] = 0;  matrix[2] =  0;
    matrix[3] = 0;  matrix[4] = 1;  matrix[5] =  0;
    matrix[6] = 0;  matrix[7] = 0;  matrix[8] =  1;
}

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

Name:     Camera::setPosition()
Purpose:  Sets the camera's position
Params:   position to set to
Returns:  none

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

void Camera::setPosition( float x , float y , float z )
{
    // Set the camera's position

    pos_x = x;
    pos_y = y;
    pos_z = z;
}

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

Name:     Camera::getPosition()
Purpose:  Gets the camera's position and stores in the given 3 component vector
Params:   vector to save position to
Returns:  none

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

void Camera::getPosition( float * position )
{
    // Abort on null pointer

    if ( position == 0 ) return;

    // Otherwise get position: if following an object then take into account the objects position also

    if ( followObject )
    {
        //----------------------------------------------------------------------
        // Following another object. Take into account the objects position also.
        //----------------------------------------------------------------------

        // Get the cameras relative position to the object

        position[0] = pos_x;
        position[1] = pos_y;
        position[2] = pos_z;

        // Rotate this position by the orientation of the object being followed

        mlTransform3d( position , followMatrix );

        // Now add on the position of the object being followed

        position[0] += followPos_x;
        position[1] += followPos_y;
        position[2] += followPos_z;
    }
    else
    {
        // Not following another object. just give normal position

        position[0] = pos_x;
        position[1] = pos_y;
        position[2] = pos_z;
    }

}

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

Name:     Camera::move()
Purpose:  Moves camera's position by specified amount.
Params:   amount to move
Returns:  none

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

void Camera::move( float x , float y , float z )
{
    // Move the cameras position

    pos_x += x;
    pos_y += y;
    pos_z += z;
}

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

Name:     Camera::moveLocal()
Purpose:  Moves camera's position by specified amount, relative to its own direction.
Params:   amount to move
Returns:  none

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

void Camera::moveLocal( float x , float y , float z )
{
    // Move the cameras position relative to its own direction

    pos_x += x * matrix[0] + y * matrix[1] + z * matrix[2];
    pos_y += x * matrix[3] + y * matrix[4] + z * matrix[5];
    pos_z += x * matrix[6] + y * matrix[7] + z * matrix[8];
}

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

Name:     Camera::follow()
Purpose:  Makes the camera follow an object. Gets the objects position and orientation
          matrices, and camera orientation and position becomes relative to this.
          If object given is null then the camera follows no longer.
Params:   Object to follow. Whether or not to draw the object being followed.
Returns:  none

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

void Camera::follow( GameObject * object , bool followObjectVisible )
{
    // Set the object being followed:

    this->followObject = object;

    // Save whether to draw the object being followed or not:

    this->followObjectVisible = followObjectVisible;

    // If we are now following an object then set the camera paramters to make the camera follow it:

    if ( this->followObject )
    {
        // Get the position of the object

        followPos_x = object->getPosX();
        followPos_y = object->getPosY();
        followPos_z = object->getPosZ();

        // Save the orientation of the object

        object->getOrientationMatrix(followMatrix);
    }
}

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

Name:     Camera::viewFrom()
Purpose:  Sets up the modelview transform in openGL such that the scene is viewed
          from the cameras point of view and orientation.
Params:   none
Returns:  none

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

void Camera::viewFrom()
{
    // Select the model view matrix

    glMatrixMode(GL_MODELVIEW);

    // Get the cameras homegenous transformation matrix which combines the rotation and translations of the camera

    float transform[16]; getHomogenousMatrix(transform);

    // Load the transformation matrix with openGL

    glLoadMatrixf(transform);
}

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

Name:     Camera::getOrientationMatrix()
Purpose:  Retrieves the camera's orientation matrix and saves to matrix given
Params:   matrix to save to
Returns:  none

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

void Camera::getOrientationMatrix(float * matrix)
{
    // Check pointer is valid

    if ( matrix == 0 ) return;

    //--------------------------------------------------------------------------
    // See if the camera is following an object. If so then orientation is given
    // relative to the orientation of the object being followed.
    //--------------------------------------------------------------------------

    if ( followObject == 0 )
    {
        //----------------------------------------------------------------------
        // Easy case: not following an object.
        // Fill in the matrix with cameras' own orientation.
        //----------------------------------------------------------------------

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

        matrix[3] = this->matrix[3];
        matrix[4] = this->matrix[4];
        matrix[5] = this->matrix[5];

        matrix[6] = this->matrix[6];
        matrix[7] = this->matrix[7];
        matrix[8] = this->matrix[8];
    }
    else
    {
        //----------------------------------------------------------------------
        // Harder case: follwing another object. Must give orientation relative
        // to orientation of the object being followed.
        //----------------------------------------------------------------------

        // Easiest way is to get the cameras homogenous matrix: will be gotten
        // relative to the object being followed:

        float homogenousMatrix[16]; getHomogenousMatrix(homogenousMatrix);

        // Copy the orientation part from the homogenous matrix to matrix given

        matrix[0] = homogenousMatrix[0 ];
        matrix[1] = homogenousMatrix[1 ];
        matrix[2] = homogenousMatrix[2 ];

        matrix[3] = homogenousMatrix[4 ];
        matrix[4] = homogenousMatrix[5 ];
        matrix[5] = homogenousMatrix[6 ];

        matrix[6] = homogenousMatrix[8 ];
        matrix[7] = homogenousMatrix[9 ];
        matrix[8] = homogenousMatrix[10];
    }
}

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

Name:     Camera::getHomogenousMatrix()
Purpose:  Gets a homegenous 4x4 matrix that describes both the camera's orientation
          and position. Can be used for views in OpenGL.
Params:   matrix to save to
Returns:  none

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

void Camera::getHomogenousMatrix(float * matrix)
{
    // Check pointer is valid

    if ( matrix == 0 ) return;

    //--------------------------------------------------------------------------
    // See if the camera is following an object or not
    //--------------------------------------------------------------------------

    if ( followObject  == 0  )
    {
        //----------------------------------------------------------------------
        // Camera not following another object
        //----------------------------------------------------------------------

        // Make up a 4x4 matrix with the camera's orientation as the rotational part

        float rotation[16];

        rotation[0 ] = this->matrix[0];
        rotation[1 ] = this->matrix[1];
        rotation[2 ] = this->matrix[2];
        rotation[3 ] = 0;

        rotation[4 ] = this->matrix[3];
        rotation[5 ] = this->matrix[4];
        rotation[6 ] = this->matrix[5];
        rotation[7 ] = 0;

        rotation[8 ] = this->matrix[6];
        rotation[9 ] = this->matrix[7];
        rotation[10] = this->matrix[8];
        rotation[11] = 0;

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

        // Now make up another 4x4 matrix with the camera's position as the translation part

        float translation[16];

        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;

        // Now combine the translation and rotation (doing translation first) and save to rotation matrix

        mlMatrixMult4x4( translation , rotation );

        // Now save the rotation matrix to the matrix given

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

        matrix[4 ] = rotation[4 ];
        matrix[5 ] = rotation[5 ];
        matrix[6 ] = rotation[6 ];
        matrix[7 ] = rotation[7 ];

        matrix[8 ] = rotation[8 ];
        matrix[9 ] = rotation[9 ];
        matrix[10] = rotation[10];
        matrix[11] = rotation[11];

        matrix[12] = rotation[12];
        matrix[13] = rotation[13];
        matrix[14] = rotation[14];
        matrix[15] = rotation[15];
    }
    else
    {
        //----------------------------------------------------------------------
        // Camera is following another object: give the cameras transformation
        // matrix such that its position and orientation are given relative to
        // the object being followed. Maths gets a bit stingy.. but it does the job!
        //----------------------------------------------------------------------

        // Make up a 4x4 matrix with the camera's orientation as the rotational part

        float rotation[16];

        rotation[0 ] = this->matrix[0];
        rotation[1 ] = this->matrix[1];
        rotation[2 ] = this->matrix[2];
        rotation[3 ] = 0;

        rotation[4 ] = this->matrix[3];
        rotation[5 ] = this->matrix[4];
        rotation[6 ] = this->matrix[5];
        rotation[7 ] = 0;

        rotation[8 ] = this->matrix[6];
        rotation[9 ] = this->matrix[7];
        rotation[10] = this->matrix[8];
        rotation[11] = 0;

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

        // Makeup another matrix with the objects orientation (inverted by transposing)
        // as the rotational part. The rotation needs to be inverted since camera (world coordinate system) transforms
        // are the opposite of doing local (object coordinate system) transforms.

        float objectRotation[16];

        objectRotation[0 ] = this->followMatrix[0];
        objectRotation[1 ] = this->followMatrix[3];
        objectRotation[2 ] = this->followMatrix[6];
        objectRotation[3 ] = 0;

        objectRotation[4 ] = this->followMatrix[1];
        objectRotation[5 ] = this->followMatrix[4];
        objectRotation[6 ] = this->followMatrix[7];
        objectRotation[7 ] = 0;

        objectRotation[8 ] = this->followMatrix[2];
        objectRotation[9 ] = this->followMatrix[5];
        objectRotation[10] = this->followMatrix[8];
        objectRotation[11] = 0;

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

        // Combine the object and camera rotation, doing the object rotation first

        mlMatrixMult4x4( objectRotation , rotation  );

        // Now make up another 4x4 translation matrix to transform to the objects position

        float translation[16];

        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] = -followPos_x;
        translation[13] = -followPos_y;
        translation[14] = -followPos_z;
        translation[15] = 1;

        // Now consider the cameras position in this matrix (which is relative to the object being followed)
        // The cameras position is described not only relative to the objects position, but to its orientation too:

        translation[12] -= pos_x * followMatrix[0] + pos_y * followMatrix[3] + pos_z * followMatrix[6];
        translation[13] -= pos_x * followMatrix[1] + pos_y * followMatrix[4] + pos_z * followMatrix[7];
        translation[14] -= pos_x * followMatrix[2] + pos_y * followMatrix[5] + pos_z * followMatrix[8];

        // Now combine the translation and rotation (doing translation first) and save to rotation matrix

        mlMatrixMult4x4( translation , rotation );

        // Now save the rotation matrix to the matrix given

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

        matrix[4 ] = rotation[4 ];
        matrix[5 ] = rotation[5 ];
        matrix[6 ] = rotation[6 ];
        matrix[7 ] = rotation[7 ];

        matrix[8 ] = rotation[8 ];
        matrix[9 ] = rotation[9 ];
        matrix[10] = rotation[10];
        matrix[11] = rotation[11];

        matrix[12] = rotation[12];
        matrix[13] = rotation[13];
        matrix[14] = rotation[14];
        matrix[15] = rotation[15];
    }
}

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

Name:     Camera::rotateX()
Purpose:  Rotates camera's orientation about the x axis
Params:   amount to rotate by
Returns:  none

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

void Camera::rotateX( float angle )
{
    // Make up two unit vectors: representing the y and z axis

    float vecy[3] = { 0 , 1 , 0 };
    float vecz[3] = { 0 , 0 , 1 };

    // Rotate these vectors about the y axis

    mlRotate3dX( vecy , angle );
    mlRotate3dX( vecz , angle );

    // Now make up a 3x3 matrix with the two rotated vectors as columns and another column for the other axis (x)

    float rotation[9] =
    {
        1 ,  vecy[0] , vecz[0],
        0 ,  vecy[1] , vecz[1],
        0 ,  vecy[2] , vecz[2]
    };

    // Describe the cameras current orientation in terms of the rotation and save result to rotatation

    mlMatrixMult3x3( matrix , rotation );

    // Orthogonalise rotation matrix: done to prevent error build up

    mlOrthogonalise3x3(rotation);

    // Normalise the rotation matrix: done to prevent error build up

    mlNormalise3x3(rotation);

    // Save the rotation matrix as the cameras new orientation matrix

    matrix[0] = rotation[0];
    matrix[1] = rotation[1];
    matrix[2] = rotation[2];

    matrix[3] = rotation[3];
    matrix[4] = rotation[4];
    matrix[5] = rotation[5];

    matrix[6] = rotation[6];
    matrix[7] = rotation[7];
    matrix[8] = rotation[8];
}

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

Name:     Camera::rotateY()
Purpose:  Rotates camera's orientation about the y axis
Params:   amount to rotate by
Returns:  none

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

void Camera::rotateY( float angle )
{
    // Make up two unit vectors: representing the x and z axis

    float vecx[3] = { 1 , 0 , 0 };
    float vecz[3] = { 0 , 0 , 1 };

    // Rotate these vectors about the y axis

    mlRotate3dY( vecx , -angle );
    mlRotate3dY( vecz , -angle );

    // Now make up a 3x3 matrix with the two rotated vectors as columns and another column for the other axis (y)

    float rotation[9] =
    {
        vecx[0] , 0 , vecz[0],
        vecx[1] , 1 , vecz[1],
        vecx[2] , 0 , vecz[2]
    };

    // Describe the cameras current orientation in terms of the rotation and save result to rotatation

    mlMatrixMult3x3( matrix , rotation );

    // Orthogonalise rotation matrix: done to prevent error build up

    mlOrthogonalise3x3(rotation);

    // Normalise the rotation matrix: done to prevent error build up

    mlNormalise3x3(rotation);

    // Save the rotation matrix as the cameras new orientation matrix

    matrix[0] = rotation[0];
    matrix[1] = rotation[1];
    matrix[2] = rotation[2];

    matrix[3] = rotation[3];
    matrix[4] = rotation[4];
    matrix[5] = rotation[5];

    matrix[6] = rotation[6];
    matrix[7] = rotation[7];
    matrix[8] = rotation[8];
}

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

Name:     Camera::rotateZ()
Purpose:  Rotates camera's orientation about the z axis
Params:   amount to rotate by
Returns:  none

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

void Camera::rotateZ( float angle )
{
    // Make up two unit vectors: representing the x and y axis

    float vecx[3] = { 1 , 0 , 0 };
    float vecy[3] = { 0 , 1 , 0 };

    // Rotate these vectors about the z axis

    mlRotate3dZ( vecx , -angle );
    mlRotate3dZ( vecy , -angle );

    // Now make up a 3x3 matrix with the two rotated vectors as columns and another column for the other axis (z)

    float rotation[9] =
    {
        vecx[0] , vecy[0] , 0 ,
        vecx[1] , vecy[1] , 0 ,
        vecx[2] , vecy[2] , 1
    };

    // Describe the cameras current orientation in terms of the rotation and save result to rotatation

    mlMatrixMult3x3( matrix , rotation );

    // Orthogonalise rotation matrix: done to prevent error build up

    mlOrthogonalise3x3(rotation);

    // Normalise the rotation matrix: done to prevent error build up

    mlNormalise3x3(rotation);

    // Save the rotation matrix as the cameras new orientation matrix

    matrix[0] = rotation[0];
    matrix[1] = rotation[1];
    matrix[2] = rotation[2];

    matrix[3] = rotation[3];
    matrix[4] = rotation[4];
    matrix[5] = rotation[5];

    matrix[6] = rotation[6];
    matrix[7] = rotation[7];
    matrix[8] = rotation[8];
}
