00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026 #include "nel/3d/ps_ribbon_look_at.h"
00027 #include "nel/3d/particle_system.h"
00028 #include "nel/3d/ps_macro.h"
00029 #include "nel/3d/driver.h"
00030
00031 namespace NL3D
00032 {
00033
00035
00037
00038 const float ZEpsilon = 10E-3f;
00039 const float NormEpsilon = 10E-8f;
00040
00041
00042 struct CVectInfo
00043 {
00044 NLMISC::CVector Interp;
00045 NLMISC::CVector Proj;
00046 };
00047 typedef std::vector<CVectInfo> TRibbonVect;
00048
00049 CPSRibbonLookAt::TVBMap CPSRibbonLookAt::_VBMap;
00050 CPSRibbonLookAt::TVBMap CPSRibbonLookAt::_ColoredVBMap;
00051
00052
00053 CPSRibbonLookAt::CPSRibbonLookAt()
00054 {
00055 NL_PS_FUNC(CPSRibbonLookAt_CPSRibbonLookAt)
00056 }
00057
00058
00059 CPSRibbonLookAt::~CPSRibbonLookAt()
00060 {
00061 NL_PS_FUNC(CPSRibbonLookAt_CPSRibbonLookAtDtor)
00062
00063 }
00064
00065
00066 void CPSRibbonLookAt::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00067 {
00068 NL_PS_FUNC(CPSRibbonLookAt_serial)
00072 sint ver = f.serialVersion(4);
00073 if (ver > 3)
00074 {
00075 CPSRibbonBase::serial(f);
00076 }
00077 else
00078 {
00079 CPSParticle::serial(f);
00080 }
00081 CPSColoredParticle::serialColorScheme(f);
00082 CPSSizedParticle::serialSizeScheme(f);
00083 serialMaterial(f);
00084 uint32 dummy = 0;
00085 if (ver <= 3)
00086 {
00087 f.serial(_SegDuration, _NbSegs, dummy );
00088 }
00089 ITexture *tex = NULL;
00090
00091 if (ver > 2)
00092 {
00093 f.serial(_Parametric);
00094 }
00095
00096
00097 if (!f.isReading())
00098 {
00099 tex = _Tex;
00100 f.serialPolyPtr(tex);
00101 }
00102 else
00103 {
00104 f.serialPolyPtr(tex);
00105 setTexture(tex);
00106 _Tex = tex;
00107 if (_Tex)
00108 {
00109 _Tex->setWrapS(ITexture::Clamp);
00110 _Tex->setWrapT(ITexture::Clamp);
00111 }
00112 setTailNbSeg(_NbSegs);
00113 }
00114 }
00115
00116
00117
00118 void CPSRibbonLookAt::setTexture(CSmartPtr<ITexture> tex)
00119 {
00120 NL_PS_FUNC(CPSRibbonLookAt_setTexture)
00121 _Tex = tex;
00122 if (_Tex)
00123 {
00124 _Tex->setWrapS(ITexture::Clamp);
00125 _Tex->setWrapT(ITexture::Clamp);
00126 }
00127 updateMatAndVbForColor();
00128 }
00129
00130
00131
00132 void CPSRibbonLookAt::step(TPSProcessPass pass)
00133 {
00134 NL_PS_FUNC(CPSRibbonLookAt_step)
00135 if (pass == PSMotion)
00136 {
00137 if (!_Parametric)
00138 {
00139 updateGlobals();
00140 }
00141 }
00142 else
00143 if (
00144 (pass == PSBlendRender && hasTransparentFaces())
00145 || (pass == PSSolidRender && hasOpaqueFaces())
00146 )
00147 {
00148 uint32 step;
00149 uint numToProcess;
00150 computeSrcStep(step, numToProcess);
00151 if (!numToProcess) return;
00152
00154 CParticleSystem &ps = *(_Owner->getOwner());
00155 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00156 {
00157 _Mat.setColor(ps.getGlobalColorLighted());
00158 }
00159 else
00160 {
00161 _Mat.setColor(ps.getGlobalColor());
00162 }
00166 displayRibbons(numToProcess, step);
00167 }
00168 else
00169 if (pass == PSToolRender)
00170 {
00171
00172 }
00173 }
00174
00175
00176
00177 void CPSRibbonLookAt::newElement(const CPSEmitterInfo &info)
00178 {
00179 NL_PS_FUNC(CPSRibbonLookAt_newElement)
00180 CPSRibbonBase::newElement(info);
00181 newColorElement(info);
00182 newSizeElement(info);
00183 }
00184
00185
00186
00187 void CPSRibbonLookAt::deleteElement(uint32 index)
00188 {
00189 NL_PS_FUNC(CPSRibbonLookAt_deleteElement)
00190 CPSRibbonBase::deleteElement(index);
00191 deleteColorElement(index);
00192 deleteSizeElement(index);
00193 }
00194
00195
00196
00197 void CPSRibbonLookAt::resize(uint32 size)
00198 {
00199 NL_PS_FUNC(CPSRibbonLookAt_resize)
00200 nlassert(size < (1 << 16));
00201 CPSRibbonBase::resize(size);
00202 resizeColor(size);
00203 resizeSize(size);
00204 }
00205
00206
00207 void CPSRibbonLookAt::updateMatAndVbForColor(void)
00208 {
00209 NL_PS_FUNC(CPSRibbonLookAt_updateMatAndVbForColor)
00210 _Mat.setTexture(0, _Tex);
00211 _Mat.setDoubleSided(true);
00212 }
00213
00214
00215 static inline void MakeProj(NLMISC::CVector &dest, const NLMISC::CVector &src)
00216 {
00217 NL_PS_FUNC(MakeProj)
00218 if (fabsf(src.y) > NormEpsilon * NormEpsilon)
00219 {
00220 dest.x = src.x / src.y;
00221 dest.z = src.z / src.y;
00222 dest.y = src.y;
00223 }
00224 }
00225
00226 static inline void BuildSlice(const NLMISC::CMatrix &mat, CVertexBuffer &vb, uint8 *currVert, uint32 vertexSize,
00227 const NLMISC::CVector &I,
00228 const NLMISC::CVector &K,
00229 TRibbonVect::iterator pos,
00230 TRibbonVect::iterator prev,
00231 TRibbonVect::iterator next,
00232 float ribSize)
00234 {
00235 NL_PS_FUNC(BuildSlice)
00236 CHECK_VERTEX_BUFFER(vb, currVert);
00237 CHECK_VERTEX_BUFFER(vb, currVert);
00238 NLMISC::CVector tangent;
00239
00240 float invTgNorm;
00241 float tgNorm;
00242
00243 if (prev->Proj.y > ZEpsilon && next->Proj.y > ZEpsilon)
00244 {
00245 tangent = next->Proj - prev->Proj;
00246 tangent.y = 0;
00247 tgNorm = tangent.norm();
00248 if (fabs(tgNorm) > 10E-8)
00249 {
00250 invTgNorm = 1.f / tgNorm;
00251 }
00252 else
00253 {
00254 invTgNorm = 1.f;
00255 }
00256
00257 *(NLMISC::CVector *) currVert = pos->Interp + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00258 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00259 }
00260 else if (prev->Proj.y > ZEpsilon)
00261 {
00262
00263 NLMISC::CVector inter;
00264 NLMISC::CVector tInter = CVector::Null;
00265 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00266 {
00267 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00268 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00269 MakeProj(tInter, mat * inter);
00270 }
00271 else
00272 {
00273 *(NLMISC::CVector *) currVert = pos->Interp;
00274 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00275 return;
00276 }
00277
00278 tangent = tInter - prev->Proj;
00279 tangent.y = 0;
00280
00281 tgNorm = tangent.norm();
00282 if (fabs(tgNorm) > 10E-8)
00283 {
00284 invTgNorm = 1.f / tgNorm;
00285 }
00286 else
00287 {
00288 invTgNorm = 1.f;
00289 }
00290
00291
00292 *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00293 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00294 }
00295 else if (next->Proj.y > ZEpsilon)
00296 {
00297
00298 NLMISC::CVector inter;
00299 NLMISC::CVector tInter = NLMISC::CVector::Null;
00300 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00301 {
00302 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00303 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00304 MakeProj(tInter, mat * inter);
00305 }
00306 else
00307 {
00308 *(NLMISC::CVector *) currVert = pos->Interp;
00309 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00310 return;
00311 }
00312
00313 tangent = next->Proj - tInter;
00314 tangent.y = 0;
00315 tgNorm = tangent.norm();
00316 if (fabs(tgNorm) > 10E-8)
00317 {
00318 invTgNorm = 1.f / tgNorm;
00319 }
00320 else
00321 {
00322 invTgNorm = 1.f;
00323 }
00324
00325
00326 *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00327 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00328
00329 }
00330 else
00331 {
00332 *(NLMISC::CVector *) currVert = pos->Interp;
00333 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00334 }
00335
00336 }
00337
00338
00339
00340 void CPSRibbonLookAt::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00341 {
00342
00343 NL_PS_FUNC(CPSRibbonLookAt_displayRibbons)
00344 if (!nbRibbons) return;
00345 nlassert(_Owner);
00346 CPSRibbonBase::updateLOD();
00347 if (_UsedNbSegs < 2) return;
00348 const float date = _Owner->getOwner()->getSystemDate();
00349 uint8 *currVert;
00350 CVBnPB &VBnPB = getVBnPB();
00351 CVertexBuffer &VB = VBnPB.VB;
00352 CIndexBuffer &PB = VBnPB.PB;
00353 const uint32 vertexSize = VB.getVertexSize();
00354 uint colorOffset=0;
00355 const uint32 vertexSizeX2 = vertexSize << 1;
00356 const NLMISC::CVector I = _Owner->computeI();
00357 const NLMISC::CVector K = _Owner->computeK();
00358 const NLMISC::CMatrix &localToWorldMatrix = getLocalToWorldTrailMatrix();
00359 const NLMISC::CMatrix &mat = getViewMat() * localToWorldMatrix;
00360 IDriver *drv = this->getDriver();
00361 #ifdef NL_DEBUG
00362 nlassert(drv);
00363 #endif
00364 drv->setupModelMatrix(localToWorldMatrix);
00365 _Owner->incrementNbDrawnParticles(nbRibbons);
00366 const uint numRibbonBatch = getNumRibbonsInVB();
00367 static TRibbonVect currRibbon;
00368 static std::vector<float> sizes;
00369 static std::vector<NLMISC::CRGBA> colors;
00370
00371 if (_UsedNbSegs == 0) return;
00372
00373 currRibbon.resize(_UsedNbSegs + 1);
00374 sizes.resize(numRibbonBatch);
00375
00376
00378 CParticleSystem &ps = *(_Owner->getOwner());
00379 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00380 {
00381 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColorLighted());
00382 }
00383 else
00384 if (ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed())
00385 {
00386 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());
00387 }
00388 else
00389 {
00390 forceModulateConstantColor(false);
00391 _Mat.setColor(ps.getGlobalColor());
00392 }
00393
00394 if (_ColorScheme)
00395 {
00396 colorOffset = VB.getColorOff();
00397 colors.resize(numRibbonBatch);
00398 }
00399
00400
00401
00402 uint toProcess;
00403 uint ribbonIndex = 0;
00404 uint32 fpRibbonIndex = 0;
00405 if (_ColorScheme)
00406 {
00407 _ColorScheme->setColorType(drv->getVertexColorFormat());
00408 }
00409 do
00410 {
00411 toProcess = std::min((uint) (nbRibbons - ribbonIndex) , numRibbonBatch);
00413 const float *ptCurrSize;
00414 uint32 ptCurrSizeIncrement;
00415 if (_SizeScheme)
00416 {
00417 ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);
00418 ptCurrSizeIncrement = 1;
00419 }
00420 else
00421 {
00422 ptCurrSize = &_ParticleSize;
00423 ptCurrSizeIncrement = 0;
00424 }
00425
00426
00428 NLMISC::CRGBA *ptCurrColor=0;
00429 if (_ColorScheme)
00430 {
00431 colors.resize(nbRibbons);
00432 ptCurrColor = (NLMISC::CRGBA *) _ColorScheme->make(this->_Owner, ribbonIndex, &colors[0], sizeof(NLMISC::CRGBA), toProcess, true, srcStep);
00433 }
00434 VB.setNumVertices(2 * (_UsedNbSegs + 1) * toProcess);
00435 {
00436 CVertexBufferReadWrite vba;
00437 VB.lock (vba);
00438 currVert = (uint8 *) vba.getVertexCoordPointer();
00439 for (uint k = ribbonIndex; k < ribbonIndex + toProcess; ++k)
00440 {
00441
00442 TRibbonVect::iterator rIt = currRibbon.begin(), rItEnd = currRibbon.end(), rItEndMinusOne = rItEnd - 1;
00443
00445
00447
00448 if (!_Parametric)
00449 {
00450
00452
00454
00455
00456 computeRibbon((uint) (fpRibbonIndex >> 16), &rIt->Interp, sizeof(CVectInfo));
00457 do
00458 {
00459 MakeProj(rIt->Proj, mat * rIt->Interp);
00460 ++rIt;
00461 }
00462 while (rIt != rItEnd);
00463 }
00464 else
00465 {
00467
00469
00470 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
00471 &rIt->Interp, sizeof(CVectInfo) );
00472
00473 do
00474 {
00475 MakeProj(rIt->Proj, mat * rIt->Interp);
00476 ++rIt;
00477 }
00478 while (rIt != rItEnd);
00479 }
00480
00481 rIt = currRibbon.begin();
00482
00483
00484
00485 if (_ColorScheme)
00486 {
00487 uint8 *currColVertex = currVert + colorOffset;
00488 uint colCount = (_UsedNbSegs + 1) << 1;
00489 do
00490 {
00491 * (CRGBA *) currColVertex = *ptCurrColor;
00492 currColVertex += vertexSize;
00493 }
00494 while (--colCount);
00495
00496 ++ptCurrColor;
00497 }
00498
00500
00501 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt, rIt + 1, *ptCurrSize);
00502 currVert += vertexSizeX2;
00503 ++rIt;
00504
00505
00506
00507 for (;;)
00508 {
00509
00510 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt - 1, rIt + 1, *ptCurrSize);
00511
00512 ++rIt;
00513 if (rIt == rItEndMinusOne) break;
00514
00515 currVert += vertexSizeX2;
00516 }
00517 currVert += vertexSizeX2;
00518
00519 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt , rIt - 1, rIt, *ptCurrSize);
00520 ptCurrSize += ptCurrSizeIncrement;
00521 currVert += vertexSizeX2;
00522
00523 fpRibbonIndex += srcStep;
00524
00525 }
00526 }
00527 PB.setNumIndexes((_UsedNbSegs << 1) * toProcess * 3);
00528 drv->activeVertexBuffer(VB);
00529
00530 drv->activeIndexBuffer (PB);
00531 drv->renderTriangles (_Mat, 0, PB.getNumIndexes()/3);
00532 ribbonIndex += toProcess;
00533 }
00534 while (ribbonIndex != nbRibbons);
00535 }
00536
00537
00538 bool CPSRibbonLookAt::hasTransparentFaces(void)
00539 {
00540 NL_PS_FUNC(CPSRibbonLookAt_hasTransparentFaces)
00541 return getBlendingMode() != CPSMaterial::alphaTest ;
00542 }
00543
00544
00545
00546 bool CPSRibbonLookAt::hasOpaqueFaces(void)
00547 {
00548 NL_PS_FUNC(CPSRibbonLookAt_hasOpaqueFaces)
00549 return !hasTransparentFaces();
00550 }
00551
00552
00553 uint32 CPSRibbonLookAt::getNumWantedTris() const
00554 {
00555 NL_PS_FUNC(CPSRibbonLookAt_getNumWantedTris)
00556 nlassert(_Owner);
00557
00558 return _Owner->getSize() * _NbSegs * 2;
00559 }
00560
00561
00562
00563
00564 CPSRibbonLookAt::CVBnPB &CPSRibbonLookAt::getVBnPB()
00565 {
00566 NL_PS_FUNC(CPSRibbonLookAt_getVBnPB)
00567 TVBMap &map = _ColorScheme ? _VBMap : _ColoredVBMap;
00568 TVBMap::iterator it = map.find(_UsedNbSegs + 1);
00569 if (it != map.end())
00570 {
00571 return it->second;
00572 }
00573 else
00574 {
00575 const uint numRibbonInVB = getNumRibbonsInVB();
00576 CVBnPB &VBnPB = map[_UsedNbSegs + 1];
00577
00579 CVertexBuffer &vb = VBnPB.VB;
00580 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00581 CVertexBuffer::TexCoord0Flag |
00582 (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00583 vb.setNumVertices(2 * (_UsedNbSegs + 1) * numRibbonInVB );
00584 vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
00585 CVertexBufferReadWrite vba;
00586 vb.lock (vba);
00587
00588
00589 CIndexBuffer &pb = VBnPB.PB;
00590 pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
00591 pb.setNumIndexes((_UsedNbSegs << 1) * numRibbonInVB * 3);
00592 CIndexBufferReadWrite iba;
00593 pb.lock (iba);
00595 uint vbIndex = 0;
00596 uint pbIndex = 0;
00597 for (uint i = 0; i < numRibbonInVB; ++i)
00598 {
00599 for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
00600 {
00601 vba.setTexCoord(vbIndex, 0, CUV((1.f - k / (float) _UsedNbSegs), 0));
00602 vba.setTexCoord(vbIndex + 1, 0, CUV((1.f - k / (float) _UsedNbSegs), 1));
00603 if (k != _UsedNbSegs)
00604 {
00606 iba.setTri(pbIndex, vbIndex + 1, vbIndex + 2, vbIndex);
00607 iba.setTri(pbIndex+3, vbIndex + 1, vbIndex + 3, vbIndex + 2);
00608 pbIndex+=6;
00609 }
00610 vbIndex += 2;
00611 }
00612 }
00613 return VBnPB;
00614 }
00615 }
00616
00617
00618 uint CPSRibbonLookAt::getNumRibbonsInVB() const
00619 {
00620 NL_PS_FUNC(CPSRibbonLookAt_getNumRibbonsInVB)
00622 const uint vertexInVB = 256;
00623 return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
00624 }
00625
00626
00627 void CPSRibbonLookAt::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
00628 {
00629 NL_PS_FUNC(CPSRibbonLookAt_enumTexs)
00630 if (_Tex)
00631 {
00632 dest.push_back(_Tex);
00633 _Tex->getShareName();
00634 }
00635 }
00636
00637
00638 }