ps_fan_light.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
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 // fan light implementation //
00043 
00044 
00045 uint8 CPSFanLight::_RandomPhaseTab[32][128];
00046 bool CPSFanLight::_RandomPhaseTabInitialized = false;
00047 
00048 CPSFanLight::TVBMap             CPSFanLight::_VBMap; // fanlight, no texture
00049 CPSFanLight::TVBMap             CPSFanLight::_TexVBMap; // fanlight, textured
00050 CPSFanLight::TVBMap             CPSFanLight::_ColoredVBMap; // fanlight, no texture, varying color
00051 CPSFanLight::TVBMap             CPSFanLight::_ColoredTexVBMap; // fanlight, textured, varying color
00052 CPSFanLight::TIBMap             CPSFanLight::_IBMap;
00053 
00054 
00055 static const uint FanLightBufSize  = 128; // the size of a buffer of particle to deal with at a time
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         // get (and build if necessary) the vb and the ib
00086         f.getVBnIB(vb, ib);
00087         // tmp
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); // for benchmark purpose
00093         float pSizes[FanLightBufSize];
00094         float pAngles[FanLightBufSize];
00095         T endPosIt;
00096 
00097         sint32 k; // helps to count the fans
00098 
00099 
00100          // if so, we need to deal process separatly group of particles
00101         const uint32 stride = vb->getVertexSize();
00102 
00103         float currentAngle;
00104         const float angleStep = 256.0f / f._NbFans;
00105 
00106 
00107         float *currentSizePt; // it points either the particle constant size, or a size in a table
00108         float *currentAnglePt; // it points either the particle constant angle, or an angle in a table
00109 
00110 
00111         const uint32 currentSizePtIncrement = f._SizeScheme ? 1 : 0; // increment to get the next size for the size pointer. It is 0 if the size is constant
00112         const uint32 currentAnglePtIncrement = f._Angle2DScheme ? 1 : 0; // increment to get the next angle for the angle pointer. It is 0 if the size is constant
00113 
00114 
00115         uint leftToDo = size;
00116         if (f._ColorScheme)
00117         {
00118             // we change the color at each fan light center
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                 // compute individual colors if needed
00131                 if (f._ColorScheme)
00132                 {
00133                     // we change the color at each fan light center
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                     // the start angle
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                     // compute radius & vect for first fan
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                     // computes other fans
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                     // interpolate radius, so that the fanlight loops correctly
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                     // last fan
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 // this blur a tab of bytes once
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     // build several random tab, and linearly interpolate between l values
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     //#ifdef NL_DEBUG
00258         _RandomPhaseTabInitialized = true;
00259     //#endif
00260 }
00261 
00263 uint32 CPSFanLight::getNumWantedTris() const
00264 {
00265     NL_PS_FUNC(CPSFanLight_getNumWantedTris)
00266     nlassert(_Owner);
00267     //return _Owner->getMaxSize() * _NbFans;
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     // always setup global colors
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 //  if (!FilterPS[3]) return;
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     // TODO
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     //notifyOwnerMaxNumFacesChanged();
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     //touch();
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 // we need to create the vb
00515     {
00516         // create an entry (we setup the primitive block at the same time, this could be avoided, but doesn't make much difference)
00517         CVertexBuffer &vb = vbMap[_NbFans]; // create a vb
00518         CIndexBuffer &ib = _IBMap[_NbFans]; // eventually create a pb
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); // keep local memory because of interleaved format
00526         vb.setName("CPSFanLight");
00527         ib.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
00528         ib.setNumIndexes(size * _NbFans * 3);
00529         // pointer on the current index to fill
00530         CIndexBufferReadWrite iba;
00531         ib.lock (iba);
00532         TIndexType *ptIndex = (TIndexType *) iba.getPtr();
00533 
00534         CVertexBufferReadWrite vba;
00535         vb.lock (vba);
00536 
00537         // index of the first vertex of the current fanFilght
00538         uint currVertFan = 0;
00539 
00540         uint l; // the current fan in the current fanlight
00541         uint k; // the current fan light
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 } // NL3D

Generated on Thu Jan 7 08:26:28 2010 for NeL by  doxygen 1.6.1