// minimal basic type definitions for Crimsonland mods
// 2003 (c) 10tons

#ifndef CLTYPES_H
#define CLTYPES_H

#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>



#ifndef DWORD // just assume we haven't got any of these
typedef unsigned long       DWORD;
typedef unsigned char       BYTE;
typedef unsigned short      WORD;
#endif

#define SafeDel(x)		{ if (x) delete x; x = 0; }
#define SafeDelArray(x)	{ if (x) delete [] x; x = 0; }

#ifndef M_PI // assume no math thingies are defined
#define M_PI       3.14159265358979323846
#define M_PI_2     1.57079632679489661923
#define M_PI_4     0.785398163397448309616
#define M_1_PI     0.318309886183790671538
#define M_2_PI     0.636619772367581343076
#define M_2_SQRTPI 1.12837916709551257390
#define M_SQRT2    1.41421356237309504880
#define M_SQRT1_2  0.707106781186547524401
#endif

#include <stdio.h>

struct vec2_t;
struct mat3_t;

void		VEC2_Transform (vec2_t& res, vec2_t& v, mat3_t& t);
mat3_t&		MAT3_Multiply (mat3_t& C, const mat3_t& A, const mat3_t& B);

void		MAT3_Rotate (mat3_t& m, float a);


inline float m_fabs (float f)
{
	int tmp = (*(int *) &f) & 0x7FFFFFFF;
	return *(float *) &tmp;
}




struct vec2_t
{
	union
	{
		struct { float x, y;	};
		float v[2];
	};

	vec2_t ()							{}
	vec2_t (float _x, float _y)			{ x = _x; y = _y; }
	vec2_t (vec2_t *u)					{ memcpy (v, u->v, 2); }


	inline vec2_t operator - (const vec2_t &v)
	{
		return vec2_t (x - v.x, y - v.y);
	}

	inline vec2_t operator + (const vec2_t &v)
	{
		return vec2_t (x + v.x, y + v.y);
	}

	inline vec2_t& operator += (const vec2_t &v)
	{
		x += v.x;
		y += v.y;
		return *this;
	}

	inline vec2_t& operator -= (const vec2_t &v)
	{
		x -= v.x;
		y -= v.y;
		return *this;
	}

	inline vec2_t& operator *= (float scalar)
	{
		x *= scalar;
		y *= scalar;
		return *this;
	}
	inline vec2_t operator - ()
	{
		return vec2_t (-x, -y);
	}

	inline bool operator == (const vec2_t &v)
	{
		return (x == v.x && y == v.y);
	}

	inline bool operator != (const vec2_t &v)
	{
		return (x != v.x || y != v.y);
	}
};

inline vec2_t operator * (const vec2_t &v, float s)
{	return vec2_t (s * v.x, s * v.y);	}

inline vec2_t operator * (float s, const vec2_t &v)
{	return vec2_t (s * v.x, s * v.y);	}



inline float VEC2_Dot (const vec2_t &v1, const vec2_t &v2)
{
	return v1.x*v2.x + v1.y*v2.y;
}

inline vec2_t VEC2_Perp (const vec2_t &v)
{
	return vec2_t (-v.y, v.x);
}

inline vec2_t *VEC2_Normalize (vec2_t &v)
{
	float		lenRcp;

	lenRcp = 1/sqrtf (VEC2_Dot (v, v));

	v.x *= lenRcp;
	v.y *= lenRcp;

	return &v;
}

inline float VEC2_Length (vec2_t &v)
{
	float		lenRcp;

	lenRcp = 1/sqrtf (VEC2_Dot (v, v));

	return 1 / lenRcp;
}


inline float VEC2_Angle (const vec2_t &v)
{
	return atan2f(v.y, v.x);
}


inline float VEC2_Angle (const vec2_t &u, const vec2_t &v)
{
	vec2_t s(u), t(v);

	VEC2_Normalize (s);
	VEC2_Normalize (t);

	return acosf (VEC2_Dot (s, t));
}


struct mat3_t
{
	union
	{
		float v[9];
		float v3x3[3][3];
		struct
		{
			float m11, m12, m13;
			float m21, m22, m23;
			float m31, m32, m33;
		};
	};
};


inline void MAT3_SetIdentity (mat3_t& m)
{
	memset (m.v, 0, sizeof (float) * 9);
	m.m11 = m.m22 = m.m33 = 1;
}



// rotation for 2d
inline void MAT3_Rotate (mat3_t& m, float a)
{
	MAT3_SetIdentity (m);
	float c = cosf (a);
	float s = sinf (a);
	m.m11 = c;  m.m12 = s; m.m13 = 0;
	m.m21 = -s; m.m22 = c; m.m23 = 1;
	m.m31 = 0;  m.m32 = 0; m.m33 = 0;
}


// C = A * B
inline mat3_t& MAT3_Multiply (mat3_t& C, const mat3_t& A, const mat3_t& B)
{
    C.m11 = A.m11 * B.m11 + A.m12 * B.m21 + A.m13 * B.m31;
    C.m21 = A.m21 * B.m11 + A.m22 * B.m21 + A.m23 * B.m31;
    C.m31 = A.m31 * B.m11 + A.m32 * B.m21 + A.m33 * B.m31;
    C.m12 = A.m11 * B.m12 + A.m12 * B.m22 + A.m13 * B.m32;
    C.m22 = A.m21 * B.m12 + A.m22 * B.m22 + A.m23 * B.m32;
    C.m32 = A.m31 * B.m12 + A.m32 * B.m22 + A.m33 * B.m32;
    C.m13 = A.m11 * B.m13 + A.m12 * B.m23 + A.m13 * B.m33;
    C.m23 = A.m21 * B.m13 + A.m22 * B.m23 + A.m23 * B.m33;
    C.m33 = A.m31 * B.m13 + A.m32 * B.m23 + A.m33 * B.m33;
    return C;
}

inline mat3_t operator * (mat3_t &a, const mat3_t &b)
{
	mat3_t r;
	MAT3_Multiply (r, a, b);
	return r;
}


inline void MAT3_Translate (mat3_t& m, float x, float y)
{
	MAT3_SetIdentity (m);
	m.m13 = x;
	m.m23 = y;
}

inline void MAT3_Scale (mat3_t& m, float x, float y)
{
	MAT3_SetIdentity (m);
	m.m11 = x;
	m.m22 = y;
}


// transform 2d vector by 3x3 matrix, assume 'z' == 1
inline void VEC2_Transform (vec2_t& res, vec2_t& v, mat3_t& t)
{
	res.x = v.x * t.m11 + v.y * t.m12 + t.m13;
	res.y = v.x * t.m21 + v.y * t.m22 + t.m23;
	//res.z = v.x * t.m31 + v.y * t.m32 + v.z * t.m33;
}




// 2d planes, lines one might say

struct plane2_t
{
	float		a, b, c;
};

inline void PLANE2_Normalize (plane2_t &plane)
{
	float magnitude;
	magnitude = 1/sqrtf (plane.a * plane.a + plane.b * plane.b);

	plane.a *= magnitude;
	plane.b *= magnitude;
	plane.c *= magnitude;
}

inline float PLANE2_PointSide (plane2_t &plane, vec2_t &p)
{
	return plane.a * p.x + plane.b * p.y + plane.c;
}

// very simple color abstraction
struct color_t
{
	float		r, g, b, a;

	color_t ()						
			{ }
	color_t (float _r, float _g, float _b, float _a)
			{ r = _r; g = _g; b = _b; a = _a; }
};




#endif // CLTYPES_H