Merge branch 'ryzom/ark-features' into main/gingo-test
[ryzomcore.git] / nel / src / 3d / ps_float.cpp
blob7c364f2b852772b734a6a8e5bcc6e0e29142ca0f
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/ps_float.h"
20 #include "nel/3d/ps_register_float_attribs.h"
21 #include "nel/misc/fast_floor.h"
23 #ifdef DEBUG_NEW
24 #define new DEBUG_NEW
25 #endif
27 namespace NL3D {
30 /////////////////////////////////////
31 // CPSFloatGradient implementation //
32 /////////////////////////////////////
34 CPSFloatGradient::CPSFloatGradient(const float *floatTab, uint32 nbValues, uint32 nbStages, float nbCycles)
35 : CPSValueGradient<float>(nbCycles)
37 _F.setValues(floatTab, nbValues, nbStages) ;
41 ////////////////////////////////////////////
42 // CPSFloatBezierCurve implementation //
43 ////////////////////////////////////////////
45 CPSFloatCurveFunctor::CPSFloatCurveFunctor() : _NumSamples(0), _Smoothing(true)
48 _CtrlPoints.push_back(CCtrlPoint(0, 0.5f));
49 _CtrlPoints.push_back(CCtrlPoint(1, 0.5f));
50 updateTab();
54 ///=======================================================================================
55 void CPSFloatCurveFunctor::sortPoints(void)
57 std::sort(_CtrlPoints.begin(), _CtrlPoints.end());
60 ///=======================================================================================
61 void CPSFloatCurveFunctor::addControlPoint(const CCtrlPoint &ctrlPoint)
63 _CtrlPoints.push_back(ctrlPoint);
64 sortPoints();
65 updateTab();
68 ///=======================================================================================
69 const CPSFloatCurveFunctor::CCtrlPoint &CPSFloatCurveFunctor::getControlPoint(uint index) const
71 return _CtrlPoints[index];
74 ///=======================================================================================
75 void CPSFloatCurveFunctor::setCtrlPoint(uint index, const CCtrlPoint &ctrlPoint)
77 nlassert(ctrlPoint.Date >= 0 && ctrlPoint.Date <= 1);
78 _CtrlPoints[index] = ctrlPoint;
79 sortPoints();
80 updateTab();
83 ///=======================================================================================
84 void CPSFloatCurveFunctor::removeCtrlPoint(uint index)
86 nlassert(_CtrlPoints.size() > 1);
87 _CtrlPoints.erase(_CtrlPoints.begin() + index);
88 updateTab();
91 ///=======================================================================================
92 void CPSFloatCurveFunctor::setNumSamples(uint32 numSamples)
94 nlassert(numSamples > 0);
95 _NumSamples = numSamples;
96 updateTab();
99 ///=======================================================================================
100 float CPSFloatCurveFunctor::getValue(float date) const
102 if (_CtrlPoints.empty()) return 0.f;
103 NLMISC::clamp(date, 0, 1);
104 // find a key that has a higher value
105 CPSVector<CCtrlPoint>::V::const_iterator it = _CtrlPoints.begin();
106 while ( it != _CtrlPoints.end() && it->Date <= date ) ++it;
108 if (it == _CtrlPoints.begin()) return _CtrlPoints[0].Value;
109 if (it == _CtrlPoints.end()) return _CtrlPoints[_CtrlPoints.size() - 1].Value;
110 CPSVector<CCtrlPoint>::V::const_iterator precIt = it - 1;
111 if (precIt->Date == it->Date) return 0.5f * (precIt->Value + it->Value);
112 const float lambda = (date - precIt->Date) / (it->Date - precIt->Date);
113 if (!_Smoothing) // linear interpolation
115 return lambda * it->Value + (1.f - lambda) * precIt->Value;
117 else // hermite interpolation
119 float width = it->Date - precIt->Date;
120 uint index = (uint)(precIt - _CtrlPoints.begin());
121 float t1 = getSlope(index) * width, t2 = getSlope(index + 1) * width;
122 const float lambda2 = NLMISC::sqr(lambda);
123 const float lambda3 = lambda2 * lambda;
124 const float h1 = 2 * lambda3 - 3 * lambda2 + 1;
125 const float h2 = - 2 * lambda3 + 3 * lambda2;
126 const float h3 = lambda3 - 2 * lambda2 + lambda;
127 const float h4 = lambda3 - lambda2;
129 return h1 * precIt->Value + h2 * it->Value + h3 * t1 + h4 * t2;
133 ///=======================================================================================
134 void CPSFloatCurveFunctor::updateTab(void)
136 float step = 1.f / _NumSamples;
137 float d = 0.f;
138 _Tab.resize(_NumSamples + 1);
139 uint k;
140 for (k = 0; k <= _NumSamples; ++k)
142 _Tab[k] = getValue(d);
143 d += step;
145 _MinValue = _MaxValue = _Tab[0];
146 for (k = 1; k <= _NumSamples; ++k)
148 _MinValue = std::min(_MinValue, _Tab[k]);
149 _MaxValue = std::max(_MaxValue, _Tab[k]);
153 ///=======================================================================================
154 void CPSFloatCurveFunctor::serial(NLMISC::IStream &f)
156 f.serialVersion(1);
157 f.serial(_NumSamples, _Smoothing);
158 f.serialCont(_CtrlPoints);
159 if (f.isReading())
161 updateTab();
165 ///=======================================================================================
166 float CPSFloatCurveFunctor::getSlope(uint index) const
168 // tangent for first point
169 if (index == 0)
171 return _CtrlPoints[1].Date != _CtrlPoints[0].Date ? (_CtrlPoints[1].Value - _CtrlPoints[0].Value)
172 / (_CtrlPoints[1].Date - _CtrlPoints[0].Date)
173 : 1e6f;
176 // tangent for last point
177 if (index == _CtrlPoints.size() - 1)
179 return _CtrlPoints[index].Date != _CtrlPoints[index - 1].Date ? (_CtrlPoints[index].Value - _CtrlPoints[index - 1].Value)
180 / (_CtrlPoints[index].Date - _CtrlPoints[index - 1].Date)
181 : 1e6f;
184 // tangent for other points
185 return _CtrlPoints[index + 1].Date != _CtrlPoints[index - 1].Date ? (_CtrlPoints[index + 1].Value - _CtrlPoints[index - 1].Value)
186 / (_CtrlPoints[index + 1].Date - _CtrlPoints[index - 1].Date)
187 : 1e6f;
190 ///=======================================================================================
191 void CPSFloatCurveFunctor::enableSmoothing(bool enable /* = true*/)
193 _Smoothing = enable;
194 updateTab();
197 ///=======================================================================================
198 void PSRegisterFloatAttribs()
200 NLMISC_REGISTER_CLASS(CPSFloatBlender);
201 NLMISC_REGISTER_CLASS(CPSFloatGradient);
202 NLMISC_REGISTER_CLASS(CPSFloatMemory);
203 NLMISC_REGISTER_CLASS(CPSFloatBinOp);
204 NLMISC_REGISTER_CLASS(CPSFloatCurve);
207 } // NL3D