/* Copyright (c) 2002-2012 Croteam Ltd. 
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation


This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */

// DlgTerrainProperties.cpp : implementation file
//

#include "stdafx.h"
#include "WorldEditor.h"
#include "DlgTerrainProperties.h"

#ifdef _DEBUG
#undef new
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

static INDEX _iShadowMapShift=0;
static INDEX _iShadingMapShift=1;
static PIX _pixGlobalPretenderTextureWidth=64;

/////////////////////////////////////////////////////////////////////////////
// CDlgTerrainProperties dialog


CDlgTerrainProperties::CDlgTerrainProperties(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgTerrainProperties::IDD, pParent)
{
	//{{AFX_DATA_INIT(CDlgTerrainProperties)
	m_strHeightmapSize = _T("");
	m_strShadowMapSize = _T("");
	m_strTerrainPretender = _T("");
	m_strTilePretender = _T("");
	m_fTerrainLength = 0.0f;
	m_fTerrainHeight = 0.0f;
	m_fTerrainWidth = 0.0f;
	m_fLODSwitch = 0.0f;
	m_strShadingMapSize = _T("");
	m_strMemoryConsumption = _T("");
	m_strLayerMemory = _T("");
	m_strEdgeMap = _T("");
	//}}AFX_DATA_INIT
  
  CTerrain *ptrTerrain=GetTerrain();
  if(ptrTerrain==NULL) return;

  _iShadowMapShift=ptrTerrain->tr_iShadowMapSizeAspect;
  _iShadingMapShift=ptrTerrain->tr_iShadingMapSizeAspect;
  _pixGlobalPretenderTextureWidth=ptrTerrain->tr_pixTopMapWidth;
}


