//=============================================================================
// Unreal Tournament SDK //
//-------------------------
// sdkCore //
//-----------
// Unreal Tournament SDK (c) Copyright 2007-2011 Stephan "Shadow" Nagel, 
// Under Artistic License 2.0
//
// UnSDKMath.h
//
// Header by: Shadow
//
// Description:
// Function Header for extended Math Functions used in the 
// whole SDK (Function Interface)
//
// Build 250: changed to inlines to gain speed increase
// TO DO: comment out every function 			    
//=============================================================================


/*-----------------------------------------------------------------------------
	Global Constants.
-----------------------------------------------------------------------------*/

// Trigonometric Constants
#define RadToDegree 0.017453292519943296 
#define DegreeToRad 57.295779513082321600

#define URotToDeg 0.005493;
#define DegToURot 182.044449;

#define RadianToURot 10430.3783505f;
#define URotToRadian 0.000095873799f;

#define GO 1.6180339887499	            	
#define dPI 6.2831853071795864           	
#define sinPI 0.054803665	            
#define cosPI 0.998497149	            	
#define tanPI 0.05488615	
	
// Rotational Constants
#define OneSpin 65536				
#define HSpin 32768
#define QSpin 16384
#define EtSpin 8192

// Standard Math Constants
#define Euler 2.7182818284590452
	            	
#define AlphaDamp 0.9 

// Color Constants
#define Red FColor(255,0,0);
#define Green FColor(0,255,0);
#define Blue FColor(0,0,255);
#define Gold FColor(255,255,0);
#define Orange FColor(255,128,0);
#define Cyan FColor(0,255,255);
#define Pink FColor(255,0,255);
#define Purple FColor(128,0,255);
#define LGrey FColor(192,192,192);
#define DGrey FColor(128,128,128);
#define White FColor(255,255,255);
#define Black FColor(0,0,0);

//-----------------------------------------------------------------------------
// Forward Class Declaration

class FsdkPlane;				// extended Plane Support
class FsdkMatrix;				// extended Matrix Support
class FsdkRotationMatrix;


/*-----------------------------------------------------------------------------
	Global functions.
-----------------------------------------------------------------------------*/


//-----------------------------------------------------------------------------
// Standard Functions   

inline INT URand(INT Max)
{
	return Max>0 ? (appRand() % Max) : 0;
}


//-----------------------------------------------------------------------------
// Bool Functions  

inline UBOOL RandBool()
{
	int i = 1 + URand(2);

	if (i == 0)
		return true;
	else 
		return false;
}


//-----------------------------------------------------------------------------
// Byte Functions  

//Converts a Float to Byte Value
inline BYTE FloatToByte(float F, UBOOL bSign)
{
	BYTE result;

	if (bSign)
	{
		if (F > 0.98f)
			result = 255;
		else if (F < -0.98f)
			result = 0;
		else 
			result = BYTE(F + 1.f) * 128.f;
	}
	else
	{
		if (F > 0.98f)
			result = 255;
		else if (F < 0.02f)		
			result = 0;
		else 
			result = BYTE(F*255.f);
	}

	return result;
}

//Converts a Byte to Float Value
inline FLOAT ByteToFloat(BYTE Input, UBOOL bSign)
{
	float result;

	if (bSign)
		result = float(Input / 128.f) - 1.f; 
	else
		result = float(Input / 255.f);

	return result;
}


//-----------------------------------------------------------------------------
// Integer Functions  

inline INT Round(FLOAT x)
{
	return int(x + 0.5);
}

inline INT iSign(INT x)
{
	if (x > 0)
		return 1;
	else if (x < 0)
		return -1;
	else 
		return 0;
}

inline INT iXRandRange(INT Min, INT Max)
{
	return Min + (Max - Min) * appFrand();
}

inline INT Rand2(INT Max)
{
	int num = URand(Max + 1);

	if (URand(2) == 1)
		num = -num;

	return num;
}

// Integer Range Wrapper, doesn't use Integer Range Variable as input to keep global support
// Either randomizes between min and max or returns constant values
inline INT RangeInt(INT Min, INT Max)
{
	if (Min >= Max)			// Build 250: Clamp min with >=
		return Max;

	else if (Min < Max)
		return iXRandRange(Min,Max);

	else return 0;
}

// Integer Range Wrapper2, doesn't use Integer Range Variable as input to keep global support
// Either randomizes between min and max or returns difference between max and min
inline INT RangeInt2(INT Min, INT Max)
{
	if (Min >= Max)			// Build 250: Clamp min with >=
		return Max;

	else if (Min < Max)
		return Max - Min;

	else return 0;
}

inline void SwapInt(INT& A, INT& B)
{
	INT Temp = A;
	A = B;
	B = Temp;
}

//n! of n... 
inline INT nFac(INT n)
{
	if (n <= 0)
		return 1;
	else
		return n * nFac(n - 1);
}

//Is X odd or even
inline UBOOL nEven(INT x)
{
	float y;

	y = x % 2;

	if (y == 0.0)
		return true;
	else
		return false;
}

inline UBOOL IsPowerOfTwo(INT i)			// Build 250
{
	return !(i & (i - 1));
}

// Returns the previous power of two of in
// Build 161: small fix for VS C++ 2008
inline INT PrevPowerOfTwo(INT in)
{	
	double X=0.0,Y=0.0;

	X = log(double(in));
	Y = log(double(2));

	return 1 << INT(X / Y);
}

// Build 161: small fix for VS C++ 2008
inline INT iBiChain(INT N)
{	
	double X = 2.0, Y = (N-1.0);	
	return 2 * pow(X,Y);
}

inline INT iOddChain(INT N)
{
	return 1 + ((N-1) * 2);
}

//-----------------------------------------------------------------------------
// Float Functions  

inline UBOOL FApproxZero(FLOAT X)
{
	return UBOOL (X < KINDA_SMALL_NUMBER);
}

inline INT Sign(FLOAT x)
{
	if (x > 0.0)
		return 1;
	else if (x < 0.0)
		return -1;
	else 
		return 0;
}

inline void SwapFloat(FLOAT& A, FLOAT& B)
{
	FLOAT Temp = A;
	A = B;
	B = Temp;
}

inline FLOAT Frac(FLOAT X)
{
	return X - floor(X);
}

inline FLOAT BaseValue(FLOAT V, FLOAT P)
{
	return (V * 100) / P;
}

inline FLOAT Percentage(FLOAT V, FLOAT B)
{
	return (V / B) * 100;
}

inline FLOAT PercentValue(FLOAT B, FLOAT P)
{
	return B * (P / 100);
}

inline FLOAT XRandRange(FLOAT Min, FLOAT Max)
{
    return Min + (Max - Min) * appFrand();
}

// Float Range Wrapper, doesn't use Float Range Variable as input to keep global support
// Either randomizes between min and max or returns constant values
inline FLOAT RangeFloat(FLOAT Min, FLOAT Max)
{
	if (Min >= Max)			// Build 250: Clamp min with >=
		return Max;

	else if (Min < Max)
		return XRandRange(Max,Min);

	else return 0.0;
}


// Float Range Wrapper, doesn't use Float Range Variable as input to keep global support
// Either randomizes between min and max or returns difference between max and min
inline FLOAT RangeFloat2(FLOAT Min, FLOAT Max)
{
	if (Min == Max)			// Build 250: Clamp min with >=
		return Max;

	else if (Min < Max)
		return Max - Min;

	else return 0.0;
}

inline FLOAT AdvRandRange(FLOAT Min, FLOAT Max, FLOAT Mod)
{
	INT Counter = 0;
	FLOAT Res;

	if (Mod == 0)
		Res = XRandRange(Max,Min);

	else if (Mod > 0)
	{
		Counter++;
	
		if (Counter == fabs(Mod))
		{
			Counter = 0;
			Res = XRandRange(Max,Min);
		}
	}
	else
	{
		Counter++;
	
		if (Counter == fabs(Mod))
		{
			Counter = Counter;
			Res = XRandRange(Max,Min);
		}	
	}

	return Res;
}

inline FLOAT RandFClamp(FLOAT Min, FLOAT Max, FLOAT Mod)
{
	INT Counter = 0;
	FLOAT Res;

	if (Mod == 0.0)
	{
		if (RandBool())
			Res = Max;
		else
			Res = Min;
	}

	else if (Mod > 0.0)
	{
		Counter++;
	
		if (Counter == fabs(Mod))
		{
			Counter = 0;

			if (RandBool())
				Res = Max;
			else
				Res = Min;
		}
	}
	else
	{
		Counter++;
	
		if (Counter == fabs(Mod))
		{
			Counter = Counter;

			if (RandBool())
				Res = Max;
			else
				Res = Min;
		}	
	}

	return Res;
}

inline FLOAT FRand2(FLOAT Variance, FLOAT Base)
{
	return Base + appFrand() * Variance;
}

// Binumeric Logarithm of a
// Build 161: small fix for VS C++ 2008
inline FLOAT LogB(FLOAT A)
{
	double X = A, Y = 2.0;

	return log(X) / log(Y);
}

// Decadic Logarithm of a
// Build 161: small fix for VS C++ 2008
inline FLOAT LogD(FLOAT A)
{
	double X = A, Y = 10.0;

	return log(X) / log(Y);
}

// Normal Logarithm of a, a to base of b
// Build 161: small fix for VS C++ 2008
inline FLOAT LogAB(FLOAT A, FLOAT B)
{
	double X = A, Y = 0.0;

	if (B > 0.0)
	{	
		Y = B;
		return log(X) / log(Y);
	}
	else 
	{
		Y = 10.0;
		return log(X) / log(Y);
	}
}

inline FLOAT nRoot(FLOAT X, FLOAT N)
{
	if (X > 0.0 && N >= 2.0)
		return pow(X, 1/N);
	else
		return 0.0;
}

inline FLOAT nRoot2(FLOAT X, FLOAT N, FLOAT M)
{
	if (X > 0.0 && N >= 2.0)
		return pow(X,M/N);
	else
		return 0.0;
}

inline FLOAT MetaRoot(FLOAT X, FLOAT N, FLOAT M)
{
	if (X > 0.0 && N >= 2.0)
		return pow(X,1/(M*N));
	else
		return 0.0;
}

inline FLOAT fGeoChainExplicite(FLOAT Base, INT N, FLOAT Q)
{
	return Base * pow(Q,(N-1));
}

inline FLOAT fArChainExplicite(FLOAT Base, INT N, FLOAT D)
{
	return Base + ((N-1) * D);
}

inline FLOAT fArChainExpInv(FLOAT InverseBase, FLOAT Base, FLOAT N, INT D)
{
	return InverseBase / fArChainExplicite(Base,N,D);
}

// Build 250: multiplies with constants (faster), instead of (Rad * 180) / PI
inline FLOAT RadToDeg(FLOAT Rad)
{
	return Rad * RadToDegree;
}

// Build 250: multiplies with constants (faster), instead of (Deg * PI) / 180
inline FLOAT DegToRad(FLOAT Deg)
{
	return Deg * DegreeToRad;
}

// Build 335:
inline FLOAT RotToDeg(FLOAT RotAngle)
{
	return RotAngle * URotToDeg;
}

// Build 335:
inline FLOAT DegToRot(FLOAT DegAngle)
{
	return DegAngle * DegToURot;
}

inline FLOAT dSin(FLOAT Angle)
{
	return sin(DegToRad(Angle));
}

inline FLOAT dCos(FLOAT Angle)
{
	return cos(DegToRad(Angle));
}

inline FLOAT CoTan(FLOAT X)
{
	return 1.0 / tan(X);
}

inline FLOAT Sec(FLOAT X)
{
	return 1.0 / cos(X);
}

inline FLOAT Csc(FLOAT X)
{
	return 1.0 / sin(X);
}

inline FLOAT SecH(FLOAT X)
{
	return 1.0 / cosh(X);
}

