00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/ps_float.h"
00029 #include "3d/ps_register_float_attribs.h"
00030 #include "3d/fast_floor.h"
00031
00032 namespace NL3D {
00033
00034
00035
00036
00037
00038 float CPSFloatGradient::_DefaultGradient[] = { 0.1f, 1.0f } ;
00039
00040
00042
00044
00045 CPSFloatGradient::CPSFloatGradient(const float *floatTab, uint32 nbValues, uint32 nbStages, float nbCycles)
00046 : CPSValueGradient<float>(nbCycles)
00047 {
00048 _F.setValues(floatTab, nbValues, nbStages) ;
00049 }
00050
00051
00053
00055
00056 CPSFloatCurveFunctor::CPSFloatCurveFunctor() : _NumSamples(128), _Smoothing(true)
00057 {
00058 _CtrlPoints.push_back(CCtrlPoint(0, 0.5f));
00059 _CtrlPoints.push_back(CCtrlPoint(1, 0.5f));
00060 updateTab();
00061 }
00062
00064 void CPSFloatCurveFunctor::sortPoints(void)
00065 {
00066 std::sort(_CtrlPoints.begin(), _CtrlPoints.end());
00067 }
00068
00070 void CPSFloatCurveFunctor::addControlPoint(const CCtrlPoint &ctrlPoint)
00071 {
00072 _CtrlPoints.push_back(ctrlPoint);
00073 sortPoints();
00074 updateTab();
00075 }
00076
00078 const CPSFloatCurveFunctor::CCtrlPoint &CPSFloatCurveFunctor::getControlPoint(uint index) const
00079 {
00080 return _CtrlPoints[index];
00081 }
00082
00084 void CPSFloatCurveFunctor::setCtrlPoint(uint index, const CCtrlPoint &ctrlPoint)
00085 {
00086 nlassert(ctrlPoint.Date >= 0 && ctrlPoint.Date <= 1);
00087 _CtrlPoints[index] = ctrlPoint;
00088 sortPoints();
00089 updateTab();
00090 }
00091
00093 void CPSFloatCurveFunctor::removeCtrlPoint(uint index)
00094 {
00095 nlassert(_CtrlPoints.size() > 1);
00096 _CtrlPoints.erase(_CtrlPoints.begin() + index);
00097 updateTab();
00098 }
00099
00101 void CPSFloatCurveFunctor::setNumSamples(uint32 numSamples)
00102 {
00103 nlassert(numSamples > 0);
00104 _NumSamples = numSamples;
00105 updateTab();
00106 }
00107
00109 float CPSFloatCurveFunctor::getValue(float date) const
00110 {
00111 NLMISC::clamp(date, 0, 1);
00112
00113 std::vector<CCtrlPoint>::const_iterator it = _CtrlPoints.begin();
00114 while ( it != _CtrlPoints.end() && it->Date <= date ) ++it;
00115
00116 if (it == _CtrlPoints.begin()) return _CtrlPoints[0].Value;
00117 if (it == _CtrlPoints.end()) return _CtrlPoints[_CtrlPoints.size() - 1].Value;
00118 std::vector<CCtrlPoint>::const_iterator precIt = it - 1;
00119 if (precIt->Date == it->Date) return 0.5f * (precIt->Value + it->Value);
00120 const float lambda = (date - precIt->Date) / (it->Date - precIt->Date);
00121 if (!_Smoothing)
00122 {
00123 return lambda * it->Value + (1.f - lambda) * precIt->Value;
00124 }
00125 else
00126 {
00127 float width = it->Date - precIt->Date;
00128 uint index = precIt - _CtrlPoints.begin();
00129 float t1 = getSlope(index) * width, t2 = getSlope(index + 1) * width;
00130 const float lambda2 = NLMISC::sqr(lambda);
00131 const float lambda3 = lambda2 * lambda;
00132 const float h1 = 2 * lambda3 - 3 * lambda2 + 1;
00133 const float h2 = - 2 * lambda3 + 3 * lambda2;
00134 const float h3 = lambda3 - 2 * lambda2 + lambda;
00135 const float h4 = lambda3 - lambda2;
00136
00137 return h1 * precIt->Value + h2 * it->Value + h3 * t1 + h4 * t2;
00138 }
00139 }
00140
00142 void CPSFloatCurveFunctor::updateTab(void)
00143 {
00144 float step = 1.f / _NumSamples;
00145 float d = 0.f;
00146 _Tab.resize(_NumSamples + 1);
00147 for (uint k = 0; k <= _NumSamples; ++k)
00148 {
00149 _Tab[k] = getValue(d);
00150 d += step;
00151 }
00152 }
00153
00155 void CPSFloatCurveFunctor::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00156 {
00157 f.serialVersion(1);
00158 f.serial(_NumSamples, _Smoothing);
00159 f.serialCont(_CtrlPoints);
00160 if (f.isReading())
00161 {
00162 updateTab();
00163 }
00164 }
00165
00167 float CPSFloatCurveFunctor::getSlope(uint index) const
00168 {
00169
00170 if (index == 0)
00171 {
00172 return _CtrlPoints[1].Date != _CtrlPoints[0].Date ? (_CtrlPoints[1].Value - _CtrlPoints[0].Value)
00173 / (_CtrlPoints[1].Date - _CtrlPoints[0].Date)
00174 : 1e6f;
00175 }
00176
00177
00178 if (index == _CtrlPoints.size() - 1)
00179 {
00180 return _CtrlPoints[index].Date != _CtrlPoints[index - 1].Date ? (_CtrlPoints[index].Value - _CtrlPoints[index - 1].Value)
00181 / (_CtrlPoints[index].Date - _CtrlPoints[index - 1].Date)
00182 : 1e6f;
00183 }
00184
00185
00186 return _CtrlPoints[index + 1].Date != _CtrlPoints[index - 1].Date ? (_CtrlPoints[index + 1].Value - _CtrlPoints[index - 1].Value)
00187 / (_CtrlPoints[index + 1].Date - _CtrlPoints[index - 1].Date)
00188 : 1e6f;
00189 }
00190
00192 void CPSFloatCurveFunctor::enableSmoothing(bool enable )
00193 {
00194 _Smoothing = enable;
00195 updateTab();
00196 }
00197
00199 void PSRegisterFloatAttribs()
00200 {
00201 NLMISC_REGISTER_CLASS(CPSFloatBlender);
00202 NLMISC_REGISTER_CLASS(CPSFloatGradient);
00203 NLMISC_REGISTER_CLASS(CPSFloatMemory);
00204 NLMISC_REGISTER_CLASS(CPSFloatBinOp);
00205 NLMISC_REGISTER_CLASS(CPSFloatCurve);
00206 }
00207
00208 }