Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / ps_tail_dot.cpp
blobe8146e5829f52a5abb7bd8dcd8714bee306ddacc
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "std3d.h"
19 #include "nel/3d/ps_tail_dot.h"
20 #include "nel/3d/ps_macro.h"
21 #include "nel/3d/driver.h"
22 #include "nel/3d/particle_system.h"
23 #include "nel/3d/texture_mem.h"
24 #include "nel/misc/smart_ptr.h"
26 #include <memory>
28 #ifdef DEBUG_NEW
29 #define new DEBUG_NEW
30 #endif
32 namespace NL3D
34 static NLMISC::CRGBA GradientB2W[] = {NLMISC::CRGBA(0, 0, 0, 0), NLMISC::CRGBA(255, 255, 255, 255) };
36 /// private use : this create a gradient texture that goew from black to white
37 static ITexture *CreateGradientTexture()
39 NL_PS_FUNC(CreateGradientTexture)
40 CUniquePtr<CTextureMem> tex(new CTextureMem((uint8 *) &GradientB2W,
41 sizeof(GradientB2W),
42 false, /* dont delete */
43 false, /* not a file */
44 2, 1)
46 tex->setWrapS(ITexture::Clamp);
47 tex->setShareName("#GradBW");
48 return tex.release();
52 ///////////////////////////////
53 // CPSTailDot implementation //
54 ///////////////////////////////
56 CPSTailDot::TVBMap CPSTailDot::_VBMap; // index / vertex buffers with no color
57 CPSTailDot::TVBMap CPSTailDot::_FadedVBMap; // index / vertex buffers for constant color with fading
58 CPSTailDot::TVBMap CPSTailDot::_ColoredVBMap; // index / vertex buffer + colors
59 CPSTailDot::TVBMap CPSTailDot::_FadedColoredVBMap; // index / vertex buffer + faded colors
61 //=======================================================
62 CPSTailDot::CPSTailDot() : _ColorFading(false),
63 _GlobalColor(false),
64 _Lighted(false),
65 _ForceLighted(false),
66 _Touch(true)
68 NL_PS_FUNC(CPSTailDot_CPSTailDot)
69 setInterpolationMode(Linear);
70 setSegDuration(0.06f);
71 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("TailDot");
74 //=======================================================
75 CPSTailDot::~CPSTailDot()
77 NL_PS_FUNC(CPSTailDot_CPSTailDotDtor)
78 // delete _DyingRibbons;
81 //=======================================================
82 void CPSTailDot::serial(NLMISC::IStream &f)
84 NL_PS_FUNC(CPSTailDot_serial)
86 sint ver = f.serialVersion(3);
87 if (ver == 1)
89 nlassert(f.isReading());
91 /// we had CPSParticle::serial(f), but this is not the base class anymore, so we emulate this...
92 /// version 2 : auto-lod saved
93 sint ver2 = f.serialVersion(2);
95 // here is CPSLocatedBindable::serial(f)
96 sint ver3 = f.serialVersion(4);
97 f.serialPtr(_Owner);
98 if (ver3 > 1) f.serialEnum(_LOD);
99 if (ver3 > 2) f.serial(_Name);
100 if (ver3 > 3)
102 if (f.isReading())
104 uint32 id;
105 f.serial(id);
106 setExternID(id);
108 else
110 f.serial(_ExternID);
114 if (ver2 >= 2)
116 bool bDisableAutoLOD;
117 f.serial(bDisableAutoLOD);
118 disableAutoLOD(bDisableAutoLOD);
121 uint32 tailNbSegs;
122 bool colorFading;
123 bool systemBasisEnabled;
125 CPSColoredParticle::serialColorScheme(f);
126 f.serial(tailNbSegs, colorFading, systemBasisEnabled);
128 _ColorFading = colorFading;
129 _NbSegs = tailNbSegs >> 1;
130 if (_NbSegs < 2) _NbSegs = 2;
131 setInterpolationMode(Linear);
132 serialMaterial(f);
135 nlassert(_Owner);
136 resize(_Owner->getMaxSize());
137 initDateVect();
138 resetFromOwner();
141 if (ver >= 2)
143 CPSRibbonBase::serial(f);
144 CPSColoredParticle::serialColorScheme(f);
145 CPSMaterial::serialMaterial(f);
146 bool colorFading = _ColorFading;
147 f.serial(colorFading);
148 _ColorFading = colorFading;
149 if (ver >= 3)
151 uint32 tailNbSegs = _NbSegs;
152 f.serial(tailNbSegs);
154 if (f.isReading())
156 setTailNbSeg(_NbSegs);
157 touch();
163 //=======================================================
164 void CPSTailDot::step(TPSProcessPass pass)
166 NL_PS_FUNC(CPSTailDot_step)
167 if (pass == PSMotion)
169 if (!_Parametric)
171 updateGlobals();
174 else
175 if (
176 (pass == PSBlendRender && hasTransparentFaces())
177 || (pass == PSSolidRender && hasOpaqueFaces())
180 uint32 step;
181 uint numToProcess;
182 computeSrcStep(step, numToProcess);
183 if (!numToProcess) return;
185 /// update the material color
186 CParticleSystem &ps = *(_Owner->getOwner());
187 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
189 _Mat.setColor(ps.getGlobalColorLighted());
191 else
193 _Mat.setColor(ps.getGlobalColor());
196 /** We support Auto-LOD for ribbons, although there is a built-in LOD (that change the geometry rather than the number of ribbons)
197 * that gives better result (both can be used simultaneously)
200 displayRibbons(numToProcess, step);
203 else
204 if (pass == PSToolRender) // edition mode only
206 //showTool();
211 //=======================================================
212 void CPSTailDot::newElement(const CPSEmitterInfo &info)
214 NL_PS_FUNC(CPSTailDot_newElement)
215 CPSRibbonBase::newElement(info);
216 newColorElement(info);
220 //=======================================================
221 void CPSTailDot::deleteElement(uint32 index)
223 NL_PS_FUNC(CPSTailDot_deleteElement)
224 CPSRibbonBase::deleteElement(index);
225 deleteColorElement(index);
229 //=======================================================
230 void CPSTailDot::resize(uint32 size)
232 NL_PS_FUNC(CPSTailDot_resize)
233 nlassert(size < (1 << 16));
234 CPSRibbonBase::resize(size);
235 resizeColor(size);
238 //=======================================================
239 void CPSTailDot::updateMatAndVbForColor(void)
241 NL_PS_FUNC(CPSTailDot_updateMatAndVbForColor)
242 touch();
245 //==========================================================================
246 void CPSTailDot::displayRibbons(uint32 nbRibbons, uint32 srcStep)
248 // if (!FilterPS[8]) return;
249 NL_PS_FUNC(CPSTailDot_displayRibbons)
250 if (!nbRibbons) return;
251 nlassert(_Owner);
252 CPSRibbonBase::updateLOD();
253 if (_UsedNbSegs < 2) return;
254 const float date = _Owner->getOwner()->getSystemDate();
255 uint8 *currVert;
256 CVBnPB &VBnPB = getVBnPB(); // get the appropriate vb (built it if needed)
257 CVertexBuffer &VB = VBnPB.VB;
258 CIndexBuffer &PB = VBnPB.PB;
259 const uint32 vertexSize = VB.getVertexSize();
260 uint colorOffset=0;
262 IDriver *drv = this->getDriver();
263 #ifdef NL_DEBUG
264 nlassert(drv);
265 #endif
266 drv->setupModelMatrix(getLocalToWorldTrailMatrix());
267 _Owner->incrementNbDrawnParticles(nbRibbons); // for benchmark purpose
268 const uint numRibbonBatch = getNumRibbonsInVB(); // number of ribons to process at once
269 if (_UsedNbSegs == 0) return;
271 ////////////////////
272 // Material setup //
273 ////////////////////
274 CParticleSystem &ps = *(_Owner->getOwner());
275 bool useGlobalColor = ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed();
276 if (useGlobalColor != _GlobalColor)
278 _GlobalColor = useGlobalColor;
279 touch();
281 if (usesGlobalColorLighting() != _Lighted)
283 _Lighted = usesGlobalColorLighting();
284 touch();
286 if (ps.getForceGlobalColorLightingFlag() != _ForceLighted)
288 _ForceLighted = ps.getForceGlobalColorLightingFlag();
289 touch();
291 updateMaterial();
292 setupGlobalColor();
294 if (_ColorScheme)
296 colorOffset = VB.getColorOff();
299 /////////////////////
300 // Compute ribbons //
301 /////////////////////
303 uint toProcess;
304 uint ribbonIndex = 0; // index of the first ribbon in the batch being processed
305 uint32 fpRibbonIndex = 0; // fixed point index in source
306 if (_ColorScheme)
308 _ColorScheme->setColorType(drv->getVertexColorFormat());
312 toProcess = std::min((uint) (nbRibbons - ribbonIndex) /* = left to do */, numRibbonBatch);
313 VB.setNumVertices((_UsedNbSegs + 1) * toProcess);
315 CVertexBufferReadWrite vba;
316 VB.lock (vba);
317 currVert = (uint8 *) vba.getVertexCoordPointer();
319 /// compute colors
320 if (_ColorScheme)
322 _ColorScheme->makeN(this->_Owner, ribbonIndex, currVert + colorOffset, vertexSize, toProcess, _UsedNbSegs + 1, srcStep);
324 uint k = toProcess;
325 //////////////////////////////////////////////////////////////////////////////////////
326 // interpolate and project points the result is directly setup in the vertex buffer //
327 //////////////////////////////////////////////////////////////////////////////////////
328 if (!_Parametric)
331 //////////////////////
332 // INCREMENTAL CASE //
333 //////////////////////
336 // the parent class has a method to get the ribbons positions
337 computeRibbon((uint) (fpRibbonIndex >> 16), (CVector *) currVert, vertexSize);
338 currVert += vertexSize * (_UsedNbSegs + 1);
339 fpRibbonIndex += srcStep;
341 while (--k);
343 else
345 //////////////////////
346 // PARAMETRIC CASE //
347 //////////////////////
350 // we compute each pos thanks to the parametric curve
351 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
352 (NLMISC::CVector *) currVert, vertexSize);
353 currVert += vertexSize * (_UsedNbSegs + 1);
354 fpRibbonIndex += srcStep;
356 while (--k);
360 const uint numLine = _UsedNbSegs * toProcess;
361 PB.setNumIndexes(2 * numLine);
362 // display the result
363 drv->activeIndexBuffer(PB);
364 drv->activeVertexBuffer(VB);
365 drv->renderLines (_Mat, 0, numLine);
366 ribbonIndex += toProcess;
368 while (ribbonIndex != nbRibbons);
371 //==========================================================================
372 bool CPSTailDot::hasTransparentFaces(void)
374 NL_PS_FUNC(CPSTailDot_hasTransparentFaces)
375 return getBlendingMode() != CPSMaterial::alphaTest ;
379 //==========================================================================
380 bool CPSTailDot::hasOpaqueFaces(void)
382 NL_PS_FUNC(CPSTailDot_hasOpaqueFaces)
383 return !hasTransparentFaces();
386 //==========================================================================
387 uint32 CPSTailDot::getNumWantedTris() const
389 NL_PS_FUNC(CPSTailDot_getNumWantedTris)
390 nlassert(_Owner);
391 //return _Owner->getMaxSize() * _NbSegs;
392 return _Owner->getSize() * _NbSegs;
397 //==========================================================================
398 CPSTailDot::CVBnPB &CPSTailDot::getVBnPB()
400 NL_PS_FUNC(CPSTailDot_getVBnPB)
401 /// choose the right vb
402 TVBMap &map = _ColorScheme ? (_ColorFading ? _FadedColoredVBMap : _ColoredVBMap) // per ribbon color
403 : (_ColorFading ? _FadedVBMap : _VBMap); // global color
404 TVBMap::iterator it = map.find(_UsedNbSegs + 1);
405 if (it != map.end())
407 return it->second;
409 else // must create this vb, with few different size, it is still interseting, though they are only destroyed at exit
411 const uint numRibbonInVB = getNumRibbonsInVB();
412 CVBnPB &VBnPB = map[_UsedNbSegs + 1]; // make an entry
414 /// set the vb format & size
415 /// In the case of a ribbon with color and fading, we encode the fading in a texture
416 /// If the ribbon has fading, but only a global color, we encode it in the primary color
417 CVertexBuffer &vb = VBnPB.VB;
418 vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
419 vb.setVertexFormat(CVertexBuffer::PositionFlag
420 |(_ColorScheme || _ColorFading ? CVertexBuffer::PrimaryColorFlag : 0)
421 | (_ColorScheme && _ColorFading ? CVertexBuffer::TexCoord0Flag : 0));
423 vb.setNumVertices((_UsedNbSegs + 1) * numRibbonInVB ); // 1 seg = 1 line + terminal vertices
425 // set the primitive block size
426 CIndexBuffer &pb = VBnPB.PB;
427 pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
428 pb.setNumIndexes(2 * _UsedNbSegs * numRibbonInVB);
429 /// Setup the pb and vb parts. Not very fast but executed only once
430 uint vbIndex = 0;
431 uint pbIndex = 0;
432 CIndexBufferReadWrite ibaWrite;
433 pb.lock (ibaWrite);
434 CVertexBufferReadWrite vba;
435 vb.lock (vba);
436 for (uint i = 0; i < numRibbonInVB; ++i)
438 for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
441 if (_ColorScheme && _ColorFading)
443 vba.setTexCoord(vbIndex, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
445 else if (_ColorFading)
447 uint8 intensity = (uint8) (255 * (1.f - ((float) k / _UsedNbSegs)));
448 NLMISC::CRGBA col(intensity, intensity, intensity, intensity);
449 vba.setColor(vbIndex, col);
452 /// add 1 line in the primitive block
453 if (k != _UsedNbSegs)
455 ibaWrite.setLine(pbIndex, vbIndex, vbIndex + 1);
456 pbIndex+=2;
458 ++vbIndex;
461 vb.setName("CPSTailDot");
462 NL_SET_IB_NAME(pb, "CPSTailDot");
463 return VBnPB;
467 //==========================================================================
468 uint CPSTailDot::getNumRibbonsInVB() const
470 NL_PS_FUNC(CPSTailDot_getNumRibbonsInVB)
471 /// approximation of the max number of vertices we want in a vb
472 const uint vertexInVB = 256;
473 return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
477 //==========================================================================
478 void CPSTailDot::updateMaterial()
480 NL_PS_FUNC(CPSTailDot_updateMaterial)
481 if (!_Touch) return;
483 static NLMISC::CRefPtr<ITexture> ptGradTexture;
485 CParticleSystem &ps = *(_Owner->getOwner());
486 if (_ColorScheme)
487 { // PER RIBBON COLOR
488 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting() || ps.getColorAttenuationScheme() || ps.isUserColorUsed())
490 if (_ColorFading) // global color + fading + per ribbon color
492 // the first stage is used to get fading * global color
493 // the second stage multiply the result by the diffuse colot
494 if (ptGradTexture == NULL) // have we got a gradient texture ?
496 ptGradTexture = CreateGradientTexture();
498 _Mat.setTexture(0, ptGradTexture);
499 CPSMaterial::forceTexturedMaterialStages(2); // use constant color 0 * diffuse, 1 stage needed
500 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
501 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Diffuse);
503 else // per ribbon color with global color
505 CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed
506 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
509 else
511 if (_ColorFading) // per ribbon color, fading
513 if (ptGradTexture == NULL) // have we got a gradient texture ?
515 ptGradTexture = CreateGradientTexture();
517 _Mat.setTexture(0, ptGradTexture);
518 CPSMaterial::forceTexturedMaterialStages(1);
519 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
521 else // per color ribbon with no fading, and no global color
523 CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only
527 else // GLOBAL COLOR
529 if (_ColorFading)
531 CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed
532 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
534 else // constant color
536 CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only
540 _Touch = false;
543 //==========================================================================
544 void CPSTailDot::setupGlobalColor()
546 NL_PS_FUNC(CPSTailDot_setupGlobalColor)
547 /// setup the global color if it is used
548 CParticleSystem &ps = *(_Owner->getOwner());
549 if (_ColorScheme)
551 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
553 _Mat.texConstantColor(0, ps.getGlobalColorLighted());
555 else
557 _Mat.texConstantColor(0, ps.getGlobalColor());
560 else // GLOBAL COLOR with / without fading
562 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
564 NLMISC::CRGBA col;
565 col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
566 if (_ColorFading)
568 _Mat.texConstantColor(0, col);
570 else // color attenuation, no fading :
572 _Mat.setColor(col);
575 else
576 if (ps.getColorAttenuationScheme() || ps.isUserColorUsed())
578 NLMISC::CRGBA col;
579 col.modulateFromColor(ps.getGlobalColor(), _Color);
580 if (_ColorFading)
582 _Mat.texConstantColor(0, col);
584 else // color attenuation, no fading :
586 _Mat.setColor(col);
589 else
591 if (_ColorFading)
593 _Mat.texConstantColor(0, _Color);
595 else // constant color
597 _Mat.setColor(_Color);
603 } // NL3D