/*
 *			GPAC - Multimedia Framework C SDK
 *
 *			Authors: Jean Le Feuvre
 *			Copyright (c) Telecom ParisTech 2000-2019
 *					All rights reserved
 *
 *  This file is part of GPAC / common tools sub-project
 *
 *  GPAC is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  GPAC is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#ifndef _GF_MATH_H_
#define _GF_MATH_H_

#ifdef __cplusplus
extern "C" {
#endif

/*!
\file <gpac/maths.h>
\brief Mathematics and Trigonometric.
 */

#include <gpac/setup.h>

#include <math.h>


/*!
\addtogroup math_grp
\brief Mathematics and Trigonometric

This section documents the math and trigo functions used in the GPAC framework. GPAC can be compiled with
 fixed-point support, representing float values on a 16.16 signed integer, which implies a developer
 must take care of float computations when using GPAC.\n
 A developper should not need to know in which mode the framework has been compiled as long as he uses
 the math functions of GPAC which work in both float and fixed-point mode.\n
 Using fixed-point version is decided at compilation time and cannot be changed. The feature is signaled
 through the GPAC_FIXED_POINT macro: when defined, GPAC has been compiled in fixed-point mode

@{
 */


/*****************************************************************************************
			FIXED-POINT SUPPORT - HARDCODED FOR 16.16 representation
	the software rasterizer also use a 16.16 representation even in non-fixed version
******************************************************************************************/

#ifdef GPAC_FIXED_POINT

/*!
Fixed 16.16 number
\hideinitializer
 \note This documentation has been generated for a fixed-point version of the GPAC framework.
 */
typedef s32 Fixed;
#define FIX_ONE			0x10000L
#define INT2FIX(v)		((Fixed)( ((s32) (v) ) << 16))
#define FLT2FIX(v)		((Fixed) ((v) * FIX_ONE))
#define FIX2INT(v)		((s32)(((v)+((FIX_ONE>>1)))>>16))
#define FIX2FLT(v)		((Float)( ((Float)(v)) / ((Float) FIX_ONE)))
#define FIX_EPSILON		2
#define FIX_MAX			0x7FFFFFFF
#define FIX_MIN			-FIX_MAX
#define GF_PI2		102944
#define GF_PI		205887
#define GF_2PI		411774

/*!\return 1/a, expressed as fixed number*/
Fixed gf_invfix(Fixed a);
/*!\return a*b, expressed as fixed number*/
Fixed gf_mulfix(Fixed a, Fixed b);
/*!\return a*b/c, expressed as fixed number*/
Fixed gf_muldiv(Fixed a, Fixed b, Fixed c);
/*!\return a/b, expressed as fixed number*/
Fixed gf_divfix(Fixed a, Fixed b);
/*!\return sqrt(a), expressed as fixed number*/
Fixed gf_sqrt(Fixed x);
/*!\return ceil(a), expressed as fixed number*/
Fixed gf_ceil(Fixed a);
/*!\return floor(a), expressed as fixed number*/
Fixed gf_floor(Fixed a);
/*!\return cos(a), expressed as fixed number*/
Fixed gf_cos(Fixed angle);
/*!\return sin(a), expressed as fixed number*/
Fixed gf_sin(Fixed angle);
/*!\return tan(a), expressed as fixed number*/
Fixed gf_tan(Fixed angle);
/*!\return acos(a), expressed as fixed number*/
Fixed gf_acos(Fixed angle);
/*!\return asin(a), expressed as fixed number*/
Fixed gf_asin(Fixed angle);
/*!\return atan(y, x), expressed as fixed number*/
Fixed gf_atan2(Fixed y, Fixed x);

#else


/*!Fixed is 32bit float number
 \note This documentation has been generated for a float version of the GPAC framework.
*/
typedef Float Fixed;
#define FIX_ONE			1.0f
#define INT2FIX(v)		((Float) (v))
#define FLT2FIX(v)		((Float) (v))
#define FIX2INT(v)		((s32)(v))
#define FIX2FLT(v)		((Float) (v))
#define FIX_EPSILON		GF_EPSILON_FLOAT
#define FIX_MAX			GF_MAX_FLOAT
#define FIX_MIN			-GF_MAX_FLOAT
#define GF_PI2		1.5707963267949f
#define GF_PI		3.1415926535898f
#define GF_2PI		6.2831853071796f

/*!\hideinitializer 1/_a, expressed as fixed number*/
#define gf_invfix(_a)	(FIX_ONE/(_a))
/*!\hideinitializer _a*_b, expressed as fixed number*/
#define gf_mulfix(_a, _b)		((_a)*(_b))
/*!\hideinitializer _a*_b/_c, expressed as fixed number*/
#define gf_muldiv(_a, _b, _c)	(((_c != 0)) ? (_a)*(_b)/(_c) : GF_MAX_FLOAT)
/*!\hideinitializer _a/_b, expressed as fixed number*/
#define gf_divfix(_a, _b)		(((_b != 0)) ? (_a)/(_b) : GF_MAX_FLOAT)
/*!\hideinitializer sqrt(_a), expressed as fixed number*/
#define gf_sqrt(_a) ((Float) sqrt(_a))
/*!\hideinitializer ceil(_a), expressed as fixed number*/
#define gf_ceil(_a) ((Float) ceil(_a))
/*!\hideinitializer floor(_a), expressed as fixed number*/
#define gf_floor(_a) ((Float) floor(_a))
/*!\hideinitializer cos(_a), expressed as fixed number*/
#define gf_cos(_a) ((Float) cos(_a))
/*!\hideinitializer sin(_a), expressed as fixed number*/
#define gf_sin(_a) ((Float) sin(_a))
/*!\hideinitializer tan(_a), expressed as fixed number*/
#define gf_tan(_a) ((Float) tan(_a))
/*!\hideinitializer atan2(_y,_x), expressed as fixed number*/
#define gf_atan2(_y, _x) ((Float) atan2(_y, _x))
/*!\hideinitializer acos(_a), expressed as fixed number*/
#define gf_acos(_a) ((Float) acos(_a))
/*!\hideinitializer asin(_a), expressed as fixed number*/
#define gf_asin(_a) ((Float) asin(_a))

