import
	coneneko.all,
	std.math,
	std.stdio,
	opengl,
	openglu;

void main()
{
	scope wnd = new Window(); // openglの初期化が必要
	try
	{
		test1();
		test2();
		test3();
		test4();
	}
	catch (Exception e) writefln(e.toString);
}

unittest
{
	assert(
		matrix(
			0, 1, 2, 3,
			4, 5, 6, 7,
			8, 9, 10, 11,
			12, 13, 14, 15
		) == matrix(
			0, 1, 2, 3,
			4, 5, 6, 7,
			8, 9, 10, 11,
			12, 13, 14, 15
		)
	);
}

bool eq(float a, float b)
{
	if (fdim(a, b) < 0.0001) return true;
	writefln("%f != %f,  %f", a, b, fdim(a, b));
	return false;
}

bool eq(Matrix a, Matrix b)
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (fdim(a.m[i][j], b.m[i][j]) > 0.0001)
			{
				writefln("%f ", fdim(a.m[i][j], b.m[i][j]));
				writefln("%f != %f", a.m[i][j], b.m[i][j]);
				a.print();
				b.print();
				return false;
			}
		}
	}
	return true;
}

void test1()
{
	Matrix m;
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	glTranslatef(1, 0, 0);
	glRotatef(90, 1, 0, 0);
	glGetFloatv(GL_MODELVIEW_MATRIX, cast(float*)&m);
	//m.print();
	
	Matrix m2 = Matrix.identity;
	m2 *= Matrix.translation(1, 0, 0);
	m2 *= Matrix.rotationX(PI_2);
	//m2.print();
	
	assert(eq(m, m2));
}

void test2()
{
	float[16] array;
	for (int i = 0; i < 16; i++) array[i] = i;
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	glLoadMatrixf(array.ptr);
	Matrix m;
	glGetFloatv(GL_MODELVIEW_MATRIX, cast(float*)&m);
	//m.print();
	// 0123
	// 4567
	// 89ab
	// cdef
}

void test3()
{
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	glOrtho(0, 640, 0, 480, -320, 320);
	Matrix m;
	glGetFloatv(GL_MODELVIEW_MATRIX, cast(float*)&m);
	auto m2 = Matrix.ortho(0, 640, 0, 480, -320, 320);
	//m.print();
	//m2.print();
	assert(eq(m, m2));
}

void test4()
{
	Matrix m = Matrix.perspectiveFov(PI / 8.0, 640.0 / 480.0, 100.0, 1000.0);
	auto v = Vector(0, 0, -1000, 1) * m;
	v /= v.w;
	//v.print();
	assert(eq(v.z, 1.0));
	
	auto v2 = Vector(0, 0, -1, 1) * m;
	v2 /= v2.w;
	//v2.print();
	assert(eq(v2.z, -1.0));
	
	glMatrixMode(GL_MODELVIEW_MATRIX);
	glLoadIdentity();
	gluPerspective(180.0 / 8.0, 640.0 / 480.0, 100.0, 1000.0);
	Matrix m2;
	glGetFloatv(GL_MODELVIEW_MATRIX, cast(float*)&m2);
	//m.print();
	//m2.print();
	assert(eq(m, m2));
}