void CDlgTerrainProperties::DoDataExchange(CDataExchange* pDX)
{
  CTString strTemp;

  CTerrain *ptrTerrain=GetTerrain();
  if(ptrTerrain==NULL) return;

  // if dialog is recieving data
  if( pDX->m_bSaveAndValidate == FALSE && IsWindow(m_ctrlShadowMapSlider))
  {
    m_fTerrainWidth =ptrTerrain->tr_vTerrainSize(1);
    m_fTerrainHeight=ptrTerrain->tr_vTerrainSize(2);
    m_fTerrainLength=ptrTerrain->tr_vTerrainSize(3);

    INDEX iItemW=m_ctrlHeightMapWidth.GetCurSel();
    PIX pixW=m_ctrlHeightMapWidth.GetItemData( iItemW);

    INDEX iItemH=m_ctrlHeightMapHeight.GetCurSel();
    PIX pixH=m_ctrlHeightMapHeight.GetItemData( iItemH);
    INDEX iMemHeightMap=pixW*pixH*sizeof(UWORD)/1024;
    strTemp.PrintF("Height map size: %d x %d, Memory: %d KB", pixW, pixH, iMemHeightMap);
    m_strHeightmapSize=strTemp;

    PrepareGlobalPretenderCombo();

    INDEX iShadowMapShift=m_ctrlShadowMapSlider.GetPos();
    PIX pixSwW=Clamp(PIX((pixW-1)*pow(2.0f,iShadowMapShift)),PIX(4),PIX(2048));
    PIX pixSwH=Clamp(PIX((pixH-1)*pow(2.0f,iShadowMapShift)),PIX(4),PIX(2048));
    INDEX iMemShadowMap=pixSwW*pixSwH*sizeof(COLOR)/1024*1.333f;
    strTemp.PrintF("Size: %d x %d, Memory: %d KB", pixSwW, pixSwH, iMemShadowMap);
    m_strShadowMapSize=strTemp;

    INDEX iShadingMapShift=10-m_ctrlShadingMapSlider.GetPos();
    PIX pixSdW=Clamp(PIX(pixSwW*pow(2.0f,-iShadingMapShift)),PIX(4),PIX(pixSwW));
    PIX pixSdH=Clamp(PIX(pixSwH*pow(2.0f,-iShadingMapShift)),PIX(4),PIX(pixSwH));
    INDEX iMemShadingMap=pixSdW*pixSdW*sizeof(UWORD)/1024;
    strTemp.PrintF("Size: %d x %d, Memory: %d KB", pixSdW, pixSdH, iMemShadingMap);
    m_strShadingMapSize=strTemp;

    INDEX iGlobalPretender=m_ctrlGlobalPretenderTexture.GetCurSel();
    INDEX pixSize=m_ctrlGlobalPretenderTexture.GetItemData(iGlobalPretender);
    INDEX iMemTerrainPretender=pixSize*pixSize*sizeof(UWORD)/1024*1.333f;
    strTemp.PrintF("Size: %d x %d, Memory: %d KB", pixSize, pixSize, iMemTerrainPretender);
    m_strTerrainPretender=strTemp;

    INDEX iTlp=m_ctrlTilePretender.GetCurSel();
    PIX pixTlpW=m_ctrlTilePretender.GetItemData( iTlp);
    INDEX iMemTilePretender=pixTlpW*pixTlpW*sizeof(UWORD)/1024*1.333f;
    strTemp.PrintF("Tile pretender texture (%d KB)", iMemTilePretender);
    m_strTilePretender=strTemp;

    INDEX ctLayers=ptrTerrain->tr_atlLayers.Count();
    INDEX iMemLayers=(pixW*pixH*ctLayers)/1024;
    strTemp.PrintF("Layer memory consumption (%d layers): %d KB", ctLayers, iMemLayers);
    m_strLayerMemory=strTemp;

    INDEX iMemEdgeMap=(pixW*pixH)/1024;
    strTemp.PrintF("Edge map memory consumption: %d KB", iMemEdgeMap);
    m_strEdgeMap=strTemp;

    strTemp.PrintF("Terrain total uncompressed static data memory consumption (without tile pretender textures and geometry): %d KB",
                    iMemHeightMap+iMemShadowMap+iMemShadingMap+iMemTerrainPretender+iMemLayers+iMemEdgeMap);
    m_strMemoryConsumption=strTemp;
    
    m_fLODSwitch=ptrTerrain->tr_fDistFactor;
  }

	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CDlgTerrainProperties)
	DDX_Control(pDX, IDC_GLOBAL_PRETENDER, m_ctrlGlobalPretenderTexture);
	DDX_Control(pDX, IDC_TILE_PRETENDER, m_ctrlTilePretender);
	DDX_Control(pDX, IDC_SHADING_MAP, m_ctrlShadingMapSlider);
	DDX_Control(pDX, IDC_TERRAIN_QUADS_PER_TILE, m_ctrlQuadsPerTile);
	DDX_Control(pDX, IDC_TERRAIN_HM_WIDTH, m_ctrlHeightMapWidth);
	DDX_Control(pDX, IDC_TERRAIN_HM_HEIGHT, m_ctrlHeightMapHeight);
	DDX_Control(pDX, IDC_SHADOW_MAP, m_ctrlShadowMapSlider);
	DDX_Text(pDX, IDC_HEIGHTIMAP_SIZE_T, m_strHeightmapSize);
	DDX_Text(pDX, IDC_SHADOW_MAP_T, m_strShadowMapSize);
	DDX_Text(pDX, IDC_TERRAIN_PRETENDER_T, m_strTerrainPretender);
	DDX_Text(pDX, IDC_TILE_PRETENDER_T, m_strTilePretender);
	DDX_Text(pDX, IDC_TERRAIN_LENGTH, m_fTerrainLength);
	DDV_MinMaxFloat(pDX, m_fTerrainLength, 0.f, 1.e+007f);
	DDX_Text(pDX, IDC_TERRAIN_HEIGHT, m_fTerrainHeight);
	DDV_MinMaxFloat(pDX, m_fTerrainHeight, 0.f, 1.e+007f);
	DDX_Text(pDX, IDC_TERRAIN_WIDTH, m_fTerrainWidth);
	DDV_MinMaxFloat(pDX, m_fTerrainWidth, 0.f, 1.e+007f);
	DDX_Text(pDX, IDC_TERRAIN_LOD_SWITCH, m_fLODSwitch);
	DDV_MinMaxFloat(pDX, m_fLODSwitch, 0.f, 1.e+007f);
	DDX_Text(pDX, IDC_SHADING_MAP_T, m_strShadingMapSize);
	DDX_Text(pDX, IDC_TERRAIN_MEMORY_T, m_strMemoryConsumption);
	DDX_Text(pDX, IDC_LAYER_MEMORY_T, m_strLayerMemory);
	DDX_Text(pDX, IDC_TERRAIN_EDGE_MEMORY_T, m_strEdgeMap);
	//}}AFX_DATA_MAP

  // if dialog is giving data
  if( pDX->m_bSaveAndValidate != FALSE)
  {
    BOOL bUpdateTerrain=FALSE;

    // handle heightmap size change
    INDEX iItemW=m_ctrlHeightMapWidth.GetCurSel();
    PIX pixW=m_ctrlHeightMapWidth.GetItemData( iItemW);
    INDEX iItemH=m_ctrlHeightMapHeight.GetCurSel();
    PIX pixH=m_ctrlHeightMapHeight.GetItemData( iItemH);
    if( ptrTerrain->tr_pixHeightMapWidth != pixW ||
        ptrTerrain->tr_pixHeightMapHeight!= pixH )
    {
      ptrTerrain->ReAllocateHeightMap(pixW, pixH);
      bUpdateTerrain=TRUE;
    }

    // handle terrain size change
    if( ptrTerrain->tr_vTerrainSize(1)!=m_fTerrainWidth ||
        ptrTerrain->tr_vTerrainSize(2)!=m_fTerrainHeight||
        ptrTerrain->tr_vTerrainSize(3)!=m_fTerrainLength)
    {
      ptrTerrain->SetTerrainSize(FLOAT3D(m_fTerrainWidth,m_fTerrainHeight,m_fTerrainLength));
      bUpdateTerrain=TRUE;
    }

    // handle tile pretender texture size change
    INDEX iTlp=m_ctrlTilePretender.GetCurSel();
    PIX pixTlpW=m_ctrlTilePretender.GetItemData( iTlp);
    if( ptrTerrain->tr_pixFirstMipTopMapWidth != pixTlpW)
    {
      ptrTerrain->SetTileTopMapSize(pixTlpW);
      bUpdateTerrain=TRUE;
    }

    // handle quads per tile change
    INDEX iQuadItem=m_ctrlQuadsPerTile.GetCurSel();
    INDEX ctQuads=m_ctrlQuadsPerTile.GetItemData( iQuadItem);
    if(ctQuads!=ptrTerrain->tr_ctQuadsInTileRow)
    {
      ptrTerrain->SetQuadsPerTileRow(ctQuads);
      bUpdateTerrain=TRUE;
    }
    
    // handle LOD distance change
    if( m_fLODSwitch!=ptrTerrain->tr_fDistFactor)
    {
      ptrTerrain->SetLodDistanceFactor(m_fLODSwitch);
    }

    // handle global pretender texture change
    INDEX iGlobalPretender=m_ctrlGlobalPretenderTexture.GetCurSel();
    INDEX pixSize=m_ctrlGlobalPretenderTexture.GetItemData(iGlobalPretender);
    if(pixSize!=ptrTerrain->tr_pixTopMapWidth)
    {
      ptrTerrain->SetGlobalTopMapSize(pixSize);
      bUpdateTerrain=TRUE;
    }

    // handle shadow changes
    if( (m_ctrlShadowMapSlider.GetPos()!=_iShadowMapShift) ||
        (m_ctrlShadingMapSlider.GetPos()!=10-_iShadingMapShift) )
    {
      _iShadowMapShift=m_ctrlShadowMapSlider.GetPos();
      _iShadingMapShift=10-m_ctrlShadingMapSlider.GetPos();
      ptrTerrain->SetShadowMapsSize(_iShadowMapShift,_iShadingMapShift);
      bUpdateTerrain=TRUE;
    }

    // update terrain
    if(bUpdateTerrain)
    {
      ptrTerrain->tr_penEntity->TerrainChangeNotify();
      GenerateLayerDistribution(-1);
      ptrTerrain->RefreshTerrain();
      ptrTerrain->UpdateShadowMap();
      theApp.m_ctTerrainPage.MarkChanged();
    }
  }
}


