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_ribbon_look_at.h"
00029 #include "3d/particle_system.h"
00030 #include "3d/ps_macro.h"
00031 #include "3d/driver.h"
00032
00033 namespace NL3D
00034 {
00035
00037
00039
00040 const float ZEpsilon = 10E-3f;
00041 const float NormEpsilon = 10E-8f;
00042
00043
00044 struct CVectInfo
00045 {
00046 NLMISC::CVector Interp;
00047 NLMISC::CVector Proj;
00048 };
00049 typedef std::vector<CVectInfo> TRibbonVect;
00050
00051 CPSRibbonLookAt::TVBMap CPSRibbonLookAt::_VBMap;
00052 CPSRibbonLookAt::TVBMap CPSRibbonLookAt::_ColoredVBMap;
00053
00054
00055 CPSRibbonLookAt::CPSRibbonLookAt()
00056 {
00057 }
00058
00059
00060 CPSRibbonLookAt::~CPSRibbonLookAt()
00061 {
00062
00063 }
00064
00065
00066 void CPSRibbonLookAt::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00067 {
00071 sint ver = f.serialVersion(4);
00072 if (ver > 3)
00073 {
00074 CPSRibbonBase::serial(f);
00075 }
00076 else
00077 {
00078 CPSParticle::serial(f);
00079 }
00080 CPSColoredParticle::serialColorScheme(f);
00081 CPSSizedParticle::serialSizeScheme(f);
00082 serialMaterial(f);
00083 uint32 dummy = 0;
00084 if (ver <= 3)
00085 {
00086 f.serial(_SegDuration, _NbSegs, dummy );
00087 }
00088 ITexture *tex = NULL;
00089
00090 if (ver > 2)
00091 {
00092 f.serial(_Parametric);
00093 }
00094
00095
00096 if (!f.isReading())
00097 {
00098 tex = _Tex;
00099 f.serialPolyPtr(tex);
00100 }
00101 else
00102 {
00103 f.serialPolyPtr(tex);
00104 setTexture(tex);
00105 setTailNbSeg(_NbSegs);
00106 }
00107 }
00108
00109
00110
00111 void CPSRibbonLookAt::setTexture(CSmartPtr<ITexture> tex)
00112 {
00113 _Tex = tex;
00114 updateMatAndVbForColor();
00115 }
00116
00117
00118
00119 void CPSRibbonLookAt::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00120 {
00121 if (pass == PSMotion)
00122 {
00123 if (!_Parametric)
00124 {
00125 updateGlobals();
00126 }
00127 }
00128 else
00129 if (
00130 (pass == PSBlendRender && hasTransparentFaces())
00131 || (pass == PSSolidRender && hasOpaqueFaces())
00132 )
00133 {
00134 uint32 step;
00135 uint numToProcess;
00136 computeSrcStep(step, numToProcess);
00137 if (!numToProcess) return;
00138
00140 CParticleSystem &ps = *(_Owner->getOwner());
00141 _Mat.setColor(ps.getGlobalColor());
00142
00147 displayRibbons(numToProcess, step);
00148
00149 }
00150 else
00151 if (pass == PSToolRender)
00152 {
00153
00154 }
00155 }
00156
00157
00158
00159 void CPSRibbonLookAt::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00160 {
00161 CPSRibbonBase::newElement(emitterLocated, emitterIndex);
00162 newColorElement(emitterLocated, emitterIndex);
00163 newSizeElement(emitterLocated, emitterIndex);
00164 }
00165
00166
00167
00168 void CPSRibbonLookAt::deleteElement(uint32 index)
00169 {
00170 CPSRibbonBase::deleteElement(index);
00171 deleteColorElement(index);
00172 deleteSizeElement(index);
00173 }
00174
00175
00176
00177 void CPSRibbonLookAt::resize(uint32 size)
00178 {
00179 nlassert(size < (1 << 16));
00180 CPSRibbonBase::resize(size);
00181 resizeColor(size);
00182 resizeSize(size);
00183 }
00184
00185
00186 void CPSRibbonLookAt::updateMatAndVbForColor(void)
00187 {
00188 _Mat.setTexture(0, _Tex);
00189 }
00190
00191
00192 static inline void MakeProj(NLMISC::CVector &dest, const NLMISC::CVector &src)
00193 {
00194 if (fabsf(src.y) > NormEpsilon * NormEpsilon)
00195 {
00196 dest.x = src.x / src.y;
00197 dest.z = src.z / src.y;
00198 dest.y = src.y;
00199 }
00200 }
00201
00202 static inline void BuildSlice(const NLMISC::CMatrix &mat, CVertexBuffer &vb, uint8 *currVert, uint32 vertexSize,
00203 const NLMISC::CVector &I,
00204 const NLMISC::CVector &K,
00205 TRibbonVect::iterator pos,
00206 TRibbonVect::iterator prev,
00207 TRibbonVect::iterator next,
00208 float ribSize)
00210 {
00211 CHECK_VERTEX_BUFFER(vb, currVert);
00212 CHECK_VERTEX_BUFFER(vb, currVert);
00213 NLMISC::CVector tangent;
00214
00215 float invTgNorm;
00216 float tgNorm;
00217
00218 if (prev->Proj.y > ZEpsilon && next->Proj.y > ZEpsilon)
00219 {
00220 tangent = next->Proj - prev->Proj;
00221 tangent.y = 0;
00222 tgNorm = tangent.norm();
00223 if (fabs(tgNorm) > 10E-8)
00224 {
00225 invTgNorm = 1.f / tgNorm;
00226 }
00227 else
00228 {
00229 invTgNorm = 1.f;
00230 }
00231
00232
00233 *(NLMISC::CVector *) currVert = pos->Interp + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00234 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00235 }
00236 else if (prev->Proj.y > ZEpsilon)
00237 {
00238
00239 NLMISC::CVector inter;
00240 NLMISC::CVector tInter;
00241 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00242 {
00243 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00244 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00245 MakeProj(tInter, mat * inter);
00246 }
00247 else
00248 {
00249 *(NLMISC::CVector *) currVert = pos->Interp;
00250 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00251 return;
00252 }
00253
00254 tangent = tInter - prev->Proj;
00255 tangent.y = 0;
00256
00257 tgNorm = tangent.norm();
00258 if (fabs(tgNorm > 10E-8))
00259 {
00260 invTgNorm = 1.f / tgNorm;
00261 }
00262 else
00263 {
00264 invTgNorm = 1.f;
00265 }
00266
00267
00268 *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00269 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00270 }
00271 else if (next->Proj.y > ZEpsilon)
00272 {
00273
00274
00275 NLMISC::CVector inter;
00276 NLMISC::CVector tInter;
00277 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00278 {
00279 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00280 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00281 MakeProj(tInter, mat * inter);
00282 }
00283 else
00284 {
00285 *(NLMISC::CVector *) currVert = pos->Interp;
00286 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00287 return;
00288 }
00289
00290 tangent = next->Proj - tInter;
00291 tangent.y = 0;
00292 tgNorm = tangent.norm();
00293 if (fabs(tgNorm > 10E-8))
00294 {
00295 invTgNorm = 1.f / tgNorm;
00296 }
00297 else
00298 {
00299 invTgNorm = 1.f;
00300 }
00301
00302
00303 *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00304 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00305
00306 }
00307 else
00308 {
00309 *(NLMISC::CVector *) currVert = pos->Interp;
00310 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00311 }
00312
00313 }
00314
00315
00316
00317 void CPSRibbonLookAt::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00318 {
00319 if (!nbRibbons) return;
00320 nlassert(_Owner);
00321 CPSRibbonBase::updateLOD();
00322 if (_UsedNbSegs < 2) return;
00323
00324 const float date = _Owner->getOwner()->getSystemDate();
00325 uint8 *currVert;
00326
00327 CVBnPB &VBnPB = getVBnPB();
00328 CVertexBuffer &VB = VBnPB.VB;
00329 CPrimitiveBlock &PB = VBnPB.PB;
00330
00331 const uint32 vertexSize = VB.getVertexSize();
00332 uint colorOffset=0;
00333 const uint32 vertexSizeX2 = vertexSize << 1;
00334 const NLMISC::CVector I = _Owner->computeI();
00335 const NLMISC::CVector K = _Owner->computeK();
00336
00337
00338 CMatrix mat = _Owner->isInSystemBasis() ? getViewMat() * getSysMat()
00339 : getViewMat();
00340 IDriver *drv = this->getDriver();
00341 setupDriverModelMatrix();
00342 drv->activeVertexBuffer(VB);
00343 _Owner->incrementNbDrawnParticles(nbRibbons);
00344
00345 const uint numRibbonBatch = getNumRibbonsInVB();
00346
00347
00348 static TRibbonVect currRibbon;
00349 static std::vector<float> sizes;
00350 static std::vector<NLMISC::CRGBA> colors;
00351
00352
00353
00354
00355
00356 if (_UsedNbSegs == 0) return;
00357
00358 currRibbon.resize(_UsedNbSegs + 1);
00359 sizes.resize(numRibbonBatch);
00360
00361
00363 CParticleSystem &ps = *(_Owner->getOwner());
00364 if (ps.getColorAttenuationScheme() != NULL)
00365 {
00366 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());
00367 }
00368 else
00369 {
00370 forceModulateConstantColor(false);
00371 _Mat.setColor(ps.getGlobalColor());
00372 }
00373
00374 if (_ColorScheme)
00375 {
00376 colorOffset = VB.getColorOff();
00377 colors.resize(numRibbonBatch);
00378 }
00379
00380
00381 uint toProcess;
00382 uint ribbonIndex = 0;
00383
00384 uint32 fpRibbonIndex = 0;
00385
00386 do
00387 {
00388 toProcess = std::min((uint) (nbRibbons - ribbonIndex) , numRibbonBatch);
00389
00390
00392 const float *ptCurrSize;
00393 uint32 ptCurrSizeIncrement;
00394 if (_SizeScheme)
00395 {
00396 ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);
00397 ptCurrSizeIncrement = 1;
00398 }
00399 else
00400 {
00401 ptCurrSize = &_ParticleSize;
00402 ptCurrSizeIncrement = 0;
00403 }
00404
00406 NLMISC::CRGBA *ptCurrColor=0;
00407 if (_ColorScheme)
00408 {
00409 colors.resize(nbRibbons);
00410 ptCurrColor = (NLMISC::CRGBA *) _ColorScheme->make(this->_Owner, ribbonIndex, &colors[0], sizeof(NLMISC::CRGBA), toProcess, true, srcStep);
00411 }
00412
00413 currVert = (uint8 *) VB.getVertexCoordPointer();
00414 for (uint k = ribbonIndex; k < ribbonIndex + toProcess; ++k)
00415 {
00416
00417 TRibbonVect::iterator rIt = currRibbon.begin(), rItEnd = currRibbon.end(), rItEndMinusOne = rItEnd - 1;
00418
00420
00422
00423 if (!_Parametric)
00424 {
00425
00427
00429
00430
00431 computeRibbon((uint) (fpRibbonIndex >> 16), &rIt->Interp, sizeof(CVectInfo));
00432 do
00433 {
00434 MakeProj(rIt->Proj, mat * rIt->Interp);
00435 ++rIt;
00436 }
00437 while (rIt != rItEnd);
00438 }
00439 else
00440 {
00442
00444
00445 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
00446 &rIt->Interp, sizeof(CVectInfo) );
00447
00448 do
00449 {
00450 MakeProj(rIt->Proj, mat * rIt->Interp);
00451 ++rIt;
00452 }
00453 while (rIt != rItEnd);
00454 }
00455
00456 rIt = currRibbon.begin();
00457
00458
00459
00460 if (_ColorScheme)
00461 {
00462 uint8 *currColVertex = currVert + colorOffset;
00463 uint colCount = (_UsedNbSegs + 1) << 1;
00464 do
00465 {
00466 * (CRGBA *) currColVertex = *ptCurrColor;
00467 currColVertex += vertexSize;
00468 }
00469 while (--colCount);
00470
00471 ++ptCurrColor;
00472 }
00473
00475
00476 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt, rIt + 1, *ptCurrSize);
00477 currVert += vertexSizeX2;
00478 ++rIt;
00479
00480
00481
00482 for (;;)
00483 {
00484
00485 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt - 1, rIt + 1, *ptCurrSize);
00486
00487 ++rIt;
00488 if (rIt == rItEndMinusOne) break;
00489
00490 currVert += vertexSizeX2;
00491 }
00492 currVert += vertexSizeX2;
00493
00494 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt , rIt - 1, rIt, *ptCurrSize);
00495 ptCurrSize += ptCurrSizeIncrement;
00496 currVert += vertexSizeX2;
00497
00498 fpRibbonIndex += srcStep;
00499 }
00500
00501 PB.setNumTri((_UsedNbSegs << 1) * toProcess);
00502
00503 drv->render(PB, _Mat);
00504 ribbonIndex += toProcess;
00505 }
00506 while (ribbonIndex != nbRibbons);
00507 }
00508
00509
00510 bool CPSRibbonLookAt::hasTransparentFaces(void)
00511 {
00512 return getBlendingMode() != CPSMaterial::alphaTest ;
00513 }
00514
00515
00516
00517 bool CPSRibbonLookAt::hasOpaqueFaces(void)
00518 {
00519 return !hasTransparentFaces();
00520 }
00521
00522
00523 uint32 CPSRibbonLookAt::getMaxNumFaces(void) const
00524 {
00525 nlassert(_Owner);
00526 return _Owner->getMaxSize() * _NbSegs * 2;
00527 }
00528
00529
00530
00531
00532 CPSRibbonLookAt::CVBnPB &CPSRibbonLookAt::getVBnPB()
00533 {
00534 TVBMap &map = _ColorScheme ? _VBMap : _ColoredVBMap;
00535 TVBMap::iterator it = map.find(_UsedNbSegs + 1);
00536 if (it != map.end())
00537 {
00538 return it->second;
00539 }
00540 else
00541 {
00542 const uint numRibbonInVB = getNumRibbonsInVB();
00543 CVBnPB &VBnPB = map[_UsedNbSegs + 1];
00544
00546 CVertexBuffer &vb = VBnPB.VB;
00547 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00548 CVertexBuffer::TexCoord0Flag |
00549 (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00550 vb.setNumVertices(2 * (_UsedNbSegs + 1) * numRibbonInVB );
00551
00552
00553 CPrimitiveBlock &pb = VBnPB.PB;
00554 pb.setNumTri((_UsedNbSegs << 1) * numRibbonInVB);
00556 uint vbIndex = 0;
00557 uint pbIndex = 0;
00558 for (uint i = 0; i < numRibbonInVB; ++i)
00559 {
00560 for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
00561 {
00562 vb.setTexCoord(vbIndex, 0, CUV((1.f - k / (float) _UsedNbSegs), 0));
00563 vb.setTexCoord(vbIndex + 1, 0, CUV((1.f - k / (float) _UsedNbSegs), 1));
00564 if (k != _UsedNbSegs)
00565 {
00567 pb.setTri(pbIndex ++, vbIndex + 1, vbIndex + 2, vbIndex);
00568 pb.setTri(pbIndex ++, vbIndex + 1, vbIndex + 3, vbIndex + 2);
00569 }
00570 vbIndex += 2;
00571 }
00572 }
00573 return VBnPB;
00574 }
00575 }
00576
00577
00578 uint CPSRibbonLookAt::getNumRibbonsInVB() const
00579 {
00581 const uint vertexInVB = 256;
00582 return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
00583 }
00584
00585 }