#include "bvh1.h"

using namespace VRUT;

float BVH1::GetSurafceArea(const BVHNode & node)
{
	float x = node.max.v[3] - node.min.v[3];
	float y = node.max.v[2] - node.min.v[2];
	float z = node.max.v[1] - node.min.v[1];
	return 2.0f * (x*y + x*z + y*z);
};

float BVH1::GetCost(int index)
{
	if (nodes[index].offset < 0)
	{ 
		// Interior node 
		BVHNode & left = nodes[nodes[index].t];
		BVHNode & right = nodes[nodes[index].t + 1];
		float sa = GetSurafceArea(nodes[index]);
		float leftCost = sa != 0.0f ? GetSurafceArea(left) / sa * GetCost(nodes[index].t) : 0.0f;
		float rightCost = sa != 0.0f ? GetSurafceArea(right) / sa * GetCost(nodes[index].t+1) : 0.0f;
		return CT + leftCost + rightCost; 
	} 
	else 
	{ 
		// Leaf node
		return CI * nodes[index].t; 
	}
}

BVH1::BVH1() : nodes(nullptr), numberOfNodes(0)
#if !USE_TRIANGLEDATA
	, triangles(NULL)
#endif
{}

BVH1::~BVH1()
{
	Clear();
}

void BVH1::Clear()
{
	if (numberOfNodes != 0)
	{
		VrutAlignedFree(nodes);
		nodes = nullptr;
		numberOfNodes = 0;
	}
}

const BVH1::BVHNode * BVH1::GetNodes()
{
	return nodes;
}

float BVH1::GetCost()
{
	return numberOfNodes > 0 ? GetCost(0) : 0;
}

void BVH1::GetVerticesAt(const int index, Vector3 & v1, Vector3 & v2, Vector3 & v3) const
{
#if USE_TRIANGLEDATA
	v1 = triangles[index].v1;
	v2 = triangles[index].v2;
	v3 = triangles[index].v3;
#else
	v1 = trianglesCol[index].v2 + trianglesCol[index].e1;
	v2 = trianglesCol[index].v2;
	v3 = trianglesCol[index].v2 + trianglesCol[index].e2;
#endif
}

void BVH1::GetTextureCoordsAt(const int index, Vector2 *& texCoords1, Vector2 *& texCoords2, Vector2 *& texCoords3) const
{
#if USE_TRIANGLEDATA
	texCoords1 = const_cast<Vector2*>(&triangles[index].texCoord1);
	texCoords2 = const_cast<Vector2*>(&triangles[index].texCoord2);
	texCoords3 = const_cast<Vector2*>(&triangles[index].texCoord3);
#else
	texCoords1 = const_cast<Vector2*>(&trianglesTex[index].texCoord1);
	texCoords2 = const_cast<Vector2*>(&trianglesTex[index].texCoord2);
	texCoords3 = const_cast<Vector2*>(&trianglesTex[index].texCoord3);
#endif
}

#if !USE_TRIANGLEDATA
void BVH1::GetNormalAt(const int index, const float u, const float v, Vector3 &normal) const
{
	if ((trianglesNorm[index].n1.x == 0) && (trianglesNorm[index].n1.y == 0) && (trianglesNorm[index].n1.z == 0))
		normal = trianglesNorm[index].n2;
	else
		normal = (u * trianglesNorm[index].n1 + (1 - u - v) * trianglesNorm[index].n2 + v * trianglesNorm[index].n3).Normalize();
}
#endif