#endif

/*!\def FIX_ONE
 \hideinitializer
 Fixed unit value
*/
/*!\def INT2FIX(v)
 \hideinitializer
 Conversion from integer to fixed
*/
/*!\def FLT2FIX(v)
 \hideinitializer
 Conversion from float to fixed
*/
/*!\def FIX2INT(v)
 \hideinitializer
 Conversion from fixed to integer
*/
/*!\def FIX2FLT(v)
 \hideinitializer
 Conversion from fixed to float
*/
/*!\def FIX_EPSILON
 \hideinitializer
 Epsilon Fixed (positive value closest to 0)
*/
/*!\def FIX_MAX
 \hideinitializer
 Maximum Fixed (maximum representable fixed value)
*/
/*!\def FIX_MIN
 \hideinitializer
 Minimum Fixed (minimum representable fixed value)
*/
/*!\def GF_PI2
 \hideinitializer
 PI/2 expressed as Fixed
*/
/*!\def GF_PI
 \hideinitializer
 PI expressed as Fixed
*/
/*!\def GF_2PI
 \hideinitializer
 2*PI expressed as Fixed
*/

/*! compute the difference between two angles, with a result in [-PI, PI]
\param a first angle
\param b first angle
\return angle difference
*/
Fixed gf_angle_diff(Fixed a, Fixed b);

/*!
\brief Field bit-size

Gets the number of bits needed to represent the value.
\param MaxVal Maximum value to be represented.
\return number of bits required to represent the value.
 */
u32 gf_get_bit_size(u32 MaxVal);

/*!
\brief Get power of 2

Gets the closest power of 2 greater or equal to the value.
\param val value to be used.
\return requested power of 2.
 */
u32 gf_get_next_pow2(u32 val);

/*!
\addtogroup math2d_grp Math 2d
\ingroup math_grp
\brief 2D Mathematics

This section documents mathematic tools for 2D geometry and color matrices operations

@{
 */

/*!\brief 2D point
 *
 *The 2D point object is used in all the GPAC framework for both point and vector representation.
*/
typedef struct __vec2f
{
	Fixed x;
	Fixed y;
} GF_Point2D;
/*!
\brief get 2D vector length

Gets the length of a 2D vector
\param vec the target vector
\return length of the vector
 */
Fixed gf_v2d_len(GF_Point2D *vec);
/*!
\brief get distance between 2 points

Gets the distance between the 2 points
\param a first point
\param b second point
\return distance
 */
Fixed gf_v2d_distance(GF_Point2D *a, GF_Point2D *b);
/*!
\brief 2D vector from polar coordinates

Constructs a 2D vector from its polar coordinates
\param length the length of the vector
\param angle the angle of the vector in radians
\return the 2D vector
 */
GF_Point2D gf_v2d_from_polar(Fixed length, Fixed angle);

/*!
\brief rectangle 2D

The 2D rectangle used in the GPAC project.
 */
typedef struct
{
	/*!the left coordinate of the rectangle*/
	Fixed x;
	/*!the top coordinate of the rectangle, regardless of the canvas orientation. In other words, y is always the
	greatest coordinate value, 	even if the rectangle is presented bottom-up. This insures proper rectangles testing*/
	Fixed y;
	/*!the width of the rectangle. Width must be greater than or equal to 0*/
	Fixed width;
	/*!the height of the rectangle. Height must be greater than or equal to 0*/
	Fixed height;
} GF_Rect;

/*!
 \brief rectangle union

Gets the union of two rectangles.
\param rc1 first rectangle of the union. Upon return, this rectangle will contain the result of the union
\param rc2 second rectangle of the union
*/
void gf_rect_union(GF_Rect *rc1, GF_Rect *rc2);
/*!
 \brief centers a rectangle

Builds a rectangle centered on the origin
\param w width of the rectangle
\param h height of the rectangle
\return centered rectangle object
*/
GF_Rect gf_rect_center(Fixed w, Fixed h);
/*!
 \brief rectangle overlap test

Tests if two rectangles overlap.
\param rc1 first rectangle to test
\param rc2 second rectangle to test
\return 1 if rectangles overlap, 0 otherwise
*/
Bool gf_rect_overlaps(GF_Rect rc1, GF_Rect rc2);
/*!
\brief rectangle identity test

Tests if two rectangles are identical.
\param rc1 first rectangle to test
\param rc2 second rectangle to test
\return 1 if rectangles are identical, 0 otherwise
*/
Bool gf_rect_equal(GF_Rect *rc1, GF_Rect *rc2);