BEGIN_MESSAGE_MAP(CDlgTerrainProperties, CDialog)
	//{{AFX_MSG_MAP(CDlgTerrainProperties)
	ON_WM_HSCROLL()
	ON_CBN_SELCHANGE(IDC_TERRAIN_HM_WIDTH, OnSelchangeTerrainHmWidth)
	ON_CBN_SELCHANGE(IDC_TERRAIN_HM_HEIGHT, OnSelchangeTerrainHmHeight)
	ON_CBN_SELCHANGE(IDC_TILE_PRETENDER, OnSelchangeTilePretender)
	ON_CBN_SELCHANGE(IDC_GLOBAL_PRETENDER, OnSelchangeGlobalPretender)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDlgTerrainProperties message handlers

void CDlgTerrainProperties::InitComboBoxes(void)
{
  INDEX iToSelect, iWidth;
  CTerrain *ptrTerrain=GetTerrain();
  if(ptrTerrain==NULL) return;

  // prepare quads per tile combo box
  m_ctrlQuadsPerTile.ResetContent();
  iToSelect=3;
  for(INDEX iQuads=4; iQuads<=2048; iQuads*=2)
  {
    CTString strItem;
    strItem.PrintF("%d x %d", iQuads, iQuads);
	  INDEX iAddedAs=m_ctrlQuadsPerTile.AddString(CString(strItem));
	  m_ctrlQuadsPerTile.SetItemData(iAddedAs,iQuads);
    if(ptrTerrain->tr_ctQuadsInTileRow==iQuads)
    {
      iToSelect=iAddedAs;
    }
  }
	m_ctrlQuadsPerTile.SetCurSel(iToSelect);

  // prepare heightmap size combo boxes
	m_ctrlHeightMapWidth.ResetContent();
	m_ctrlHeightMapHeight.ResetContent();
  INDEX iToSelectW=3;
  INDEX iToSelectH=3;
  for(iWidth=32; iWidth<=2048; iWidth*=2)
  {
    CTString strItem;
    strItem.PrintF("%d", iWidth+1);
	  // width
    INDEX iW=m_ctrlHeightMapWidth.AddString(CString(strItem));
    m_ctrlHeightMapWidth.SetItemData(iW,iWidth+1);
    if(ptrTerrain->tr_pixHeightMapWidth==iWidth+1)    iToSelectW=iW;
	  // height
    INDEX iH=m_ctrlHeightMapHeight.AddString(CString(strItem));
    m_ctrlHeightMapHeight.SetItemData(iH,iWidth+1);
    if(ptrTerrain->tr_pixHeightMapHeight==iWidth+1)    iToSelectH=iH;
  }
  m_ctrlHeightMapWidth.SetCurSel( iToSelectW);
  m_ctrlHeightMapHeight.SetCurSel(iToSelectH);

  PrepareTilePretenderCombo();
  PrepareGlobalPretenderCombo();
}

