mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-17 21:11:39 +00:00
471 lines
11 KiB
C++
471 lines
11 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
//
|
|
|
|
#include "std_afx.h"
|
|
#include "object_viewer.h"
|
|
#include "curve_edit.h"
|
|
#include "editable_range.h"
|
|
#include "nel/3d/ps_float.h"
|
|
#include "nel/misc/common.h"
|
|
#include "nel/misc/fast_floor.h"
|
|
|
|
static const uint CtrlPointSize = 3;
|
|
|
|
|
|
|
|
CurveEdit::CurveEdit(NL3D::CPSFloatCurveFunctor *curve, CParticleWorkspace::CNode *ownerNode, IPopupNotify *pn, CWnd* pParent /*=NULL*/)
|
|
: CDialog(CurveEdit::IDD, pParent),
|
|
_Node(ownerNode),
|
|
_PN(pn),
|
|
Curve(curve),
|
|
_State(Create),
|
|
_X(10),
|
|
_Y(10),
|
|
_Width(350),
|
|
_Height(200),
|
|
_SelectedCtrlPoint(-1),
|
|
_NumSamplesDlg(NULL)
|
|
|
|
{
|
|
nlassert(Curve);
|
|
//{{AFX_DATA_INIT(CurveEdit)
|
|
m_DisplayInterpolation = FALSE;
|
|
m_SmoothingOn = FALSE;
|
|
//}}AFX_DATA_INIT
|
|
scaleMinMax();
|
|
}
|
|
|
|
CurveEdit::~CurveEdit()
|
|
{
|
|
if (_NumSamplesDlg)
|
|
{
|
|
_NumSamplesDlg->DestroyWindow();
|
|
delete _NumSamplesDlg;
|
|
}
|
|
}
|
|
|
|
|
|
void CurveEdit::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(CurveEdit)
|
|
DDX_Check(pDX, IDC_DISPLAY_INTERPOLATION, m_DisplayInterpolation);
|
|
DDX_Check(pDX, IDC_SMOOTHING_ON, m_SmoothingOn);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(CurveEdit, CDialog)
|
|
//{{AFX_MSG_MAP(CurveEdit)
|
|
ON_WM_MOUSEMOVE()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_PAINT()
|
|
ON_BN_CLICKED(IDC_ZOOM_OUT, OnZoomOut)
|
|
ON_BN_CLICKED(IDC_ZOOM_IN, OnZoomIn)
|
|
ON_BN_CLICKED(IDC_GO_UP, OnGoUp)
|
|
ON_BN_CLICKED(IDC_GO_DOWN, OnGoDown)
|
|
ON_BN_CLICKED(IDC_MOVE_POINT, OnMovePoint)
|
|
ON_BN_CLICKED(IDC_ADD_POINT, OnAddPoint)
|
|
ON_BN_CLICKED(IDC_REMOVE_POINT, OnRemovePoint)
|
|
ON_BN_CLICKED(IDC_DISPLAY_INTERPOLATION, OnDisplayInterpolation)
|
|
ON_BN_CLICKED(IDC_SMOOTHING_ON, OnSmoothingOn)
|
|
ON_BN_CLICKED(IDC_LAST_EQUAL_FIRST, OnLastEqualFirst)
|
|
ON_BN_CLICKED(IDC_CENTER_CURVE, OnCenterCurve)
|
|
ON_BN_CLICKED(IDC_FIRST_EQUAL_LAST, OnFirstEqualLast)
|
|
ON_WM_DESTROY()
|
|
ON_WM_CLOSE()
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CurveEdit message handlers
|
|
|
|
void CurveEdit::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
switch (_State)
|
|
{
|
|
case Move:
|
|
case Remove:
|
|
{
|
|
sint cpIndex = intersectCtrlPoint(point.x, point.y);
|
|
if (cpIndex != _SelectedCtrlPoint)
|
|
{
|
|
_SelectedCtrlPoint = cpIndex;
|
|
Invalidate();
|
|
}
|
|
}
|
|
break;
|
|
case Moving:
|
|
{
|
|
Curve->setCtrlPoint(_SelectedCtrlPoint,coordsFromScreen(point.x, point.y));
|
|
_SelectedCtrlPoint = intersectCtrlPoint(point.x, point.y); // the index of the point we are moving may have changed
|
|
if (_SelectedCtrlPoint == -1) _State = Move;
|
|
Invalidate();
|
|
}
|
|
break;
|
|
}
|
|
|
|
CDialog::OnMouseMove(nFlags, point);
|
|
}
|
|
|
|
void CurveEdit::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
switch (_State)
|
|
{
|
|
case Moving:
|
|
_State = Move;
|
|
_SelectedCtrlPoint = intersectCtrlPoint(point.x, point.y);
|
|
Invalidate();
|
|
break;
|
|
case Removing:
|
|
_State = Remove;
|
|
break;
|
|
case Created:
|
|
_State = Create;
|
|
break;
|
|
}
|
|
CDialog::OnLButtonUp(nFlags, point);
|
|
}
|
|
|
|
void CurveEdit::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
switch (_State)
|
|
{
|
|
case Move:
|
|
{
|
|
if (_SelectedCtrlPoint != -1) _State = Moving;
|
|
}
|
|
break;
|
|
case Create:
|
|
{
|
|
Curve->addControlPoint(coordsFromScreen(point.x, point.y));
|
|
_State = Created;
|
|
invalidate();
|
|
}
|
|
case Remove:
|
|
{
|
|
if ( _SelectedCtrlPoint == -1 || Curve->getNumCtrlPoints() == 2 ) return;
|
|
Curve->removeCtrlPoint(_SelectedCtrlPoint);
|
|
_State= Removing;
|
|
_SelectedCtrlPoint = -1;
|
|
invalidate();
|
|
}
|
|
break;
|
|
}
|
|
CDialog::OnLButtonDown(nFlags, point);
|
|
}
|
|
|
|
void CurveEdit::OnPaint()
|
|
{
|
|
UpdateData();
|
|
CPaintDC dc(this); // device context for painting
|
|
drawBackGround(dc);
|
|
drawUnits(dc);
|
|
drawCurve(dc);
|
|
if (m_DisplayInterpolation) drawInterpolatingCurve(dc);
|
|
drawCtrlPoints(dc);
|
|
}
|
|
|
|
|
|
void CurveEdit::setupBoundRect(CDC &dc)
|
|
{
|
|
CRgn rgn;
|
|
rgn.CreateRectRgn(_X, _X, _X + _Width, _Y + _Height);
|
|
dc.SelectClipRgn(&rgn, RGN_COPY );
|
|
}
|
|
|
|
void CurveEdit::drawBackGround(CDC &dc)
|
|
{
|
|
setupBoundRect(dc);
|
|
dc.FillSolidRect(_X, _Y, _Width, _Height, 0xffffff);
|
|
}
|
|
|
|
|
|
|
|
POINT CurveEdit::makePoint(float date, float value) const
|
|
{
|
|
POINT p;
|
|
p.x = (int) (_X + date * _Width);
|
|
p.y = (int) (_Y + _Height - _Scale * _Height * (value - _Origin));
|
|
return p;
|
|
}
|
|
|
|
|
|
sint CurveEdit::intersectCtrlPoint(sint x, sint y)
|
|
{
|
|
uint numPoints = Curve->getNumCtrlPoints();
|
|
for (uint k = 0; k < numPoints; ++k)
|
|
{
|
|
const CCtrlPoint &cp = Curve->getControlPoint(k);
|
|
POINT p = makePoint(cp.Date, cp.Value);
|
|
if ( x >= (sint) (p.x - CtrlPointSize)
|
|
&& x <= (sint) (p.x + CtrlPointSize)
|
|
&& y >= (sint) (p.y - CtrlPointSize)
|
|
&& y <= (sint) (p.y + CtrlPointSize) )
|
|
{
|
|
return k;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
CurveEdit::CCtrlPoint CurveEdit::coordsFromScreen(sint x, sint y) const
|
|
{
|
|
float date =(x - _X) / (float) _Width;
|
|
NLMISC::clamp(date, 0.f, 1.f);
|
|
CCtrlPoint pos(
|
|
date,
|
|
_Origin + (_Y + _Height - y) / (_Scale * _Height)
|
|
);
|
|
return pos;
|
|
}
|
|
|
|
|
|
void CurveEdit::drawCurve(CDC &dc)
|
|
{
|
|
setupBoundRect(dc);
|
|
CPen pen;
|
|
pen.CreatePen(PS_SOLID, 1, (COLORREF) 0x000000);
|
|
CGdiObject *oldPen = dc.SelectObject(&pen);
|
|
|
|
dc.MoveTo(makePoint(0, Curve->getValue(0)));
|
|
for (sint x = 0; x < _Width; ++x)
|
|
{
|
|
const float date = x / (float) _Width;
|
|
dc.LineTo(_X + x, makePoint(date, Curve->getValue(date)).y);
|
|
}
|
|
dc.SelectObject(oldPen);
|
|
}
|
|
|
|
|
|
void CurveEdit::drawInterpolatingCurve(CDC &dc)
|
|
{
|
|
setupBoundRect(dc);
|
|
CPen pen;
|
|
pen.CreatePen(PS_SOLID, 1, (COLORREF) 0x772211);
|
|
CGdiObject *oldPen = dc.SelectObject(&pen);
|
|
dc.MoveTo(makePoint(0, getSampledValue(0)));
|
|
for (sint x = 0; x < _Width; ++x)
|
|
{
|
|
const float date = x / (float) _Width;
|
|
dc.LineTo(_X + x, makePoint(date, getSampledValue(date)).y);
|
|
}
|
|
dc.SelectObject(oldPen);
|
|
}
|
|
|
|
|
|
|
|
void CurveEdit::scaleMinMax()
|
|
{
|
|
float minValue, maxValue;
|
|
maxValue = minValue = getSampledValue(0);
|
|
for (sint x = 1; x < _Width; ++x)
|
|
{
|
|
const float date = x / (float) _Width;
|
|
const float value = getSampledValue(date);
|
|
minValue = std::min(minValue, value);
|
|
maxValue = std::max(maxValue, value);
|
|
}
|
|
_Origin = (maxValue == minValue) ? minValue - .5f : minValue;
|
|
_Scale = (maxValue == minValue) ? 1.f : 1.f / (maxValue - minValue);
|
|
}
|
|
|
|
|
|
|
|
|
|
void CurveEdit::drawCtrlPoints(CDC &dc)
|
|
{
|
|
setupBoundRect(dc);
|
|
CPen pens[2];
|
|
pens[0].CreatePen(PS_SOLID, 1, (COLORREF) 0x00ff00);
|
|
pens[1].CreatePen(PS_SOLID, 1, (COLORREF) 0x0000ff);
|
|
|
|
uint numPoints = Curve->getNumCtrlPoints();
|
|
for (uint k = 0; k < numPoints; ++k)
|
|
{
|
|
CGdiObject *oldPen = dc.SelectObject(&pens[k == (uint) _SelectedCtrlPoint ? 1 : 0]); // slect the red pen if thi ctrl point is selected
|
|
const CCtrlPoint &cp = Curve->getControlPoint(k);
|
|
POINT p = makePoint(cp.Date, cp.Value);
|
|
dc.MoveTo(p.x- CtrlPointSize, p.y - CtrlPointSize);
|
|
dc.LineTo(p.x + CtrlPointSize, p.y - CtrlPointSize);
|
|
dc.LineTo(p.x + CtrlPointSize, p.y + CtrlPointSize);
|
|
dc.LineTo(p.x - CtrlPointSize, p.y + CtrlPointSize);
|
|
dc.LineTo(p.x - CtrlPointSize, p.y - CtrlPointSize);
|
|
dc.SelectObject(oldPen);
|
|
}
|
|
}
|
|
|
|
|
|
void CurveEdit::OnZoomOut()
|
|
{
|
|
_Scale *= 1.5f;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnZoomIn()
|
|
{
|
|
_Scale *= 0.5f;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnGoUp()
|
|
{
|
|
_Origin += (1.f / _Scale) * 0.25f;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnGoDown()
|
|
{
|
|
_Origin -= (1.f / _Scale) * 0.25f;
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
void CurveEdit::drawUnits(CDC &dc)
|
|
{
|
|
CPen pens[2];
|
|
pens[0].CreatePen(PS_SOLID, 1, (COLORREF) 0xaaaaaa);
|
|
pens[1].CreatePen(PS_SOLID, 1, (COLORREF) 0xff0011);
|
|
|
|
sint upVal = (sint) floorf(coordsFromScreen(0, _X).Value);
|
|
sint downVal = (sint) floorf(coordsFromScreen(0, _X + _Width).Value);
|
|
|
|
nlassert(upVal >= downVal);
|
|
for (sint k = downVal ; k <= upVal ; ++k)
|
|
{
|
|
CGdiObject *oldPen = dc.SelectObject(&pens[k == 0 ? 1 : 0]);
|
|
dc.MoveTo(makePoint(0, (float) k));
|
|
dc.LineTo(makePoint(1, (float) k));
|
|
dc.SelectObject(oldPen);
|
|
}
|
|
}
|
|
|
|
BOOL CurveEdit::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
((CButton *) GetDlgItem(IDC_ADD_POINT))->SetCheck(1);
|
|
|
|
_NumSamplesDlg = new CEditableRangeUInt(std::string("FLOAT_CURVE_NB_SAMPLE"), _Node, 1, 512);
|
|
_NumSampleWrapper.CE = this;
|
|
_NumSamplesDlg->setWrapper(&_NumSampleWrapper);
|
|
_NumSamplesDlg->init(80, 225, this);
|
|
_NumSamplesDlg->enableLowerBound(1, true);
|
|
m_SmoothingOn = Curve->hasSmoothing();
|
|
|
|
UpdateData(FALSE);
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void CurveEdit::OnMovePoint()
|
|
{
|
|
_State = Move;
|
|
_SelectedCtrlPoint = -1;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnAddPoint()
|
|
{
|
|
_State = Create;
|
|
_SelectedCtrlPoint = -1;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnRemovePoint()
|
|
{
|
|
_State = Remove;
|
|
_SelectedCtrlPoint = -1;
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnDisplayInterpolation()
|
|
{
|
|
Invalidate();
|
|
}
|
|
|
|
|
|
|
|
float CurveEdit::getSampledValue(float date) const
|
|
{
|
|
nlassert(Curve);
|
|
nlassert(date >=0 && date < 1);
|
|
NLMISC::OptFastFloorBegin();
|
|
float result = (*Curve)(date);
|
|
NLMISC::OptFastFloorEnd();
|
|
return result;
|
|
}
|
|
|
|
void CurveEdit::OnSmoothingOn()
|
|
{
|
|
UpdateData();
|
|
nlassert(Curve);
|
|
Curve->enableSmoothing(m_SmoothingOn ? true : false /* perf; warning */);
|
|
invalidate();
|
|
}
|
|
|
|
|
|
void CurveEdit::OnLastEqualFirst()
|
|
{
|
|
CCtrlPoint pt = Curve->getControlPoint(0);
|
|
pt.Date = Curve->getControlPoint(Curve->getNumCtrlPoints() - 1).Date;
|
|
Curve->setCtrlPoint(Curve->getNumCtrlPoints() - 1, pt);
|
|
invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnCenterCurve()
|
|
{
|
|
scaleMinMax();
|
|
Invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnFirstEqualLast()
|
|
{
|
|
CCtrlPoint pt = Curve->getControlPoint(Curve->getNumCtrlPoints() - 1);
|
|
pt.Date = Curve->getControlPoint(0).Date;
|
|
Curve->setCtrlPoint(0, pt);
|
|
invalidate();
|
|
}
|
|
|
|
void CurveEdit::OnDestroy()
|
|
{
|
|
CDialog::OnDestroy();
|
|
}
|
|
|
|
void CurveEdit::init(CWnd *pParent)
|
|
{
|
|
CDialog::Create(IDD_CURVE_EDIT, pParent);
|
|
ShowWindow(SW_SHOW);
|
|
}
|
|
|
|
|
|
void CurveEdit::OnClose()
|
|
{
|
|
CDialog::OnClose();
|
|
_PN->childPopupClosed(this);
|
|
}
|
|
|
|
void CurveEdit::invalidate()
|
|
{
|
|
if (_Node)
|
|
{
|
|
_Node->setModified(true);
|
|
}
|
|
Invalidate();
|
|
}
|