/*!
\brief pixel-aligned rectangle

Pixel-aligned rectangle used in the GPAC framework. This is usually needed for 2D drawing algorithms.
 */
typedef struct
{
	/*!the left coordinate of the rectangle*/
	s32 x;
	/*!the top coordinate of the rectangle, regardless of the canvas orientation. In other words, y is always the
	greatest coordinate value, even if the rectangle is presented bottom-up. This insures proper rectangles operations*/
	s32 y;
	/*!the width of the rectangle. Width must be greater than or equal to 0*/
	s32 width;
	/*!the height of the rectangle. Height must be greater than or equal to 0*/
	s32 height;
} GF_IRect;
/*!
\brief gets the pixelized version of a rectangle

Gets the smallest pixel-aligned rectangle completely containing a rectangle
\param r the rectangle to transform
\return the pixel-aligned transformed rectangle
*/
GF_IRect gf_rect_pixelize(GF_Rect *r);


/*!
\brief 2D matrix

The 2D affine matrix object usied in GPAC. The transformation of P(x,y) in P'(X, Y) is:
 \code
	X = m[0]*x + m[1]*y + m[2];
	Y = m[3]*x + m[4]*y + m[5];
 \endcode
*/
typedef struct
{
	Fixed m[6];
} GF_Matrix2D;

/*!\brief matrix initialization
\hideinitializer

Inits the matrix to the identity matrix
*/
#define gf_mx2d_init(_obj) { memset((_obj).m, 0, sizeof(Fixed)*6); (_obj).m[0] = (_obj).m[4] = FIX_ONE; }
/*!\brief matrix copy
\hideinitializer

Copies the matrix _from to the matrix _obj
*/
#define gf_mx2d_copy(_obj, from) memcpy((_obj).m, (from).m, sizeof(Fixed)*6)
/*!\brief matrix identity testing
\hideinitializer

This macro evaluates to 1 if the matrix _obj is the identity matrix, 0 otherwise
*/
#define gf_mx2d_is_identity(_obj) ((!(_obj).m[1] && !(_obj).m[2] && !(_obj).m[3] && !(_obj).m[5] && ((_obj).m[0]==FIX_ONE) && ((_obj).m[4]==FIX_ONE)) ? 1 : 0)

/*!\brief 2D matrix multiplication

Multiplies two 2D matrices from*_this
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param from transformation matrix to add
*/
void gf_mx2d_add_matrix(GF_Matrix2D *_this, GF_Matrix2D *from);

/*!\brief 2D matrix pre-multiplication

Multiplies two 2D matrices _this*from
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param from transformation matrix to add
*/
void gf_mx2d_pre_multiply(GF_Matrix2D *_this, GF_Matrix2D *from);

/*!\brief matrix translating

Translates a 2D matrix
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param cx horizontal translation
\param cy vertical translation
*/
void gf_mx2d_add_translation(GF_Matrix2D *_this, Fixed cx, Fixed cy);
/*!\brief matrix rotating

Rotates a 2D matrix
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param cx horizontal rotation center coordinate
\param cy vertical rotation center coordinate
\param angle rotation angle in radians
*/
void gf_mx2d_add_rotation(GF_Matrix2D *_this, Fixed cx, Fixed cy, Fixed angle);
/*!\brief matrix scaling

Scales a 2D matrix
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param scale_x horizontal scaling factor
\param scale_y vertical scaling factor
*/
void gf_mx2d_add_scale(GF_Matrix2D *_this, Fixed scale_x, Fixed scale_y);
/*!\brief matrix uncentered scaling

Scales a 2D matrix with a non-centered scale
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param scale_x horizontal scaling factor
\param scale_y vertical scaling factor
\param cx horizontal scaling center coordinate
\param cy vertical scaling center coordinate
\param angle scale orienttion angle in radians
*/
void gf_mx2d_add_scale_at(GF_Matrix2D *_this, Fixed scale_x, Fixed scale_y, Fixed cx, Fixed cy, Fixed angle);
/*!\brief matrix skewing

Skews a 2D matrix
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param skew_x horizontal skew factor
\param skew_y vertical skew factor
*/
void gf_mx2d_add_skew(GF_Matrix2D *_this, Fixed skew_x, Fixed skew_y);
/*!\brief matrix horizontal skewing

Skews a 2D matrix horizontally by a given angle
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param angle horizontal skew angle in radians
*/
void gf_mx2d_add_skew_x(GF_Matrix2D *_this, Fixed angle);
/*!\brief matrix vertical skewing

Skews a 2D matrix vertically by a given angle
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
\param angle vertical skew angle in radians
*/
void gf_mx2d_add_skew_y(GF_Matrix2D *_this, Fixed angle);
/*!\brief matrix inversing

Inverses a 2D matrix
\param _this matrix being transformed. Once the function is called, _this contains the result matrix
*/
void gf_mx2d_inverse(GF_Matrix2D *_this);
/*!\brief matrix coordinate transformation

Applies a 2D matrix transformation to coordinates
\param _this transformation matrix
\param x pointer to horizontal coordinate. Once the function is called, x contains the transformed horizontal coordinate
\param y pointer to vertical coordinate. Once the function is called, y contains the transformed vertical coordinate
*/
void gf_mx2d_apply_coords(GF_Matrix2D *_this, Fixed *x, Fixed *y);
/*!\brief matrix point transformation

Applies a 2D matrix transformation to a 2D point
\param _this transformation matrix
\param pt pointer to 2D point. Once the function is called, pt contains the transformed point
*/
void gf_mx2d_apply_point(GF_Matrix2D *_this, GF_Point2D *pt);
/*!\brief matrix rectangle transformation

Applies a 2D matrix transformation to a rectangle, giving the enclosing rectangle of the transformed one
\param _this transformation matrix
\param rc pointer to rectangle. Once the function is called, rc contains the transformed rectangle
*/
void gf_mx2d_apply_rect(GF_Matrix2D *_this, GF_Rect *rc);