inline FLOAT ASecH(FLOAT X)
{
	return log((1 + sqrt(1 - X*X)) / X);
}

inline FLOAT ASinH(FLOAT X)
{
	return log(X + sqrt(X*X + 1));
}

inline FLOAT ACosH(FLOAT X)
{
	return log(X + sqrt(X*X - 1));
}

inline FLOAT ATanH(FLOAT X)
{
	return 1.0 / tanh(X);
}

inline FLOAT Sinc(FLOAT X, UBOOL bNormalized)
{
	if (!bNormalized)
		return sin(X) / X; 
	else
		return sin(PI * X) / PI;
}

inline FLOAT Tanc(FLOAT X)
{
	return tan(X) / X; 
}

inline FLOAT Sig(FLOAT X)
{
	return 1.0 / (1 + exp(-X)); 
}

inline FLOAT ASig(FLOAT X)
{
	return -log(1/X - 1);
}

inline FLOAT SqWave(FLOAT X)
{
	return Sign(sin(X));
}

inline FLOAT TriWave(FLOAT X)
{
	return fabs(Frac(X));
}

// Build 335:
inline FLOAT FLerp(FLOAT A, FLOAT B, FLOAT Alpha)
{
	return A + Alpha * (B - A);
}

// Build 335:
inline FLOAT FSmerp(FLOAT A, FLOAT B, FLOAT Alpha)
{
	return A + Alpha * Alpha * (3.f - 2.f * Alpha) * (B - A);
}

// Build 300: fixed
inline void FScaleDirect(FLOAT& Result, FLOAT T, FLOAT Min, FLOAT Max, FLOAT X, UBOOL bIncrease)
{
	if (bIncrease)
	{
		Result += T/X;
	
		if (Result >= Max)
			Result = Max;
	}
	else
	{
		Result -= T/X;

		if (Result <= Min)
			Result = Min;
	}
}

// Build 300: fixed
inline void FScaleDirectDelta(FLOAT& Result, FLOAT T, FLOAT Min, FLOAT Max, FLOAT X, UBOOL bIncrease, FLOAT Delta)
{
	FLOAT MinDelta, MaxDelta, XDelta;

	XDelta = X/Delta;

	if (bIncrease)
	{
		Result += T/XDelta;
		MaxDelta = Max * Delta;
	
		if (Result >= Max)
			Result = Max;
	}
	else
	{
		Result -= T/XDelta;
		MinDelta = Min * Delta;

		if (Result <= Min)
			Result = Min;
	}
}

// Build 300: fixed
inline FLOAT FScaleLinear(FLOAT Base, FLOAT T, FLOAT Min, FLOAT Max, FLOAT X, UBOOL bIncrease, UBOOL bLoop = 0)
{
	if (bIncrease)
		return Clamp(Base + T/X, Min, Max);
	else
		return Clamp(Base - T/X, Min, Max);
}

inline FLOAT FScaleDelta(FLOAT Base, FLOAT T, FLOAT Min, FLOAT Max, FLOAT X, UBOOL bIncrease, FLOAT Delta)
{
	FLOAT MinDelta, MaxDelta, BaseDelta, XDelta;

	MinDelta = Min * Delta;
	MaxDelta = Max * Delta;
	BaseDelta = Base * Delta;
	XDelta = X / Delta;

	if (bIncrease)
		return Clamp(BaseDelta + T/XDelta, MinDelta, MaxDelta);
	else
		return Clamp(BaseDelta - T/XDelta, MinDelta, MaxDelta);
}

inline FLOAT FScaleDeltaNoLim(FLOAT Base, FLOAT T, FLOAT X, UBOOL bIncrease, FLOAT Delta)
{
	FLOAT BaseDelta, XDelta;

	BaseDelta = Base * Delta;
	XDelta = X / Delta;

	if (bIncrease)
		return BaseDelta + T/XDelta;
	else
		return BaseDelta - T/XDelta;
}

inline FLOAT FScaleDeltaNoBaseLim(FLOAT Base, FLOAT T, FLOAT X, UBOOL bIncrease, FLOAT Delta)
{
	FLOAT XDelta = X / Delta;

	if (bIncrease)
		return Base + T/XDelta;
	else
		return Base - T/XDelta;
}

inline FLOAT GetDistance(FVector A, FVector B, INT DFactor)
{
	FLOAT moddist, distance;
	FVector diff = B - A;

	distance = diff.Size();

	if (DFactor > 0)
	{
		moddist = distance/DFactor;

		return moddist;
	}
	else 
		return distance;
}

inline FLOAT FDistFunctionGen(FLOAT Base, FVector A, FVector B, FLOAT Factor, FLOAT Min, FLOAT Max)
{
	FLOAT f;

	if (Factor > 0.f)
		f = Base * GetDistance(A, B, Factor);
	else 
		f = Base / GetDistance(A, B, fabs(double(Factor)));

	return f;

	if (Max > 0.0)
		f = Clamp(f,Min,Max);
}

inline FLOAT FDistFunctionGenDelta(FLOAT Base, FVector A, FVector B, FLOAT Factor, FLOAT Min, FLOAT Max, FLOAT Delta = 1.f)
{
	FLOAT Result;
	FLOAT DeltaFactor = Factor * Delta;
	FLOAT DeltaBase = Base * Delta;

	if (DeltaFactor > 0.f)
		Result = DeltaBase * GetDistance(A, B, DeltaFactor); 
	else 
		Result = DeltaBase / GetDistance(A, B, fabs(double(DeltaFactor)));

	return Result;

	if (Max > 0.0)
	{
		FLOAT MinDelta = Min * Delta;
		FLOAT MaxDelta = Max * Delta;

		Result = Clamp(Result, MinDelta, MaxDelta);
	}
}

/*
    OP_Square               = 0,
    OP_Exp                  = 1,
    OP_Sin                  = 2,
    OP_Cos                  = 3,
    OP_Tan                  = 4,
    OP_CoTan                = 5,
    OP_ASin                 = 6,
    OP_ACos                 = 7,
    OP_ATan                 = 8,
    OP_Sec                  = 9,
    OP_CoSec                =10,
    OP_SecH                 =11,
    OP_ASecH                =12,
    OP_SinH                 =13,
    OP_CosH                 =14,
    OP_TanH                 =15,
    OP_ASinH                =16,
    OP_ACosH                =17,
    OP_ATanH                =18,
    OP_Sinc                 =19,
    OP_Tanc                 =20,
*/

inline FLOAT FMathFunctionGen(BYTE Mode, FLOAT T, FLOAT Amp, FLOAT Freq, FLOAT Damp, UBOOL bAbs, FLOAT Base, FLOAT Min, FLOAT Max)
{
	FLOAT xFunc, tFreq, Res, damping;

	tFreq = Freq * T;

	if (fabs(Damp) < Freq)
	{
		switch(Mode)
		{
		case 0:xFunc = tFreq*tFreq;break;
		case 1:xFunc = exp(tFreq);break;
		case 2:xFunc = sin(tFreq);break;
		case 3:xFunc = cos(tFreq);break;
		case 4:xFunc = tan(tFreq);break;
		case 5:xFunc = CoTan(tFreq);break;
		case 6:xFunc = asin(tFreq);break;
		case 7:xFunc = acos(tFreq);break;
		case 8:xFunc = atan(tFreq);break;
		case 9:xFunc = Sec(tFreq);break;
		case 10:xFunc = Csc(tFreq);break;
		case 11:xFunc = SecH(tFreq);break;
		case 12:xFunc = ASecH(tFreq);break;
		case 13:xFunc = sinh(tFreq);break;
		case 14:xFunc = cosh(tFreq);break;
		case 15:xFunc = tanh(tFreq);break;
		case 16:xFunc = ASinH(tFreq);break;
		case 17:xFunc = ACosH(tFreq);break;
		case 18:xFunc = ATanH(tFreq);break;
		case 19:xFunc = Sinc(tFreq,false);break;
		case 20:xFunc = Tanc(tFreq);break;
		}

		//No Damping, damping constant is too small (Harmonic Oscillator)
		if (fabs(Damp) <= 0.001f)
		{
			Res = Base + (Amp * xFunc);

			if (bAbs)
				Res = fabs(Res);
		}

		//Weak Damping, frequency > damping constant (Damped Harmonic Oscillator)
		else
		{
			damping = Amp * exp(-Damp * T);

			Res = Base + (damping * xFunc);

			if (bAbs)
				Res = fabs(Res);
		}
	}

	if (Max != 0.0 && Min == 0.0)
		Res = Clamp(Res,Base - Amp,Max);

	else if (Max == 0.0 && Min != 0.0)
		Res = Clamp(Res,Min,Base + Amp);

	else if (Max != 0.0 && Min != 0.0)
		Res = Clamp(Res,Min,Max);

	return Res;
}

inline FLOAT FFunctionGen(BYTE Mode, FLOAT T, FLOAT Base, FLOAT Mod, FLOAT Min, FLOAT Max, FLOAT X, FLOAT Y)
{
	FLOAT Result;

	switch(Mode)
	{
	case 0:
		Result = Base;
	break;

	case 1:
		Result = FScaleLinear(Base,T,Min,Max,X,true);
	break;

	case 2:
		Result = FScaleLinear(Base,T,Min,Max,Y,false);
	break;

	case 3:
		Result = AdvRandRange(Min,Max,Mod);
	break;

	case 4:
		Result = RandFClamp(Min,Max,Mod);
	break;	
	}

	if (Mode >= 5 && Mode < 26)
		Result = FMathFunctionGen(BYTE(Mode - 5),T,Y,X,Mod,UBOOL(Mod > 0),Base,Min,Max);

	return Result;
}

inline FLOAT FFunctionGenDelta(BYTE Mode, FLOAT T, FLOAT Base, FLOAT Mod, FLOAT Min, FLOAT Max, FLOAT X, FLOAT Y, FLOAT Delta)
{
	FLOAT Result;

	switch(Mode)
	{
	case 0:
		Result = Base * Delta;
	break;

	case 1:
		Result = FScaleDelta(Base, T, Min, Max, X, true, Delta);
	break;

	case 2:
		Result = FScaleDelta(Base, T, Min, Max, Y, false, Delta);
	break;

	case 3:
		Result = AdvRandRange(Min,Max,Mod) * Delta;
	break;

	case 4:
		Result = RandFClamp(Min,Max,Mod) * Delta;
	break;
	}

	if (Mode >= 5 && Mode < 26)
		Result = FMathFunctionGen(BYTE(Mode - 5),T,Y,X,Mod,UBOOL(Mod > 0),Base,Min,Max) * Delta;

	return Result;
}

inline FLOAT FFunctionGenMeshAlpha(BYTE Mode, FLOAT T, FLOAT Base, FLOAT Mod, FLOAT Min, FLOAT Max, FLOAT X, FLOAT Y)
{
	return FFunctionGenDelta(Mode,T,Base,Mod,Min,Max,X,Y,2.0f);
}

inline FLOAT appInvSqrt(FLOAT F)
{
	const FLOAT fThree = 3.0f;
	const FLOAT fOneHalf = 0.5f;

	FLOAT temp;

	__asm
	{
		movss xmm1,[F]
		rsqrtss	xmm0,xmm1	
		
		movss xmm3,[fThree]
		movss xmm2,xmm0
		mulss xmm0,xmm1			
		mulss xmm0,xmm2			
		mulss xmm2,[fOneHalf]		
		subss xmm3,xmm0			
		mulss xmm3,xmm2		
		movss [temp],xmm3
	}

	return temp;
}

//-----------------------------------------------------------------------------
// Vector Functions  


inline UBOOL VUniform(FVector V)
{
	return (Abs(V.X-V.Y) == 0.f) &&
	       (Abs(V.Y-V.Z) == 0.f);
}

