/*
	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.
*/

#ifndef MATHLIBRARY_H
#define MATHLIBRARY_H

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include <cmath>
#include <cstdlib>

//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################
//
//
// Module Name:  MathLibrary
// Purpose:      C Module consisting of various maths helper functions.
//
//
//##############################################################################
//##############################################################################
//##############################################################################
//##############################################################################

//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------

// PI * 2, PI, PI/2, PI/4 etc...

#define PI_INV      0.31830988618379067153776752674503f
#define PI2		    6.283185307179586476925286766559f
#define PI		    3.1415926535897932384626433832795f
#define PI_2		1.5707963267948966192313216916398f
#define PI_4		0.78539816339744830961566084581988f
#define PI_8        0.39269908169872415480783042290994f
#define PI_16       0.19634954084936207740391521145497f
#define PI_32       0.098174770424681038701957605727484f
#define PI_64       0.049087385212340519350978802863742f
#define PI_128      0.024543692606170259675489401431871f
#define PI_256      0.012271846303085129837744700715936f

// Degrees to radians, radians to degrees: just multiply by these to convert

#define TO_RADIANS  0.017453292519943295769236907684886f
#define TO_DEGREES  57.295779513082320876798154814105f

//------------------------------------------------------------------------------
// 2D Vector functions
//------------------------------------------------------------------------------

void    mlNormalise2d  ( float * vec1 );                                // normalise a vector
float   mlLenght2d     ( const float * vec1 );                          // get vector lenght
float   mlMagnitude2d  ( const float * vec1 );                          // get vector magnitude
float   mlAngle2d      ( const float * vec1 );                          // returns orientation of a vector (in radians) in range 0-2PI
float   mlDot2d        ( const float * vec1 , const float * vec2 );     // dot product between two vectors
void    mlScale2d      ( float * vec1 , const float   scale  );         // scales input vector by amount
void    mlRotate2d     ( float * vec1 , const float   angle  );         // Rotates a vector anti-clockwise by given angle (in radians)
void    mlRotate2dCW   ( float * vec1 , const float   angle  );         // Rotates a vector clockwise by given angle (in radians)
void    mlTranslate2d  ( float * vec1 , const float * vec2   );         // Translates vec1 by vec2

//------------------------------------------------------------------------------
// 2D Polygon functions
//------------------------------------------------------------------------------

// Tells if a point is inside a polygon. polygon must be convex for this to work correctly.

bool mlPointInPolygon2d
(
    float       x ,         // x coordinate of point to check
    float       y ,         // y coordinate of point to check
    float *     coords ,    // pointer to array of x,y coordinates for the polygon
    unsigned    numPoints   // number of points in the polygon
);

//------------------------------------------------------------------------------
// 3D Vector functions
//------------------------------------------------------------------------------

void    mlScale3d      ( float * vec1 , float   scale  );                 // scales input vector by amount
void    mlTranslate3d  ( float * vec1 , const float * vec2   );           // Translates vec1 by vec2
void    mlNormalise3d  ( float * vec1 );                                  // normalise a vector
float   mlLenght3d     ( const float * vec1 );                            // get vector lenght
float   mlMagnitude3d  ( const float * vec1 );                            // get vector magnitude
void    mlRotate3dX    ( float * vec1 , const float angle );              // Rotate vector about x axis by angle degrees (in radians)
void    mlRotate3dY    ( float * vec1 , const float angle );              // Rotate vector about y axis by angle degrees (in radians)
void    mlRotate3dZ    ( float * vec1 , const float angle );              // Rotate vector about z axis by angle degrees (in radians)
float   mlDot3d        ( const float * vec1 , const float * vec2 );       // dot product between two vectors

// Distance between two 3d points

float mlDistance3d
(
    const float * vec1 ,
    const float * vec2
);

// Squared distance between two 3d points

float mlSquaredDistance3d
(
    const float * vec1 ,
    const float * vec2
);

// 3d cross product between two vectors: save to dest

void mlCross3d
(
    const float * vec1 ,
    const float * vec2 ,
    float * dest
);

// Reflects vec1 through vec2

void mlReflect3d
(
    float       * vec1,
    const float * vec2
);