/*!\brief matrix decomposition

Decomposes a 2D matrix M as M=Scale x Rotation x Translation if possible
\param _this transformation matrix
\param scale resulting scale part
\param rotate resulting rotation part
\param translate resulting translation part
\return 0 if matrix cannot be decomposed, 1 otherwise
*/
Bool gf_mx2d_decompose(GF_Matrix2D *_this, GF_Point2D *scale, Fixed *rotate, GF_Point2D *translate);

/*! @} */


/*!
\addtogroup math3d_grp Math 3d
\ingroup math_grp
\brief 3D Mathematics

This section documents mathematic tools for 3D geometry operations

@{
 */

/*!\brief 3D point or vector

The 3D point object is used in all the GPAC framework for both point and vector representation.
*/
typedef struct __vec3f
{
	Fixed x;
	Fixed y;
	Fixed z;
} GF_Vec;

/*base vector operations are MACROs for faster access*/
/*!\hideinitializer macro evaluating to 1 if vectors are equal, 0 otherwise*/
#define gf_vec_equal(v1, v2) (((v1).x == (v2).x) && ((v1).y == (v2).y) && ((v1).z == (v2).z))
/*!\hideinitializer macro reversing a vector v = v*/
#define gf_vec_rev(v) { (v).x = -(v).x; (v).y = -(v).y; (v).z = -(v).z; }
/*!\hideinitializer macro performing the minus operation res = v1 - v2*/
#define gf_vec_diff(res, v1, v2) { (res).x = (v1).x - (v2).x; (res).y = (v1).y - (v2).y; (res).z = (v1).z - (v2).z; }
/*!\hideinitializer macro performing the add operation res = v1 + v2*/
#define gf_vec_add(res, v1, v2) { (res).x = (v1).x + (v2).x; (res).y = (v1).y + (v2).y; (res).z = (v1).z + (v2).z; }

/*!
\brief get 3D vector length

Gets the length of a 3D vector
\param v the target vector
\return length of the vector
 */
Fixed gf_vec_len(GF_Vec v);

/*!
\brief get 3D vector length

Gets the length of a 3D vector
\param v the target vector
\return length of the vector
 */
Fixed gf_vec_len_p(GF_Vec *v);

/*!
\brief get 3D vector square length

Gets the square length of a 3D vector
\param v the target vector
\return square length of the vector
 */
Fixed gf_vec_lensq(GF_Vec v);

/*!
\brief get 3D vector square length

Gets the square length of a 3D vector
\param v the target vector
\return square length of the vector
 */
Fixed gf_vec_lensq_p(GF_Vec *v);
/*!
\brief get 3D vector dot product

Gets the dot product of two vectors
\param v1 first vector
\param v2 second vector
\return dot product of the vectors
 */
Fixed gf_vec_dot(GF_Vec v1, GF_Vec v2);
/*!
\brief get 3D vector dot product

Gets the dot product of two vectors
\param v1 first vector
\param v2 second vector
\return dot product of the vectors
 */
Fixed gf_vec_dot_p(GF_Vec *v1, GF_Vec *v2);
/*!
\brief vector normalization

Normalize the vector, eg make its length equal to \ref FIX_ONE
\param v vector to normalize
 */
void gf_vec_norm(GF_Vec *v);
/*!
\brief vector scaling

Scales a vector by a given amount
\param v vector to scale
\param f scale factor
\return scaled vector
 */
GF_Vec gf_vec_scale(GF_Vec v, Fixed f);
/*!
\brief vector scaling

Scales a vector by a given amount
\param v vector to scale
\param f scale factor
\return scaled vector
 */
GF_Vec gf_vec_scale_p(GF_Vec *v, Fixed f);
/*!
\brief vector cross product

Gets the cross product of two vectors
\param v1 first vector
\param v2 second vector
\return cross-product vector
 */
GF_Vec gf_vec_cross(GF_Vec v1, GF_Vec v2);
/*!
\brief vector cross product

Gets the cross product of two vectors
\param v1 first vector
\param v2 second vector
\return cross-product vector
 */
GF_Vec gf_vec_cross_p(GF_Vec *v1, GF_Vec *v2);

/*!\brief 4D vector

The 4D vector object is used in all the GPAC framework for 4 dimension vectors, VRML Rotations and quaternions representation.
*/
typedef struct __vec4f
{
	Fixed x;
	Fixed y;
	Fixed z;
	Fixed q;
} GF_Vec4;