inline UBOOL VApproxUniform(FVector V)
{
	return (Abs(V.X-V.Y) < KINDA_SMALL_NUMBER) && (Abs(V.Y-V.Z) < KINDA_SMALL_NUMBER);
}

// Dot Product between A and B, ignoring Z component
inline FLOAT DotWOZ(FVector A, FVector B)
{
	A.Z = B.Z;
	A = A.SafeNormal();
	B = B.SafeNormal();

	return A | B;
}

// Returns the smaller of two Vectors
inline FVector VMin(FVector A, FVector B)
{
	if (A.Size() > B.Size())
		return A;
	else 
		return B;
}

// Returns the greater of two Vectors
inline FVector VMax(FVector A, FVector B)
{
	if (A.Size() < B.Size())
		return A;
	else 
		return B;
}

// Clamps a vector V by Min and Max
inline FVector VClamp(FVector V, FVector Min, FVector Max)
{
	if (V.Size() <= Min.Size())
		return Min;
	else if (V.Size() >= Max.Size())
		return Max;
	else 
		return V;
}

//Clamps a vector V by Min and Max
inline FLOAT VClamp2(FVector V, FLOAT Min, FLOAT Max)
{
	if (V.Size() <= Min)
		return Min;
	else if (V.Size() >= Max)
		return Max;
	else 
		return V.Size();
}

//randomizes Vector between Min and Max
inline FVector VRandRange(FVector Min, FVector Max)
{
	return Min + (Max - Min) * VRand();
}

// Build 250:
inline FVector VRange(FVector Min, FVector Max)
{
	if (Min == Max)
		return Max;

	else if (Min.Size() < Max.Size())
		return VRandRange(Min,Max);

	else return FVector(0,0,0);
}

inline UBOOL VOrthogonal(FVector A, FVector B)
{
	if ((A | B) == 0.0)
		return true;
	else
		return false;
}

inline UBOOL VCollinear(FVector A, FVector B)
{
	return (A ^ B).IsZero();
}

inline FLOAT VAngleCos(FVector A, FVector B)
{
	return FLOAT(cos( (A | B) / (A.Size() * B.Size()) ));
}

inline FLOAT VAngle(FVector A, FVector B)
{
	return FLOAT(1.0 / cos( (A | B) / (A.Size() * B.Size()) ));
}

inline FVector VProjectOnTo(FVector A, FVector B) 
{ 
	return (((A | B) / (B | B)) * B); 
}

// Returns the Spat Product of the 3 Vectors A, B and C (must be function, operators allow only 2 parameters)
inline FVector VSpat(FVector A, FVector B, FVector C)
{
	if (!A.IsZero() && !B.IsZero() && !C.IsZero())
		return A * (A ^ B);
    else 
		return FVector(0.0,0.0,0.0);
}

// Returns the Double Cross Product of the 3 Vectors A, B and C (must be function, operators allow only 2 parameters)
inline FVector VDoubleCross(FVector A, FVector B, FVector C)
{
	if (!A.IsZero() && !B.IsZero() && !C.IsZero())
		return A ^ (B ^ C);
   	else 
		return FVector(0.0,0.0,0.0);
}

// Linear Alpha Interpolation between A and B
// Build 120: fixed formula
inline FVector VLerp(FVector A, FVector B, FLOAT Alpha)
{
	return A + Alpha * (B - A);
}

// Smoothed Linear Alpha Interpolation between A and B
// Build 120: fixed formula
inline FVector VSmerp(FVector A, FVector B, FLOAT Alpha)
{
	return  A + Alpha * Alpha * (3.f - 2.f * Alpha) * (B - A);
}

// 3D Smooth Interpolation between A and B, returns current Position (DeltaV), needs to be ticked
inline UBOOL VInterpolate(FVector A, FVector B, FVector DeltaV, FLOAT DeltaT)
{
	FVector Delta;
	UBOOL bFinished;

	Delta = B-A;

	bFinished = (DeltaV.Size() <= 10);
	DeltaV = (A + (Delta * DeltaT));

	return bFinished;
}

// Returns the distance between A and B as new vector
inline FVector GetVDistance(FVector A, FVector B)
{
	FLOAT Dist = FVector(A-B).Size();
	return (A - B) / Dist;
}

// Build 250: made faster (using SizeSquared instead of Size)
// Compares the distance between A and B with Compare
// true = distance >= compare
// false = distance < compare
inline UBOOL PointsAreNear(FVector A, FVector B, FLOAT Compare)
{
	FLOAT CompareSq = Compare * Compare;

	if (FVector(A-B).SizeSquared() < CompareSq)
		return true;
	else
		return false;
}

// Build 300: 
inline UBOOL PointIsBetween(FVector Relative, FVector Point, FLOAT Closer, FLOAT Further)
{
	FLOAT CloserSq = Closer * Closer;
	FLOAT FurtherSq = Further * Further;

	if (FVector(Relative-Point).SizeSquared() >= CloserSq && FVector(Relative-Point).SizeSquared() <= FurtherSq)
		return true;
	else
		return false;
}

// Checks if Point intersects the Line of the Vectors Start->End
inline UBOOL PointIntersects(FVector Point, FVector Start, FVector End)
{
	FLOAT LambdaX, LambdaY, LambdaZ;

	LambdaX = (Point.X - Start.X) / End.X;
	LambdaY = (Point.Y - Start.Y) / End.Y;
	LambdaZ = (Point.Z - Start.Z) / End.Z;

	// If all three Lambdas are equal, the Line from Start to End intersects with Point
	return UBOOL(LambdaX == LambdaY && LambdaY == LambdaZ && LambdaZ == LambdaX);
}

// Build 250:
// Checks if Point is within a X/Y Field
inline UBOOL PointInField(FVector Point, FVector FieldCenter, FVector Field)
{
	FVector MinField, MaxField;

	MinField = FieldCenter - Field;
	MaxField = FieldCenter + Field;

	if (Point.X >= MinField.X && Point.X <= MaxField.X)
	{
		if (Point.Y >= MinField.Y && Point.Y <= MaxField.Y)
			return true;
	}

	return false;
}

// Build 250:
// Checks if Point is within a Box
inline UBOOL PointInBox(FVector Point, FVector BoxCenter, FVector Box)
{
	FVector MinBox, MaxBox;

	MinBox = BoxCenter - Box;
	MaxBox = BoxCenter + Box;

	if (Point.X >= MinBox.X && Point.X <= MaxBox.X)
	{
		if (Point.Y >= MinBox.Y && Point.Y <= MaxBox.Y)
		{
			if (Point.Z >= MinBox.Z && Point.Z <= MaxBox.Z)
				return true;
		}
	}

	return false;
}



//-----------------------------------------------------------------------------
// Rotator Functions  

inline UBOOL RApproxZero(FRotator R)
{
	return UBOOL (Abs(R.Pitch) < KINDA_SMALL_NUMBER &&
		      Abs(R.Yaw) < KINDA_SMALL_NUMBER &&
		      Abs(R.Roll) < KINDA_SMALL_NUMBER);
}

inline FLOAT RSize(FRotator R)
{
	return Abs(R.Pitch) + Abs(R.Yaw) + Abs(R.Roll);
}

inline FLOAT RSizeNRoll(FRotator R)
{
	return Abs(R.Pitch) + Abs(R.Yaw);
}

inline FRotator RMin(FRotator A, FRotator B)
{
	if (RSize(A) > RSize(B))
		return A;
	else 
		return B;
}

inline FRotator RMax(FRotator A, FRotator B)
{
	if (RSize(A) < RSize(B))
		return A;
	else 
		return B;
}

inline FRotator RClamp(FRotator R, FRotator Min, FRotator Max)
{
	if (RSize(R) <= RSize(Min))
		return Min;
	else if (RSize(R) >= RSize(Max))
		return Max;
	else 
		return R;
}

inline FRotator RRange(FRotator Min, FRotator Max)
{
	return Min + (Max - Min) * appFrand();
}

// Build 250:
inline FRotator RotRange(FRotator Min, FRotator Max)
{
	if (Min == Max)
		return Max;

	else if (RSize(Min) < RSize(Max))
		return RRange(Min,Max);

	else return FRotator(0,0,0);
}

inline FRotator RNormalize(FRotator Rot)
{
	Rot.Pitch = Rot.Pitch & 0xFFFF;
	if (Rot.Pitch > 32767)
		Rot.Pitch -= 0x10000;

	Rot.Roll  = Rot.Roll & 0xFFFF;
	if (Rot.Roll  > 32767)
		Rot.Roll  -= 0x10000;

	Rot.Yaw   = Rot.Yaw & 0xFFFF;
	if (Rot.Yaw   > 32767)
		Rot.Yaw   -= 0x10000;

	return Rot;
}

//Build 120: fixed formula
inline FRotator RLerp(FRotator A, FRotator B, FLOAT Alpha)
{
	return A + Alpha * (B - A);
}

//Build 120: fixed formula
inline FRotator RSmerp(FRotator A, FRotator B, FLOAT Alpha)
{
	return A + Alpha * Alpha * (3.f - 2.f * Alpha) * (B - A);
}

inline UBOOL RInterpolate(FRotator A, FRotator B, FRotator DeltaR, FLOAT DeltaT)
{
	FRotator Delta = B-A;

	UBOOL bFinished = (RSize(DeltaR) <= 100);
	DeltaR = (A + (Delta * DeltaT));

	return bFinished;
}

inline FLOAT RFunctionGen(BYTE Mode, FLOAT T, FLOAT Base, FLOAT Mod, FLOAT Min, FLOAT Max, FLOAT X, FLOAT Y)
{
	return FFunctionGenDelta(Mode,T,Base,Mod,Min,Max,X,Y,OneSpin);
}

inline FLOAT RScaleLinear(FLOAT Angle, FLOAT Rate, FLOAT T)
{
	if (Rate != 0.f)
	{
		FLOAT Spin = 1.f / Rate;

		if (Rate > 0.f)
			return FScaleDeltaNoBaseLim(Angle, T, Spin, true, OneSpin);
		else
			return FScaleDeltaNoBaseLim(Angle, T, fabs(Spin), false, OneSpin);
	}
	else
		return Angle;
}

inline FRotator RotRand(UBOOL bRoll = 0)
{
	FRotator RRot;

	RRot.Yaw = ((2 * appRand()) % 65535);
	RRot.Pitch = ((2 * appRand()) % 65535);

	if (bRoll)
		RRot.Roll = ((2 * appRand()) % 65535);
	else
		RRot.Roll = 0;

	return RRot;
}


//-----------------------------------------------------------------------------
// Extended FColor Functions

inline FColor MakeRandomColor()
{
	BYTE R = (BYTE)(appFrand()*255.f);
	BYTE G = (BYTE)(appFrand()*255.f);
	BYTE B = (BYTE)(appFrand()*255.f);

	return FColor(R,G,B);
}

inline FColor ColorAdd(FColor A, FColor B)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R + B.R, 0, 255);
	Result.G = Clamp<BYTE>(A.G + B.G, 0, 255);
	Result.B = Clamp<BYTE>(A.B + B.B, 0, 255);

	return Result;
}

inline FColor ColorSub(FColor A, FColor B)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R - B.R, 0, 255);
	Result.G = Clamp<BYTE>(A.G - B.G, 0, 255);
	Result.B = Clamp<BYTE>(A.B - B.B, 0, 255);

	return Result;
}

inline FColor ColorMult(FColor A, FColor B)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R * B.R, 0, 255);
	Result.G = Clamp<BYTE>(A.G * B.G, 0, 255);
	Result.B = Clamp<BYTE>(A.B * B.B, 0, 255);

	return Result;
}

inline FColor ColorMultScalar(FColor A, FLOAT Scalar)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R * Scalar, 0, 255);
	Result.G = Clamp<BYTE>(A.G * Scalar, 0, 255);
	Result.B = Clamp<BYTE>(A.B * Scalar, 0, 255);

	return Result;
}