//------------------------------------------------------------------------------
// Matrix multiplication functions
//------------------------------------------------------------------------------

void mlMatrixMult3x3  ( const float * matrix1, float * matrix2 );   // Multiplies matrix2 by matrix1 and saves result in matrix2 (both matrices 3x3 in dimensions)
void mlMatrixMult4x4  ( const float * matrix1, float * matrix2 );   // Multiplies matrix2 by matrix1 and saves result in matrix2 (both matrices 4x4 in dimensions)

//------------------------------------------------------------------------------
// Miscellaneous matrix operations
//------------------------------------------------------------------------------

void mlTranspose3x3     ( float * matrix );    // transposes a 3x3 matrix, changing columns into rows.
void mlTranspose4x4     ( float * matrix );    // transposes a 4x4 matrix, changing columns into rows.
void mlOrthogonalise3x3 ( float * matrix );    // forces all three column vectors of the 3x3 matrix to be perpendicular to each other
void mlNormalise3x3     ( float * matrix );    // normalises the three column vectors of the 3x3 matrix

//------------------------------------------------------------------------------
// Vector / matrix transformation functions
//------------------------------------------------------------------------------

void mlTransform3d( float * vec , const float * matrix );     // Transform the given 3 component vector by the given 3x3 matrix
void mlTransform4d( float * vec , const float * matrix );     // Transform the homogenous row vector by the homogenous 4x4 matrix

//------------------------------------------------------------------------------
// 3D Line functions
//------------------------------------------------------------------------------

// Intersect the line with the plane given. If line is parallel to plane then
// resulting point will be given as a point at near infinity along the the line

void mlLinePlaneIntersect3d
(
    const float * lineStart,
    const float * lineDirection,
    const float * planeNormal,
    const float * planePoint,
    float       * intersectPoint
);

//------------------------------------------------------------------------------
// 3D Point functions
//------------------------------------------------------------------------------

// Find the shortest distance from a point to a line:
// direction does not neccesarily have to be normalised.

float mlPointDistanceToLine3d
(
    const float * point,
    const float * lineStart,
    const float * lineDirection
);

// Same as above, but gives squared distance and is faster:

float mlPointSquaredDistanceToLine3d
(
    const float * point,
    const float * lineStart,
    const float * lineDirection
);

// Find the distance from a point to a plane. may be negative depending on which
// side of the plane the point lies. Line is considered infinite in this case.

float mlPointToPlaneDistance3d
(
    const float * point,
    const float * planeNormal,
    const float * planePoint
);

// Find the squared distance from a point to a plane

float mlPointToPlaneSquaredDistance3d
(
    const float * point,
    const float * planeNormal,
    const float * planePoint
);

// Tells if a point is on the 'inside' of a plane:

bool mlPointInsidePlane3d
(
    const float * point,
    const float * planeNormal,
    const float * planePoint
);

// See if a point is contained within a sphere

bool mlPointInSphere3d
(
    const float * point,
    const float * spherePosition,
    float         sphereRadius
);

//------------------------------------------------------------------------------
// Sphere functions
//------------------------------------------------------------------------------

// Collides a bounding sphere with a given line segment and changes bounding
// sphere position such that there is no more collision: returns true if there was a collision

bool mlSphereLineCollision3d
(
    const float *  lineStart,
    const float *  lineEnd,
    float *        spherePosition,
    float          sphereRadius
);

// See if a bounding sphere interesects or lies inside a half space defined by a plane

bool mlSphereInsidePlane3d
(
    const float * spherePosition,
    const float   sphereRadius,
    const float * planeNormal,
    const float * planePoint
);

//------------------------------------------------------------------------------
// Other
//------------------------------------------------------------------------------

// Gives a random float between 0 and 1

float mlRandomFloat();

// Gives a random integer. may be any value.

unsigned mlRandomInt();

// Seeds the random number generator.

void mlRandomSeed( unsigned randomSeed );

// Rounds the given float and returns the rounded value:

float mlRound( float value );

// Rounds to a specified number of decimal places

float mlDecimalRound( float value , unsigned decimalPlaces );

#endif // ifndef MATHLIBRARY_H