/*!\brief 3D matrix

The 3D matrix object used in GPAC. The matrix is oriented like OpenGL matrices (column-major ordering), with
 the translation part at the end of the coefficients list.
 \note Unless specified otherwise, the matrix object is always expected to represent an affine transformation.
 */
typedef struct __matrix
{
	Fixed m[16];
} GF_Matrix;


/*!\hideinitializer gets the len of a quaternion*/
#define gf_quat_len(v) gf_sqrt(gf_mulfix((v).q,(v).q) + gf_mulfix((v).x,(v).x) + gf_mulfix((v).y,(v).y) + gf_mulfix((v).z,(v).z))
/*!\hideinitializer normalizes a quaternion*/
#define gf_quat_norm(v) { \
	Fixed __mag = gf_quat_len(v);	\
	(v).x = gf_divfix((v).x, __mag); (v).y = gf_divfix((v).y, __mag); (v).z = gf_divfix((v).z, __mag); (v).q = gf_divfix((v).q, __mag);	\
	}	\
 
/*!\brief quaternion to rotation

Transforms a quaternion to a Rotation, expressed as a 4 dimension vector with x,y,z for axis and q for rotation angle
\param quat the quaternion to transform
\return the rotation value
 */
GF_Vec4 gf_quat_to_rotation(GF_Vec4 *quat);
/*!\brief quaternion from rotation

Transforms a Rotation to a quaternion
\param rot the rotation to transform
\return the quaternion value
 */
GF_Vec4 gf_quat_from_rotation(GF_Vec4 rot);
/*! Inverses a quaternion
\param quat the quaternion to inverse
\return the inverted quaternion
*/
GF_Vec4 gf_quat_get_inv(GF_Vec4 *quat);
/*!\brief quaternion multiplication

Multiplies two quaternions
\param q1 the first quaternion
\param q2 the second quaternion
\return the resulting quaternion
 */
GF_Vec4 gf_quat_multiply(GF_Vec4 *q1, GF_Vec4 *q2);
/*!\brief quaternion vector rotating

Rotates a vector with a quaternion
\param quat the quaternion modelizing the rotation
\param vec the vector to rotate
\return the resulting vector
 */
GF_Vec gf_quat_rotate(GF_Vec4 *quat, GF_Vec *vec);
/*!\brief quaternion from axis and cos

Constructs a quaternion from an axis and a cosinus value (shortcut to \ref gf_quat_from_rotation)
\param axis the rotation axis
\param cos_a the rotation cosinus value
\return the resulting quaternion
 */
GF_Vec4 gf_quat_from_axis_cos(GF_Vec axis, Fixed cos_a);
/*!\brief quaternion interpolation

Interpolates two quaternions using spherical linear interpolation
\param q1 the first quaternion
\param q2 the second quaternion
\param frac the fraction of the interpolation, between 0 and \ref FIX_ONE
\return the interpolated quaternion
 */
GF_Vec4 gf_quat_slerp(GF_Vec4 q1, GF_Vec4 q2, Fixed frac);

/*!\brief 3D Bounding Box

The 3D Bounding Box is a 3D Axis-Aligned Bounding Box used to in various tools of the GPAC framework for bounds
 estimation of a 3D object. It features an axis-aligned box and a sphere bounding volume for fast intersection tests.
 */
typedef struct
{
	/*!minimum x, y, and z of the object*/
	GF_Vec min_edge;
	/*!maximum x, y, and z of the object*/
	GF_Vec max_edge;

	/*!center of the bounding box.\note this is computed from min_edge and max_edge*/
	GF_Vec center;
	/*!radius of the bounding sphere for this box.\note this is computed from min_edge and max_edge*/
	Fixed radius;
	/*!the bbox center and radius are valid*/
	Bool is_set;
} GF_BBox;
/*! updates information of the bounding box based on the edge information
\param b the target bounding box
*/
void gf_bbox_refresh(GF_BBox *b);
/*!builds a bounding box from a 2D rectangle
\param box the bounding box to build
\param rc the source rectangle
*/
void gf_bbox_from_rect(GF_BBox *box, GF_Rect *rc);
/*!builds a rectangle from a 3D bounding box.
\note The z dimension is lost and no projection is performed
\param rc the destination rectangle
\param box the source bounding box
*/
void gf_rect_from_bbox(GF_Rect *rc, GF_BBox *box);
/*!\brief bounding box expansion

Checks if a point is inside a bounding box and updates the bounding box to include it if not the case
\param box the bounding box object
\param pt the 3D point to check
*/
void gf_bbox_grow_point(GF_BBox *box, GF_Vec pt);
/*!performs the union of two bounding boxes
\param b1 the first bounding box
\param b2 the bounding box to add
*/
void gf_bbox_union(GF_BBox *b1, GF_BBox *b2);
/*!checks if two bounding boxes are equal or not
\param b1 the first bounding box
\param b2 the second bounding box
\return GF_TRUE if equal
*/
Bool gf_bbox_equal(GF_BBox *b1, GF_BBox *b2);
/*!checks if a point is inside a bounding box or not
\param box the bounding box
\param p the point to check
\return GF_TRUE if point is inside
*/
Bool gf_bbox_point_inside(GF_BBox *box, GF_Vec *p);
/*!\brief get box vertices

Returns the 8 bounding box vertices given the minimum and maximum edge. Vertices are ordered to respect
 "p-vertex indexes", (vertex from a box closest to plane) and so that n-vertex (vertex from a box farthest from plane)
 is 7-p_vx_idx
\param bmin minimum edge of the box
\param bmax maximum edge of the box
\param vecs list of 8 3D points used to store the vertices.
*/
void gf_bbox_get_vertices(GF_Vec bmin, GF_Vec bmax, GF_Vec *vecs);


