#include "Building.h"
#include "CodingUtils.h"

using namespace core;

Building::Building(float hue, core::vector3df& _size, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id)
	: scene::ISceneNode(parent, mgr, id)
	, m_size(_size)
	, m_hue(hue)
{
	//Define material properties
	m_material.Wireframe = false;
	m_material.FogEnable = false;
	m_material.Lighting = false;
	m_material.setTexture(0, SceneManager->getVideoDriver()->getTexture("./assets/windows.jpg"));
	m_material.setFlag(video::EMF_ANISOTROPIC_FILTER, true);
	

	//
	//
	// The cube will be centered in the Center of the bottom
	// rectangle. Where the "C" is in the following ascii cube
	//
	//
	//			4-----------5
	//		   /|          /|
	//		  / |         / |
	//		 /  |        /  |  m_size.Y
	//		7-----------6   |
	//		|   |       |   |
	//		|   0-------|---1
	//		|  /        |  /
	//		| /     C   | /   m_size.Z
	//		|/          |/
	//		3-----------2
	//
	//         m_size.X
	//
	//  ========================
	// ===== ASCII ART FTW! =====
	//  ========================
	//
	// Numbers represent the vertices of the cube.
	//
	// Also, the coordinate system used for this model space is:
	//
	//
	//          Y
	//			|
	//			|
	//			0------X
	//		   /
	//        /
	//       Z
	//

	//Geometry
	const float xHalf = m_size.X / 2;
	const float zHalf = m_size.Z / 2;
	const float y = m_size.Y;

	//Vertex positions
	const vector3df positions[] = {
		//Lower
		vector3df(-xHalf, 0, -zHalf),	//0
		vector3df(xHalf, 0, -zHalf),	//1
		vector3df(xHalf, 0, zHalf),		//2
		vector3df(-xHalf, 0, zHalf),	//3
		//Upper
		vector3df(-xHalf, y, -zHalf),	//4
		vector3df(xHalf, y, -zHalf),	//5
		vector3df(xHalf, y, zHalf),		//6
		vector3df(-xHalf, y, zHalf),	//7
	};

	//Add faces
	unsigned int vertexIndex = 0;
	unsigned int indexIndex = 0;
	addFace(vertexIndex, indexIndex, positions, vector3df(0,0,1), 7, 6, 2, 3);
	addFace(vertexIndex, indexIndex, positions, vector3df(1,0,0), 6, 5, 1, 2);
	addFace(vertexIndex, indexIndex, positions, vector3df(0,0,-1), 5, 4, 0, 1);
	addFace(vertexIndex, indexIndex, positions, vector3df(-1,0,0), 4, 7, 3, 0);
	addFace(vertexIndex, indexIndex, positions, vector3df(0,1,0), 7, 4, 5, 6);

	//Disable UV on top face
	m_vertices[vertexIndex-1].TCoords.X = m_vertices[vertexIndex-1].TCoords.Y = 0;
	m_vertices[vertexIndex-2].TCoords.X = m_vertices[vertexIndex-2].TCoords.Y = 0;
	m_vertices[vertexIndex-3].TCoords.X = m_vertices[vertexIndex-3].TCoords.Y = 0;
	m_vertices[vertexIndex-4].TCoords.X = m_vertices[vertexIndex-4].TCoords.Y = 0;

	//Initialize bounding box
	m_box.reset(m_vertices[0].Pos);
	for (s32 i=1; i<VERTEX_COUNT; ++i) {
		m_box.addInternalPoint(m_vertices[i].Pos);
	}

}

Building::~Building()
{
}

void Building::addFace(unsigned& vertexIndex, unsigned& indexIndex, 
	const vector3df* positions, const core::vector3df& normal,
	unsigned v1, unsigned v2, unsigned v3, unsigned v4)
{
	video::SColorf vertexColorRGB;
	const video::SColorHSL vertexColorHSL(m_hue,30,60);
	vertexColorHSL.toRGB(vertexColorRGB);
	video::SColor vertexColor = vertexColorRGB.toSColor();

	//Indices
	m_indices[indexIndex++] = vertexIndex+1;	//Triangle 1
	m_indices[indexIndex++] = vertexIndex;
	m_indices[indexIndex++] = vertexIndex+2;

	m_indices[indexIndex++] = vertexIndex+2;	//Triangle 2
	m_indices[indexIndex++] = vertexIndex;
	m_indices[indexIndex++] = vertexIndex+3;

	//Vertices
	const float maxU = m_size.X / 64.f;
	const float maxV = m_size.Y / 64.f;
	m_vertices[vertexIndex++] = video::S3DVertex(
		positions[v1].X, positions[v1].Y, positions[v1].Z,
		normal.X, normal.Y, normal.Z,
		vertexColor,0,0);
	m_vertices[vertexIndex++] = video::S3DVertex(
		positions[v2].X, positions[v2].Y, positions[v2].Z,
		normal.X, normal.Y, normal.Z,
		vertexColor,maxU,0);
	m_vertices[vertexIndex++] = video::S3DVertex(
		positions[v3].X, positions[v3].Y, positions[v3].Z,
		normal.X, normal.Y, normal.Z,
		vertexColor,maxU,maxV);
	m_vertices[vertexIndex++] = video::S3DVertex(
		positions[v4].X, positions[v4].Y, positions[v4].Z,
		normal.X, normal.Y, normal.Z,
		vertexColor,0,maxV);
}

void Building::OnRegisterSceneNode()
{
	if (IsVisible)
		SceneManager->registerNodeForRendering(this);

	ISceneNode::OnRegisterSceneNode();
}

void Building::render()
{
	video::IVideoDriver* driver = SceneManager->getVideoDriver();

	driver->setMaterial(m_material);
	driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
	driver->drawVertexPrimitiveList(&m_vertices[0], VERTEX_COUNT, &m_indices[0], PRIMITIVE_COUNT,
		video::EVT_STANDARD, scene::EPT_TRIANGLES, video::EIT_16BIT);
}