inline FColor ColorDiv(FColor A, FColor B)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R / B.R, 0, 255);
	Result.G = Clamp<BYTE>(A.G / B.G, 0, 255);
	Result.B = Clamp<BYTE>(A.B / B.B, 0, 255);

	return Result;
}

inline FColor ColorDivScalar(FColor A, FLOAT Scalar)
{
	FColor Result;

	Result.R = Clamp<BYTE>(A.R / Scalar, 0, 255);
	Result.G = Clamp<BYTE>(A.G / Scalar, 0, 255);
	Result.B = Clamp<BYTE>(A.B / Scalar, 0, 255);

	return Result;
}

inline FColor ColorLerp(FColor A, FColor B, FLOAT Amount)
{
	FColor Result;

	Result.R = A.R + Amount * (B.R - A.R);
	Result.G = A.G + Amount * (B.G - A.G);
	Result.B = A.B + Amount * (B.B - A.B);

	return Result;
}

inline FColor ColorSmerp(FColor A, FColor B, FLOAT Amount)
{
	FColor Result;

	Result.R = (-2 * (B.R - A.R) * pow(Amount, 3)) + (3 * (B.R - A.R) * (Amount * Amount)) + A.R;
	Result.G = (-2 * (B.G - A.G) * pow(Amount, 3)) + (3 * (B.G - A.G) * (Amount * Amount)) + A.G;
	Result.B = (-2 * (B.B - A.B) * pow(Amount, 3)) + (3 * (B.B - A.B) * (Amount * Amount)) + A.B;

	return Result;
}

inline FColor VectorToRGB(FVector ColorVector, FLOAT A)
{
	FColor Result;
	FLOAT Alpha;

	if (A == 0.0f)
		Alpha = 255;
	else
		Alpha = A;

	Result.R = ColorVector.X * 255;
	Result.G = ColorVector.Y * 255;
	Result.B = ColorVector.Z * 255;
	Result.A = Alpha;

	return Result;
}

inline FVector RGBToVector(FColor Color)
{
	FVector Result;

	Result.X = Color.R / 255;
	Result.Y = Color.G / 255;
	Result.Z = Color.B / 255;

	return Result;
}

inline FColor HLSToRGB(FLOAT H, FLOAT L, FLOAT S)
{
	FLOAT OffsetSaturation;
	FVector Res;
 
	H = Clamp<FLOAT>(H,0,255);
	L = Clamp<FLOAT>(L,0,255);
	S = Clamp<FLOAT>(S,0,255);
	S = 255 - S;
 
	if(H < 85)
		Res.X = Min<FLOAT>(1, (85 - H)  / 42.5); 
 
	else if(H > 170)
		Res.X = Min<FLOAT>(1, (H - 170) / 42.5);
 
	if (H < 170)
		Res.Y = Min<FLOAT>(1, (85 - fabs(H -  85)) / 42.5);
 
	if (H > 85)
		Res.Z = Min<FLOAT>(1, (85 - fabs(H - 170)) / 42.5);
 
	if (S < 255)
	{
		Res = Res * (S / 255);
		OffsetSaturation = (255 - S) / 255;

		Res.X += OffsetSaturation;
		Res.Y += OffsetSaturation;
		Res.Z += OffsetSaturation;
	}
 
	Res = Res * ((255 - Abs(L - 255)) / 255);

	FColor C;

	C.R = Res.X * 255;
	C.G = Res.Y * 255;
	C.B = Res.Z * 255;
 
	return C;
}

inline FVector ColorMap(FVector RGB)
{
	FLOAT xMin, xMax;
	FLOAT r,g,b,h,l,s;
	FVector hls;

	RGB.X = ClampPositiveFloat(RGB.X, 0, 1);
	RGB.Y = ClampPositiveFloat(RGB.Y, 0, 1);
	RGB.Z = ClampPositiveFloat(RGB.Z, 0, 1);

	r = RGB.X;
	g = RGB.Y;
	b = RGB.Z;

	xMax = Max(Max(r,g),b) ;
	xMin = Min(Max(r,g),b);

	l = (xMax+xMin)/2;

	if (xMax == xMin)
	{
		s = 0;
		h = 0;
	}
	else
	{
		if (l < 0.5)
			s = (xMax-xMin) / (xMax+xMin);
		if (l >= 0.5)  
			s = (xMax-xMin) / (2.0-xMax-xMin);
	}

	if (r == xMax)
		h  = (g-b)/(xMax-xMin);
	if (g == xMax)
		h = 2.0 + (b-r)/(xMax-xMin);
	if (b == xMax)    
		h = 4.0 + (r-g)/(xMax-xMin);

	hls.X = (h/6)*255;
	hls.Y = (l*86);
	hls.Z = (l*255);

	return hls;
}

inline void RGBToHLS(FColor InRGB, BYTE& Hue, BYTE& Luminance, BYTE& Saturation)
{
    FVector RGB;

    RGB.X = InRGB.R / 255.0;
    RGB.Y = InRGB.G / 255.0;
    RGB.Z = InRGB.B / 255.0;

    FVector HLS = ColorMap(RGB);

    Hue = HLS.X;
	Luminance = HLS.Y;
    Saturation = HLS.Z;
}

//-----------------------------------------------------------------------------
// Mini Timer Functions (Build 300)

inline FLOAT MiniTimer(FLOAT T, FLOAT GoalTime, UBOOL bCountdown)
{
	if (bCountdown)
		return FScaleLinear(GoalTime, T, 0.f, GoalTime, GoalTime, false);
	else
		return FScaleLinear(0.f, T, 0.f, GoalTime, GoalTime, true);		
}


//-----------------------------------------------------------------------------
// FVector2D Support (Build 335)

struct FVector2DBool
{
	BITFIELD X:1;
	BITFIELD Y:1;
};

//-----------------------------------------------------------------------------
// FVector2D Support (Build 250)

struct FVector2D 
{
	FLOAT	X, Y;

	// Base Constructor
	FORCEINLINE FVector2D(){}

	// Make FVector2D from 2 indipendent Floats
	FORCEINLINE FVector2D(FLOAT InX, FLOAT InY) : X(InX), Y(InY){}

	// Make FVector2D from 2 indipendent Integers
	FORCEINLINE FVector2D(INT InX, INT InY)
	{
		X = (FLOAT)InX;
		Y = (FLOAT)InY;
	}

	// Make a uniform FVector2D from a single Scale Component
	FORCEINLINE FVector2D(FLOAT Scale) : X(Scale), Y(Scale){}


	// Standard Operators
	friend FVector2D operator*(FLOAT Scale, const FVector2D& V)
	{
		return FVector2D(V.X * Scale, V.Y * Scale);
	}
	FORCEINLINE FVector2D operator+(const FVector2D& V) const
	{
		return FVector2D(X + V.X, Y + V.Y);
	}
	FORCEINLINE FVector2D operator-(const FVector2D& V) const
	{
		return FVector2D( X - V.X, Y - V.Y );
	}
	FORCEINLINE FVector2D operator*(FLOAT Scale) const
	{
		return FVector2D(X * Scale, Y * Scale);
	}
	FVector2D operator/(FLOAT Scale) const
	{
		FLOAT RScale = 1.f/Scale;
		return FVector2D(X * RScale, Y * RScale);
	}
	FORCEINLINE FVector2D operator*(const FVector2D& V) const
	{
		return FVector2D(X * V.X, Y * V.Y);
	}

	// Comparison operators.
	UBOOL operator==(const FVector2D& V) const
	{
		return X == V.X && Y == V.Y;
	}
	UBOOL operator!=(const FVector2D& V)  const
	{
		return X != V.X || Y != V.Y;
	}

	// Unary operators.
	FORCEINLINE FVector2D operator-() const
	{
		return FVector2D(-X, -Y);
	}

	// Assignment operators.
	FORCEINLINE FVector2D operator+=(const FVector2D& V)
	{
		X += V.X;
		Y += V.Y;

		return *this;
	}

	FORCEINLINE FVector2D operator-=(const FVector2D& V)
	{
		X -= V.X;
		Y -= V.Y;

		return *this;
	}

	FORCEINLINE FVector2D operator*=(FLOAT Scale)
	{
		X *= Scale;
		Y *= Scale;

		return *this;
	}

	FVector2D operator/=(FLOAT F)
	{
		FLOAT RF = 1.f/F;

		X *= RF;
		Y *= RF;

		return *this;
	}

	FVector2D operator*=(const FVector2D& V)
	{
		X *= V.X;
		Y *= V.Y;

		return *this;
	}

	FVector2D operator/=(const FVector2D& V)
	{
		X /= V.X;
		Y /= V.Y;

		return *this;
	}
    	FLOAT& operator[]( INT i )
	{
		check(i>-1);
		check(i<2);
		if( i == 0 )	return X;
		else			return Y;
	}

	// Standard functions.
	FLOAT GetMax() const
	{
		return Max(X,Y);
	}

	FLOAT GetAbsMax() const
	{
		return Max(Abs(X),Abs(Y));
	}

	FLOAT GetMin() const
	{
		return Min(X,Y);
	}

	FLOAT Size() const
	{
		return appSqrt(X*X + Y*Y);
	}
	FLOAT SizeSq() const
	{
		return X*X + Y*Y;
	}
	FVector2D Normalize() const
	{	
		FLOAT Mag = Size();

		if(Mag < SMALL_NUMBER)
			return FVector2D(0.f,0.f);
		else
			return FVector2D(X*(1.f/Mag), Y*(1.f/Mag));
	}

	int IsNearlyZero() const
	{
		return	Abs(X)<KINDA_SMALL_NUMBER
			&&	Abs(Y)<KINDA_SMALL_NUMBER;
	}

	UBOOL IsZero() const
	{
		return X == 0.f && Y == 0.f;
	}

	FLOAT& Component(INT Index)
	{
		return (&X)[Index];
	}

	FORCEINLINE FVector2D SafeNormal() const
	{
		FLOAT SqSum = X*X + Y*Y;

		if (SqSum < SMALL_NUMBER)
			return FVector2D(0.f);

		return FVector2D(X*appInvSqrt(SqSum), Y*appInvSqrt(SqSum));
	}

	// Serializer.
	friend FArchive& operator<<(FArchive& Ar, FVector2D& V)
	{
		return Ar << V.X << V.Y;
	}
};


//-----------------------------------------------------------------------------
// Extended Matrix Support 

// A highly extended Matrix Class, to compensate missing calculations in original FMatrix like Determinant Calculation

class SDKCORE_API FsdkMatrix
{
public:

	// Variables.
#if __GNUG__
	FLOAT M[4][4] GCC_ALIGN(16);
	static const FsdkMatrix Identity;
#elif _MSC_VER
	__declspec(align(16)) FLOAT M[4][4];
	static const __declspec(align(16)) FsdkMatrix Identity;
#else
#error FMatrix needs to be properly aligned
#endif 

	// Constructors.
	FORCEINLINE FsdkMatrix()
	{
	}

	FORCEINLINE FsdkMatrix(FPlane InX,FPlane InY,FPlane InZ,FPlane InW)
	{
		M[0][0] = InX.X; M[0][1] = InX.Y;  M[0][2] = InX.Z;  M[0][3] = InX.W;
		M[1][0] = InY.X; M[1][1] = InY.Y;  M[1][2] = InY.Z;  M[1][3] = InY.W;
		M[2][0] = InZ.X; M[2][1] = InZ.Y;  M[2][2] = InZ.Z;  M[2][3] = InZ.W;
		M[3][0] = InW.X; M[3][1] = InW.Y;  M[3][2] = InW.Z;  M[3][3] = InW.W;
	}

