00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/ps_macro.h"
00029 #include "3d/ps_shockwave.h"
00030 #include "3d/driver.h"
00031 #include "3d/texture_grouped.h"
00032 #include "3d/ps_iterator.h"
00033 #include "3d/particle_system.h"
00034
00035
00036 namespace NL3D
00037 {
00038
00040
00042
00043
00044 static const uint ShockWaveBufSize = 128;
00045
00046
00047 static const uint NumVertsInBuffer = 8 * ShockWaveBufSize;
00048
00049
00050 CPSShockWave::TPBMap CPSShockWave::_PBMap;
00051 CPSShockWave::TVBMap CPSShockWave::_VBMap;
00052 CPSShockWave::TVBMap CPSShockWave::_AnimTexVBMap;
00053 CPSShockWave::TVBMap CPSShockWave::_ColoredVBMap;
00054 CPSShockWave::TVBMap CPSShockWave::_ColoredAnimTexVBMap;
00056
00058
00059
00065 class CPSShockWaveHelper
00066 {
00067 public:
00068 template <class T>
00069 static void drawShockWave(T posIt, CPSShockWave &s, uint size, uint32 srcStep)
00070 {
00071 PARTICLES_CHECK_MEM;
00072 nlassert(s._Owner);
00073
00074
00075 CVertexBuffer *vb;
00076 CPrimitiveBlock *pb;
00077 s.getVBnPB(vb, pb);
00078
00079 const uint32 vSize = vb->getVertexSize();
00080 IDriver *driver = s.getDriver();
00081 s._Owner->incrementNbDrawnParticles(size);
00082 s.setupDriverModelMatrix();
00083 const uint numShockWaveToDealWith = std::min(ShockWaveBufSize, s.getNumShockWavesInVB());
00084 driver->activeVertexBuffer(*vb);
00085
00086 static CPlaneBasis planeBasis[ShockWaveBufSize];
00087 float sizes[ShockWaveBufSize];
00088 float angles[ShockWaveBufSize];
00089
00090 uint leftToDo = size, toProcess;
00091 T endIt;
00092 uint8 *currVertex;
00093 uint k ;
00094
00095 const float angleStep = 256.f / s._NbSeg;
00096 float currAngle;
00097
00098 CPlaneBasis *ptCurrBasis;
00099 uint32 ptCurrBasisIncrement = s._PlaneBasisScheme ? 1 : 0;
00100
00101 float *ptCurrSize;
00102 uint32 ptCurrSizeIncrement = s._SizeScheme ? 1 : 0;
00103
00104 float *ptCurrAngle;
00105 uint32 ptCurrAngleIncrement = s._Angle2DScheme ? 1 : 0;
00106
00107 CVector radVect, innerVect;
00108 float radiusRatio;
00109
00110 do
00111 {
00112 currVertex = (uint8 *) vb->getVertexCoordPointer();
00113 toProcess = leftToDo > numShockWaveToDealWith ? numShockWaveToDealWith : leftToDo;
00114 endIt = posIt + toProcess;
00115 if (s._SizeScheme)
00116 {
00117 ptCurrSize = (float *) (s._SizeScheme->make(s._Owner, size - leftToDo, (void *) sizes, sizeof(float), toProcess, true, srcStep));
00118 }
00119 else
00120 {
00121 ptCurrSize = &s._ParticleSize;
00122 }
00123
00124 if (s._PlaneBasisScheme)
00125 {
00126 ptCurrBasis = (CPlaneBasis *) (s._PlaneBasisScheme->make(s._Owner, size - leftToDo, (void *) planeBasis, sizeof(CPlaneBasis), toProcess, true, srcStep));
00127 }
00128 else
00129 {
00130 ptCurrBasis = &s._PlaneBasis;
00131 }
00132
00133 if (s._Angle2DScheme)
00134 {
00135 ptCurrAngle = (float *) (s._Angle2DScheme->make(s._Owner, size - leftToDo, (void *) angles, sizeof(float), toProcess, true, srcStep));
00136 }
00137 else
00138 {
00139 ptCurrAngle = &s._Angle2D;
00140 }
00141
00142
00143 s.updateVbColNUVForRender(size - leftToDo, toProcess, srcStep, *vb);
00144 do
00145 {
00146 currAngle = *ptCurrAngle;
00147 if (fabsf(*ptCurrSize) > 10E-6)
00148 {
00149 radiusRatio = (*ptCurrSize - s._RadiusCut) / *ptCurrSize;
00150 }
00151 else
00152 {
00153 radiusRatio = 0.f;
00154 }
00155
00156 for (k = 0; k <= s._NbSeg; ++k)
00157 {
00158 radVect = *ptCurrSize * (CPSUtil::getCos((sint32) currAngle) * ptCurrBasis->X + CPSUtil::getSin((sint32) currAngle) * ptCurrBasis->Y);
00159 innerVect = radiusRatio * radVect;
00160 CHECK_VERTEX_BUFFER(*vb, currVertex);
00161 * (CVector *) currVertex = *posIt + radVect;
00162 currVertex += vSize;
00163 CHECK_VERTEX_BUFFER(*vb, currVertex);
00164 * (CVector *) currVertex = *posIt + innerVect;
00165 currVertex += vSize;
00166 currAngle += angleStep;
00167 }
00168
00169 ++posIt;
00170 ptCurrBasis += ptCurrBasisIncrement;
00171 ptCurrSize += ptCurrSizeIncrement;
00172 ptCurrAngle += ptCurrAngleIncrement;
00173 }
00174 while (posIt != endIt);
00175
00176 pb->setNumQuad(toProcess * s._NbSeg);
00177 driver->render(*pb, s._Mat);
00178 leftToDo -= toProcess;
00179 }
00180 while (leftToDo);
00181 PARTICLES_CHECK_MEM;
00182 }
00183 };
00184
00186 CPSShockWave::CPSShockWave(uint nbSeg, float radiusCut, CSmartPtr<ITexture> tex)
00187 : _NbSeg(nbSeg)
00188 , _RadiusCut(radiusCut)
00189 , _UFactor(1.f)
00190
00191 {
00192 nlassert(nbSeg > 2 && nbSeg <= 64);
00193 setTexture(tex);
00194 init();
00195 _Name = std::string("ShockWave");
00196 }
00197
00199 uint32 CPSShockWave::getMaxNumFaces(void) const
00200 {
00201 nlassert(_Owner);
00202 return (_Owner->getMaxSize() * _NbSeg) << 1 ;
00203 }
00204
00206 bool CPSShockWave::hasTransparentFaces(void)
00207 {
00208 return getBlendingMode() != CPSMaterial::alphaTest ;
00209 }
00210
00212 bool CPSShockWave::hasOpaqueFaces(void)
00213 {
00214 return !hasTransparentFaces();
00215 }
00216
00218 void CPSShockWave::setNbSegs(uint nbSeg)
00219 {
00220 nlassert(nbSeg > 2 && nbSeg <= 64);
00221 _NbSeg = nbSeg;
00222 if (_Owner)
00223 {
00224 resize(_Owner->getMaxSize());
00225 notifyOwnerMaxNumFacesChanged();
00226 }
00227 }
00228
00230 void CPSShockWave::setRadiusCut(float radiusCut)
00231 {
00232 _RadiusCut = radiusCut;
00233 if (_Owner)
00234 {
00235 resize(_Owner->getMaxSize());
00236 }
00237 }
00238
00240 void CPSShockWave::setUFactor(float value)
00241 {
00242 nlassert(_Owner);
00243 _UFactor = value;
00244 resize(_Owner->getSize());
00245 }
00246
00248 void CPSShockWave::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00249 {
00250 sint ver = f.serialVersion(2);
00251 CPSParticle::serial(f);
00252 CPSColoredParticle::serialColorScheme(f);
00253 CPSSizedParticle::serialSizeScheme(f);
00254 CPSTexturedParticle::serialTextureScheme(f);
00255 CPSRotated3DPlaneParticle::serialPlaneBasisScheme(f);
00256 CPSRotated2DParticle::serialAngle2DScheme(f);
00257 serialMaterial(f);
00258 f.serial(_NbSeg, _RadiusCut);
00259 if (ver > 1)
00260 {
00261 f.serial(_UFactor);
00262 }
00263 init();
00264 }
00265
00267 inline void CPSShockWave::setupUFactor()
00268 {
00269 if (_UFactor != 1.f)
00270 {
00271 _Mat.enableUserTexMat(0);
00272 CMatrix texMat;
00273 texMat.setRot(_UFactor * NLMISC::CVector::I,
00274 NLMISC::CVector::J,
00275 NLMISC::CVector::K
00276 );
00277 _Mat.setUserTexMat(0, texMat);
00278 }
00279 else
00280 {
00281 _Mat.enableUserTexMat(0, false);
00282 }
00283 }
00284
00286 void CPSShockWave::draw(bool opaque)
00287 {
00288 PARTICLES_CHECK_MEM;
00289 if (!_Owner->getSize()) return;
00290
00291 uint32 step;
00292 uint numToProcess;
00293 computeSrcStep(step, numToProcess);
00294 if (!numToProcess) return;
00295
00296
00297
00299 CParticleSystem &ps = *(_Owner->getOwner());
00301 if (_ColorScheme != NULL && ps.getColorAttenuationScheme() != NULL)
00302 {
00303 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());
00304 }
00305 else
00306 {
00307 forceModulateConstantColor(false);
00308 if (!ps.getColorAttenuationScheme())
00309 {
00310 _Mat.setColor(_Color);
00311 }
00312 else
00313 {
00314 NLMISC::CRGBA col;
00315 col.modulateFromColor(ps.getGlobalColor(), _Color);
00316 _Mat.setColor(col);
00317 }
00318 }
00320
00321 setupUFactor();
00322
00323 if (step == (1 << 16))
00324 {
00325 CPSShockWaveHelper::drawShockWave(_Owner->getPos().begin(),
00326 *this,
00327 numToProcess,
00328 step
00329 );
00330 }
00331 else
00332 {
00333 CPSShockWaveHelper::drawShockWave(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
00334 *this,
00335 numToProcess,
00336 step
00337 );
00338 }
00339
00340 PARTICLES_CHECK_MEM;
00341 }
00342
00344 bool CPSShockWave::completeBBox(NLMISC::CAABBox &box) const
00345 {
00346
00347 return false;
00348 }
00349
00351 void CPSShockWave::init(void)
00352 {
00353 _Mat.setLighting(false);
00354 _Mat.setZFunc(CMaterial::less);
00355 _Mat.setDoubleSided(true);
00356 updateMatAndVbForColor();
00357 updateMatAndVbForTexture();
00358 }
00359
00361 void CPSShockWave::updateVbColNUVForRender(uint32 startIndex, uint32 size, uint32 srcStep, CVertexBuffer &vb)
00362 {
00363 nlassert(_Owner);
00364 if (!size) return;
00365 if (_ColorScheme)
00366 {
00367
00368 _ColorScheme->makeN(_Owner, startIndex, vb.getColorPointer(), vb.getVertexSize(), size, (_NbSeg + 1) << 1, srcStep);
00369 }
00370
00371 if (_TexGroup)
00372 {
00373 sint32 textureIndex[ShockWaveBufSize];
00374 const uint32 stride = vb.getVertexSize(), stride2 = stride << 1;
00375 uint8 *currUV = (uint8 *) vb.getTexCoordPointer();
00376 uint k;
00377
00378 uint32 currIndexIncr;
00379 const sint32 *currIndex;
00380
00381 if (_TextureIndexScheme)
00382 {
00383 currIndex = (sint32 *) (_TextureIndexScheme->make(_Owner, startIndex, textureIndex, sizeof(sint32), size, true, srcStep));
00384 currIndexIncr = 1;
00385 }
00386 else
00387 {
00388 currIndex = &_TextureIndex;
00389 currIndexIncr = 0;
00390 }
00391
00392 while (size--)
00393 {
00394
00395 const CTextureGrouped::TFourUV &uvGroup = _TexGroup->getUVQuad((uint32) *currIndex);
00396
00397 k = _NbSeg + 1;
00398
00399 for (k = 0; k <= _NbSeg; ++k)
00400 {
00401
00402 *(CUV *) currUV = uvGroup.uv0 + CUV(k * _UFactor, 0);
00403 *(CUV *) (currUV + stride) = uvGroup.uv3 + CUV(k * _UFactor, 0);
00404
00405 currUV += stride2;
00406 }
00407 while (--k);
00408
00409 currIndex += currIndexIncr;
00410 }
00411 }
00412 }
00413
00415 void CPSShockWave::updateMatAndVbForColor(void)
00416 {
00417
00418 if (_Owner)
00419 {
00420 resize(_Owner->getMaxSize());
00421 }
00422 }
00423
00425 void CPSShockWave::updateMatAndVbForTexture(void)
00426 {
00427 _Mat.setTexture(0, _TexGroup ? (ITexture *) _TexGroup : (ITexture *) _Tex);
00428 }
00429
00431 void CPSShockWave::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00432 {
00433 newColorElement(emitterLocated, emitterIndex);
00434 newTextureIndexElement(emitterLocated, emitterIndex);
00435 newSizeElement(emitterLocated, emitterIndex);
00436 newAngle2DElement(emitterLocated, emitterIndex);
00437 }
00438
00440 void CPSShockWave::deleteElement(uint32 index)
00441 {
00442 deleteColorElement(index);
00443 deleteTextureIndexElement(index);
00444 deleteSizeElement(index);
00445 deleteAngle2DElement(index);
00446 }
00447
00449 void CPSShockWave::resize(uint32 aSize)
00450 {
00451 nlassert(aSize < (1 << 16));
00452 resizeColor(aSize);
00453 resizeTextureIndex(aSize);
00454 resizeSize(aSize);
00455 resizeAngle2D(aSize);
00456 }
00457
00459 void CPSShockWave::getVBnPB(CVertexBuffer *&retVb, CPrimitiveBlock *&retPb)
00460 {
00461 TVBMap &vbMap = _ColorScheme == NULL ? (_TexGroup == NULL ? _VBMap : _AnimTexVBMap)
00462 : (_TexGroup == NULL ? _ColoredVBMap : _ColoredAnimTexVBMap);
00463
00464
00465 TVBMap::iterator vbIt = vbMap.find(_NbSeg);
00466 if (vbIt != vbMap.end())
00467 {
00468 retVb = &(vbIt->second);
00469 TPBMap::iterator pbIt = _PBMap.find(_NbSeg);
00470 nlassert(pbIt != _PBMap.end());
00471 retPb = &(pbIt->second);
00472 }
00473 else
00474 {
00475
00476 CVertexBuffer &vb = vbMap[_NbSeg];
00477 CPrimitiveBlock &pb = _PBMap[_NbSeg];
00478 const uint32 size = getNumShockWavesInVB();
00479 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00480 CVertexBuffer::TexCoord0Flag |
00481 (_ColorScheme != NULL ? CVertexBuffer::PrimaryColorFlag : 0)
00482 );
00483 vb.setNumVertices((size * (_NbSeg + 1)) << 1 );
00484 pb.reserveQuad(size * _NbSeg);
00485 for (uint32 k = 0; k < size; ++k)
00486 {
00487 for (uint32 l = 0; l < _NbSeg; ++l)
00488 {
00489 const uint32 index = ((k * (_NbSeg + 1)) + l) << 1;
00490 pb.setQuad(l + (k * _NbSeg) , index , index + 2, index + 3, index + 1);
00491 vb.setTexCoord(index, 0, CUV((float) l, 0));
00492 vb.setTexCoord(index + 1, 0, CUV((float) l, 1));
00493 }
00494 const uint32 index = ((k * (_NbSeg + 1)) + _NbSeg) << 1;
00495 vb.setTexCoord(index, 0, CUV((float) _NbSeg, 0));
00496 vb.setTexCoord(index + 1, 0, CUV((float) _NbSeg, 1));
00497 }
00498 retVb = &vb;
00499 retPb = &pb;
00500 }
00501 }
00502
00504 uint CPSShockWave::getNumShockWavesInVB() const
00505 {
00506 const uint numRib = NumVertsInBuffer / ((_NbSeg + 1) << 1);
00507 return std::max(1u, numRib);
00508 }
00509
00510 }