// prepare tile pretender combo boxes
void CDlgTerrainProperties::PrepareTilePretenderCombo(void)
{
  CTerrain *ptrTerrain=GetTerrain();
  if(ptrTerrain==NULL) return;

  m_ctrlTilePretender.ResetContent();
  INDEX iToSelect=6;
  for(INDEX iWidth=4; iWidth<=2048; iWidth*=2)
  {
    CTString strItem;
    strItem.PrintF("%d x %d", iWidth, iWidth);
	  INDEX iAddedAs=m_ctrlTilePretender.AddString(CString(strItem));
    m_ctrlTilePretender.SetItemData(iAddedAs, iWidth);

    if(ptrTerrain->tr_pixFirstMipTopMapWidth==iWidth)
    {
      iToSelect=iAddedAs;
    }
  }
	m_ctrlTilePretender.SetCurSel(iToSelect);
  
}

// prepare tile pretender combo boxes
void CDlgTerrainProperties::PrepareGlobalPretenderCombo(void)
{
  CTerrain *ptrTerrain=GetTerrain();
  if(ptrTerrain==NULL) return;

  INDEX iHeightMapWidthItem=m_ctrlHeightMapWidth.GetCurSel();
  PIX pixHeightMapWidth=m_ctrlHeightMapWidth.GetItemData(iHeightMapWidthItem);
  INDEX iHeightMapHeightItem=m_ctrlHeightMapHeight.GetCurSel();
  PIX pixHeightMapHeight=m_ctrlHeightMapHeight.GetItemData(iHeightMapHeightItem);

  m_ctrlGlobalPretenderTexture.ResetContent();
  INDEX iToSelect=_pixGlobalPretenderTextureWidth;
  FLOAT fAspect=FLOAT(pixHeightMapWidth-1)/(pixHeightMapHeight-1);
  for(INDEX iWidth=4; iWidth<=2048; iWidth*=2)
  {
    CTString strItem;
    strItem.PrintF("%d x %d", iWidth, INDEX(iWidth/fAspect));
	  INDEX iAddedAs=m_ctrlGlobalPretenderTexture.AddString(CString(strItem));
    m_ctrlGlobalPretenderTexture.SetItemData(iAddedAs, iWidth);
    if(_pixGlobalPretenderTextureWidth==iWidth)
    {
      iToSelect=iAddedAs;
    }
  }
	m_ctrlGlobalPretenderTexture.SetCurSel(iToSelect);
}

