# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

ps_fan_light.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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 // fan light implementation //
00045 
00046 
00047 uint8 CPSFanLight::_RandomPhaseTab[32][128];
00048 bool CPSFanLight::_RandomPhaseTabInitialized = false;
00049 
00050 CPSFanLight::TVBMap                             CPSFanLight::_VBMap; // fanlight, no texture
00051 CPSFanLight::TVBMap                             CPSFanLight::_TexVBMap; // fanlight, textured
00052 CPSFanLight::TVBMap                             CPSFanLight::_ColoredVBMap; // fanlight, no texture, varying color
00053 CPSFanLight::TVBMap                             CPSFanLight::_ColoredTexVBMap; // fanlight, textured, varying color
00054 CPSFanLight::TIBMap                             CPSFanLight::_IBMap;
00055 
00056 
00057 static const uint FanLightBufSize  = 128; // the size of a buffer of particle to deal with at a time
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                 // get (and build if necessary) the vb and the ib
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); // for benchmark purpose                     
00090                 float pSizes[FanLightBufSize];
00091                 float pAngles[FanLightBufSize];
00092                 T endPosIt;             
00093 
00094                 sint32 k; // helps to count the fans
00095 
00096                 
00097                  // if so, we need to deal process separatly group of particles                 
00098                 const uint32 stride = vb->getVertexSize();
00099 
00100                 float currentAngle;
00101                 const float angleStep = 256.0f / f._NbFans;     
00102 
00103                 
00104                 float *currentSizePt; // it points either the particle constant size, or a size in a table
00105                 float *currentAnglePt; // it points either the particle constant angle, or an angle in a table
00106 
00107                 
00108                 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
00109                 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
00110                                 
00111 
00112                 uint leftToDo = size;
00113                 do
00114                 {                               
00115                         uint8 *ptVect = (uint8 *) vb->getVertexCoordPointer();
00116                         uint toProcess = std::min(leftToDo, maxNumFanLightToDealWith);                                                  
00117                         // compute individual colors if needed
00118                         if (f._ColorScheme)
00119                         {
00120                                 // we change the color at each fan light center
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                                 // the start angle
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                                 // compute radius & vect for first fan
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                                 // computes other fans
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                                 // interpolate radius, so that the fanlight loops correctly
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                                 // last fan
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 // this blur a tab of bytes once
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         // build several random tab, and linearly interpolate between l values
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         //#ifdef NL_DEBUG
00240                 _RandomPhaseTabInitialized = true;
00241         //#endif
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         // always setup global colors 
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         // TODO
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 // we need to create the vb
00482         {               
00483                 // create an entry (we setup the primitive block at the same time, this could be avoided, but doesn't make much difference)             
00484                 CVertexBuffer &vb = vbMap[_NbFans]; // create a vb
00485                 TIndexBuffer &ib = _IBMap[_NbFans]; // eventually create a pb
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                 // pointer on the current index to fill
00494                 TIndexBuffer::iterator ptIndex = ib.begin();    
00495                 
00496                 // index of the first vertex of the current fanFilght
00497                 uint currVertFan = 0;
00498 
00499                 uint l; // the current fan in the current fanlight
00500                 uint k; // the current fan light
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 } // NL3D