00001
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00079 if(_FatherSkeletonModel)
00080 {
00081
00082
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;
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;
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
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
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
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
00196
00197
00198
00199
00200
00201 for (;;)
00202 {
00203 float dt = currIt->SamplingDate - (currIt + 1)->SamplingDate;
00204
00205 if (dt < 10E-6f)
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
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
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
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
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
00434 sr->restart();
00435 }
00436 else
00437 {
00438
00439 sr->stopNoUnroll();
00440 }
00441 }
00442 _LastSampleFrame = scene->getNumRender();
00443 sr->setupFromShape();
00444 sr->samplePos((float) scene->getCurrentTime());
00445
00448
00449
00450
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 }