Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / 3d / ps_shockwave.cpp
blobcc7547c45d7992b6f30c7b27e4f58212b5f7587d
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_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"
27 #ifdef DEBUG_NEW
28 #define new DEBUG_NEW
29 #endif
31 namespace NL3D
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
62 public:
63 template <class T>
64 static void drawShockWave(T posIt, CPSShockWave &s, uint size, uint32 srcStep)
66 NL_PS_FUNC(drawShockWave_drawShockWave)
67 PARTICLES_CHECK_MEM;
68 nlassert(s._Owner);
70 // get / build the vertex buffer and the primitive block
71 CVertexBuffer *vb;
72 CIndexBuffer *pb;
73 s.getVBnPB(vb, pb);
75 const uint32 vSize = vb->getVertexSize();
76 IDriver *driver = s.getDriver();
77 if (s._ColorScheme)
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;
91 T endIt;
92 uint8 *currVertex;
93 uint k ;
95 const float angleStep = 256.f / s._NbSeg;
96 float currAngle;
98 CPlaneBasis *ptCurrBasis;
99 uint32 ptCurrBasisIncrement = s._PlaneBasisScheme ? 1 : 0;
101 float *ptCurrSize;
102 uint32 ptCurrSizeIncrement = s._SizeScheme ? 1 : 0;
104 float *ptCurrAngle;
105 uint32 ptCurrAngleIncrement = s._Angle2DScheme ? 1 : 0;
107 CVector radVect, innerVect;
108 float radiusRatio;
113 toProcess = leftToDo > numShockWaveToDealWith ? numShockWaveToDealWith : leftToDo;
114 vb->setNumVertices((toProcess * (s._NbSeg + 1)) << 1);
116 CVertexBufferReadWrite vba;
117 vb->lock (vba);
118 currVertex = (uint8 *) vba.getVertexCoordPointer();
119 endIt = posIt + toProcess;
120 if (s._SizeScheme)
122 ptCurrSize = (float *) (s._SizeScheme->make(s._Owner, size - leftToDo, (void *) sizes, sizeof(float), toProcess, true, srcStep));
124 else
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));
133 else
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));
142 else
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;
156 else
158 radiusRatio = 0.f;
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;
167 currVertex += vSize;
168 CHECK_VERTEX_BUFFER(*vb, currVertex);
169 * (CVector *) currVertex = *posIt + innerVect;
170 currVertex += vSize;
171 currAngle += angleStep;
174 ++posIt;
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;
189 while (leftToDo);
190 PARTICLES_CHECK_MEM;
194 ///=================================================================================
195 CPSShockWave::CPSShockWave(uint nbSeg, float radiusCut, CSmartPtr<ITexture> tex)
196 : _NbSeg(nbSeg)
197 , _RadiusCut(radiusCut)
198 , _UFactor(1.f)
201 NL_PS_FUNC(CPSShockWave_CPSShockWave)
202 nlassert(nbSeg > 2 && nbSeg <= 64);
203 setTexture(tex);
204 init();
205 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("ShockWave");
208 ///=================================================================================
209 uint32 CPSShockWave::getNumWantedTris() const
211 NL_PS_FUNC(CPSShockWave_getNumWantedTris)
212 nlassert(_Owner);
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);
236 _NbSeg = nbSeg;
237 if (_Owner)
239 resize(_Owner->getMaxSize());
240 //notifyOwnerMaxNumFacesChanged();
244 ///=================================================================================
245 void CPSShockWave::setRadiusCut(float radiusCut)
247 NL_PS_FUNC(CPSShockWave_setRadiusCut)
248 _RadiusCut = radiusCut;
249 if (_Owner)
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
260 _UFactor = value;
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);
275 serialMaterial(f);
276 f.serial(_NbSeg, _RadiusCut);
277 if (ver > 1)
279 f.serial(_UFactor);
281 init();
284 ///=================================================================================
285 inline void CPSShockWave::setupUFactor()
287 NL_PS_FUNC(CPSShockWave_setupUFactor)
288 if (_UFactor != 1.f)
290 _Mat.enableUserTexMat(0);
291 CMatrix texMat;
292 texMat.setRot(_UFactor * NLMISC::CVector::I,
293 NLMISC::CVector::J,
294 NLMISC::CVector::K
296 _Mat.setUserTexMat(0, texMat);
298 else
300 _Mat.enableUserTexMat(0, false);
304 ///=================================================================================
305 void CPSShockWave::draw(bool opaque)
307 // if (!FilterPS[7]) return;
308 NL_PS_FUNC(CPSShockWave_draw)
309 PARTICLES_CHECK_MEM;
310 if (!_Owner->getSize()) return;
312 uint32 step;
313 uint numToProcess;
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());
334 else
336 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());
339 else
341 forceModulateConstantColor(false);
342 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
344 NLMISC::CRGBA col;
345 col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
346 _Mat.setColor(col);
348 else
349 if (!ps.getColorAttenuationScheme() || ps.isUserColorUsed())
351 _Mat.setColor(_Color);
353 else
355 NLMISC::CRGBA col;
356 col.modulateFromColor(ps.getGlobalColor(), _Color);
357 _Mat.setColor(col);
360 //////
362 setupUFactor();
364 if (step == (1 << 16))
366 CPSShockWaveHelper::drawShockWave(_Owner->getPos().begin(),
367 *this,
368 numToProcess,
369 step
372 else
374 CPSShockWaveHelper::drawShockWave(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
375 *this,
376 numToProcess,
377 step
381 PARTICLES_CHECK_MEM;
384 ///=================================================================================
385 bool CPSShockWave::completeBBox(NLMISC::CAABBox &box) const
387 NL_PS_FUNC(CPSShockWave_completeBBox)
388 // TODO : implement this
389 return false;
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)
407 nlassert(_Owner);
408 CVertexBufferReadWrite vba;
409 vb.lock (vba);
410 if (!size) return;
411 if (_ColorScheme)
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();
422 uint k;
424 uint32 currIndexIncr;
425 const sint32 *currIndex;
427 if (_TextureIndexScheme)
429 currIndex = (sint32 *) (_TextureIndexScheme->make(_Owner, startIndex, textureIndex, sizeof(sint32), size, true, srcStep));
430 currIndexIncr = 1;
432 else
434 currIndex = &_TextureIndex;
435 currIndexIncr = 0;
438 while (size--)
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
449 currUV += stride2;
452 currIndex += currIndexIncr;
457 ///=================================================================================
458 void CPSShockWave::updateMatAndVbForColor(void)
460 NL_PS_FUNC(CPSShockWave_updateMatAndVbForColor)
461 if (_Owner)
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));
499 resizeColor(aSize);
500 resizeTextureIndex(aSize);
501 resizeSize(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;
534 vb.lock (vba);
535 pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
536 pb.setNumIndexes(2 * 3 * size * _NbSeg);
537 CIndexBufferReadWrite ibaWrite;
538 pb.lock (ibaWrite);
539 uint finalIndex = 0;
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);
546 finalIndex+=3;
547 ibaWrite.setTri(finalIndex, index + 1, index + 2, index + 0);
548 finalIndex+=3;
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));
556 retVb = &vb;
557 retPb = &pb;
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);
578 } // NL3D