#include <scene/resources/world.h>
#include "direct_lod_multimesh.h"

void LodMultiMesh3D::set_mesh(int id, Ref<Mesh> mesh)
{
	meshes[id] = mesh;
	VisualServer::get_singleton()->instance_set_visible(multimeshes[id].instance, false);
	if (!mesh.is_null())
		VisualServer::get_singleton()->multimesh_set_mesh(multimeshes[id].id, mesh->get_rid());
	else
		VisualServer::get_singleton()->multimesh_set_mesh(multimeshes[id].id, RID());
	VisualServer::get_singleton()->instance_set_visible(multimeshes[id].instance, true);
}

Ref<Mesh> LodMultiMesh3D::get_mesh(int id) const
{
	return meshes[id];
}

void LodMultiMesh3D::set_instance_count(int id, int count)
{
	VisualServer::get_singleton()->multimesh_allocate(multimeshes[id].id,
			count, VS::MULTIMESH_TRANSFORM_3D,
			VS::MultimeshColorFormat(color_format),
			VS::MultimeshCustomDataFormat(custom_data_format));
	multimeshes[id].instance_count = count;
}

int LodMultiMesh3D::get_instance_count(int id) const
{

	return multimeshes[id].instance_count;
}

void LodMultiMesh3D::set_visible_instance_count(int id, int count)
{
	ERR_FAIL_COND(count < -1);
	VisualServer::get_singleton()->multimesh_set_visible_instances(multimeshes[id].id, count);
	multimeshes[id].visible_instance_count = count;
}

int LodMultiMesh3D::get_visible_instance_count(int id) const
{

	return multimeshes[id].visible_instance_count;
}

void LodMultiMesh3D::set_instance_transform(int id, int instance, const Transform &xform) {

	VisualServer::get_singleton()->multimesh_instance_set_transform(multimeshes[id].id,
			instance, xform);
}

LodMultiMesh3D::LodMultiMesh3D()
{
	custom_data_format = CUSTOM_DATA_8BIT;
	color_format = COLOR_FLOAT;
}

LodMultiMesh3D::~LodMultiMesh3D()
{
	List<struct multimesh_data>::Element *e =
		multimeshes.front();
	while(e) {
		const struct multimesh_data &md = e->get();
		VisualServer::get_singleton()->instance_set_scenario(md.instance, RID());
		VisualServer::get_singleton()->free(md.id);
		e = e->next();
	}
}
void LodMultiMesh3D::add_mesh(Ref<Mesh> mesh)
{
	struct multimesh_data md;
	md.id = VisualServer::get_singleton()->multimesh_create();
	md.instance = VisualServer::get_singleton()->instance_create();
	if (mesh.ptr())
		VisualServer::get_singleton()->multimesh_set_mesh(md.id, mesh->get_rid());
	else
		VisualServer::get_singleton()->multimesh_set_mesh(md.id, RID());
	VisualServer::get_singleton()->instance_set_base(md.instance, md.id);
	md.instance_count = 0;
	md.visible_instance_count = -1;
	md.lod_decimator = 1;
	VisualServer::get_singleton()->instance_set_visible(md.instance, true);
	multimeshes.push_back(md);
}

void LodMultiMesh3D::set_instance_color(int id, int instance, const Color &color) {

	VisualServer::get_singleton()->multimesh_instance_set_color(
			multimeshes[id].id, instance, color);
}
Color LodMultiMesh3D::get_instance_color(int id, int instance) const
{

	return VisualServer::get_singleton()->multimesh_instance_get_color(multimeshes[id].id, instance);
}

void LodMultiMesh3D::hide()
{
	List<struct multimesh_data>::Element *e =
		multimeshes.front();
	while(e) {
		const struct multimesh_data &md = e->get();
		VS::get_singleton()->instance_set_visible(md.instance, false);
		e = e->next();
	}
	visible = false;
}

void LodMultiMesh3D::show()
{
	List<struct multimesh_data>::Element *e =
		multimeshes.front();
	while(e) {
		const struct multimesh_data &md = e->get();
		VS::get_singleton()->instance_set_visible(md.instance, true);
		e = e->next();
	}
	visible = true;
}
bool LodMultiMesh3D::is_visible() const
{
	return visible;
}

void LodMultiMesh3D::set_global_transform(const Transform &xform)
{
	xf = xform;
	List<struct multimesh_data>::Element *e =
		multimeshes.front();
	while(e) {
		const struct multimesh_data &md = e->get();
		VisualServer::get_singleton()->instance_set_transform(md.instance, xf);
		e = e->next();
	}
}

Transform LodMultiMesh3D::get_global_transform() const
{
	return xf;
}

void LodMultiMesh3D::set_world(const World *world)
{
	List<struct multimesh_data>::Element *e =
		multimeshes.front();
	RID r;
	if (world)
		r = world->get_scenario();
	while(e) {
		const struct multimesh_data &md = e->get();
		VisualServer::get_singleton()->instance_set_scenario(md.instance, r);
		e = e->next();
	}
}

AABB LodMultiMesh3D::get_aabb(int id) const
{
	return VisualServer::get_singleton()->multimesh_get_aabb(multimeshes[id].id);
}

Vector3 LodMultiMesh3D::get_center() const
{
	AABB r;
	int i;
	for (i = 0; i < multimeshes.size(); i++)
		r.merge_with(get_aabb(i));
	return r.position + r.size *0.5f + get_global_transform().origin;
}