BOOL CDlgTerrainProperties::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
  // initialize combo boxes
  InitComboBoxes();

	m_ctrlShadowMapSlider.SetRange(-10, 10, TRUE);
	m_ctrlShadingMapSlider.SetRange(0, 10, TRUE);

  m_ctrlShadowMapSlider.SetPos(_iShadowMapShift);
  m_ctrlShadowMapSlider.Invalidate(FALSE);
  m_ctrlShadingMapSlider.SetPos(10-_iShadingMapShift);
  m_ctrlShadingMapSlider.Invalidate(FALSE);

  UpdateData(FALSE);
	return TRUE;
}

BOOL _bUpdateDlg=TRUE;
void CDlgTerrainProperties::OnSelchangeTerrainHmWidth() 
{
  if(_bUpdateDlg)
  {
    _bUpdateDlg=FALSE;
    m_ctrlHeightMapHeight.SetCurSel(m_ctrlHeightMapWidth.GetCurSel());
    PrepareGlobalPretenderCombo();
    UpdateData(FALSE);
    _bUpdateDlg=TRUE;
  }
}

void CDlgTerrainProperties::OnSelchangeTerrainHmHeight() 
{
  if(_bUpdateDlg)
  {
    _bUpdateDlg=FALSE;
    m_ctrlHeightMapWidth.SetCurSel(m_ctrlHeightMapHeight.GetCurSel());
    PrepareGlobalPretenderCombo();
    UpdateData(FALSE);
    _bUpdateDlg=TRUE;
  }
}

void CDlgTerrainProperties::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
  UpdateData( FALSE);
}

void CDlgTerrainProperties::OnOK() 
{
	CDialog::OnOK();
}

void CDlgTerrainProperties::OnSelchangeTilePretender() 
{
  UpdateData( FALSE);
}

void CDlgTerrainProperties::OnSelchangeGlobalPretender() 
{
  INDEX iItem=m_ctrlGlobalPretenderTexture.GetCurSel();
  PIX pixValue=m_ctrlGlobalPretenderTexture.GetItemData(iItem);
  _pixGlobalPretenderTextureWidth=pixValue;
}