
#include <cstdlib>
#include <Spectre/Math/Math.h>

namespace math {

	float rand(float min, float max) {

		float r = ((float) ::rand()) / RAND_MAX;
		return ((max - min) * r) + min;
	}

	float deg2rad(float deg) {

		return deg * 3.141592654f / 180.0f;
	}

	unsigned int nextPowerOfTwo(unsigned int value) {

		if (value == 0) {
			return 1;
		}

		unsigned int exp = static_cast<unsigned int>(::ceil(log2(value)));
		return ::pow(2.0f, exp);
	}

	Matrix4f orthoProjection(float left, float right,
		float bottom, float top,
		float zNear, float zFar) {

		float	rl = (right - left), 
			tb = (top - bottom),
			fn = (zFar - zNear),
			rl2 = 2.0f / rl,
			tb2 = 2.0f / tb,
			fn2 = 2.0f / fn,
			x = (right + left) / rl,
			y = (top + bottom) / tb,
			z = (zFar + zNear) / fn;

		return Matrix4f(
			rl2 , 0.0f,  0.0f, -x,
			0.0f, tb2 ,  0.0f, -y,
			0.0f, 0.0f,  -fn2, -z,
			0.0f, 0.0f,  0.0f, 1.0f
		);
	}

	Matrix4f rotation(float theta) {

		float r = deg2rad(theta);
		float s = std::sin(r);
		float c = std::cos(r);

		return Matrix4f(
			   c,   -s, 0.0f, 0.0f,
			   s,    c, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);
	}

	Matrix4f translate(const Vector2f& v) {

		return Matrix4f(
			1.0f, 0.0f, 0.0f, v.x,
			0.0f, 1.0f, 0.0f, v.y,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);

	}

	Matrix4f scale(const Vector2f& f) {

		return Matrix4f(
			f.x , 0.0f, 0.0f, 0.0f,
			0.0f, f.y , 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 0.0f, 1.0f);
	}

	Vector3f getTranslate(const Matrix4f matrix) {

		return Vector3f(matrix.e[12], matrix.e[13], matrix.e[14]);
	}


	Vector3f getUpVector(const Matrix4f matrix) {

		return Vector3f(matrix.e[4], matrix.e[5], matrix.e[6]);
	}

	Vector3f getForwardVector(const Matrix4f matrix) {

		return Vector3f(matrix.e[8], matrix.e[9], matrix.e[10]);
	}
};