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.h"
00027 #include "nel/3d/ps_macro.h"
00028 #include "nel/3d/particle_system.h"
00029 #include "nel/3d/driver.h"
00030 #include "nel/3d/ps_util.h"
00031 #include "nel/3d/texture_mem.h"
00032 #include "nel/misc/matrix.h"
00033
00034 namespace NL3D
00035 {
00036
00037 static NLMISC::CRGBA GradientB2W[] = {NLMISC::CRGBA(0, 0, 0, 0), NLMISC::CRGBA(255, 255, 255, 255) };
00038
00039 CPSRibbon::TVBMap CPSRibbon::_VBMaps[16];
00040
00041
00043 static ITexture *CreateGradientTexture()
00044 {
00045 NL_PS_FUNC(CreateGradientTexture)
00046 std::auto_ptr<CTextureMem> tex(new CTextureMem((uint8 *) &GradientB2W,
00047 sizeof(GradientB2W),
00048 false,
00049 false,
00050 2, 1)
00051 );
00052
00053 tex->setShareName("#GradBW");
00054 return tex.release();
00055 }
00056
00057
00059
00061
00062
00063 const NLMISC::CVector CPSRibbon::Triangle[] =
00064 {
00065 NLMISC::CVector(0, 1, 0),
00066 NLMISC::CVector(1, -1, 0),
00067 NLMISC::CVector(-1, -1, 0),
00068 };
00069
00070 const NLMISC::CVector CPSRibbon::Losange[] =
00071 {
00072 NLMISC::CVector(0, 1.f, 0),
00073 NLMISC::CVector(1.f, 0, 0),
00074 NLMISC::CVector(0, -1.f, 0),
00075 NLMISC::CVector(-1.f, 0, 0)
00076 };
00077
00078 const NLMISC::CVector CPSRibbon::HeightSides[] =
00079 {
00080 NLMISC::CVector(-0.5f, 1, 0),
00081 NLMISC::CVector(0.5f, 1, 0),
00082 NLMISC::CVector(1, 0.5f, 0),
00083 NLMISC::CVector(1, -0.5f, 0),
00084 NLMISC::CVector(0.5f, -1, 0),
00085 NLMISC::CVector(-0.5f, -1, 0),
00086 NLMISC::CVector(-1, -0.5f, 0),
00087 NLMISC::CVector(-1, 0.5f, 0)
00088 };
00089
00090
00091 const NLMISC::CVector CPSRibbon::Pentagram[] =
00092 {
00093 NLMISC::CVector(0, 1, 0),
00094 NLMISC::CVector(1, -1, 0),
00095 NLMISC::CVector(-1, 0, 0),
00096 NLMISC::CVector(1, 0, 0),
00097 NLMISC::CVector(-1, -1, 0)
00098 };
00099
00100 const NLMISC::CVector CPSRibbon::SimpleSegmentX[] =
00101 {
00102 NLMISC::CVector(1, 0, 0),
00103 NLMISC::CVector(-1, 0, 0),
00104 };
00105 const uint CPSRibbon::NbVerticesInSimpleSegmentX = sizeof(CPSRibbon::SimpleSegmentX) / sizeof(CVector);
00106
00107 const NLMISC::CVector CPSRibbon::SimpleSegmentY[] =
00108 {
00109 NLMISC::CVector(0, 1, 0),
00110 NLMISC::CVector(0, -1, 0),
00111 };
00112 const uint CPSRibbon::NbVerticesInSimpleSegmentY = sizeof(CPSRibbon::SimpleSegmentY) / sizeof(CVector);
00113
00114 const NLMISC::CVector CPSRibbon::SimpleSegmentZ[] =
00115 {
00116 NLMISC::CVector(0, 0, 1),
00117 NLMISC::CVector(0, 0, -1),
00118 };
00119 const uint CPSRibbon::NbVerticesInSimpleSegmentZ = sizeof(CPSRibbon::SimpleSegmentZ) / sizeof(CVector);
00120
00121 const NLMISC::CVector CPSRibbon::SimpleBrace[] =
00122 {
00123 NLMISC::CVector(1, 0, 0),
00124 NLMISC::CVector(-1, 0, 0),
00125 NLMISC::CVector(0, 1, 0),
00126 NLMISC::CVector(0, -1, 0)
00127 };
00128 const uint CPSRibbon::NbVerticesInSimpleBrace = sizeof(CPSRibbon::SimpleBrace) / sizeof(CVector);
00129
00130 const uint CPSRibbon::NbVerticesInTriangle = sizeof(CPSRibbon::Triangle) / sizeof(CVector);
00131 const uint CPSRibbon::NbVerticesInLosange = sizeof(Losange) / sizeof(CVector);
00132 const uint CPSRibbon::NbVerticesInHeightSide = sizeof(CPSRibbon::HeightSides) / sizeof(CVector);
00133 const uint CPSRibbon::NbVerticesInPentagram = sizeof(CPSRibbon::Pentagram) / sizeof(CVector);
00134
00135
00136 struct CDummy2DAngle : CPSRotated2DParticle
00137 {
00138 CPSLocated *getAngle2DOwner(void) { return NULL; }
00139 };
00140
00142 void CPSRibbon::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00143 {
00144 NL_PS_FUNC(CPSRibbon_serial)
00145
00146
00147 sint ver = f.serialVersion(3);
00148 if (ver == 1)
00149 {
00150 nlassert(f.isReading());
00151
00154 sint ver2 = f.serialVersion(2);
00155
00156
00157 sint ver3 = f.serialVersion(4);
00158 f.serialPtr(_Owner);
00159 if (ver3 > 1) f.serialEnum(_LOD);
00160 if (ver3 > 2) f.serial(_Name);
00161 if (ver3 > 3)
00162 {
00163 if (f.isReading())
00164 {
00165 uint32 id;
00166 f.serial(id);
00167 setExternID(id);
00168 }
00169 else
00170 {
00171 f.serial(_ExternID);
00172 }
00173 }
00174
00175 if (ver2 >= 2)
00176 {
00177 bool bDisableAutoLOD;
00178 f.serial(bDisableAutoLOD);
00179 disableAutoLOD(bDisableAutoLOD);
00180 }
00181
00182 uint32 tailNbSegs;
00183 bool colorFading;
00184 bool systemBasisEnabled;
00185 bool drEnabled;
00186
00187 CPSColoredParticle::serialColorScheme(f);
00188 CPSSizedParticle::serialSizeScheme(f);
00189
00190
00191 {
00192 CDummy2DAngle _Dummy2DAngle;
00193 _Dummy2DAngle.serialAngle2DScheme(f);
00194 }
00195
00196 f.serial(colorFading, systemBasisEnabled);
00197 serialMaterial(f);
00198
00199 f.serial(drEnabled);
00200 f.serial(tailNbSegs);
00201 ITexture *tex = NULL;
00202 f.serialPolyPtr(tex);
00203 _Tex = tex;
00204 if (_Tex != NULL)
00205 {
00206 f.serial(_UFactor, _VFactor) ;
00207 }
00208
00209
00210 f.serialCont(_Shape);
00211
00212
00213 _NbSegs = tailNbSegs >> 1;
00214 if (_NbSegs < 1) _NbSegs = 2;
00215 setInterpolationMode(Linear);
00216
00217 nlassert(_Owner);
00218 resize(_Owner->getMaxSize());
00219 initDateVect();
00220 resetFromOwner();
00221 }
00222
00223
00224 if (ver >= 2)
00225 {
00226 CPSRibbonBase::serial(f);
00227 CPSColoredParticle::serialColorScheme(f);
00228 CPSSizedParticle::serialSizeScheme(f);
00229 CPSMaterial::serialMaterial(f);
00230 f.serialCont(_Shape);
00231 bool colorFading = _ColorFading;
00232 f.serial(colorFading);
00233 _ColorFading = colorFading;
00234 uint32 tailNbSegs = _NbSegs;
00235 f.serial(tailNbSegs);
00236 if (f.isReading())
00237 {
00238 setTailNbSeg(_NbSegs);
00239 touch();
00240 }
00241 ITexture *tex = _Tex;
00242 f.serialPolyPtr(tex);
00243 _Tex = tex;
00244 if (_Tex != NULL)
00245 {
00246 f.serial(_UFactor, _VFactor) ;
00247 }
00248 }
00249
00250 if (ver >= 3)
00251 {
00252 bool braceMode = _BraceMode;
00253 f.serial(braceMode);
00254 _BraceMode = braceMode;
00255 f.serialEnum(_Orientation);
00256 }
00257
00258 if (f.isReading())
00259 {
00260 touch();
00261 }
00262 }
00263
00264
00265
00266 CPSRibbon::CPSRibbon() : _UFactor(1.f),
00267 _VFactor(1.f),
00268 _Orientation(FollowPath),
00269 _BraceMode(true),
00270 _ColorFading(true),
00271 _GlobalColor(false),
00272 _Lighted(false),
00273 _ForceLighted(false),
00274 _Touch(true)
00275 {
00276 NL_PS_FUNC(CPSRibbon_CPSRibbon)
00277 setInterpolationMode(Linear);
00278 setSegDuration(0.06f);
00279 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("Ribbon");
00280 setShape(Triangle, NbVerticesInTriangle);
00281 _Mat.setDoubleSided(true);
00282 }
00283
00284
00285
00286 CPSRibbon::~CPSRibbon()
00287 {
00288 NL_PS_FUNC(CPSRibbon_CPSRibbonDtor)
00289 }
00290
00291
00292
00293 inline uint CPSRibbon::getNumVerticesInSlice() const
00294 {
00295 NL_PS_FUNC(CPSRibbon_getNumVerticesInSlice)
00296 if (_BraceMode)
00297 {
00298 return _Shape.size();
00299 }
00300 else
00301 {
00302 return _Shape.size() + (_Tex == NULL ? 0 : 1);
00303 }
00304 }
00305
00306
00307
00308
00309
00310
00311 void CPSRibbon::step(TPSProcessPass pass)
00312 {
00313 NL_PS_FUNC(CPSRibbon_step)
00314 if (pass == PSMotion)
00315 {
00316 if (!_Parametric)
00317 {
00318 updateGlobals();
00319 }
00320 }
00321 else
00322 if (
00323 (pass == PSBlendRender && hasTransparentFaces())
00324 || (pass == PSSolidRender && hasOpaqueFaces())
00325 )
00326 {
00327 uint32 step;
00328 uint numToProcess;
00329 computeSrcStep(step, numToProcess);
00330 if (!numToProcess) return;
00331
00333 CParticleSystem &ps = *(_Owner->getOwner());
00334 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00335 {
00336 _Mat.setColor(ps.getGlobalColorLighted());
00337 }
00338 else
00339 {
00340 _Mat.setColor(ps.getGlobalColor());
00341 }
00342
00347 displayRibbons(numToProcess, step);
00348
00349 }
00350 else
00351 if (pass == PSToolRender)
00352 {
00353
00354 }
00355 }
00356
00357
00358
00359 void CPSRibbon::newElement(const CPSEmitterInfo &info)
00360 {
00361 NL_PS_FUNC(CPSRibbon_newElement)
00362 CPSRibbonBase::newElement(info);
00363 newColorElement(info);
00364 newSizeElement(info);
00365 }
00366
00367
00368
00369 void CPSRibbon::deleteElement(uint32 index)
00370 {
00371 NL_PS_FUNC(CPSRibbon_deleteElement)
00372 CPSRibbonBase::deleteElement(index);
00373 deleteColorElement(index);
00374 deleteSizeElement(index);
00375 }
00376
00377
00378
00379 void CPSRibbon::resize(uint32 size)
00380 {
00381 NL_PS_FUNC(CPSRibbon_resize)
00382 nlassert(size < (1 << 16));
00383 CPSRibbonBase::resize(size);
00384 resizeColor(size);
00385 resizeSize(size);
00386 }
00387
00388
00389 void CPSRibbon::updateMatAndVbForColor(void)
00390 {
00391 NL_PS_FUNC(CPSRibbon_updateMatAndVbForColor)
00392 touch();
00393 }
00394
00395
00397
00398 static inline uint8 *BuildRibbonFirstSlice(const NLMISC::CVector &pos,
00399 uint numVerts,
00400 uint8 *dest,
00401 uint vertexSize
00402 )
00403 {
00404 NL_PS_FUNC(BuildRibbonFirstSlice)
00405 do
00406 {
00407 * (NLMISC::CVector *) dest = pos;
00408 dest += vertexSize;
00409 }
00410 while (--numVerts);
00411 return dest;
00412 }
00413
00414
00416
00417 static inline uint8 *ComputeRibbonSliceFollowPath(const NLMISC::CVector &prev,
00418 const NLMISC::CVector &next,
00419 const NLMISC::CVector *shape,
00420 uint numVerts,
00421 uint8 *dest,
00422 uint vertexSize,
00423 float size,
00424 NLMISC::CMatrix &basis
00425 )
00426 {
00427 NL_PS_FUNC(ComputeRibbonSliceFollowPath)
00428
00429
00430 const float epsilon = 10E-5f;
00431 if (fabsf(next.x - prev.x) > epsilon
00432 || fabsf(next.y - prev.y) > epsilon
00433 || fabsf(next.z - prev.z) > epsilon)
00434 {
00435
00436 CPSUtil::buildSchmidtBasis(next - prev, basis);
00437 }
00438 basis.setPos(next);
00439
00440 const NLMISC::CVector *shapeEnd = shape + numVerts;
00441 do
00442 {
00443 *(NLMISC::CVector *) dest = basis * (size * (*shape));
00444 ++shape;
00445 dest += vertexSize;
00446 }
00447 while (shape != shapeEnd);
00448 return dest;
00449 }
00450
00452
00453 static inline uint8 *ComputeRibbonSliceIdentity(const NLMISC::CVector &prev,
00454 const NLMISC::CVector &next,
00455 const NLMISC::CVector *shape,
00456 uint numVerts,
00457 uint8 *dest,
00458 uint vertexSize,
00459 float size
00460 )
00461 {
00462 NL_PS_FUNC(ComputeRibbonSliceIdentity)
00463 const NLMISC::CVector *shapeEnd = shape + numVerts;
00464 do
00465 {
00466 ((NLMISC::CVector *) dest)->set(size * shape->x + next.x,
00467 size * shape->y + next.y,
00468 size * shape->z + next.z);
00469 ++shape;
00470 dest += vertexSize;
00471 }
00472 while (shape != shapeEnd);
00473 return dest;
00474 }
00475
00477 static inline uint8 *ComputeRibbonSliceFollowPathXY(const NLMISC::CVector &prev,
00478 const NLMISC::CVector &next,
00479 const NLMISC::CVector *shape,
00480 uint numVerts,
00481 uint8 *dest,
00482 uint vertexSize,
00483 float size,
00484 NLMISC::CMatrix &basis
00485 )
00486 {
00487 NL_PS_FUNC(ComputeRibbonSliceFollowPathXY)
00488 float deltaX = next.x - prev.x;
00489 float deltaY = next.y - prev.y;
00490 const float epsilon = 10E-5f;
00491 if (fabsf(deltaX) > epsilon
00492 || fabsf(deltaY) > epsilon)
00493 {
00494 float norm = sqrtf(NLMISC::sqr(deltaX) + NLMISC::sqr(deltaY));
00495 float invNorm = (norm != 0.f) ? 1.f / norm : 0.f;
00496 NLMISC::CVector I, J;
00497 J.set(deltaX * invNorm, deltaY * invNorm, 0.f);
00498 I.set(-J.y, J.x, 0.f);
00499 basis.setRot(I, CVector::K, J, true);
00500 }
00501 basis.setPos(next);
00502 const NLMISC::CVector *shapeEnd = shape + numVerts;
00503 do
00504 {
00505 *(NLMISC::CVector *) dest = basis * (size * (*shape));
00506 ++shape;
00507 dest += vertexSize;
00508 }
00509 while (shape != shapeEnd);
00510 return dest;
00511 }
00512
00513
00514
00515
00517
00518
00519 static inline uint8 *ComputeUntexturedRibbonMesh(uint8 *destVb,
00520 uint vertexSize,
00521 const NLMISC::CVector *curve,
00522 const NLMISC::CVector *shape,
00523 uint numSegs,
00524 uint numVerticesInShape,
00525 float sizeIncrement,
00526 float size,
00527 CPSRibbon::TOrientation orientation
00528 )
00529 {
00530 NL_PS_FUNC(ComputeUntexturedRibbonMesh)
00531 CMatrix basis;
00532 basis.scale(0);
00533 switch(orientation)
00534 {
00535 case CPSRibbon::FollowPath:
00536 do
00537 {
00538 destVb = ComputeRibbonSliceFollowPath(curve[1],
00539 curve[0],
00540 shape,
00541 numVerticesInShape,
00542 destVb,
00543 vertexSize,
00544 size,
00545 basis);
00546 ++ curve;
00547 size -= sizeIncrement;
00548 }
00549 while (--numSegs);
00550 break;
00551 case CPSRibbon::FollowPathXY:
00552 do
00553 {
00554 destVb = ComputeRibbonSliceFollowPathXY(curve[1],
00555 curve[0],
00556 shape,
00557 numVerticesInShape,
00558 destVb,
00559 vertexSize,
00560 size,
00561 basis);
00562 ++ curve;
00563 size -= sizeIncrement;
00564 }
00565 while (--numSegs);
00566 break;
00567 case CPSRibbon::Identity:
00568 do
00569 {
00570 destVb = ComputeRibbonSliceIdentity(curve[1],
00571 curve[0],
00572 shape,
00573 numVerticesInShape,
00574 destVb,
00575 vertexSize,
00576 size
00577 );
00578 ++ curve;
00579 size -= sizeIncrement;
00580 }
00581 while (--numSegs);
00582 break;
00583 default:
00584 nlassert(0);
00585 break;
00586 }
00587 return BuildRibbonFirstSlice(curve[0], numVerticesInShape, destVb, vertexSize);
00588 }
00589
00591
00592
00593 static inline uint8 *ComputeTexturedRibbonMesh(uint8 *destVb,
00594 uint vertexSize,
00595 const NLMISC::CVector *curve,
00596 const NLMISC::CVector *shape,
00597 uint numSegs,
00598 uint numVerticesInShape,
00599 float sizeIncrement,
00600 float size,
00601 CPSRibbon::TOrientation orientation
00602 )
00603 {
00604 NL_PS_FUNC(ComputeTexturedRibbonMesh)
00605 CMatrix basis;
00606 basis.scale(0);
00607 switch(orientation)
00608 {
00609 case CPSRibbon::FollowPath:
00610 do
00611 {
00612 uint8 *nextDestVb = ComputeRibbonSliceFollowPath(curve[1],
00613 curve[0],
00614 shape,
00615 numVerticesInShape,
00616 destVb,
00617 vertexSize,
00618 size,
00619 basis
00620 );
00621
00622 * (NLMISC::CVector *) nextDestVb = * (NLMISC::CVector *) destVb;
00623 destVb = nextDestVb + vertexSize;
00624
00625 ++ curve;
00626 size -= sizeIncrement;
00627 }
00628 while (--numSegs);
00629 break;
00630 case CPSRibbon::FollowPathXY:
00631 do
00632 {
00633 uint8 *nextDestVb = ComputeRibbonSliceFollowPathXY(curve[1],
00634 curve[0],
00635 shape,
00636 numVerticesInShape,
00637 destVb,
00638 vertexSize,
00639 size,
00640 basis
00641 );
00642
00643 * (NLMISC::CVector *) nextDestVb = * (NLMISC::CVector *) destVb;
00644 destVb = nextDestVb + vertexSize;
00645
00646 ++ curve;
00647 size -= sizeIncrement;
00648 }
00649 while (--numSegs);
00650 break;
00651 case CPSRibbon::Identity:
00652 do
00653 {
00654 uint8 *nextDestVb = ComputeRibbonSliceIdentity(curve[1],
00655 curve[0],
00656 shape,
00657 numVerticesInShape,
00658 destVb,
00659 vertexSize,
00660 size
00661 );
00662
00663 * (NLMISC::CVector *) nextDestVb = * (NLMISC::CVector *) destVb;
00664 destVb = nextDestVb + vertexSize;
00665
00666 ++ curve;
00667 size -= sizeIncrement;
00668 }
00669 while (--numSegs);
00670 break;
00671 default:
00672 nlassert(0);
00673 break;
00674 }
00675 return BuildRibbonFirstSlice(curve[0], numVerticesInShape + 1, destVb, vertexSize);
00676 }
00677
00678
00679 void CPSRibbon::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00680 {
00681
00682 NL_PS_FUNC(CPSRibbon_displayRibbons)
00683 if (!nbRibbons) return;
00684 nlassert(_Owner);
00685 CPSRibbonBase::updateLOD();
00686 if (_UsedNbSegs < 2) return;
00687 const float date = _Owner->getOwner()->getSystemDate();
00688 uint8 *currVert;
00689 CVBnPB &VBnPB = getVBnPB();
00690 CVertexBuffer &VB = VBnPB.VB;
00691 CIndexBuffer &PB = VBnPB.PB;
00692 const uint32 vertexSize = VB.getVertexSize();
00693 uint colorOffset=0;
00694
00695 IDriver *drv = this->getDriver();
00696 #ifdef NL_DEBUG
00697 nlassert(drv);
00698 #endif
00699 drv->setupModelMatrix(getLocalToWorldTrailMatrix());
00700 _Owner->incrementNbDrawnParticles(nbRibbons);
00701 const uint numRibbonBatch = getNumRibbonsInVB();
00702 if (_UsedNbSegs == 0) return;
00704
00706 CParticleSystem &ps = *(_Owner->getOwner());
00707 bool useGlobalColor = ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed();
00708 if (useGlobalColor != _GlobalColor)
00709 {
00710 _GlobalColor = useGlobalColor;
00711 touch();
00712 }
00713 if (usesGlobalColorLighting() != _Lighted)
00714 {
00715 _Lighted = usesGlobalColorLighting();
00716 touch();
00717 }
00718 if (ps.getForceGlobalColorLightingFlag() != _ForceLighted)
00719 {
00720 _ForceLighted = ps.getForceGlobalColorLightingFlag();
00721 touch();
00722 }
00723 updateMaterial();
00724 setupGlobalColor();
00725
00726 if (_ColorScheme)
00727 {
00728 colorOffset = VB.getColorOff();
00729 }
00731
00733 const uint numVerticesInSlice = getNumVerticesInSlice();
00734 const uint numVerticesInShape = _Shape.size();
00735
00736 static std::vector<float> sizes;
00737 static std::vector<NLMISC::CVector> ribbonPos;
00738 ribbonPos.resize(_UsedNbSegs + 1);
00739 sizes.resize(numRibbonBatch);
00740
00741
00742 uint toProcess;
00743 uint ribbonIndex = 0;
00744 uint32 fpRibbonIndex = 0;
00745 if (_ColorScheme)
00746 {
00747 _ColorScheme->setColorType(drv->getVertexColorFormat());
00748 }
00749 do
00750 {
00751 toProcess = std::min((uint) (nbRibbons - ribbonIndex) , numRibbonBatch);
00752 VB.setNumVertices((_UsedNbSegs + 1) * toProcess * numVerticesInSlice);
00753 {
00754 CVertexBufferReadWrite vba;
00755 VB.lock(vba);
00756 currVert = (uint8 *) vba.getVertexCoordPointer();
00758 const float *ptCurrSize;
00759 uint32 ptCurrSizeIncrement;
00760 if (_SizeScheme)
00761 {
00762 ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);
00763 ptCurrSizeIncrement = 1;
00764 }
00765 else
00766 {
00767 ptCurrSize = &_ParticleSize;
00768 ptCurrSizeIncrement = 0;
00769 }
00770
00772 if (_ColorScheme)
00773 {
00774 _ColorScheme->makeN(this->_Owner, ribbonIndex, currVert + colorOffset, vertexSize, toProcess, numVerticesInSlice * (_UsedNbSegs + 1), srcStep);
00775 }
00776 uint k = toProcess;
00778
00780 if (!_Parametric)
00781 {
00783
00785 if (_Tex != NULL && !_BraceMode)
00786 {
00787 do
00788 {
00789 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00790 ptCurrSize += ptCurrSizeIncrement;
00791
00792 computeRibbon((uint) (fpRibbonIndex >> 16), &ribbonPos[0], sizeof(NLMISC::CVector));
00793 currVert = ComputeTexturedRibbonMesh(currVert,
00794 vertexSize,
00795 &ribbonPos[0],
00796 &_Shape[0],
00797 _UsedNbSegs,
00798 numVerticesInShape,
00799 ribbonSizeIncrement,
00800 *ptCurrSize,
00801 _Orientation
00802 );
00803 fpRibbonIndex += srcStep;
00804 }
00805 while (--k);
00806 }
00807 else
00808 {
00809 do
00810 {
00811 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00812 ptCurrSize += ptCurrSizeIncrement;
00813
00814 computeRibbon((uint) (fpRibbonIndex >> 16), &ribbonPos[0], sizeof(NLMISC::CVector));
00815 currVert = ComputeUntexturedRibbonMesh(currVert,
00816 vertexSize,
00817 &ribbonPos[0],
00818 &_Shape[0],
00819 _UsedNbSegs,
00820 numVerticesInShape,
00821 ribbonSizeIncrement,
00822 *ptCurrSize,
00823 _Orientation
00824 );
00825 fpRibbonIndex += srcStep;
00826 }
00827 while (--k);
00828 }
00829 }
00830 else
00831 {
00833
00835 if (_Tex != NULL)
00836 {
00837 do
00838 {
00839 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00840 ptCurrSize += ptCurrSizeIncrement;
00841 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1),
00842 _UsedSegDuration,
00843 _UsedNbSegs + 1,
00844 (uint) (fpRibbonIndex >> 16),
00845 &ribbonPos[0]);
00846
00847 currVert = ComputeTexturedRibbonMesh(currVert,
00848 vertexSize,
00849 &ribbonPos[0],
00850 &_Shape[0],
00851 _UsedNbSegs,
00852 numVerticesInShape,
00853 ribbonSizeIncrement,
00854 *ptCurrSize,
00855 _Orientation
00856 );
00857 fpRibbonIndex += srcStep;
00858 }
00859 while (--k);
00860 }
00861 else
00862 {
00863 do
00864 {
00865 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00866 ptCurrSize += ptCurrSizeIncrement;
00867 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1),
00868 _UsedSegDuration,
00869 _UsedNbSegs + 1,
00870 (uint) (fpRibbonIndex >> 16),
00871 &ribbonPos[0]);
00872
00873 currVert = ComputeUntexturedRibbonMesh(currVert,
00874 vertexSize,
00875 &ribbonPos[0],
00876 &_Shape[0],
00877 _UsedNbSegs,
00878 numVerticesInShape,
00879 ribbonSizeIncrement,
00880 *ptCurrSize,
00881 _Orientation
00882 );
00883 fpRibbonIndex += srcStep;
00884 }
00885 while (--k);
00886 }
00887 }
00888 }
00889
00890 uint numTri = numVerticesInShape * _UsedNbSegs * toProcess;
00891 if (!_BraceMode)
00892 {
00893 numTri <<= 1;
00894 }
00895 PB.setNumIndexes(3 * numTri);
00896 drv->activeIndexBuffer(PB);
00897 drv->activeVertexBuffer(VB);
00898 drv->renderTriangles(_Mat, 0, numTri);
00899 ribbonIndex += toProcess;
00900 }
00901 while (ribbonIndex != nbRibbons);
00902
00903 }
00904
00905
00906 bool CPSRibbon::hasTransparentFaces(void)
00907 {
00908 NL_PS_FUNC(CPSRibbon_hasTransparentFaces)
00909 return getBlendingMode() != CPSMaterial::alphaTest ;
00910 }
00911
00912
00913
00914 bool CPSRibbon::hasOpaqueFaces(void)
00915 {
00916 NL_PS_FUNC(CPSRibbon_hasOpaqueFaces)
00917 return !hasTransparentFaces();
00918 }
00919
00920
00921 uint32 CPSRibbon::getNumWantedTris() const
00922 {
00923 NL_PS_FUNC(CPSRibbon_getNumWantedTris)
00924 nlassert(_Owner);
00925
00926 return _Owner->getSize() * _NbSegs;
00927 }
00928
00929
00930
00931 static inline void setTri(CIndexBufferReadWrite &ibrw, const CVertexBuffer &vb, uint32 triIndex, uint32 i0, uint32 i1, uint32 i2)
00932 {
00933 nlassert(i0 < vb.getNumVertices());
00934 nlassert(i1 < vb.getNumVertices());
00935 nlassert(i2 < vb.getNumVertices());
00936 ibrw.setTri(triIndex, i0, i1, i2);
00937 }
00938
00939
00940 CPSRibbon::CVBnPB &CPSRibbon::getVBnPB()
00941 {
00942 NL_PS_FUNC(CPSRibbon_getVBnPB)
00943
00944
00946 TVBMap &map = _VBMaps[ (_BraceMode ? 8 : 0) |
00947 (_Tex != NULL ? 4 : 0) |
00948 (_ColorScheme != NULL ? 2 : 0) |
00949 (_ColorFading ? 1 : 0)
00950 ];
00951
00952 const uint numVerticesInSlice = getNumVerticesInSlice();
00953 const uint numVerticesInShape = _Shape.size();
00954
00955
00956
00957
00958 uint VBnPDIndex = ((_UsedNbSegs + 1) << 16) | numVerticesInSlice;
00959 TVBMap::iterator it = map.find(VBnPDIndex);
00960 if (it != map.end())
00961 {
00962 return it->second;
00963 }
00964 else
00965 {
00966 const uint numRibbonInVB = getNumRibbonsInVB();
00967 CVBnPB &VBnPB = map[VBnPDIndex];
00968 CIndexBuffer &pb = VBnPB.PB;
00969 CVertexBuffer &vb = VBnPB.VB;
00970 vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
00974 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00975 (_ColorScheme || _ColorFading ? CVertexBuffer::PrimaryColorFlag : 0) |
00976 ((_ColorScheme && _ColorFading) || _Tex != NULL ? CVertexBuffer::TexCoord0Flag : 0) |
00977 (_Tex != NULL && _ColorScheme && _ColorFading ? CVertexBuffer::TexCoord1Flag : 0)
00978 );
00979 vb.setNumVertices((_UsedNbSegs + 1) * numRibbonInVB * numVerticesInSlice);
00980 pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
00981
00982 if (_BraceMode)
00983 {
00984 pb.setNumIndexes(6 * _UsedNbSegs * numRibbonInVB * (_Shape.size() / 2));
00985 }
00986 else
00987 {
00988 pb.setNumIndexes(6 * _UsedNbSegs * numRibbonInVB * _Shape.size());
00989 }
00990
00991 CIndexBufferReadWrite ibaWrite;
00992 pb.lock (ibaWrite);
00993 CVertexBufferReadWrite vba;
00994 vb.lock(vba);
00996 uint vbIndex = 0;
00997 uint pbIndex = 0;
00998 uint i, k, l;
00999 for (i = 0; i < numRibbonInVB; ++i)
01000 {
01001 for (k = 0; k < (_UsedNbSegs + 1); ++k)
01002 {
01003
01005 if (k != _UsedNbSegs)
01006 {
01007 if (_BraceMode)
01008 {
01009 uint vIndex = vbIndex;
01010 for (l = 0; l < numVerticesInShape / 2; ++l)
01011 {
01012 setTri(ibaWrite, vb, pbIndex, vIndex, vIndex + numVerticesInSlice, vIndex + numVerticesInSlice + 1);
01013 pbIndex+=3;
01014 setTri(ibaWrite, vb, pbIndex, vIndex, vIndex + numVerticesInSlice + 1, vIndex + 1);
01015 pbIndex+=3;
01016 vIndex += 2;
01017 }
01018 }
01019 else
01020 {
01021 uint vIndex = vbIndex;
01022 for (l = 0; l < (numVerticesInShape - 1); ++l)
01023 {
01024 setTri(ibaWrite, vb, pbIndex, vIndex, vIndex + numVerticesInSlice, vIndex + numVerticesInSlice + 1);
01025 pbIndex+=3;
01026 setTri(ibaWrite, vb, pbIndex, vIndex, vIndex + numVerticesInSlice + 1, vIndex + 1);
01027 pbIndex+=3;
01028 ++ vIndex;
01029 }
01030
01032 uint nextVertexIndex = (numVerticesInShape == numVerticesInSlice) ? vIndex + 1 - numVerticesInShape
01033 : vIndex + 1;
01034 setTri(ibaWrite, vb, pbIndex, vIndex, vIndex + numVerticesInSlice, nextVertexIndex + numVerticesInSlice);
01035 pbIndex+=3;
01036 setTri(ibaWrite, vb, pbIndex, vIndex, nextVertexIndex + numVerticesInSlice, nextVertexIndex);
01037 pbIndex+=3;
01038 }
01039 }
01040
01042 if (_BraceMode)
01043 {
01044 for (l = 0; l < numVerticesInSlice / 2; ++l)
01045 {
01046 nlassert(vbIndex < vb.getNumVertices());
01048 if (_Tex != NULL)
01049 {
01050 vba.setTexCoord(vbIndex,
01051 _ColorScheme && _ColorFading ? 1 : 0,
01052 (float) k / _UsedNbSegs,
01053 0.f
01054 );
01055 vba.setTexCoord(vbIndex + 1,
01056 _ColorScheme && _ColorFading ? 1 : 0,
01057 (float) k / _UsedNbSegs,
01058 1.f
01059 );
01060 }
01062 if (_ColorFading)
01063 {
01064
01065 if (_ColorScheme == NULL)
01066 {
01067 uint8 intensity = (uint8) (255 * (1.f - ((float) k / _UsedNbSegs)));
01068 NLMISC::CRGBA col(intensity, intensity, intensity, intensity);
01069 vba.setColor(vbIndex, col);
01070 vba.setColor(vbIndex + 1, col);
01071 }
01072 else
01073 {
01074 vba.setTexCoord(vbIndex, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
01075 vba.setTexCoord(vbIndex + 1, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
01076 }
01077 }
01078 vbIndex += 2;
01079 }
01080 }
01081 else
01082 {
01083 for (l = 0; l < numVerticesInSlice; ++l)
01084 {
01085 nlassert(vbIndex < vb.getNumVertices());
01087 if (_Tex != NULL)
01088 {
01089 vba.setTexCoord(vbIndex,
01090 _ColorScheme && _ColorFading ? 1 : 0,
01091 (float) k / _UsedNbSegs,
01092 1.f - (l / (float) numVerticesInShape)
01093 );
01094 }
01096 if (_ColorFading)
01097 {
01098
01099 if (_ColorScheme == NULL)
01100 {
01101 uint8 intensity = (uint8) (255 * (1.f - ((float) k / _UsedNbSegs)));
01102 NLMISC::CRGBA col(intensity, intensity, intensity, intensity);
01103 vba.setColor(vbIndex, col);
01104 }
01105 else
01106 {
01107 vba.setTexCoord(vbIndex, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
01108 }
01109 }
01110 ++ vbIndex;
01111 }
01112 }
01113 }
01114 }
01115 return VBnPB;
01116 }
01117 }
01118
01119
01120 uint CPSRibbon::getNumRibbonsInVB() const
01121 {
01122 NL_PS_FUNC(CPSRibbon_getNumRibbonsInVB)
01123 const uint numVerticesInSlice = getNumVerticesInSlice();
01124 const uint vertexInVB = 512;
01125 return std::max(1u, (uint) (vertexInVB / (numVerticesInSlice * (_UsedNbSegs + 1))));
01126 }
01127
01128
01129
01130 inline void CPSRibbon::updateUntexturedMaterial()
01131 {
01132 NL_PS_FUNC(CPSRibbon_updateUntexturedMaterial)
01134
01136
01137 static NLMISC::CRefPtr<ITexture> ptGradTexture;
01138
01139 CParticleSystem &ps = *(_Owner->getOwner());
01140 if (_ColorScheme)
01141 {
01142 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting() || ps.getColorAttenuationScheme() || ps.isUserColorUsed())
01143 {
01144 if (_ColorFading)
01145 {
01146
01147
01148 if (ptGradTexture == NULL)
01149 {
01150 ptGradTexture = CreateGradientTexture();
01151 }
01152 _Mat.setTexture(0, ptGradTexture);
01153 CPSMaterial::forceTexturedMaterialStages(2);
01154 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
01155 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Diffuse);
01156 }
01157 else
01158 {
01159 CPSMaterial::forceTexturedMaterialStages(1);
01160 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
01161 }
01162 }
01163 else
01164 {
01165 if (_ColorFading)
01166 {
01167 if (ptGradTexture == NULL)
01168 {
01169 ptGradTexture = CreateGradientTexture();
01170 }
01171 _Mat.setTexture(0, ptGradTexture);
01172 ptGradTexture->setWrapS(ITexture::Clamp);
01173 ptGradTexture->setWrapT(ITexture::Clamp);
01174 CPSMaterial::forceTexturedMaterialStages(1);
01175 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01176 }
01177 else
01178 {
01179 CPSMaterial::forceTexturedMaterialStages(0);
01180 }
01181 }
01182 }
01183 else
01184 {
01185 if (_ColorFading)
01186 {
01187 CPSMaterial::forceTexturedMaterialStages(1);
01188 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
01189 }
01190 else
01191 {
01192 CPSMaterial::forceTexturedMaterialStages(0);
01193 }
01194 }
01195 _Touch = false;
01196 }
01197
01198
01199 inline void CPSRibbon::updateTexturedMaterial()
01200 {
01201 NL_PS_FUNC(CPSRibbon_updateTexturedMaterial)
01203
01205 if (_Tex)
01206 {
01207
01208
01209 }
01210 static NLMISC::CRefPtr<ITexture> ptGradTexture;
01211 CParticleSystem &ps = *(_Owner->getOwner());
01212 if (_ColorScheme)
01213 {
01214 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting() || ps.getColorAttenuationScheme() || ps.isUserColorUsed())
01215 {
01216 if (_ColorFading)
01217 {
01218 if (ptGradTexture == NULL)
01219 {
01220 ptGradTexture = CreateGradientTexture();
01221 }
01223 _Mat.setTexture(0, ptGradTexture);
01224 ptGradTexture->setWrapS(ITexture::Clamp);
01225 ptGradTexture->setWrapT(ITexture::Clamp);
01226 _Mat.setTexture(1, _Tex);
01227 CPSMaterial::forceTexturedMaterialStages(3);
01228 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01229 SetupModulatedStage(_Mat, 1, CMaterial::Texture, CMaterial::Previous);
01230 SetupModulatedStage(_Mat, 2, CMaterial::Previous, CMaterial::Constant);
01231 }
01232 else
01233 {
01234 _Mat.setTexture(0, _Tex);
01235
01236 CPSMaterial::forceTexturedMaterialStages(2);
01237 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01238 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Constant);
01239 }
01240 }
01241 else
01242 {
01243 if (_ColorFading)
01244 {
01245 if (ptGradTexture == NULL)
01246 {
01247 ptGradTexture = CreateGradientTexture();
01248 }
01249 _Mat.setTexture(0, ptGradTexture);
01250 ptGradTexture->setWrapS(ITexture::Clamp);
01251 ptGradTexture->setWrapT(ITexture::Clamp);
01252 _Mat.setTexture(1, _Tex);
01253 CPSMaterial::forceTexturedMaterialStages(2);
01254 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01255 SetupModulatedStage(_Mat, 1, CMaterial::Texture, CMaterial::Previous);
01256 }
01257 else
01258 {
01259 _Mat.setTexture(0, _Tex);
01260 CPSMaterial::forceTexturedMaterialStages(1);
01261 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01262 }
01263 }
01264 }
01265 else
01266 {
01267
01268 if (_ColorFading)
01269 {
01270 _Mat.setTexture(0, _Tex);
01271 CPSMaterial::forceTexturedMaterialStages(2);
01272 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01273 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Constant);
01274 }
01275 else
01276 {
01277 _Mat.setTexture(0, _Tex);
01278 CPSMaterial::forceTexturedMaterialStages(1);
01279 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
01280 }
01281 }
01282 _Touch = false;
01283 }
01284
01285
01286 void CPSRibbon::updateMaterial()
01287 {
01288 NL_PS_FUNC(CPSRibbon_updateMaterial)
01289 if (!_Touch) return;
01290 if (_Tex != NULL)
01291 {
01292 updateTexturedMaterial();
01293 setupTextureMatrix();
01294 }
01295 else
01296 {
01297 updateUntexturedMaterial();
01298 }
01299 }
01300
01301
01302
01303
01304 inline void CPSRibbon::setupUntexturedGlobalColor()
01305 {
01306 NL_PS_FUNC(CPSRibbon_setupUntexturedGlobalColor)
01308 CParticleSystem &ps = *(_Owner->getOwner());
01309 if (_ColorScheme)
01310 {
01311 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
01312 {
01313 _Mat.texConstantColor(0, ps.getGlobalColorLighted());
01314 }
01315 else
01316 {
01317 _Mat.texConstantColor(0, ps.getGlobalColor());
01318 }
01319 }
01320 else
01321 {
01322 NLMISC::CRGBA col;
01323 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
01324 {
01325 col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
01326 }
01327 else if (ps.getColorAttenuationScheme() || ps.isUserColorUsed())
01328 {
01329 col.modulateFromColor(ps.getGlobalColor(), _Color);
01330 }
01331 else
01332 {
01333 col = _Color;
01334 }
01335 if (_ColorFading)
01336 {
01337 _Mat.texConstantColor(0, col);
01338 }
01339 else
01340 {
01341 _Mat.setColor(col);
01342 }
01343 }
01344 }
01345
01346
01347 inline void CPSRibbon::setupTexturedGlobalColor()
01348 {
01349 NL_PS_FUNC(CPSRibbon_setupTexturedGlobalColor)
01351 CParticleSystem &ps = *(_Owner->getOwner());
01352 if (_ColorScheme)
01353 {
01354 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
01355 {
01356 if (_ColorFading)
01357 {
01358 _Mat.texConstantColor(2, ps.getGlobalColorLighted());
01359 }
01360 else
01361 {
01362 _Mat.texConstantColor(1, ps.getGlobalColorLighted());
01363 }
01364 }
01365 else
01366 {
01367 if (_ColorFading)
01368 {
01369 _Mat.texConstantColor(2, ps.getGlobalColor());
01370 }
01371 else
01372 {
01373 _Mat.texConstantColor(1, ps.getGlobalColor());
01374 }
01375 }
01376 }
01377 else
01378 {
01379 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
01380 {
01381 NLMISC::CRGBA col;
01382 col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
01383 if (_ColorFading)
01384 {
01385 _Mat.texConstantColor(1, col);
01386 }
01387 else
01388 {
01389 _Mat.setColor(col);
01390 }
01391 }
01392 else
01393 if (ps.getColorAttenuationScheme() || ps.isUserColorUsed())
01394 {
01395 NLMISC::CRGBA col;
01396 col.modulateFromColor(ps.getGlobalColor(), _Color);
01397 if (_ColorFading)
01398 {
01399 _Mat.texConstantColor(1, col);
01400 }
01401 else
01402 {
01403 _Mat.setColor(col);
01404 }
01405 }
01406 else
01407 {
01408 if (_ColorFading)
01409 {
01410 _Mat.texConstantColor(1, _Color);
01411 }
01412 else
01413 {
01414 _Mat.setColor(_Color);
01415 }
01416 }
01417 }
01418 }
01419
01420
01421
01422 void CPSRibbon::setupGlobalColor()
01423 {
01424 NL_PS_FUNC(CPSRibbon_setupGlobalColor)
01425 if (_Tex != NULL) setupTexturedGlobalColor();
01426 else setupUntexturedGlobalColor();
01427 }
01428
01429
01430 void CPSRibbon::setupTextureMatrix()
01431 {
01432 NL_PS_FUNC(CPSRibbon_setupTextureMatrix)
01433 uint stage = (_ColorScheme != NULL && _ColorFading == true) ? 1 : 0;
01434 if (_UFactor != 1.f || _VFactor != 1.f)
01435 {
01436 _Mat.enableUserTexMat(stage);
01437 CMatrix texMat;
01438 texMat.setRot(_UFactor * NLMISC::CVector::I,
01439 _VFactor * NLMISC::CVector::J,
01440 NLMISC::CVector::K
01441 );
01442 _Mat.setUserTexMat(stage, texMat);
01443 }
01444 else
01445 {
01446 _Mat.enableUserTexMat(stage, false);
01447 }
01448 _Mat.enableUserTexMat(1 - stage, false);
01449 }
01450
01451
01453 void CPSRibbon::setShape(const CVector *shape, uint32 nbPointsInShape, bool braceMode)
01454 {
01455 NL_PS_FUNC(CPSRibbon_setShape)
01456 if (!braceMode)
01457 {
01458 nlassert(nbPointsInShape >= 3);
01459 }
01460 else
01461 {
01462 nlassert(nbPointsInShape >= 2);
01463 nlassert(!(nbPointsInShape & 1));
01464 }
01465 _Shape.resize(nbPointsInShape);
01466 std::copy(shape, shape + nbPointsInShape, _Shape.begin());
01467 _BraceMode = braceMode;
01468 }
01469
01471 void CPSRibbon::getShape(CVector *shape) const
01472 {
01473 NL_PS_FUNC(CPSRibbon_getShape)
01474 std::copy(_Shape.begin(), _Shape.end(), shape);
01475 }
01476
01478 void CPSRibbon::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
01479 {
01480 NL_PS_FUNC(CPSRibbon_enumTexs)
01481 if (_Tex)
01482 {
01483 dest.push_back(_Tex);
01484 }
01485 }
01486
01487
01488 }