# 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  

water_height_map.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000, 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 "water_height_map.h"
00029 #include "nel/misc/common.h"
00030 #include "nel/misc/debug.h"
00031 #include "nel/misc/vector_2f.h"
00032 #include <algorithm>
00033 #include <math.h>
00034 
00035 
00036 
00037 namespace NL3D
00038 {
00039 
00040 //===========================================================================================
00041 
00042 CWaterHeightMap::CWaterHeightMap() : Date(-1),
00043                                                                          _WavesEnabled(false),
00044                                                                          _Damping(0.97f),
00045                                                                          _FilterWeight(4),
00046                                                                          _UnitSize(0.6f),
00047                                                                          _WaveIntensity(0),
00048                                                                          _WavePeriod(0),
00049                                                                          _WaveImpulsionRadius(3),
00050                                                                          _BorderWaves(true),
00051                                                                          _EmitEllapsedTime(0),
00052                                                                          _PropagateEllapsedTime(0),
00053                                                                          _PropagationTime(0.10f),
00054                                                                          _X(0),
00055                                                                          _Y(0),
00056                                                                          _NewX(0),
00057                                                                          _NewY(0),
00058                                                                          _CurrMap(0),
00059                                                                          _Size(0)
00060 {               
00061 }
00062 
00063 
00064 //===========================================================================================
00065 
00066 void    CWaterHeightMap::setPropagationTime(float time)
00067 {
00068         _PropagationTime = time;
00069         _PropagateEllapsedTime = 0;
00070         for (uint k = 0; k < NumWaterMap; ++k)
00071         {       
00072                 clearArea(k, 0, 0, _Size << 1, _Size << 1);
00073         }
00074 }
00075 
00076 //===========================================================================================
00077 
00078 void CWaterHeightMap::updateUserPos()
00079 {
00080         const sint x = _NewX;
00081         const sint y = _NewY;
00082 
00083         nlassert(_Size != 0);
00084         if ((uint) x == _X && (uint) y == _Y) return;
00085         if ((uint) abs(x - _X) < _Size && (uint) abs(y - _Y) < _Size) // are there common pixels with the previous location?
00086         {
00087                 // compute zone
00088         
00089                 sint XDivSize;
00090                 if ((sint) _X >= 0) XDivSize = (sint) _X / (sint) _Size;
00091                 else XDivSize = ((sint) (_X + 1) / (sint) _Size) - 1;
00092 
00093                 sint YDivSize;
00094                 if ((sint) _Y >= 0) YDivSize = (sint) _Y / (sint) _Size;
00095                 else YDivSize = ((sint) (_Y + 1) / (sint) _Size) - 1;
00096 
00097                 sint xDivSize;
00098                 if (x >= 0) xDivSize = (sint) x / (sint) _Size;
00099                 else xDivSize = ((sint) (x + 1) / (sint) _Size) - 1;
00100 
00101                 sint yDivSize;
00102                 if (y >= 0) yDivSize = (sint) y / (sint) _Size;
00103                 else yDivSize = ((sint) (y + 1) / (sint) _Size) - 1;
00104 
00105                 // different zone -> must decal datas
00106                 if (xDivSize != XDivSize || yDivSize != YDivSize)
00107                 {
00108                         sint left   = std::max(x, (sint) _X);
00109                         sint top    = std::max(y, (sint) _Y);
00110                         sint right  = std::min(x + (sint) _Size, (sint) (_X + _Size));
00111                         sint bottom = std::min(y + (sint) _Size, (sint) (_Y + _Size));
00112                         sint offsetX, offsetY;
00113                         if (xDivSize != XDivSize) 
00114                         {
00115                                 offsetX = xDivSize < XDivSize ?  _Size : -(sint)_Size;
00116                         }
00117                         else
00118                         {
00119                                 offsetX = 0;
00120                         }
00121 
00122                         if (yDivSize != YDivSize) 
00123                         {
00124                                 offsetY = yDivSize < YDivSize ?  _Size : -(sint)_Size;
00125                         }
00126                         else
00127                         {
00128                                 offsetY = 0;
00129                         }
00130 
00131                         sint orgX = _Size * XDivSize;
00132                         sint orgY = _Size * YDivSize;
00133                         for (uint k = 0; k < NumWaterMap; ++k)
00134                         {
00135                                 makeCpy(k, (uint) (left - orgX + offsetX) , (uint) (top - orgY + offsetY),
00136                                                 (uint) (left - orgX), (uint) (top - orgY),
00137                                                 (uint) (right - left), (uint) (bottom - top));
00138                         }
00139                 }
00140                 
00141                 sint newOrgX = _Size * xDivSize;
00142                 sint newOrgY = _Size * yDivSize;
00143                 // clear new area
00144                 if (x == (sint) _X)
00145                 {
00146                         if (y < (sint) _Y)
00147                         {
00148                                 // x, y, width, height
00149                                 clearZone(x - newOrgX, y - newOrgY, _Size, _Y - y);
00150                         }
00151                         else
00152                         {
00153                                 clearZone(x - newOrgX, y + _Size - newOrgY, _Size, y - _Y);
00154                         }
00155                 }
00156                 else
00157                 {
00158                         if (x > (sint) _X)
00159                         {
00160                                 if (y == (sint) _Y)
00161                                 {
00162                                         clearZone(_X + _Size - newOrgX, y - newOrgY, x - _X, _Size);
00163                                 }
00164                                 else if (y < (sint) _Y)
00165                                 {
00166                                         clearZone(_X + _Size - newOrgX, _Y - newOrgY, x - _X, _Size - (_Y - y));
00167                                         clearZone(x - newOrgX, y - newOrgY, _Size, _Y - y);
00168                                 }
00169                                 else
00170                                 {
00171                                         clearZone(_X + _Size - newOrgX, y - newOrgY, x - _X, _Size - (y - _Y));
00172                                         clearZone(x - newOrgX, _Y + _Size - newOrgY, _Size, y - _Y);
00173                                 }
00174                         }
00175                         else
00176                         {
00177                                 if (y == (sint) _Y)
00178                                 {
00179                                         clearZone(x - newOrgX, y - newOrgY, _X - x, _Size);
00180                                 }
00181                                 else if (y < (sint) _Y)
00182                                 {
00183                                         clearZone(x - newOrgX, y - newOrgY, _Size, _Y - y);
00184                                         clearZone(x - newOrgX, _Y - newOrgY, _X - x, _Size - (_Y - y));
00185                                 }
00186                                 else
00187                                 {
00188                                         clearZone(x - newOrgX, y - newOrgY, _X - x, _Size - (y -_Y));
00189                                         clearZone(x - newOrgX, _Y + _Size - newOrgY, _Size, y - _Y);
00190                                 }
00191                         }
00192                 }
00193                 
00194         }
00195         else
00196         {
00197                 // the new area has no common pixel's with the previous one
00198                 // clear the whole new area
00199                 uint px = _X % _Size;
00200                 uint py = _Y % _Size;
00201                 clearZone(px, py, _Size, _Size);
00202         }
00203 
00204         _X = (uint) x;
00205         _Y = (uint) y;
00206 }
00207 
00208 
00209 
00210 //===========================================================================================
00211 
00212 void CWaterHeightMap::animatePart(float startTime, float endTime)
00213 {
00214         if (endTime < 0.5f * _PropagationTime)
00215         {
00216                 // perform propagation
00217                 propagate((uint) (_Size * 2.f * startTime / _PropagationTime), (uint) (_Size * 2.f * endTime / _PropagationTime));      
00218         }
00219         else
00220         {
00221                 //  end propagation and start filter
00222                 if (startTime < 0.5f * _PropagationTime)
00223                 {
00224                         propagate((uint) (_Size * 2.f * startTime / _PropagationTime), _Size);  
00225                         filter(0, (uint) (_Size * 2.f * (endTime / _PropagationTime - 0.5f)));
00226                 }
00227                 else
00228                 {
00229                         filter((uint) (_Size * 2.f * (startTime  / _PropagationTime - 0.5f)), (uint) (_Size * 2.f * (endTime  / _PropagationTime - 0.5f)));
00230                 }
00231         }
00232 }
00233 
00234 //===========================================================================================
00235 
00236 void CWaterHeightMap::animate(float deltaT)
00237 {       
00238         if (deltaT < 0) deltaT = 0;
00239         if (deltaT > _PropagationTime)
00240         {
00241                 animatePart(0, _PropagationTime);
00242                 swapBuffers(deltaT);
00243                 _PropagateEllapsedTime = 0;
00244         }
00245         else
00246         {
00247                 const float endTime   = _PropagateEllapsedTime + deltaT;                
00248                 const float startTime = _PropagateEllapsedTime;
00249 
00250                 if (endTime < _PropagationTime)
00251                 {
00252                         animatePart(startTime, endTime);
00253                         _PropagateEllapsedTime = endTime;
00254                 }
00255                 else
00256                 {
00257                         animatePart(startTime, _PropagationTime);
00258                         swapBuffers(deltaT);
00259                         //animatePart(0, endTime - _PropagationTime);
00260 
00261                         _PropagateEllapsedTime = 0 /*endTime - _PropagationTime*/;
00262                 }                               
00263         }
00264         animateWaves(deltaT);
00265 }
00266 
00267 //===========================================================================================
00268 
00269 void            CWaterHeightMap::setSize(uint32 size)
00270 {
00271         nlassert(size > 4);
00272         _Size  = size;  
00273         for (uint k = 0; k < NumWaterMap; ++k)
00274         {
00275                 _Map[k].resize(4 * _Size * _Size);
00276                 clearArea(k, 0, 0, _Size << 1, _Size << 1);
00277         }
00278         //_Grad.resize(4 * _Size * _Size);              
00279 }
00280 
00281 //===========================================================================================
00282 
00283 void            CWaterHeightMap::makeCpy(uint buffer, uint dX, uint dY, uint sX, uint sY, uint width, uint height)
00284 {       
00285         if (width == 0 || height == 0) return;
00286         nlassert(dX <= (2 * _Size));
00287         nlassert(dY <= (2 * _Size));
00288         nlassert(sX <= (2 * _Size));
00289         nlassert(sY <= (2 * _Size));
00290         nlassert(dX + width <= 2 * _Size);
00291         nlassert(sX + width <= 2 * _Size);
00292         nlassert(dY + height <= 2 * _Size);
00293         nlassert(sY + height <= 2 * _Size);
00294         
00295         sint stepY;
00296         float *src, *dest;
00297 
00298         const sint stride = _Size << 1;
00299         if (dY  <= sY)
00300         {
00301                 stepY = stride;
00302                 src   =  &_Map[buffer][sX + sY * stride];
00303                 dest  =  &_Map[buffer][dX + dY * stride];
00304         }
00305         else
00306         {
00307                 stepY = -stride;
00308                 src   =  &_Map[buffer][sX + (sY + height - 1) * stride];
00309                 dest  =  &_Map[buffer][dX + (dY + height - 1) * stride];
00310         }
00311 
00312         sint k = height;
00313         do
00314         {
00315                 if (dest < src)
00316                 {
00317                         std::copy(src, src + width, dest);
00318                 }
00319                 else
00320                 {
00321                         float *rSrc  = src  + width;
00322                         float *rDest = dest + width;
00323                         do
00324                         {
00325                                 --rSrc;
00326                                 --rDest;
00327                                 *rDest = *rSrc;
00328                         }
00329                         while (rSrc != src);
00330                 }
00331                 src  += stepY;
00332                 dest += stepY;
00333         }
00334         while (--k);
00335 }
00336 
00337 //===========================================================================================
00338 
00339 void            CWaterHeightMap::setUserPos(sint x, sint y)
00340 {       
00341         _NewX = x;      
00342         _NewY = y;      
00343 }
00344 
00345 //===========================================================================================
00346 
00347 void            CWaterHeightMap::getUserPos(sint &x, sint &y) const
00348 {               
00349         x = (sint) _X; y = (sint) _Y;
00350 }
00351 
00352 
00353 
00354 //===========================================================================================
00355 
00356 void            CWaterHeightMap::propagate(uint start, uint end)
00357 {       
00358         start = std::max(1u, start);
00359         end   = std::min((uint) (_Size - 1), end);
00360         const float damping = _Damping;
00361         clearBorder(0);
00362         clearBorder(1);
00363         nlassert(_Size != 0);
00364         sint x, y;
00365         uint px = _X % _Size;
00366         uint py = _Y % _Size;
00367         sint offset = px + 1 + ((py + start) * (_Size << 1));   
00368         //nlinfo("%d, %d, %d",  (_CurrMap + (NumWaterMap - 1)) % NumWaterMap,  _CurrMap, 
00369         float *buf2 = &_Map[ (_CurrMap + (NumWaterMap - 1)) % NumWaterMap][offset];
00370         float *buf1 = &_Map[_CurrMap][offset];  
00371         float *dest = &_Map[(_CurrMap + 1) % NumWaterMap][offset];
00372         
00373         const sint  sizeX2 = _Size << 1;
00374         y = end - start;
00375         if (y <= 0) return;
00376         do
00377         {
00378                 x = _Size - 2;
00379                 do
00380                 {
00381                         *dest   = damping * ( 0.5f * (buf1[1] + buf1[-1] + buf1[sizeX2] + buf1[- sizeX2]) - *buf2);                     
00382                         ++buf1;
00383                         ++buf2;
00384                         ++dest;
00385                 }
00386                 while (--x);
00387                 buf1 = buf1 + _Size + 2;
00388                 buf2 = buf2 + _Size + 2;
00389                 dest = dest + _Size + 2;
00390         }
00391         while (--y);
00392         
00393 }
00394 
00395 
00396 
00397 //===========================================================================================
00398 
00399 void    CWaterHeightMap::filter(uint start, uint end)
00400 {       
00401         start = std::max(1u, start);
00402         end   = std::min((uint) (_Size - 1), end);
00403         const float blurCoeff = _FilterWeight;
00404         nlassert(_Size != 0);
00405         sint x, y;
00406         uint px = _X % _Size;
00407         uint py = _Y % _Size;
00408         sint offset = px + 1 + ((py + start) * (_Size << 1));
00409         float *buf = &_Map[ (_CurrMap + 1) % NumWaterMap ][offset];
00410         //NLMISC::CVector2f *ptGrad = &_Grad[offset];
00411         y = end - start;
00412         if (y <= 0) return;
00413         const float totalBlurCoeff = (1.f / (4.f + blurCoeff));
00414         const sint  sizeX2 = _Size << 1;
00415         do
00416         {
00417                 x = _Size - 2;
00418                 do
00419                 {
00420                         *buf = totalBlurCoeff * (*buf * blurCoeff
00421                                                                                  + buf[1] 
00422                                                                                  + buf[-1]
00423                                                                                  + buf[sizeX2]
00424                                                                                  + buf[- sizeX2]
00425                                                                          );     
00426                         // compute gradient
00427                         /*ptGrad->x = buf[1]                - buf[- 1];
00428                         ptGrad->y = buf[sizeX2]     - buf[- sizeX2];*/
00429 
00430                         ++buf;
00431                         //++ptGrad;
00432                 }
00433                 while (--x);
00434                 buf    += _Size + 2;
00435                 //ptGrad += _Size + 2;
00436         }
00437         while (--y);    
00438 }
00439 
00440 //===========================================================================================
00441 
00442 void CWaterHeightMap::animateWaves(float deltaT)
00443 {
00444         if (_WavesEnabled)
00445         {
00446                 uint numWaves;
00447                 if (_WavePeriod == 0)
00448                 {
00449                         numWaves = 1;
00450                 }
00451                 else
00452                 {
00453                         _EmitEllapsedTime += deltaT;
00454                         if (_EmitEllapsedTime > _WavePeriod)
00455                         {
00456                                 numWaves = (uint) (_EmitEllapsedTime / _WavePeriod);
00457                                 _EmitEllapsedTime -= numWaves * _WavePeriod;
00458                                 if (numWaves > 10) numWaves = 10;
00459                         }
00460                         else
00461                         {
00462                                 numWaves = 0;
00463                         }
00464                 }
00465                 
00466                 uint k;
00467                 // generate automatic waves
00468                 if (!_BorderWaves)
00469                 {
00470                         if (_WaveIntensity != 0)
00471                         {
00472                                 for (k = 0; k < numWaves; ++k)
00473                                 {
00474                                         perturbate(_NewX + rand() % _Size, _NewY + rand() % _Size, _WaveImpulsionRadius, _WaveIntensity);
00475                                 }
00476                         }
00477                 }
00478                 else
00479                 {
00480                         switch(rand() & 3) // choose a random border
00481                         {
00482                                 case 0: // top border
00483                                         for (k = 0; k < numWaves; ++k)
00484                                         {
00485                                                 perturbate(_NewX + (uint) rand() % _Size, _NewY, _WaveImpulsionRadius, _WaveIntensity);
00486                                         }
00487                                 break;
00488                                 case 1: // bottom border
00489                                         for (k = 0; k < numWaves; ++k)
00490                                         {
00491                                                 perturbate(_NewX + (uint) rand() % _Size, _NewY + _Size - 1, _WaveImpulsionRadius, _WaveIntensity);
00492                                         }
00493                                 break;
00494                                 case 2: // right border
00495                                         for (k = 0; k < numWaves; ++k)
00496                                         {
00497                                                 perturbate(_NewX + _Size - 1, _NewY + (uint) rand() % _Size, _WaveImpulsionRadius, _WaveIntensity);
00498                                         }
00499                                 break;
00500                                 case 3: // left border
00501                                         for (k = 0; k < numWaves; ++k)
00502                                         {
00503                                                 perturbate(_NewX, _NewY + (uint) rand() % _Size, _WaveImpulsionRadius, _WaveIntensity);
00504                                         }
00505                                 break;
00506                         }
00507         
00508                 }
00509         }
00510 }
00511 
00512 //===========================================================================================
00513 
00514 void CWaterHeightMap::swapBuffers(float deltaT)
00515 {
00516         updateUserPos();
00517         _CurrMap = (_CurrMap + 1) % NumWaterMap;
00518 }
00519 
00520 
00521 //===========================================================================================
00522 
00523 void CWaterHeightMap::clearZone(sint x, sint y, sint width, sint height)
00524 {
00525         for (uint k = 0; k < NumWaterMap; ++k)
00526         {
00527                 clearArea(k, x, y, width, height);
00528         }
00529 }
00530 
00531 //===========================================================================================
00532 
00533 void CWaterHeightMap::clearArea(uint8 currMap, sint x, sint y, sint width, sint height)
00534 {       
00535         nlassert(_Size > 1);
00536         nlassert(width >= 0);
00537         nlassert(height >= 0);
00538         uint sizex2 = _Size << 1;
00539 
00540         if (x < 0)
00541         {               
00542                 width += x;
00543                 x = 0;
00544                 if (width <= 0) return;
00545         }
00546         if (y < 0)
00547         {
00548                 height += y;
00549                 y = 0;
00550                 if (height <= 0) return;
00551         }
00552         if (x + width > (sint) sizex2)
00553         {
00554                 width = width - (x + width - sizex2);
00555         }
00556 
00557         if (y + height > (sint) sizex2)
00558         {
00559                 height = height - (y + height - sizex2);
00560         }
00561         
00562         float *dest = &*(_Map[  currMap  ].begin() + x + (_Size << 1) * y);
00563         do
00564         {
00565                 std::fill(dest, dest + width, 0.f);             
00566                 dest  += (_Size << 1);
00567         }
00568         while (-- height);
00569 }
00570 
00571 
00572 
00573 //===========================================================================================
00574 
00575 void    CWaterHeightMap::perturbate(sint x, sint y, sint radius, float intensity)
00576 {
00577                 nlassert(_Size != 0);
00578                 nlassert(radius > 0);
00579                 sint orgX = _X - _X % _Size;
00580                 sint orgY = _Y - _Y % _Size;
00581                 TFloatVect &map = _Map[(_CurrMap + 1) % NumWaterMap];
00582                 const uint sizeX2 = _Size << 1;
00583                 for (sint px = -radius + 1; px < radius; ++px)
00584                 {
00585                         for (sint py = -radius + 1; py < radius; ++py)          
00586                         {       
00587                                 if ((uint) (x + px - orgX) < sizeX2 
00588                                         && (uint) (y + py - orgY) < sizeX2)
00589                                 {                                       
00590                                 
00591                                         float dist = ((float) radius - sqrtf((float) (px * px + py * py ))) / (float) radius;
00592                                         float v = dist < radius ? intensity * cosf(dist * (float) NLMISC::Pi * 0.5f) : 0.f;
00593                                         map[x + px - orgX + sizeX2 * (y + py - orgY)] = v;
00594                                 }
00595                         }
00596                 }
00597 }
00598 
00599 //===========================================================================================
00600 
00601 void    CWaterHeightMap::perturbate(const NLMISC::CVector2f &pos, float strenght, float radius)
00602 {
00603         const float invUnitSize = 1.f / _UnitSize;
00604         perturbate((sint) (pos.x * invUnitSize), (sint) (pos.y * invUnitSize), (sint) radius, strenght);
00605 }
00606 
00607 //===========================================================================================
00608 
00609 void CWaterHeightMap::perturbatePoint(sint x, sint y, float intensity)
00610 {       
00611         sint orgX = _X - _X % _Size;
00612         sint orgY = _Y - _Y % _Size;
00613         uint X = (uint) (x - orgX);
00614         uint Y = (uint) (y - orgY);     
00615         if (X < (_Size << 1)
00616                 && Y < (_Size << 1)
00617                 )
00618         {
00619                 const uint sizex2 = _Size << 1;         
00620                 TFloatVect &map = _Map[(_CurrMap + 1) % NumWaterMap];
00621                 map[X + sizex2 * Y] = intensity;                
00622         }
00623 }
00624 
00625 //===========================================================================================
00626 
00627 void    CWaterHeightMap::perturbatePoint(const NLMISC::CVector2f &pos, float strenght)
00628 {
00629         const float invUnitSize = 1.f / _UnitSize;
00630         perturbatePoint((sint) (pos.x * invUnitSize), (sint) (pos.y * invUnitSize), strenght);
00631 }
00632 
00633 //===========================================================================================
00634 
00635 void    CWaterHeightMap::clearBorder(uint currMap)
00636 {
00637         float *map  = &_Map[currMap][0];
00638         uint sizex2 = _Size << 1;
00639 
00640         // top and bottom
00641 
00642         float *up    = &map[(_X % _Size) + sizex2 * (_Y % _Size)];
00643         float *curr = up;
00644         const float *endUp = up + _Size;
00645         const uint  downOff  = (_Size - 1) * sizex2;
00646         do
00647         {
00648                 *curr = curr[downOff] = 0.f;
00649                 ++curr;
00650         }
00651         while (curr != endUp);
00652 
00653         // right and left
00654         curr  = up;
00655         const float *endLeft = up + downOff;
00656         const uint  rightOff = _Size - 1;
00657         do
00658         {
00659                 *curr = curr[rightOff] = 0.f;
00660                 curr += sizex2;
00661         }
00662         while (curr != endLeft);
00663 }
00664 
00665 //===========================================================================================
00666 
00667 void CWaterHeightMap::setWaves(float intensity, float period, uint radius, bool border)
00668 {
00669         _WaveIntensity            = intensity;
00670         _WavePeriod                       = period;
00671         _WaveImpulsionRadius  = radius;
00672         _BorderWaves              = border;
00673 
00674 }
00675 
00676 
00677 //===========================================================================================
00678 
00679 void CWaterHeightMap::serial(NLMISC::IStream &f)  throw(NLMISC::EStream)
00680 {
00681         f.xmlPushBegin("WaterHeightMap");                       
00682                 f.xmlSetAttrib ("NAME")                                 ;
00683                 f.serial (_Name);
00684         f.xmlPushEnd();
00685         (void)f.serialVersion(0);
00686         f.xmlSerial(_Size, "SIZE");
00687         if (f.isReading())
00688         {
00689                 setSize(_Size);
00690         }
00691         f.xmlSerial(_Damping, "DAMPING");
00692         f.xmlSerial(_FilterWeight, "FILTER_WEIGHT");
00693         f.xmlSerial(_UnitSize, "WATER_UNIT_SIZE");      
00694         f.xmlSerial(_WavesEnabled, "WavesEnabled");
00695         if (_WavesEnabled)
00696         {
00697                 f.xmlPush("WavesParams");
00698                         f.xmlSerial(_WaveIntensity, "WAVE_INTENSITY");
00699                         f.xmlSerial(_WavePeriod, "WAVE_PERIOD");
00700                         f.xmlSerial(_WaveImpulsionRadius, "WAVE_IMPULSION_RADIUS");
00701                         f.xmlSerial(_BorderWaves, "BORDER_WAVES");
00702                         f.xmlSerial(_PropagationTime, "PROPAGATION_TIME");
00703                 f.xmlPop();
00704         }
00705         f.xmlPop();
00706 }
00707 
00708 
00709 
00710 
00711 //*** perform a bilinear on 4 values
00712 //   0---1
00713 //   |   |
00714 //   3---2
00715 static float inline BilinFilter(float v0, float v1, float v2, float v3, float u, float v)
00716 {
00717         const float g = v * v3 + (1.f - v) * v0;
00718         const float h = v * v2 + (1.f - v) * v1;
00719         return u * h + (1.f - u) * g;
00720 }
00721 
00722 
00723 
00724 //===========================================================================================
00725 
00726 float   CWaterHeightMap::getHeight(const NLMISC::CVector2f &pos)
00727 {
00728         const float invUnitSize = 1.f / _UnitSize;
00729         
00730         const float xPos = invUnitSize * pos.x; // position in map space
00731         const float yPos = invUnitSize * pos.y; // position in map space
00732 
00733         
00734         if ((uint) xPos - _X < _Size - 1
00735                 && (uint) yPos - _Y < _Size - 1
00736                 )
00737 
00738         {
00739 
00740                 const sint orgX = _X - _X % _Size;
00741                 const sint orgY = _Y - _Y % _Size;
00742                 const uint sizeX2 = _Size << 1;
00743 
00744         
00745                 const sint  fxPos = (sint) floorf(xPos); 
00746                 const sint  fyPos = (sint) floorf(yPos); 
00747 
00748         
00749                         
00750                         const float deltaU        = xPos - fxPos;
00751                         const float deltaV        = yPos - fyPos;
00752                         const uint  offset        = (uint) fxPos - orgX + sizeX2 * ( (uint) fyPos - orgY);
00753                         const float lambda        = getBufferRatio();
00754                         const float *map1     = getPrevPointer();
00755                         const float *map2     = getPointer();
00756 
00757                         return BilinFilter(lambda * map2[offset]                          + (1.f - lambda) * map1[offset        ],                        // top left
00758                                                            lambda * map2[offset + 1]              + (1.f - lambda) * map1[offset + 1],            // top right
00759                                                            lambda * map2[offset + sizeX2 + 1] + (1.f - lambda) * map1[offset + sizeX2 + 1], // bottom right
00760                                                            lambda * map2[offset + sizeX2 ]    + (1.f - lambda) * map1[offset + sizeX2 ],          // bottom left
00761                                                            deltaU,
00762                                                            deltaV
00763                                                            );
00764         }                                               
00765         else return 0;
00766 
00767 }
00768 
00769 } // NL3D