/*!\brief matrix initialization
 \hideinitializer

Inits the matrix to the identity matrix
*/
#define gf_mx_init(_obj) { memset((_obj).m, 0, sizeof(Fixed)*16); (_obj).m[0] = (_obj).m[5] = (_obj).m[10] = (_obj).m[15] = FIX_ONE; }

/*! macro to check if a matrix is the identity matrix*/
#define gf_mx_is_identity(_obj) ((!(_obj).m[1] && !(_obj).m[2] && !(_obj).m[3] && !(_obj).m[4] && !(_obj).m[6] && !(_obj).m[7] && !(_obj).m[8] && !(_obj).m[9] && !(_obj).m[11] && !(_obj).m[12] && !(_obj).m[13] && !(_obj).m[14] && ((_obj).m[0]==FIX_ONE) && ((_obj).m[5]==FIX_ONE)&& ((_obj).m[10]==FIX_ONE)&& ((_obj).m[15]==FIX_ONE)) ? 1 : 0)

/*!\brief matrix copy
 \hideinitializer

 Copies the matrix _from to the matrix _obj
*/
#define gf_mx_copy(_obj, from) memcpy(&(_obj), &(from), sizeof(GF_Matrix));
/*!\brief matrix constructor from 2D

Initializes a 3D matrix from a 2D matrix.\note all z-related coefficients will be set to default.
\param mx the target matrix to initialize
\param mat2D the source 2D matrix
*/
void gf_mx_from_mx2d(GF_Matrix *mx, GF_Matrix2D *mat2D);
/*!\brief matrix equality testing

Tests if two matrices are equal or not.
\param mx1 the first matrix
\param mx2 the first matrix
\return GF_TRUE if matrices are same, GF_FALSE otherwise
*/
Bool gf_mx_equal(GF_Matrix *mx1, GF_Matrix *mx2);
/*!\brief matrix translation

Translates a matrix
\param mx the matrix being transformed. Once the function is called, contains the result matrix
\param tx horizontal translation
\param ty vertical translation
\param tz depth translation
*/
void gf_mx_add_translation(GF_Matrix *mx, Fixed tx, Fixed ty, Fixed tz);
/*!\brief matrix scaling

Scales a matrix
\param mx the matrix being transformed. Once the function is called, contains the result matrix
\param sx horizontal translation scaling
\param sy vertical translation scaling
\param sz depth translation scaling
*/
void gf_mx_add_scale(GF_Matrix *mx, Fixed sx, Fixed sy, Fixed sz);
/*!\brief matrix rotating

Rotates a matrix
\param mx the matrix being transformed. Once the function is called, contains the result matrix
\param angle rotation angle in radians
\param x horizontal coordinate of rotation axis
\param y vertical coordinate of rotation axis
\param z depth coordinate of rotation axis
*/
void gf_mx_add_rotation(GF_Matrix *mx, Fixed angle, Fixed x, Fixed y, Fixed z);
/*!\brief matrices multiplication

Multiplies a matrix with another one mx = mx*mul
\param mx the matrix being transformed. Once the function is called, contains the result matrix
\param mul the matrix to add
*/
void gf_mx_add_matrix(GF_Matrix *mx, GF_Matrix *mul);
/*!\brief 2D matrix multiplication

Adds a 2D affine matrix to a matrix
\param mx the matrix
\param mat2D the matrix to premultiply
 */
void gf_mx_add_matrix_2d(GF_Matrix *mx, GF_Matrix2D *mat2D);

/*!\brief affine matrix inversion

Inverses an affine matrix.\warning Results are undefined if the matrix is not an affine one
\param mx the matrix to inverse
 */
void gf_mx_inverse(GF_Matrix *mx);
/*!\brief transpose 4x4 matrix

Transposes a 4x4 matrix
\param mx the matrix to transpose
 */
void gf_mx_transpose(GF_Matrix *mx);
/*!\brief matrix point transformation

Applies a 3D matrix transformation to a 3D point
\param mx transformation matrix
\param pt pointer to 3D point. Once the function is called, pt contains the transformed point
*/
void gf_mx_apply_vec(GF_Matrix *mx, GF_Vec *pt);
/*!\brief matrix rectangle transformation

Applies a 3D matrix transformation to a rectangle, giving the enclosing rectangle of the transformed one.\note all depth information are discarded.
\param _this transformation matrix
\param rc pointer to rectangle. Once the function is called, rc contains the transformed rectangle
*/
void gf_mx_apply_rect(GF_Matrix *_this, GF_Rect *rc);
/*!\brief ortho matrix construction

Creates an orthogonal projection matrix. This assume the NDC Z lies in [-1,1]
\param mx matrix to initialize
\param left min horizontal coordinate of viewport
\param right max horizontal coordinate of viewport
\param bottom min vertical coordinate of viewport
\param top max vertical coordinate of viewport
\param z_near min depth coordinate of viewport
\param z_far max depth coordinate of viewport
*/
void gf_mx_ortho(GF_Matrix *mx, Fixed left, Fixed right, Fixed bottom, Fixed top, Fixed z_near, Fixed z_far);

