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

Generated on Tue Mar 16 06:35:02 2004 for NeL by doxygen 1.3.6