	FORCEINLINE FsdkMatrix(FVector InX,FVector InY,FVector InZ,FVector InW)
	{
		M[0][0] = InX.X; M[0][1] = InX.Y;  M[0][2] = InX.Z;  M[0][3] = 0.0f;
		M[1][0] = InY.X; M[1][1] = InY.Y;  M[1][2] = InY.Z;  M[1][3] = 0.0f;
		M[2][0] = InZ.X; M[2][1] = InZ.Y;  M[2][2] = InZ.Z;  M[2][3] = 0.0f;
		M[3][0] = InW.X; M[3][1] = InW.Y;  M[3][2] = InW.Z;  M[3][3] = 1.0f;
	}

	FsdkMatrix(const FVector& Origin, const FQuat& Q)
	{
		FLOAT wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;

		x2 = Q.X + Q.X;  y2 = Q.Y + Q.Y;  z2 = Q.Z + Q.Z;
		xx = Q.X * x2;   xy = Q.X * y2;   xz = Q.X * z2;
		yy = Q.Y * y2;   yz = Q.Y * z2;   zz = Q.Z * z2;
		wx = Q.W * x2;   wy = Q.W * y2;   wz = Q.W * z2;

		M[0][0] = 1.0f - (yy + zz);	M[1][0] = xy - wz;				M[2][0] = xz + wy;			M[3][0] = Origin.X;
		M[0][1] = xy + wz;			M[1][1] = 1.0f - (xx + zz);		M[2][1] = yz - wx;			M[3][1] = Origin.Y;
		M[0][2] = xz - wy;			M[1][2] = yz + wx;				M[2][2] = 1.0f - (xx + yy);	M[3][2] = Origin.Z;
		M[0][3] = 0.0f;				M[1][3] = 0.0f;					M[2][3] = 0.0f;				M[3][3] = 1.0f;
	}

	FORCEINLINE FsdkMatrix(const FVector& Origin, const FPlane& Q)
	{
		FLOAT wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;

		x2 = Q.X + Q.X;  y2 = Q.Y + Q.Y;  z2 = Q.Z + Q.Z;
		xx = Q.X * x2;   xy = Q.X * y2;   xz = Q.X * z2;
		yy = Q.Y * y2;   yz = Q.Y * z2;   zz = Q.Z * z2;
		wx = Q.W * x2;   wy = Q.W * y2;   wz = Q.W * z2;

		M[0][0] = 1.0f - (yy + zz);	M[1][0] = xy - wz;				M[2][0] = xz + wy;			M[3][0] = Origin.X;
		M[0][1] = xy + wz;			M[1][1] = 1.0f - (xx + zz);		M[2][1] = yz - wx;			M[3][1] = Origin.Y;
		M[0][2] = xz - wy;			M[1][2] = yz + wx;				M[2][2] = 1.0f - (xx + yy);	M[3][2] = Origin.Z;
		M[0][3] = 0.0f;				M[1][3] = 0.0f;					M[2][3] = 0.0f;				M[3][3] = 1.0f;
	}

	FsdkMatrix(const FVector& Origin, const FRotator& Rotation);

	// Destructor.

	~FsdkMatrix()
	{
	}

	FORCEINLINE void SetIdentity()
	{
		M[0][0] = 1; M[0][1] = 0;  M[0][2] = 0;  M[0][3] = 0;
		M[1][0] = 0; M[1][1] = 1;  M[1][2] = 0;  M[1][3] = 0;
		M[2][0] = 0; M[2][1] = 0;  M[2][2] = 1;  M[2][3] = 0;
		M[3][0] = 0; M[3][1] = 0;  M[3][2] = 0;  M[3][3] = 1;
	}

	FsdkMatrix GetIdentity() const
	{
		return FsdkMatrix(FPlane(1,0,0,0),
						  FPlane(0,1,0,0),
						  FPlane(0,0,1,0),
						  FPlane(0,0,0,1));
	}

	// Concatenation operator.

	inline FsdkMatrix operator*(const FsdkMatrix& Other) const
	{
		FsdkMatrix	Result;

#if ASM
		__asm
		{
		mov		eax,[Other]
		mov		ecx,[this]
	
		movups	xmm4,[eax]				// Other.M[0][0-3]
		movups	xmm5,[eax+16]			// Other.M[1][0-3]
		movups	xmm6,[eax+32]			// Other.M[2][0-3]
		movups	xmm7,[eax+48]			// Other.M[3][0-3]

		lea		eax,[Result]

		// Begin first row of result.
		movss	xmm0,[ecx]				// M[0][0] 
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4

		movss	xmm1,[ecx+4]			// M[0][1]
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm5

		movss	xmm2,[ecx+8]			// M[0][2]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm6

		addps	xmm1,xmm0				// First row done with xmm0

		movss	xmm3,[ecx+12]			// M[0][3]
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		// Begin second row of result.
		movss	xmm0,[ecx+16]			// M[1][0] 
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm2				// First row done with xmm2
		
		movss	xmm2,[ecx+20]			// M[1][1]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm5

		addps	xmm3,xmm1				// First row done with xmm1
	
		movss	xmm1,[ecx+24]			// M[1][2]
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm6

		movups	[eax],xmm3				// Store Result.M[0][0-3]
		// Done computing first row.
		
		addps	xmm2,xmm0				// Second row done with xmm0

		movss	xmm3,[ecx+28]			// M[1][3]
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		// Begin third row of result.
		movss	xmm0,[ecx+32]			// M[2][0] 
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm1				// Second row done with xmm1
		
		movss	xmm1,[ecx+36]			// M[2][1]
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm5

		addps	xmm3,xmm2				// Second row done with xmm2

		movss	xmm2,[ecx+40]			// M[2][2]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm6

		movups	[eax+16],xmm3			// Store Result.M[1][0-3]
		// Done computing second row.

		addps	xmm1,xmm0				// Third row done with xmm0

		movss	xmm3,[ecx+44]			// M[2][3]
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		// Begin fourth row of result.
		movss	xmm0,[ecx+48]			// M[3][0]
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm2				// Third row done with xmm2
		
		movss	xmm2,[ecx+52]			// M[3][1]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm5

		addps	xmm3,xmm1				// Third row done with xmm1
		
		movss	xmm1,[ecx+56]			// M[3][2]
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm6

		movups	[eax+32],xmm3			// Store Result.M[2][0-3]
		// Done computing third row.

		addps	xmm2,xmm0

		movss	xmm3,[ecx+60]			// M[3][3]
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		// stall
	
		addps	xmm3,xmm1
		
		// stall

		addps	xmm3,xmm2
	
		movups	[eax+48],xmm3			// Store Result.M[3][0-3]
		// Done computing fourth row.
		}
#else

		Result.M[0][0] = M[0][0] * Other.M[0][0] + M[0][1] * Other.M[1][0] + M[0][2] * Other.M[2][0] + M[0][3] * Other.M[3][0];
		Result.M[0][1] = M[0][0] * Other.M[0][1] + M[0][1] * Other.M[1][1] + M[0][2] * Other.M[2][1] + M[0][3] * Other.M[3][1];
		Result.M[0][2] = M[0][0] * Other.M[0][2] + M[0][1] * Other.M[1][2] + M[0][2] * Other.M[2][2] + M[0][3] * Other.M[3][2];
		Result.M[0][3] = M[0][0] * Other.M[0][3] + M[0][1] * Other.M[1][3] + M[0][2] * Other.M[2][3] + M[0][3] * Other.M[3][3];

		Result.M[1][0] = M[1][0] * Other.M[0][0] + M[1][1] * Other.M[1][0] + M[1][2] * Other.M[2][0] + M[1][3] * Other.M[3][0];
		Result.M[1][1] = M[1][0] * Other.M[0][1] + M[1][1] * Other.M[1][1] + M[1][2] * Other.M[2][1] + M[1][3] * Other.M[3][1];
		Result.M[1][2] = M[1][0] * Other.M[0][2] + M[1][1] * Other.M[1][2] + M[1][2] * Other.M[2][2] + M[1][3] * Other.M[3][2];
		Result.M[1][3] = M[1][0] * Other.M[0][3] + M[1][1] * Other.M[1][3] + M[1][2] * Other.M[2][3] + M[1][3] * Other.M[3][3];

		Result.M[2][0] = M[2][0] * Other.M[0][0] + M[2][1] * Other.M[1][0] + M[2][2] * Other.M[2][0] + M[2][3] * Other.M[3][0];
		Result.M[2][1] = M[2][0] * Other.M[0][1] + M[2][1] * Other.M[1][1] + M[2][2] * Other.M[2][1] + M[2][3] * Other.M[3][1];
		Result.M[2][2] = M[2][0] * Other.M[0][2] + M[2][1] * Other.M[1][2] + M[2][2] * Other.M[2][2] + M[2][3] * Other.M[3][2];
		Result.M[2][3] = M[2][0] * Other.M[0][3] + M[2][1] * Other.M[1][3] + M[2][2] * Other.M[2][3] + M[2][3] * Other.M[3][3];

		Result.M[3][0] = M[3][0] * Other.M[0][0] + M[3][1] * Other.M[1][0] + M[3][2] * Other.M[2][0] + M[3][3] * Other.M[3][0];
		Result.M[3][1] = M[3][0] * Other.M[0][1] + M[3][1] * Other.M[1][1] + M[3][2] * Other.M[2][1] + M[3][3] * Other.M[3][1];
		Result.M[3][2] = M[3][0] * Other.M[0][2] + M[3][1] * Other.M[1][2] + M[3][2] * Other.M[2][2] + M[3][3] * Other.M[3][2];
		Result.M[3][3] = M[3][0] * Other.M[0][3] + M[3][1] * Other.M[1][3] + M[3][2] * Other.M[2][3] + M[3][3] * Other.M[3][3];

#endif

		return Result;
	}