/*!\brief ortho matrix with reverse Z construction

Creates an orthogonal projection matrix with reverse Z. This assume the NDC Z lies in [0,1], not [-1,1]
\param mx matrix to initialize
\param left min horizontal coordinate of viewport
\param right max horizontal coordinate of viewport
\param bottom min vertical coordinate of viewport
\param top max vertical coordinate of viewport
\param z_near min depth coordinate of viewport
\param z_far max depth coordinate of viewport
*/
void gf_mx_ortho_reverse_z(GF_Matrix *mx, Fixed left, Fixed right, Fixed bottom, Fixed top, Fixed z_near, Fixed z_far);

/*!\brief perspective matrix construction

Creates a perspective projection matrix. This assume the NDC Z lies in [-1,1]
\param mx matrix to initialize
\param fov camera field of view angle in radian
\param aspect_ratio viewport aspect ratio
\param z_near min depth coordinate of viewport
\param z_far max depth coordinate of viewport
*/
void gf_mx_perspective(GF_Matrix *mx, Fixed fov, Fixed aspect_ratio, Fixed z_near, Fixed z_far);

/*!\brief perspective matrix with reverse Z  construction

Creates a perspective projection matrix with reverse Z. This assume the NDC Z lies in [0,1]
\param mx matrix to initialize
\param fov camera field of view angle in radian
\param aspect_ratio viewport aspect ratio
\param z_near min depth coordinate of viewport
\param z_far max depth coordinate of viewport
*/
void gf_mx_perspective_reverse_z(GF_Matrix *mx, Fixed fov, Fixed aspect_ratio, Fixed z_near, Fixed z_far);

/*!\brief creates look matrix

Creates a transformation matrix looking at a given direction from a given point (camera matrix).
\param mx matrix to initialize
\param position position
\param target look direction
\param up_vector vector describing the up direction
*/
void gf_mx_lookat(GF_Matrix *mx, GF_Vec position, GF_Vec target, GF_Vec up_vector);
/*!\brief matrix box transformation

Applies a 3D matrix transformation to a bounding box, giving the enclosing box of the transformed one
\param mx transformation matrix
\param b pointer to bounding box. Once the function is called, contains the transformed bounding box
*/
void gf_mx_apply_bbox(GF_Matrix *mx, GF_BBox *b);
/*!\brief matrix box sphere transformation

Applies a 3D matrix transformation to a bounding box, computing only the enclosing sphere of the transformed one.
\param mx transformation matrix
\param box pointer to bounding box. Once the function is called, contains the transformed bounding sphere
*/
void gf_mx_apply_bbox_sphere(GF_Matrix *mx, GF_BBox *box);
/*!\brief non-affine matrix multiplication

Multiplies two non-affine matrices mx = mx*mul
\param mat the target matrix
\param mul the matrix we multiply with
*/
void gf_mx_add_matrix_4x4(GF_Matrix *mat, GF_Matrix *mul);
/*!\brief non-affine matrix inversion

Inverses a non-affine matrices
\param mx the target matrix
\return 1 if inversion was done, 0 if inversion not possible.
*/
Bool gf_mx_inverse_4x4(GF_Matrix *mx);
/*!\brief matrix 4D vector transformation

Applies a 3D non-affine matrix transformation to a 4 dimension vector
\param mx transformation matrix
\param vec pointer to the vector. Once the function is called, contains the transformed vector
*/
void gf_mx_apply_vec_4x4(GF_Matrix *mx, GF_Vec4 *vec);

/*!\brief matrix yaw pitch roll decomposition

Extracts yaw, pitch and roll info from a matrix
\param mx the matrix to decompose
\param yaw the extracted yaw angle in radians
\param pitch the extracted pitch angle in radians
\param roll the extracted roll angle in radians
*/
void gf_mx_get_yaw_pitch_roll(GF_Matrix *mx, Fixed *yaw, Fixed *pitch, Fixed *roll);

/*!\brief matrix decomposition

Decomposes a matrix into translation, scale, shear and rotate
\param mx the matrix to decompose
\param translate the decomposed translation part
\param scale the decomposed scaling part
\param rotate the decomposed rotation part, expressed as a Rotataion (axis + angle)
\param shear the decomposed shear part
 */
void gf_mx_decompose(GF_Matrix *mx, GF_Vec *translate, GF_Vec *scale, GF_Vec4 *rotate, GF_Vec *shear);
/*!\brief matrix vector rotation

Rotates a vector with a given matrix, ignoring any translation.
\param mx transformation matrix
\param pt pointer to 3D vector. Once the function is called, pt contains the transformed vector
 */
void gf_mx_rotate_vector(GF_Matrix *mx, GF_Vec *pt);
/*!\brief matrix initialization from vectors

Inits a matrix to rotate the local axis in the given vectors
\param mx matrix to initialize
\param x_axis target normalized X axis
\param y_axis target normalized Y axis
\param z_axis target normalized Z axis
*/
void gf_mx_rotation_matrix_from_vectors(GF_Matrix *mx, GF_Vec x_axis, GF_Vec y_axis, GF_Vec z_axis);
/*!\brief matrix to 2D matrix

Inits a 2D matrix by removing all depth info from a 3D matrix
\param mx2d 2D matrix to initialize
\param mx 3D matrix to use
*/
void gf_mx2d_from_mx(GF_Matrix2D *mx2d, GF_Matrix *mx);

