# 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_look_at.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_look_at.h"
00029 #include "3d/particle_system.h"
00030 #include "3d/ps_macro.h"
00031 #include "3d/driver.h"
00032 
00033 namespace NL3D 
00034 {
00035 
00037 // CPSRibbonLookAt implementation //
00039 
00040 const float ZEpsilon = 10E-3f;
00041 const float NormEpsilon = 10E-8f;
00042 
00043 
00044 struct CVectInfo
00045 {
00046         NLMISC::CVector Interp;
00047         NLMISC::CVector Proj;   
00048 };
00049 typedef std::vector<CVectInfo> TRibbonVect; // a vector used for intermediate computations
00050 
00051 CPSRibbonLookAt::TVBMap         CPSRibbonLookAt::_VBMap;                        // index buffers with no color
00052 CPSRibbonLookAt::TVBMap         CPSRibbonLookAt::_ColoredVBMap;  // index buffer + colors       
00053 
00054 //=======================================================       
00055 CPSRibbonLookAt::CPSRibbonLookAt()
00056 {
00057 }
00058 
00059 //=======================================================       
00060 CPSRibbonLookAt::~CPSRibbonLookAt()
00061 {
00062 //      delete _DyingRibbons;
00063 }
00064 
00065 //=======================================================       
00066 void CPSRibbonLookAt::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00067 {
00071         sint ver = f.serialVersion(4);
00072         if (ver > 3)
00073         {
00074                 CPSRibbonBase::serial(f);
00075         }
00076         else
00077         {
00078                 CPSParticle::serial(f);
00079         }
00080         CPSColoredParticle::serialColorScheme(f);       
00081         CPSSizedParticle::serialSizeScheme(f);          
00082         serialMaterial(f);
00083         uint32 dummy = 0; /* _NbDyingRibbons */
00084         if (ver <= 3)
00085         {
00086                 f.serial(_SegDuration, _NbSegs, dummy /*_NbDyingRibbons*/);
00087         }
00088         ITexture *tex = NULL;
00089 
00090         if (ver > 2)
00091         {
00092                 f.serial(_Parametric);
00093         }
00094 
00095 
00096         if (!f.isReading())
00097         {               
00098                 tex = _Tex;
00099                 f.serialPolyPtr(tex);   
00100         }
00101         else
00102         {               
00103                 f.serialPolyPtr(tex);
00104                 setTexture(tex);
00105                 setTailNbSeg(_NbSegs); // force to build the vb
00106         }       
00107 }
00108 
00109 
00110 //=======================================================       
00111 void CPSRibbonLookAt::setTexture(CSmartPtr<ITexture> tex)
00112 {
00113         _Tex = tex;
00114         updateMatAndVbForColor();
00115 }
00116 
00117 
00118 //=======================================================       
00119 void CPSRibbonLookAt::step(TPSProcessPass pass, TAnimationTime ellapsedTime, TAnimationTime realEt)
00120 {       
00121         if (pass == PSMotion)
00122         {               
00123                 if (!_Parametric)
00124                 {
00125                         updateGlobals();
00126                 }
00127         }
00128         else
00129         if (
00130                 (pass == PSBlendRender && hasTransparentFaces())
00131                 || (pass == PSSolidRender && hasOpaqueFaces())
00132                 )
00133         {
00134                 uint32 step;
00135                 uint   numToProcess;
00136                 computeSrcStep(step, numToProcess);     
00137                 if (!numToProcess) return;
00138                 
00140                 CParticleSystem &ps = *(_Owner->getOwner());    
00141                 _Mat.setColor(ps.getGlobalColor());
00142                 
00147                 displayRibbons(numToProcess, step);
00148 
00149         }
00150         else 
00151         if (pass == PSToolRender) // edition mode only
00152         {                       
00153                 //showTool();
00154         }       
00155 }
00156 
00157 
00158 //=======================================================       
00159 void CPSRibbonLookAt::newElement(CPSLocated *emitterLocated, uint32 emitterIndex)
00160 {
00161         CPSRibbonBase::newElement(emitterLocated, emitterIndex);
00162         newColorElement(emitterLocated, emitterIndex);
00163         newSizeElement(emitterLocated, emitterIndex);   
00164 }
00165 
00166 
00167 //=======================================================       
00168 void CPSRibbonLookAt::deleteElement(uint32 index)
00169 {
00170         CPSRibbonBase::deleteElement(index);
00171         deleteColorElement(index);
00172         deleteSizeElement(index);       
00173 }
00174 
00175 
00176 //=======================================================       
00177 void CPSRibbonLookAt::resize(uint32 size)
00178 {
00179         nlassert(size < (1 << 16));
00180         CPSRibbonBase::resize(size);    
00181         resizeColor(size);
00182         resizeSize(size);                       
00183 }
00184 
00185 //=======================================================       
00186 void CPSRibbonLookAt::updateMatAndVbForColor(void)
00187 {
00188         _Mat.setTexture(0, _Tex);
00189 }
00190 
00191 //=======================================================       
00192 static inline void MakeProj(NLMISC::CVector &dest, const NLMISC::CVector &src)
00193 {               
00194         if (fabsf(src.y) > NormEpsilon * NormEpsilon)
00195         {
00196                 dest.x = src.x / src.y;
00197                 dest.z = src.z / src.y;
00198                 dest.y = src.y; 
00199         }       
00200 }
00201 
00202 static inline void BuildSlice(const NLMISC::CMatrix &mat, CVertexBuffer &vb, uint8 *currVert, uint32 vertexSize,
00203                                                           const NLMISC::CVector &I, 
00204                                                           const NLMISC::CVector &K, 
00205                                                           TRibbonVect::iterator  pos,
00206                                                           TRibbonVect::iterator  prev,
00207                                                           TRibbonVect::iterator  next,
00208                                                           float ribSize)
00210 {
00211         CHECK_VERTEX_BUFFER(vb, currVert);
00212         CHECK_VERTEX_BUFFER(vb, currVert);
00213         NLMISC::CVector tangent;
00214 
00215         float invTgNorm; // inverse of the' norm of the projected segment
00216         float tgNorm;
00217 
00218         if (prev->Proj.y > ZEpsilon && next->Proj.y > ZEpsilon) // the 2 points are in front of the camera
00219         {
00220                 tangent = next->Proj - prev->Proj;
00221                 tangent.y = 0;
00222                 tgNorm = tangent.norm();
00223                 if (fabs(tgNorm) > 10E-8)
00224                 {
00225                         invTgNorm = 1.f / tgNorm;
00226                 }
00227                 else
00228                 {
00229                         invTgNorm = 1.f;
00230                 }
00231                 // build orthogonals vectors to tangent
00232                 
00233                 *(NLMISC::CVector *) currVert = pos->Interp + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);                                            
00234                 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);                   
00235         }
00236         else if (prev->Proj.y > ZEpsilon) // second point cross the near plane
00237         {
00238                 // compute intersection point
00239                 NLMISC::CVector inter;
00240                 NLMISC::CVector tInter;         
00241                 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00242                 {
00243                                 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00244                                 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;                          
00245                                 MakeProj(tInter, mat * inter);
00246                 }
00247                 else // 
00248                 {
00249                         *(NLMISC::CVector *) currVert = pos->Interp;
00250                         *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;                     
00251                         return;
00252                 }
00253                 
00254                 tangent = tInter - prev->Proj;          
00255                 tangent.y = 0;
00256 
00257                 tgNorm = tangent.norm();
00258                 if (fabs(tgNorm > 10E-8))
00259                 {
00260                         invTgNorm = 1.f / tgNorm;                       
00261                 }
00262                 else
00263                 {
00264                         invTgNorm = 1.f;
00265                 }
00266                 // build orthogonals vectors to tangent
00267                 
00268                 *(NLMISC::CVector *) currVert = inter + ribSize *  invTgNorm * (tangent.x * K - tangent.z * I);         
00269                 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00270         }
00271         else if (next->Proj.y > ZEpsilon) // first point cross the near plane
00272         {
00273                         // compute intersection point
00274                 // compute intersection point
00275                 NLMISC::CVector inter;
00276                 NLMISC::CVector tInter;
00277                 if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00278                 {
00279                                 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00280                                 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;                          
00281                                 MakeProj(tInter, mat * inter);
00282                 }
00283                 else // 
00284                 {
00285                         *(NLMISC::CVector *) currVert = pos->Interp;
00286                         *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00287                         return;
00288                 }
00289                 
00290                 tangent = next->Proj - tInter;          
00291                 tangent.y = 0;
00292                 tgNorm = tangent.norm();
00293                 if (fabs(tgNorm > 10E-8))
00294                 {
00295                         invTgNorm = 1.f / tgNorm;                       
00296                 }
00297                 else
00298                 {
00299                         invTgNorm = 1.f;
00300                 }
00301                 // build orthogonals vectors to tangent
00302                 
00303                 *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);          
00304                 *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00305 
00306         }
00307         else // two points are not visible
00308         {
00309                 *(NLMISC::CVector *) currVert = pos->Interp;
00310                 *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00311         }
00312         
00313 }
00314 
00315 
00316 //==========================================================================    
00317 void CPSRibbonLookAt::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00318 {       
00319         if (!nbRibbons) return;
00320         nlassert(_Owner);       
00321         CPSRibbonBase::updateLOD();
00322         if (_UsedNbSegs < 2) return;
00323 
00324         const float date = _Owner->getOwner()->getSystemDate();
00325         uint8                                           *currVert;
00326 
00327         CVBnPB                                          &VBnPB = getVBnPB(); // get the appropriate vb (build it if needed)
00328         CVertexBuffer                           &VB = VBnPB.VB;
00329         CPrimitiveBlock                         &PB = VBnPB.PB;
00330 
00331         const uint32                            vertexSize  = VB.getVertexSize();
00332         uint                                            colorOffset=0;
00333         const uint32                            vertexSizeX2  = vertexSize << 1;
00334         const NLMISC::CVector       I = _Owner->computeI();
00335         const NLMISC::CVector       K = _Owner->computeK();
00336 
00337         
00338         CMatrix mat =  _Owner->isInSystemBasis() ? getViewMat()  *  getSysMat()
00339                                                                                                                                   : getViewMat();
00340         IDriver *drv = this->getDriver();
00341         setupDriverModelMatrix();
00342         drv->activeVertexBuffer(VB);
00343         _Owner->incrementNbDrawnParticles(nbRibbons); // for benchmark purpose  
00344         
00345         const uint numRibbonBatch = getNumRibbonsInVB(); // number of ribons to process at once
00346         
00347 
00348         static TRibbonVect                                 currRibbon;
00349         static std::vector<float>                  sizes;
00350         static std::vector<NLMISC::CRGBA>  colors;
00351 
00352 
00353         
00354         
00355 
00356         if (_UsedNbSegs == 0) return;
00357 
00358         currRibbon.resize(_UsedNbSegs + 1);
00359         sizes.resize(numRibbonBatch);
00360 
00361 
00363         CParticleSystem &ps = *(_Owner->getOwner());
00364         if (ps.getColorAttenuationScheme() != NULL)
00365         {               
00366                 CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());             
00367         }
00368         else
00369         {       
00370                 forceModulateConstantColor(false);
00371                 _Mat.setColor(ps.getGlobalColor());
00372         }
00373 
00374         if (_ColorScheme)
00375         {
00376                 colorOffset = VB.getColorOff();
00377                 colors.resize(numRibbonBatch);          
00378         }
00379         
00380         
00381         uint toProcess;
00382         uint ribbonIndex = 0; // index of the first ribbon in the batch being processed
00383         
00384         uint32 fpRibbonIndex = 0;
00385 
00386         do
00387         {
00388                 toProcess = std::min((uint) (nbRibbons - ribbonIndex) /* = left to do */, numRibbonBatch);
00389         
00390 
00392                 const float     *ptCurrSize;
00393                 uint32  ptCurrSizeIncrement;
00394                 if (_SizeScheme)
00395                 {                       
00396                         ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);                        
00397                         ptCurrSizeIncrement = 1;
00398                 }
00399                 else
00400                 {
00401                         ptCurrSize = &_ParticleSize;
00402                         ptCurrSizeIncrement = 0;
00403                 }
00404 
00406                 NLMISC::CRGBA   *ptCurrColor=0;
00407                 if (_ColorScheme)
00408                 {
00409                         colors.resize(nbRibbons);
00410                         ptCurrColor = (NLMISC::CRGBA *) _ColorScheme->make(this->_Owner, ribbonIndex, &colors[0], sizeof(NLMISC::CRGBA), toProcess, true, srcStep);                     
00411                 }               
00412                 
00413                 currVert = (uint8 *) VB.getVertexCoordPointer();
00414                 for (uint k = ribbonIndex; k < ribbonIndex + toProcess; ++k)
00415                 {                       
00416                         
00417                         TRibbonVect::iterator rIt = currRibbon.begin(), rItEnd = currRibbon.end(), rItEndMinusOne = rItEnd - 1;
00418 
00420                         // interpolate and project points //
00422                 
00423                                 if (!_Parametric)
00424                                 {
00425 
00427                                         // INCREMENTAL CASE //
00429 
00430                                         // the parent class has a method to get the ribbons positions
00431                                         computeRibbon((uint) (fpRibbonIndex >> 16), &rIt->Interp, sizeof(CVectInfo));                           
00432                                         do
00433                                         {                                       
00434                                                 MakeProj(rIt->Proj, mat * rIt->Interp); 
00435                                                 ++rIt;                          
00436                                         }
00437                                         while (rIt != rItEnd);                  
00438                                 }
00439                                 else
00440                                 {
00442                                         // PARAMETRIC  CASE //
00444                                         // we compute each pos thanks to the parametric curve                           
00445                                         _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
00446                                                                                          &rIt->Interp, sizeof(CVectInfo) );                             
00447                                         // project each position now
00448                                         do
00449                                         {                                       
00450                                                 MakeProj(rIt->Proj, mat * rIt->Interp); 
00451                                                 ++rIt;                          
00452                                         }
00453                                         while (rIt != rItEnd);                  
00454                                 }
00455 
00456                                 rIt = currRibbon.begin();
00457 
00458                 
00459                                 // setup colors
00460                                 if (_ColorScheme)
00461                                 {
00462                                         uint8 *currColVertex = currVert + colorOffset;
00463                                         uint colCount = (_UsedNbSegs + 1) << 1;
00464                                         do
00465                                         {
00466                                                 * (CRGBA *) currColVertex = *ptCurrColor;
00467                                                 currColVertex += vertexSize;
00468                                         }
00469                                         while (--colCount);
00470 
00471                                         ++ptCurrColor;                  
00472                                 }
00473 
00475                                 // deals with first point                               
00476                                 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt, rIt + 1, *ptCurrSize);                                
00477                                 currVert += vertexSizeX2;               
00478                                 ++rIt;
00479 
00480                                 
00481                                 // deals with other points                              
00482                                 for (;;) // we assume at least 2 segments, so we must have a middle point               
00483                                 {                                               
00484                                         // build 2 vertices with the right tangent. /* to project 2 */ is old projected point
00485                                         BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt - 1, rIt + 1, *ptCurrSize); 
00486                                         // next position                
00487                                         ++rIt;
00488                                         if (rIt == rItEndMinusOne) break;                                       
00489                                         // next vertex                  
00490                                         currVert += vertexSizeX2;               
00491                                 }
00492                                 currVert += vertexSizeX2;
00493                                 // last point.
00494                                 BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt , rIt - 1, rIt, *ptCurrSize);                                                                               
00495                                 ptCurrSize += ptCurrSizeIncrement;
00496                                 currVert += vertexSizeX2;
00497 
00498                                 fpRibbonIndex += srcStep;
00499                 }
00500 
00501                 PB.setNumTri((_UsedNbSegs << 1) * toProcess);
00502                 // display the result
00503                 drv->render(PB, _Mat);
00504                 ribbonIndex += toProcess;               
00505         }
00506         while (ribbonIndex != nbRibbons);
00507 }       
00508 
00509 //==========================================================================    
00510 bool CPSRibbonLookAt::hasTransparentFaces(void)
00511 {
00512         return getBlendingMode() != CPSMaterial::alphaTest ;
00513 }
00514 
00515 
00516 //==========================================================================    
00517 bool CPSRibbonLookAt::hasOpaqueFaces(void)
00518 {
00519         return !hasTransparentFaces();
00520 }
00521 
00522 //==========================================================================    
00523 uint32 CPSRibbonLookAt::getMaxNumFaces(void) const
00524 {
00525         nlassert(_Owner);
00526         return _Owner->getMaxSize() * _NbSegs * 2;      
00527 }
00528 
00529 
00530 
00531 //==========================================================================    
00532 CPSRibbonLookAt::CVBnPB &CPSRibbonLookAt::getVBnPB()
00533 {
00534         TVBMap &map = _ColorScheme ? _VBMap : _ColoredVBMap;    
00535         TVBMap::iterator it = map.find(_UsedNbSegs + 1);
00536         if (it != map.end())
00537         {
00538                 return it->second;
00539         }
00540         else    // must create this vb
00541         {
00542                 const uint numRibbonInVB = getNumRibbonsInVB();
00543                 CVBnPB &VBnPB = map[_UsedNbSegs + 1]; // make an entry
00544 
00546                 CVertexBuffer &vb = VBnPB.VB;
00547                 vb.setVertexFormat(CVertexBuffer::PositionFlag |
00548                                                    CVertexBuffer::TexCoord0Flag | 
00549                                                    (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00550                 vb.setNumVertices(2 * (_UsedNbSegs + 1) * numRibbonInVB );
00551 
00552                 // set the primitive block size
00553                 CPrimitiveBlock &pb = VBnPB.PB;
00554                 pb.setNumTri((_UsedNbSegs << 1) * numRibbonInVB);
00556                 uint vbIndex = 0;
00557                 uint pbIndex = 0; 
00558                 for (uint i = 0; i < numRibbonInVB; ++i)
00559                 {
00560                         for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
00561                         {                               
00562                                 vb.setTexCoord(vbIndex, 0, CUV((1.f - k / (float) _UsedNbSegs), 0)); 
00563                                 vb.setTexCoord(vbIndex + 1, 0, CUV((1.f - k / (float) _UsedNbSegs), 1)); 
00564                                 if (k != _UsedNbSegs)
00565                                 {
00567                                         pb.setTri(pbIndex ++, vbIndex + 1, vbIndex + 2, vbIndex);
00568                                         pb.setTri(pbIndex ++, vbIndex + 1, vbIndex + 3, vbIndex + 2);
00569                                 }
00570                                 vbIndex += 2;
00571                         }
00572                 }
00573                 return VBnPB;
00574         }
00575 }
00576 
00577 //==========================================================================    
00578 uint    CPSRibbonLookAt::getNumRibbonsInVB() const
00579 {
00581         const uint vertexInVB = 256;    
00582         return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
00583 }
00584 
00585 } // NL3D