# 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_model.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 "nel/misc/vector_2d.h"
00029 #include "nel/misc/vector_h.h"
00030 #include "nel/misc/hierarchical_timer.h"
00031 #include "nel/3d/animation_time.h"
00032 #include "3d/water_model.h"
00033 #include "3d/water_shape.h"
00034 #include "3d/water_pool_manager.h"
00035 #include "3d/water_height_map.h"
00036 #include "3d/dru.h"
00037 #include "3d/scene.h"
00038 #include "3d/driver.h"
00039 #include "3d/render_trav.h"
00040 #include "3d/anim_detail_trav.h"
00041 
00042 
00043 
00044 
00045 namespace NL3D {
00046 
00047 
00048 //=======================================================================
00049 
00050 CWaterModel::CWaterModel() : _Scene(NULL)
00051 {
00052         setOpacity(false);
00053         setTransparency(true);
00054         setOrderingLayer(1);
00055 }
00056 
00057 //=======================================================================
00058 
00059 void CWaterModel::registerBasic()
00060 {
00061         CMOT::registerModel(WaterModelClassId, TransformShapeId, CWaterModel::creator); 
00062         CMOT::registerObs(RenderTravId, WaterModelClassId, CWaterRenderObs::creator);   
00063 }
00064 
00065 
00066 //=======================================================================
00067 
00068 ITrack* CWaterModel::getDefaultTrack (uint valueId)
00069 {
00070         nlassert(Shape);
00071         CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00072         switch (valueId)
00073         {
00074                 case PosValue:                  return ws->getDefaultPos(); break;              
00075                 case ScaleValue:                return ws->getDefaultScale(); break;
00076                 case RotQuatValue:              return ws->getDefaultRotQuat(); break;
00077                 default: // delegate to parent
00078                         return CTransformShape::getDefaultTrack(valueId);
00079                 break;
00080         }
00081 }
00082 
00083 //=======================================================================
00084 
00085 uint32  CWaterModel::getWaterHeightMapID() const
00086 {
00087         CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00088         return ws->_WaterPoolID;
00089 }
00090 
00091 //=======================================================================
00092 
00093 float   CWaterModel::getHeightFactor() const
00094 {
00095         CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00096         return ws->_WaveHeightFactor;
00097 }
00098 
00099 
00100 //=======================================================================
00101 
00102 float   CWaterModel::getHeight(const NLMISC::CVector2f &pos)
00103 {
00104         CWaterShape *ws          = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);  
00105         CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(ws->_WaterPoolID);
00106         const float height   = whm.getHeight(pos);
00107         return height * ws->_WaveHeightFactor + this->getPos().z;
00108 }
00109 
00110 //=======================================================================
00111 
00112 float   CWaterModel::getAttenuatedHeight(const NLMISC::CVector2f &pos, const NLMISC::CVector &viewer)
00113 {       
00114         CWaterShape *ws          = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);                  
00115         CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(ws->_WaterPoolID);
00116         const float maxDist = whm.getUnitSize() * (whm.getSize() >> 1); 
00117         const NLMISC::CVector planePos(pos.x, pos.y, this->getPos().z);
00118         const float userDist = (planePos - viewer).norm();
00119 
00120         if (userDist > maxDist)
00121         {
00122                 return this->getPos().z;
00123         }
00124         else
00125         {
00126                 const float height   = whm.getHeight(pos);
00127                 return ws->_WaveHeightFactor * height * (1.f - userDist / maxDist) + this->getPos().z;
00128         }
00129 }
00130 
00131 
00132 //=======================================================================
00133 
00134 // perform a bilinear on 4 values
00135 //   0---1
00136 //   |   |
00137 //   3---2
00138 static float inline BilinFilter(float v0, float v1, float v2, float v3, float u, float v)
00139 {
00140         float g = v * v3 + (1.f - v) * v0;
00141         float h = v * v2 + (1.f - v) * v1;
00142         return u * h + (1.f - u) * g;
00143 }
00144 
00145 
00146 
00147 //=======================================================================
00148 
00150 static void inline FillWaterVB(uint8 *&vbPointer, float x, float y, float z, float nx, float ny)
00151 {
00152         * (float *) vbPointer = x;
00153         ((float *) vbPointer)[1] = y;
00154         ((float *) vbPointer)[2] = z;
00155         *((float *) (vbPointer + 3 * sizeof(float))) = nx;
00156         *((float *) (vbPointer + 4 * sizeof(float))) = ny;
00157         vbPointer += 5 * sizeof(float);
00158 }
00159 
00160 //***************************************************************************************************************
00161 
00162 
00164 #ifdef NL_OS_WINDOWS
00165         __forceinline
00166 #endif
00167 static void SetupWaterVertex(  sint  qLeft,
00168                                                            sint  qRight,
00169                                                            sint  qUp,
00170                                                            sint  qDown,
00171                                                            sint  qSubLeft,
00172                                                            sint  qSubDown,
00173                                                            const NLMISC::CVector &inter,                                                           
00174                                                            float invWaterRatio,                                                    
00175                                                            sint  doubleWaterHeightMapSize,
00176                                                            CWaterHeightMap &whm,
00177                                                            uint8 *&vbPointer,
00178                                                            float offsetX,
00179                                                            float offsetY
00180                                                            )
00181 {
00182         const float wXf = invWaterRatio * (inter.x + offsetX);
00183         const float wYf = invWaterRatio * (inter.y + offsetY);
00184 
00185         sint wx = (sint) floorf(wXf);
00186         sint wy = (sint) floorf(wYf);
00187 
00188         
00189 
00190         if (!
00191                  (wx >= qLeft && wx < qRight && wy < qUp &&  wy >= qDown)
00192            )
00193         {       
00194                 // no perturbation is visible
00195                 FillWaterVB(vbPointer, inter.x, inter.y, 0, 0, 0);              
00196         }
00197         else
00198         {
00199                 
00200 
00201                 // filter height and gradient at the given point
00202                 const sint stride = doubleWaterHeightMapSize;
00203 
00204                 
00205                 const uint xm     = (uint) (wx - qSubLeft);
00206                 const uint ym     = (uint) (wy - qSubDown);
00207                 const sint offset = xm + stride * ym;
00208                 const float                       *ptWater     = whm.getPointer()         + offset;
00209 
00210         /*      float epsilon = 10E-5f;
00211                 if (ptWater[0] > epsilon                         || ptWater[0] < epsilon 
00212                         || ptWater[1] > epsilon                  || ptWater[1] < epsilon 
00213                         || ptWater[stride] > epsilon     || ptWater[stride] < epsilon
00214                         || ptWater[stride + 1] > epsilon || ptWater[stride + 1] < epsilon
00215                         )
00216                 {*/
00217 
00218                         float deltaU = wXf - wx;
00219                         float deltaV = wYf - wy;
00220                         nlassert(deltaU >= 0.f && deltaU <= 1.f  && deltaV >= 0.f && deltaV <= 1.f);
00221                         const float                       *ptWaterPrev = whm.getPrevPointer()  + offset;
00222 
00223 
00224 
00225                         float g0x, g1x, g2x, g3x;  // x gradient for current 
00226                         float g0xp, g1xp, g2xp, g3xp;
00227 
00228                         float gradCurrX, gradCurrY;
00229 
00230                         float g0y, g1y, g2y, g3y; // y gradient for previous map
00231                         float g0yp, g1yp, g2yp, g3yp;
00232 
00233                         float gradPrevX, gradPrevY;
00234 
00236 
00237                         g0x = ptWater[ 1] - ptWater[ - 1];
00238                         g1x = ptWater[ 2] - ptWater[ 0 ];
00239                         g2x = ptWater[ 2 + stride] - ptWater[ stride];
00240                         g3x = ptWater[ 1 + stride] - ptWater[ - 1 + stride];
00241 
00242                         gradCurrX = BilinFilter(g0x, g1x, g2x, g3x, deltaU, deltaV);
00243 
00244 
00245                         g0y = ptWater[ stride] - ptWater[ - stride];
00246                         g1y = ptWater[ stride + 1] - ptWater[ - stride + 1];
00247                         g2y = ptWater[ (stride << 1) + 1] - ptWater[ 1];
00248                         g3y = ptWater[ (stride << 1)] - ptWater[0];
00249 
00250                         gradCurrY = BilinFilter(g0y, g1y, g2y, g3y, deltaU, deltaV);
00251 
00253 
00254                         g0xp = ptWaterPrev[ 1] - ptWaterPrev[ - 1];
00255                         g1xp = ptWaterPrev[ 2] - ptWaterPrev[ 0  ];
00256                         g2xp = ptWaterPrev[ 2 + stride] - ptWaterPrev[ + stride];
00257                         g3xp = ptWaterPrev[ 1 + stride] - ptWaterPrev[ - 1 + stride];
00258 
00259                         gradPrevX = BilinFilter(g0xp, g1xp, g2xp, g3xp, deltaU, deltaV);
00260 
00261 
00262                         g0yp = ptWaterPrev[ stride] - ptWaterPrev[ - stride];
00263                         g1yp = ptWaterPrev[ stride + 1] - ptWaterPrev[ - stride + 1];
00264                         g2yp = ptWaterPrev[ (stride << 1) + 1] - ptWaterPrev[ 1 ];
00265                         g3yp = ptWaterPrev[ (stride << 1)] - ptWaterPrev[ 0 ];
00266 
00267                         gradPrevY = BilinFilter(g0yp, g1yp, g2yp, g3yp, deltaU, deltaV);
00268 
00269 
00271                         float h = BilinFilter(ptWater[ 0 ], ptWater[ + 1], ptWater[ 1 + stride], ptWater[stride], deltaU, deltaV);
00272 
00274                         float hPrev = BilinFilter(ptWaterPrev[ 0 ], ptWaterPrev[ 1], ptWaterPrev[ 1 + stride], ptWaterPrev[stride], deltaU, deltaV);
00275                         
00276 
00277                         float timeRatio = whm.getBufferRatio();
00278 
00279 
00280                         FillWaterVB(vbPointer, inter.x, inter.y, timeRatio * h + (1.f - timeRatio) * hPrev,
00281                                                 4.5f * (timeRatio * gradCurrX + (1.f - timeRatio) * gradPrevX),
00282                                                 4.5f * (timeRatio * gradCurrY + (1.f - timeRatio) * gradPrevY)
00283                                            );
00284 
00285 
00286 
00287                         //NLMISC::CVector2f *ptGrad  = whm.getGradPointer() + offset;
00288 
00289 
00290 
00291 
00292 
00293                 /*      float dh1 = deltaV * ptWater[stride] + (1.f - deltaV) *  ptWater[0];
00294                         float dh2 = deltaV * ptWater[stride + 1] + (1.f - deltaV) *  ptWater[1];
00295                         float h = deltaU * dh2 + (1.f - deltaU ) * dh1;
00296 
00297                         
00298                         float gR = deltaV * ptGrad[stride + 1].x + (1.f - deltaV) * ptGrad[1].x;
00299                         float gL = deltaV * ptGrad[stride].x + (1.f - deltaV) * ptGrad[0].x;
00300 
00301                         float grU = 4.5f * (deltaU *  gR + (1.f - deltaU) * gL);
00302 
00303                         gR = deltaV * ptGrad[stride + 1].y + (1.f - deltaV) * ptGrad[1].y;
00304                         gL = deltaV * ptGrad[stride].y + (1.f - deltaV) * ptGrad[0].y;
00305 
00306                         float grV = 4.5f * (deltaU *  gR + (1.f - deltaU) * gL);
00307 
00308                         vb.setValueFloat3Ex (Water_VB_POS, vbIndex, inter.x, inter.y, h);
00309                         vb.setValueFloat2Ex (Water_VB_DX, vbIndex, grU, grV);
00310                         */
00311                 /*}
00312                 else
00313                 {
00314                         // no perturbation is visible
00315                         FillWaterVB(vbPointer, inter.x, inter.y, 0, 0, 0);              
00316                 }*/
00317         }
00318 }
00319 
00320 //*********************************************************
00321 // compute a rotation matrix from the K and the up vector
00322 static void ComputeUpMatrix(const NLMISC::CVector &J, NLMISC::CMatrix &dest, const NLMISC::CMatrix &defaultMat)
00323 {
00324         // if the J vector is oriented toward K, we must use another vector to compute the matrix
00325         const float JdotK = J.z;
00326         if ( (1.0f - fabsf(J.z)) < 10E-6)
00327         {       
00328                 dest.setRot(defaultMat.getRot());               
00329         }
00330         else
00331         {
00332                 NLMISC::CVector up        = (NLMISC::CVector::K - JdotK * J).normed();
00333                 NLMISC::CVector right = J ^ up;
00334                 dest.setRot(right, J, up);
00335         }
00336 }
00337 
00338 //*************************************************************
00339 // draw a 2d polygon after a transformation
00340 static void DrawPoly2D(CVertexBuffer &vb, IDriver *drv, const NLMISC::CMatrix &mat, const NLMISC::CPolygon &p)
00341 {
00342         uint k;
00343 
00344         for (k = 0; k < p.Vertices.size(); ++k)
00345         {
00346                 NLMISC::CVector tPos = mat * NLMISC::CVector(p.Vertices[k].x, p.Vertices[k].y, 0);
00347                 vb.setValueFloat3Ex (WATER_VB_POS, k, tPos.x, tPos.y, tPos.z);                                                                                  
00348                 vb.setValueFloat2Ex (WATER_VB_DX,  k, 0, 0);                    
00349         }
00350         static std::vector<uint32> ib;
00351         ib.resize(3 * p.Vertices.size());
00352 
00353         for (k = 0; k < p.Vertices.size() - 2; ++k)
00354         {
00355                 ib[ k * 3      ] = 0;
00356                 ib[ k * 3  + 1 ] = k + 1;
00357                 ib[ k * 3  + 2 ] = k + 2;
00358         }       
00359         drv->renderSimpleTriangles(&ib[0], p.Vertices.size() - 2);      
00360 }
00361 
00362 //***************************************************************************************************************
00363 
00364 void    CWaterRenderObs::traverse(IObs *caller)
00365 {                       
00366         H_AUTO( NL3D_Water_Render );
00367 
00368         CRenderTrav                                     *trav                   = NLMISC::safe_cast<CRenderTrav *>(Trav);
00369         CWaterModel                                     *m                              = NLMISC::safe_cast<CWaterModel *>(Model);
00370         CWaterShape                                     *shape                  = NLMISC::safe_cast<CWaterShape *>((IShape *) m->Shape);
00371         IDriver                                         *drv                    = trav->getDriver();
00372         const std::vector<CPlane>       &worldPyramid   = ((NLMISC::safe_cast<CClipTrav *>(ClipObs->Trav))->WorldFrustumPyramid);       
00373 
00374         if (shape->_GridSizeTouched)
00375         {
00376                 shape->setupVertexBuffer();
00377         }
00378 
00379 
00380         // inverted object world matrix
00381         //NLMISC::CMatrix invObjMat = HrcObs->WorldMatrix.inverted();
00382 
00383         // viewer pos in world space
00384         const NLMISC::CVector &obsPos = /*invObjMat **/ trav->CamPos;
00385 
00386         // camera matrix in world space
00387         const NLMISC::CMatrix &camMat = trav->CamMatrix;
00388 
00389         // view matrix (inverted cam matrix)
00390         const NLMISC::CMatrix &viewMat = trav->ViewMatrix;
00391 
00392         // compute the camera matrix such as there is no rotation around the y axis
00393         NLMISC::CMatrix camMatUp;
00394         ComputeUpMatrix(camMat.getJ(), camMatUp, camMat);
00395         camMatUp.setPos(camMat.getPos());
00396 
00397         const NLMISC::CMatrix matViewUp = camMatUp.inverted();
00398 
00399         // plane z pos in world
00400         const float zHeight =  HrcObs->WorldMatrix.getPos().z;
00401 
00402         const sint numStepX = CWaterShape::getScreenXGridSize();
00403         const sint numStepY = CWaterShape::getScreenYGridSize();
00404 
00405         const float invNumStepX = 1.f / numStepX;
00406         const float invNumStepY = 1.f / numStepY;
00407 
00408         const uint rotBorderSize = (shape->_MaxGridSize + (shape->_XGridBorder << 1) - numStepX) >> 1;
00409         
00410         const sint isAbove = obsPos.z > zHeight ? 1 : 0;
00411 
00412                 
00413 
00414         //==================//
00415         // polygon clipping //
00416         //==================//
00417 
00418         uint k;
00419         static NLMISC::CPolygon clippedPoly, endClippedPoly;    
00420         clippedPoly.Vertices.resize(shape->_Poly.Vertices.size());
00421         for (k = 0; k < shape->_Poly.Vertices.size(); ++k)
00422         {
00423                 clippedPoly.Vertices[k].set(shape->_Poly.Vertices[k].x, 
00424                                                                         shape->_Poly.Vertices[k].y,
00425                                                                         0
00426                                                                    );
00427         }
00428         
00429         endClippedPoly = clippedPoly;
00430 
00431 
00432         // Build the view pyramid. We need to rebuild it because we use a wider one to avoid holes on the border of the screen
00433 
00434         static NLMISC::CPlane plvect[6];
00435 
00436         const float borderFactor = 0.67f; // we must avoid numerical imprecision as well as the rotation case (must divide by sqrt(2))
00437         const float fRight = trav->Right * (2.f * borderFactor * (float) CWaterShape::_XGridBorder +  (float) numStepX) / numStepX;
00438         const float fTop   = trav->Top   * (2.f * borderFactor * (float) CWaterShape::_YGridBorder +  (float) numStepY) / numStepY;
00439 
00440         // build pyramid corners
00441         const float nearDist        = trav->Near;
00442         const float farDist                     = trav->Far;    
00443         const float transitionDist      = shape->_TransitionRatio   * farDist;
00444 
00445         const NLMISC::CVector           pfoc(0,0,0);
00446         const NLMISC::CVector           lb(-fRight,  nearDist, - fTop );
00447         const NLMISC::CVector           lt(-fRight,  nearDist, fTop  );
00448         const NLMISC::CVector           rb( fRight,  nearDist, -fTop );
00449         const NLMISC::CVector           rt(fRight,      nearDist, fTop  );
00450 
00451         const NLMISC::CVector           lbfarDist(-fRight, transitionDist, -fTop);
00452         const NLMISC::CVector           ltfarDist(-fRight, transitionDist, fTop );
00453         const NLMISC::CVector           rtfarDist(fRight , transitionDist, fTop  );
00454 
00455         
00456         plvect[0].make(lt, lb, rt);                                                     // near plane
00457         plvect[1].make(lbfarDist, ltfarDist, rtfarDist);    // far plane
00458 
00459         plvect[2].make(pfoc, lt, lb);
00460         plvect[3].make(pfoc, rt, lt);
00461         plvect[4].make(pfoc, rb, rt);
00462         plvect[5].make(pfoc, lb, rb);
00463 
00464                 
00465         const NLMISC::CMatrix pyramidMat = viewMat * HrcObs->WorldMatrix;
00466         for (k = 0; k < worldPyramid.size(); ++k)
00467         {
00468                 plvect[k] = plvect[k] * pyramidMat; // put the plane in object space
00469         }
00470 
00471         clippedPoly.clip(plvect, 6);    // get the tesselated part of the poly 
00472 
00473         // modify the pyramid to get the transition part of the poly (no tesselated)
00474         plvect[0].d   += (transitionDist - nearDist);
00475         // plvect[1].d   -= (farDist - transitionDist);
00476         // dont clip by far plane (done by driver)
00477         endClippedPoly.clip(plvect, 1);
00478         endClippedPoly.clip(plvect + 2, 4);
00479 
00480 
00481 
00483         if (clippedPoly.Vertices.size() == 0 && endClippedPoly.Vertices.size() == 0)
00484         {
00485                 return; 
00486         }
00487 
00488         
00489         NLMISC::CMatrix modelMat;
00490         modelMat.setPos(NLMISC::CVector(obsPos.x, obsPos.y, zHeight));
00491         drv->setupModelMatrix(modelMat);
00492         
00493 
00494         //==================//
00495         // material setup   //
00496         //==================//
00497 
00498         CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(shape->_WaterPoolID);
00499         setupMaterialNVertexShader(drv, shape, obsPos, isAbove > 0, whm.getUnitSize() * (whm.getSize() >> 1), zHeight);
00500 
00501         //setAttenuationFactor(drv, false, obsPos, camMat.getJ(), farDist);
00502         //disableAttenuation(drv);
00503 
00504         
00505         //================================//
00506         //      Vertex buffer setup           //
00507         //================================//
00508                 
00509         drv->activeVertexBuffer(shape->_VB);
00510 
00511         //================================//
00512         //      tesselated part of the poly   //
00513         //================================//
00514 
00515         if (clippedPoly.Vertices.size())
00516         {
00517                 
00518                 //======================================//
00519                 // Polygon projection on the near plane //
00520                 //======================================//
00521 
00522                 static NLMISC::CPolygon2D projPoly; // projected poly
00523                 projPoly.Vertices.resize(clippedPoly.Vertices.size());
00524                 const float Near = trav->Near;
00525                 const float xFactor = (numStepX >> 1) * Near  / trav->Right;
00526                 const float xOffset = (float) (numStepX >> 1) + 0.5f;
00527                 const float yFactor = - (numStepX >> 1) * Near  / trav->Top;
00528                 const float yOffset = (float) (numStepY >> 1) - 0.5f * isAbove;
00529                 
00530                 const NLMISC::CMatrix projMat =  matViewUp * HrcObs->WorldMatrix;
00531                 for (k = 0; k < clippedPoly.Vertices.size(); ++k)
00532                 {
00533                         // project points in the view
00534                         NLMISC::CVector t = projMat * clippedPoly.Vertices[k];
00535                         float invY = 1.f / t.y;
00536                         projPoly.Vertices[k].set(xFactor * t.x * invY + xOffset, yFactor * t.z * invY + yOffset);
00537                 }
00538 
00539 
00540 
00541                 //=============================================//
00542                 // compute borders of poly at a low resolution //
00543                 //=============================================//
00544 
00545                 NLMISC::CPolygon2D::TRasterVect rasters;                
00546                 sint startY;
00547                 projPoly.computeBorders(rasters, startY);
00548 
00549                 if (rasters.size())
00550                 {
00551                         //===========================//
00552                         // perform Water animation   //
00553                         //===========================//                 
00554 
00555                         const float WaterRatio = whm.getUnitSize();
00556                         const float invWaterRatio = 1.f / WaterRatio;
00557                         const uint  WaterHeightMapSize = whm.getSize();
00558                         const uint  doubleWaterHeightMapSize = (WaterHeightMapSize << 1);
00559                                                 
00560 
00561                         sint64 idate = (NLMISC::safe_cast<CHrcTrav *>(HrcObs->Trav))->CurrentDate;
00562 
00563 
00564                         
00565                         if (idate != whm.Date)
00566                         {
00567                                 whm.setUserPos((sint) (obsPos.x * invWaterRatio) - (WaterHeightMapSize >> 1),
00568                                            (sint) (obsPos.y * invWaterRatio) - (WaterHeightMapSize >> 1)
00569                                           );
00570                                 nlassert(m->_Scene); // this object should have been created from a CWaterShape!
00571                                 whm.animate((float) (m->_Scene->getEllapsedTime()));                                                                                            
00572                                 whm.Date = idate;
00573                         }
00574                         
00575                         //float startDate = (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()));
00576 
00577                         //=====================================//
00578                         //      compute heightmap useful area      //
00579                         //=====================================//
00580 
00588                         sint mapPosX, mapPosY;
00589 
00592                         whm.getUserPos(mapPosX, mapPosY);
00593 
00594                         const uint mapBorder = 3;
00595                         /*const sint qRight = (sint) mapPosX + (WaterHeightMapSize >> 1) - mapBorder;
00596                                   sint qLeft  = (sint) mapPosX - (WaterHeightMapSize >> 1);
00597                         const sint qUp    = (sint) mapPosY + (WaterHeightMapSize >> 1) - mapBorder;
00598                                   sint qDown  = (sint) mapPosY - (WaterHeightMapSize >> 1); */
00599 
00600 
00601                         const sint qRight = (sint) mapPosX + WaterHeightMapSize - mapBorder;
00602                                   sint qLeft  = (sint) mapPosX;
00603                         const sint qUp    = (sint) mapPosY + WaterHeightMapSize - mapBorder;
00604                                   sint qDown  = (sint) mapPosY;
00605 
00607                         const sint qSubLeft = qLeft - (uint)  qLeft % WaterHeightMapSize;
00608                         const sint qSubDown = qDown - (uint)  qDown % WaterHeightMapSize;
00609 
00610                         qLeft += mapBorder;
00611                         qDown += mapBorder;
00612 
00613                 
00614 
00615                         
00616                         //==============================================//
00617                         // setup rays to be traced, and their increment //
00618                         //==============================================//
00619                         
00620 
00621                         // compute  camera rays in world space
00622                         CVector currHV = trav->Left * camMatUp.getI() + trav->Near * camMatUp.getJ() + trav->Top * camMatUp.getK(); // current border vector, incremented at each line
00623                         CVector currV; // current ray vector
00624                         CVector xStep = (trav->Right - trav->Left) * invNumStepX * camMatUp.getI();        // xStep for the ray vector
00625                         CVector yStep = (trav->Bottom - trav->Top) * invNumStepY * camMatUp.getK();    // yStep for the ray vector
00626                         
00627 
00628 
00629                         //===============================================//
00630                         //                              perform display                  //
00631                         //===============================================//
00632 
00633                         // scale currHV at the top of the poly
00634                         currHV += (startY - 0.5f  * isAbove) * yStep;
00635 
00636                         // current index buffer used. We swap each time a row has been drawn
00637                         std::vector<uint32> *currIB = &CWaterShape::_IBUpDown, *otherIB = &CWaterShape::_IBDownUp;
00638 
00639                                         
00640                         sint vIndex = 0; // index in vertices   
00641 
00642                         // current raster position
00643                         sint oldStartX, oldEndX, realStartX, realEndX;  
00644                         //float invNearWidth = numStepX / (trav->Right - trav->Left);
00645 
00646                                 //nlinfo("size = %d, maxSize = ", rasters.size(), numStepY);
00647 
00648 
00649                         const uint wqHeight = rasters.size();
00650                         if (wqHeight)
00651                         {
00652                                 // denominator of the intersection equation
00653                                 const float denom = - obsPos.z + zHeight; 
00654                                 // test the upper raster
00655                                 // if it is above the horizon, we modify it to reach the correct location
00656                                 const float horizonEpsilon = 10E-4f; // we must be a little below the horizon
00657 
00658                                 // distance from the viewer along the traced ray
00659                                 float t;
00660 
00661                                 
00662 
00663 
00664                                  NLMISC::CPolygon2D::TRasterVect::const_iterator it = rasters.begin();
00665                                 for (uint l = 0; l <= wqHeight; ++l)
00666                                 {               
00667                                         //nlinfo("start = %d, end = %d", it->first, it->second);                                
00668                                         const sint startX = it->first;
00669                                         const sint endX   = (it->second + 1);
00670 
00671                                         nlassert(startX >= - (sint) rotBorderSize);
00672                                         nlassert(endX  <= (sint) (numStepX + rotBorderSize));
00673 
00674                                         if (l != 0)
00675                                         {
00676                                                 realStartX = std::min(startX, oldStartX);
00677                                                 realEndX = std::max(endX, oldEndX);
00678                                         }
00679                                         else
00680                                         {
00681                                                 realStartX = startX;
00682                                                 realEndX =   endX;
00683                                         }
00684 
00685                                         
00686                                         // current view vector
00687                                         currV   = currHV + (realStartX - 0.5f) * xStep;
00688                                         
00689                                         if (l == 0)
00690                                         {
00691                                                 if (isAbove)
00692                                                 {
00693                                                         // test wether the first row is out of horizon.
00694                                                         // if this is the case, we make a correction
00695                                                         if (denom * currV.z <= 0)
00696                                                         {                                       
00697                                                                 // correct for the first line only by adding a y offset
00698                                                                 currV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon)   - currV.z) / yStep.z;
00699                                                         }
00700 
00701                                                         // now, for the transition, check wether the first raster does not go over the transition dist
00702                                                 
00703                                                         t = denom / currV.z;
00704                                                         const float VJ = camMat.getJ() * currV;
00705                                                         if ( t * VJ >  transitionDist)
00706                                                         {                                                       
00707                                                                 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currV.z);
00708                                                                 // correct the first line to reach that position
00709                                                                 currV += delta * yStep;
00710                                                         }
00711                                                 }
00712                                         }
00713 
00714                                         
00715                                         uint8 *vbPointer = (uint8 *) shape->_VB.getVertexCoordPointer() + shape->_VB.getVertexSize() * (vIndex + realStartX + rotBorderSize);                                                                                           
00716                                                 
00717 
00718                                         for (sint k = realStartX; k <= realEndX; ++k)
00719                                         {       
00720                                                 t =   denom / currV.z;                                          
00721                                                 // compute intersection with plane                                                                                      
00722                                                 CVector inter = t * currV;
00723                                                 inter.z += obsPos.z;
00724                                                 SetupWaterVertex(qLeft, qRight, qUp, qDown, qSubLeft, qSubDown, inter, invWaterRatio, doubleWaterHeightMapSize, whm, vbPointer, obsPos.x, obsPos.y);
00725                                                 currV += xStep;                                         
00726                                         }
00727 
00728                                         if (l != 0) // 2 line of the ib done ?
00729                                         {                                               
00730                                                 sint count = oldEndX - oldStartX;
00731                                                 if (count > 0)
00732                                                 {                                                                                               
00733                                                         drv->renderSimpleTriangles(&((*currIB)[(oldStartX + rotBorderSize) * 6]),
00734                                                                                                  2 * count );                           
00735                                                 }               
00736                                         }
00737 
00738                                         oldStartX = startX;
00739                                         oldEndX   = endX;
00740                                         currHV    += yStep;
00741                                         vIndex    = (numStepX + 2 * rotBorderSize + 1) - vIndex; // swap first row and second row
00742                                         std::swap(currIB, otherIB);
00743                                         if (l < (wqHeight - 1))
00744                                         {
00745                                                 ++it;
00746                                         }
00747                                         else
00748                                         {
00749                                                 if (!isAbove)
00750                                                 {
00751                                                         // last line
00752                                                         // test wether we are out of horizon
00753                                                         if (denom * currHV.z <= 0)
00754                                                         {                                               
00755                                                                 // correct for the first line only by adding a y offset
00756                                                                 currHV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon)  - currHV.z) / yStep.z;
00757                                                         }
00758 
00759                                                         // now, for the transition, check wether the first raster does not go over the transition dist
00760                                                 
00761                                                         t = denom / currHV.z;
00762                                                         const float VJ = camMat.getJ() * currHV;
00763                                                         if ( t * VJ >  transitionDist)
00764                                                         {                                                       
00765                                                                 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currHV.z);
00766                                                                 // correct the first line to reach that position
00767                                                                 currHV += delta * yStep;
00768                                                         }
00769                                                 }
00770 
00771                                         }
00772                                 }
00773                                         
00774                         }
00775                         //nlinfo("display: %f ms", (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()) - startDate));
00776                 }
00777         }
00778 
00779         //=========================================//
00780         //                      display end poly               //
00781         //=========================================//
00782 
00783         if (endClippedPoly.Vertices.size() != 0)
00784         {       
00785                 CMatrix mtx; /*= HrcObs->WorldMatrix;*/
00786                 // mtx.setPos(NLMISC::CVector(-obsPos.x, -obsPos.y, obsPos.z));
00787 
00788                 mtx.setPos(HrcObs->WorldMatrix.getPos() + NLMISC::CVector(-obsPos.x, -obsPos.y, 0));
00789                 // set right obsever position
00790                 drv->setConstant(7, 0, 0, obsPos.z /* - zHeight*/ , 0.f);
00791                 //setAttenuationFactor(drv, true, obsPos, camMat.getJ(), farDist);                              
00792                 DrawPoly2D(shape->_VB, drv, mtx, endClippedPoly);
00793         }
00794 
00795         /*if (endTransitionClippedPoly.Vertices.size() != 0)
00796         {                               
00797                 disableAttenuation(drv);                                
00798                 DrawPoly2D(shape->_VB, drv, HrcObs->WorldMatrix, endTransitionClippedPoly);
00799         }*/
00800 
00801 
00802         if (drv->isVertexProgramSupported())
00803         {
00804                 bool result =  drv->activeVertexProgram(NULL);
00805                 if (!result) nlwarning("no vertex program setupped");
00806         }
00807         
00808 
00809         this->traverseSons();
00810 }
00811 
00812 //***********************
00813 // Water MATERIAL SETUP //
00814 //***********************
00815 
00816 void CWaterRenderObs::setupMaterialNVertexShader(IDriver *drv, CWaterShape *shape, const NLMISC::CVector &obsPos, bool above, float maxDist, float zHeight)
00817 {       
00818         CMaterial WaterMat;
00819         WaterMat.setLighting(false);
00820         WaterMat.setDoubleSided(true);  
00821         WaterMat.setColor(NLMISC::CRGBA::White);
00822 
00823         WaterMat.setBlend(true);
00824         WaterMat.setSrcBlend(CMaterial::srcalpha);
00825         WaterMat.setDstBlend(CMaterial::invsrcalpha);
00826         WaterMat.setZWrite(true);
00827 
00828         if (drv->isVertexProgramSupported())    
00829         {
00830                 const uint cstOffset = 4; // 4 places for the matrix
00831                 NLMISC::CVectorH cst[13];
00832                 
00833                 
00834                 //=========================//
00835                 //      setup Water material   //
00836                 //=========================//
00837         
00838                 uint alphaMapStage, envMapStage;        
00839                 WaterMat.setColor(NLMISC::CRGBA::White);
00840 
00841                 bool useBumpedVersion = false;
00842                 bool useEMBM = false;
00843                 if (drv->getNbTextureStages() >= 4 && (drv->supportTextureShaders() || drv->supportEMBM()))
00844                 {
00845                         if (drv->supportTextureShaders())
00846                         {
00847                                 useBumpedVersion = true;
00848                         }
00849                         else // must support EMBM on stages 0 and 1
00850                         {
00851                                 if (drv->isEMBMSupportedAtStage(0) && drv->isEMBMSupportedAtStage(1))
00852                                 {
00853                                         useBumpedVersion = true;
00854                                         useEMBM = true;
00855                                 }
00856                         }
00857                 }               
00858 
00859                 
00860                 if (!useBumpedVersion)
00861                 {                                               
00862                         WaterMat.texEnvOpRGB(0, CMaterial::Modulate);
00863                         alphaMapStage = 1;
00864                         envMapStage  = 0;
00865                 }
00866                 else
00867                 {
00868                         shape->updateHeightMapNormalizationFactors();
00869 
00870                         // setup bump proj matrix                       
00871                         const float idMat[] = {0.25f * shape->_HeightMapNormalizationFactor[0], 0, 0, 0.25f * shape->_HeightMapNormalizationFactor[0]}; 
00872                         const float idMat2[] = {shape->_HeightMapNormalizationFactor[1], 0, 0, shape->_HeightMapNormalizationFactor[1]};        
00873 
00874                         WaterMat.setTexture(0, shape->_BumpMap[0]);
00875                         WaterMat.setTexture(1, shape->_BumpMap[1]);                             
00876                         WaterMat.texEnvOpRGB(2, CMaterial::Replace);
00877                         alphaMapStage = 3;
00878                         envMapStage   = 2;
00879 
00880                         // Version with texture shaders
00881                         if (!useEMBM)
00882                         {                                               
00883                                 drv->setMatrix2DForTextureOffsetAddrMode(1, idMat);
00884                                 drv->setMatrix2DForTextureOffsetAddrMode(2, idMat2);                            
00885 
00886 
00887                                 //if (shape->_BumpMap[0]->supportSharing()) nlinfo(shape->_BumpMap[0]->getShareName().c_str());
00888                                 //if (shape->_BumpMap[1]->supportSharing()) nlinfo(shape->_BumpMap[1]->getShareName().c_str());
00889 
00890                                 /*WaterMat.texEnvOpRGB(1, CMaterial::Replace);
00891                                 WaterMat.texEnvOpRGB(1, CMaterial::Replace);*/
00892                                 WaterMat.enableTexAddrMode();
00893                                 WaterMat.setTexAddressingMode(0, CMaterial::FetchTexture);              
00894                                 WaterMat.setTexAddressingMode(1, CMaterial::OffsetTexture);
00895                                 WaterMat.setTexAddressingMode(2, CMaterial::OffsetTexture);
00896                                 WaterMat.setTexAddressingMode(3, shape->_ColorMap ? CMaterial::FetchTexture : CMaterial::TextureOff);                           
00897                         }
00898                         else // version with EMBM
00899                         {
00900                                 drv->setEMBMMatrix(0, idMat2);          
00901                                 drv->setEMBMMatrix(1, idMat2);
00902                                 WaterMat.texEnvOpRGB(0, CMaterial::EMBM);
00903                                 //WaterMat.texEnvOpRGB(0, CMaterial::Replace);
00904                                 //WaterMat.texEnvOpRGB(0, CMaterial::EMBM);
00905                                 WaterMat.texEnvOpRGB(1, CMaterial::EMBM);
00906                                 WaterMat.setTexture(0, NULL);                   
00907                         }
00908                 }
00909                 
00910 
00911                 if (!above && shape->_EnvMap[1])
00912                 {
00913                         WaterMat.setTexture(envMapStage, shape->_EnvMap[1]);    
00914                         //if (shape->_EnvMap[1]->supportSharing()) nlinfo(shape->_EnvMap[1]->getShareName().c_str());
00915                 }
00916                 else
00917                 {
00918                         WaterMat.setTexture(envMapStage, shape->_EnvMap[0]);
00919                 }
00920                 shape->envMapUpdate();
00921 
00922                 
00923                 if (shape->_ColorMap)
00924                 {                       
00925                         WaterMat.setTexture(alphaMapStage, shape->_ColorMap);
00926                         //if (shape->_ColorMap->supportSharing()) nlinfo(shape->_ColorMap->getShareName().c_str());
00927 
00928 
00929                         // setup 2x3 matrix for lookup in diffuse map
00930                         cst[13 - cstOffset].set(shape->_ColorMapMatColumn0.x, shape->_ColorMapMatColumn1.x, 0, shape->_ColorMapMatColumn0.x * obsPos.x + shape->_ColorMapMatColumn1.x * obsPos.y + shape->_ColorMapMatPos.x); 
00931                         cst[14 - cstOffset].set(shape->_ColorMapMatColumn0.y, shape->_ColorMapMatColumn1.y, 0, shape->_ColorMapMatColumn0.y * obsPos.x + shape->_ColorMapMatColumn1.y * obsPos.y + shape->_ColorMapMatPos.y);                   
00932                         WaterMat.texEnvOpRGB(alphaMapStage, CMaterial::Modulate);
00933                         WaterMat.texEnvOpAlpha(alphaMapStage, CMaterial::Modulate);
00934                 }
00935                 else
00936                 {
00937                         cst[13 - cstOffset].set(0, 0, 0, 0);
00938                         cst[14 - cstOffset].set(0, 0, 0, 0);                    
00939                 }
00940 
00941                 cst[16 - cstOffset].set(0.1f, 0.1f, 0.1f, 0.1f); // used to avoid imprecision when performing a RSQ to get distance from the origin
00942                 // cst[16 - cstOffset].set(0.0f, 0.0f, 0.0f, 0.0f); // used to avoid imprecision when performing a RSQ to get distance from the origin
00943 
00944                                         
00945 
00946 
00947                 cst[5  - cstOffset].set(0.f, 0.f, 0.f, 0.f); // claping negative values to 0
00948 
00949                 // slope of attenuation of normal / height with distance                
00950                 const float invMaxDist = shape->_WaveHeightFactor / maxDist;
00951                 cst[6  - cstOffset].set(invMaxDist, shape->_WaveHeightFactor, 0, 0);            
00952 
00953                 /*cst[6  - cstOffset].set(invMaxDist, invMaxDist, invMaxDist, invMaxDist); // upcoming light vectorshape->_WaveHeightFactor             
00954                 cst[15  - cstOffset].set(shape->_WaveHeightFactor, shape->_WaveHeightFactor, shape->_WaveHeightFactor, shape->_WaveHeightFactor);
00955                 */
00956 
00957 
00958                                 
00959 
00961                 drv->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
00962 
00963                 // retrieve current time
00964                 float date  = 0.001f * NLMISC::CTime::getLocalTime();
00965                 // set bumpmaps pos
00966                 cst[9  - cstOffset].set(obsPos.x * shape->_HeightMapScale[0].x + date * shape->_HeightMapSpeed[0].x, shape->_HeightMapScale[0].y * obsPos.y + date * shape->_HeightMapSpeed[0].y, 0.f, 0.f); // bump map 0 offset
00967                 cst[10  - cstOffset].set(shape->_HeightMapScale[0].x, shape->_HeightMapScale[0].y, 0, 0); // bump map 0 scale
00968                 cst[11  - cstOffset].set(shape->_HeightMapScale[1].x * obsPos.x + date * shape->_HeightMapSpeed[1].x, shape->_HeightMapScale[1].y * obsPos.y + date * shape->_HeightMapSpeed[0].y, 0.f, 0.f); // bump map 1 offset
00969                 cst[12  - cstOffset].set(shape->_HeightMapScale[1].x, shape->_HeightMapScale[1].y, 0, 0); // bump map 1 scale
00970 
00971                                 
00972                         
00973                 
00974 
00975 
00976                 cst[4  - cstOffset].set(1.f, 1.f, 1.f, 1.f); // use with min man, and to get the 1 constant             
00977                 cst[7  - cstOffset].set(0, 0, obsPos.z - zHeight, 0.f);
00978                 cst[8  - cstOffset].set(0.5f, 0.5f, 0.f, 0.f); // used to scale reflected ray into the envmap
00979 
00980         
00981                 
00982 
00984                 drv->setConstant(4, sizeof(cst) / sizeof(cst[0]), (float *) &cst[0]);
00985 
00986                 shape->initVertexProgram();             
00987                 bool result;
00988                 if (useBumpedVersion)
00989                 {
00990                         if (!useEMBM)
00991                         {                       
00992                                 result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
00993                                                                                                 : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
00994                         }
00995                         else
00996                         {
00997                                 result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump1Diffuse).get())
00998                                                                                                 : drv->activeVertexProgram((shape->_VertexProgramBump1).get());
00999                         }
01000                 }
01001                 else
01002                 {
01003                         result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramNoBumpDiffuse).get())
01004                                                                                 : drv->activeVertexProgram((shape->_VertexProgramNoBump).get());
01005                 }
01006                 if (!result) nlwarning("no vertex program setupped");                           
01007         }
01008         else
01009         {               
01010                 WaterMat.setColor(NLMISC::CRGBA(0, 32, 190, 128));      
01011         }
01012 
01013 
01014         // temp for test
01015 /*      WaterMat = CMaterial();
01016         WaterMat.initUnlit();
01017         WaterMat.setDoubleSided(true);
01018         WaterMat.setColor(CRGBA::Red);
01019 
01020 
01021          WaterMat.texEnvOpRGB(0, CMaterial::Replace);
01022         WaterMat.texEnvOpAlpha(0, CMaterial::Replace);
01023         WaterMat.texEnvArg0RGB(0, CMaterial::Diffuse, CMaterial::SrcColor);
01024         WaterMat.texEnvArg0Alpha(0, CMaterial::Diffuse, CMaterial::SrcAlpha);
01025         */
01026 
01027         drv->setupMaterial(WaterMat);
01028 }
01029 
01030 //=======================================================================================
01031 //                                                      wave maker implementation
01032 //=======================================================================================
01033 
01034 
01035 CWaveMakerModel::CWaveMakerModel() : _Time(0), _Scene(NULL)
01036 {
01037         // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
01038         CTransform::setIsForceAnimDetail(true);
01039 }
01040 
01041 //================================================
01042 
01043 void CWaveMakerModel::registerBasic()
01044 {
01045         CMOT::registerModel(WaveMakerModelClassId, TransformShapeId, CWaveMakerModel::creator);
01046         CMOT::registerObs(AnimDetailTravId, WaveMakerModelClassId, CWaveMakerDetailObs::creator);       
01047 }
01048 
01049 //================================================
01050 
01051 ITrack* CWaveMakerModel::getDefaultTrack (uint valueId)
01052 {
01053         nlassert(Shape);
01054         CWaveMakerShape *ws = NLMISC::safe_cast<CWaveMakerShape *>((IShape *) Shape);
01055         switch (valueId)
01056         {
01057                 case PosValue:                  return ws->getDefaultPos(); break;      
01058                 default: // delegate to parent
01059                         return CTransformShape::getDefaultTrack(valueId);
01060                 break;
01061         }
01062 }
01063 
01064 //================================================
01065 
01066 void    CWaveMakerDetailObs::traverse(IObs *caller)
01067 {
01068         CTransformAnimDetailObs::traverse(caller);
01070         CWaveMakerModel *wmm = NLMISC::safe_cast<CWaveMakerModel *>(Model);
01071         nlassert(wmm->_Scene);
01073         CWaveMakerShape *wms = NLMISC::safe_cast<CWaveMakerShape *>((IShape *) wmm->Shape);
01074         const NLMISC::CVector   worldPos = this->ClipObs->HrcObs->WorldMatrix.getPos();
01075         const NLMISC::CVector2f pos2d(worldPos.x, worldPos.y);
01077         CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(wms->_PoolID);
01078         // get the time delta 
01079         const TAnimationTime deltaT  = std::min(wmm->_Scene->getEllapsedTime(), (TAnimationTime) whm.getPropagationTime());
01080         wmm->_Time += deltaT;
01081         if (!wms->_ImpulsionMode)
01082         {
01083                 whm.perturbate(pos2d, wms->_Intensity * cosf(2.f / wms->_Period * (float) NLMISC::Pi * wmm->_Time), wms->_Radius);
01084         }
01085         else
01086         {
01087                 if (wmm->_Time > wms->_Period)
01088                 {
01089                         wmm->_Time -= wms->_Period;
01090                         whm.perturbate(pos2d, wms->_Intensity, wms->_Radius);
01091                 }
01092         }
01093         this->traverseSons();
01094 }
01095 
01096 
01097 } // NL3D