// NeL - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . // vegetable_density_page.cpp : implementation file // #include "std_afx.h" #include "object_viewer.h" #include "vegetable_density_page.h" #include "vegetable_edit_tools.h" #include "vegetable_noise_value_dlg.h" #include "vegetable_dlg.h" #include "nel/misc/noise_value.h" #include "nel/3d/vegetable.h" #define NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE 256 ///////////////////////////////////////////////////////////////////////////// // CVegetableDensityPage property page IMPLEMENT_DYNCREATE(CVegetableDensityPage, CPropertyPage) CVegetableDensityPage::CVegetableDensityPage() : CPropertyPage(CVegetableDensityPage::IDD), _DensityDlg(NULL), _MaxDensityDlg(NULL) { //{{AFX_DATA_INIT(CVegetableDensityPage) //}}AFX_DATA_INIT } CVegetableDensityPage::~CVegetableDensityPage() { #define REMOVE_WND(wnd) if (wnd) { wnd->DestroyWindow(); delete wnd; } REMOVE_WND(_DensityDlg); REMOVE_WND(_MaxDensityDlg); } void CVegetableDensityPage::DoDataExchange(CDataExchange* pDX) { CPropertyPage::DoDataExchange(pDX); //{{AFX_DATA_MAP(CVegetableDensityPage) DDX_Control(pDX, IDC_STATIC_VEGETABLE_SHAPENAME, StaticVegetableShape); DDX_Control(pDX, IDC_STATIC_MAX_DENSITY, MaxDensityStaticText); DDX_Control(pDX, IDC_SLIDER_ANGLE_MIN, AngleMinSlider); DDX_Control(pDX, IDC_SLIDER_ANGLE_MAX, AngleMaxSlider); DDX_Control(pDX, IDC_EDIT_ANGLE_MIN, AngleMinEdit); DDX_Control(pDX, IDC_EDIT_ANGLE_MAX, AngleMaxEdit); DDX_Control(pDX, IDC_COMBO_DIST_TYPE, DistTypeCombo); DDX_Control(pDX, IDC_CHECK_MAX_DENSITY, MaxDensityCheckBox); //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CVegetableDensityPage, CPropertyPage) //{{AFX_MSG_MAP(CVegetableDensityPage) ON_BN_CLICKED(IDC_CHECK_MAX_DENSITY, OnCheckMaxDensity) ON_CBN_SELCHANGE(IDC_COMBO_DIST_TYPE, OnSelchangeComboDistType) ON_BN_CLICKED(IDC_RADIO_ANGLE_CEILING, OnRadioAngleCeiling) ON_BN_CLICKED(IDC_RADIO_ANGLE_FLOOR, OnRadioAngleFloor) ON_BN_CLICKED(IDC_RADIO_ANGLE_WALL, OnRadioAngleWall) ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_ANGLE_MAX, OnReleasedcaptureSliderAngleMax) ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER_ANGLE_MIN, OnReleasedcaptureSliderAngleMin) ON_EN_KILLFOCUS(IDC_EDIT_ANGLE_MIN, OnKillfocusEditAngleMin) ON_EN_KILLFOCUS(IDC_EDIT_ANGLE_MAX, OnKillfocusEditAngleMax) ON_EN_CHANGE(IDC_EDIT_ANGLE_MIN, OnChangeEditAngleMin) ON_EN_CHANGE(IDC_EDIT_ANGLE_MAX, OnChangeEditAngleMax) ON_BN_CLICKED(IDC_BUTTON_VEGETABLE_BROWSE, OnButtonVegetableBrowse) //}}AFX_MSG_MAP END_MESSAGE_MAP() // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** // *************************************************************************** void CVegetableDensityPage::setVegetableToEdit(NL3D::CVegetable *vegetable) { _Vegetable= vegetable; // If not NULL, init all controls. if(_Vegetable) { // Init ShapeName // ---------- StaticVegetableShape.SetWindowText(nlUtf8ToTStr(_Vegetable->ShapeName)); // init Creation Distance. // ---------- // normalize creation distance for this editor. _Vegetable->DistType= std::min( (uint)_Vegetable->DistType, (uint)(DistTypeCombo.GetCount()-1) ); // set Creation Distance. DistTypeCombo.SetCurSel( _Vegetable->DistType ); // init _DensityDlg. // ---------- _DensityDlg->setNoiseValue(&_Vegetable->Density, _VegetableDlg); // init MaxDensity // ---------- if(_Vegetable->MaxDensity == -1) { // Disable the checkBox and the slider. MaxDensityCheckBox.SetCheck(0); static float dummy; _MaxDensityDlg->setFloat(&dummy, _VegetableDlg); _MaxDensityDlg->EnableWindow(false); // Init with a default value _PrecMaxDensityValue= NL_VEGETABLE_EDIT_DEFAULT_MAX_DENSITY; } else { // Enable the checkBox and the slider MaxDensityCheckBox.SetCheck(1); _MaxDensityDlg->setFloat(&_Vegetable->MaxDensity, _VegetableDlg); _MaxDensityDlg->EnableWindow(true); } // init AngleSetup. // ---------- NL3D::CVegetable::TAngleType angType= _Vegetable->getAngleType(); // disable 3 radio buttons. ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_FLOOR))->SetCheck(0); ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_WALL))->SetCheck(0); ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_CEILING))->SetCheck(0); // enable only the one of interest. switch(angType) { case NL3D::CVegetable::AngleGround: ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_FLOOR))->SetCheck(1); enableAngleEdit(IDC_RADIO_ANGLE_FLOOR); break; case NL3D::CVegetable::AngleWall: ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_WALL))->SetCheck(1); enableAngleEdit(IDC_RADIO_ANGLE_WALL); break; case NL3D::CVegetable::AngleCeiling: ((CButton*)GetDlgItem(IDC_RADIO_ANGLE_CEILING))->SetCheck(1); enableAngleEdit(IDC_RADIO_ANGLE_CEILING); break; } // to avoid a strange bug if pos==0... (not correctly setuped the first time) AngleMinSlider.SetPos(10); AngleMaxSlider.SetPos(10); // Init sliders / edit. updateViewAngleMin(); updateViewAngleMax(); } } // *************************************************************************** void CVegetableDensityPage::enableAngleEdit(uint radioId) { // first disable all AngleMinSlider.EnableWindow(false); AngleMinEdit.EnableWindow(false); AngleMaxSlider.EnableWindow(false); AngleMaxEdit.EnableWindow(false); // Then enable only what needed. if(radioId == IDC_RADIO_ANGLE_WALL || radioId == IDC_RADIO_ANGLE_FLOOR) { AngleMinSlider.EnableWindow(true); AngleMinEdit.EnableWindow(true); } if(radioId == IDC_RADIO_ANGLE_WALL || radioId == IDC_RADIO_ANGLE_CEILING) { AngleMaxSlider.EnableWindow(true); AngleMaxEdit.EnableWindow(true); } } // *************************************************************************** void CVegetableDensityPage::updateViewAngleMin() { double angle= _Vegetable->getCosAngleMin(); NLMISC::clamp(angle, -1, 1); angle= asin(angle); sint pos= (sint)(angle/(NLMISC::Pi/2) * NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); NLMISC::clamp(pos, -NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE, NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); AngleMinSlider.SetPos(pos); CString stmp; stmp.Format(_T("%.2f"), (double)(angle*180/NLMISC::Pi)); AngleMinEdit.SetWindowText(stmp); } // *************************************************************************** void CVegetableDensityPage::updateViewAngleMax() { double angle= _Vegetable->getCosAngleMax(); NLMISC::clamp(angle, -1, 1); angle= asin(angle); sint pos= (sint)(angle/(NLMISC::Pi/2) * NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); NLMISC::clamp(pos, -NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE, NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); AngleMaxSlider.SetPos(pos); CString stmp; stmp.Format(_T("%.2f"), (double)(angle * 180 / NLMISC::Pi)); AngleMaxEdit.SetWindowText(stmp); } // *************************************************************************** void CVegetableDensityPage::updateAngleMinFromEditText() { // get angles edited. TCHAR stmp[256]; AngleMinEdit.GetWindowText(stmp, 256); float angleMin; NLMISC::fromString(NLMISC::tStrToUtf8(stmp), angleMin); NLMISC::clamp(angleMin, -90, 90); // make a sinus, because 90 => 1, and -90 =>-1 float cosAngleMin= (float)sin(angleMin*NLMISC::Pi/180.f); // setup vegetable. if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleWall) _Vegetable->setAngleWall(cosAngleMin, _Vegetable->getCosAngleMax()); else if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleGround) _Vegetable->setAngleGround(cosAngleMin); // update views updateViewAngleMin(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::updateAngleMaxFromEditText() { // get angles edited. TCHAR stmp[256]; AngleMaxEdit.GetWindowText(stmp, 256); float angleMax; NLMISC::fromString(NLMISC::tStrToUtf8(stmp), angleMax); NLMISC::clamp(angleMax, -90, 90); // make a sinus, because 90 => 1, and -90 =>-1 float cosAngleMax= (float)sin(angleMax*NLMISC::Pi/180.f); // setup vegetable. if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleWall) _Vegetable->setAngleWall(_Vegetable->getCosAngleMin(), cosAngleMax); else if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleCeiling) _Vegetable->setAngleCeiling(cosAngleMax); // update views updateViewAngleMax(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** // *************************************************************************** // CVegetableDensityPage message handlers // *************************************************************************** // *************************************************************************** // *************************************************************************** BOOL CVegetableDensityPage::OnInitDialog() { CPropertyPage::OnInitDialog(); // position setup. uint x= 5; // Position of the density DlgBox relative to CVegetableDensityPage. uint yDensity= 130; // y relative to MaxDensity Group uint yMaxDensity= 45; // get y of MaxDensityStaticText relative to CVegetableDensityPage. RECT rectParent; RECT rect; GetWindowRect(&rectParent); MaxDensityStaticText.GetWindowRect(&rect); // and apply. yMaxDensity+= rect.top - rectParent.top; // Init Density Dialog. _DensityDlg = new CVegetableNoiseValueDlg (std::string("Density")); _DensityDlg->setDefaultRangeAbs(NL_VEGETABLE_DENSITY_ABS_RANGE_MIN, NL_VEGETABLE_DENSITY_ABS_RANGE_MAX); _DensityDlg->setDefaultRangeRand(NL_VEGETABLE_DENSITY_RAND_RANGE_MIN, NL_VEGETABLE_DENSITY_RAND_RANGE_MAX); _DensityDlg->setDefaultRangeFreq(NL_VEGETABLE_FREQ_RANGE_MIN, NL_VEGETABLE_FREQ_RANGE_MAX); _DensityDlg->init(x, yDensity, this); // Init MaxDensity Dialog. _MaxDensityDlg = new CDirectEditableRangeFloat (std::string("VEGET_MAX_DENSITY"), 0, NL_VEGETABLE_EDIT_DEFAULT_MAX_DENSITY, "MaxDensity"); _MaxDensityDlg->enableLowerBound(0, false); _MaxDensityDlg->init(x+10, yMaxDensity, this); // Init angle sliders. AngleMinSlider.SetRange(-NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE, NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); AngleMaxSlider.SetRange(-NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE, NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE); // Init ShapeName StaticVegetableShape.SetWindowText(_T("")); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } // *************************************************************************** void CVegetableDensityPage::OnCheckMaxDensity() { if(MaxDensityCheckBox.GetCheck() == 1) { // check, restore maxDensity _Vegetable->MaxDensity= _PrecMaxDensityValue; // enable dlg. _MaxDensityDlg->setFloat(&_Vegetable->MaxDensity, _VegetableDlg); _MaxDensityDlg->EnableWindow(true); } else { // uncheck, bkup maxDenstiy _PrecMaxDensityValue= _Vegetable->MaxDensity; // disable dlg static float dummy; _MaxDensityDlg->setFloat(&dummy, _VegetableDlg); _MaxDensityDlg->EnableWindow(false); // and setup vegetable (disable MaxDensity). _Vegetable->MaxDensity= -1; } // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::OnSelchangeComboDistType() { // Get the DistType, and just copy to vegetable. _Vegetable->DistType= DistTypeCombo.GetCurSel(); // Since used to display name in selection listBox, must update the name _VegetableDlg->updateCurSelVegetableName(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::OnRadioAngleCeiling() { // Enable just the AngleMax slider. enableAngleEdit(IDC_RADIO_ANGLE_CEILING); // Init value. _Vegetable->setAngleCeiling(0); // Update view Value updateViewAngleMax(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::OnRadioAngleFloor() { // Enable just the AngleMin slider. enableAngleEdit(IDC_RADIO_ANGLE_FLOOR); // Init value. _Vegetable->setAngleGround(0); // Update view Value updateViewAngleMin(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::OnRadioAngleWall() { // Enable both sliders. enableAngleEdit(IDC_RADIO_ANGLE_WALL); // Init value. _Vegetable->setAngleWall(-1, 1); // Update view Value updateViewAngleMin(); updateViewAngleMax(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } // *************************************************************************** void CVegetableDensityPage::OnReleasedcaptureSliderAngleMax(NMHDR* pNMHDR, LRESULT* pResult) { float angle= 90 * (float)AngleMaxSlider.GetPos() / (float)NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE; NLMISC::clamp(angle, -90, 90); // make a sinus, because 90 => 1, and -90 =>-1 float cosAngleMax= (float)sin(angle*NLMISC::Pi/180.f); // setup vegetable. if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleWall) _Vegetable->setAngleWall(_Vegetable->getCosAngleMin(), cosAngleMax); else _Vegetable->setAngleCeiling(cosAngleMax); // update view updateViewAngleMax(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); *pResult = 0; } // *************************************************************************** void CVegetableDensityPage::OnReleasedcaptureSliderAngleMin(NMHDR* pNMHDR, LRESULT* pResult) { float angle= 90 * (float)AngleMinSlider.GetPos() / (float)NL_VEGETABLE_EDIT_ANGLE_SLIDER_SIZE; NLMISC::clamp(angle, -90, 90); // make a sinus, because 90 => 1, and -90 =>-1 float cosAngleMin= (float)sin(angle*NLMISC::Pi/180.f); // setup vegetable. if(_Vegetable->getAngleType()== NL3D::CVegetable::AngleWall) _Vegetable->setAngleWall(cosAngleMin, _Vegetable->getCosAngleMax()); else _Vegetable->setAngleGround(cosAngleMin); // update view updateViewAngleMin(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); *pResult = 0; } // *************************************************************************** void CVegetableDensityPage::OnKillfocusEditAngleMin() { updateAngleMinFromEditText(); } void CVegetableDensityPage::OnKillfocusEditAngleMax() { updateAngleMaxFromEditText(); } static void concatEdit2Lines(CEdit &edit) { const uint lineLen= 1000; uint n; // retrieve the 2 lines. TCHAR tmp0[2*lineLen]; TCHAR tmp1[lineLen]; n= edit.GetLine(0, tmp0, lineLen); tmp0[n]= 0; n= edit.GetLine(1, tmp1, lineLen); tmp1[n]= 0; // concat and update the CEdit. edit.SetWindowText(_tcscat(tmp0, tmp1)); } void CVegetableDensityPage::OnChangeEditAngleMin() { // Trick to track "Enter" keypress: CEdit are multiline. If GetLineCount()>1, then // user has press enter. if(AngleMinEdit.GetLineCount()>1) { // must ccat the 2 first lines. concatEdit2Lines(AngleMinEdit); // the text (and so the lineCount) is reseted in this method. updateAngleMinFromEditText(); } } void CVegetableDensityPage::OnChangeEditAngleMax() { // Trick to track "Enter" keypress: CEdit are multiline. If GetLineCount()>1, then // user has press enter. if(AngleMaxEdit.GetLineCount()>1) { // must ccat the 2 first lines. concatEdit2Lines(AngleMinEdit); // the text (and so the lineCount) is reseted in this method. updateAngleMaxFromEditText(); } } // *************************************************************************** void CVegetableDensityPage::OnButtonVegetableBrowse() { CFileDialog fd(TRUE, _T("veget"), _T("*.veget"), 0, NULL, this) ; fd.m_ofn.lpstrTitle = _T("Open Vegetable Shape"); if (fd.DoModal() == IDOK) { // Add to the path std::string fileName = NLMISC::tStrToUtf8(fd.GetFileName()); // Add search path for the .veget std::string path = NLMISC::CFile::getPath(NLMISC::tStrToUtf8(fd.GetPathName())); NLMISC::CPath::addSearchPath (path); try { // verify the file can be opened. NLMISC::CPath::lookup(fileName); // update shapeName and view _Vegetable->ShapeName = fileName; StaticVegetableShape.SetWindowText(fd.GetFileName()); // update the name in the list-box _VegetableDlg->updateCurSelVegetableName(); // update 3D view _VegetableDlg->refreshVegetableDisplay(); } catch (const NLMISC::EPathNotFound &ep) { MessageBox(nlUtf8ToTStr(ep.what()), _T("Can't open file")); } } }