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_macro.h"
20 #include "nel/3d/ps_shockwave.h"
21 #include "nel/3d/driver.h"
22 #include "nel/3d/texture_grouped.h"
23 #include "nel/3d/ps_iterator.h"
24 #include "nel/3d/particle_system.h"
25 #include "nel/3d/debug_vb.h"
34 ///////////////////////////
35 // constant definition //
36 ///////////////////////////
38 // max number of shockwave to be processed at once
39 static const uint ShockWaveBufSize
= 128;
41 // the number of vertices we want in a vertex buffer
42 static const uint NumVertsInBuffer
= 8 * ShockWaveBufSize
;
45 CPSShockWave::TPBMap
CPSShockWave::_PBMap
; // the primitive blocks
46 CPSShockWave::TVBMap
CPSShockWave::_VBMap
; // vb ith unanimated texture
47 CPSShockWave::TVBMap
CPSShockWave::_AnimTexVBMap
; // vb ith unanimated texture
48 CPSShockWave::TVBMap
CPSShockWave::_ColoredVBMap
; // vb ith unanimated texture
49 CPSShockWave::TVBMap
CPSShockWave::_ColoredAnimTexVBMap
; // vb ith unanimated texture
50 /////////////////////////////////
51 // CPSShockWave implementation //
52 /////////////////////////////////
55 /** Well, we could have put a method template in CPSShockWave, but some compilers
56 * want the definition of the methods in the header, and some compilers
57 * don't want friend with function template, so we use a static method template of a friend class instead,
58 * which gives us the same result :)
60 class CPSShockWaveHelper
64 static void drawShockWave(T posIt
, CPSShockWave
&s
, uint size
, uint32 srcStep
)
66 NL_PS_FUNC(drawShockWave_drawShockWave
)
70 // get / build the vertex buffer and the primitive block
75 const uint32 vSize
= vb
->getVertexSize();
76 IDriver
*driver
= s
.getDriver();
79 s
._ColorScheme
->setColorType(driver
->getVertexColorFormat());
81 s
._Owner
->incrementNbDrawnParticles(size
); // for benchmark purpose
82 s
.setupDriverModelMatrix();
83 const uint numShockWaveToDealWith
= std::min(ShockWaveBufSize
, s
.getNumShockWavesInVB());
86 static CPlaneBasis planeBasis
[ShockWaveBufSize
];
87 float sizes
[ShockWaveBufSize
];
88 float angles
[ShockWaveBufSize
];
90 uint leftToDo
= size
, toProcess
;
95 const float angleStep
= 256.f
/ s
._NbSeg
;
98 CPlaneBasis
*ptCurrBasis
;
99 uint32 ptCurrBasisIncrement
= s
._PlaneBasisScheme
? 1 : 0;
102 uint32 ptCurrSizeIncrement
= s
._SizeScheme
? 1 : 0;
105 uint32 ptCurrAngleIncrement
= s
._Angle2DScheme
? 1 : 0;
107 CVector radVect
, innerVect
;
113 toProcess
= leftToDo
> numShockWaveToDealWith
? numShockWaveToDealWith
: leftToDo
;
114 vb
->setNumVertices((toProcess
* (s
._NbSeg
+ 1)) << 1);
116 CVertexBufferReadWrite vba
;
118 currVertex
= (uint8
*) vba
.getVertexCoordPointer();
119 endIt
= posIt
+ toProcess
;
122 ptCurrSize
= (float *) (s
._SizeScheme
->make(s
._Owner
, size
- leftToDo
, (void *) sizes
, sizeof(float), toProcess
, true, srcStep
));
126 ptCurrSize
= &s
._ParticleSize
;
129 if (s
._PlaneBasisScheme
)
131 ptCurrBasis
= (CPlaneBasis
*) (s
._PlaneBasisScheme
->make(s
._Owner
, size
- leftToDo
, (void *) planeBasis
, sizeof(CPlaneBasis
), toProcess
, true, srcStep
));
135 ptCurrBasis
= &s
._PlaneBasis
;
138 if (s
._Angle2DScheme
)
140 ptCurrAngle
= (float *) (s
._Angle2DScheme
->make(s
._Owner
, size
- leftToDo
, (void *) angles
, sizeof(float), toProcess
, true, srcStep
));
144 ptCurrAngle
= &s
._Angle2D
;
148 s
.updateVbColNUVForRender(size
- leftToDo
, toProcess
, srcStep
, *vb
, *driver
);
151 currAngle
= *ptCurrAngle
;
152 if (fabsf(*ptCurrSize
) > 10E-6)
154 radiusRatio
= (*ptCurrSize
- s
._RadiusCut
) / *ptCurrSize
;
161 for (k
= 0; k
<= s
._NbSeg
; ++k
)
163 radVect
= *ptCurrSize
* (CPSUtil::getCos((sint32
) currAngle
) * ptCurrBasis
->X
+ CPSUtil::getSin((sint32
) currAngle
) * ptCurrBasis
->Y
);
164 innerVect
= radiusRatio
* radVect
;
165 CHECK_VERTEX_BUFFER(*vb
, currVertex
);
166 * (CVector
*) currVertex
= *posIt
+ radVect
;
168 CHECK_VERTEX_BUFFER(*vb
, currVertex
);
169 * (CVector
*) currVertex
= *posIt
+ innerVect
;
171 currAngle
+= angleStep
;
175 ptCurrBasis
+= ptCurrBasisIncrement
;
176 ptCurrSize
+= ptCurrSizeIncrement
;
177 ptCurrAngle
+= ptCurrAngleIncrement
;
179 while (posIt
!= endIt
);
182 const uint numTri
= 2 * toProcess
* s
._NbSeg
;
183 pb
->setNumIndexes(3 * numTri
);
184 driver
->activeIndexBuffer(*pb
);
185 driver
->activeVertexBuffer(*vb
);
186 driver
->renderTriangles(s
._Mat
, 0, numTri
);
187 leftToDo
-= toProcess
;
194 ///=================================================================================
195 CPSShockWave::CPSShockWave(uint nbSeg
, float radiusCut
, CSmartPtr
<ITexture
> tex
)
197 , _RadiusCut(radiusCut
)
201 NL_PS_FUNC(CPSShockWave_CPSShockWave
)
202 nlassert(nbSeg
> 2 && nbSeg
<= 64);
205 if (CParticleSystem::getSerializeIdentifierFlag()) _Name
= std::string("ShockWave");
208 ///=================================================================================
209 uint32
CPSShockWave::getNumWantedTris() const
211 NL_PS_FUNC(CPSShockWave_getNumWantedTris
)
213 //return (_Owner->getMaxSize() * _NbSeg) << 1 ;
214 return (_Owner
->getSize() * _NbSeg
) << 1 ;
217 ///=================================================================================
218 bool CPSShockWave::hasTransparentFaces(void)
220 NL_PS_FUNC(CPSShockWave_hasTransparentFaces
)
221 return getBlendingMode() != CPSMaterial::alphaTest
;
224 ///=================================================================================
225 bool CPSShockWave::hasOpaqueFaces(void)
227 NL_PS_FUNC(CPSShockWave_hasOpaqueFaces
)
228 return !hasTransparentFaces();
231 ///=================================================================================
232 void CPSShockWave::setNbSegs(uint nbSeg
)
234 NL_PS_FUNC(CPSShockWave_setNbSegs
)
235 nlassert(nbSeg
> 2 && nbSeg
<= 64);
239 resize(_Owner
->getMaxSize());
240 //notifyOwnerMaxNumFacesChanged();
244 ///=================================================================================
245 void CPSShockWave::setRadiusCut(float radiusCut
)
247 NL_PS_FUNC(CPSShockWave_setRadiusCut
)
248 _RadiusCut
= radiusCut
;
251 resize(_Owner
->getMaxSize());
255 ///=================================================================================
256 void CPSShockWave::setUFactor(float value
)
258 NL_PS_FUNC(CPSShockWave_setUFactor
)
259 nlassert(_Owner
); // must be attached to an owner before to call this method
261 resize(_Owner
->getSize()); // resize also recomputes the UVs..
264 ///=================================================================================
265 void CPSShockWave::serial(NLMISC::IStream
&f
)
267 NL_PS_FUNC(CPSShockWave_serial
)
268 sint ver
= f
.serialVersion(2);
269 CPSParticle::serial(f
);
270 CPSColoredParticle::serialColorScheme(f
);
271 CPSSizedParticle::serialSizeScheme(f
);
272 CPSTexturedParticle::serialTextureScheme(f
);
273 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f
);
274 CPSRotated2DParticle::serialAngle2DScheme(f
);
276 f
.serial(_NbSeg
, _RadiusCut
);
284 ///=================================================================================
285 inline void CPSShockWave::setupUFactor()
287 NL_PS_FUNC(CPSShockWave_setupUFactor
)
290 _Mat
.enableUserTexMat(0);
292 texMat
.setRot(_UFactor
* NLMISC::CVector::I
,
296 _Mat
.setUserTexMat(0, texMat
);
300 _Mat
.enableUserTexMat(0, false);
304 ///=================================================================================
305 void CPSShockWave::draw(bool opaque
)
307 // if (!FilterPS[7]) return;
308 NL_PS_FUNC(CPSShockWave_draw
)
310 if (!_Owner
->getSize()) return;
314 computeSrcStep(step
, numToProcess
);
315 if (!numToProcess
) return;
319 /// update the material if the global color of the system is variable
320 CParticleSystem
&ps
= *(_Owner
->getOwner());
321 /// update the material if the global color of the system is variable
322 if (_ColorScheme
!= NULL
&&
323 (ps
.getColorAttenuationScheme() != NULL
||
324 ps
.isUserColorUsed() ||
325 ps
.getForceGlobalColorLightingFlag() ||
326 usesGlobalColorLighting()
330 if (ps
.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
332 CPSMaterial::forceModulateConstantColor(true, ps
.getGlobalColorLighted());
336 CPSMaterial::forceModulateConstantColor(true, ps
.getGlobalColor());
341 forceModulateConstantColor(false);
342 if (ps
.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
345 col
.modulateFromColor(ps
.getGlobalColorLighted(), _Color
);
349 if (!ps
.getColorAttenuationScheme() || ps
.isUserColorUsed())
351 _Mat
.setColor(_Color
);
356 col
.modulateFromColor(ps
.getGlobalColor(), _Color
);
364 if (step
== (1 << 16))
366 CPSShockWaveHelper::drawShockWave(_Owner
->getPos().begin(),
374 CPSShockWaveHelper::drawShockWave(TIteratorVectStep1616(_Owner
->getPos().begin(), 0, step
),
384 ///=================================================================================
385 bool CPSShockWave::completeBBox(NLMISC::CAABBox
&box
) const
387 NL_PS_FUNC(CPSShockWave_completeBBox
)
388 // TODO : implement this
392 ///=================================================================================
393 void CPSShockWave::init(void)
395 NL_PS_FUNC(CPSShockWave_init
)
396 _Mat
.setLighting(false);
397 _Mat
.setZFunc(CMaterial::less
);
398 _Mat
.setDoubleSided(true);
399 updateMatAndVbForColor();
400 updateMatAndVbForTexture();
403 ///=================================================================================
404 void CPSShockWave::updateVbColNUVForRender(uint32 startIndex
, uint32 size
, uint32 srcStep
, CVertexBuffer
&vb
, IDriver
&drv
)
406 NL_PS_FUNC(CPSShockWave_updateVbColNUVForRender
)
408 CVertexBufferReadWrite vba
;
413 // compute the colors, each color is replicated n times...
414 _ColorScheme
->makeN(_Owner
, startIndex
, vba
.getColorPointer(), vb
.getVertexSize(), size
, (_NbSeg
+ 1) << 1, srcStep
);
417 if (_TexGroup
) // if it has a constant texture we are sure it has been setupped before...
419 sint32 textureIndex
[ShockWaveBufSize
];
420 const uint32 stride
= vb
.getVertexSize(), stride2
= stride
<< 1;
421 uint8
*currUV
= (uint8
*) vba
.getTexCoordPointer();
424 uint32 currIndexIncr
;
425 const sint32
*currIndex
;
427 if (_TextureIndexScheme
)
429 currIndex
= (sint32
*) (_TextureIndexScheme
->make(_Owner
, startIndex
, textureIndex
, sizeof(sint32
), size
, true, srcStep
));
434 currIndex
= &_TextureIndex
;
440 // for now, we don't make texture index wrapping
441 const CTextureGrouped::TFourUV
&uvGroup
= _TexGroup
->getUVQuad((uint32
) *currIndex
);
443 for (k
= 0; k
<= _NbSeg
; ++k
)
446 *(CUV
*) currUV
= uvGroup
.uv0
+ CUV(k
* _UFactor
, 0);
447 *(CUV
*) (currUV
+ stride
) = uvGroup
.uv3
+ CUV(k
* _UFactor
, 0);
448 // point the next quad
452 currIndex
+= currIndexIncr
;
457 ///=================================================================================
458 void CPSShockWave::updateMatAndVbForColor(void)
460 NL_PS_FUNC(CPSShockWave_updateMatAndVbForColor
)
463 resize(_Owner
->getMaxSize());
467 ///=================================================================================
468 void CPSShockWave::updateMatAndVbForTexture(void)
470 NL_PS_FUNC(CPSShockWave_updateMatAndVbForTexture
)
471 _Mat
.setTexture(0, _TexGroup
? (ITexture
*) _TexGroup
: (ITexture
*) _Tex
);
474 ///=================================================================================
475 void CPSShockWave::newElement(const CPSEmitterInfo
&info
)
477 NL_PS_FUNC(CPSShockWave_newElement
)
478 newColorElement(info
);
479 newTextureIndexElement(info
);
480 newSizeElement(info
);
481 newAngle2DElement(info
);
484 ///=================================================================================
485 void CPSShockWave::deleteElement(uint32 index
)
487 NL_PS_FUNC(CPSShockWave_deleteElement
)
488 deleteColorElement(index
);
489 deleteTextureIndexElement(index
);
490 deleteSizeElement(index
);
491 deleteAngle2DElement(index
);
494 ///=================================================================================
495 void CPSShockWave::resize(uint32 aSize
)
497 NL_PS_FUNC(CPSShockWave_resize
)
498 nlassert(aSize
< (1 << 16));
500 resizeTextureIndex(aSize
);
502 resizeAngle2D(aSize
);
505 ///=================================================================================
506 void CPSShockWave::getVBnPB(CVertexBuffer
*&retVb
, CIndexBuffer
*&retPb
)
508 NL_PS_FUNC(CPSShockWave_getVBnPB
)
509 TVBMap
&vbMap
= _ColorScheme
== NULL
? (_TexGroup
== NULL
? _VBMap
: _AnimTexVBMap
)
510 : (_TexGroup
== NULL
? _ColoredVBMap
: _ColoredAnimTexVBMap
);
513 TVBMap::iterator vbIt
= vbMap
.find(_NbSeg
);
514 if (vbIt
!= vbMap
.end())
516 retVb
= &(vbIt
->second
);
517 TPBMap::iterator pbIt
= _PBMap
.find(_NbSeg
);
518 nlassert(pbIt
!= _PBMap
.end());
519 retPb
= &(pbIt
->second
);
521 else // we need to create the vb
523 // create an entry (we setup the primitive block at the same time, this could be avoided, but doesn't make much difference)
524 CVertexBuffer
&vb
= vbMap
[_NbSeg
]; // create a vb
525 CIndexBuffer
&pb
= _PBMap
[_NbSeg
]; // eventually create a pb
526 const uint32 size
= getNumShockWavesInVB();
527 vb
.setVertexFormat(CVertexBuffer::PositionFlag
|
528 CVertexBuffer::TexCoord0Flag
|
529 (_ColorScheme
!= NULL
? CVertexBuffer::PrimaryColorFlag
: 0)
531 vb
.setNumVertices((size
* (_NbSeg
+ 1)) << 1 );
532 vb
.setPreferredMemory(CVertexBuffer::AGPVolatile
, true);
533 CVertexBufferReadWrite vba
;
535 pb
.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT
);
536 pb
.setNumIndexes(2 * 3 * size
* _NbSeg
);
537 CIndexBufferReadWrite ibaWrite
;
540 for (uint32 k
= 0; k
< size
; ++k
)
542 for (uint32 l
= 0; l
< _NbSeg
; ++l
)
544 const uint32 index
= ((k
* (_NbSeg
+ 1)) + l
) << 1;
545 ibaWrite
.setTri(finalIndex
, index
+ 1 , index
+ 3, index
+ 2);
547 ibaWrite
.setTri(finalIndex
, index
+ 1, index
+ 2, index
+ 0);
549 vba
.setTexCoord(index
, 0, CUV((float) l
, 0));
550 vba
.setTexCoord(index
+ 1, 0, CUV((float) l
, 1));
552 const uint32 index
= ((k
* (_NbSeg
+ 1)) + _NbSeg
) << 1;
553 vba
.setTexCoord(index
, 0, CUV((float) _NbSeg
, 0));
554 vba
.setTexCoord(index
+ 1, 0, CUV((float) _NbSeg
, 1));
558 vb
.setName("CPSShockWave");
559 NL_SET_IB_NAME(pb
, "CPSShockWave");
563 ///=================================================================================
564 uint
CPSShockWave::getNumShockWavesInVB() const
566 NL_PS_FUNC(CPSShockWave_getNumShockWavesInVB
)
567 const uint numRib
= NumVertsInBuffer
/ ((_NbSeg
+ 1) << 1);
568 return std::max(1u, numRib
);
571 ///=================================================================================
572 void CPSShockWave::enumTexs(std::vector
<NLMISC::CSmartPtr
<ITexture
> > &dest
, IDriver
&drv
)
574 NL_PS_FUNC(CPSShockWave_enumTexs
)
575 CPSTexturedParticle::enumTexs(dest
);