ps_zone.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_zone.h"
00027 #include "nel/3d/vertex_buffer.h"
00028 #include "nel/3d/index_buffer.h"
00029 #include "nel/3d/material.h"
00030 #include "nel/3d/ps_util.h"
00031 #include "nel/3d/dru.h"
00032 #include "nel/3d/particle_system.h"
00033 #include "nel/misc/plane.h"
00034 
00035 // tmp
00036 
00037 #include "nel/3d/particle_system_model.h"
00038 
00039 #include <cmath>
00040 #include <limits>
00041 
00042 namespace NL3D {
00043 
00044 
00045 /*
00046  * Constructor
00047  */
00048 CPSZone::CPSZone() : _BounceFactor(1.f), _CollisionBehaviour(bounce)
00049 {
00050     NL_PS_FUNC(CPSZone_CPSZone)
00051 }
00052 
00053 void CPSZone::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00054 {
00055     NL_PS_FUNC(CPSZone_serial)
00056     f.serialVersion(1);
00057     CPSTargetLocatedBindable::serial(f);
00058     f.serialEnum(_CollisionBehaviour);
00059     f.serial(_BounceFactor);
00060     if (f.isReading())
00061     {
00062         for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00063         {
00064             // though this is not a force, this prevent parametric motion
00065             (*it)->addNonIntegrableForceRef();
00066         }
00067     }
00068 }
00069 
00073 void CPSZone::attachTarget(CPSLocated *ptr)
00074 {
00075     NL_PS_FUNC(CPSZone_attachTarget)
00076     CPSTargetLocatedBindable::attachTarget(ptr);
00077     ptr->queryCollisionInfo();
00078     ptr->addNonIntegrableForceRef();
00079 }
00080 
00081 
00082 
00083 
00084 
00086 void CPSZone::releaseTargetRsc(CPSLocated *target)
00087 {
00088     NL_PS_FUNC(CPSZone_releaseTargetRsc)
00089     // tell the target that we were using collision infos and that we won't use them anymore
00090     target->releaseCollisionInfo();
00091     target->releaseNonIntegrableForceRef();
00092 }
00093 
00094 
00095 
00096 void CPSZone::step(TPSProcessPass pass)
00097 {
00098     NL_PS_FUNC(CPSZone_step)
00099     // for zone, the PSCollision pass and the PSToolRenderPass are processed
00100     switch(pass)
00101     {
00102         case PSToolRender:
00103             show();
00104             break;
00105         default: break;
00106     }
00107 }
00108 
00109 
00110 // build a basis with K = the normal of the plane
00111 CMatrix CPSZonePlane::buildBasis(uint32 index) const
00112 {
00113     NL_PS_FUNC(CPSZonePlane_buildBasis)
00114     CMatrix m;
00115     m.setPos(_Owner->getPos()[index]);
00116     CPSUtil::buildSchmidtBasis(_Normal[index], m);
00117     return m;
00118 }
00119 
00120 
00123 /*void CPSZone::bounce(uint32 locatedIndex, const CVector &bouncePoint, const CVector &surfNormal, float elasticity, TAnimationTime ellapsedTime)
00124 {
00125     CVector &speed = _Owner->getSpeed()[locatedIndex];
00126     const CVector &pos   = _Owner->getPos()[locatedIndex];
00127     CVector &bounceVect = elasticity  * (speed - 2.0f * (speed * surfNormal) * surfNormal); // speed vector after collision
00128     // now check where the located will be after integration
00129     CVector d = bouncePoint - pos;
00130     TAnimationTime collideDelay = speed.norm() / d.norm();
00131     CVector finalPos = bouncePoint + (ellapsedTime - collideDelay) * bounceVect;
00132     // now, we must have pos + ellapsedTime * newSpeed = finalPos
00133     // newSpeed = alpha * (finalPos - pos)
00134     // so alpha = 1 / ellapsedTime
00135 
00136     speed = (1.0f / ellapsedTime) * (finalPos - pos);
00137 }*/
00138 
00139 
00140 void CPSZonePlane::show()
00141 {
00142     NL_PS_FUNC(CPSZonePlane_show)
00143     const float planeSize = 2.0f;
00144     setupDriverModelMatrix();
00145     IDriver *driver = getDriver();
00146     uint k  = 0;
00147     setupDriverModelMatrix();
00148     CPSLocated *loc;
00149     uint32 index;
00150     CPSLocatedBindable *lb;
00151     _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00152     for (TPSAttribVector::const_iterator it = _Owner->getPos().begin(); it != _Owner->getPos().end(); ++it, ++k)
00153     {
00154         const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
00155         CMatrix mat = buildBasis(k);
00156         CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00157         setupDriverModelMatrix();
00158         CDRU::drawLine(*it + (planeSize  + 3) * mat.getI() + planeSize * mat.getJ(),
00159                        *it - (planeSize + 3) * mat.getI() + planeSize * mat.getJ(),
00160                        col,
00161                        *driver);
00162 
00163         CDRU::drawLine(*it + (planeSize  + 3) * mat.getI() - planeSize * mat.getJ(),
00164                        *it - (planeSize + 3) * mat.getI() - planeSize * mat.getJ(),
00165                        col,
00166                        *driver);
00167 
00168         CDRU::drawLine(*it + planeSize  * mat.getI() + (planeSize + 3) * mat.getJ(),
00169                        *it + planeSize * mat.getI() - (planeSize + 3) * mat.getJ(),
00170                        col,
00171                        *driver);
00172         CDRU::drawLine(*it - planeSize  * mat.getI() + (planeSize + 3) * mat.getJ(),
00173                        *it - planeSize * mat.getI() - (planeSize + 3) * mat.getJ(),
00174                        col,
00175                        *driver);
00176     }
00177 }
00178 
00179 
00180 
00181 void CPSZonePlane::resize(uint32 size)
00182 {
00183     NL_PS_FUNC(CPSZonePlane_resize)
00184     nlassert(size < (1 << 16));
00185     _Normal.resize(size);
00186 }
00187 
00188 
00189 void CPSZonePlane::newElement(const CPSEmitterInfo &info)
00190 {
00191     NL_PS_FUNC(CPSZonePlane_newElement)
00192     nlassert(_Normal.getSize() != _Normal.getMaxSize());
00193     _Normal.insert(CVector(0, 0, 1));
00194 }
00195 
00196 
00197 void CPSZonePlane::deleteElement(uint32 index)
00198 {
00199     NL_PS_FUNC(CPSZonePlane_deleteElement)
00200     _Normal.remove(index);
00201 }
00202 
00203 
00204 void CPSZonePlane::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00205 {
00206     NL_PS_FUNC(CPSZonePlane_computeCollisions)
00207     MINI_TIMER(PSStatsZonePlane)
00208     // for each target, we must check whether they are going through the plane
00209     // if so they must bounce
00210     TPSAttribVector::const_iterator planePosIt, planePosEnd, normalIt;
00211     CPSCollisionInfo ci;
00212     // cycle through the planes
00213     planePosEnd = _Owner->getPos().end();
00214     for (planePosIt = _Owner->getPos().begin(), normalIt = _Normal.begin(); planePosIt != planePosEnd; ++planePosIt, ++normalIt)
00215     {
00216 
00217         // we must setup the plane in the good basis
00218         const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00219         const float epsilon = 0.5f * PSCollideEpsilon;
00220         NLMISC::CPlane p;
00221         p.make(m.mulVector(*normalIt), m * (*planePosIt));
00222         // deals with each particle
00223         const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00224         const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00225         const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00226         while (itPosBefore != itPosBeforeEnd)
00227         {
00228             float posSide = p * *itPosBefore;
00229             float negSide = p * *itPosAfter;
00230             if (posSide >= - epsilon && negSide <= epsilon)
00231             {
00232                 float alpha;
00233                 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00234                 {
00235                     alpha = posSide / (posSide - negSide);
00236                 }
00237                 else
00238                 {
00239                     alpha = 0.f;
00240                 }
00241                 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
00242                 ci.Dist = startEnd.norm();
00243                 // we translate the particle from an epsilon so that it won't get hooked to the plane
00244                 ci.NewPos = *itPosBefore  + startEnd + PSCollideEpsilon * p.getNormal();
00245                 const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00246                 ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00247                 ci.CollisionZone = this;
00248                 CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00249             }
00250             ++ itPosBefore;
00251             ++ itPosAfter;
00252         }
00253     }
00254 
00255 }
00256 
00257 void CPSZonePlane::setMatrix(uint32 index, const CMatrix &m)
00258 {
00259     NL_PS_FUNC(CPSZonePlane_setMatrix)
00260     nlassert(index < _Normal.getSize());
00261     _Normal[index] = m.getK();
00262     _Owner->getPos()[index] = m.getPos();
00263 }
00264 
00265 CMatrix CPSZonePlane::getMatrix(uint32 index) const
00266 {
00267     NL_PS_FUNC(CPSZonePlane_getMatrix)
00268     return buildBasis(index);
00269 }
00270 
00271 
00272 CVector CPSZonePlane::getNormal(uint32 index)
00273 {
00274     NL_PS_FUNC(CPSZonePlane_getNormal)
00275     return _Normal[index];
00276 }
00277 void CPSZonePlane::setNormal(uint32 index, CVector n)
00278 {
00279     NL_PS_FUNC(CPSZonePlane_setNormal)
00280     _Normal[index] = n;
00281 }
00282 
00283 
00284 
00285 
00286 void CPSZonePlane::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00287 {
00288     NL_PS_FUNC(CPSZonePlane_serial)
00289     f.serialVersion(1);
00290     CPSZone::serial(f);
00291     f.serial(_Normal);
00292 }
00293 
00294 
00295 
00297 // sphere implementation //
00299 
00300 void CPSZoneSphere::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00301 {
00302     NL_PS_FUNC(CPSZoneSphere_computeCollisions)
00303     MINI_TIMER(PSStatsZoneSphere)
00304     // for each target, we must check whether they are going through the plane
00305     // if so they must bounce
00306     TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00307     TPSAttribVector::const_iterator spherePosIt, spherePosEnd;
00308     CPSCollisionInfo ci;
00309     float rOut, rIn;
00310     // cycle through the spheres
00311     spherePosEnd = _Owner->getPos().end();
00312     for (spherePosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(); spherePosIt != spherePosEnd; ++spherePosIt, ++radiusIt)
00313     {
00314         // we must setup the sphere in the good basis
00315         const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00316         CVector center = m * *spherePosIt;
00317         // deals with each particle
00318         const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00319         const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00320         const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00321         while (itPosBefore != itPosBeforeEnd)
00322         {
00323             // check whether the located is going through the sphere
00324             // we don't use raytracing for now because it is too slow ...
00325             rOut = (*itPosBefore - center) * (*itPosBefore - center);
00326             // initial position outside the sphere ?
00327             if (rOut > radiusIt->R2)
00328             {
00329                 rIn = (*itPosAfter - center) * (*itPosAfter - center);
00330                 const CVector &pos = *itPosBefore;
00331                 const CVector &dest = *itPosAfter;
00332                 const CVector D = dest - pos;
00333                 // final position inside the sphere ?
00334                 if ( rIn <= radiusIt->R2)
00335                 {
00336                     // discriminant of the intersection equation
00337                     const float b = 2.f * (pos * D - D * center), a = D * D
00338                                 , c = (pos * pos) + (center * center) - 2.f * (pos * center) - radiusIt->R2;
00339                     float d = b * b - 4 * a * c;
00340                     if (d > 0.f)
00341                     {
00342                         d = sqrtf(d);
00343                         // roots of the equation, we take the smallest
00344                         const float r1 = .5f * (-b + 2.f * d) * a,
00345                                     r2 = .5f * (-b - 2.f * d) * a;
00346                         const float  r = std::min(r1, r2);
00347                         // collision point
00348                         const CVector C = pos  + r * D;
00349                         const float alpha = ((C - pos) * D) * a;
00350                         const CVector startEnd = alpha * (dest - pos);
00351                         CVector normal = C - center;
00352                         normal = normal * (1.f / radiusIt->R);
00353                         ci.Dist = startEnd.norm();
00354                         // we translate the particle from an epsilon so that it won't get hooked to the sphere
00355                         ci.NewPos = pos  + startEnd + PSCollideEpsilon * normal;
00356                         const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00357                         ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * normal) * normal);
00358                         ci.CollisionZone = this;
00359                         CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00360                     }
00361                 }
00362             }
00363             ++ itPosBefore;
00364             ++ itPosAfter;
00365         }
00366     }
00367 
00368 }
00369 
00370 
00371 
00372 void CPSZoneSphere::show()
00373 {
00374     NL_PS_FUNC(CPSZoneSphere_show)
00375 
00376     CPSLocated *loc;
00377     uint32 index;
00378     CPSLocatedBindable *lb;
00379     _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00380 
00381 
00382     TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00383     TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end();
00384     setupDriverModelMatrix();
00385     for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++k)
00386     {
00387         const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
00388         CPSUtil::displaySphere(*getDriver(), radiusIt->R, *posIt, 5, col);
00389     }
00390 }
00391 
00392 void CPSZoneSphere::setMatrix(uint32 index, const CMatrix &m)
00393 {
00394     NL_PS_FUNC(CPSZoneSphere_setMatrix)
00395     nlassert(index < _Radius.getSize());
00396 
00397     // compute new pos
00398     _Owner->getPos()[index] = m.getPos();
00399 
00400 }
00401 
00402 
00403 CMatrix CPSZoneSphere::getMatrix(uint32 index) const
00404 {
00405     NL_PS_FUNC(CPSZoneSphere_getMatrix)
00406     nlassert(index < _Radius.getSize());
00407     CMatrix m;
00408     m.identity();
00409     m.translate(_Owner->getPos()[index]);
00410     return m;
00411 }
00412 
00413 void CPSZoneSphere::setScale(uint32 k, float scale)
00414 {
00415     NL_PS_FUNC(CPSZoneSphere_setScale)
00416     _Radius[k].R = scale;
00417     _Radius[k].R2 = scale * scale;
00418 }
00419 CVector CPSZoneSphere::getScale(uint32 k) const
00420 {
00421     NL_PS_FUNC(CPSZoneSphere_getScale)
00422     return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00423 }
00424 
00425 
00426 void CPSZoneSphere::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00427 {
00428     NL_PS_FUNC(CPSZoneSphere_serial)
00429     f.serialVersion(1);
00430     CPSZone::serial(f);
00431     f.serial(_Radius);
00432 }
00433 
00434 void CPSZoneSphere::resize(uint32 size)
00435 {
00436     NL_PS_FUNC(CPSZoneSphere_resize)
00437     nlassert(size < (1 << 16));
00438     _Radius.resize(size);
00439 }
00440 
00441 void CPSZoneSphere::newElement(const CPSEmitterInfo &info)
00442 {
00443     NL_PS_FUNC(CPSZoneSphere_newElement)
00444     CRadiusPair rp;
00445     rp.R = rp.R2 = 1.f;
00446     nlassert(_Radius.getSize() != _Radius.getMaxSize());
00447     _Radius.insert(rp);
00448 }
00449 
00450 void CPSZoneSphere::deleteElement(uint32 index)
00451 {
00452     NL_PS_FUNC(CPSZoneSphere_deleteElement)
00453     _Radius.remove(index);
00454 }
00455 
00456 
00458 // CPSZoneDisc implementation //
00460 void CPSZoneDisc::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00461 {
00462     NL_PS_FUNC(CPSZoneDisc_computeCollisions)
00463     MINI_TIMER(PSStatsZoneDisc)
00464     // for each target, we must check whether they are going through the disc
00465     // if so they must bounce
00466     TPSAttribVector::const_iterator discPosIt, discPosEnd, normalIt;
00467     TPSAttribRadiusPair::const_iterator radiusIt;
00468     CPSCollisionInfo ci;
00469     // the square of radius at the hit point
00470     float hitRadius2;
00471     // alpha is the ratio that gives the percent of endPos - startPos that hit the disc
00472     CVector center;
00473     // cycle through the disc
00474     discPosEnd = _Owner->getPos().end();
00475     for (discPosIt = _Owner->getPos().begin(), radiusIt = _Radius.begin(), normalIt = _Normal.begin(); discPosIt != discPosEnd; ++discPosIt, ++normalIt, ++radiusIt)
00476     {
00477         // we must setup the disc in the good basis
00478         const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00479         NLMISC::CPlane p;
00480         center = m * (*discPosIt);
00481         p.make(m.mulVector(*normalIt), center);
00482 
00483         // deals with each particle
00484         const float epsilon = 0.5f * PSCollideEpsilon;
00485 
00486         // deals with each particle
00487         const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00488         const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00489         const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00490         while (itPosBefore != itPosBeforeEnd)
00491         {
00492             float posSide = p * *itPosBefore;
00493             float negSide = p * *itPosAfter;
00494             if (posSide >= - epsilon && negSide <= epsilon)
00495             {
00496                 float alpha;
00497                 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
00498                 {
00499                     alpha = posSide / (posSide - negSide);
00500                 }
00501                 else
00502                 {
00503                     alpha = 0.f;
00504                 }
00505                 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
00506                 ci.Dist = startEnd.norm();
00507                 // we translate the particle from an epsilon so that it won't get hooked to the disc
00508                 ci.NewPos = *itPosBefore  + startEnd + PSCollideEpsilon * p.getNormal();
00509                 // now, check the collision pos against radius
00510                 hitRadius2 = (ci.NewPos - center) * (ci.NewPos - center);
00511                 if (hitRadius2 < radiusIt->R2) // check collision against disc
00512                 {
00513                     const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00514                     ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
00515                     ci.CollisionZone = this;
00516                     CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00517                 }
00518 
00519             }
00520             ++ itPosBefore;
00521             ++ itPosAfter;
00522         }
00523     }
00524 }
00525 
00526 void CPSZoneDisc::show()
00527 {
00528     NL_PS_FUNC(CPSZoneDisc_show)
00529     TPSAttribRadiusPair::const_iterator radiusIt = _Radius.begin();
00530     TPSAttribVector::const_iterator posIt = _Owner->getPos().begin(), endPosIt = _Owner->getPos().end()
00531                                     , normalIt = _Normal.begin();
00532     setupDriverModelMatrix();
00533     CMatrix mat;
00534 
00535 
00536 
00537     CPSLocated *loc;
00538     uint32 index;
00539     CPSLocatedBindable *lb;
00540     _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
00541 
00542 
00543 
00544     for (uint k = 0; posIt != endPosIt; ++posIt, ++radiusIt, ++normalIt, ++k)
00545     {
00546         const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
00547         CPSUtil::buildSchmidtBasis(*normalIt, mat);
00548         CPSUtil::displayDisc(*getDriver(), radiusIt->R, *posIt, mat, 32, col);
00549 
00550         mat.setPos(*posIt);
00551         CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
00552         setupDriverModelMatrix();
00553     }
00554 }
00555 
00556 
00557 
00558 
00559 
00560 
00561 void CPSZoneDisc::setMatrix(uint32 index, const CMatrix &m)
00562 {
00563     NL_PS_FUNC(CPSZoneDisc_setMatrix)
00564     nlassert(index < _Radius.getSize());
00565     // compute new pos
00566     _Owner->getPos()[index] = m.getPos();
00567     // compute new normal
00568     _Normal[index] = m.getK();
00569 }
00570 
00571 CMatrix CPSZoneDisc::getMatrix(uint32 index) const
00572 {
00573     NL_PS_FUNC(CPSZoneDisc_getMatrix)
00574     CMatrix m, b;
00575     m.translate(_Owner->getPos()[index]);
00576     CPSUtil::buildSchmidtBasis(_Normal[index], b);
00577     m = m * b;
00578     return m;
00579 }
00580 
00581 CVector CPSZoneDisc::getNormal(uint32 index)
00582 {
00583     NL_PS_FUNC(CPSZoneDisc_getNormal)
00584     return _Normal[index];
00585 }
00586 void CPSZoneDisc::setNormal(uint32 index, CVector n)
00587 {
00588     NL_PS_FUNC(CPSZoneDisc_setNormal)
00589     _Normal[index] = n;
00590 }
00591 
00592 void CPSZoneDisc::setScale(uint32 k, float scale)
00593 {
00594     NL_PS_FUNC(CPSZoneDisc_setScale)
00595     _Radius[k].R = scale;
00596     _Radius[k].R2 = scale * scale;
00597 }
00598 
00599 CVector CPSZoneDisc::getScale(uint32 k) const
00600 {
00601     NL_PS_FUNC(CPSZoneDisc_getScale)
00602     return CVector(_Radius[k].R, _Radius[k].R, _Radius[k].R);
00603 }
00604 
00605 
00606 void CPSZoneDisc::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00607 {
00608     NL_PS_FUNC(CPSZoneDisc_serial)
00609     f.serialVersion(1);
00610     CPSZone::serial(f);
00611     f.serial(_Normal);
00612     f.serial(_Radius);
00613 }
00614 
00615 void CPSZoneDisc::resize(uint32 size)
00616 {
00617     NL_PS_FUNC(CPSZoneDisc_resize)
00618     nlassert(size < (1 << 16));
00619     _Radius.resize(size);
00620     _Normal.resize(size);
00621 }
00622 
00623 void CPSZoneDisc::newElement(const CPSEmitterInfo &info)
00624 {
00625     NL_PS_FUNC(CPSZoneDisc_newElement)
00626     CRadiusPair rp;
00627     rp.R = rp.R2 = 1.f;
00628     nlassert(_Radius.getSize() != _Radius.getMaxSize());
00629     _Radius.insert(rp);
00630     _Normal.insert(CVector::K);
00631 }
00632 
00633 void CPSZoneDisc::deleteElement(uint32 index)
00634 {
00635     NL_PS_FUNC(CPSZoneDisc_deleteElement)
00636     _Radius.remove(index);
00637     _Normal.remove(index);
00638 }
00639 
00640 
00642 // CPSZoneCylinder implementation //
00644 
00645 
00646 /*
00647 void CPSZoneCylinder::performMotion(TAnimationTime ellapsedTime)
00648 {
00649     TPSAttribVector::const_iterator dimIt = _Dim.begin();
00650     CPSAttrib<CPlaneBasis>::const_iterator basisIt = _Basis.begin();
00651     TPSAttribVector::const_iterator cylinderPosIt, cylinderPosEnd, targetPosIt, targetPosEnd;
00652     CVector dest;
00653     CPSCollisionInfo ci;
00654     CVector startEnd;
00655     uint32 k;
00656     const TPSAttribVector *speedAttr;
00657 
00658 
00659 
00660     for (TTargetCont::iterator it = _Targets.begin(); it != _Targets.end(); ++it)
00661     {
00662 
00663         speedAttr = &((*it)->getSpeed());
00664 
00665 
00666         // cycle through the cylinders
00667 
00668         cylinderPosEnd = _Owner->getPos().end();
00669         for (cylinderPosIt = _Owner->getPos().begin(); cylinderPosIt != cylinderPosEnd
00670                 ; ++cylinderPosIt, ++dimIt, ++basisIt)
00671         {
00672 
00673             // we must setup the cylinder in the good basis
00674 
00675             const CMatrix &m = CPSLocated::getConversionMatrix(*it, this->_Owner);
00676 
00677 
00678 
00679             // compute the new center pos
00680             CVector center = m * *cylinderPosIt;
00681 
00682             // compute a basis for the cylinder
00683             CVector I = m.mulVector(basisIt->X);
00684             CVector J = m.mulVector(basisIt->Y);
00685             CVector K = m.mulVector(basisIt->X ^ basisIt->Y);
00686 
00687 
00688             // the pos projected (and scale) over the plane basis of the cylinder, the pos minus the center
00689             CVector projectedPos, tPos;
00690 
00691             // the same, but with the final position
00692             CVector destProjectedPos, destTPos;
00693 
00694 
00695             // deals with each particle
00696             targetPosEnd = (*it)->getPos().end();
00697             for (targetPosIt = (*it)->getPos().begin(), k = 0; targetPosIt != targetPosEnd; ++targetPosIt, ++k)
00698             {
00699                 const CVector &speed = (*speedAttr)[k];
00700                 const CVector &pos = *targetPosIt;
00701 
00702 
00703 
00704                 // check whether current pos was outside the cylinder
00705 
00706 
00707                 tPos = pos - center;
00708                 projectedPos = (1 / dimIt->x) * (I * tPos) * I + (1 / dimIt->y)  * (J * tPos) * J;
00709 
00710                 if (!
00711                      (
00712                         ((tPos * K) < dimIt->z)
00713                         && ((tPos * K) > -dimIt->z)
00714                         && (projectedPos * projectedPos < 1.f)
00715                      )
00716                    )
00717                 {
00718                     dest = pos + ellapsedTime *  speed;
00719                     destTPos = dest - center;
00720                     destProjectedPos = (1.f / dimIt->x) * (I * tPos) * I + (1.f / dimIt->y)  * (J * tPos) * J;
00721 
00722                     // test whether the new position is inside the cylinder
00723 
00724 
00725                     if (!
00726                          (
00727                             ((destTPos * K) < dimIt->z)
00728                             && ((destTPos * K) > -dimIt->z)
00729                             && (destProjectedPos * destProjectedPos < 1.f)
00730                          )
00731                        )
00732                     {
00733                         // now, detect the closest hit point (the smallest alpha, with alpha, the percent of the move vector
00734                         // to reach the hit point)
00735 
00736                         const float epsilon = 10E-6f;
00737 
00738                         float alphaTop, alphaBottom, alphaCyl;
00739 
00740                         const float denum = (dest - pos) * K;
00741 
00742                         // top plane
00743 
00744                         if (fabs(denum) < epsilon)
00745                         {
00746                             alphaTop = (dimIt->z - (tPos * K)) / denum;
00747                             if (alphaTop < 0.f) alphaTop = 1.f;
00748                         }
00749                         else
00750                         {
00751                             alphaTop = 1.f;
00752                         }
00753 
00754                         // bottom plane
00755 
00756                         if (fabs(denum) < epsilon)
00757                         {
00758                             alphaBottom = (- dimIt->z - (tPos * K)) / denum;
00759                             if (alphaBottom < 0.f) alphaBottom = 1.f;
00760                         }
00761                         else
00762                         {
00763                             alphaBottom = 1.f;
00764                         }
00765 
00766                         // cylinder
00767 
00768                         //expressed the src and dest positions in the cylinder basis
00769 
00770                         const float ox = tPos * I, oy = tPos * J, dx = (destTPos - tPos) * I, dy = (destTPos - tPos) * J;
00771 
00772                         // coefficients of the equation : a * alpha ^ 2 + b * alpha + c = 0
00773                         const float a = (dx * dx) / (dimIt->x * dimIt->x)
00774                                   + (dy * dy) / (dimIt->y * dimIt->y);
00775                         const float b = 2.f * (ox * dx) / (dimIt->x * dimIt->x)
00776                                   + (oy * dy) / (dimIt->y * dimIt->y);
00777                         const float c = ox * ox + oy * oy - 1;
00778 
00779                         // discriminant
00780                         const float delta = b * b - 4.f * a * c;
00781 
00782                         if (delta < epsilon)
00783                         {
00784                             alphaCyl = 1.f;
00785                         }
00786                         else
00787                         {
00788                             const float deltaRoot = sqrtf(delta);
00789                             const float r1 = (- b - deltaRoot) / (2.f / a);
00790                             const float r2 = (- b - deltaRoot) / (2.f / a);
00791 
00792                             if (r1 < 0.f) alphaCyl = r2;
00793                                 else if (r2 < 0.f) alphaCyl = r1;
00794                                     else alphaCyl = r1 < r2 ? r1 : r2;
00795                         }
00796 
00797 
00798                         // now, choose the minimum positive dist
00799 
00800                         if (alphaTop < alphaBottom && alphaTop < alphaCyl)
00801                         {
00802                             // collision with the top plane
00803                             CVector startEnd = alphaTop * (dest - pos);
00804                             ci.newPos = pos + startEnd + PSCollideEpsilon * K;
00805                             ci.dist = startEnd.norm();
00806                             ci.newSpeed = (-2.f * (speed * K)) * K + speed;
00807                             ci.collisionZone = this;
00808 
00809                             (*it)->collisionUpdate(ci, k);
00810                         }
00811                         else
00812                             if (alphaBottom < alphaCyl)
00813                             {
00814                                 // collision with the bottom plane
00815                                 CVector startEnd = alphaBottom * (dest - pos);
00816                                 ci.newPos = pos + startEnd - PSCollideEpsilon * K;
00817                                 ci.dist = startEnd.norm();
00818                                 ci.newSpeed = (-2.f * (speed * K)) * K + speed;
00819                                 ci.collisionZone = this;
00820 
00821 
00822                                 (*it)->collisionUpdate(ci, k);
00823                             }
00824                             else
00825                             {
00826                                 // collision with the cylinder
00827 
00828                                 CVector startEnd = alphaCyl * (dest - pos);
00829 
00830                                 // normal at the hit point. It is the gradient of the implicit equation x^2 / a^2 + y^2 / b^2 - R^ 2=  0
00831                                 // so we got unormalized n =  (2 x / a ^ 2, 2 y / b ^ 2, 0) in the basis of the cylinder
00832                                 // As we'll normalize it, we don't need  the 2 factor
00833 
00834                                 float px = ox + alphaCyl * dx;
00835                                 float py = oy + alphaCyl * dy;
00836 
00837                                 CVector normal = px / (dimIt->x * dimIt->x) * I + py / (dimIt->y * dimIt->y) * J;
00838                                 normal.normalize();
00839 
00840                                 ci.newPos = pos + startEnd - PSCollideEpsilon * normal;
00841                                 ci.dist = startEnd.norm();
00842                                 ci.newSpeed = (-2.f * (speed * normal)) * normal + speed;
00843                                 ci.collisionZone = this;
00844 
00845                                 (*it)->collisionUpdate(ci, k);
00846                             }
00847 
00848                     }
00849                 }
00850             }
00851         }
00852     }
00853 }
00854 */
00855 
00856 
00857 void CPSZoneCylinder::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
00858 {
00859     NL_PS_FUNC(CPSZoneCylinder_computeCollisions)
00860     MINI_TIMER(PSStatsZoneCylinder)
00861     TPSAttribVector::const_iterator dimIt;
00862     CPSAttrib<CPlaneBasis>::const_iterator basisIt;
00863     TPSAttribVector::const_iterator cylinderPosIt, cylinderPosEnd;
00864     CPSCollisionInfo ci;
00865     // cycle through the cylinders
00866     cylinderPosEnd = _Owner->getPos().end();
00867     for (cylinderPosIt = _Owner->getPos().begin(), basisIt = _Basis.begin(),  dimIt = _Dim.begin(); cylinderPosIt != cylinderPosEnd; ++cylinderPosIt, ++dimIt, ++basisIt)
00868     {
00869         // we must setup the cylinder in the good basis
00870         const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
00871         // compute the new center pos
00872         CVector center = m * *cylinderPosIt;
00873         // compute a basis for the cylinder
00874         CVector I = m.mulVector(basisIt->X);
00875         CVector J = m.mulVector(basisIt->Y);
00876         CVector K = m.mulVector(basisIt->X ^ basisIt->Y);
00877         // the pos projected (and scale) over the plane basis of the cylinder, the pos minus the center
00878         CVector projectedPos, tPos;
00879         // the same, but with the final position
00880         CVector destProjectedPos, destTPos;
00881         // deals with each particle
00882         // deals with each particle
00883         const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
00884         const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
00885         const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
00886         while (itPosBefore != itPosBeforeEnd)
00887         {
00888             const CVector &pos = *itPosBefore;
00889             // check whether current pos was outside the cylinder
00890             tPos = pos - center;
00891             projectedPos = (1 / dimIt->x) * (I * tPos) * I + (1 / dimIt->y)  * (J * tPos) * J;
00892             if (!
00893                  (
00894                     ((tPos * K) < dimIt->z)
00895                     && ((tPos * K) > -dimIt->z)
00896                     && (projectedPos * projectedPos < 1.f)
00897                  )
00898                )
00899             {
00900                 const CVector &dest = *itPosAfter;
00901                 destTPos = dest - center;
00902                 destProjectedPos = (1.f / dimIt->x) * (I * destTPos) * I + (1.f / dimIt->y)  * (J * destTPos) * J;
00903                 // test whether the new position is inside the cylinder
00904                 if (
00905                     ((destTPos * K) < dimIt->z)
00906                     && ((destTPos * K) > -dimIt->z)
00907                     && (destProjectedPos * destProjectedPos < 1.f)
00908                    )
00909                 {
00910                     // now, detect the closest hit point (the smallest alpha, with alpha, the percent of the move vector
00911                     // to reach the hit point)
00912                     const float epsilon = 10E-3f;
00913                     float alphaTop, alphaBottom, alphaCyl;
00914                     const float denum = (dest - pos) * K;
00915                     // top plane
00916                     if (fabs(denum) < epsilon)
00917                     {
00918                         alphaTop = (dimIt->z - (tPos * K)) / denum;
00919                         if (alphaTop < 0.f) alphaTop = 1.f;
00920                     }
00921                     else
00922                     {
00923                         alphaTop = 1.f;
00924                     }
00925                     // bottom plane
00926                     if (fabs(denum) < epsilon)
00927                     {
00928                         alphaBottom = (- dimIt->z - (tPos * K)) / denum;
00929                         if (alphaBottom < 0.f) alphaBottom = 1.f;
00930                     }
00931                     else
00932                     {
00933                         alphaBottom = 1.f;
00934                     }
00935                     // cylinder
00936                     //expressed the src and dest positions in the cylinder basis
00937                     const float ox = tPos * I, oy = tPos * J, dx = (destTPos - tPos) * I, dy = (destTPos - tPos) * J;
00938                     // coefficients of the equation : a * alpha ^ 2 + b * alpha + c = 0
00939                     const float a = (dx * dx) / (dimIt->x * dimIt->x)
00940                               + (dy * dy) / (dimIt->y * dimIt->y);
00941                     const float b = 2.f * ((ox * dx) / (dimIt->x * dimIt->x)
00942                               + (oy * dy) / (dimIt->y * dimIt->y));
00943                     const float c = (ox * ox) / (dimIt->x * dimIt->x) + (oy * oy) / (dimIt->y * dimIt->y)  - 1;
00944                     // discriminant
00945                     const float delta = b * b - 4.f * a * c;
00946 
00947                     if (delta < epsilon)
00948                     {
00949                         alphaCyl = 1.f;
00950                     }
00951                     else
00952                     {
00953                         const float deltaRoot = sqrtf(delta);
00954                         const float r1 = (- b + 2.f * deltaRoot) / (2.f * a);
00955                         const float r2 = (- b - 2.f * deltaRoot) / (2.f * a);
00956 
00957                         if (r1 < 0.f) alphaCyl = r2;
00958                             else if (r2 < 0.f) alphaCyl = r1;
00959                                 else alphaCyl = r1 < r2 ? r1 : r2;
00960 
00961                                 if (alphaCyl < 0.f) alphaCyl = 1.f;
00962                     }
00963                     const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
00964                     // now, choose the minimum positive dist
00965                     if (alphaTop < alphaBottom && alphaTop < alphaCyl)
00966                     {
00967                         // collision with the top plane
00968                         CVector startEnd = alphaTop * (dest - pos);
00969                         ci.NewPos = pos + startEnd + PSCollideEpsilon * K;
00970                         ci.Dist = startEnd.norm();
00971                         ci.NewSpeed = (-2.f * (speed * K)) * K + speed;
00972                         ci.CollisionZone = this;
00973                         CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00974                     }
00975                     else
00976                         if (alphaBottom < alphaCyl)
00977                         {
00978                             // collision with the bottom plane
00979                             CVector startEnd = alphaBottom * (dest - pos);
00980                             ci.NewPos = pos + startEnd - PSCollideEpsilon * K;
00981                             ci.Dist = startEnd.norm();
00982                             ci.NewSpeed = (-2.f * (speed * K)) * K + speed;
00983                             ci.CollisionZone = this;
00984                             CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
00985                         }
00986                         else
00987                         {
00988                             // collision with the cylinder
00989                             CVector startEnd = alphaCyl * (dest - pos);
00990                             // normal at the hit point. It is the gradient of the implicit equation x^2 / a^2 + y^2 / b^2 - R^ 2=  0
00991                             // so we got unormalized n =  (2 x / a ^ 2, 2 y / b ^ 2, 0) in the basis of the cylinder
00992                             // As we'll normalize it, we don't need  the 2 factor
00993                             float px = ox + alphaCyl * dx;
00994                             float py = oy + alphaCyl * dy;
00995                             CVector normal = px / (dimIt->x * dimIt->x) * I + py / (dimIt->y * dimIt->y) * J;
00996                             normal.normalize();
00997                             ci.NewPos = pos + startEnd + PSCollideEpsilon * normal;
00998                             ci.Dist = startEnd.norm();
00999                             ci.NewSpeed = (-2.f * (speed * normal)) * normal + speed;
01000                             ci.CollisionZone = this;
01001                             CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
01002                         }
01003 
01004                 }
01005             }
01006             ++ itPosBefore;
01007             ++ itPosAfter;
01008         }
01009     }
01010 }
01011 
01012 void CPSZoneCylinder::show()
01013 {
01014     NL_PS_FUNC(CPSZoneCylinder_show)
01015     TPSAttribVector::const_iterator dimIt = _Dim.begin()
01016                                     ,posIt = _Owner->getPos().begin()
01017                                     , endPosIt = _Owner->getPos().end();
01018 
01019     CPSAttrib<CPlaneBasis>::const_iterator basisIt = _Basis.begin();
01020 
01021     setupDriverModelMatrix();
01022     CMatrix mat;
01023 
01024 
01025 
01026     CPSLocated *loc;
01027     uint32 index;
01028     CPSLocatedBindable *lb;
01029     _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01030 
01031 
01032     for (uint32 k = 0; posIt != endPosIt; ++posIt, ++dimIt, ++basisIt, ++k)
01033     {
01034         mat.setRot(basisIt->X, basisIt->Y, basisIt->X ^ basisIt->Y);
01035         mat.setPos(CVector::Null);
01036 
01037         const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
01038 
01039 
01040         CPSUtil::displayCylinder(*getDriver(), *posIt, mat, *dimIt, 32, col);
01041 
01042         mat.setPos(*posIt);
01043         CPSUtil::displayBasis(getDriver() ,getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01044         setupDriverModelMatrix();
01045 
01046     }
01047 }
01048 
01049 
01050 
01051 void CPSZoneCylinder::setMatrix(uint32 index, const CMatrix &m)
01052 {
01053     NL_PS_FUNC(CPSZoneCylinder_setMatrix)
01054     // transform the basis
01055     _Basis[index].X = m.getI();
01056     _Basis[index].Y = m.getJ();
01057 
01058     // compute new pos
01059     _Owner->getPos()[index] = m.getPos();
01060 
01061 
01062 }
01063 
01064 
01065 
01066 CMatrix CPSZoneCylinder::getMatrix(uint32 index) const
01067 {
01068     NL_PS_FUNC(CPSZoneCylinder_getMatrix)
01069     CMatrix m;
01070     m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^_Basis[index].Y);
01071     m.setPos(_Owner->getPos()[index]);
01072     return m;
01073 }
01074 
01075 
01076 void CPSZoneCylinder::setScale(uint32 k, float scale)
01077 {
01078     NL_PS_FUNC(CPSZoneCylinder_setScale)
01079     _Dim[k] = CVector(scale, scale, scale);
01080 }
01081 
01082 CVector CPSZoneCylinder::getScale(uint32 k) const
01083 {
01084     NL_PS_FUNC(CPSZoneCylinder_getScale)
01085     return _Dim[k];
01086 }
01087 
01088 void CPSZoneCylinder::setScale(uint32 index, const CVector &s)
01089 {
01090     NL_PS_FUNC(CPSZoneCylinder_setScale)
01091     _Dim[index] = s;
01092 }
01093 
01094 
01095 void CPSZoneCylinder::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01096 {
01097     NL_PS_FUNC(CPSZoneCylinder_serial)
01098     f.serialVersion(1);
01099     CPSZone::serial(f);
01100     f.serial(_Basis);
01101     f.serial(_Dim);
01102 }
01103 
01104 
01105 
01106 void CPSZoneCylinder::resize(uint32 size)
01107 {
01108     NL_PS_FUNC(CPSZoneCylinder_resize)
01109     nlassert(size < (1 << 16));
01110     _Basis.resize(size);
01111     _Dim.resize(size);
01112 }
01113 
01114 void CPSZoneCylinder::newElement(const CPSEmitterInfo &info)
01115 {
01116     NL_PS_FUNC(CPSZoneCylinder_newElement)
01117     _Basis.insert(CPlaneBasis(CVector::K));
01118     _Dim.insert(CVector(1, 1, 1));
01119 }
01120 
01121 void CPSZoneCylinder::deleteElement(uint32 index)
01122 {
01123     NL_PS_FUNC(CPSZoneCylinder_deleteElement)
01124     _Basis.remove(index);
01125     _Dim.remove(index);
01126 }
01127 
01128 
01130 //  implementation of CPSZoneRectangle      //
01132 
01133 void CPSZoneRectangle::computeCollisions(CPSLocated &target, uint firstInstanceIndex, const NLMISC::CVector *posBefore, const NLMISC::CVector *posAfter)
01134 {
01135     NL_PS_FUNC(CPSZoneRectangle_computeCollisions)
01136     MINI_TIMER(PSStatsZoneRectangle)
01137     // for each target, we must check whether they are going through the rectangle
01138     // if so they must bounce
01139     TPSAttribVector::const_iterator rectanglePosIt, rectanglePosEnd;
01140     CPSAttrib<CPlaneBasis>::const_iterator basisIt;
01141     TPSAttribFloat::const_iterator widthIt, heightIt;
01142     CPSCollisionInfo ci;
01143     // alpha is the ratio that gives the percent of endPos - startPos that hit the rectangle
01144     basisIt = _Basis.begin();
01145     heightIt = _Height.begin();
01146     widthIt = _Width.begin();
01147     rectanglePosEnd = _Owner->getPos().end();
01148     for (rectanglePosIt = _Owner->getPos().begin(); rectanglePosIt != rectanglePosEnd; ++rectanglePosIt, ++basisIt, ++widthIt, ++heightIt)
01149     {
01150         // we must setup the rectangle in the good basis
01151         const CMatrix &m = CPSLocated::getConversionMatrix(&target, this->_Owner);
01152         NLMISC::CPlane p;
01153         CVector center = m * (*rectanglePosIt);
01154         const CVector X = m.mulVector(basisIt->X);
01155         const CVector Y = m.mulVector(basisIt->Y);
01156         p.make(X ^ Y, center);
01157         // deals with each particle
01158         const float epsilon = 0.5f * PSCollideEpsilon;
01159         const NLMISC::CVector *itPosBefore = posBefore + firstInstanceIndex;
01160         const NLMISC::CVector *itPosBeforeEnd = posBefore + target.getSize();
01161         const NLMISC::CVector *itPosAfter = posAfter + firstInstanceIndex;
01162         while (itPosBefore != itPosBeforeEnd)
01163         {
01164             float posSide = p * *itPosBefore;
01165             float negSide = p * *itPosAfter;
01166             if (posSide >= - epsilon && negSide <= epsilon)
01167             {
01168                 float alpha;
01169                 if (fabsf(posSide - negSide) > std::numeric_limits<float>::min())
01170                 {
01171                     alpha = posSide / (posSide - negSide);
01172                 }
01173                 else
01174                 {
01175                     alpha = 0.f;
01176                 }
01177                 CVector startEnd = alpha * (*itPosAfter - *itPosBefore);
01178                 ci.Dist = startEnd.norm();
01179                 // we translate the particle from an epsilon so that it won't get hooked to the rectangle
01180                 ci.NewPos = *itPosBefore + startEnd;
01181                 // tmp
01182                 if ( fabs( (ci.NewPos - center) * X ) < *widthIt && fabs( (ci.NewPos - center) * Y ) < *heightIt) // check collision against rectangle
01183                 {
01184                     ci.NewPos += PSCollideEpsilon * p.getNormal();
01185                     const CVector &speed = target.getSpeed()[itPosBefore - posBefore];
01186                     ci.NewSpeed = _BounceFactor * (speed - 2.0f * (speed * p.getNormal()) * p.getNormal());
01187                     ci.CollisionZone = this;
01188                     CPSLocated::_Collisions[itPosBefore - posBefore].update(ci);
01189                 }
01190             }
01191             ++ itPosBefore;
01192             ++ itPosAfter;
01193         }
01194     }
01195 
01196 }
01197 
01198 
01199 void CPSZoneRectangle::show()
01200 {
01201     NL_PS_FUNC(CPSZoneRectangle_show)
01202     nlassert(_Owner);
01203     const uint size = _Owner->getSize();
01204     if (!size) return;
01205     setupDriverModelMatrix();
01206     CMatrix mat;
01207 
01208     CPSLocated *loc;
01209     uint32 index;
01210     CPSLocatedBindable *lb;
01211     _Owner->getOwner()->getCurrentEditedElement(loc, index, lb);
01212 
01213     for (uint k = 0; k < size; ++k)
01214     {
01215         const CVector &I = _Basis[k].X;
01216         const CVector &J = _Basis[k].Y;
01217         mat.setRot(I, J , I ^J);
01218         mat.setPos(_Owner->getPos()[k]);
01219         CPSUtil::displayBasis(getDriver(), getLocalToWorldMatrix(), mat, 1.f, *getFontGenerator(), *getFontManager());
01220         setupDriverModelMatrix();
01221 
01222         const CRGBA col = ((lb == NULL || this == lb) && loc == _Owner && index == k  ? CRGBA::Red : CRGBA(127, 127, 127));
01223 
01224 
01225 
01226         const CVector &pos = _Owner->getPos()[k];
01227         CPSUtil::display3DQuad(*getDriver(), pos + I * _Width[k] + J * _Height[k]
01228                                            , pos + I * _Width[k] - J * _Height[k]
01229                                            , pos - I * _Width[k] - J * _Height[k]
01230                                            , pos - I * _Width[k] + J * _Height[k], col);
01231     }
01232 }
01233 
01234 void CPSZoneRectangle::setMatrix(uint32 index, const CMatrix &m)
01235 {
01236     NL_PS_FUNC(CPSZoneRectangle_setMatrix)
01237     nlassert(_Owner);
01238 
01239     _Owner->getPos()[index] = m.getPos();
01240     _Basis[index].X = m.getI();
01241     _Basis[index].Y = m.getJ();
01242 }
01243 
01244 
01245 CMatrix CPSZoneRectangle::getMatrix(uint32 index) const
01246 {
01247     NL_PS_FUNC(CPSZoneRectangle_getMatrix)
01248     nlassert(_Owner);
01249     CMatrix m;
01250     m.setRot(_Basis[index].X, _Basis[index].Y, _Basis[index].X ^ _Basis[index].Y);
01251     m.setPos(_Owner->getPos()[index]);
01252     return m;
01253 }
01254 
01255 void CPSZoneRectangle::setScale(uint32 index, float scale)
01256 {
01257     NL_PS_FUNC(CPSZoneRectangle_setScale)
01258     _Width[index] = scale;
01259     _Height[index] = scale;
01260 }
01261 void CPSZoneRectangle::setScale(uint32 index, const CVector &s)
01262 {
01263     NL_PS_FUNC(CPSZoneRectangle_setScale)
01264     _Width[index] = s.x;
01265     _Height[index] = s.y;
01266 }
01267 CVector CPSZoneRectangle::getScale(uint32 index) const
01268 {
01269     NL_PS_FUNC(CPSZoneRectangle_getScale)
01270     return CVector(_Width[index], _Height[index], 1.f);
01271 }
01272 
01273 
01274 
01275 void CPSZoneRectangle::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
01276 {
01277     NL_PS_FUNC(CPSZoneRectangle_IStream )
01278     f.serialVersion(1);
01279     CPSZone::serial(f);
01280     f.serial(_Basis);
01281     f.serial(_Width);
01282     f.serial(_Height);
01283 }
01284 
01285 
01286 void CPSZoneRectangle::resize(uint32 size)
01287 {
01288     NL_PS_FUNC(CPSZoneRectangle_resize)
01289     nlassert(size < (1 << 16));
01290     _Basis.resize(size);
01291     _Width.resize(size);
01292     _Height.resize(size);
01293 }
01294 
01295 void CPSZoneRectangle::newElement(const CPSEmitterInfo &info)
01296 {
01297     NL_PS_FUNC(CPSZoneRectangle_newElement)
01298     _Basis.insert(CPlaneBasis(CVector::K));
01299     _Width.insert(1.f);
01300     _Height.insert(1.f);
01301 }
01302 
01303 void CPSZoneRectangle::deleteElement(uint32 index)
01304 {
01305     NL_PS_FUNC(CPSZoneRectangle_deleteElement)
01306     _Basis.remove(index);
01307     _Width.remove(index);
01308     _Height.remove(index);
01309 }
01310 
01311 
01312 
01313 } // NL3D

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