# 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  

seg_remanence.cpp

Go to the documentation of this file.
00001 
00006 /* Copyright, 2000, 2001, 2002 Nevrax Ltd.
00007  *
00008  * This file is part of NEVRAX NEL.
00009  * NEVRAX NEL is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2, or (at your option)
00012  * any later version.
00013 
00014  * NEVRAX NEL is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017  * General Public License for more details.
00018 
00019  * You should have received a copy of the GNU General Public License
00020  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00021  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00022  * MA 02111-1307, USA.
00023  */
00024 
00025 #include "std3d.h"
00026 
00027 #include "3d/seg_remanence.h"
00028 #include "3d/seg_remanence_shape.h"
00029 #include "3d/vertex_buffer.h"
00030 #include "3d/driver.h"
00031 #include "3d/scene.h"
00032 #include "3d/anim_detail_trav.h"
00033 #include "3d/skeleton_model.h"
00034 
00035 
00036 
00037 
00038 namespace NL3D
00039 {
00040 
00042 static inline void BuildHermiteVector(const NLMISC::CVector &P0,
00043                                                            const NLMISC::CVector &P1,
00044                                                            const NLMISC::CVector &T0,
00045                                                            const NLMISC::CVector &T1,
00046                                                                          NLMISC::CVector &dest,                                                                  
00047                                                            float lambda
00048                                                            )
00049 {       
00050         const float lambda2 = lambda * lambda;
00051         const float lambda3 = lambda2 * lambda;
00052         const float h1 = 2 * lambda3 - 3 * lambda2 + 1; 
00053         const float h2 = - 2 * lambda3 + 3 * lambda2; 
00054         const float h3 = lambda3 - 2 * lambda2 + lambda; 
00055         const float h4 = lambda3 - lambda2;
00057         dest.set (h1 * P0.x + h2 * P1.x + h3 * T0.x + h4 * T1.x,
00058                           h1 * P0.y + h2 * P1.y + h3 * T0.y + h4 * T1.y,
00059                           h1 * P0.z + h2 * P1.z + h3 * T0.z + h4 * T1.z);
00060 
00061 }
00062 
00063 //===============================================================
00064 CSegRemanence::CSegRemanence() : _NumSlice(0),
00065                                                                  _Started(false),
00066                                                                  _Stopping(false),
00067                                                                  _Restarted(false),
00068                                                                  _UnrollRatio(0),
00069                                                                  _AniMat(NULL)
00070 {       
00071         IAnimatable::resize(AnimValueLast);
00072 }
00073 
00074 //===============================================================
00075 CSegRemanence::~CSegRemanence()
00076 {
00077         delete _AniMat;
00078         // Auto detach me from skeleton. Must do it here, not in ~CTransform().
00079         if(_FatherSkeletonModel)
00080         {
00081                 // detach me from the skeleton.
00082                 // Observers hierarchy is modified.
00083                 _FatherSkeletonModel->detachSkeletonSon(this);
00084                 nlassert(_FatherSkeletonModel==NULL);
00085         }
00086 }
00087 
00088 //===============================================================
00089 CSegRemanence::CSegRemanence(CSegRemanence &other)      : CTransformShape(other), _AniMat(NULL)
00090 {
00091         copyFromOther(other);
00092 }
00093 
00094 //===============================================================
00095 CSegRemanence &CSegRemanence::operator = (CSegRemanence &other)
00096 {
00097         if (this != &other)
00098         {       
00099                 (CTransformShape &) *this = (CTransformShape &) other; // copy base
00100                 copyFromOther(other);
00101         }
00102         return *this;
00103 }
00104 
00105 //===============================================================
00106 void CSegRemanence::copyFromOther(CSegRemanence &other)
00107 {
00108         if (this == &other) return;
00109         
00110         CAnimatedMaterial   *otherMat = other._AniMat != NULL ? new CAnimatedMaterial(*other._AniMat)
00111                                                                                                                   : NULL;
00112         delete _AniMat;
00113         _AniMat = otherMat;
00114 
00115         _Ribbons        = other._Ribbons; // sampled positions at each extremities of segment
00116         _NumSlice       = other._NumSlice;
00117         _NumCorners = other._NumCorners;
00118         _Started    = other._Started;
00119         _Restarted  = other._Restarted;
00120         _Stopping   = other._Stopping;
00121         _StartDate  = other._StartDate;
00122         _CurrDate   = other._CurrDate;
00123         
00124 }
00125 
00126 //===============================================================
00127 void CSegRemanence::registerBasic()
00128 {
00129         CMOT::registerModel(SegRemanenceShapeId, TransformShapeId, CSegRemanence::creator);     
00130 //      CMOT::registerObs (HrcTravId, SegRemanenceShapeId, CSegRemanenceHrcObs::creator);
00131         CMOT::registerObs(AnimDetailTravId, SegRemanenceShapeId, CSegRemanenceAnimDetailObs::creator);
00132 }
00133 
00134 
00135 //===============================================================
00136 void CSegRemanence::render(IDriver *drv, CVertexBuffer &vb, CPrimitiveBlock &pb, CMaterial &mat)
00137 {
00138         CSegRemanenceShape *srs = NLMISC::safe_cast<CSegRemanenceShape *>((IShape *) Shape);            
00139         const uint vertexSize = vb.getVertexSize();
00140         uint8 *datas = (uint8 *) vb.getVertexCoordPointer();
00141         uint numCorners = _Ribbons.size();
00142         for(uint k = 0; k < numCorners; ++k)
00143         {
00144                 _Ribbons[k].fillVB(datas, vertexSize, srs->getNumSlices(), srs->getSliceTime());
00145                 datas += (_NumSlice + 1) * vertexSize;
00146         }       
00147         
00148         // roll / unroll using texture matrix
00149         CMatrix texMat; 
00150         texMat.setPos(NLMISC::CVector(1.f - _UnrollRatio, 0, 0));
00151         if (mat.getTexture(0) != NULL)
00152                 mat.setUserTexMat(0, texMat);
00153         
00154         
00155         
00156         drv->activeVertexBuffer(vb);    
00157         drv->render(pb, mat);
00158 
00159         CScene *scene = NLMISC::safe_cast<ITravScene *>(_HrcObs->Trav)->Scene;
00160         // change unroll ratio
00161         if (!_Stopping)
00162         {
00163                 if (_UnrollRatio != 1.f)
00164                 _UnrollRatio = std::min(1.f, _UnrollRatio + scene->getEllapsedTime() / (srs->getNumSlices() * srs->getSliceTime()));
00165         }
00166         else
00167         {
00168                 _UnrollRatio = std::max(0.f, _UnrollRatio - srs->getRollupRatio() * scene->getEllapsedTime() / (srs->getNumSlices() * srs->getSliceTime()));
00169                 if (_UnrollRatio == 0.f)
00170                 {
00171                         _Stopping = false;
00172                         _Started = false;
00173                 }
00174         }
00175 }
00176 
00177 //===============================================================
00178 CSegRemanence::CRibbon::CRibbon() : _LastSamplingDate(0)
00179 {
00180 }
00181 
00182 //===============================================================
00183 void CSegRemanence::CRibbon::fillVB(uint8 *dest, uint stride, uint nbSegs, float sliceTime)
00184 {               
00185         TSampledPosVect::iterator currIt      = _Ribbon.begin();                        
00186 
00187         NLMISC::CVector t0 = (currIt + 1)->Pos - currIt->Pos;
00188         NLMISC::CVector t1 = 0.5f * ((currIt + 2)->Pos - currIt->Pos);
00189 
00190         uint leftToDo = nbSegs + 1;
00191 
00192         float lambda = 0.f;
00193         float lambdaStep = 1.f;
00194 
00195 /*      nlinfo("===============================");
00196         for(uint k = 0; k < _Ribbon.size(); ++k)
00197         {
00198                 nlinfo("pos = (%.2f, %.2f, %.2f)", _Ribbon[k].Pos.x, _Ribbon[k].Pos.y, _Ribbon[k].Pos.z);
00199         }*/
00200 
00201         for (;;)
00202         {               
00203                 float dt = currIt->SamplingDate - (currIt + 1)->SamplingDate;
00204 
00205                 if (dt < 10E-6f) // we reached the start of ribbon
00206                 {
00207 
00208                         do
00209                         {
00210                                 (NLMISC::CVector &) *dest = currIt->Pos;
00211                                 dest  += stride;
00212                         }
00213                         while (--leftToDo);                     
00214                         return;
00215                 }
00216 
00217                 float newLambdaStep = sliceTime / dt;
00218                 // readapt lambda
00219                 lambda *= newLambdaStep / lambdaStep;
00220                 lambdaStep = newLambdaStep;
00221                 for(;;)
00222                 {
00223                         if (lambda >= 1.f) break;
00225                         BuildHermiteVector(currIt->Pos, (currIt + 1)->Pos, t0, t1, (NLMISC::CVector &) *dest, lambda);
00226                         dest  += stride;
00227                         -- leftToDo;
00228                         if (!leftToDo) return;                                                                                          
00229                         lambda += lambdaStep;                   
00230                 }
00231                 
00232                 lambda -= 1.f;
00233 
00234                 // Start new segment and compute new tangents
00235                 t0 = t1;
00236                 ++currIt;               
00237                 t1 = 0.5f * ((currIt + 2)->Pos - currIt->Pos);
00238         }        
00239 }
00240 
00241 //===============================================================
00242 void CSegRemanence::CRibbon::duplicateFirstPos()
00243 {
00244         uint ribSize = _Ribbon.size();
00245         for(uint k = 1; k < ribSize; ++k)
00246         {
00247                 _Ribbon[k] = _Ribbon[0];
00248         }
00249 }
00250 
00251 //===============================================================
00252 void CSegRemanence::setupFromShape()
00253 {
00254         CSegRemanenceShape *srs = NLMISC::safe_cast<CSegRemanenceShape *>((IShape *) Shape);            
00255         if (srs->getNumCorners() != _NumCorners || srs->getNumSlices() != _NumSlice)
00256         {
00257                 _Ribbons.resize(srs->getNumCorners());
00258                 for(uint k = 0; k < _Ribbons.size(); ++k)
00259                 {
00260                         _Ribbons[k].setNumSlices(srs->getNumSlices());
00261                 }               
00262                 _NumCorners = srs->getNumCorners();
00263                 _NumSlice  = srs->getNumSlices();
00264         }
00265         updateOpacityFromShape();
00266 }
00267 
00268 
00269 //===============================================================
00270 void CSegRemanence::CRibbon::setNumSlices(uint numSegs)
00271 {       
00272         _Ribbon.resize(numSegs + 3);
00273 }
00274 
00275 //===============================================================
00276 void CSegRemanence::CRibbon::samplePos(const NLMISC::CVector &pos, float date, float sliceDuration)
00277 {
00278         nlassert(_Ribbon.size() != 0);
00279         if (date - _LastSamplingDate > sliceDuration)
00280         {
00281                 _Ribbon.pop_back();
00282                 CSampledPos sp(pos, date);
00283                 _Ribbon.push_front(sp);
00284                 _LastSamplingDate = date;
00285         }
00286         else
00287         {
00288                 _Ribbon.front().Pos = pos;
00289                 _Ribbon.front().SamplingDate = date;
00290         }
00291 }
00292 
00293 //===============================================================
00294 void CSegRemanence::samplePos(float date)
00295 {
00296         if (_Started)
00297         {       
00298                 IBaseHrcObs *bho = (IBaseHrcObs *) getObs(HrcTravId);
00299                 CSegRemanenceShape *srs = NLMISC::safe_cast<CSegRemanenceShape *>((IShape *) Shape);
00300                 uint numCorners = _Ribbons.size();
00301                 for(uint k = 0; k < numCorners; ++k)
00302                 {               
00303                         _Ribbons[k].samplePos(bho->WorldMatrix * srs->getCorner(k), date, srs->getSliceTime());
00304                 }
00305                 if (_Restarted)
00306                 {
00307                         for(uint k = 0; k < numCorners; ++k)
00308                         {
00309                                 _Ribbons[k].duplicateFirstPos();
00310                         }
00311                         _Restarted = false;
00312                         _StartDate = date;
00313                 }
00314                 _CurrDate = date;
00315         }
00316 }
00317 
00318 //===============================================================
00319 /*
00320 void CSegRemanenceHrcObs::traverse(IObs *caller)
00321 {
00322         CTransformHrcObs::traverse (caller);
00323         CSegRemanence *sr = static_cast<CSegRemanence *>(this->Model);
00324         if (sr->isStarted())
00325         {       
00326                 CScene *scene = NLMISC::safe_cast<ITravScene *>(Trav)->Scene;
00327                 if (scene->getNumRender() != (_LastSampleFrame + 1))
00328                 {
00329                         if (!sr->isStopping())
00330                         {                       
00331                                 // if wasn't visible at previous frame, must invalidate position
00332                                 sr->restart();
00333                         }
00334                         else
00335                         {
00336                                 // ribbon started unrolling when it disapperaed from screen so simply remove it
00337                                 sr->stopNoUnroll();
00338                         }
00339                 }               
00340                 _LastSampleFrame = scene->getNumRender();
00341                 sr->setupFromShape();
00342                 sr->samplePos((float) scene->getCurrentTime());
00343         }
00344 }
00345 */
00346 
00347 /*
00348 //===============================================================
00349 CSegRemanenceHrcObs::CSegRemanenceHrcObs() : _LastSampleFrame(0)
00350 {       
00351 }
00352 */
00353 
00354 //===============================================================
00355 void CSegRemanence::start()
00356 {
00357         if (_Started && !_Stopping) return;
00358         restart();              
00359 }
00360 
00361 //===============================================================
00362 void CSegRemanence::restart()
00363 {
00364         CSegRemanenceShape *srs = NLMISC::safe_cast<CSegRemanenceShape *>((IShape *) Shape);    
00365         if (!srs->getTextureShifting())
00366         {       
00367                 _UnrollRatio = 1.f;
00368         }
00369         else
00370         {
00371                 if (!_Stopping)
00372                         _UnrollRatio = 0.f;
00373         }
00374         _Started = _Restarted = true;
00375         _Stopping = false;      
00376 }
00377 
00378 //===============================================================
00379 void CSegRemanence::stop()
00380 {
00381         _Stopping = true;
00382 }
00383 
00384 //===============================================================
00385 void CSegRemanence::stopNoUnroll()
00386 {
00387         _Started = _Restarted = _Stopping = false;
00388 }
00389 
00390 //===============================================================
00391 void CSegRemanence::updateOpacityFromShape()
00392 {
00393         CSegRemanenceShape *srs = NLMISC::safe_cast<CSegRemanenceShape *>((IShape *) Shape);
00394         bool transparent = srs->getMaterial().getBlend();
00395         setTransparency(transparent);
00396         setOpacity(!transparent);
00397 }
00398 
00399 //===============================================================
00400 void CSegRemanence::setAnimatedMaterial(CAnimatedMaterial *mat)
00401 {
00402         if (mat == _AniMat) return;
00403         delete _AniMat;
00404         _AniMat = mat;
00405         _AniMat->setFather(this, OwnerBit);
00406 }
00407 
00408 //===============================================================
00409 void CSegRemanence::registerToChannelMixer(CChannelMixer *chanMixer, const std::string &prefix)
00410 {       
00411         CTransformShape::registerToChannelMixer(chanMixer, prefix);
00412         if (_AniMat)
00413         {
00414                 _AniMat->registerToChannelMixer(chanMixer, prefix + _AniMat->getMaterialName() + ".")   ;
00415         }
00416 }
00417 
00418 //===============================================================
00419 void CSegRemanenceAnimDetailObs::traverse(IObs *caller)
00420 {
00421         CTransformAnimDetailObs::traverse(caller);
00422         CSegRemanence *sr = NLMISC::safe_cast<CSegRemanence *>(Model);
00423         if (sr->isStarted())
00424         {       
00427 
00428                 CScene *scene = NLMISC::safe_cast<ITravScene *>(Trav)->Scene;
00429                 if (scene->getNumRender() != (_LastSampleFrame + 1))
00430                 {
00431                         if (!sr->isStopping())
00432                         {                       
00433                                 // if wasn't visible at previous frame, must invalidate position
00434                                 sr->restart();
00435                         }
00436                         else
00437                         {
00438                                 // ribbon started unrolling when it disapperaed from screen so simply remove it
00439                                 sr->stopNoUnroll();
00440                         }
00441                 }               
00442                 _LastSampleFrame = scene->getNumRender();
00443                 sr->setupFromShape();
00444                 sr->samplePos((float) scene->getCurrentTime());
00445 
00448 
00449         
00450                 // test if animated material must be updated.
00451                 if(sr->IAnimatable::isTouched(CSegRemanence::OwnerBit))
00452                 {
00453                         if (sr->getAnimatedMaterial())
00454                                 sr->getAnimatedMaterial()->update();                    
00455                         sr->clearAnimatedMatFlag();
00456                 }
00457         }
00458 }
00459 
00460 CSegRemanenceAnimDetailObs::CSegRemanenceAnimDetailObs() : _LastSampleFrame(0)
00461 {       
00462 }
00463 
00464 
00465 
00466 }