# 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_ribbon.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_ribbon.h"
00029 #include "3d/ps_macro.h"
00030 #include "3d/particle_system.h"
00031 #include "3d/driver.h"
00032 #include "3d/ps_util.h"
00033 #include "3d/texture_mem.h"
00034 #include "nel/misc/matrix.h"
00035 
00036 namespace NL3D 
00037 {
00038 
00039 static NLMISC::CRGBA GradientB2W[] = {NLMISC::CRGBA(0, 0, 0, 0), NLMISC::CRGBA(255, 255, 255, 255) };
00040 
00042 static ITexture *CreateGradientTexture()
00043 {
00044         std::auto_ptr<CTextureMem> tex(new CTextureMem((uint8 *) &GradientB2W,
00045                                                                                                    sizeof(GradientB2W),
00046                                                                                                    false, /* dont delete */
00047                                                                                                    false, /* not a file */
00048                                                                                                    2, 1)
00049                                                                   );
00050         tex->setWrapS(ITexture::Clamp);
00051         tex->setShareName("#GradBW");
00052         return tex.release();
00053 }
00054 
00055 
00057 // ribbon implementation //
00059 
00060         // predifined shapes
00061 const NLMISC::CVector CPSRibbon::Triangle[] = 
00062 { 
00063         NLMISC::CVector(0, 1, 0),
00064         NLMISC::CVector(1, -1, 0),
00065         NLMISC::CVector(-1, -1, 0),                                                              
00066 };
00067 
00068 const NLMISC::CVector CPSRibbon::Losange[] = 
00069 { 
00070         NLMISC::CVector(0, 1.f, 0),
00071         NLMISC::CVector(1.f, 0, 0),
00072         NLMISC::CVector(0, -1.f, 0),
00073         NLMISC::CVector(-1.f, 0, 0)
00074 };
00075 
00076 const NLMISC::CVector  CPSRibbon::HeightSides[] = 
00077 {  
00078         NLMISC::CVector(-0.5f, 1, 0),
00079         NLMISC::CVector(0.5f, 1, 0),
00080         NLMISC::CVector(1, 0.5f, 0),
00081         NLMISC::CVector(1, -0.5f, 0),
00082         NLMISC::CVector(0.5f, -1, 0),
00083         NLMISC::CVector(-0.5f, -1, 0),
00084         NLMISC::CVector(-1, -0.5f, 0),
00085         NLMISC::CVector(-1, 0.5f, 0) 
00086 };
00087 
00088 
00089 const NLMISC::CVector CPSRibbon::Pentagram[] = 
00090 { 
00091         NLMISC::CVector(0, 1, 0),
00092         NLMISC::CVector(1, -1, 0),
00093         NLMISC::CVector(-1, 0, 0),
00094         NLMISC::CVector(1, 0, 0),
00095         NLMISC::CVector(-1, -1, 0)
00096 };
00097 
00098 const uint CPSRibbon::NbVerticesInTriangle = sizeof(CPSRibbon::Triangle) / sizeof(CVector);
00099 const uint CPSRibbon::NbVerticesInLosange = sizeof(Losange) / sizeof(CVector);
00100 const uint CPSRibbon::NbVerticesInHeightSide = sizeof(CPSRibbon::HeightSides) / sizeof(CVector);
00101 const uint CPSRibbon::NbVerticesInPentagram = sizeof(CPSRibbon::Pentagram) / sizeof(CVector);
00102 
00103 
00104 CPSRibbon::TVBMap                       CPSRibbon::_VBMap;                           // index / vertex buffers with no color
00105 CPSRibbon::TVBMap                       CPSRibbon::_FadedVBMap;                  // index / vertex buffers for constant color with fading
00106 CPSRibbon::TVBMap                       CPSRibbon::_ColoredVBMap;                // index / vertex buffer + colors
00107 CPSRibbon::TVBMap                       CPSRibbon::_FadedColoredVBMap;   // index / vertex buffer + faded colors
00108 
00109 CPSRibbon::TVBMap                       CPSRibbon::_TexVBMap;                       // index / vertex buffers with no color + texture
00110 CPSRibbon::TVBMap                       CPSRibbon::_TexFadedVBMap;              // index / vertex buffers for constant color with fading + texture
00111 CPSRibbon::TVBMap                       CPSRibbon::_TexColoredVBMap;            // index / vertex buffer + colors + texture
00112 CPSRibbon::TVBMap                       CPSRibbon::_TexFadedColoredVBMap;   // index / vertex buffer + faded colors + texture
00113 
00114 
00115 struct CDummy2DAngle : CPSRotated2DParticle
00116 {
00117         CPSLocated *getAngle2DOwner(void) { return NULL; }
00118 };
00119 
00121 void CPSRibbon::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00122 {
00123         sint ver = f.serialVersion(2);
00124         if (ver == 1)
00125         {
00126                 nlassert(f.isReading());
00127 
00130                 sint ver2 = f.serialVersion(2);
00131 
00132                 // here is CPSLocatedBindable::serial(f)
00133                 sint ver3 = f.serialVersion(4);
00134                 f.serialPtr(_Owner);
00135                 if (ver3 > 1) f.serialEnum(_LOD);
00136                 if (ver3 > 2) f.serial(_Name);
00137                 if (ver3 > 3) 
00138                 {
00139                         if (f.isReading())
00140                         {
00141                                 uint32 id;
00142                                 f.serial(id);
00143                                 setExternID(id);
00144                         }
00145                         else
00146                         {
00147                                 f.serial(_ExternID);
00148                         }
00149                 }
00150 
00151                 if (ver2 >= 2)
00152                 {
00153                         bool bDisableAutoLOD;
00154                         f.serial(bDisableAutoLOD);
00155                         disableAutoLOD(bDisableAutoLOD);
00156                 }
00157 
00158                 uint32 tailNbSegs;
00159                 bool   colorFading;
00160                 bool   systemBasisEnabled;
00161                 bool   drEnabled; // dying ribbons, not supported in this version
00162 
00163                 CPSColoredParticle::serialColorScheme(f);
00164                 CPSSizedParticle::serialSizeScheme(f);
00165 
00166                 // we dont use the 2d angle anymore...serial a dummy one
00167                 {                       
00168                          CDummy2DAngle _Dummy2DAngle;
00169                         _Dummy2DAngle.serialAngle2DScheme(f); 
00170                 }
00171 
00172                 f.serial(colorFading, systemBasisEnabled);
00173                 serialMaterial(f);
00174 
00175                 f.serial(drEnabled);                            
00176                 f.serial(tailNbSegs);
00177                 ITexture *tex;
00178                 f.serialPolyPtr(tex);
00179                 _Tex = tex;
00180                 if (_Tex != NULL)
00181                 {
00182                         f.serial(_UFactor, _VFactor) ;
00183                 }
00184 
00185                 // shape serialization  
00186                 f.serialCont(_Shape);
00187                 
00188                 
00189                 _NbSegs = tailNbSegs >> 1;
00190                 if (_NbSegs < 1) _NbSegs = 2;
00191                 setInterpolationMode(Linear);
00192 
00193                 nlassert(_Owner);
00194                 resize(_Owner->getMaxSize());
00195                 initDateVect();         
00196                 resetFromOwner();       
00197         }       
00198 
00199 
00200         if (ver >= 2)
00201         {
00202                 CPSRibbonBase::serial(f);
00203                 CPSColoredParticle::serialColorScheme(f);
00204                 CPSSizedParticle::serialSizeScheme(f);
00205                 CPSMaterial::serialMaterial(f);
00206                 f.serialCont(_Shape);
00207                 bool colorFading = _ColorFading;
00208                 f.serial(colorFading);  
00209                 _ColorFading = colorFading;
00210                 uint32 tailNbSegs = _NbSegs;
00211                 f.serial(tailNbSegs);           
00212                 if (f.isReading())
00213                 {
00214                         setTailNbSeg(_NbSegs);
00215                         touch();
00216                 }
00217                 ITexture *tex = _Tex;
00218                 f.serialPolyPtr(tex);
00219                 _Tex = tex;
00220                 if (_Tex != NULL)
00221                 {
00222                         f.serial(_UFactor, _VFactor) ;
00223                 }
00224         }
00225 
00226 }
00227 
00228 
00229 //=======================================================       
00230 CPSRibbon::CPSRibbon() : _UFactor(1.f),
00231                                                  _VFactor(1.f),
00232                                                  _ColorFading(true),
00233                                                  _GlobalColor(false),
00234                                                  _Touch(true)
00235 {
00236         setInterpolationMode(Linear);
00237         setSegDuration(0.06f);
00238         _Name = std::string("Ribbon");
00239         setShape(Triangle, NbVerticesInTriangle);
00240         _Mat.setDoubleSided(true);
00241 }
00242 
00243 
00244 //=======================================================       
00245 CPSRibbon::~CPSRibbon()
00246 {
00247 }
00248 
00249 
00250 //==========================================================================    
00251 inline uint CPSRibbon::getNumVerticesInSlice() const
00252 {
00253         return _Shape.size() + (_Tex == NULL ? 0 : 1);
00254 }
00255 
00256 
00257 
00258 
00259 
00260 //=======================================================       
00261 void CPSRibbon::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00262 {       
00263         if (pass == PSMotion)
00264         {       
00265                 if (!_Parametric)
00266                 {
00267                         updateGlobals();
00268                 }
00269         }
00270         else
00271         if (
00272                 (pass == PSBlendRender && hasTransparentFaces())
00273                 || (pass == PSSolidRender && hasOpaqueFaces())
00274                 )
00275         {
00276                 uint32 step;
00277                 uint   numToProcess;
00278                 computeSrcStep(step, numToProcess);     
00279                 if (!numToProcess) return;
00280                 
00282                 CParticleSystem &ps = *(_Owner->getOwner());    
00283                 _Mat.setColor(ps.getGlobalColor());
00284                 
00289                 displayRibbons(numToProcess, step);
00290 
00291         }
00292         else 
00293         if (pass == PSToolRender) // edition mode only
00294         {                       
00295                 //showTool();
00296         }       
00297 }
00298 
00299 
00300 //=======================================================       
00301 void CPSRibbon::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00302 {
00303         CPSRibbonBase::newElement(emitterLocated, emitterIndex);
00304         newColorElement(emitterLocated, emitterIndex);
00305         newSizeElement(emitterLocated, emitterIndex);
00306 }
00307 
00308 
00309 //=======================================================       
00310 void CPSRibbon::deleteElement(uint32 index)
00311 {
00312         CPSRibbonBase::deleteElement(index);
00313         deleteColorElement(index);      
00314         deleteSizeElement(index);       
00315 }
00316 
00317 
00318 //=======================================================       
00319 void CPSRibbon::resize(uint32 size)
00320 {
00321         nlassert(size < (1 << 16));
00322         CPSRibbonBase::resize(size);    
00323         resizeColor(size);
00324         resizeSize(size);
00325 }
00326 
00327 //=======================================================       
00328 void CPSRibbon::updateMatAndVbForColor(void)
00329 {
00330         touch();
00331 }
00332 
00333 
00335 // Create the start slice of a ribbon (all vertices at the same pos)
00336 static inline uint8 *BuildRibbonFirstSlice(const NLMISC::CVector &pos,
00337                                                                                    uint  numVerts,
00338                                                                                    uint8 *dest,
00339                                                                                    uint  vertexSize
00340                                                                               )
00341 {       
00342         do
00343         {
00344                 * (NLMISC::CVector *) dest = pos;
00345                 dest += vertexSize;
00346         }
00347         while (--numVerts);
00348         return dest;
00349 }
00350 
00351 
00353 // This compute one slice of a ribbon, and return the next vertex to be filled
00354 static inline uint8 *ComputeRibbonSlice(const NLMISC::CVector &prev,
00355                                                                             const NLMISC::CVector &next,                                                                         
00356                                                                             const NLMISC::CVector *shape,
00357                                                                             uint  numVerts,
00358                                                                             uint8 *dest,
00359                                                                             uint  vertexSize,
00360                                                                                 float size
00361                                                                            )
00362 {       
00363         // compute a basis from the next and previous position.
00364         // (not optimized for now, but not widely used, either...)      
00365         static NLMISC::CMatrix m;
00366         m.setPos(next);
00367         CPSUtil::buildSchmidtBasis(next - prev, m);
00368         m.scale(size);
00369         
00370         const NLMISC::CVector *shapeEnd = shape + numVerts;
00371         do
00372         {
00373                 *(NLMISC::CVector *) dest = m * (*shape);
00374                 ++shape;
00375                 dest += vertexSize;
00376         }
00377         while (shape != shapeEnd);
00378         return dest;
00379 }
00380 
00381 
00382 
00384 // This is used to compute a ribbon mesh from its curve and its base shape.
00385 // This is for untextured versions (no need to duplicate the last vertex of each slice)
00386 static inline uint8 *ComputeUntexturedRibbonMesh(uint8 *destVb,
00387                                                                                              uint  vertexSize,
00388                                                                                              const NLMISC::CVector *curve,
00389                                                                                              const NLMISC::CVector *shape,
00390                                                                                              uint  numSegs,
00391                                                                                                  uint  numVerticesInShape,
00392                                                                                                  float sizeIncrement,
00393                                                                                                  float size
00394                                                                                                 )
00395 {                                       
00396         do
00397         {
00398                 destVb = ComputeRibbonSlice(curve[1],
00399                                                                     curve[0],
00400                                                                         shape,
00401                                                                         numVerticesInShape,
00402                                                                         destVb,
00403                                                                         vertexSize,
00404                                                                         size);
00405                 ++ curve;
00406                 size -= sizeIncrement;
00407         }
00408         while (--numSegs);
00409         return BuildRibbonFirstSlice(curve[0], numVerticesInShape, destVb, vertexSize);                 
00410 }
00411 
00413 // This is used to compute a ribbon mesh from its curve and its base shape.
00414 // (Textured Version)
00415 static inline uint8 *ComputeTexturedRibbonMesh(uint8 *destVb,
00416                                                                                            uint  vertexSize,
00417                                                                                            const NLMISC::CVector *curve,
00418                                                                                            const NLMISC::CVector *shape,
00419                                                                                            uint  numSegs,
00420                                                                                            uint  numVerticesInShape,
00421                                                                                            float sizeIncrement,
00422                                                                                            float size
00423                                                                                           )
00424 {       
00425                         
00426         do
00427         {
00428                 uint8 *nextDestVb = ComputeRibbonSlice(curve[1],
00429                                                                                            curve[0],
00430                                                                                            shape,
00431                                                                                            numVerticesInShape,
00432                                                                                            destVb,
00433                                                                                            vertexSize,
00434                                                                                            size
00435                                                                                           );
00436                 // duplicate last vertex ( equal first)
00437                 * (NLMISC::CVector *) nextDestVb = * (NLMISC::CVector *) destVb;
00438                 destVb = nextDestVb + vertexSize;
00439                 //
00440                 ++ curve;
00441                 size -= sizeIncrement;
00442         }
00443         while (--numSegs);
00444         return BuildRibbonFirstSlice(curve[0], numVerticesInShape + 1, destVb, vertexSize);     
00445 }
00446 
00447 //==========================================================================    
00448 void CPSRibbon::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00449 {       
00450         if (!nbRibbons) return;
00451         nlassert(_Owner);       
00452         CPSRibbonBase::updateLOD();
00453         if (_UsedNbSegs < 2) return;
00454         const float date = _Owner->getOwner()->getSystemDate();
00455         uint8                                           *currVert;
00456         CVBnPB                                          &VBnPB = getVBnPB(); // get the appropriate vb (built it if needed)
00457         CVertexBuffer                           &VB = VBnPB.VB;
00458         CPrimitiveBlock                         &PB = VBnPB.PB;
00459         const uint32                            vertexSize  = VB.getVertexSize();
00460         uint                                            colorOffset=0;  
00461         
00462         IDriver *drv = this->getDriver();
00463         setupDriverModelMatrix();
00464         drv->activeVertexBuffer(VB);
00465         _Owner->incrementNbDrawnParticles(nbRibbons); // for benchmark purpose          
00466         const uint numRibbonBatch = getNumRibbonsInVB(); // number of ribons to process at once         
00467         if (_UsedNbSegs == 0) return;   
00469         // Material setup //
00471                 CParticleSystem &ps = *(_Owner->getOwner());
00472                 bool useGlobalColor = ps.getColorAttenuationScheme() != NULL;
00473                 if (useGlobalColor != _GlobalColor)
00474                 {
00475                         touch();
00476                 }
00477                 updateMaterial();
00478                 setupGlobalColor();
00479                 //
00480                 if (_ColorScheme)
00481                 {
00482                         colorOffset = VB.getColorOff(); 
00483                 }       
00485         // Compute ribbons //
00487                 const uint numVerticesInSlice = getNumVerticesInSlice();
00488                 const uint numVerticesInShape = _Shape.size();
00489                 //
00490                 static std::vector<float> sizes;
00491                 static std::vector<NLMISC::CVector> ribbonPos;  // this is where the position of each ribbon slice center i stored
00492                 ribbonPos.resize(_UsedNbSegs + 1); // make sure we have enough room
00493                 sizes.resize(numRibbonBatch);
00494                 
00495                 //
00496                 uint toProcess;
00497                 uint ribbonIndex = 0; // index of the first ribbon in the batch being processed 
00498                 uint32 fpRibbonIndex = 0; // fixed point index in source
00499                 do
00500                 {
00501                         toProcess = std::min((uint) (nbRibbons - ribbonIndex) , numRibbonBatch);
00502                         currVert = (uint8 *) VB.getVertexCoordPointer();
00503                                 
00505                         const float     *ptCurrSize;
00506                         uint32  ptCurrSizeIncrement;
00507                         if (_SizeScheme)
00508                         {                       
00509                                 ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);                        
00510                                 ptCurrSizeIncrement = 1;
00511                         }
00512                         else
00513                         {
00514                                 ptCurrSize = &_ParticleSize;
00515                                 ptCurrSizeIncrement = 0;
00516                         }
00517 
00519                         if (_ColorScheme)
00520                         {                       
00521                                 _ColorScheme->makeN(this->_Owner, ribbonIndex, currVert + colorOffset, vertexSize, toProcess, numVerticesInSlice * (_UsedNbSegs + 1), srcStep);                 
00522                         }                       
00523                         uint k = toProcess;     
00525                         // interpolate and project points the result is directly setup in the vertex buffer //
00527                         if (!_Parametric)
00528                         {
00530                                 // INCREMENTAL CASE //
00532                                 if (_Tex != NULL) // textured case
00533                                 {
00534                                         do
00535                                         {
00536                                                 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00537                                                 ptCurrSize += ptCurrSizeIncrement;
00538                                                 // the parent class has a method to get the ribbons positions
00539                                                 computeRibbon((uint) (fpRibbonIndex >> 16), &ribbonPos[0], sizeof(NLMISC::CVector));
00540                                                 currVert = ComputeTexturedRibbonMesh(currVert,
00541                                                                                                                          vertexSize,
00542                                                                                                                          &ribbonPos[0],
00543                                                                                                                          &_Shape[0],
00544                                                                                                                          _UsedNbSegs,
00545                                                                                                                          numVerticesInShape,
00546                                                                                                                          ribbonSizeIncrement,
00547                                                                                                                          *ptCurrSize
00548                                                                                                                         );
00549                                                 fpRibbonIndex += srcStep;
00550                                         }
00551                                         while (--k);
00552                                 }
00553                                 else // untextured case
00554                                 {
00555                                         do
00556                                         {
00557                                                 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00558                                                 ptCurrSize += ptCurrSizeIncrement;
00559                                                 // the parent class has a method to get the ribbons positions
00560                                                 computeRibbon((uint) (fpRibbonIndex >> 16), &ribbonPos[0], sizeof(NLMISC::CVector));
00561                                                 currVert = ComputeUntexturedRibbonMesh(currVert,
00562                                                                                                                            vertexSize,
00563                                                                                                                            &ribbonPos[0],
00564                                                                                                                            &_Shape[0],
00565                                                                                                                            _UsedNbSegs,
00566                                                                                                                            numVerticesInShape,
00567                                                                                                                            ribbonSizeIncrement,
00568                                                                                                                            *ptCurrSize
00569                                                                                                                           );
00570                                                 fpRibbonIndex += srcStep;
00571                                         }
00572                                         while (--k);    
00573                                 }
00574                         }
00575                         else
00576                         {
00578                                 // PARAMETRIC  CASE //
00580                                 if (_Tex != NULL) // textured case
00581                                 {
00582                                         do
00583                                         {
00584                                                 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00585                                                 ptCurrSize += ptCurrSizeIncrement;
00586                                                 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1),
00587                                                                                                 _UsedSegDuration,
00588                                                                                                 _UsedNbSegs + 1,
00589                                                                                                 (uint) (fpRibbonIndex >> 16),
00590                                                                                                 &ribbonPos[0]);
00591 
00592                                                 currVert = ComputeTexturedRibbonMesh(currVert,
00593                                                                                                                          vertexSize,
00594                                                                                                                          &ribbonPos[0],
00595                                                                                                                          &_Shape[0],
00596                                                                                                                          _UsedNbSegs,
00597                                                                                                                          numVerticesInShape,
00598                                                                                                                          ribbonSizeIncrement,
00599                                                                                                                          *ptCurrSize
00600                                                                                                                     );
00601                                                 fpRibbonIndex += srcStep;
00602                                         }
00603                                         while (--k);
00604                                 }
00605                                 else // untextured case
00606                                 {
00607                                         do
00608                                         {
00609                                                 const float ribbonSizeIncrement = *ptCurrSize / (float) _UsedNbSegs;
00610                                                 ptCurrSize += ptCurrSizeIncrement;
00611                                                 _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1),
00612                                                                                                 _UsedSegDuration,
00613                                                                                                 _UsedNbSegs + 1,
00614                                                                                                 (uint) (fpRibbonIndex >> 16),
00615                                                                                                 &ribbonPos[0]);
00616 
00617                                                 currVert = ComputeUntexturedRibbonMesh(currVert,
00618                                                                                                                            vertexSize,
00619                                                                                                                            &ribbonPos[0],
00620                                                                                                                            &_Shape[0],
00621                                                                                                                            _UsedNbSegs,
00622                                                                                                                            numVerticesInShape,
00623                                                                                                                            ribbonSizeIncrement,
00624                                                                                                                            *ptCurrSize
00625                                                                                                                           );                            
00626                                                 fpRibbonIndex += srcStep;
00627                                         }
00628                                         while (--k);
00629                                 }                                                       
00630                         }                       
00631                         // display the result
00632                         PB.setNumTri((numVerticesInShape * _UsedNbSegs * toProcess) << 1);                      
00633                         drv->render(PB, _Mat);
00634                         ribbonIndex += toProcess;               
00635                 }
00636                 while (ribbonIndex != nbRibbons);
00637                 
00638 }       
00639 
00640 //==========================================================================    
00641 bool CPSRibbon::hasTransparentFaces(void)
00642 {
00643         return getBlendingMode() != CPSMaterial::alphaTest ;
00644 }
00645 
00646 
00647 //==========================================================================    
00648 bool CPSRibbon::hasOpaqueFaces(void)
00649 {
00650         return !hasTransparentFaces();
00651 }
00652 
00653 //==========================================================================    
00654 uint32 CPSRibbon::getMaxNumFaces(void) const
00655 {
00656         nlassert(_Owner);
00657         return _Owner->getMaxSize() * _NbSegs;  
00658 }
00659 
00660 //==========================================================================    
00661 CPSRibbon::CVBnPB &CPSRibbon::getVBnPB()
00662 {
00663         static TVBMap * const vbMaps[] =
00664         {
00666                 &_VBMap,                
00667                 &_FadedVBMap,        
00668                 &_ColoredVBMap,  
00669                 &_FadedColoredVBMap,
00671                 &_TexVBMap,             
00672                 &_TexFadedVBMap,             
00673                 &_TexColoredVBMap,  
00674                 &_TexFadedColoredVBMap
00675         };
00676 
00678         TVBMap &map = *vbMaps[ (_Tex != NULL                     ? (1 << 2) : 0)  | // set bit 2 if textured
00679                                                    (_ColorScheme != NULL  ? (1 << 1) : 0)  | // set bit 1 if per ribbon color
00680                                                    (_ColorFading                         ? 1 : 0)                  // set bit 0 if color fading
00681                                                  ];
00682 
00683         const uint numVerticesInSlice = getNumVerticesInSlice(); 
00684         const uint numVerticesInShape = _Shape.size();
00685 
00686 
00687         // The number of slice is encoded in the upper word of the vb index
00688         // The number of vertices per slices is encoded in the lower word
00689         uint VBnPDIndex = ((_UsedNbSegs + 1) << 16) | numVerticesInSlice;
00690         TVBMap::iterator it = map.find(VBnPDIndex);
00691         if (it != map.end())
00692         {
00693                 return it->second;
00694         }
00695         else    // must create this vb, with few different size, it is still interseting, though they are only destroyed at exit
00696         {
00697                 const uint numRibbonInVB = getNumRibbonsInVB();
00698                 CVBnPB &VBnPB = map[VBnPDIndex]; // make an entry
00699 
00703                 CVertexBuffer &vb = VBnPB.VB;
00704                 vb.setVertexFormat(CVertexBuffer::PositionFlag  | /* alway need position */
00705                                                    (_ColorScheme || _ColorFading ? CVertexBuffer::PrimaryColorFlag : 0) | /* need a color ? */
00706                                                    ((_ColorScheme && _ColorFading) ||  _Tex != NULL ? CVertexBuffer::TexCoord0Flag : 0) | /* need texture coordinates ? */
00707                                                    (_Tex != NULL && _ColorScheme && _ColorFading ? CVertexBuffer::TexCoord1Flag : 0) /* need 2nd texture coordinates ? */
00708                                                   );
00709                 vb.setNumVertices((_UsedNbSegs + 1) * numRibbonInVB * numVerticesInSlice); // 1 seg = 1 line + terminal vertices
00710 
00711                 // set the primitive block size
00712                 CPrimitiveBlock &pb = VBnPB.PB;
00713                 pb.setNumTri((_UsedNbSegs * numRibbonInVB * _Shape.size()) << 1);
00715                 uint vbIndex = 0;
00716                 uint pbIndex = 0; 
00717                 uint i, k, l;
00718                 for (i = 0; i < numRibbonInVB; ++i)
00719                 {
00720                         for (k = 0; k < (_UsedNbSegs + 1); ++k)
00721                         {
00722 
00724                                 if (k != _UsedNbSegs) 
00725                                 {       
00726                                         uint vIndex = vbIndex;
00727                                         for (l = 0; l < (numVerticesInShape - 1); ++l) 
00728                                         {                                                                                                                                                       
00729                                                 pb.setTri(pbIndex ++, vIndex, vIndex + numVerticesInSlice, vIndex + numVerticesInSlice + 1);
00730                                                 pb.setTri(pbIndex ++, vIndex, vIndex + numVerticesInSlice + 1, vIndex + 1);
00731                                                 ++ vIndex;
00732                                         }       
00733                                         
00735                                         uint nextVertexIndex = (numVerticesInShape == numVerticesInSlice) ?     vIndex + 1 - numVerticesInShape // no texture -> we loop 
00736                                                                                    : vIndex + 1; // a texture is used : use onemore vertex                                                                              
00737                                         pb.setTri(pbIndex ++, vIndex, vIndex + numVerticesInSlice, nextVertexIndex + numVerticesInSlice);
00738                                         pb.setTri(pbIndex ++, vIndex, nextVertexIndex + numVerticesInSlice, nextVertexIndex);
00739 
00740                                 }
00741 
00743                                 for (l = 0; l < numVerticesInSlice; ++l) 
00744                                 {
00745                                         nlassert(vbIndex < vb.getNumVertices());
00747                                         if (_Tex != NULL)
00748                                         {                                               
00749                                                 vb.setTexCoord(vbIndex,
00750                                                                            _ColorScheme && _ColorFading ? 1 : 0,                // must we use the second texture coord ? (when 1st one used by the gradient texture : we can't encode it in the diffuse as it encodes each ribbon color)
00751                                                                            (float) k / _UsedNbSegs,                               // u
00752                                                                            1.f - (l / (float) numVerticesInShape) // v
00753                                                                           );                                            
00754                                         }
00755 
00757                                         if (_ColorFading)
00758                                         {
00759                                                 // If not per ribbon color, we can encode it in the diffuse
00760                                                 if (_ColorScheme == NULL)
00761                                                 {
00762                                                         uint8 intensity = (uint8) (255 * (1.f - ((float) k / _UsedNbSegs)));
00763                                                         NLMISC::CRGBA col(intensity, intensity, intensity, intensity);
00764                                                         vb.setColor(vbIndex, col);                                              
00765                                                 }
00766                                                 else // encode it in the first texture
00767                                                 {
00768                                                         vb.setTexCoord(vbIndex, 0, 0.5f - 0.5f * ((float) k / _UsedNbSegs), 0);
00769                                                 }
00770                                         }
00771                                         ++ vbIndex;
00772                                 }
00773                                 
00774                         }
00775                 }
00776                 return VBnPB;
00777         }
00778 }
00779 
00780 //==========================================================================    
00781 uint    CPSRibbon::getNumRibbonsInVB() const
00782 {
00783         const uint numVerticesInSlice = getNumVerticesInSlice(); 
00784         const uint vertexInVB = 512;    
00785         return std::max(1u, (uint) (vertexInVB / (numVerticesInSlice * (_UsedNbSegs + 1))));
00786 }
00787 
00788 
00789 //==========================================================================    
00790 inline void     CPSRibbon::updateUntexturedMaterial()
00791 {
00793         // UNTEXTURED RIBBON //
00795 
00796         static NLMISC::CRefPtr<ITexture> ptGradTexture;
00797 
00798         CParticleSystem &ps = *(_Owner->getOwner());
00799         if (_ColorScheme)
00800         {       // PER RIBBON COLOR
00801                 if (ps.getColorAttenuationScheme())
00802                 {
00803                         if (_ColorFading) // global color + fading + per ribbon color
00804                         {
00805                                 // the first stage is used to get fading * global color
00806                                 // the second stage multiply the result by the diffuse colot
00807                                 if (ptGradTexture == NULL) // have we got a gradient texture ?
00808                                 {
00809                                         ptGradTexture = CreateGradientTexture();
00810                                 }
00811                                 _Mat.setTexture(0, ptGradTexture);
00812                                 CPSMaterial::forceTexturedMaterialStages(2); // use constant color 0 * diffuse, 1 stage needed
00813                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Constant);
00814                                 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Diffuse);
00815                         }
00816                         else // per ribbon color with global color 
00817                         {
00818                                 CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed
00819                                 SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
00820                         }
00821                 }
00822                 else
00823                 {       
00824                         if (_ColorFading) // per ribbon color, no fading
00825                         {                               
00826                                 if (ptGradTexture == NULL) // have we got a gradient texture ?
00827                                 {
00828                                         ptGradTexture = CreateGradientTexture();
00829                                 }
00830                                 _Mat.setTexture(0, ptGradTexture);
00831                                 CPSMaterial::forceTexturedMaterialStages(1);
00832                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
00833                         }
00834                         else // per color ribbon with no fading, and no global color
00835                         {
00836                                 CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only
00837                         }
00838                 }
00839         }
00840         else // GLOBAL COLOR
00841         {               
00842                 if (_ColorFading)
00843                 {                                                               
00844                         CPSMaterial::forceTexturedMaterialStages(1); // use constant color 0 * diffuse, 1 stage needed                          
00845                         SetupModulatedStage(_Mat, 0, CMaterial::Diffuse, CMaterial::Constant);
00846                 }
00847                 else // color attenuation, no fading : 
00848                 {
00849                         CPSMaterial::forceTexturedMaterialStages(0); // no texture use constant diffuse only                            
00850                 }               
00851         }
00852         _Touch = false;
00853 }
00854 
00855 //==========================================================================    
00856 inline void     CPSRibbon::updateTexturedMaterial()
00857 {
00859         // TEXTURED RIBBON //
00861 
00862         static NLMISC::CRefPtr<ITexture> ptGradTexture;
00863         CParticleSystem &ps = *(_Owner->getOwner());
00864         if (_ColorScheme)
00865         {       // PER RIBBON COLOR
00866                 if (ps.getColorAttenuationScheme())
00867                 {
00868                         if (_ColorFading) // global color + fading + per ribbon color
00869                         {                               
00870                                 if (ptGradTexture == NULL) // have we got a gradient texture ?
00871                                 {
00872                                         ptGradTexture = CreateGradientTexture(); // create it
00873                                 }
00875                                 _Mat.setTexture(0, ptGradTexture);
00876                                 _Mat.setTexture(1, _Tex);
00877                                 CPSMaterial::forceTexturedMaterialStages(3); // use constant color 0 * diffuse, 1 stage needed                          
00878                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
00879                                 SetupModulatedStage(_Mat, 1, CMaterial::Texture, CMaterial::Previous);
00880                                 SetupModulatedStage(_Mat, 2, CMaterial::Previous, CMaterial::Constant);                         
00881                         }
00882                         else // per ribbon color with global color 
00883                         {
00884                                 _Mat.setTexture(0, _Tex);
00885                                 CPSMaterial::forceTexturedMaterialStages(2); // use constant color 0 * diffuse, 1 stage needed                          
00886                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
00887                                 SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Constant);                 
00888                         }
00889                 }
00890                 else
00891                 {       
00892                         if (_ColorFading) // per ribbon color, fading : 2 textures needed
00893                         {                               
00894                                 if (ptGradTexture == NULL) // have we got a gradient texture ?
00895                                 {
00896                                         ptGradTexture = CreateGradientTexture(); // create it
00897                                 }
00898                                 _Mat.setTexture(0, ptGradTexture);
00899                                 _Mat.setTexture(1, _Tex);
00900                                 CPSMaterial::forceTexturedMaterialStages(2); 
00901                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse); // texture * ribbon color
00902                                 SetupModulatedStage(_Mat, 1, CMaterial::Texture, CMaterial::Previous);  // * gradient
00903                         }
00904                         else // per color ribbon with no fading, and no global color
00905                         {
00906                                 _Mat.setTexture(0, _Tex);
00907                                 CPSMaterial::forceTexturedMaterialStages(1); // no texture use constant diffuse only
00908                                 SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);                           
00909                         }
00910                 }
00911         }
00912         else // GLOBAL COLOR
00913         {
00914                 
00915                 if (_ColorFading) // gradient is encoded in diffuse
00916                 {
00917                         _Mat.setTexture(0, _Tex);
00918                         CPSMaterial::forceTexturedMaterialStages(2); // use constant color 0 * diffuse, 1 stage needed                          
00919                         SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);
00920                         SetupModulatedStage(_Mat, 1, CMaterial::Previous, CMaterial::Constant);                 
00921                 }
00922                 else // constant color
00923                 {
00924                         _Mat.setTexture(0, _Tex);
00925                         CPSMaterial::forceTexturedMaterialStages(1); // no texture use constant diffuse only                                                    
00926                         SetupModulatedStage(_Mat, 0, CMaterial::Texture, CMaterial::Diffuse);   
00927                 }               
00928         }
00929         _Touch = false;
00930 }
00931 
00932 //==========================================================================    
00933 void    CPSRibbon::updateMaterial()
00934 {
00935         if (!_Touch) return;
00936         if (_Tex != NULL) 
00937         {
00938                 updateTexturedMaterial();
00939                 setupTextureMatrix();
00940         }
00941         else
00942         {
00943                 updateUntexturedMaterial();
00944         }
00945 }
00946 
00947 
00948 
00949 //==========================================================================    
00950 inline void     CPSRibbon::setupUntexturedGlobalColor()
00951 {       
00953         CParticleSystem &ps = *(_Owner->getOwner());    
00954         if (_ColorScheme)
00955         {       
00956                 _Mat.texConstantColor(0, ps.getGlobalColor());                                  
00957         }
00958         else // GLOBAL COLOR with / without fading
00959         {
00960                 if (ps.getColorAttenuationScheme())
00961                 {                       
00962                         NLMISC::CRGBA col;
00963                         col.modulateFromColor(ps.getGlobalColor(), _Color);
00964                         if (_ColorFading)
00965                         {                                                               
00966                                 _Mat.texConstantColor(0, col);                          
00967                         }
00968                         else // color attenuation, no fading : 
00969                         {                                                       
00970                                 _Mat.setColor(col);
00971                         }
00972                 }
00973                 else
00974                 {
00975                         if (_ColorFading)
00976                         {
00977                                 _Mat.texConstantColor(0, _Color);                               
00978                         }
00979                         else // constant color
00980                         {
00981                                 _Mat.setColor(_Color);
00982                         }
00983                 }
00984         }
00985 }
00986 
00987 //==========================================================================    
00988 inline void     CPSRibbon::setupTexturedGlobalColor()
00989 {       
00991         CParticleSystem &ps = *(_Owner->getOwner());    
00992         if (_ColorScheme)
00993         {       
00994                 if (ps.getColorAttenuationScheme() && _ColorFading)
00995                 {
00996                         _Mat.texConstantColor(2, ps.getGlobalColor());
00997                 }
00998                 else
00999                 {
01000                         _Mat.texConstantColor(1, ps.getGlobalColor());
01001                 }                               
01002         }
01003         else // GLOBAL COLOR with / without fading
01004         {
01005                 if (ps.getColorAttenuationScheme())
01006                 {                       
01007                         NLMISC::CRGBA col;
01008                         col.modulateFromColor(ps.getGlobalColor(), _Color);
01009                         if (_ColorFading)
01010                         {                                                               
01011                                 _Mat.texConstantColor(1, col);                          
01012                         }
01013                         else // color attenuation, no fading : 
01014                         {                                                       
01015                                 _Mat.setColor(col);
01016                         }
01017                 }
01018                 else
01019                 {
01020                         if (_ColorFading)
01021                         {
01022                                 _Mat.texConstantColor(1, _Color);                               
01023                         }
01024                         else // constant color
01025                         {
01026                                 _Mat.setColor(_Color);
01027                         }
01028                 }
01029         }
01030 }
01031 
01032 
01033 //==========================================================================    
01034 void    CPSRibbon::setupGlobalColor()
01035 {
01036         if (_Tex != NULL) setupTexturedGlobalColor();
01037                 else setupUntexturedGlobalColor();
01038 }
01039 
01040 //==========================================================================    
01041 void CPSRibbon::setupTextureMatrix()
01042 {
01043         uint stage = (_ColorScheme != NULL && _ColorFading == true) ? 1 : 0;    
01044         if (_UFactor != 1.f || _VFactor != 1.f)
01045         {
01046                 _Mat.enableUserTexMat(stage);
01047                 CMatrix texMat;
01048                 texMat.setRot(_UFactor  * NLMISC::CVector::I,
01049                                           _VFactor  * NLMISC::CVector::J,
01050                                           NLMISC::CVector::K
01051                                          );
01052                 _Mat.setUserTexMat(stage, texMat);
01053         }
01054         else
01055         {
01056                 _Mat.enableUserTexMat(stage, false);
01057         }
01058         _Mat.enableUserTexMat(1 - stage, false);
01059 }
01060 
01061 //==========================================================================    
01063 void CPSRibbon::setShape(const CVector *shape, uint32 nbPointsInShape)
01064 {
01065         nlassert(nbPointsInShape >= 3);         
01066         _Shape.resize(nbPointsInShape);
01067         std::copy(shape, shape + nbPointsInShape, _Shape.begin());      
01068 }
01069 
01071 void CPSRibbon::getShape(CVector *shape) const
01072 {
01073         std::copy(_Shape.begin(), _Shape.end(), shape);
01074 }
01075 
01076 
01077 
01078 } // NL3D