1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
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.
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/>.
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"
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
,
42 false, /* dont delete */
43 false, /* not a file */
46 tex
->setWrapS(ITexture::Clamp
);
47 tex
->setShareName("#GradBW");
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),
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);
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);
98 if (ver3
> 1) f
.serialEnum(_LOD
);
99 if (ver3
> 2) f
.serial(_Name
);
116 bool bDisableAutoLOD
;
117 f
.serial(bDisableAutoLOD
);
118 disableAutoLOD(bDisableAutoLOD
);
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
);
136 resize(_Owner
->getMaxSize());
143 CPSRibbonBase::serial(f
);
144 CPSColoredParticle::serialColorScheme(f
);
145 CPSMaterial::serialMaterial(f
);
146 bool colorFading
= _ColorFading
;
147 f
.serial(colorFading
);
148 _ColorFading
= colorFading
;
151 uint32 tailNbSegs
= _NbSegs
;
152 f
.serial(tailNbSegs
);
156 setTailNbSeg(_NbSegs
);
163 //=======================================================
164 void CPSTailDot::step(TPSProcessPass pass
)
166 NL_PS_FUNC(CPSTailDot_step
)
167 if (pass
== PSMotion
)
176 (pass
== PSBlendRender
&& hasTransparentFaces())
177 || (pass
== PSSolidRender
&& hasOpaqueFaces())
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());
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
);
204 if (pass
== PSToolRender
) // edition mode only
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
);
238 //=======================================================
239 void CPSTailDot::updateMatAndVbForColor(void)
241 NL_PS_FUNC(CPSTailDot_updateMatAndVbForColor
)
245 //==========================================================================
246 void CPSTailDot::displayRibbons(uint32 nbRibbons
, uint32 srcStep
)
248 // if (!FilterPS[8]) return;
249 NL_PS_FUNC(CPSTailDot_displayRibbons
)
250 if (!nbRibbons
) return;
252 CPSRibbonBase::updateLOD();
253 if (_UsedNbSegs
< 2) return;
254 const float date
= _Owner
->getOwner()->getSystemDate();
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();
262 IDriver
*drv
= this->getDriver();
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;
274 CParticleSystem
&ps
= *(_Owner
->getOwner());
275 bool useGlobalColor
= ps
.getColorAttenuationScheme() != NULL
|| ps
.isUserColorUsed();
276 if (useGlobalColor
!= _GlobalColor
)
278 _GlobalColor
= useGlobalColor
;
281 if (usesGlobalColorLighting() != _Lighted
)
283 _Lighted
= usesGlobalColorLighting();
286 if (ps
.getForceGlobalColorLightingFlag() != _ForceLighted
)
288 _ForceLighted
= ps
.getForceGlobalColorLightingFlag();
296 colorOffset
= VB
.getColorOff();
299 /////////////////////
300 // Compute ribbons //
301 /////////////////////
304 uint ribbonIndex
= 0; // index of the first ribbon in the batch being processed
305 uint32 fpRibbonIndex
= 0; // fixed point index in source
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
;
317 currVert
= (uint8
*) vba
.getVertexCoordPointer();
322 _ColorScheme
->makeN(this->_Owner
, ribbonIndex
, currVert
+ colorOffset
, vertexSize
, toProcess
, _UsedNbSegs
+ 1, srcStep
);
325 //////////////////////////////////////////////////////////////////////////////////////
326 // interpolate and project points the result is directly setup in the vertex buffer //
327 //////////////////////////////////////////////////////////////////////////////////////
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
;
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
;
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
)
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);
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
432 CIndexBufferReadWrite ibaWrite
;
434 CVertexBufferReadWrite 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);
461 vb
.setName("CPSTailDot");
462 NL_SET_IB_NAME(pb
, "CPSTailDot");
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
)
483 static NLMISC::CRefPtr
<ITexture
> ptGradTexture
;
485 CParticleSystem
&ps
= *(_Owner
->getOwner());
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
);
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
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
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());
551 if (ps
.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
553 _Mat
.texConstantColor(0, ps
.getGlobalColorLighted());
557 _Mat
.texConstantColor(0, ps
.getGlobalColor());
560 else // GLOBAL COLOR with / without fading
562 if (ps
.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
565 col
.modulateFromColor(ps
.getGlobalColorLighted(), _Color
);
568 _Mat
.texConstantColor(0, col
);
570 else // color attenuation, no fading :
576 if (ps
.getColorAttenuationScheme() || ps
.isUserColorUsed())
579 col
.modulateFromColor(ps
.getGlobalColor(), _Color
);
582 _Mat
.texConstantColor(0, col
);
584 else // color attenuation, no fading :
593 _Mat
.texConstantColor(0, _Color
);
595 else // constant color
597 _Mat
.setColor(_Color
);