////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001.
// -------------------------------------------------------------------------
//  File name:   TerrainHoleTool.cpp
//  Version:     v1.00
//  Created:     11/1/2002 by Timur.
//  Compilers:   Visual C++ 6.0
//  Description: Terrain Modification Tool implementation.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#include "StdAfx.h"
#include "TerrainHoleTool.h"
#include "Viewport.h"
#include "TerrainHolePanel.h"
#include "Heightmap.h"
#include "Objects\DisplayContext.h"

#include "I3DEngine.h"

//////////////////////////////////////////////////////////////////////////
IMPLEMENT_DYNCREATE(CTerrainHoleTool,CEditTool)

//////////////////////////////////////////////////////////////////////////
CTerrainHoleTool::CTerrainHoleTool()
{
	m_panelId = 0;
	m_panel = 0;
	
	m_pointerPos(0,0,0);

	m_bMakeHole = true;
	m_brushRadius = 0.5;
	GetIEditor()->ClearSelection();
}

//////////////////////////////////////////////////////////////////////////
CTerrainHoleTool::~CTerrainHoleTool()
{
	m_pointerPos(0,0,0);
	if (GetIEditor()->IsUndoRecording())
		GetIEditor()->CancelUndo();
}

//////////////////////////////////////////////////////////////////////////
void CTerrainHoleTool::BeginEditParams( IEditor *ie,int flags )
{
	m_ie = ie;
	if (!m_panelId)
	{
		m_panel = new CTerrainHolePanel(this,AfxGetMainWnd());
		m_panelId = m_ie->AddRollUpPage( ROLLUP_TERRAIN,"Modify Terrain",m_panel );
		AfxGetMainWnd()->SetFocus();
	}
}

//////////////////////////////////////////////////////////////////////////
void CTerrainHoleTool::EndEditParams()
{
	if (m_panelId)
	{
		m_ie->RemoveRollUpPage(ROLLUP_TERRAIN,m_panelId);
		m_panelId = 0;
		m_panel = 0;
	}
}

//////////////////////////////////////////////////////////////////////////
bool CTerrainHoleTool::MouseCallback( CViewport *view,EMouseEvent event,CPoint &point,int flags )
{
	m_pointerPos = view->ViewToWorld( point,0,true );
	if (event == eMouseLDown || (event == eMouseMove && (flags&MK_LBUTTON)))
	{
		/*
		if (flags&MK_CONTROL)
		{
			bool bMakeHole = m_bMakeHole;
			m_bMakeHole = false;
			Modify();
			m_bMakeHole = bMakeHole;
		}
		else
		{
			Modify();
		}
		*/
		if (!GetIEditor()->IsUndoRecording())
			GetIEditor()->BeginUndo();
		Modify();
	}
	else
	{
		if (GetIEditor()->IsUndoRecording())
			GetIEditor()->AcceptUndo( "Terrain Hole" );
	}

	return true;
}

//////////////////////////////////////////////////////////////////////////
void CTerrainHoleTool::Display( DisplayContext &dc )
{
	if (dc.flags & DISPLAY_2D)
		return;

	CHeightmap *heightmap = m_ie->GetHeightmap();
	int unitSize = heightmap->GetUnitSize();

	dc.SetColor( 0,1,0,1 );
	dc.DrawTerrainCircle( m_pointerPos,m_brushRadius,0.2f );

	float fx1 = (m_pointerPos.y - m_brushRadius)/unitSize;
	float fy1 = (m_pointerPos.x - m_brushRadius)/unitSize;
	float fx2 = (m_pointerPos.y + m_brushRadius)/unitSize;
	float fy2 = (m_pointerPos.x + m_brushRadius)/unitSize;


	int x1 = MAX(fx1,0);
	int y1 = MAX(fy1,0);
	int x2 = MIN(fx2,heightmap->GetWidth()-1);
	int y2 = MIN(fy2,heightmap->GetHeight()-1);

	if (m_bMakeHole)
		dc.SetColor( 1,0,0,1 );
	else
		dc.SetColor( 0,0,1,1 );
	Vec3 p1,p2,p3,p4;
	// Make hole.
	for (int x = x1; x <= x2; x++)
	{
		for (int y = y1; y <= y2; y++)
		{
			p1.x = y*unitSize;
			p1.y = x*unitSize;
			
			p2.x = y*unitSize+unitSize;
			p2.y = x*unitSize;
			
			p3.x = y*unitSize+unitSize;
			p3.y = x*unitSize+unitSize;
			
			p4.x = y*unitSize;
			p4.y = x*unitSize+unitSize;

			p1.z = dc.engine->GetTerrainElevation(p1.x,p1.y)+0.2f;
			p2.z = dc.engine->GetTerrainElevation(p2.x,p2.y)+0.2f;
			p3.z = dc.engine->GetTerrainElevation(p3.x,p3.y)+0.2f;
			p4.z = dc.engine->GetTerrainElevation(p4.x,p4.y)+0.2f;
			dc.DrawLine( p1,p2 );
			dc.DrawLine( p2,p3 );
			dc.DrawLine( p3,p4 );
			dc.DrawLine( p1,p4 );
		}
	}
}

//////////////////////////////////////////////////////////////////////////
bool CTerrainHoleTool::OnKeyDown( CViewport *view,uint nChar,uint nRepCnt,uint nFlags )
{
	bool bProcessed = false;
	if (nChar == VK_ADD)
	{
		if (m_brushRadius < 100)
			m_brushRadius += 0.5f;
		bProcessed = true;
	}
	if (nChar == VK_SUBTRACT)
	{
		if (m_brushRadius > 0.5f)
			m_brushRadius -= 0.5f;
		bProcessed = true;
	}
	if (nChar == VK_CONTROL && !(nFlags&(1<<14))) // only once (no repeat).
	{
		m_bMakeHole = !m_bMakeHole;
		m_panel->SetMakeHole(m_bMakeHole);
	}
	if (bProcessed && m_panel)
	{
		m_panel->SetRadius(m_brushRadius);
	}
	return bProcessed;
}

bool CTerrainHoleTool::OnKeyUp( CViewport *view,uint nChar,uint nRepCnt,uint nFlags )
{
	if (nChar == VK_CONTROL)
	{
		m_bMakeHole = !m_bMakeHole;
		m_panel->SetMakeHole(m_bMakeHole);
	}
	return false;
}

//////////////////////////////////////////////////////////////////////////
void CTerrainHoleTool::Modify()
{
	CHeightmap *heightmap = m_ie->GetHeightmap();
	int unitSize = heightmap->GetUnitSize();

	float fx1 = (m_pointerPos.y - m_brushRadius)/unitSize;
	float fy1 = (m_pointerPos.x - m_brushRadius)/unitSize;
	float fx2 = (m_pointerPos.y + m_brushRadius)/unitSize;
	float fy2 = (m_pointerPos.x + m_brushRadius)/unitSize;

	int x1 = MAX(fx1,0);
	int y1 = MAX(fy1,0);
	int x2 = MIN(fx2,heightmap->GetWidth()-1);
	int y2 = MIN(fy2,heightmap->GetHeight()-1);

	if((x2-x1)>=0 && (y2-y1)>=0)
		heightmap->MakeHole( x1,y1,x2-x1,y2-y1,m_bMakeHole );
}
