//
// 3DMath.h
//

#include "metaobjects.h"

Boolean IsPowerOf2(int num);

#define OGLMath_RadiansToDegrees(x)	((float)((x) * 180.0f / PI))

float OGLPoint3D_DistanceToPlane(const OGLPoint3D *point,const OGLPlaneEquation	*plane);
float OGLPoint2D_LineDistance(OGLPoint2D *point, float p1x, float p1y, float p2x, float p2y, float *t);


extern	float CalcXAngleFromPointToPoint(float fromY, float fromZ, float toY, float toZ);
float	CalcYAngleFromPointToPoint(float oldRot, float fromX, float fromZ, float toX, float toZ);
float TurnPointTowardPoint(float *rotY, OGLPoint3D *from, float toX, float toZ, float turnSpeed);
Boolean IntersectionOfLineSegAndPlane(const OGLPlaneEquation *plane, float v1x, float v1y, float v1z,
								 float v2x, float v2y, float v2z, OGLPoint3D *outPoint);
void ApplyFrictionToDeltas(float f,OGLVector3D *d);

Boolean VectorsAreCloseEnough(const OGLVector3D *v1, const OGLVector3D *v2);
Boolean PointsAreCloseEnough(const OGLPoint3D *v1, const OGLPoint3D *v2);
float IntersectionOfYAndPlane_Func(float x, float z, const OGLPlaneEquation *p);
void OGLVector3D_Cross(const OGLVector3D *v1, const OGLVector3D	*v2, OGLVector3D *result);
void OGLMatrix4x4_Invert(const OGLMatrix4x4 *inMatrix, OGLMatrix4x4 *result);

extern	Boolean IsPointInTriangle3D(const OGLPoint3D *point3D,	const OGLPoint3D *trianglePoints, OGLVector3D *normal);
void OGLCreateFromToRotationMatrix(OGLMatrix4x4 *matrix4x4,	const OGLVector3D *v1, const OGLVector3D *v2);
void SetLookAtMatrix(OGLMatrix4x4 *m, const OGLVector3D *upVector, const OGLPoint3D *from, const OGLPoint3D *to);
void SetLookAtMatrixAndTranslate(OGLMatrix4x4 *m, const OGLVector3D *upVector, const OGLPoint3D *from, const OGLPoint3D *to);
void SetAlignmentMatrix(OGLMatrix4x4 *m, const OGLVector3D *aim);
void SetAlignmentMatrixWithZRot(OGLMatrix4x4 *m, const OGLVector3D *aim, float rotZ);

Boolean IntersectLineSegments(float x1, float y1, float x2, float y2,
		                     float x3, float y3, float x4, float y4,
                             float *x, float *y);

void CalcLineNormal2D(float p0x, float p0y, float p1x, float p1y,
					 float	px, float py, OGLVector2D *normal);
Boolean CalcRayNormal2D(const OGLVector2D *vec, float p0x, float p0y,
					 float	px, float py, OGLVector2D *normal);

void ReflectVector2D(OGLVector2D *theVector, const OGLVector2D *N, OGLVector2D *outVec);
void ReflectVector3D(const OGLVector3D *vec, OGLVector3D *N, OGLVector3D *out);

float CalcVectorLength(OGLVector3D *v);
float CalcVectorLength2D(const OGLVector2D *v);
void OGLPoint3D_Transform(const OGLPoint3D *point3D, const OGLMatrix4x4 *matrix4x4,
								OGLPoint3D *result);
void OGLMatrix4x4_SetScale(OGLMatrix4x4 *m, float x, float y, float z);
void OGLMatrix4x4_SetRotate_X(OGLMatrix4x4	*m, float angle);
void OGLMatrix4x4_SetRotate_Y(OGLMatrix4x4	*m, float angle);
void OGLMatrix4x4_SetRotate_Z(OGLMatrix4x4	*m, float angle);
void OGLMatrix4x4_SetRotateAboutPoint(OGLMatrix4x4 *matrix4x4, const OGLPoint3D	*origin,
									float xAngle, float yAngle, float zAngle);

