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_fan_light.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/ps_attrib_maker.h"
00031 #include "3d/ps_iterator.h"
00032 #include "3d/particle_system.h"
00033 #include "3d/driver.h"
00034
00035
00036
00037 namespace NL3D
00038 {
00039
00040
00041
00043
00045
00046
00047 uint8 CPSFanLight::_RandomPhaseTab[32][128];
00048 bool CPSFanLight::_RandomPhaseTabInitialized = false;
00049
00050 CPSFanLight::TVBMap CPSFanLight::_VBMap;
00051 CPSFanLight::TVBMap CPSFanLight::_TexVBMap;
00052 CPSFanLight::TVBMap CPSFanLight::_ColoredVBMap;
00053 CPSFanLight::TVBMap CPSFanLight::_ColoredTexVBMap;
00054 CPSFanLight::TIBMap CPSFanLight::_IBMap;
00055
00056
00057 static const uint FanLightBufSize = 128;
00058 static const uint NumVertsInBuffer = 4 * FanLightBufSize;
00059
00060
00062
00068 class CPSFanLightHelper
00069 {
00070 public:
00071 template <class T, class U>
00072 static void drawFanLight(T posIt, U timeIt, CPSFanLight &f, uint size, uint32 srcStep)
00073 {
00074 PARTICLES_CHECK_MEM;
00075 nlassert(f._RandomPhaseTabInitialized);
00076
00077 f.setupDriverModelMatrix();
00078 const CVector I = f.computeI();
00079 const CVector K = f.computeK();
00080
00081 CVertexBuffer *vb;
00082 CPSFanLight::TIndexBuffer *ib;
00083
00084 f.getVBnIB(vb, ib);
00085 IDriver *driver = f.getDriver();
00086 driver->activeVertexBuffer(*vb);
00087 const uint maxNumFanLightToDealWith = std::min(FanLightBufSize, f.getNumFanlightsInVB());
00088 uint8 *randomPhaseTab = &f._RandomPhaseTab[f._PhaseSmoothness][0];
00089 f._Owner->incrementNbDrawnParticles(size);
00090 float pSizes[FanLightBufSize];
00091 float pAngles[FanLightBufSize];
00092 T endPosIt;
00093
00094 sint32 k;
00095
00096
00097
00098 const uint32 stride = vb->getVertexSize();
00099
00100 float currentAngle;
00101 const float angleStep = 256.0f / f._NbFans;
00102
00103
00104 float *currentSizePt;
00105 float *currentAnglePt;
00106
00107
00108 const uint32 currentSizePtIncrement = f._SizeScheme ? 1 : 0;
00109 const uint32 currentAnglePtIncrement = f._Angle2DScheme ? 1 : 0;
00110
00111
00112 uint leftToDo = size;
00113 do
00114 {
00115 uint8 *ptVect = (uint8 *) vb->getVertexCoordPointer();
00116 uint toProcess = std::min(leftToDo, maxNumFanLightToDealWith);
00117
00118 if (f._ColorScheme)
00119 {
00120
00121 f._ColorScheme->make(f._Owner, size - leftToDo, vb->getColorPointer(), vb->getVertexSize() * (f._NbFans + 2), toProcess, false, srcStep);
00122 }
00123 if (f._SizeScheme)
00124 {
00125 currentSizePt = (float *) (f._SizeScheme->make(f._Owner, size - leftToDo, pSizes, sizeof(float), toProcess, true, srcStep));
00126 currentSizePt = pSizes;
00127 }
00128 else
00129 {
00130 currentSizePt = &f._ParticleSize;
00131 }
00132 if (f._Angle2DScheme)
00133 {
00134 currentAnglePt = (float *) (f._Angle2DScheme->make(f._Owner, size - leftToDo, pAngles, sizeof(float), toProcess, true, srcStep));
00135 }
00136 else
00137 {
00138 currentAnglePt = &f._Angle2D;
00139 }
00140
00141 float fSize, firstSize, sizeStepBase=0.0, sizeStep;
00142 if (f._PhaseSmoothness)
00143 {
00144 sizeStepBase = 1.f / f._PhaseSmoothness;
00145 }
00146 endPosIt = posIt + toProcess;
00147 for (;posIt != endPosIt; ++posIt, ++timeIt)
00148 {
00149
00150 CHECK_VERTEX_BUFFER(*vb, ptVect);
00151 *(CVector *) ptVect = *posIt;
00152
00153 currentAngle = *currentAnglePt;
00154 const uint8 phaseAdd = (uint8) (f._PhaseSpeed * (*timeIt));
00155 ptVect += stride;
00156 const float fanSize = *currentSizePt * 0.5f;
00157 const float moveIntensity = f._MoveIntensity * fanSize;
00158
00159 firstSize = fanSize + (moveIntensity * CPSUtil::getCos(randomPhaseTab[0] + phaseAdd));
00160 *(CVector *) ptVect = (*posIt) + I * firstSize * (CPSUtil::getCos((sint32) currentAngle))
00161 + K * firstSize * (CPSUtil::getSin((sint32) currentAngle));
00162 currentAngle += angleStep;
00163 ptVect += stride;
00164 fSize = firstSize;
00165
00166 const sint32 upperBound = (sint32) (f._NbFans - f._PhaseSmoothness - 1);
00167 for (k = 1; k <= upperBound; ++k)
00168 {
00169 fSize = fanSize + (moveIntensity * CPSUtil::getCos(randomPhaseTab[k] + phaseAdd));
00170 *(CVector *) ptVect = (*posIt) + I * fSize * (CPSUtil::getCos((sint32) currentAngle))
00171 + K * fSize * (CPSUtil::getSin((sint32) currentAngle));
00172 currentAngle += angleStep;
00173 ptVect += stride;
00174 }
00175
00176
00177 sizeStep = sizeStepBase * (firstSize - fSize);
00178 for (; k <= (sint32) (f._NbFans - 1); ++k)
00179 {
00180 *(CVector *) ptVect = (*posIt) + I * fSize * (CPSUtil::getCos((sint32) currentAngle))
00181 + K * fSize * (CPSUtil::getSin((sint32) currentAngle));
00182 currentAngle += angleStep;
00183 ptVect += stride;
00184 fSize += sizeStep;
00185 }
00186
00187 *(CVector *) ptVect = (*posIt) + I * firstSize * (CPSUtil::getCos((sint32) *currentAnglePt))
00188 + K * firstSize * (CPSUtil::getSin((sint32) *currentAnglePt));
00189 ptVect += stride;
00190 currentSizePt += currentSizePtIncrement;
00191 currentAnglePt += currentAnglePtIncrement;
00192 }
00193 driver->renderTriangles(f._Mat, &((*ib)[0]), toProcess * f._NbFans);
00194 leftToDo -= toProcess;
00195 }
00196 while (leftToDo != 0);
00197 PARTICLES_CHECK_MEM;
00198 }
00199 };
00200
00201
00203
00204 static void BlurBytesTab(const uint8 *src, uint8 *dest, uint size)
00205 {
00206 std::vector<uint8> b(src, src + size);
00207 for (sint k = 1 ; k < (sint) (size - 1); ++k)
00208 {
00209 dest[k] = (uint8) (((uint16) b[k - 1] + (uint16) b[k + 1])>>1);
00210 }
00211 }
00212
00214 void CPSFanLight::initFanLightPrecalc(void)
00215 {
00216
00217 float currPhase, nextPhase, phaseStep;
00218 for (uint l = 0; l < 32 ; l++)
00219 {
00220 nextPhase = (float) (uint8) (rand()&0xFF);
00221 uint32 k = 0;
00222 while (k < 128)
00223 {
00224 currPhase = nextPhase;
00225 nextPhase = (float) (uint8) (rand()&0xFF);
00226 phaseStep = (nextPhase - currPhase) / (l + 1);
00227
00228 for (uint32 m = 0; m <= l; ++m)
00229 {
00230 _RandomPhaseTab[l][k] = (uint8) currPhase;
00231 currPhase += phaseStep;
00232 ++k;
00233 if (k >= 128) break;
00234 }
00235 }
00236 for (uint m = 0; m < 2 * l; ++m)
00237 BlurBytesTab(&_RandomPhaseTab[l][0], &_RandomPhaseTab[l][0], 128);
00238 }
00239
00240 _RandomPhaseTabInitialized = true;
00241
00242 }
00243
00245 uint32 CPSFanLight::getMaxNumFaces(void) const
00246 {
00247 nlassert(_Owner);
00248 return _Owner->getMaxSize() * _NbFans;
00249 }
00250
00252 bool CPSFanLight::hasTransparentFaces(void)
00253 {
00254 return getBlendingMode() != CPSMaterial::alphaTest ;
00255 }
00256
00258 bool CPSFanLight::hasOpaqueFaces(void)
00259 {
00260 return !hasTransparentFaces();
00261 }
00262
00264 void CPSFanLight::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00265 {
00266 newColorElement(emitterLocated, emitterIndex);
00267 newSizeElement(emitterLocated, emitterIndex);
00268 newAngle2DElement(emitterLocated, emitterIndex);
00269 }
00270
00272 void CPSFanLight::deleteElement(uint32 index)
00273 {
00274 deleteColorElement(index);
00275 deleteSizeElement(index);
00276 deleteAngle2DElement(index);
00277 }
00278
00280 void CPSFanLight::setPhaseSpeed(float multiplier)
00281 {
00282 _PhaseSpeed = 256.0f * multiplier;
00283 }
00284
00286 inline void CPSFanLight::setupMaterial()
00287 {
00288 CParticleSystem &ps = *(_Owner->getOwner());
00289 bool useGlobalColor = (ps.getColorAttenuationScheme() != NULL);
00290 if (useGlobalColor != _UseGlobalColor)
00291 {
00292 touch();
00293 _UseGlobalColor = useGlobalColor;
00294 }
00295 if (_Touched)
00296 {
00298 if (_Tex == NULL)
00299 {
00300 forceTexturedMaterialStages(1);
00301 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
00302 }
00303 else
00304 {
00305 _Mat.setTexture(0, _Tex);
00306 forceTexturedMaterialStages(2);
00307 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
00308 SetupModulatedStage(_Mat, 1, CMaterial::Diffuse, CMaterial::Previous);
00309 }
00310
00311 if (!useGlobalColor)
00312 {
00313 if (!_ColorScheme)
00314 {
00315 _Mat.texConstantColor(0, _Color);
00316 }
00317 else
00318 {
00319 _Mat.texConstantColor(0, NLMISC::CRGBA::White);
00320 }
00321 }
00322 _Touched = false;
00323 }
00324
00325
00326 if (useGlobalColor)
00327 {
00328 if (_ColorScheme)
00329 {
00330 _Mat.texConstantColor(0, ps.getGlobalColor());
00331 }
00332 else
00333 {
00334 NLMISC::CRGBA col;
00335 col.modulateFromColor(ps.getGlobalColor(), _Color);
00336 _Mat.texConstantColor(0, col);
00337 }
00338 }
00339 }
00340
00342 void CPSFanLight::draw(bool opaque)
00343 {
00344 PARTICLES_CHECK_MEM;
00345 if (!_Owner->getSize()) return;
00346
00347 uint32 step;
00348 uint numToProcess;
00349 computeSrcStep(step, numToProcess);
00350 if (!numToProcess) return;
00351
00352 setupMaterial();
00353
00354 if (step == (1 << 16))
00355 {
00356 CPSFanLightHelper::drawFanLight(_Owner->getPos().begin(),
00357 _Owner->getTime().begin(),
00358 *this,
00359 numToProcess,
00360 step
00361 );
00362 }
00363 else
00364 {
00365 CPSFanLightHelper::drawFanLight(TIteratorVectStep1616(_Owner->getPos().begin(), 0, step),
00366 TIteratorTimeStep1616(_Owner->getTime().begin(), 0, step),
00367 *this,
00368 numToProcess,
00369 step
00370 );
00371 }
00372
00373 PARTICLES_CHECK_MEM;
00374 }
00375
00377 void CPSFanLight::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00378 {
00379 sint ver = f.serialVersion(2);
00380 CPSParticle::serial(f);
00381 CPSColoredParticle::serialColorScheme(f);
00382 CPSSizedParticle::serialSizeScheme(f);
00383 CPSRotated2DParticle::serialAngle2DScheme(f);
00384 f.serial(_NbFans);
00385 serialMaterial(f);
00386 if (ver > 1)
00387 {
00388 f.serial(_PhaseSmoothness, _MoveIntensity);
00389 ITexture *tex = _Tex;
00390 f.serialPolyPtr(tex);
00391 if (f.isReading()) _Tex = tex ;
00392 }
00393 if (f.isReading())
00394 {
00395 init();
00396 }
00397 }
00398
00400 bool CPSFanLight::completeBBox(NLMISC::CAABBox &box) const
00401 {
00402
00403
00404 return false;
00405 }
00406
00408 CPSFanLight::CPSFanLight(uint32 nbFans) : _NbFans(nbFans),
00409 _PhaseSmoothness(0),
00410 _MoveIntensity(1.5f),
00411 _Tex(NULL),
00412 _PhaseSpeed(256),
00413 _Touched(true),
00414 _UseGlobalColor(false)
00415
00416 {
00417 nlassert(nbFans >= 3);
00418
00419
00420 init();
00421 _Name = std::string("FanLight");
00422 }
00423
00424
00426 CPSFanLight::~CPSFanLight()
00427 {
00428 }
00429
00430
00432 void CPSFanLight::setNbFans(uint32 nbFans)
00433 {
00434 _NbFans = nbFans;
00435
00436 resize(_Owner->getMaxSize());
00437
00438 notifyOwnerMaxNumFacesChanged();
00439 }
00440
00442 void CPSFanLight::resize(uint32 size)
00443 {
00444 nlassert(size < (1 << 16));
00445 resizeColor(size);
00446 resizeAngle2D(size);
00447 resizeSize(size);
00448
00449 }
00450
00452 void CPSFanLight::init(void)
00453 {
00454 _Mat.setLighting(false);
00455 _Mat.setZFunc(CMaterial::less);
00456 _Mat.setDoubleSided(true);
00457 _Mat.setColor(NLMISC::CRGBA::White);
00458
00459 updateMatAndVbForColor();
00460 }
00461
00463 void CPSFanLight::updateMatAndVbForColor(void)
00464 {
00465 touch();
00466 }
00467
00469 void CPSFanLight::getVBnIB(CVertexBuffer *&retVb, CPSFanLight::TIndexBuffer *&retIb)
00470 {
00471 TVBMap &vbMap = _ColorScheme ? (_Tex == NULL ? _ColoredVBMap : _ColoredTexVBMap)
00472 : (_Tex == NULL ? _VBMap : _TexVBMap);
00473 TVBMap::iterator vbIt = vbMap.find(_NbFans);
00474 if (vbIt != vbMap.end())
00475 {
00476 retVb = &(vbIt->second);
00477 TIBMap::iterator pbIt = _IBMap.find(_NbFans);
00478 nlassert(pbIt != _IBMap.end());
00479 retIb = &(pbIt->second);
00480 }
00481 else
00482 {
00483
00484 CVertexBuffer &vb = vbMap[_NbFans];
00485 TIndexBuffer &ib = _IBMap[_NbFans];
00486 const uint32 size = getNumFanlightsInVB();
00487 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00488 CVertexBuffer::PrimaryColorFlag |
00489 (_Tex != NULL ? CVertexBuffer::TexCoord0Flag : 0)
00490 );
00491 vb.setNumVertices(size * (2 + _NbFans));
00492 ib.resize(size * _NbFans * 3);
00493
00494 TIndexBuffer::iterator ptIndex = ib.begin();
00495
00496
00497 uint currVertFan = 0;
00498
00499 uint l;
00500 uint k;
00501
00502 for (k = 0; k < size; ++k)
00503 {
00504 for (l = 0; l < _NbFans; ++l)
00505 {
00506 *ptIndex++ = currVertFan;
00507 *ptIndex++ = currVertFan + (l + 1);
00508 *ptIndex++ = currVertFan + (l + 2);
00509 }
00510 currVertFan += 2 + _NbFans;
00511 }
00512
00513 for (k = 0; k < size; ++k)
00514 {
00515 if (_Tex)
00516 {
00517 vb.setTexCoord(k * (_NbFans + 2), 0, NLMISC::CUV(0, 0));
00518 }
00519 if (!_ColorScheme)
00520 {
00521 vb.setColor(k * (_NbFans + 2), CRGBA::White);
00522 }
00523 if (!_Tex)
00524 {
00525 for(l = 1; l <= _NbFans + 1; ++l)
00526 {
00527 vb.setColor(l + k * (_NbFans + 2), CRGBA(0, 0, 0));
00528 }
00529 }
00530 else
00531 {
00532 for(l = 1; l <= _NbFans + 1; ++l)
00533 {
00534 vb.setColor(l + k * (_NbFans + 2), CRGBA(0, 0, 0));
00535 vb.setTexCoord(l + k * (_NbFans + 2), 0, NLMISC::CUV((l - 1) / (float) _NbFans, 1));
00536 }
00537 }
00538 }
00539
00540 retVb = &vb;
00541 retIb = &ib;
00542 }
00543 }
00544
00546 uint CPSFanLight::getNumFanlightsInVB() const
00547 {
00548 const uint numRib = NumVertsInBuffer / (2 + _NbFans);
00549 return std::max(1u, numRib);
00550 }
00551
00552 }