# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

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