# 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_shockwave.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_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 // constant definition   //
00042 
00043 // max number of shockwave to be processed at once
00044 static const uint ShockWaveBufSize = 128; 
00045 
00046 // the number of vertices we want in a vertex buffer
00047 static const uint NumVertsInBuffer = 8 * ShockWaveBufSize;
00048 
00049 
00050 CPSShockWave::TPBMap CPSShockWave::_PBMap; // the primitive blocks
00051 CPSShockWave::TVBMap CPSShockWave::_VBMap; // vb ith unanimated texture
00052 CPSShockWave::TVBMap CPSShockWave::_AnimTexVBMap; // vb ith unanimated texture
00053 CPSShockWave::TVBMap CPSShockWave::_ColoredVBMap; // vb ith unanimated texture
00054 CPSShockWave::TVBMap CPSShockWave::_ColoredAnimTexVBMap; // vb ith unanimated texture
00056 // CPSShockWave implementation //
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                 // get / build the vertex buffer and the primitive block
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); // for benchmark purpose     
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); // must be attached to an owner before to call this method
00243         _UFactor = value;
00244         resize(_Owner->getSize()); // resize also recomputes the UVs..
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         // TODO : implement this
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                 // compute the colors, each color is replicated n times...
00368                 _ColorScheme->makeN(_Owner, startIndex, vb.getColorPointer(), vb.getVertexSize(), size, (_NbSeg + 1) << 1, srcStep);
00369         }
00370 
00371         if (_TexGroup) // if it has a constant texture we are sure it has been setupped before...
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                         // for now, we don't make texture index wrapping
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                                 // point the next quad
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 // we need to create the vb
00474         {               
00475                 // create an entry (we setup the primitive block at the same time, this could be avoided, but doesn't make much difference)             
00476                 CVertexBuffer &vb = vbMap[_NbSeg]; // create a vb
00477                 CPrimitiveBlock &pb = _PBMap[_NbSeg]; // eventually create a pb
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 } // NL3D