	FORCEINLINE void operator*=(const FsdkMatrix& Other)
	{
#if ASM
		__asm
		{
		mov		eax,[Other]
		mov		ecx,[this]
	
		movups	xmm4,[eax]				// Other.M[0][0-3]
		movups	xmm5,[eax+16]			// Other.M[1][0-3]
		movups	xmm6,[eax+32]			// Other.M[2][0-3]
		movups	xmm7,[eax+48]			// Other.M[3][0-3]

		// Begin first row of result.
		movss	xmm0,[ecx]				// M[0][0] 
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4

		movss	xmm1,[ecx+4]			// M[0][1]
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm5

		movss	xmm2,[ecx+8]			// M[0][2]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm6

		addps	xmm1,xmm0				// First row done with xmm0

		movss	xmm3,[ecx+12]			// M[0][3]
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		// Begin second row of result.
		movss	xmm0,[ecx+16]			// M[1][0] 
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm2				// First row done with xmm2
		
		movss	xmm2,[ecx+20]			// M[1][1]
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm5

		addps	xmm3,xmm1				
	
		movss	xmm1,[ecx+24]		
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm6

		movups	[ecx],xmm3				
		
		addps	xmm2,xmm0				

		movss	xmm3,[ecx+28]			
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		movss	xmm0,[ecx+32]			
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm1				
		
		movss	xmm1,[ecx+36]		
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm5

		addps	xmm3,xmm2				

		movss	xmm2,[ecx+40]			
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm6

		movups	[ecx+16],xmm3			

		addps	xmm1,xmm0				

		movss	xmm3,[ecx+44]		
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		movss	xmm0,[ecx+48]			
		shufps	xmm0,xmm0,0
		mulps	xmm0,xmm4
	
		addps	xmm3,xmm2				
		
		movss	xmm2,[ecx+52]			
		shufps	xmm2,xmm2,0
		mulps	xmm2,xmm5

		addps	xmm3,xmm1				
		
		movss	xmm1,[ecx+56]			
		shufps	xmm1,xmm1,0
		mulps	xmm1,xmm6

		movups	[ecx+32],xmm3			

		addps	xmm2,xmm0

		movss	xmm3,[ecx+60]			
		shufps	xmm3,xmm3,0
		mulps	xmm3,xmm7
		
		addps	xmm3,xmm1
		
		addps	xmm3,xmm2
	
		movups	[ecx+48],xmm3			
		}
#else
		FsdkMatrix Result;
		Result.M[0][0] = M[0][0] * Other.M[0][0] + M[0][1] * Other.M[1][0] + M[0][2] * Other.M[2][0] + M[0][3] * Other.M[3][0];
		Result.M[0][1] = M[0][0] * Other.M[0][1] + M[0][1] * Other.M[1][1] + M[0][2] * Other.M[2][1] + M[0][3] * Other.M[3][1];
		Result.M[0][2] = M[0][0] * Other.M[0][2] + M[0][1] * Other.M[1][2] + M[0][2] * Other.M[2][2] + M[0][3] * Other.M[3][2];
		Result.M[0][3] = M[0][0] * Other.M[0][3] + M[0][1] * Other.M[1][3] + M[0][2] * Other.M[2][3] + M[0][3] * Other.M[3][3];

		Result.M[1][0] = M[1][0] * Other.M[0][0] + M[1][1] * Other.M[1][0] + M[1][2] * Other.M[2][0] + M[1][3] * Other.M[3][0];
		Result.M[1][1] = M[1][0] * Other.M[0][1] + M[1][1] * Other.M[1][1] + M[1][2] * Other.M[2][1] + M[1][3] * Other.M[3][1];
		Result.M[1][2] = M[1][0] * Other.M[0][2] + M[1][1] * Other.M[1][2] + M[1][2] * Other.M[2][2] + M[1][3] * Other.M[3][2];
		Result.M[1][3] = M[1][0] * Other.M[0][3] + M[1][1] * Other.M[1][3] + M[1][2] * Other.M[2][3] + M[1][3] * Other.M[3][3];

		Result.M[2][0] = M[2][0] * Other.M[0][0] + M[2][1] * Other.M[1][0] + M[2][2] * Other.M[2][0] + M[2][3] * Other.M[3][0];
		Result.M[2][1] = M[2][0] * Other.M[0][1] + M[2][1] * Other.M[1][1] + M[2][2] * Other.M[2][1] + M[2][3] * Other.M[3][1];
		Result.M[2][2] = M[2][0] * Other.M[0][2] + M[2][1] * Other.M[1][2] + M[2][2] * Other.M[2][2] + M[2][3] * Other.M[3][2];
		Result.M[2][3] = M[2][0] * Other.M[0][3] + M[2][1] * Other.M[1][3] + M[2][2] * Other.M[2][3] + M[2][3] * Other.M[3][3];

		Result.M[3][0] = M[3][0] * Other.M[0][0] + M[3][1] * Other.M[1][0] + M[3][2] * Other.M[2][0] + M[3][3] * Other.M[3][0];
		Result.M[3][1] = M[3][0] * Other.M[0][1] + M[3][1] * Other.M[1][1] + M[3][2] * Other.M[2][1] + M[3][3] * Other.M[3][1];
		Result.M[3][2] = M[3][0] * Other.M[0][2] + M[3][1] * Other.M[1][2] + M[3][2] * Other.M[2][2] + M[3][3] * Other.M[3][2];
		Result.M[3][3] = M[3][0] * Other.M[0][3] + M[3][1] * Other.M[1][3] + M[3][2] * Other.M[2][3] + M[3][3] * Other.M[3][3];
		*this = Result;

#endif
	}

	// Comparison operators.
	inline UBOOL operator==(const FsdkMatrix& Other) const
	{
		for(INT X = 0;X < 4;X++)
		{
			for(INT Y = 0;Y < 4;Y++)
			{
				if(M[X][Y] != Other.M[X][Y])
					return 0;
			}
		}

		return 1;
	}

	inline UBOOL operator!=(const FsdkMatrix& Other) const
	{
		return !(*this == Other);
	}

	// FPlane Transformation Functions.
	FORCEINLINE FPlane TransformFPlane(const FPlane &P) const
	{
		FPlane Result;

#if ASM
		__asm
		{
			mov		eax,[P]
			mov		ecx,[this]
			
			movups	xmm4,[ecx]			
			movups	xmm5,[ecx+16]		
			movups	xmm6,[ecx+32]		
			movups	xmm7,[ecx+48]		

			movss	xmm0,[eax]FVector.X
			shufps	xmm0,xmm0,0
			mulps	xmm0,xmm4

			movss	xmm1,[eax]FVector.Y
			shufps	xmm1,xmm1,0
			mulps	xmm1,xmm5

			movss	xmm2,[eax]FVector.Z
			shufps	xmm2,xmm2,0
			mulps	xmm2,xmm6

			addps	xmm0,xmm1

			movss	xmm3,[eax]FPlane.W
			shufps	xmm3,xmm3,0
			mulps	xmm3,xmm7
			
			lea		eax,[Result]

			addps	xmm2,xmm3			
			addps	xmm0,xmm2
		
			movups	[eax],xmm0
		}
#else
		Result.X = P.X * M[0][0] + P.Y * M[1][0] + P.Z * M[2][0] + P.W * M[3][0];
		Result.Y = P.X * M[0][1] + P.Y * M[1][1] + P.Z * M[2][1] + P.W * M[3][1];
		Result.Z = P.X * M[0][2] + P.Y * M[1][2] + P.Z * M[2][2] + P.W * M[3][2];
		Result.W = P.X * M[0][3] + P.Y * M[1][3] + P.Z * M[2][3] + P.W * M[3][3];
#endif

		return Result;
	}

	// FVector Transformation.
	FORCEINLINE FVector TransformFVector(const FVector &V) const
	{
		return TransformFPlane(FPlane(V.X,V.Y,V.Z,1.0f));
	}

	FORCEINLINE FVector InverseTransformFVector(const FVector &V) const
	{
		FVector t, Result;

		t.X = V.X - M[3][0];
		t.Y = V.Y - M[3][1];
		t.Z = V.Z - M[3][2];

		Result.X = t.X * M[0][0] + t.Y * M[0][1] + t.Z * M[0][2];
		Result.Y = t.X * M[1][0] + t.Y * M[1][1] + t.Z * M[1][2];
		Result.Z = t.X * M[2][0] + t.Y * M[2][1] + t.Z * M[2][2];

		return Result;
	}

	// Standard Transformation.
	FORCEINLINE FPlane TransformNormal(const FVector& V) const
	{
		return TransformFPlane(FPlane(V.X,V.Y,V.Z,0.0f));
	}

	FORCEINLINE FVector InverseTransformNormal(const FVector &V) const
	{
		FVector Result;

		Result.X = V.X * M[0][0] + V.Y * M[0][1] + V.Z * M[0][2];
		Result.Y = V.X * M[1][0] + V.Y * M[1][1] + V.Z * M[1][2];
		Result.Z = V.X * M[2][0] + V.Y * M[2][1] + V.Z * M[2][2];

		return Result;
	}

	// Transpose.
	FORCEINLINE FsdkMatrix Transpose()
	{
		FsdkMatrix Result;

		Result.M[0][0] = M[0][0];
		Result.M[0][1] = M[1][0];
		Result.M[0][2] = M[2][0];
		Result.M[0][3] = M[3][0];

		Result.M[1][0] = M[0][1];
		Result.M[1][1] = M[1][1];
		Result.M[1][2] = M[2][1];
		Result.M[1][3] = M[3][1];

		Result.M[2][0] = M[0][2];
		Result.M[2][1] = M[1][2];
		Result.M[2][2] = M[2][2];
		Result.M[2][3] = M[3][2];

		Result.M[3][0] = M[0][3];
		Result.M[3][1] = M[1][3];
		Result.M[3][2] = M[2][3];
		Result.M[3][3] = M[3][3];

		return Result;
	}