void OGLMatrix4x4_Multiply(const OGLMatrix4x4	*mA, const OGLMatrix4x4 *mB, OGLMatrix4x4	*result);
void OGLMatrix4x4_SetRotate_XYZ(OGLMatrix4x4 *m, float rx, float ry, float rz);
void OGLMatrix3x3_SetRotate(OGLMatrix3x3 *m, double angle);
void OGLMatrix3x3_SetIdentity(OGLMatrix3x3 *m);
void OGLPoint2D_Transform(const OGLPoint2D *p, const OGLMatrix3x3 *m, OGLPoint2D *result);
float OGLVector3D_Dot(const OGLVector3D	*v1, const OGLVector3D	*v2);
float OGLVector2D_Dot(const OGLVector2D	*v1,  const OGLVector2D	*v2);
float OGLVector2D_Cross(const OGLVector2D *v1, const OGLVector2D *v2);
void OGLMatrix4x4_Transpose(const OGLMatrix4x4 *matrix4x4, OGLMatrix4x4 *result);
void OGLVector3D_Normalize(const OGLVector3D *vector3D, OGLVector3D	*result);
void OGLVector3D_Transform(const OGLVector3D *vector3D,	const OGLMatrix4x4	*matrix4x4, OGLVector3D *result);
void OGLMatrix4x4_SetRotateAboutAxis(OGLMatrix4x4	*m, const OGLVector3D	*axis, float angle);

void OGLMatrix3x3_Multiply(const OGLMatrix3x3	*matrixA,
							const OGLMatrix3x3	*matrixB,
							OGLMatrix3x3		*result);

void OGLMatrix3x3_SetRotateAboutPoint(OGLMatrix3x3 *m, OGLPoint2D *origin, double angle);
void OGLVector2D_Transform(const OGLVector2D *vector2D, 
							const OGLMatrix3x3	*matrix3x3,
							OGLVector2D			*result);
void OGLMatrix4x4_SetTranslate(OGLMatrix4x4 *m, float x, float y, float z);
void OGLMatrix4x4_SetIdentity(OGLMatrix4x4 *m);
void OGLMatrix3x3_SetTranslate(OGLMatrix3x3 *m, float x, float y);

void OGLPoint3D_To4DTransformArray(const OGLPoint3D *inVertex, const OGLMatrix4x4  *matrix,
									OGLPoint4D *outVertex,  long numVertices);
void OGLPoint3D_TransformArray(const OGLPoint3D *inVertex, const OGLMatrix4x4  *matrix,
									OGLPoint3D *outVertex,  long numVertices);
void OGLPoint2D_TransformArray(const OGLPoint2D *inVertex, const OGLMatrix3x3  *matrix,
									OGLPoint2D *outVertex,  long numVertices);
void OGLVector3D_TransformArray(const OGLVector3D *inVectors, const OGLMatrix4x4 *m,
								 OGLVector3D *outVectors, int numVectors);


Boolean OGL_IsBBoxVisible(const OGLBoundingBox *bBox, OGLMatrix4x4	*localToWorld);
void OGLVector2D_Normalize(const OGLVector2D *vector2D, OGLVector2D	*result);
float OGLPoint3D_Distance(const OGLPoint3D *p1, const OGLPoint3D *p2);
float OGLPoint2D_Distance(const OGLPoint2D *p1, const OGLPoint2D *p2);
void ApplyFrictionToRotation(float f,OGLVector3D *d);
void ApplyFrictionToDeltasXZ(float f,OGLVector3D *d);

void OGLBoundingBox_Transform(OGLBoundingBox *inBox, OGLMatrix4x4 *m, OGLBoundingBox *outBox);


/*********** INTERSECTION OF Y AND PLANE ********************/
//
// INPUT:	
//			x/z		:	xz coords of point
//			p		:	ptr to the plane
//
//
// *** IMPORTANT-->  This function does not check for divides by 0!! As such, there should be no
//					"vertical" polygons (polys with normal->y == 0).
//

#define IntersectionOfYAndPlane(_x, _z, _p)	(((_p)->constant - (((_p)->normal.x * _x) + ((_p)->normal.z * _z))) / (_p)->normal.y)


/***************** ANGLE TO VECTOR ******************/
//
// Returns a normalized 2D vector based on a radian angle
//
// NOTE: +rotation == counter clockwise!
//

static inline void AngleToVector(float angle, OGLVector2D *theVector)
{
	theVector->x = -sin(angle);
	theVector->y = -cos(angle);
}



/******************** FAST RECIPROCAL **************************/
//
//   y1 = y0 + y0*(1 - num*y0), where y0 = recip_est(num)
//

#define FastReciprocal(_num,_out)		\
{										\
	float	_y0;						\
										\
	_y0 = __fres(_num);					\
	_out = _y0 * (1 - _num*_y0) + _y0;	\
}


/***************** FAST VECTOR LENGTH 3D/2D *********************/

#define VectorLength3D(_r, _inX, _inY, _inZ)	_r = sqrt((_inY*_inY) + (_inX*_inX) + (_inZ*_inZ));

#define VectorLength2D(_r, _inX, _inY)	_r = sqrt((_inY*_inY) + (_inX*_inX));



