/*!\brief Plane object*/
typedef struct
{
	/*!normal vector to the plane*/
	GF_Vec normal;
	/*!distance from origin of the plane*/
	Fixed d;
} GF_Plane;
/*!\brief matrix plane transformation

Transorms a plane by a given matrix
\param mx the matrix to use
\param plane pointer to 3D plane. Once the function is called, plane contains the transformed plane
 */
void gf_mx_apply_plane(GF_Matrix *mx, GF_Plane *plane);
/*!\brief point to plane distance

Gets the distance between a point and a plne
\param plane the plane to use
\param p pointer to ^point to check
\return the distance between the place and the point
 */
Fixed gf_plane_get_distance(GF_Plane *plane, GF_Vec *p);
/*!\brief closest point on a line

Gets the closest point on a line from a given point in space
\param line_pt a point of the line to test
\param line_vec the normalized direction vector of the line
\param pt the point to check
\return the closest point on the line to the desired point
 */
GF_Vec gf_closest_point_to_line(GF_Vec line_pt, GF_Vec line_vec, GF_Vec pt);
/*!\brief box p-vertex index

Gets the p-vertex index for a given plane. The p-vertex index is the index of the closest vertex of a bounding box to the plane. The vertices of a box are always
 *ordered in GPAC? cf \ref gf_bbox_get_vertices
\param p the plane to check
\return the p-vertex index value, ranging from 0 to 7
*/
u32 gf_plane_get_p_vertex_idx(GF_Plane *p);
/*!\brief plane line intersection

Checks for the intersection of a plane and a line
\param plane plane to test
\param linepoint a point on the line to test
\param linevec normalized direction vector of the line to test
\param outPoint optional pointer to retrieve the intersection point, NULL otherwise
\return 1 if line and plane intersect, 0 otherwise
*/
Bool gf_plane_intersect_line(GF_Plane *plane, GF_Vec *linepoint, GF_Vec *linevec, GF_Vec *outPoint);

/*!Classification types for box/plane position used in \ref gf_bbox_plane_relation*/
enum
{
	/*!box is in front of the plane*/
	GF_BBOX_FRONT,
	/*!box intersects the plane*/
	GF_BBOX_INTER,
	/*!box is back of the plane*/
	GF_BBOX_BACK
};
/*!\brief box-plane relation

Gets the spatial relation between a box and a plane
\param box the box to check
\param p the plane to check
\return the relation type
 */
u32 gf_bbox_plane_relation(GF_BBox *box, GF_Plane *p);

/*!\brief 3D Ray

The 3D ray object is used in GPAC for all collision and mouse interaction tests
*/
typedef struct
{
	/*!origin point of the ray*/
	GF_Vec orig;
	/*!normalized direction vector of the ray*/
	GF_Vec dir;
} GF_Ray;

/*!\brief ray constructor

Constructs a ray object
\param start starting point of the ray
\param end end point of the ray, or any point on the ray
\return the ray object
*/
GF_Ray gf_ray(GF_Vec start, GF_Vec end);
/*!\brief matrix ray transformation

Transforms a ray by a given transformation matrix
\param mx the matrix to use
\param r pointer to the ray. Once the function is called, contains the transformed ray
*/
void gf_mx_apply_ray(GF_Matrix *mx, GF_Ray *r);
/*!\brief ray box intersection test

Checks if a ray intersects a box or not
\param ray the ray to check
\param min_edge the minimum edge of the box to check
\param max_edge the maximum edge of the box to check
\param out_point optional location of a 3D point to store the intersection, NULL otherwise.
\return retuns 1 if the ray intersects the box, 0 otherwise
*/
Bool gf_ray_hit_box(GF_Ray *ray, GF_Vec min_edge, GF_Vec max_edge, GF_Vec *out_point);
/*!\brief ray sphere intersection test

Checks if a ray intersects a box or not
\param ray the ray to check
\param center the center of the sphere to check. If NULL, the origin (0,0,0)is used
\param radius the radius of the sphere to check
\param out_point optional location of a 3D point to store the intersection, NULL otherwise
\return retuns 1 if the ray intersects the sphere, 0 otherwise
*/
Bool gf_ray_hit_sphere(GF_Ray *ray, GF_Vec *center, Fixed radius, GF_Vec *out_point);
/*!\brief ray triangle intersection test

Checks if a ray intersects a triangle or not
\param ray the ray to check
\param v0 first vertex of the triangle
\param v1 second vertex of the triangle
\param v2 third vertex of the triangle
\param dist optional location of a fixed number to store the intersection distance from ray origin if any, NULL otherwise
\return retuns 1 if the ray intersects the triangle, 0 otherwise
*/
Bool gf_ray_hit_triangle(GF_Ray *ray, GF_Vec *v0, GF_Vec *v1, GF_Vec *v2, Fixed *dist);

/*! @} */

/*! @} */

#ifdef __cplusplus
}
#endif


#endif		/*_GF_MATH_H_*/

