#include "stdafx.h"



Area2D::Area2D(C VecI2 &xz, Ptr grid_user){
	state = AREA_UNLOADED;
	T.pos.set(xz.x,  xz.y);
	mat.setPos(Vec(pos.x*World2D.AreaSize(), 0, pos.y*World2D.AreaSize()));
	hm.del();
	mesh.del();
	phys.del();
	actor.del();
	img.del();
}

Area2D::~Area2D(){
	hm.del();
	mesh.del();
	phys.del();
	actor.del();
	img.del();
}


void Area2D::Draw(){
	if (state == AREA_ACTIVE){
		if (mesh.is()){
			switch (Renderer()){
			case RM_PREPARE:{
				mesh.draw(mat);
			}break;
			case RM_BLEND:{
			}break;
			case RM_OVERLAY:{
			}break;
			case RM_SHADOW:{
				//blocks.drawShadow(mat);
			}break;
			case RM_AMBIENT:{

			}break;
			}
		}
	}
}



void Area2D::Save(){
	File f;
	if (f.writeTry(S + "Data/Worlds/" + World2D.worldname + "/" + pos)){
	ChunkWriter cw(f);

	// heightmap
	if (File *f = cw.beginChunk("Heightmap", 0)){ hm.save(*f); }
	if (File *f = cw.beginChunk("Mesh", 0))mesh.save(*f);
	if (File *f = cw.beginChunk("Phys", 0))phys.save(*f);
	if (File *f = cw.beginChunk("PathMesh", 0)){/* m_pm.save(*f); */}
	}
}

void Area2D::Load(){
	File f;
	if (f.readTry(S + "Data/Worlds/" + World2D.worldname + "/" + pos)){
	ChunkReader cr;
	if (cr.read(f)){
	for (; File *f = cr();){
	if (cr.name() == "Heightmap"){
	switch (cr.ver()){
	case 0: if (!hm.load(*f))break;
	}
	}
	else if (cr.name() == "Mesh"){
	mesh.load(*f);
	}
	else if (cr.name() == "PathMesh"){
	//m_pm.load(*f);
	}
	else if (cr.name() == "Phys"){
	phys.load(*f);
	if (phys.is()){
	actor.create(phys).group(AG_TERRAIN); // create actor         from physical body
	}
	}

	}
	}
	}

}

void Area2D::Unload(){
	if (state == AREA_CACHE || state == AREA_ACTIVE){
		state = AREA_UNLOADED;
		hm.del();
		mesh.del();
		phys.del();
		actor.del();
		img.del();

	}
}

void Area2D::BuildMesh() // build 'mesh', 'phys' and 'actor' from 'heightmap'
{

	actor.del();
	
	// build mesh
	hm.build(mesh, 0, 6, true, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);

	// adjust mesh scale and position
	mesh.scaleMove(World2D.AreaSize(), 0);

	// simplify the mesh
	mesh.setBase(); // set software version needed for simplification and later physical body creation
	mesh.simplify(1, 0.05, 1, 0.03, 0.08, PI, true, 0, SIMPLIFY_PLANES); // simplify
	mesh.setRender(); // set rendering version from software version
	mesh.setBox();
	// create physical body

	mesh.delBase(); // mesh software version is no longer needed
}

void Area2D::Build(){
	if (state == AREA_UNLOADED){
		if (!img.is()){
			img.createSoft(World2D.AreaSize() + 1, World2D.AreaSize() + 1, 1, IMAGE_F32); // create wXh image, R8G8B8A8 type, 0 mipmap
			Generate2DHeight(pos, img, S + "Test1");
		}
		hm.create(World2D.AreaSize()+1, 0, &World2D.matA, false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr); // create heightmap
		REPD(x, hm.resolution())
			REPD(y, hm.resolution())
		{
			Flt fx = (x / Flt(hm.resolution()-1));
			Flt	fy = 1 - (y / Flt(hm.resolution()-1));
			Flt	h = img.pixelFLanczos(fx*img.w(), fy*img.h(), true);
			hm.height(x, y, Clamp(h ,- 40.0f, 40.0f ));
		}
		state = AREA_CACHE;
	}
}

void Area2D::Stitch(C Heightmap &right, C Heightmap &down){
	if (state == AREA_CACHE){
		if (right.is())
			REPD(y, right.resolution()){
			hm.height(right.resolution() - 1, y, right.height(0, y));
		}
		if (down.is())
			REPD(x, down.resolution()){
			hm.height(x, 0, down.height(x, down.resolution() - 1));
		}	
		BuildMesh();
	}
}

void Area2D::CreatePhysics(){
	if (state == AREA_CACHE){
		state = AREA_ACTIVE;
		MeshBase base; base.createPhys(mesh); base.simplify(1, 0.05, 1, 1, 1, PI, true, 0, SIMPLIFY_PLANES); // create a 1 MeshBase from all MeshParts in mesh and simplify it again
		phys.createMesh(base); // create physical body from that MeshBase
		actor.create(phys); // create actor         from physical body
		actor.pos(mat.pos);
	}
}

void Area2D::RemovePhysics(){
	if (state == AREA_UNLOADED || state == AREA_CACHE){
		phys.del();
		actor.del();
	}
}


void Area2D::update() {
	if (Time.appTime() > last_update){
		last_update = Time.appTime() + 0.33;
	}
}

