1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2010 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "object_viewer.h"
24 #include "curve_edit.h"
25 #include "editable_range.h"
26 #include "nel/3d/ps_float.h"
27 #include "nel/misc/common.h"
28 #include "nel/misc/fast_floor.h"
30 static const uint CtrlPointSize
= 3;
34 CurveEdit::CurveEdit(NL3D::CPSFloatCurveFunctor
*curve
, CParticleWorkspace::CNode
*ownerNode
, IPopupNotify
*pn
, CWnd
* pParent
/*=NULL*/)
35 : CDialog(CurveEdit::IDD
, pParent
),
44 _SelectedCtrlPoint(-1),
49 //{{AFX_DATA_INIT(CurveEdit)
50 m_DisplayInterpolation
= FALSE
;
51 m_SmoothingOn
= FALSE
;
56 CurveEdit::~CurveEdit()
60 _NumSamplesDlg
->DestroyWindow();
61 delete _NumSamplesDlg
;
66 void CurveEdit::DoDataExchange(CDataExchange
* pDX
)
68 CDialog::DoDataExchange(pDX
);
69 //{{AFX_DATA_MAP(CurveEdit)
70 DDX_Check(pDX
, IDC_DISPLAY_INTERPOLATION
, m_DisplayInterpolation
);
71 DDX_Check(pDX
, IDC_SMOOTHING_ON
, m_SmoothingOn
);
76 BEGIN_MESSAGE_MAP(CurveEdit
, CDialog
)
77 //{{AFX_MSG_MAP(CurveEdit)
82 ON_BN_CLICKED(IDC_ZOOM_OUT
, OnZoomOut
)
83 ON_BN_CLICKED(IDC_ZOOM_IN
, OnZoomIn
)
84 ON_BN_CLICKED(IDC_GO_UP
, OnGoUp
)
85 ON_BN_CLICKED(IDC_GO_DOWN
, OnGoDown
)
86 ON_BN_CLICKED(IDC_MOVE_POINT
, OnMovePoint
)
87 ON_BN_CLICKED(IDC_ADD_POINT
, OnAddPoint
)
88 ON_BN_CLICKED(IDC_REMOVE_POINT
, OnRemovePoint
)
89 ON_BN_CLICKED(IDC_DISPLAY_INTERPOLATION
, OnDisplayInterpolation
)
90 ON_BN_CLICKED(IDC_SMOOTHING_ON
, OnSmoothingOn
)
91 ON_BN_CLICKED(IDC_LAST_EQUAL_FIRST
, OnLastEqualFirst
)
92 ON_BN_CLICKED(IDC_CENTER_CURVE
, OnCenterCurve
)
93 ON_BN_CLICKED(IDC_FIRST_EQUAL_LAST
, OnFirstEqualLast
)
99 /////////////////////////////////////////////////////////////////////////////
100 // CurveEdit message handlers
102 void CurveEdit::OnMouseMove(UINT nFlags
, CPoint point
)
109 sint cpIndex
= intersectCtrlPoint(point
.x
, point
.y
);
110 if (cpIndex
!= _SelectedCtrlPoint
)
112 _SelectedCtrlPoint
= cpIndex
;
119 Curve
->setCtrlPoint(_SelectedCtrlPoint
,coordsFromScreen(point
.x
, point
.y
));
120 _SelectedCtrlPoint
= intersectCtrlPoint(point
.x
, point
.y
); // the index of the point we are moving may have changed
121 if (_SelectedCtrlPoint
== -1) _State
= Move
;
127 CDialog::OnMouseMove(nFlags
, point
);
130 void CurveEdit::OnLButtonUp(UINT nFlags
, CPoint point
)
136 _SelectedCtrlPoint
= intersectCtrlPoint(point
.x
, point
.y
);
146 CDialog::OnLButtonUp(nFlags
, point
);
149 void CurveEdit::OnLButtonDown(UINT nFlags
, CPoint point
)
155 if (_SelectedCtrlPoint
!= -1) _State
= Moving
;
160 Curve
->addControlPoint(coordsFromScreen(point
.x
, point
.y
));
166 if ( _SelectedCtrlPoint
== -1 || Curve
->getNumCtrlPoints() == 2 ) return;
167 Curve
->removeCtrlPoint(_SelectedCtrlPoint
);
169 _SelectedCtrlPoint
= -1;
174 CDialog::OnLButtonDown(nFlags
, point
);
177 void CurveEdit::OnPaint()
180 CPaintDC
dc(this); // device context for painting
184 if (m_DisplayInterpolation
) drawInterpolatingCurve(dc
);
189 void CurveEdit::setupBoundRect(CDC
&dc
)
192 rgn
.CreateRectRgn(_X
, _X
, _X
+ _Width
, _Y
+ _Height
);
193 dc
.SelectClipRgn(&rgn
, RGN_COPY
);
196 void CurveEdit::drawBackGround(CDC
&dc
)
199 dc
.FillSolidRect(_X
, _Y
, _Width
, _Height
, 0xffffff);
204 POINT
CurveEdit::makePoint(float date
, float value
) const
207 p
.x
= (int) (_X
+ date
* _Width
);
208 p
.y
= (int) (_Y
+ _Height
- _Scale
* _Height
* (value
- _Origin
));
213 sint
CurveEdit::intersectCtrlPoint(sint x
, sint y
)
215 uint numPoints
= Curve
->getNumCtrlPoints();
216 for (uint k
= 0; k
< numPoints
; ++k
)
218 const CCtrlPoint
&cp
= Curve
->getControlPoint(k
);
219 POINT p
= makePoint(cp
.Date
, cp
.Value
);
220 if ( x
>= (sint
) (p
.x
- CtrlPointSize
)
221 && x
<= (sint
) (p
.x
+ CtrlPointSize
)
222 && y
>= (sint
) (p
.y
- CtrlPointSize
)
223 && y
<= (sint
) (p
.y
+ CtrlPointSize
) )
231 CurveEdit::CCtrlPoint
CurveEdit::coordsFromScreen(sint x
, sint y
) const
233 float date
=(x
- _X
) / (float) _Width
;
234 NLMISC::clamp(date
, 0.f
, 1.f
);
237 _Origin
+ (_Y
+ _Height
- y
) / (_Scale
* _Height
)
243 void CurveEdit::drawCurve(CDC
&dc
)
247 pen
.CreatePen(PS_SOLID
, 1, (COLORREF
) 0x000000);
248 CGdiObject
*oldPen
= dc
.SelectObject(&pen
);
250 dc
.MoveTo(makePoint(0, Curve
->getValue(0)));
251 for (sint x
= 0; x
< _Width
; ++x
)
253 const float date
= x
/ (float) _Width
;
254 dc
.LineTo(_X
+ x
, makePoint(date
, Curve
->getValue(date
)).y
);
256 dc
.SelectObject(oldPen
);
260 void CurveEdit::drawInterpolatingCurve(CDC
&dc
)
264 pen
.CreatePen(PS_SOLID
, 1, (COLORREF
) 0x772211);
265 CGdiObject
*oldPen
= dc
.SelectObject(&pen
);
266 dc
.MoveTo(makePoint(0, getSampledValue(0)));
267 for (sint x
= 0; x
< _Width
; ++x
)
269 const float date
= x
/ (float) _Width
;
270 dc
.LineTo(_X
+ x
, makePoint(date
, getSampledValue(date
)).y
);
272 dc
.SelectObject(oldPen
);
277 void CurveEdit::scaleMinMax()
279 float minValue
, maxValue
;
280 maxValue
= minValue
= getSampledValue(0);
281 for (sint x
= 1; x
< _Width
; ++x
)
283 const float date
= x
/ (float) _Width
;
284 const float value
= getSampledValue(date
);
285 minValue
= std::min(minValue
, value
);
286 maxValue
= std::max(maxValue
, value
);
288 _Origin
= (maxValue
== minValue
) ? minValue
- .5f
: minValue
;
289 _Scale
= (maxValue
== minValue
) ? 1.f
: 1.f
/ (maxValue
- minValue
);
295 void CurveEdit::drawCtrlPoints(CDC
&dc
)
299 pens
[0].CreatePen(PS_SOLID
, 1, (COLORREF
) 0x00ff00);
300 pens
[1].CreatePen(PS_SOLID
, 1, (COLORREF
) 0x0000ff);
302 uint numPoints
= Curve
->getNumCtrlPoints();
303 for (uint k
= 0; k
< numPoints
; ++k
)
305 CGdiObject
*oldPen
= dc
.SelectObject(&pens
[k
== (uint
) _SelectedCtrlPoint
? 1 : 0]); // slect the red pen if thi ctrl point is selected
306 const CCtrlPoint
&cp
= Curve
->getControlPoint(k
);
307 POINT p
= makePoint(cp
.Date
, cp
.Value
);
308 dc
.MoveTo(p
.x
- CtrlPointSize
, p
.y
- CtrlPointSize
);
309 dc
.LineTo(p
.x
+ CtrlPointSize
, p
.y
- CtrlPointSize
);
310 dc
.LineTo(p
.x
+ CtrlPointSize
, p
.y
+ CtrlPointSize
);
311 dc
.LineTo(p
.x
- CtrlPointSize
, p
.y
+ CtrlPointSize
);
312 dc
.LineTo(p
.x
- CtrlPointSize
, p
.y
- CtrlPointSize
);
313 dc
.SelectObject(oldPen
);
318 void CurveEdit::OnZoomOut()
324 void CurveEdit::OnZoomIn()
330 void CurveEdit::OnGoUp()
332 _Origin
+= (1.f
/ _Scale
) * 0.25f
;
336 void CurveEdit::OnGoDown()
338 _Origin
-= (1.f
/ _Scale
) * 0.25f
;
343 void CurveEdit::drawUnits(CDC
&dc
)
346 pens
[0].CreatePen(PS_SOLID
, 1, (COLORREF
) 0xaaaaaa);
347 pens
[1].CreatePen(PS_SOLID
, 1, (COLORREF
) 0xff0011);
349 sint upVal
= (sint
) floorf(coordsFromScreen(0, _X
).Value
);
350 sint downVal
= (sint
) floorf(coordsFromScreen(0, _X
+ _Width
).Value
);
352 nlassert(upVal
>= downVal
);
353 for (sint k
= downVal
; k
<= upVal
; ++k
)
355 CGdiObject
*oldPen
= dc
.SelectObject(&pens
[k
== 0 ? 1 : 0]);
356 dc
.MoveTo(makePoint(0, (float) k
));
357 dc
.LineTo(makePoint(1, (float) k
));
358 dc
.SelectObject(oldPen
);
362 BOOL
CurveEdit::OnInitDialog()
364 CDialog::OnInitDialog();
366 ((CButton
*) GetDlgItem(IDC_ADD_POINT
))->SetCheck(1);
368 _NumSamplesDlg
= new CEditableRangeUInt(std::string("FLOAT_CURVE_NB_SAMPLE"), _Node
, 1, 512);
369 _NumSampleWrapper
.CE
= this;
370 _NumSamplesDlg
->setWrapper(&_NumSampleWrapper
);
371 _NumSamplesDlg
->init(80, 225, this);
372 _NumSamplesDlg
->enableLowerBound(1, true);
373 m_SmoothingOn
= Curve
->hasSmoothing();
376 return TRUE
; // return TRUE unless you set the focus to a control
377 // EXCEPTION: OCX Property Pages should return FALSE
380 void CurveEdit::OnMovePoint()
383 _SelectedCtrlPoint
= -1;
387 void CurveEdit::OnAddPoint()
390 _SelectedCtrlPoint
= -1;
394 void CurveEdit::OnRemovePoint()
397 _SelectedCtrlPoint
= -1;
401 void CurveEdit::OnDisplayInterpolation()
408 float CurveEdit::getSampledValue(float date
) const
411 nlassert(date
>=0 && date
< 1);
412 NLMISC::OptFastFloorBegin();
413 float result
= (*Curve
)(date
);
414 NLMISC::OptFastFloorEnd();
418 void CurveEdit::OnSmoothingOn()
422 Curve
->enableSmoothing(m_SmoothingOn
? true : false /* perf; warning */);
427 void CurveEdit::OnLastEqualFirst()
429 CCtrlPoint pt
= Curve
->getControlPoint(0);
430 pt
.Date
= Curve
->getControlPoint(Curve
->getNumCtrlPoints() - 1).Date
;
431 Curve
->setCtrlPoint(Curve
->getNumCtrlPoints() - 1, pt
);
435 void CurveEdit::OnCenterCurve()
441 void CurveEdit::OnFirstEqualLast()
443 CCtrlPoint pt
= Curve
->getControlPoint(Curve
->getNumCtrlPoints() - 1);
444 pt
.Date
= Curve
->getControlPoint(0).Date
;
445 Curve
->setCtrlPoint(0, pt
);
449 void CurveEdit::OnDestroy()
451 CDialog::OnDestroy();
454 void CurveEdit::init(CWnd
*pParent
)
456 CDialog::Create(IDD_CURVE_EDIT
, pParent
);
461 void CurveEdit::OnClose()
464 _PN
->childPopupClosed(this);
467 void CurveEdit::invalidate()
471 _Node
->setModified(true);