	// Determinant.
	inline FLOAT Determinant() const
	{
		return	M[0][0] * (
					M[1][1] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
					M[2][1] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) +
					M[3][1] * (M[1][2] * M[2][3] - M[1][3] * M[2][2])
					) -
				M[1][0] * (
					M[0][1] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
					M[2][1] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
					M[3][1] * (M[0][2] * M[2][3] - M[0][3] * M[2][2])
					) +
				M[2][0] * (
					M[0][1] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) -
					M[1][1] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
					M[3][1] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
					) -
				M[3][0] * (
					M[0][1] * (M[1][2] * M[2][3] - M[1][3] * M[2][2]) -
					M[1][1] * (M[0][2] * M[2][3] - M[0][3] * M[2][2]) +
					M[2][1] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
					);
	}

	// Inverse Matrix Calculations
	inline FsdkMatrix Inverse() const
	{
		FsdkMatrix Result;
		FLOAT Det = Determinant();

		if (Det == 0.0f)
			return GetIdentity();

		//if(Det == 0.0f)
		//	return FsdkMatrix::Identity;

		FLOAT RDet = 1.0f / Det;

		Result.M[0][0] = RDet * (
				M[1][1] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
				M[2][1] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) +
				M[3][1] * (M[1][2] * M[2][3] - M[1][3] * M[2][2])
				);
		Result.M[0][1] = -RDet * (
				M[0][1] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
				M[2][1] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
				M[3][1] * (M[0][2] * M[2][3] - M[0][3] * M[2][2])
				);
		Result.M[0][2] = RDet * (
				M[0][1] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) -
				M[1][1] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
				M[3][1] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
				);
		Result.M[0][3] = -RDet * (
				M[0][1] * (M[1][2] * M[2][3] - M[1][3] * M[2][2]) -
				M[1][1] * (M[0][2] * M[2][3] - M[0][3] * M[2][2]) +
				M[2][1] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
				);

		Result.M[1][0] = -RDet * (
				M[1][0] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
				M[2][0] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) +
				M[3][0] * (M[1][2] * M[2][3] - M[1][3] * M[2][2])
				);
		Result.M[1][1] = RDet * (
				M[0][0] * (M[2][2] * M[3][3] - M[2][3] * M[3][2]) -
				M[2][0] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
				M[3][0] * (M[0][2] * M[2][3] - M[0][3] * M[2][2])
				);
		Result.M[1][2] = -RDet * (
				M[0][0] * (M[1][2] * M[3][3] - M[1][3] * M[3][2]) -
				M[1][0] * (M[0][2] * M[3][3] - M[0][3] * M[3][2]) +
				M[3][0] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
				);
		Result.M[1][3] = RDet * (
				M[0][0] * (M[1][2] * M[2][3] - M[1][3] * M[2][2]) -
				M[1][0] * (M[0][2] * M[2][3] - M[0][3] * M[2][2]) +
				M[2][0] * (M[0][2] * M[1][3] - M[0][3] * M[1][2])
				);

		Result.M[2][0] = RDet * (
				M[1][0] * (M[2][1] * M[3][3] - M[2][3] * M[3][1]) -
				M[2][0] * (M[1][1] * M[3][3] - M[1][3] * M[3][1]) +
				M[3][0] * (M[1][1] * M[2][3] - M[1][3] * M[2][1])
				);
		Result.M[2][1] = -RDet * (
				M[0][0] * (M[2][1] * M[3][3] - M[2][3] * M[3][1]) -
				M[2][0] * (M[0][1] * M[3][3] - M[0][3] * M[3][1]) +
				M[3][0] * (M[0][1] * M[2][3] - M[0][3] * M[2][1])
				);
		Result.M[2][2] = RDet * (
				M[0][0] * (M[1][1] * M[3][3] - M[1][3] * M[3][1]) -
				M[1][0] * (M[0][1] * M[3][3] - M[0][3] * M[3][1]) +
				M[3][0] * (M[0][1] * M[1][3] - M[0][3] * M[1][1])
				);
		Result.M[2][3] = -RDet * (
				M[0][0] * (M[1][1] * M[2][3] - M[1][3] * M[2][1]) -
				M[1][0] * (M[0][1] * M[2][3] - M[0][3] * M[2][1]) +
				M[2][0] * (M[0][1] * M[1][3] - M[0][3] * M[1][1])
				);

		Result.M[3][0] = -RDet * (
				M[1][0] * (M[2][1] * M[3][2] - M[2][2] * M[3][1]) -
				M[2][0] * (M[1][1] * M[3][2] - M[1][2] * M[3][1]) +
				M[3][0] * (M[1][1] * M[2][2] - M[1][2] * M[2][1])
				);
		Result.M[3][1] = RDet * (
				M[0][0] * (M[2][1] * M[3][2] - M[2][2] * M[3][1]) -
				M[2][0] * (M[0][1] * M[3][2] - M[0][2] * M[3][1]) +
				M[3][0] * (M[0][1] * M[2][2] - M[0][2] * M[2][1])
				);
		Result.M[3][2] = -RDet * (
				M[0][0] * (M[1][1] * M[3][2] - M[1][2] * M[3][1]) -
				M[1][0] * (M[0][1] * M[3][2] - M[0][2] * M[3][1]) +
				M[3][0] * (M[0][1] * M[1][2] - M[0][2] * M[1][1])
				);
		Result.M[3][3] = RDet * (
				M[0][0] * (M[1][1] * M[2][2] - M[1][2] * M[2][1]) -
				M[1][0] * (M[0][1] * M[2][2] - M[0][2] * M[2][1]) +
				M[2][0] * (M[0][1] * M[1][2] - M[0][2] * M[1][1])
				);

		return Result;
	}

	FsdkMatrix TransposeAdjoint() const
	{
		FsdkMatrix ta;

		ta.M[0][0] = this->M[1][1] * this->M[2][2] - this->M[1][2] * this->M[2][1];
		ta.M[0][1] = this->M[1][2] * this->M[2][0] - this->M[1][0] * this->M[2][2];
		ta.M[0][2] = this->M[1][0] * this->M[2][1] - this->M[1][1] * this->M[2][0];
		ta.M[0][3] = 0.f;

		ta.M[1][0] = this->M[2][1] * this->M[0][2] - this->M[2][2] * this->M[0][1];
		ta.M[1][1] = this->M[2][2] * this->M[0][0] - this->M[2][0] * this->M[0][2];
		ta.M[1][2] = this->M[2][0] * this->M[0][1] - this->M[2][1] * this->M[0][0];
		ta.M[1][3] = 0.f;

		ta.M[2][0] = this->M[0][1] * this->M[1][2] - this->M[0][2] * this->M[1][1];
		ta.M[2][1] = this->M[0][2] * this->M[1][0] - this->M[0][0] * this->M[1][2];
		ta.M[2][2] = this->M[0][0] * this->M[1][1] - this->M[0][1] * this->M[1][0];
		ta.M[2][3] = 0.f;

		ta.M[3][0] = 0.f;
		ta.M[3][1] = 0.f;
		ta.M[3][2] = 0.f;
		ta.M[3][3] = 1.f;

		return ta;
	}

	// Remove any scaling from this matrix
	void RemoveScaling()
	{
		FLOAT SquareSum, Scale;

		for (INT i=0; i<3; i++)
		{
			SquareSum = (M[i][0] * M[i][0]) + (M[i][1] * M[i][1]) + (M[i][2] * M[i][2]);
			if (SquareSum > SMALL_NUMBER)
			{
				Scale = 1.f/appSqrt(SquareSum);
				M[i][0] *= Scale; 
				M[i][1] *= Scale; 
				M[i][2] *= Scale; 
			}
		}
	}

	void ScaleTranslation(const FVector& Scale3D)
	{
		M[3][0] *= Scale3D.X;
		M[3][1] *= Scale3D.Y;
		M[3][2] *= Scale3D.Z;
	}

	FVector GetOrigin() const
	{ 
		return FVector(M[3][0],M[3][1],M[3][2]);
	}

	FVector GetAxis(INT i) const
	{
		checkSlow(i >= 0 && i <= 2);
		return FVector(M[i][0], M[i][1], M[i][2]);
	}

	void SetAxis(INT i, const FVector& Axis)
	{
		checkSlow(i >= 0 && i <= 2);
		M[i][0] = Axis.X;
		M[i][1] = Axis.Y;
		M[i][2] = Axis.Z;
	}

	void SetOrigin(const FVector& NewOrigin)
	{
		M[3][0] = NewOrigin.X;
		M[3][1] = NewOrigin.Y;
		M[3][2] = NewOrigin.Z;
	}

	inline FRotator Rotator() const;
	
	static UBOOL MakeFrustumPlane(FLOAT A,FLOAT B,FLOAT C,FLOAT D,FPlane& OutPlane)
	{
		FLOAT LengthSquared = A * A + B * B + C * C;
		if (LengthSquared > DELTA*DELTA)
		{
			FLOAT	InvLength = 1.0f / appSqrt(LengthSquared);
			OutPlane = FPlane(-A * InvLength,-B * InvLength,-C * InvLength,D * InvLength);
			return 1;
		}
		else
			return 0;
	}

	UBOOL GetFrustumNearPlane(FPlane& OutPlane) const
	{
		return MakeFrustumPlane(M[0][2], M[1][2], M[2][2], M[3][2], OutPlane);
	}

	UBOOL GetFrustumFarPlane(FPlane& OutPlane) const 
	{
		return MakeFrustumPlane(M[0][3] - M[0][2],
								M[1][3] - M[1][2],
								M[2][3] - M[2][2],
								M[3][3] - M[3][2],
								OutPlane);
	}

	UBOOL GetFrustumLeftPlane(FPlane& OutPlane) const
	{
		return MakeFrustumPlane(M[0][3] + M[0][0],
								M[1][3] + M[1][0],
								M[2][3] + M[2][0],
								M[3][3] + M[3][0],
								OutPlane);
	}

	UBOOL GetFrustumRightPlane(FPlane& OutPlane) const
	{
		return MakeFrustumPlane(M[0][3] - M[0][0],
								M[1][3] - M[1][0],
								M[2][3] - M[2][0],
								M[3][3] - M[3][0],
								OutPlane);
	}

	UBOOL GetFrustumTopPlane(FPlane& OutPlane) const
	{
		return MakeFrustumPlane(M[0][3] - M[0][1],
								M[1][3] - M[1][1],
								M[2][3] - M[2][1],
								M[3][3] - M[3][1],
								OutPlane);
	}

	UBOOL GetFrustumBottomPlane(FPlane& OutPlane) const
	{
		return MakeFrustumPlane(
			M[0][3] + M[0][1],
			M[1][3] + M[1][1],
			M[2][3] + M[2][1],
			M[3][3] + M[3][1],
			OutPlane);
	}

	// Serializer.
	friend FArchive& operator<<(FArchive& Ar,FsdkMatrix& M)
	{
		return Ar << 
			M.M[0][0] << M.M[0][1] << M.M[0][2] << M.M[0][3] << 
			M.M[1][0] << M.M[1][1] << M.M[1][2] << M.M[1][3] << 
			M.M[2][0] << M.M[2][1] << M.M[2][2] << M.M[2][3] << 
			M.M[3][0] << M.M[3][1] << M.M[3][2] << M.M[3][3];
	}
};

// A FVector-scaled Matrix Class
class SDKCORE_API FsdkScaleMatrix : public FsdkMatrix
{

public:

	// Constructor
	FsdkScaleMatrix(FVector Scale) :
		FsdkMatrix(FPlane(Scale.X,	0.0f, 0.0f, 0.0f),
				FPlane(0.0f, Scale.Y, 0.0f, 0.0f),
				FPlane(0.0f, 0.0f, Scale.Z,	0.0f),
				FPlane(0.0f, 0.0f, 0.0f, 1.0f)){}
};

// A translational Matrix Class
class SDKCORE_API FsdkTranslationMatrix : public FsdkMatrix
{

public:

	// Constructor
	FsdkTranslationMatrix(FVector Delta) :
		FsdkMatrix(FPlane(1.0f, 0.0f, 0.0f, 0.0f),
				FPlane(0.0f, 1.0f, 0.0f, 0.0f),
				FPlane(0.0f, 0.0f, 1.0f, 0.0f),
				FPlane(Delta.X,	Delta.Y, Delta.Z,1.0f)){}
};

// A rotational Matrix Class
class SDKCORE_API FsdkRotationMatrix : public FsdkMatrix
{

public:

#if 0
	// Constructor
	FsdkRotationMatrix(FRotator Rot) :
		FsdkMatrix(
			Identity *

			// Pitch
			FsdkMatrix(FPlane(+GMath.CosTab(Rot.Pitch), 0.0f, +GMath.SinTab(Rot.Pitch), 0.0f),
					   FPlane(0.0f,	1.0f, 0.0f, 0.0f),
					   FPlane(-GMath.SinTab(Rot.Pitch), 0.0f, +GMath.CosTab(Rot.Pitch), 0.0f),
					   FPlane(0.0f,	0.0f, 0.0f, 1.0f)) *

			// Yaw
			FsdkMatrix(FPlane(+GMath.CosTab(Rot.Yaw), +GMath.SinTab(Rot.Yaw), 0.0f, 0.0f),
					FPlane(-GMath.SinTab(Rot.Yaw), +GMath.CosTab(Rot.Yaw), 0.0f, 0.0f),
					FPlane(0.0f, 0.0f, 1.0f, 0.0f),
					FPlane(0.0f, 0.0f, 0.0f, 1.0f)) *

			// Roll
			FsdkMatrix(FPlane(1.0f, 0.0f, 0.0f, 0.0f),
					FPlane(0.0f, +GMath.CosTab(Rot.Roll), -GMath.SinTab(Rot.Roll), 0.0f),
					FPlane(0.0f, +GMath.SinTab(Rot.Roll), +GMath.CosTab(Rot.Roll), 0.0f),
					FPlane(0.0f, 0.0f, 0.0f, 1.0f)) ) {}
#else

	// Constructor
	FsdkRotationMatrix(FRotator Rot)
	{
		FLOAT	SR	= GMath.SinTab(Rot.Roll),
				SP	= GMath.SinTab(Rot.Pitch),
				SY	= GMath.SinTab(Rot.Yaw),
				CR	= GMath.CosTab(Rot.Roll),
				CP	= GMath.CosTab(Rot.Pitch),
				CY	= GMath.CosTab(Rot.Yaw);

		M[0][0]	= CP * CY;
		M[0][1]	= CP * SY;
		M[0][2]	= SP;
		M[0][3]	= 0.f;

		M[1][0]	= SR * SP * CY - CR * SY;
		M[1][1]	= SR * SP * SY + CR * CY;
		M[1][2]	= - SR * CP;
		M[1][3]	= 0.f;

		M[2][0]	= -( CR * SP * CY + SR * SY );
		M[2][1]	= CY * SR - CR * SP * SY;
		M[2][2]	= CR * CP;
		M[2][3]	= 0.f;

		M[3][0]	= 0.f;
		M[3][1]	= 0.f;
		M[3][2]	= 0.f;
		M[3][3]	= 1.f;
	}
#endif
};

class SDKCORE_API FsdkInverseRotationMatrix : public FsdkMatrix
{
public:

	FsdkInverseRotationMatrix(FRotator Rot) :
		FsdkMatrix(

			// Pitch
			FsdkMatrix(FPlane(+GMath.CosTab(-Rot.Pitch), 0.0f, +GMath.SinTab(-Rot.Pitch), 0.0f),
					FPlane(0.0f, 1.0f, 0.0f, 0.0f),
					FPlane(-GMath.SinTab(-Rot.Pitch), 0.0f, +GMath.CosTab(-Rot.Pitch), 0.0f),
					FPlane(0.0f, 0.0f, 0.0f, 1.0f)) *

			// Yaw
			FsdkMatrix(FPlane(+GMath.CosTab(-Rot.Yaw),	+GMath.SinTab(-Rot.Yaw), 0.0f,	0.0f),
					FPlane(-GMath.SinTab(-Rot.Yaw),	+GMath.CosTab(-Rot.Yaw), 0.0f,	0.0f),
					FPlane(0.0f, 0.0f, 1.0f, 0.0f),
					FPlane(0.0f, 0.0f, 0.0f, 1.0f)) *

			// Roll
			FsdkMatrix(FPlane(1.0f, 0.0f, 0.0f, 0.0f),
				FPlane(0.0f, +GMath.CosTab(-Rot.Roll),-GMath.SinTab(-Rot.Roll),	0.0f),
				FPlane(0.0f, +GMath.SinTab(-Rot.Roll),+GMath.CosTab(-Rot.Roll),	0.0f),
				FPlane(0.0f, 0.0f, 0.0f, 1.0f)) ) {}
};

FsdkMatrix LocalToWorld(AActor* A);
FsdkMatrix WorldToLocal(AActor* A);

//-----------------------------------------------------------------------------
// Extended Plane Support 

// An extended Plane class with additional needed functionality
class SDKCORE_API FsdkPlane : public FVector
{
public:

	FLOAT W;

	// Constructors.
	FORCEINLINE FsdkPlane(){}
	FORCEINLINE FsdkPlane(const FsdkPlane& P) :	FVector(P),	W(P.W) {}
	FORCEINLINE FsdkPlane(const FVector& V) :	FVector(V),	W(0) {}

	FORCEINLINE FsdkPlane(FLOAT InX, FLOAT InY, FLOAT InZ, FLOAT InW) : FVector(InX,InY,InZ), W(InW) {}
	FORCEINLINE FsdkPlane(FVector InNormal, FLOAT InW) : FVector(InNormal), W(InW) {}

	FORCEINLINE FsdkPlane(FVector InBase, const FVector &InNormal) : 
		FVector(InNormal),
		W(InBase | InNormal){}

	FsdkPlane(FVector A, FVector B, FVector C) :
		FVector( ((B-A)^(C-A)).SafeNormal() ),
		W( A | ((B-A)^(C-A)).SafeNormal() ) {}

	FORCEINLINE FLOAT PlaneDot(const FVector &P) const
	{
		return X*P.X + Y*P.Y + Z*P.Z - W;
	}

	FsdkPlane Flip() const
	{
		return FsdkPlane(-X,-Y,-Z,-W);
	}

	inline FsdkPlane TransformByUsingAdjointT(const FsdkMatrix& M, FLOAT DetM, const FsdkMatrix& TA)  const;

	// Operators mostly taken from old FPlane:
	UBOOL operator == (const FsdkPlane& P) const
	{
		return X == P.X && Y==P.Y && Z==P.Z && W==P.W;
	}
	UBOOL operator != (const FsdkPlane& P) const
	{
		return X!=P.X || Y!=P.Y || Z!=P.Z || W!=P.W;
	}
	FORCEINLINE FLOAT operator | (const FsdkPlane& P) const
	{
		return X*P.X + Y*P.Y + Z*P.Z + W*P.W;
	}
	FsdkPlane operator + (const FsdkPlane& P) const
	{
		return FsdkPlane(X + P.X, Y + P.Y, Z + P.Z, W + P.W);
	}
	FsdkPlane operator - (const FsdkPlane& P) const
	{
		return FsdkPlane(X - P.X, Y - P.Y, Z - P.Z, W - P.W);
	}
	FsdkPlane operator / (FLOAT Scale) const
	{
		FLOAT RScale = 1.f/Scale;
		return FsdkPlane(X * RScale, Y * RScale, Z * RScale, W * RScale);
	}
	FsdkPlane operator * (FLOAT Scale) const
	{
		return FsdkPlane(X * Scale, Y * Scale, Z * Scale, W * Scale);
	}
	FsdkPlane operator * (const FsdkPlane& P)
	{
		return FsdkPlane(X*P.X, Y*P.Y, Z*P.Z, W*P.W);
	}
	FsdkPlane operator += (const FsdkPlane& P)
	{
		X += P.X;
		Y += P.Y;
		Z += P.Z;
		W += P.W;

		return *this;
	}
	FsdkPlane operator -= (const FsdkPlane& P)
	{
		X -= P.X; 
		Y -= P.Y; 
		Z -= P.Z; 
		W -= P.W;

		return *this;
	}
	FsdkPlane operator *= (FLOAT Scale)
	{
		X *= Scale;
		Y *= Scale;
		Z *= Scale;
		W *= Scale;

		return *this;
	}
	FsdkPlane operator *= (const FsdkPlane& P)
	{
		X *= P.X;
		Y *= P.Y;
		Z *= P.Z;
		W *= P.W;

		return *this;
	}
	FsdkPlane operator /= (FLOAT V)
	{
		FLOAT RV = 1.f/V;

		X *= RV; 
		Y *= RV;
		Z *= RV; 
		W *= RV;

		return *this;
	}

	// Serializer.
	friend FArchive& operator<<(FArchive& Ar, FsdkPlane &P)
	{
		return Ar << (FVector&)P << P.W;
	}
};

//-----------------------------------------------------------------------------
// Quaternion Support (Build 359)

inline FPlane QuatAdd(FPlane A, FPlane B)
{
	return FPlane(A.X + B.X, A.Y + B.Y, A.Z + B.Z, A.W + B.W);
}

inline FPlane QuatSub(FPlane A, FPlane B)
{
	return FPlane(A.X - B.X, A.Y - B.Y, A.Z - B.Z, A.W - B.W);
}

inline FPlane QuatInv(FPlane Q)
{
	return FPlane(-Q.X, -Q.Y, -Q.Z, Q.W);
}

inline FPlane QuatMult(FPlane A, FPlane B)
{
	return FPlane(A.W * B.X + A.X * B.W + A.Y * B.Z - A.Z * B.Y,
				  A.W * B.Y - A.X * B.Z + A.Y * B.W + A.Z * B.X,
				  A.W * B.Z + A.X * B.Y - A.Y * B.X + A.Z * B.W,
				  A.W * B.W - A.X * B.X - A.Y * B.Y - A.Z * B.Z);
}

inline FPlane QuatMultScalar(FPlane Q, FLOAT F)
{
	return FPlane(F*Q.X, F*Q.Y, F*Q.Z, F*Q.W);
}

inline FPlane QuatMultScalarInc(FPlane Q, FLOAT F)
{
	Q.X *= F;
	Q.Y *= F;
	Q.Z *= F;
	Q.W *= F;

	return Q;
}

inline FLOAT QuatSizeSq(FPlane Q)
{
	return (FLOAT)(Q.X*Q.X + Q.Y*Q.Y + Q.Z*Q.Z + Q.W*Q.W);
}

inline FLOAT QuatSize(FPlane Q)
{
	return appSqrt(QuatSizeSq(Q));
}

inline FPlane QMakeFromAxis(FVector Axis, FLOAT Angle)
{
	FLOAT angleh = 0.5f * Angle;
	FLOAT s = appSin(angleh);
	FLOAT c = appCos(angleh);

	FLOAT X = s * Axis.X;
	FLOAT Y = s * Axis.Y;
	FLOAT Z = s * Axis.Z;

	return FPlane(X, Y, Z, c);
}

inline FPlane QuatNorm(FPlane Q)
{
	FLOAT SquareSum = QuatSizeSq(Q);

	if (SquareSum >= DELTA)
	{
		FLOAT Scale = appInvSqrt(SquareSum);

		return QuatMultScalarInc(Q, Scale);
	}
	else 
		return FPlane(0.0f, 0.0f, 0.0f, 1.0f);
}

inline FVector QRotateVector(FPlane Q, FVector V)
{	
	FVector QV(Q.X, Q.Y, Q.Z);
	FVector Result = 2.f * Q.W * (QV ^ V);

	Result  += ((Q.W * Q.W) - (QV | QV)) * V;
	Result  += (2.f * (QV | V)) * QV;

	return Result;
}

inline FLOAT QuatDot(FPlane A, FPlane B)
{
	return (A.X*B.X + A.Y*B.Y + A.Z*B.Z);
}

inline FPlane RotToQuat(FRotator Rot)
{
	FLOAT P, Y, R;
	FLOAT cyaw,cpitch,croll;
	FLOAT syaw,spitch,sroll;
	FLOAT cyawcpitch,syawspitch,cyawspitch,syawcpitch;

	P = -0.5 * Rot.Pitch / RadianToURot;
	Y = -0.5 * Rot.Yaw / RadianToURot;
	R = 0.5 * Rot.Roll / RadianToURot;

	cpitch = appCos(P); 
	cyaw = appCos(Y);
	croll = appCos(R);

	spitch = appSin(P);
	syaw = appSin(Y);
	sroll = appSin(R);

	cyawcpitch = cyaw * cpitch;
	syawspitch = syaw * spitch;
	cyawspitch = cyaw * spitch;
	syawcpitch = syaw * cpitch;

	return FPlane(cyawcpitch*croll + syawspitch*sroll,
				  cyawcpitch*sroll - syawspitch*croll,
				  cyawspitch*croll + syawcpitch*sroll,
				  syawcpitch*croll - cyawspitch*sroll);
}

inline FRotator QuatToRot(FPlane Q)
{
	return FsdkMatrix(FVector(0.f,0.f,0.f), Q).Rotator();
}

inline void AlignQuatWith(FPlane& A, FPlane& B)
{
	FLOAT Minus = Square(A.X-B.X) + Square(A.Y-B.Y) + Square(A.Z-B.Z) + Square(A.W-B.W);
	FLOAT Plus = Square(A.X+B.X) + Square(A.Y+B.Y) + Square(A.Z+B.Z) + Square(A.W+B.W);

	if (Minus > Plus)
	{
		A.X = - B.X;
		A.Y = - B.Y;
		A.Z = - B.Z;
		A.W = - B.W;
	}
}

inline FPlane QSlerp(FPlane A, FPlane B, FLOAT Alpha)
{
	FLOAT Cosom, RawCosom, scaleA, scaleB;

	Cosom = RawCosom = QuatDot(A, B);

	if (RawCosom < 0.0f)  
		Cosom = -RawCosom;
	
	if (Cosom < 0.9999f)
	{	
		FLOAT omega = appAcos(Cosom);
		FLOAT sininv = 1.f/appSin(omega);

		scaleA = appSin((1.f - Alpha) * omega) * sininv;
		scaleB = appSin(Alpha * omega) * sininv;
	}
	else
	{
		scaleA = 1.0f - Alpha;
		scaleB = Alpha;	
	}

	if (RawCosom < 0.0f)
		scaleB = -scaleB;

	FPlane Result;
		
	Result.X = scaleA * A.X + scaleB * B.X;
	Result.Y = scaleA * A.Y + scaleB * B.Y;
	Result.Z = scaleA * A.Z + scaleB * B.Z;
	Result.W = scaleA * A.W + scaleB * B.W;

	return Result;
}

inline FPlane QFindBetween(FVector A, FVector B)
{
	FVector Cross = A ^ B;
	FLOAT cMag = Cross.Size();

	if (cMag < KINDA_SMALL_NUMBER)
		return FPlane(0.f, 0.f, 0.f, 0.f);

	FLOAT angle = asin(cMag); 

	FLOAT dot = A | B;

	if (dot < 0.f)
		angle = PI - angle;

	FLOAT sinAngleH = appSin(0.5f * angle);
	FLOAT cosAngleH = appCos(0.5f * angle);

	FVector Axis = Cross / cMag;

	return FPlane(sinAngleH * Axis.X,
				  sinAngleH * Axis.Y,
				  sinAngleH * Axis.Z,
				  cosAngleH);
}