
#include "Cube.h"
#include "Matrix4x4.h"
#include "Vec4.h"
#include "Point2.h"
#include "PalettizedFrameBuffer.h"
#include <cmath>

namespace
{
	static const float PiToRadians = 3.1415926535897932384626f / 180.0f;
}


void Cube::Update(float deltaTime)
{
	// Live++: change the cube rotation on the different axes
	m_angleX = fmodf(m_angleX + deltaTime * 1.1f * m_speed * PiToRadians, 360.0f);
	m_angleY = fmodf(m_angleY + deltaTime * 1.2f * m_speed * PiToRadians, 360.0f);
	m_angleZ = fmodf(m_angleZ + deltaTime * 1.3f * m_speed * PiToRadians, 360.0f);
}


void Cube::Render(PalettizedFrameBuffer* frameBuffer, int x, int y)
{
	// Live++: change the size of the cube
	const float scale = 100.0f;

	Matrix4x4 matX;
	matX.RotateX(m_angleX);

	Matrix4x4 matY;
	matY.RotateY(m_angleY);

	Matrix4x4 matZ;
	matZ.RotateZ(m_angleZ);

	Matrix4x4 matScale;
	matScale.Scale(scale);

	Matrix4x4 transformation;
	transformation.Identity();
	transformation.Multiply(matX);
	transformation.Multiply(matY);
	transformation.Multiply(matZ);
	transformation.Multiply(matScale);

	const Vec4 vertices[8u] =
	{
		{ -1.0f, -1.0f, -1.0f, 0.0f },
		{ -1.0f, -1.0f, +1.0f, 0.0f },
		{ -1.0f, +1.0f, -1.0f, 0.0f },
		{ -1.0f, +1.0f, +1.0f, 0.0f },
		{ +1.0f, -1.0f, -1.0f, 0.0f },
		{ +1.0f, -1.0f, +1.0f, 0.0f },
		{ +1.0f, +1.0f, -1.0f, 0.0f },
		{ +1.0f, +1.0f, +1.0f, 0.0f }
	};

	Vec4 transformedVertices[8u] = {};
	Point2 projectedVertices[8u] = {};

	for (unsigned int i = 0u; i < 8u; ++i)
	{
		transformedVertices[i] = transformation.Transform(vertices[i]);

		// Live++: change the projection to see how that affects the rendering of the cube
		projectedVertices[i].x = int(transformedVertices[i].x * scale / (transformedVertices[i].z / 15.0f + 100.0f) + x);
		projectedVertices[i].y = int(transformedVertices[i].y * scale / (transformedVertices[i].z / 15.0f + 100.0f) + y);
	}

	frameBuffer->DrawLine(projectedVertices[0], projectedVertices[1]);
	frameBuffer->DrawLine(projectedVertices[1], projectedVertices[3]);
	frameBuffer->DrawLine(projectedVertices[3], projectedVertices[2]);
	frameBuffer->DrawLine(projectedVertices[2], projectedVertices[0]);

	frameBuffer->DrawLine(projectedVertices[4], projectedVertices[5]);
	frameBuffer->DrawLine(projectedVertices[5], projectedVertices[7]);
	frameBuffer->DrawLine(projectedVertices[7], projectedVertices[6]);
	frameBuffer->DrawLine(projectedVertices[6], projectedVertices[4]);

	frameBuffer->DrawLine(projectedVertices[0], projectedVertices[4]);
	frameBuffer->DrawLine(projectedVertices[1], projectedVertices[5]);
	frameBuffer->DrawLine(projectedVertices[2], projectedVertices[6]);
	frameBuffer->DrawLine(projectedVertices[3], projectedVertices[7]);
}
