ps_ribbon_look_at.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/3d/ps_ribbon_look_at.h"
00027 #include "nel/3d/particle_system.h"
00028 #include "nel/3d/ps_macro.h"
00029 #include "nel/3d/driver.h"
00030 
00031 namespace NL3D
00032 {
00033 
00035 // CPSRibbonLookAt implementation //
00037 
00038 const float ZEpsilon = 10E-3f;
00039 const float NormEpsilon = 10E-8f;
00040 
00041 
00042 struct CVectInfo
00043 {
00044     NLMISC::CVector Interp;
00045     NLMISC::CVector Proj;
00046 };
00047 typedef std::vector<CVectInfo> TRibbonVect; // a vector used for intermediate computations
00048 
00049 CPSRibbonLookAt::TVBMap     CPSRibbonLookAt::_VBMap;            // index buffers with no color
00050 CPSRibbonLookAt::TVBMap     CPSRibbonLookAt::_ColoredVBMap;  // index buffer + colors
00051 
00052 //=======================================================
00053 CPSRibbonLookAt::CPSRibbonLookAt()
00054 {
00055     NL_PS_FUNC(CPSRibbonLookAt_CPSRibbonLookAt)
00056 }
00057 
00058 //=======================================================
00059 CPSRibbonLookAt::~CPSRibbonLookAt()
00060 {
00061     NL_PS_FUNC(CPSRibbonLookAt_CPSRibbonLookAtDtor)
00062 //  delete _DyingRibbons;
00063 }
00064 
00065 //=======================================================
00066 void CPSRibbonLookAt::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00067 {
00068     NL_PS_FUNC(CPSRibbonLookAt_serial)
00072     sint ver = f.serialVersion(4);
00073     if (ver > 3)
00074     {
00075         CPSRibbonBase::serial(f);
00076     }
00077     else
00078     {
00079         CPSParticle::serial(f);
00080     }
00081     CPSColoredParticle::serialColorScheme(f);
00082     CPSSizedParticle::serialSizeScheme(f);
00083     serialMaterial(f);
00084     uint32 dummy = 0; /* _NbDyingRibbons */
00085     if (ver <= 3)
00086     {
00087         f.serial(_SegDuration, _NbSegs, dummy /*_NbDyingRibbons*/);
00088     }
00089     ITexture *tex = NULL;
00090 
00091     if (ver > 2)
00092     {
00093         f.serial(_Parametric);
00094     }
00095 
00096 
00097     if (!f.isReading())
00098     {
00099         tex = _Tex;
00100         f.serialPolyPtr(tex);
00101     }
00102     else
00103     {
00104         f.serialPolyPtr(tex);
00105         setTexture(tex);
00106         _Tex = tex;
00107         if (_Tex)
00108         {
00109             _Tex->setWrapS(ITexture::Clamp);
00110             _Tex->setWrapT(ITexture::Clamp);
00111         }
00112         setTailNbSeg(_NbSegs); // force to build the vb
00113     }
00114 }
00115 
00116 
00117 //=======================================================
00118 void CPSRibbonLookAt::setTexture(CSmartPtr<ITexture> tex)
00119 {
00120     NL_PS_FUNC(CPSRibbonLookAt_setTexture)
00121     _Tex = tex;
00122     if (_Tex)
00123     {
00124         _Tex->setWrapS(ITexture::Clamp);
00125         _Tex->setWrapT(ITexture::Clamp);
00126     }
00127     updateMatAndVbForColor();
00128 }
00129 
00130 
00131 //=======================================================
00132 void CPSRibbonLookAt::step(TPSProcessPass pass)
00133 {
00134     NL_PS_FUNC(CPSRibbonLookAt_step)
00135     if (pass == PSMotion)
00136     {
00137         if (!_Parametric)
00138         {
00139             updateGlobals();
00140         }
00141     }
00142     else
00143     if (
00144         (pass == PSBlendRender && hasTransparentFaces())
00145         || (pass == PSSolidRender && hasOpaqueFaces())
00146         )
00147     {
00148         uint32 step;
00149         uint   numToProcess;
00150         computeSrcStep(step, numToProcess);
00151         if (!numToProcess) return;
00152 
00154         CParticleSystem &ps = *(_Owner->getOwner());
00155         if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00156         {
00157             _Mat.setColor(ps.getGlobalColorLighted());
00158         }
00159         else
00160         {
00161             _Mat.setColor(ps.getGlobalColor());
00162         }
00166         displayRibbons(numToProcess, step);
00167     }
00168     else
00169     if (pass == PSToolRender) // edition mode only
00170     {
00171         //showTool();
00172     }
00173 }
00174 
00175 
00176 //=======================================================
00177 void CPSRibbonLookAt::newElement(const CPSEmitterInfo &info)
00178 {
00179     NL_PS_FUNC(CPSRibbonLookAt_newElement)
00180     CPSRibbonBase::newElement(info);
00181     newColorElement(info);
00182     newSizeElement(info);
00183 }
00184 
00185 
00186 //=======================================================
00187 void CPSRibbonLookAt::deleteElement(uint32 index)
00188 {
00189     NL_PS_FUNC(CPSRibbonLookAt_deleteElement)
00190     CPSRibbonBase::deleteElement(index);
00191     deleteColorElement(index);
00192     deleteSizeElement(index);
00193 }
00194 
00195 
00196 //=======================================================
00197 void CPSRibbonLookAt::resize(uint32 size)
00198 {
00199     NL_PS_FUNC(CPSRibbonLookAt_resize)
00200     nlassert(size < (1 << 16));
00201     CPSRibbonBase::resize(size);
00202     resizeColor(size);
00203     resizeSize(size);
00204 }
00205 
00206 //=======================================================
00207 void CPSRibbonLookAt::updateMatAndVbForColor(void)
00208 {
00209     NL_PS_FUNC(CPSRibbonLookAt_updateMatAndVbForColor)
00210     _Mat.setTexture(0, _Tex);
00211     _Mat.setDoubleSided(true);
00212 }
00213 
00214 //=======================================================
00215 static inline void MakeProj(NLMISC::CVector &dest, const NLMISC::CVector &src)
00216 {
00217     NL_PS_FUNC(MakeProj)
00218     if (fabsf(src.y) > NormEpsilon * NormEpsilon)
00219     {
00220         dest.x = src.x / src.y;
00221         dest.z = src.z / src.y;
00222         dest.y = src.y;
00223     }
00224 }
00225 
00226 static inline void BuildSlice(const NLMISC::CMatrix &mat, CVertexBuffer &vb, uint8 *currVert, uint32 vertexSize,
00227                               const NLMISC::CVector &I,
00228                               const NLMISC::CVector &K,
00229                               TRibbonVect::iterator  pos,
00230                               TRibbonVect::iterator  prev,
00231                               TRibbonVect::iterator  next,
00232                               float ribSize)
00234 {
00235     NL_PS_FUNC(BuildSlice)
00236     CHECK_VERTEX_BUFFER(vb, currVert);
00237     CHECK_VERTEX_BUFFER(vb, currVert);
00238     NLMISC::CVector tangent;
00239 
00240     float invTgNorm; // inverse of the' norm of the projected segment
00241     float tgNorm;
00242 
00243     if (prev->Proj.y > ZEpsilon && next->Proj.y > ZEpsilon) // the 2 points are in front of the camera
00244     {
00245         tangent = next->Proj - prev->Proj;
00246         tangent.y = 0;
00247         tgNorm = tangent.norm();
00248         if (fabs(tgNorm) > 10E-8)
00249         {
00250             invTgNorm = 1.f / tgNorm;
00251         }
00252         else
00253         {
00254             invTgNorm = 1.f;
00255         }
00256         // build orthogonals vectors to tangent
00257         *(NLMISC::CVector *) currVert = pos->Interp + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00258         *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00259     }
00260     else if (prev->Proj.y > ZEpsilon) // second point cross the near plane
00261     {
00262         // compute intersection point
00263         NLMISC::CVector inter;
00264         NLMISC::CVector tInter = CVector::Null;
00265         if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00266         {
00267                 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00268                 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00269                 MakeProj(tInter, mat * inter);
00270         }
00271         else //
00272         {
00273             *(NLMISC::CVector *) currVert = pos->Interp;
00274             *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00275             return;
00276         }
00277 
00278         tangent = tInter - prev->Proj;
00279         tangent.y = 0;
00280 
00281         tgNorm = tangent.norm();
00282         if (fabs(tgNorm) > 10E-8)
00283         {
00284             invTgNorm = 1.f / tgNorm;
00285         }
00286         else
00287         {
00288             invTgNorm = 1.f;
00289         }
00290         // build orthogonals vectors to tangent
00291 
00292         *(NLMISC::CVector *) currVert = inter + ribSize *  invTgNorm * (tangent.x * K - tangent.z * I);
00293         *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00294     }
00295     else if (next->Proj.y > ZEpsilon) // first point cross the near plane
00296     {
00297         // compute intersection point
00298         NLMISC::CVector inter;
00299         NLMISC::CVector tInter = NLMISC::CVector::Null;
00300         if (fabsf(prev->Proj.y - next->Proj.y) > NormEpsilon)
00301         {
00302                 float lambda = (next->Proj.y - ZEpsilon) / (next->Proj.y - prev->Proj.y);
00303                 inter = lambda * prev->Interp + (1.f - lambda) * next->Interp;
00304                 MakeProj(tInter, mat * inter);
00305         }
00306         else //
00307         {
00308             *(NLMISC::CVector *) currVert = pos->Interp;
00309             *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00310             return;
00311         }
00312 
00313         tangent = next->Proj - tInter;
00314         tangent.y = 0;
00315         tgNorm = tangent.norm();
00316         if (fabs(tgNorm) > 10E-8)
00317         {
00318             invTgNorm = 1.f / tgNorm;
00319         }
00320         else
00321         {
00322             invTgNorm = 1.f;
00323         }
00324         // build orthogonals vectors to tangent
00325 
00326         *(NLMISC::CVector *) currVert = inter + ribSize * invTgNorm * (tangent.x * K - tangent.z * I);
00327         *(NLMISC::CVector *) (currVert + vertexSize) = inter + ribSize * invTgNorm * (- tangent.x * K + tangent.z * I);
00328 
00329     }
00330     else // two points are not visible
00331     {
00332         *(NLMISC::CVector *) currVert = pos->Interp;
00333         *(NLMISC::CVector *) (currVert + vertexSize) = pos->Interp;
00334     }
00335 
00336 }
00337 
00338 
00339 //==========================================================================
00340 void CPSRibbonLookAt::displayRibbons(uint32 nbRibbons, uint32 srcStep)
00341 {
00342 //  if (!FilterPS[6]) return;
00343     NL_PS_FUNC(CPSRibbonLookAt_displayRibbons)
00344     if (!nbRibbons) return;
00345     nlassert(_Owner);
00346     CPSRibbonBase::updateLOD();
00347     if (_UsedNbSegs < 2) return;
00348     const float date = _Owner->getOwner()->getSystemDate();
00349     uint8                       *currVert;
00350     CVBnPB                      &VBnPB = getVBnPB(); // get the appropriate vb (build it if needed)
00351     CVertexBuffer               &VB = VBnPB.VB;
00352     CIndexBuffer                &PB = VBnPB.PB;
00353     const uint32                vertexSize  = VB.getVertexSize();
00354     uint                        colorOffset=0;
00355     const uint32                vertexSizeX2  = vertexSize << 1;
00356     const NLMISC::CVector       I = _Owner->computeI();
00357     const NLMISC::CVector       K = _Owner->computeK();
00358     const NLMISC::CMatrix &localToWorldMatrix = getLocalToWorldTrailMatrix();
00359     const NLMISC::CMatrix &mat =  getViewMat() * localToWorldMatrix;
00360     IDriver *drv = this->getDriver();
00361     #ifdef NL_DEBUG
00362         nlassert(drv);
00363     #endif
00364     drv->setupModelMatrix(localToWorldMatrix);
00365     _Owner->incrementNbDrawnParticles(nbRibbons); // for benchmark purpose
00366     const uint numRibbonBatch = getNumRibbonsInVB(); // number of ribbons to process at once
00367     static TRibbonVect                 currRibbon;
00368     static std::vector<float>          sizes;
00369     static std::vector<NLMISC::CRGBA>  colors;
00370 
00371     if (_UsedNbSegs == 0) return;
00372 
00373     currRibbon.resize(_UsedNbSegs + 1);
00374     sizes.resize(numRibbonBatch);
00375 
00376 
00378     CParticleSystem &ps = *(_Owner->getOwner());
00379     if (ps.getForceGlobalColorLightingFlag() || usesGlobalColorLighting())
00380     {
00381         CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColorLighted());
00382     }
00383     else
00384     if (ps.getColorAttenuationScheme() != NULL || ps.isUserColorUsed())
00385     {
00386         CPSMaterial::forceModulateConstantColor(true, ps.getGlobalColor());
00387     }
00388     else
00389     {
00390         forceModulateConstantColor(false);
00391         _Mat.setColor(ps.getGlobalColor());
00392     }
00393 
00394     if (_ColorScheme)
00395     {
00396         colorOffset = VB.getColorOff();
00397         colors.resize(numRibbonBatch);
00398     }
00399 
00400 
00401 
00402     uint toProcess;
00403     uint ribbonIndex = 0; // index of the first ribbon in the batch being processed
00404     uint32 fpRibbonIndex = 0;
00405     if (_ColorScheme)
00406     {
00407         _ColorScheme->setColorType(drv->getVertexColorFormat());
00408     }
00409     do
00410     {
00411         toProcess = std::min((uint) (nbRibbons - ribbonIndex) /* = left to do */, numRibbonBatch);
00413         const float *ptCurrSize;
00414         uint32  ptCurrSizeIncrement;
00415         if (_SizeScheme)
00416         {
00417             ptCurrSize = (float *) _SizeScheme->make(this->_Owner, ribbonIndex, &sizes[0], sizeof(float), toProcess, true, srcStep);
00418             ptCurrSizeIncrement = 1;
00419         }
00420         else
00421         {
00422             ptCurrSize = &_ParticleSize;
00423             ptCurrSizeIncrement = 0;
00424         }
00425 
00426 
00428         NLMISC::CRGBA   *ptCurrColor=0;
00429         if (_ColorScheme)
00430         {
00431             colors.resize(nbRibbons);
00432             ptCurrColor = (NLMISC::CRGBA *) _ColorScheme->make(this->_Owner, ribbonIndex, &colors[0], sizeof(NLMISC::CRGBA), toProcess, true, srcStep);
00433         }
00434         VB.setNumVertices(2 * (_UsedNbSegs + 1) * toProcess);
00435         {
00436             CVertexBufferReadWrite vba;
00437             VB.lock (vba);
00438             currVert = (uint8 *) vba.getVertexCoordPointer();
00439             for (uint k = ribbonIndex; k < ribbonIndex + toProcess; ++k)
00440             {
00441 
00442                 TRibbonVect::iterator rIt = currRibbon.begin(), rItEnd = currRibbon.end(), rItEndMinusOne = rItEnd - 1;
00443 
00445                 // interpolate and project points //
00447 
00448                     if (!_Parametric)
00449                     {
00450 
00452                         // INCREMENTAL CASE //
00454 
00455                         // the parent class has a method to get the ribbons positions
00456                         computeRibbon((uint) (fpRibbonIndex >> 16), &rIt->Interp, sizeof(CVectInfo));
00457                         do
00458                         {
00459                             MakeProj(rIt->Proj, mat * rIt->Interp);
00460                             ++rIt;
00461                         }
00462                         while (rIt != rItEnd);
00463                     }
00464                     else
00465                     {
00467                         // PARAMETRIC  CASE //
00469                         // we compute each pos thanks to the parametric curve
00470                         _Owner->integrateSingle(date - _UsedSegDuration * (_UsedNbSegs + 1), _UsedSegDuration, _UsedNbSegs + 1, (uint) (fpRibbonIndex >> 16),
00471                                                  &rIt->Interp, sizeof(CVectInfo) );
00472                         // project each position now
00473                         do
00474                         {
00475                             MakeProj(rIt->Proj, mat * rIt->Interp);
00476                             ++rIt;
00477                         }
00478                         while (rIt != rItEnd);
00479                     }
00480 
00481                     rIt = currRibbon.begin();
00482 
00483 
00484                     // setup colors
00485                     if (_ColorScheme)
00486                     {
00487                         uint8 *currColVertex = currVert + colorOffset;
00488                         uint colCount = (_UsedNbSegs + 1) << 1;
00489                         do
00490                         {
00491                             * (CRGBA *) currColVertex = *ptCurrColor;
00492                             currColVertex += vertexSize;
00493                         }
00494                         while (--colCount);
00495 
00496                         ++ptCurrColor;
00497                     }
00498 
00500                     // deals with first point
00501                     BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt, rIt + 1, *ptCurrSize);
00502                     currVert += vertexSizeX2;
00503                     ++rIt;
00504 
00505 
00506                     // deals with other points
00507                     for (;;) // we assume at least 2 segments, so we must have a middle point
00508                     {
00509                         // build 2 vertices with the right tangent. /* to project 2 */ is old projected point
00510                         BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt, rIt - 1, rIt + 1, *ptCurrSize);
00511                         // next position
00512                         ++rIt;
00513                         if (rIt == rItEndMinusOne) break;
00514                         // next vertex
00515                         currVert += vertexSizeX2;
00516                     }
00517                     currVert += vertexSizeX2;
00518                     // last point.
00519                     BuildSlice(mat, VB, currVert, vertexSize, I, K, rIt , rIt - 1, rIt, *ptCurrSize);
00520                     ptCurrSize += ptCurrSizeIncrement;
00521                     currVert += vertexSizeX2;
00522 
00523                     fpRibbonIndex += srcStep;
00524 
00525             }
00526         }
00527         PB.setNumIndexes((_UsedNbSegs << 1) * toProcess * 3);
00528         drv->activeVertexBuffer(VB);
00529         // display the result
00530         drv->activeIndexBuffer (PB);
00531         drv->renderTriangles (_Mat, 0, PB.getNumIndexes()/3);
00532         ribbonIndex += toProcess;
00533     }
00534     while (ribbonIndex != nbRibbons);
00535 }
00536 
00537 //==========================================================================
00538 bool CPSRibbonLookAt::hasTransparentFaces(void)
00539 {
00540     NL_PS_FUNC(CPSRibbonLookAt_hasTransparentFaces)
00541     return getBlendingMode() != CPSMaterial::alphaTest ;
00542 }
00543 
00544 
00545 //==========================================================================
00546 bool CPSRibbonLookAt::hasOpaqueFaces(void)
00547 {
00548     NL_PS_FUNC(CPSRibbonLookAt_hasOpaqueFaces)
00549     return !hasTransparentFaces();
00550 }
00551 
00552 //==========================================================================
00553 uint32 CPSRibbonLookAt::getNumWantedTris() const
00554 {
00555     NL_PS_FUNC(CPSRibbonLookAt_getNumWantedTris)
00556     nlassert(_Owner);
00557     //return _Owner->getMaxSize() * _NbSegs * 2;
00558     return _Owner->getSize() * _NbSegs * 2;
00559 }
00560 
00561 
00562 
00563 //==========================================================================
00564 CPSRibbonLookAt::CVBnPB &CPSRibbonLookAt::getVBnPB()
00565 {
00566     NL_PS_FUNC(CPSRibbonLookAt_getVBnPB)
00567     TVBMap &map = _ColorScheme ? _VBMap : _ColoredVBMap;
00568     TVBMap::iterator it = map.find(_UsedNbSegs + 1);
00569     if (it != map.end())
00570     {
00571         return it->second;
00572     }
00573     else    // must create this vb
00574     {
00575         const uint numRibbonInVB = getNumRibbonsInVB();
00576         CVBnPB &VBnPB = map[_UsedNbSegs + 1]; // make an entry
00577 
00579         CVertexBuffer &vb = VBnPB.VB;
00580         vb.setVertexFormat(CVertexBuffer::PositionFlag |
00581                            CVertexBuffer::TexCoord0Flag |
00582                            (_ColorScheme ? CVertexBuffer::PrimaryColorFlag : 0));
00583         vb.setNumVertices(2 * (_UsedNbSegs + 1) * numRibbonInVB );
00584         vb.setPreferredMemory(CVertexBuffer::AGPVolatile, true);
00585         CVertexBufferReadWrite vba;
00586         vb.lock (vba);
00587 
00588         // set the primitive block size
00589         CIndexBuffer &pb = VBnPB.PB;
00590         pb.setFormat(NL_DEFAULT_INDEX_BUFFER_FORMAT);
00591         pb.setNumIndexes((_UsedNbSegs << 1) * numRibbonInVB * 3);
00592         CIndexBufferReadWrite iba;
00593         pb.lock (iba);
00595         uint vbIndex = 0;
00596         uint pbIndex = 0;
00597         for (uint i = 0; i < numRibbonInVB; ++i)
00598         {
00599             for (uint k = 0; k < (_UsedNbSegs + 1); ++k)
00600             {
00601                 vba.setTexCoord(vbIndex, 0, CUV((1.f - k / (float) _UsedNbSegs), 0)); 
00602                 vba.setTexCoord(vbIndex + 1, 0, CUV((1.f - k / (float) _UsedNbSegs), 1)); 
00603                 if (k != _UsedNbSegs)
00604                 {
00606                     iba.setTri(pbIndex, vbIndex + 1, vbIndex + 2, vbIndex);
00607                     iba.setTri(pbIndex+3, vbIndex + 1, vbIndex + 3, vbIndex + 2);
00608                     pbIndex+=6;
00609                 }
00610                 vbIndex += 2;
00611             }
00612         }
00613         return VBnPB;
00614     }
00615 }
00616 
00617 //==========================================================================
00618 uint    CPSRibbonLookAt::getNumRibbonsInVB() const
00619 {
00620     NL_PS_FUNC(CPSRibbonLookAt_getNumRibbonsInVB)
00622     const uint vertexInVB = 256;
00623     return std::max(1u, (uint) (vertexInVB / (_UsedNbSegs + 1)));
00624 }
00625 
00626 //==========================================================================
00627 void CPSRibbonLookAt::enumTexs(std::vector<NLMISC::CSmartPtr<ITexture> > &dest, IDriver &drv)
00628 {
00629     NL_PS_FUNC(CPSRibbonLookAt_enumTexs)
00630     if (_Tex)
00631     {
00632         dest.push_back(_Tex);
00633         _Tex->getShareName();
00634     }
00635 }
00636 
00637 
00638 } // NL3D

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