00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "std3d.h"
00025
00026 #include "nel/3d/ps_fan_light.h"
00027 #include "nel/3d/ps_macro.h"
00028 #include "nel/3d/ps_attrib_maker.h"
00029 #include "nel/3d/ps_iterator.h"
00030 #include "nel/3d/particle_system.h"
00031 #include "nel/3d/driver.h"
00032
00033
00034
00035 namespace NL3D
00036 {
00037
00038
00039
00041
00043
00044
00045 uint8 CPSFanLight::_RandomPhaseTab[32][128];
00046 bool CPSFanLight::_RandomPhaseTabInitialized = false;
00047
00048 CPSFanLight::TVBMap CPSFanLight::_VBMap;
00049 CPSFanLight::TVBMap CPSFanLight::_TexVBMap;
00050 CPSFanLight::TVBMap CPSFanLight::_ColoredVBMap;
00051 CPSFanLight::TVBMap CPSFanLight::_ColoredTexVBMap;
00052 CPSFanLight::TIBMap CPSFanLight::_IBMap;
00053
00054
00055 static const uint FanLightBufSize = 128;
00056 static const uint NumVertsInBuffer = 4 * FanLightBufSize;
00057
00058
00059
00060
00061
00063
00069 class CPSFanLightHelper
00070 {
00071 public:
00072 template <class T, class U>
00073 static void drawFanLight(T posIt, U timeIt, CPSFanLight &f, uint size, uint32 srcStep)
00074 {
00075 NL_PS_FUNC(CPSFanLightHelper_drawFanLight)
00076 PARTICLES_CHECK_MEM;
00077 nlassert(f._RandomPhaseTabInitialized);
00078
00079 f.setupDriverModelMatrix();
00080 const CVector I = f.computeI();
00081 const CVector K = f.computeK();
00082
00083 CVertexBuffer *vb;
00084 CIndexBuffer *ib;
00085
00086 f.getVBnIB(vb, ib);
00087
00088 vb->setPreferredMemory(CVertexBuffer::AGPVolatile, true);
00089 IDriver *driver = f.getDriver();
00090 const uint maxNumFanLightToDealWith = std::min(FanLightBufSize, f.getNumFanlightsInVB());
00091 uint8 *randomPhaseTab = &f._RandomPhaseTab[f._PhaseSmoothness][0];
00092 f._Owner->incrementNbDrawnParticles(size);
00093 float pSizes[FanLightBufSize];
00094 float pAngles[FanLightBufSize];
00095 T endPosIt;
00096
00097 sint32 k;
00098
00099
00100
00101 const uint32 stride = vb->getVertexSize();
00102
00103 float currentAngle;
00104 const float angleStep = 256.0f / f._NbFans;
00105
00106
00107 float *currentSizePt;
00108 float *currentAnglePt;
00109
00110
00111 const uint32 currentSizePtIncrement = f._SizeScheme ? 1 : 0;
00112 const uint32 currentAnglePtIncrement = f._Angle2DScheme ? 1 : 0;
00113
00114
00115 uint leftToDo = size;
00116 if (f._ColorScheme)
00117 {
00118
00119 f._ColorScheme->setColorType(driver->getVertexColorFormat());
00120 }
00121 do
00122 {
00123 uint toProcess = std::min(leftToDo, maxNumFanLightToDealWith);
00124 vb->setNumVertices(toProcess * f._NbFans * 3);
00125 {
00126 CVertexBufferReadWrite vba;
00127 vb->lock (vba);
00128
00129 uint8 *ptVect = (uint8 *) vba.getVertexCoordPointer();
00130
00131 if (f._ColorScheme)
00132 {
00133
00134 f._ColorScheme->make(f._Owner, size - leftToDo, vba.getColorPointer(), vb->getVertexSize() * (f._NbFans + 2), toProcess, false, srcStep);
00135 }
00136 if (f._SizeScheme)
00137 {
00138 currentSizePt = (float *) (f._SizeScheme->make(f._Owner, size - leftToDo, pSizes, sizeof(float), toProcess, true, srcStep));
00139 currentSizePt = pSizes;
00140 }
00141 else
00142 {
00143 currentSizePt = &f._ParticleSize;
00144 }
00145 if (f._Angle2DScheme)
00146 {
00147 currentAnglePt = (float *) (f._Angle2DScheme->make(f._Owner, size - leftToDo, pAngles, sizeof(float), toProcess, true, srcStep));
00148 }
00149 else
00150 {
00151 currentAnglePt = &f._Angle2D;
00152 }
00153
00154 float fSize, firstSize, sizeStepBase=0.0, sizeStep;
00155 if (f._PhaseSmoothness)
00156 {
00157 sizeStepBase = 1.f / f._PhaseSmoothness;
00158 }
00159 endPosIt = posIt + toProcess;
00160 for (;posIt != endPosIt; ++posIt, ++timeIt)
00161 {
00162
00163 CHECK_VERTEX_BUFFER(*vb, ptVect);
00164 *(CVector *) ptVect = *posIt;
00165
00166 currentAngle = *currentAnglePt;
00167 const uint8 phaseAdd = (uint8) (f._PhaseSpeed * (*timeIt));
00168 ptVect += stride;
00169 const float fanSize = *currentSizePt * 0.5f;
00170 const float moveIntensity = f._MoveIntensity * fanSize;
00171
00172 firstSize = fanSize + (moveIntensity * CPSUtil::getCos(randomPhaseTab[0] + phaseAdd));
00173 *(CVector *) ptVect = (*posIt) + I * firstSize * (CPSUtil::getCos((sint32) currentAngle))
00174 + K * firstSize * (CPSUtil::getSin((sint32) currentAngle));
00175 currentAngle += angleStep;
00176 ptVect += stride;
00177 fSize = firstSize;
00178
00179 const sint32 upperBound = (sint32) (f._NbFans - f._PhaseSmoothness - 1);
00180 for (k = 1; k <= upperBound; ++k)
00181 {
00182 fSize = fanSize + (moveIntensity * CPSUtil::getCos(randomPhaseTab[k] + phaseAdd));
00183 *(CVector *) ptVect = (*posIt) + I * fSize * (CPSUtil::getCos((sint32) currentAngle))
00184 + K * fSize * (CPSUtil::getSin((sint32) currentAngle));
00185 currentAngle += angleStep;
00186 ptVect += stride;
00187 }
00188
00189
00190 sizeStep = sizeStepBase * (firstSize - fSize);
00191 for (; k <= (sint32) (f._NbFans - 1); ++k)
00192 {
00193 *(CVector *) ptVect = (*posIt) + I * fSize * (CPSUtil::getCos((sint32) currentAngle))
00194 + K * fSize * (CPSUtil::getSin((sint32) currentAngle));
00195 currentAngle += angleStep;
00196 ptVect += stride;
00197 fSize += sizeStep;
00198 }
00199
00200 *(CVector *) ptVect = (*posIt) + I * firstSize * (CPSUtil::getCos((sint32) *currentAnglePt))
00201 + K * firstSize * (CPSUtil::getSin((sint32) *currentAnglePt));
00202 ptVect += stride;
00203 currentSizePt += currentSizePtIncrement;
00204 currentAnglePt += currentAnglePtIncrement;
00205 }
00206 }
00207 driver->activeIndexBuffer(*ib);
00208 driver->activeVertexBuffer(*vb);
00209 driver->renderTriangles(f._Mat, 0, toProcess * f._NbFans);
00210 leftToDo -= toProcess;
00211 }
00212 while (leftToDo != 0);
00213 PARTICLES_CHECK_MEM;
00214 }
00215 };
00216
00217
00219
00220 static void BlurBytesTab(const uint8 *src, uint8 *dest, uint size)
00221 {
00222 NL_PS_FUNC(BlurBytesTab)
00223 std::vector<uint8> b(src, src + size);
00224 for (sint k = 1 ; k < (sint) (size - 1); ++k)
00225 {
00226 dest[k] = (uint8) (((uint16) b[k - 1] + (uint16) b[k + 1])>>1);
00227 }
00228 }
00229
00231 void CPSFanLight::initFanLightPrecalc(void)
00232 {
00233 NL_PS_FUNC(CPSFanLight_initFanLightPrecalc)
00234
00235 float currPhase, nextPhase, phaseStep;
00236 for (uint l = 0; l < 32 ; l++)
00237 {
00238 nextPhase = (float) (uint8) (rand()&0xFF);
00239 uint32 k = 0;
00240 while (k < 128)
00241 {
00242 currPhase = nextPhase;
00243 nextPhase = (float) (uint8) (rand()&0xFF);
00244 phaseStep = (nextPhase - currPhase) / (l + 1);
00245
00246 for (uint32 m = 0; m <= l; ++m)
00247 {
00248 _RandomPhaseTab[l][k] = (uint8) currPhase;
00249 currPhase += phaseStep;
00250 ++k;
00251 if (k >= 128) break;
00252 }
00253 }
00254 for (uint m = 0; m < 2 * l; ++m)
00255 BlurBytesTab(&_RandomPhaseTab[l][0], &_RandomPhaseTab[l][0], 128);
00256 }
00257
00258 _RandomPhaseTabInitialized = true;
00259
00260 }
00261
00263 uint32 CPSFanLight::getNumWantedTris() const
00264 {
00265 NL_PS_FUNC(CPSFanLight_getNumWantedTris)
00266 nlassert(_Owner);
00267
00268 return _Owner->getSize() * _NbFans;
00269 }
00270
00272 bool CPSFanLight::hasTransparentFaces(void)
00273 {
00274 NL_PS_FUNC(CPSFanLight_hasTransparentFaces)
00275 return getBlendingMode() != CPSMaterial::alphaTest ;
00276 }
00277
00279 bool CPSFanLight::hasOpaqueFaces(void)
00280 {
00281 NL_PS_FUNC(CPSFanLight_hasOpaqueFaces)
00282 return !hasTransparentFaces();
00283 }
00284
00286 void CPSFanLight::newElement(const CPSEmitterInfo &info)
00287 {
00288 NL_PS_FUNC(CPSFanLight_newElement)
00289 newColorElement(info);
00290 newSizeElement(info);
00291 newAngle2DElement(info);
00292 }
00293
00295 void CPSFanLight::deleteElement(uint32 index)
00296 {
00297 NL_PS_FUNC(CPSFanLight_deleteElement)
00298 deleteColorElement(index);
00299 deleteSizeElement(index);
00300 deleteAngle2DElement(index);
00301 }
00302
00304 void CPSFanLight::setPhaseSpeed(float multiplier)
00305 {
00306 NL_PS_FUNC(CPSFanLight_setPhaseSpeed)
00307 _PhaseSpeed = 256.0f * multiplier;
00308 }
00309
00311 inline void CPSFanLight::setupMaterial()
00312 {
00313 NL_PS_FUNC(CPSFanLight_setupMaterial)
00314 CParticleSystem &ps = *(_Owner->getOwner());
00316 if (_Tex == NULL)
00317 {
00318 forceTexturedMaterialStages(1);
00319 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
00320 }
00321 else
00322 {
00323 _Mat.setTexture(0, _Tex);
00324 forceTexturedMaterialStages(2);
00325 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
00326 SetupModulatedStage(_Mat, 1, CMaterial::Diffuse, CMaterial::Previous);
00327 }
00328
00329
00330 if (_ColorScheme)
00331 {
00332 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00333 {
00334 _Mat.texConstantColor(0, ps.getGlobalColorLighted());
00335 }
00336 else
00337 {
00338 _Mat.texConstantColor(0, ps.getGlobalColor());
00339 }
00340 }
00341 else
00342 {
00343 NLMISC::CRGBA col;
00344 if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00345 {
00346 col.modulateFromColor(ps.getGlobalColorLighted(), _Color);
00347 }
00348 else if (ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed())
00349 {
00350 col.modulateFromColor(ps.getGlobalColor(), _Color);
00351 }
00352 else
00353 {
00354 col = _Color;
00355 }
00356 _Mat.texConstantColor(0, col);
00357 }
00358 }
00359
00360
00362 void CPSFanLight::draw(bool opaque)
00363 {
00364
00365 NL_PS_FUNC(CPSFanLight_draw)
00366 PARTICLES_CHECK_MEM;
00367 if (!_Owner->getSize()) return;
00368
00369 uint32 step;
00370 uint numToProcess;
00371 computeSrcStep(step, numToProcess);
00372 if (!numToProcess) return;
00373
00374 setupMaterial();
00375
00376 if (step == (1 << 16))
00377 {
00378 CPSFanLightHelper::drawFanLight(_Owner->getPos().begin(),
00379 _Owner->getTime().begin(),
00380 *this,
00381 numToProcess,
00382 step
00383 );
00384 }
00385 else
00386 {
00387 CPSFanLightHelper::drawFanLight(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
00388 TIteratorTimeStep1616(_Owner->getTime().begin(), 0, step),
00389 *this,
00390 numToProcess,
00391 step
00392 );
00393 }
00394
00395 PARTICLES_CHECK_MEM;
00396 }
00397
00399 void CPSFanLight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00400 {
00401 NL_PS_FUNC(CPSFanLight_serial)
00402 sint ver = f.serialVersion(2);
00403 CPSParticle::serial(f);
00404 CPSColoredParticle::serialColorScheme(f);
00405 CPSSizedParticle::serialSizeScheme(f);
00406 CPSRotated2DParticle::serialAngle2DScheme(f);
00407 f.serial(_NbFans);
00408 serialMaterial(f);
00409 if (ver > 1)
00410 {
00411 f.serial(_PhaseSmoothness, _MoveIntensity);
00412 ITexture *tex = _Tex;
00413 f.serialPolyPtr(tex);
00414 if (f.isReading()) _Tex = tex ;
00415 }
00416 if (f.isReading())
00417 {
00418 init();
00419 }
00420 }
00421
00423 bool CPSFanLight::completeBBox(NLMISC::CAABBox &box) const
00424 {
00425 NL_PS_FUNC(CPSFanLight_completeBBox)
00426
00427
00428 return false;
00429 }
00430
00432 CPSFanLight::CPSFanLight(uint32 nbFans) : _NbFans(nbFans),
00433 _PhaseSmoothness(0),
00434 _MoveIntensity(1.5f),
00435 _Tex(NULL),
00436 _PhaseSpeed(256)
00437 {
00438 NL_PS_FUNC(CPSFanLight_CPSFanLight)
00439 nlassert(nbFans >= 3);
00440
00441
00442 init();
00443 if (CParticleSystem::getSerializeIdentifierFlag()) _Name = std::string("FanLight");
00444 }
00445
00446
00448 CPSFanLight::~CPSFanLight()
00449 {
00450 NL_PS_FUNC(CPSFanLight_CPSFanLight)
00451 }
00452
00453
00455 void CPSFanLight::setNbFans(uint32 nbFans)
00456 {
00457 NL_PS_FUNC(CPSFanLight_setNbFans)
00458 _NbFans = nbFans;
00459 resize(_Owner->getMaxSize());
00460
00461 }
00462
00464 void CPSFanLight::resize(uint32 size)
00465 {
00466 NL_PS_FUNC(CPSFanLight_resize)
00467 nlassert(size < (1 << 16));
00468 resizeColor(size);
00469 resizeAngle2D(size);
00470 resizeSize(size);
00471
00472 }
00473
00475 void CPSFanLight::init(void)
00476 {
00477 NL_PS_FUNC(CPSFanLight_init)
00478 _Mat.setLighting(false);
00479 _Mat.setZFunc(CMaterial::less);
00480 _Mat.setDoubleSided(true);
00481 _Mat.setColor(NLMISC::CRGBA::White);
00482
00483 updateMatAndVbForColor();
00484 }
00485
00487 void CPSFanLight::updateMatAndVbForColor(void)
00488 {
00489 NL_PS_FUNC(CPSFanLight_updateMatAndVbForColor)
00490
00491 }
00492
00494 void CPSFanLight::getVBnIB(CVertexBuffer *&retVb, CIndexBuffer *&retIb)
00495 {
00496 NL_PS_FUNC(CPSFanLight_getVBnIB)
00497 TVBMap &vbMap = _ColorScheme ? (_Tex == NULL ? _ColoredVBMap : _ColoredTexVBMap)
00498 : (_Tex == NULL ? _VBMap : _TexVBMap);
00499 #ifdef NL_NAMED_INDEX_BUFFER
00500 const char *ibName = _ColorScheme ? (_Tex == NULL ? "_ColoredVBMap" : "_ColoredTexVBMap")
00501 : (_Tex == NULL ? "_VBMap" : "_TexVBMap");
00502 #endif
00503 TVBMap::iterator vbIt = vbMap.find(_NbFans);
00504 if (vbIt != vbMap.end())
00505 {
00506 retVb = &(vbIt->second);
00507 TIBMap::iterator pbIt = _IBMap.find(_NbFans);
00508 nlassert(pbIt != _IBMap.end());
00509 #ifdef NL_NAMED_INDEX_BUFFER
00510 if (pbIt->second.getName().empty()) NL_SET_IB_NAME(pbIt->second, ibName);
00511 #endif
00512 retIb = &(pbIt->second);
00513 }
00514 else
00515 {
00516
00517 CVertexBuffer &vb = vbMap[_NbFans];
00518 CIndexBuffer &ib = _IBMap[_NbFans];
00519 const uint32 size = getNumFanlightsInVB();
00520 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00521 CVertexBuffer::PrimaryColorFlag |
00522 (_Tex != NULL ? CVertexBuffer::TexCoord0Flag : 0)
00523 );
00524 vb.setNumVertices(size * (2 + _NbFans));
00525 vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
00526 vb.setName("CPSFanLight");
00527 ib.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
00528 ib.setNumIndexes(size * _NbFans * 3);
00529
00530 CIndexBufferReadWrite iba;
00531 ib.lock (iba);
00532 TIndexType *ptIndex = (TIndexType *) iba.getPtr();
00533
00534 CVertexBufferReadWrite vba;
00535 vb.lock (vba);
00536
00537
00538 uint currVertFan = 0;
00539
00540 uint l;
00541 uint k;
00542
00543 for (k = 0; k < size; ++k)
00544 {
00545 for (l = 0; l < _NbFans; ++l)
00546 {
00547 *ptIndex++ = (TIndexType) currVertFan;
00548 *ptIndex++ = (TIndexType) (currVertFan + (l + 1));
00549 *ptIndex++ = (TIndexType) (currVertFan + (l + 2));
00550 }
00551 currVertFan += 2 + _NbFans;
00552 }
00553
00554 for (k = 0; k < size; ++k)
00555 {
00556 if (_Tex)
00557 {
00558 vba.setTexCoord(k * (_NbFans + 2), 0, NLMISC::CUV(0, 0));
00559 }
00560 if (!_ColorScheme)
00561 {
00562 vba.setColor(k * (_NbFans + 2), CRGBA::White);
00563 }
00564 if (!_Tex)
00565 {
00566 for(l = 1; l <= _NbFans + 1; ++l)
00567 {
00568 vba.setColor(l + k * (_NbFans + 2), CRGBA(0, 0, 0));
00569 }
00570 }
00571 else
00572 {
00573 for(l = 1; l <= _NbFans + 1; ++l)
00574 {
00575 vba.setColor(l + k * (_NbFans + 2), CRGBA(0, 0, 0));
00576 vba.setTexCoord(l + k * (_NbFans + 2), 0, NLMISC::CUV((l - 1) / (float) _NbFans, 1));
00577 }
00578 }
00579 }
00580
00581 retVb = &vb;
00582 retIb = &ib;
00583 }
00584 }
00585
00587 uint CPSFanLight::getNumFanlightsInVB() const
00588 {
00589 NL_PS_FUNC(CPSFanLight_getNumFanlightsInVB)
00590 const uint numRib = NumVertsInBuffer / (2 + _NbFans);
00591 return std::max(1u, numRib);
00592 }
00593
00595 void CPSFanLight::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
00596 {
00597 NL_PS_FUNC(CPSFanLight_enumTexs)
00598 if (_Tex)
00599 {
00600 dest.push_back(_Tex);
00601 }
00602 }
00603
00604 }