# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

ps_float.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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 // CPSFloatGradient implementation //
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 // CPSFloatBezierCurve implementation     //
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         // find a key that has a higher value
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) // linear interpolation
00122         {               
00123                 return lambda * it->Value + (1.f - lambda) * precIt->Value;
00124         }
00125         else // hermite interpolation
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         // tangent for first point
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         // tangent for last point
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         // tangent for other points
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 /* = true*/)
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 } // NL3D