water_model.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2000, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 #include "std3d.h"
00025 
00026 #include "nel/misc/vector_2f.h"
00027 #include "nel/misc/vector_h.h"
00028 #include "nel/misc/hierarchical_timer.h"
00029 #include "nel/3d/animation_time.h"
00030 #include "nel/3d/water_model.h"
00031 #include "nel/3d/water_shape.h"
00032 #include "nel/3d/water_pool_manager.h"
00033 #include "nel/3d/water_height_map.h"
00034 #include "nel/3d/dru.h"
00035 #include "nel/3d/scene.h"
00036 #include "nel/3d/driver.h"
00037 #include "nel/3d/render_trav.h"
00038 #include "nel/3d/anim_detail_trav.h"
00039 #include "nel/3d/texture_emboss.h"
00040 #include "nel/3d/texture_bump.h"
00041 #include "nel/3d/water_env_map.h"
00042 
00043 
00044 using NLMISC::CVector2f;
00045 
00046 
00047 namespace NL3D {
00048 
00049 // for normal rendering
00050 CMaterial CWaterModel::_WaterMat;
00051 // for simple rendering
00052 CMaterial CWaterModel::_SimpleWaterMat;
00053 const uint WATER_MODEL_DEFAULT_NUM_VERTICES = 5000;
00054 
00055 NLMISC::CRefPtr<IDriver> CWaterModel::_CurrDrv;
00056 
00057 
00058 
00059 // TMP
00060 volatile bool forceWaterSimpleRender = false;
00061 
00062 //=======================================================================
00063 void CWaterModel::setupVertexBuffer(CVertexBuffer &vb, uint numWantedVertices, IDriver *drv)
00064 {
00065     if (!numWantedVertices) return;
00066     if (vb.getNumVertices() == 0 || drv != _CurrDrv) // not setupped yet, or driver changed ?
00067     {
00068         vb.setNumVertices(0);
00069         vb.setName("Water");
00070         vb.setPreferredMemory(CVertexBuffer::AGPPreferred, false);
00071         if (drv->isWaterShaderSupported())
00072         {
00073             vb.setVertexFormat(CVertexBuffer::PositionFlag);
00074         }
00075         else
00076         {
00077             vb.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag);
00078         }
00079         _CurrDrv = drv;
00080     }
00081     uint numVerts = std::max(numWantedVertices, WATER_MODEL_DEFAULT_NUM_VERTICES);
00082     if (numVerts > vb.getNumVertices())
00083     {
00084         const uint vb_INCREASE_SIZE = 1000;
00085         numVerts = vb_INCREASE_SIZE * ((numVerts + (vb_INCREASE_SIZE - 1)) / vb_INCREASE_SIZE); // snap size
00086         vb.setNumVertices((uint32) numVerts);
00087     }
00088 }
00089 
00090 //=======================================================================
00091 CWaterModel::CWaterModel()
00092 {
00093     setOpacity(false);
00094     setTransparency(true);
00095     setOrderingLayer(1);
00096     // RenderFilter: We are a SegRemanece
00097     _RenderFilterType= UScene::FilterWater;
00098     _Prev = NULL;
00099     _Next = NULL;
00100     _MatrixUpdateDate = 0;
00101 }
00102 
00103 //=======================================================================
00104 CWaterModel::~CWaterModel()
00105 {
00106     CScene *scene = getOwnerScene();
00107     if (scene && scene->getWaterCallback())
00108     {
00109         nlassert(Shape);
00110         CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00111         scene->getWaterCallback()->waterSurfaceRemoved(ws->getUseSceneWaterEnvMap(0) || ws->getUseSceneWaterEnvMap(1));
00112     }
00113     // should be already unlinked, but security
00114     unlink();
00115 }
00116 
00117 //=======================================================================
00118 void CWaterModel::registerBasic()
00119 {
00120     CScene::registerModel(WaterModelClassId, TransformShapeId, CWaterModel::creator);
00121 }
00122 
00123 
00124 //=======================================================================
00125 ITrack* CWaterModel::getDefaultTrack (uint valueId)
00126 {
00127     nlassert(Shape);
00128     CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00129     switch (valueId)
00130     {
00131         case PosValue:          return ws->getDefaultPos(); break;
00132         case ScaleValue:        return ws->getDefaultScale(); break;
00133         case RotQuatValue:      return ws->getDefaultRotQuat(); break;
00134         default: // delegate to parent
00135             return CTransformShape::getDefaultTrack(valueId);
00136         break;
00137     }
00138 }
00139 
00140 
00141 //=======================================================================
00142 uint32  CWaterModel::getWaterHeightMapID() const
00143 {
00144     CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00145     return ws->_WaterPoolID;
00146 }
00147 
00148 //=======================================================================
00149 float   CWaterModel::getHeightFactor() const
00150 {
00151     CWaterShape *ws = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00152     return ws->_WaveHeightFactor;
00153 }
00154 
00155 
00156 //=======================================================================
00157 float   CWaterModel::getHeight(const CVector2f &pos)
00158 {
00159     CWaterShape *ws      = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00160     CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(ws->_WaterPoolID);
00161     const float height   = whm.getHeight(pos);
00162     return height * ws->_WaveHeightFactor + this->getPos().z;
00163 }
00164 
00165 //=======================================================================
00166 float   CWaterModel::getAttenuatedHeight(const CVector2f &pos, const NLMISC::CVector &viewer)
00167 {
00168     CWaterShape *ws      = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00169     CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(ws->_WaterPoolID);
00170     const float maxDist = whm.getUnitSize() * (whm.getSize() >> 1);
00171     const NLMISC::CVector planePos(pos.x, pos.y, this->getMatrix().getPos().z);
00172     const float userDist = (planePos - viewer).norm();
00173 
00174     if (userDist > maxDist)
00175     {
00176         return this->getMatrix().getPos().z;
00177     }
00178     else
00179     {
00180         const float height   = whm.getHeight(pos);
00181         return ws->_WaveHeightFactor * height * (1.f - userDist / maxDist) + this->getMatrix().getPos().z;
00182     }
00183 }
00184 
00185 
00186 //=======================================================================
00187 
00188 // perform a bilinear on 4 values
00189 //   0---1
00190 //   |   |
00191 //   3---2
00192 
00193 /*
00194 static float inline BilinFilter(float v0, float v1, float v2, float v3, float u, float v)
00195 {
00196     float g = v * v3 + (1.f - v) * v0;
00197     float h = v * v2 + (1.f - v) * v1;
00198     return u * h + (1.f - u) * g;
00199 }
00200 */
00201 
00202 
00203 //=======================================================================
00204 
00206 /*
00207 static void inline FillWaterVB(uint8 *&vbPointer, float x, float y, float z, float nx, float ny)
00208 {
00209     * (float *) vbPointer = x;
00210     ((float *) vbPointer)[1] = y;
00211     ((float *) vbPointer)[2] = z;
00212     *((float *) (vbPointer + 3 * sizeof(float))) = nx;
00213     *((float *) (vbPointer + 4 * sizeof(float))) = ny;
00214     vbPointer += 5 * sizeof(float);
00215 }
00216 */
00217 
00218 //***************************************************************************************************************
00219 /*
00220 #ifdef NL_OS_WINDOWS
00221     __forceinline
00222 #endif
00223 static void SetupWaterVertex(  sint  qLeft,
00224                                sint  qRight,
00225                                sint  qUp,
00226                                sint  qDown,
00227                                sint  qSubLeft,
00228                                sint  qSubDown,
00229                                const NLMISC::CVector &inter,
00230                                float invWaterRatio,
00231                                sint  doubleWaterHeightMapSize,
00232                                CWaterHeightMap &whm,
00233                                uint8 *&vbPointer,
00234                                float offsetX,
00235                                float offsetY
00236                                )
00237 {
00238     const float wXf = invWaterRatio * (inter.x + offsetX);
00239     const float wYf = invWaterRatio * (inter.y + offsetY);
00240 
00241     sint wx = (sint) floorf(wXf);
00242     sint wy = (sint) floorf(wYf);
00243 
00244 
00245 
00246     if (!
00247          (wx >= qLeft && wx < qRight && wy < qUp &&  wy >= qDown)
00248        )
00249     {
00250         // no perturbation is visible
00251         FillWaterVB(vbPointer, inter.x, inter.y, 0, 0, 0);
00252     }
00253     else
00254     {
00255 
00256 
00257         // filter height and gradient at the given point
00258         const sint stride = doubleWaterHeightMapSize;
00259 
00260 
00261         const uint xm     = (uint) (wx - qSubLeft);
00262         const uint ym     = (uint) (wy - qSubDown);
00263         const sint offset = xm + stride * ym;
00264         const float           *ptWater     = whm.getPointer()     + offset;
00265 
00266 
00267             float deltaU = wXf - wx;
00268             float deltaV = wYf - wy;
00269             //nlassert(deltaU >= 0.f && deltaU <= 1.f  && deltaV >= 0.f && deltaV <= 1.f);
00270 
00271             const float           *ptWaterPrev = whm.getPrevPointer()  + offset;
00272 
00273 
00274 
00275             float g0x, g1x, g2x, g3x;  // x gradient for current
00276             float g0xp, g1xp, g2xp, g3xp;
00277 
00278             float gradCurrX, gradCurrY;
00279 
00280             float g0y, g1y, g2y, g3y; // y gradient for previous map
00281             float g0yp, g1yp, g2yp, g3yp;
00282 
00283             float gradPrevX, gradPrevY;
00284 
00286 
00287             g0x = ptWater[ 1] - ptWater[ - 1];
00288             g1x = ptWater[ 2] - ptWater[ 0 ];
00289             g2x = ptWater[ 2 + stride] - ptWater[ stride];
00290             g3x = ptWater[ 1 + stride] - ptWater[ - 1 + stride];
00291 
00292             gradCurrX = BilinFilter(g0x, g1x, g2x, g3x, deltaU, deltaV);
00293 
00294 
00295             g0y = ptWater[ stride] - ptWater[ - stride];
00296             g1y = ptWater[ stride + 1] - ptWater[ - stride + 1];
00297             g2y = ptWater[ (stride << 1) + 1] - ptWater[ 1];
00298             g3y = ptWater[ (stride << 1)] - ptWater[0];
00299 
00300             gradCurrY = BilinFilter(g0y, g1y, g2y, g3y, deltaU, deltaV);
00301 
00303 
00304             g0xp = ptWaterPrev[ 1] - ptWaterPrev[ - 1];
00305             g1xp = ptWaterPrev[ 2] - ptWaterPrev[ 0  ];
00306             g2xp = ptWaterPrev[ 2 + stride] - ptWaterPrev[ + stride];
00307             g3xp = ptWaterPrev[ 1 + stride] - ptWaterPrev[ - 1 + stride];
00308 
00309             gradPrevX = BilinFilter(g0xp, g1xp, g2xp, g3xp, deltaU, deltaV);
00310 
00311 
00312             g0yp = ptWaterPrev[ stride] - ptWaterPrev[ - stride];
00313             g1yp = ptWaterPrev[ stride + 1] - ptWaterPrev[ - stride + 1];
00314             g2yp = ptWaterPrev[ (stride << 1) + 1] - ptWaterPrev[ 1 ];
00315             g3yp = ptWaterPrev[ (stride << 1)] - ptWaterPrev[ 0 ];
00316 
00317             gradPrevY = BilinFilter(g0yp, g1yp, g2yp, g3yp, deltaU, deltaV);
00318 
00319 
00321             float h = BilinFilter(ptWater[ 0 ], ptWater[ + 1], ptWater[ 1 + stride], ptWater[stride], deltaU, deltaV);
00322 
00324             float hPrev = BilinFilter(ptWaterPrev[ 0 ], ptWaterPrev[ 1], ptWaterPrev[ 1 + stride], ptWaterPrev[stride], deltaU, deltaV);
00325 
00326 
00327             float timeRatio = whm.getBufferRatio();
00328 
00329 
00330             FillWaterVB(vbPointer, inter.x, inter.y, timeRatio * h + (1.f - timeRatio) * hPrev,
00331                         4.5f * (timeRatio * gradCurrX + (1.f - timeRatio) * gradPrevX),
00332                         4.5f * (timeRatio * gradCurrY + (1.f - timeRatio) * gradPrevY)
00333                        );
00334 
00335             //NLMISC::CVector2f *ptGrad  = whm.getGradPointer() + offset;
00336     }
00337 }
00338 */
00339 
00340 
00341 //*****************************************************************************************************
00342 /*
00343 static void DrawPoly2D(CVertexBuffer &vb, IDriver *drv, const NLMISC::CMatrix &mat, const NLMISC::CPolygon &p)
00344 {
00345     uint k;
00346 
00347     {
00348         CVertexBufferReadWrite vba;
00349         vb.lock (vba);
00350         for (k = 0; k < p.Vertices.size(); ++k)
00351         {
00352             NLMISC::CVector tPos = mat * NLMISC::CVector(p.Vertices[k].x, p.Vertices[k].y, 0);
00353             vba.setValueFloat3Ex (WATER_VB_POS, k, tPos.x, tPos.y, tPos.z);
00354             vba.setValueFloat2Ex (WATER_VB_DX,  k, 0, 0);
00355         }
00356     }
00357     static CIndexBuffer ib;
00358     ib.setNumIndexes(3 * p.Vertices.size());
00359     {
00360         CIndexBufferReadWrite ibaWrite;
00361         ib.lock (ibaWrite);
00362         uint32 *ptr = ibaWrite.getPtr();
00363         for (k = 0; k < p.Vertices.size() - 2; ++k)
00364         {
00365             ptr[ k * 3      ] = 0;
00366             ptr[ k * 3  + 1 ] = k + 1;
00367             ptr[ k * 3  + 2 ] = k + 2;
00368         }
00369     }
00370     drv->activeIndexBuffer(ib);
00371     drv->renderSimpleTriangles(0, p.Vertices.size() - 2);
00372 }
00373 */
00374 
00375 
00376 //***************************************************************************************************************
00377 /*
00378 void    CWaterModel::traverseRender()
00379 {
00380     H_AUTO( NL3D_Water_Render );
00381 
00382     CRenderTrav                 &renderTrav     = getOwnerScene()->getRenderTrav();
00383     IDriver                     *drv            = renderTrav.getDriver();
00384 
00385 
00386     #ifndef FORCE_SIMPLE_WATER_RENDER
00387         if (!drv->isWaterShaderSupported())
00388     #endif
00389     {
00390         doSimpleRender(drv);
00391         return;
00392     }
00393 
00394     CWaterShape                 *shape          = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
00395 
00396 
00397     if (shape->_GridSizeTouched)
00398     {
00399         shape->setupVertexBuffer();
00400     }
00401 
00402     // inverted object world matrix
00403     //NLMISC::CMatrix invObjMat = getWorldMatrix().inverted();
00404 
00405     // viewer pos in world space
00406     const NLMISC::CVector &obsPos =  renderTrav.CamPos;
00407 
00408     // camera matrix in world space
00409     const NLMISC::CMatrix &camMat = renderTrav.CamMatrix;
00410 
00411     // view matrix (inverted cam matrix)
00412     const NLMISC::CMatrix &viewMat = renderTrav.ViewMatrix;
00413 
00414     // compute the camera matrix such as there is no rotation around the y axis
00415     NLMISC::CMatrix camMatUp;
00416     ComputeUpMatrix(camMat.getJ(), camMatUp, camMat);
00417     camMatUp.setPos(camMat.getPos());
00418 
00419     const NLMISC::CMatrix matViewUp = camMatUp.inverted();
00420 
00421     // plane z pos in world
00422     const float zHeight =  getWorldMatrix().getPos().z;
00423 
00424     const sint numStepX = CWaterShape::getScreenXGridSize();
00425     const sint numStepY = CWaterShape::getScreenYGridSize();
00426 
00427     const float invNumStepX = 1.f / numStepX;
00428     const float invNumStepY = 1.f / numStepY;
00429 
00430     const uint rotBorderSize = (shape->_MaxGridSize + (shape->_XGridBorder << 1) - numStepX) >> 1;
00431 
00432     const sint isAbove = obsPos.z > zHeight ? 1 : 0;
00433 
00434 
00435     #ifdef NO_WATER_TESSEL
00436         const float transitionDist  = renderTrav.Near * 0.99f;
00437     #else
00438         const float transitionDist  = shape->_TransitionRatio   * renderTrav.Far;
00439     #endif
00440 
00441 
00442     NLMISC::CMatrix modelMat;
00443     modelMat.setPos(NLMISC::CVector(obsPos.x, obsPos.y, zHeight));
00444     drv->setupModelMatrix(modelMat);
00445 
00446     //==================//
00447     // material setup   //
00448     //==================//
00449 
00450     CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(shape->_WaterPoolID);
00451 
00452     setupMaterialNVertexShader(drv, shape, obsPos, isAbove > 0, whm.getUnitSize() * (whm.getSize() >> 1), zHeight);
00453 
00454 
00455     drv->setupMaterial(CWaterModel::_WaterMat);
00456 
00457     sint numPass = drv->beginMaterialMultiPass();
00458     nlassert(numPass == 1); // for now, we assume water is always rendered in a single pass !
00459     drv->setupMaterialPass(0);
00460 
00461 
00462     //setAttenuationFactor(drv, false, obsPos, camMat.getJ(), farDist);
00463     //disableAttenuation(drv);
00464 
00465 
00466     //================================//
00467     //  Vertex buffer setup           //
00468     //================================//
00469 
00470     drv->activeVertexBuffer(shape->_VB);
00471 
00472     //================================//
00473     //  tesselated part of the poly   //
00474     //================================//
00475 
00476     if (_ClippedPoly.Vertices.size())
00477     {
00478         //======================================//
00479         // Polygon projection on the near plane //
00480         //======================================//
00481 
00482         static NLMISC::CPolygon2D projPoly; // projected poly
00483         projPoly.Vertices.resize(_ClippedPoly.Vertices.size());
00484         const float Near = renderTrav.Near;
00485 
00486 
00487         const float xFactor = numStepX * Near / (renderTrav.Right - renderTrav.Left);
00488         const float xOffset = numStepX * (-renderTrav.Left / (renderTrav.Right - renderTrav.Left)) + 0.5f;
00489         const float yFactor = numStepY * Near  / (renderTrav.Bottom - renderTrav.Top);
00490         const float yOffset = numStepY * (-renderTrav.Top / (renderTrav.Bottom - renderTrav.Top)) - 0.5f * isAbove;
00491 
00492         const NLMISC::CMatrix projMat =  matViewUp * getWorldMatrix();
00493         uint k;
00494         for (k = 0; k < _ClippedPoly.Vertices.size(); ++k)
00495         {
00496             // project points in the view
00497             NLMISC::CVector t = projMat * _ClippedPoly.Vertices[k];
00498             float invY = 1.f / t.y;
00499             projPoly.Vertices[k].set(xFactor * t.x * invY + xOffset, yFactor * t.z * invY + yOffset);
00500         }
00501 
00502         //=============================================//
00503         // compute borders of poly at a low resolution //
00504         //=============================================//
00505 
00506         NLMISC::CPolygon2D::TRasterVect rasters;
00507         sint startY;
00508         projPoly.computeBorders(rasters, startY);
00509 
00510         if (rasters.size())
00511         {
00512             //===========================//
00513             // perform Water animation   //
00514             //===========================//
00515 
00516             const float WaterRatio = whm.getUnitSize();
00517             const float invWaterRatio = 1.f / WaterRatio;
00518             const uint  WaterHeightMapSize = whm.getSize();
00519             const uint  doubleWaterHeightMapSize = (WaterHeightMapSize << 1);
00520 
00521 
00522             sint64 idate = getOwnerScene()->getHrcTrav().CurrentDate;
00523 
00524 
00525 
00526             if (idate != whm.Date)
00527             {
00528                 whm.setUserPos((sint) (obsPos.x * invWaterRatio) - (WaterHeightMapSize >> 1),
00529                        (sint) (obsPos.y * invWaterRatio) - (WaterHeightMapSize >> 1)
00530                       );
00531                 nlassert(getOwnerScene()); // this object should have been created from a CWaterShape!
00532                 whm.animate((float) (getOwnerScene()->getEllapsedTime()));
00533                 whm.Date = idate;
00534             }
00535 
00536             //float startDate = (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()));
00537 
00538             //=====================================//
00539             //  compute heightmap useful area      //
00540             //=====================================//
00541 
00542             // We don't store a heighmap for a complete Water area
00543             // we just consider the height of Water columns that are near the observer
00544             //
00545             // Compute a quad in Water height field space that contains the useful heights
00546             // This helps us to decide whether we should do a lookup in the height map
00547 
00548             sint mapPosX, mapPosY;
00549 
00552             whm.getUserPos(mapPosX, mapPosY);
00553 
00554             const uint mapBorder = 3;
00555 
00556             const sint qRight = (sint) mapPosX + WaterHeightMapSize - mapBorder;
00557                   sint qLeft  = (sint) mapPosX;
00558             const sint qUp    = (sint) mapPosY + WaterHeightMapSize - mapBorder;
00559                   sint qDown  = (sint) mapPosY;
00560 
00562             const sint qSubLeft = qLeft - (uint)  qLeft % WaterHeightMapSize;
00563             const sint qSubDown = qDown - (uint)  qDown % WaterHeightMapSize;
00564 
00565             qLeft += mapBorder;
00566             qDown += mapBorder;
00567 
00568             //==============================================//
00569             // setup rays to be traced, and their increment //
00570             //==============================================//
00571 
00572 
00573             // compute  camera rays in world space
00574             NLMISC::CVector currHV = renderTrav.Left * camMatUp.getI() + renderTrav.Near * camMatUp.getJ() + renderTrav.Top * camMatUp.getK(); // current border vector, incremented at each line
00575             NLMISC::CVector currV; // current ray vector
00576             NLMISC::CVector xStep = (renderTrav.Right - renderTrav.Left) * invNumStepX * camMatUp.getI();      // xStep for the ray vector
00577             NLMISC::CVector yStep = (renderTrav.Bottom - renderTrav.Top) * invNumStepY * camMatUp.getK();    // yStep for the ray vector
00578 
00579             //===============================================//
00580             //              perform display                  //
00581             //===============================================//
00582 
00583             // scale currHV at the top of the poly
00584             currHV += (startY - 0.5f  * isAbove) * yStep;
00585 
00586             // current index buffer used. We swap each time a row has been drawn
00587             CIndexBuffer *currIB = &CWaterShape::_IBUpDown, *otherIB = &CWaterShape::_IBDownUp;
00588 
00589 
00590             sint vIndex = 0; // index in vertices
00591 
00592             // current raster position
00593             sint oldStartX, oldEndX, realStartX, realEndX;
00594             //float invNearWidth = numStepX / (renderTrav.Right - renderTrav.Left);
00595 
00596                 //nlinfo("size = %d, maxSize = ", rasters.size(), numStepY);
00597 
00598 
00599             const uint wqHeight = rasters.size();
00600             if (wqHeight)
00601             {
00602                 // denominator of the intersection equation
00603                 const float denom = - obsPos.z + zHeight;
00604                 // test the upper raster
00605                 // if it is above the horizon, we modify it to reach the correct location
00606                 const float horizonEpsilon = 10E-4f; // we must be a little below the horizon
00607 
00608                 // distance from the viewer along the traced ray
00609                 float t;
00610 
00611                 NLMISC::CPolygon2D::TRasterVect::const_iterator it = rasters.begin();
00612                 for (uint l = 0; l <= wqHeight; ++l)
00613                 {
00614                     //nlinfo("start = %d, end = %d", it->first, it->second);
00615                     const sint startX = it->first;
00616                     const sint endX   = (it->second + 1);
00617 
00618                     nlassert(startX >= - (sint) rotBorderSize);
00619                     nlassert(endX  <= (sint) (numStepX + rotBorderSize));
00620 
00621                     if (l != 0)
00622                     {
00623                         realStartX = std::min(startX, oldStartX);
00624                         realEndX = std::max(endX, oldEndX);
00625                     }
00626                     else
00627                     {
00628                         realStartX = startX;
00629                         realEndX =   endX;
00630                     }
00631 
00632 
00633                     // current view vector
00634                     currV   = currHV + (realStartX - 0.5f) * xStep;
00635 
00636                     if (l == 0)
00637                     {
00638                         if (isAbove)
00639                         {
00640                             // test whether the first row is out of horizon.
00641                             // if this is the case, we make a correction
00642                             if (denom * currV.z <= 0)
00643                             {
00644                                 // correct for the first line only by adding a y offset
00645                                 currV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon)   - currV.z) / yStep.z;
00646                             }
00647 
00648                             // now, for the transition, check whether the first raster does not go over the transition dist
00649 
00650                             t = denom / currV.z;
00651                             const float VJ = camMat.getJ() * currV;
00652                             if ( t * VJ >  transitionDist)
00653                             {
00654                                 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currV.z);
00655                                 // correct the first line to reach that position
00656                                 currV += delta * yStep;
00657                             }
00658                         }
00659                     }
00660 
00661 
00662                     {
00663                         CVertexBufferReadWrite vba;
00664                         shape->_VB.lock (vba);
00665                         uint8 *vbPointer = (uint8 *) vba.getVertexCoordPointer() + shape->_VB.getVertexSize() * (vIndex + realStartX + rotBorderSize);
00666 
00667 
00668                         for (sint k = realStartX; k <= realEndX; ++k)
00669                         {
00670                             t =   denom / currV.z;
00671                             // compute intersection with plane
00672                             NLMISC::CVector inter = t * currV;
00673                             inter.z += obsPos.z;
00674                             SetupWaterVertex(qLeft, qRight, qUp, qDown, qSubLeft, qSubDown, inter, invWaterRatio, doubleWaterHeightMapSize, whm, vbPointer, obsPos.x, obsPos.y);
00675                             currV += xStep;
00676                         }
00677                     }
00678 
00679                     if (l != 0) // 2 line of the ib done ?
00680                     {
00681                         sint count = oldEndX - oldStartX;
00682                         if (count > 0)
00683                         {
00684                             drv->activeIndexBuffer(*currIB);
00685                             drv->renderSimpleTriangles((oldStartX + rotBorderSize) * 6, 2 * count );
00686                         }
00687                     }
00688 
00689                     oldStartX = startX;
00690                     oldEndX   = endX;
00691                     currHV    += yStep;
00692                     vIndex    = (numStepX + 2 * rotBorderSize + 1) - vIndex; // swap first row and second row
00693                     std::swap(currIB, otherIB);
00694                     if (l < (wqHeight - 1))
00695                     {
00696                         ++it;
00697                     }
00698                     else
00699                     {
00700                         if (!isAbove)
00701                         {
00702                             // last line
00703                             // test whether we are out of horizon
00704                             if (denom * currHV.z <= 0)
00705                             {
00706                                 // correct for the first line only by adding a y offset
00707                                 currHV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon)  - currHV.z) / yStep.z;
00708                             }
00709 
00710                             // now, for the transition, check whether the first raster does not go over the transition dist
00711 
00712                             t = denom / currHV.z;
00713                             const float VJ = camMat.getJ() * currHV;
00714                             if ( t * VJ >  transitionDist)
00715                             {
00716                                 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currHV.z);
00717                                 // correct the first line to reach that position
00718                                 currHV += delta * yStep;
00719                             }
00720                         }
00721 
00722                     }
00723                 }
00724 
00725             }
00726             //nlinfo("display: %f ms", (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()) - startDate));
00727         }
00728     }
00729 
00730     //=========================================//
00731     //          display end poly               //
00732     //=========================================//
00733 
00734     if (_EndClippedPoly.Vertices.size() != 0)
00735     {
00736 
00737         CMatrix xform = _WorldMatrix;
00738         xform.movePos(NLMISC::CVector(- obsPos.x, - obsPos.y, _WorldMatrix.getPos().z));
00739         DrawPoly2D(shape->_VB, drv, xform, _EndClippedPoly);
00740     }
00741 
00742     drv->endMaterialMultiPass();
00743 
00744 
00745     drv->activeVertexProgram(NULL);
00746 
00747 }
00748 */
00749 
00750 //***********************
00751 // Water MATERIAL SETUP //
00752 //***********************
00753 /*
00754 void CWaterModel::setupMaterialNVertexShader(IDriver *drv, CWaterShape *shape, const NLMISC::CVector &obsPos, bool above, float maxDist, float zHeight)
00755 {
00756     static bool matSetupped = false;
00757     if (!matSetupped)
00758     {
00759         _WaterMat.setLighting(false);
00760         _WaterMat.setDoubleSided(true);
00761         _WaterMat.setColor(NLMISC::CRGBA::White);
00762         _WaterMat.setBlend(true);
00763         _WaterMat.setSrcBlend(CMaterial::srcalpha);
00764         _WaterMat.setDstBlend(CMaterial::invsrcalpha);
00765         _WaterMat.setZWrite(true);
00766         _WaterMat.setShader(CMaterial::Water);
00767     }
00768 
00769 
00770     const uint cstOffset = 4; // 4 places for the matrix
00771     NLMISC::CVectorH cst[13];
00772 
00773 
00774     //=========================//
00775     //  setup Water material   //
00776     //=========================//
00777 
00778     CWaterModel::_WaterMat.setTexture(0, shape->_BumpMap[0]);
00779     CWaterModel::_WaterMat.setTexture(1, shape->_BumpMap[1]);
00780     CWaterModel::_WaterMat.setTexture(3, shape->_ColorMap);
00781 
00782     CScene *scene = getOwnerScene();
00783     if (!above && shape->_EnvMap[1])
00784     {
00785         if (shape->_UsesSceneWaterEnvMap[1])
00786         {
00787             if (scene->getWaterEnvMap())
00788             {
00789                 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
00790             }
00791             else
00792             {
00793                 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
00794             }
00795         }
00796         else
00797         {
00798             CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
00799         }
00800     }
00801     else
00802     {
00803         if (shape->_UsesSceneWaterEnvMap[0])
00804         {
00805             if (scene->getWaterEnvMap())
00806             {
00807                 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
00808             }
00809             else
00810             {
00811                 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
00812             }
00813         }
00814         else
00815         {
00816             CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
00817         }
00818     }
00819 
00820     shape->envMapUpdate();
00821 
00822     const uint alphaMapStage = 3;
00823     if (shape->_ColorMap)
00824     {
00825         //WaterMat.setTexture(alphaMapStage, shape->_ColorMap);
00826         //if (shape->_ColorMap->supportSharing()) nlinfo(shape->_ColorMap->getShareName().c_str());
00827 
00828 
00829         // setup 2x3 matrix for lookup in diffuse map
00830         updateDiffuseMapMatrix();
00831         cst[13 - cstOffset].set(_ColorMapMatColumn0.x, _ColorMapMatColumn1.x, 0, _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x);
00832         cst[14 - cstOffset].set(_ColorMapMatColumn0.y, _ColorMapMatColumn1.y, 0, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y);
00833     }
00834     else
00835     {
00836         cst[13 - cstOffset].set(0, 0, 0, 0);
00837         cst[14 - cstOffset].set(0, 0, 0, 0);
00838     }
00839 
00840     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
00841     // 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
00842 
00843     cst[5  - cstOffset].set(0.f, 0.f, 0.f, 0.f); // claping negative values to 0
00844 
00845     // slope of attenuation of normal / height with distance
00846     const float invMaxDist = shape->_WaveHeightFactor / maxDist;
00847     cst[6  - cstOffset].set(invMaxDist, shape->_WaveHeightFactor, 0, 0);
00848 
00850     drv->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
00851     drv->setConstantFog(18);
00852 
00853     // retrieve current time
00854     float date  = 0.001f * (NLMISC::CTime::getLocalTime() & 0xffffff); // must keep some precision.
00855     // set bumpmaps pos
00856     cst[9  - cstOffset].set(fmodf(obsPos.x * shape->_HeightMapScale[0].x, 1.f) + fmodf(date * shape->_HeightMapSpeed[0].x, 1.f), fmodf(shape->_HeightMapScale[0].y * obsPos.y, 1.f) + fmodf(date * shape->_HeightMapSpeed[0].y, 1.f), 0.f, 1.f); // bump map 0 offset
00857     cst[10  - cstOffset].set(shape->_HeightMapScale[0].x, shape->_HeightMapScale[0].y, 0, 0); // bump map 0 scale
00858     cst[11  - cstOffset].set(fmodf(shape->_HeightMapScale[1].x * obsPos.x, 1.f) + fmodf(date * shape->_HeightMapSpeed[1].x, 1.f), fmodf(shape->_HeightMapScale[1].y * obsPos.y, 1.f) + fmodf(date * shape->_HeightMapSpeed[1].y, 1.f), 0.f, 1.f); // bump map 1 offset
00859     cst[12  - cstOffset].set(shape->_HeightMapScale[1].x, shape->_HeightMapScale[1].y, 0, 0); // bump map 1 scale
00860 
00861     cst[4  - cstOffset].set(1.f, 1.f, 1.f, 1.f); // use with min man, and to get the 1 constant
00862     cst[7  - cstOffset].set(0, 0, obsPos.z - zHeight, 1.f);
00863     cst[8  - cstOffset].set(0.5f, 0.5f, 0.f, 1.f); // used to scale reflected ray into the envmap
00864 
00866     drv->setConstant(4, sizeof(cst) / sizeof(cst[0]), (float *) &cst[0]);
00867 
00868     shape->initVertexProgram();
00869     bool result;
00870 
00871     //if (useBumpedVersion)
00872     //{
00873     //  if (!useEMBM)
00874     //  {
00875     //      result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
00876     //                                      : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
00877     //  }
00878     //  else
00879     //  {
00880     //      result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump1Diffuse).get())
00881     //                                      : drv->activeVertexProgram((shape->_VertexProgramBump1).get());
00882     //  }
00883     //}
00884     //else
00885     //{
00886     //  result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramNoBumpDiffuse).get())
00887     //                              : drv->activeVertexProgram((shape->_VertexProgramNoBump).get());
00888     //}
00889 
00890     //result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
00891     //                                      : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
00892     //
00893     //if (!result) nlwarning("no vertex program setuped");
00894 }
00895 */
00896 
00897 
00898 
00899 void CWaterModel::setupMaterialNVertexShader(IDriver *drv, CWaterShape *shape, const NLMISC::CVector &obsPos, bool above, float zHeight)
00900 {
00901     static bool matSetupped = false;
00902     if (!matSetupped)
00903     {
00904         _WaterMat.setLighting(false);
00905         _WaterMat.setDoubleSided(true);
00906         _WaterMat.setColor(NLMISC::CRGBA::White);
00907         _WaterMat.setBlend(true);
00908         _WaterMat.setSrcBlend(CMaterial::srcalpha);
00909         _WaterMat.setDstBlend(CMaterial::invsrcalpha);
00910         _WaterMat.setZWrite(true);
00911         _WaterMat.setShader(CMaterial::Water);
00912     }
00913     const uint cstOffset = 5; // 4 places for the matrix
00914     NLMISC::CVectorH cst[13];
00915     //=========================//
00916     //  setup Water material   //
00917     //=========================//
00918     CWaterModel::_WaterMat.setTexture(0, shape->_BumpMap[0]);
00919     CWaterModel::_WaterMat.setTexture(1, shape->_BumpMap[1]);
00920     CWaterModel::_WaterMat.setTexture(3, shape->_ColorMap);
00921     CScene *scene = getOwnerScene();
00922     if (!above && shape->_EnvMap[1])
00923     {
00924         if (shape->_UsesSceneWaterEnvMap[1])
00925         {
00926             if (scene->getWaterEnvMap())
00927             {
00928                 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
00929             }
00930             else
00931             {
00932                 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
00933             }
00934         }
00935         else
00936         {
00937             CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
00938         }
00939     }
00940     else
00941     {
00942         if (shape->_UsesSceneWaterEnvMap[0])
00943         {
00944             if (scene->getWaterEnvMap())
00945             {
00946                 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
00947             }
00948             else
00949             {
00950                 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
00951             }
00952         }
00953         else
00954         {
00955             CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
00956         }
00957     }
00958     shape->envMapUpdate();
00959     if (shape->_ColorMap)
00960     {
00961         // setup 2x3 matrix for lookup in diffuse map
00962         updateDiffuseMapMatrix();
00963         cst[11].set(_ColorMapMatColumn0.x, _ColorMapMatColumn1.x, 0, _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x);
00964         cst[12].set(_ColorMapMatColumn0.y, _ColorMapMatColumn1.y, 0, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y);
00965     }
00967     drv->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
00968     // retrieve current time
00969     double date  = scene->getCurrentTime();
00970     // set bumpmaps pos
00971     cst[6].set(fmodf(obsPos.x * shape->_HeightMapScale[0].x, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[0].x, 1), fmodf(shape->_HeightMapScale[0].y * obsPos.y, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[0].y, 1), 0.f, 1.f); // bump map 0 offset
00972     cst[5].set(shape->_HeightMapScale[0].x, shape->_HeightMapScale[0].y, 0, 0); // bump map 0 scale
00973     cst[8].set(fmodf(shape->_HeightMapScale[1].x * obsPos.x, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[1].x, 1), fmodf(shape->_HeightMapScale[1].y * obsPos.y, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[1].y, 1), 0.f, 1.f); // bump map 1 offset
00974     cst[7].set(shape->_HeightMapScale[1].x, shape->_HeightMapScale[1].y, 0, 0); // bump map 1 scale
00975     cst[9].set(0, 0, obsPos.z - zHeight, 1.f);
00976     cst[10].set(0.5f, 0.5f, 0.f, 1.f); // used to scale reflected ray into the envmap
00978     drv->setConstant(cstOffset, sizeof(cst) / sizeof(cst[0]) - cstOffset, (float *) &cst[cstOffset]);
00979     shape->initVertexProgram();
00980     drv->activeVertexProgram(shape->_ColorMap ? CWaterShape::_VertexProgramNoWaveDiffuse.get() : CWaterShape::_VertexProgramNoWave.get());
00981     drv->setConstantFog(4);
00982 }
00983 
00984 //================================================
00985 void CWaterModel::setupSimpleRender(CWaterShape *shape, const NLMISC::CVector &obsPos, bool above)
00986 {
00987     // rendering of water when no vertex / pixel shaders are available
00988     static bool init = false;
00989     if (!init)
00990     {
00991         // setup the material, no special shader is used here
00992         _SimpleWaterMat.setLighting(false);
00993         _SimpleWaterMat.setDoubleSided(true);
00994         _SimpleWaterMat.setColor(NLMISC::CRGBA::White);
00995 
00996         _SimpleWaterMat.setBlend(true);
00997         _SimpleWaterMat.setSrcBlend(CMaterial::srcalpha);
00998         _SimpleWaterMat.setDstBlend(CMaterial::invsrcalpha);
00999         _SimpleWaterMat.setZWrite(true);
01000         _SimpleWaterMat.setShader(CMaterial::Normal);
01001 
01002         // stage 0
01003         _SimpleWaterMat.texEnvOpRGB(0, CMaterial::Replace);
01004         _SimpleWaterMat.texEnvOpAlpha(0, CMaterial::Replace);
01005         _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
01006         _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
01007 
01008         // stage 1
01009         _SimpleWaterMat.texEnvOpRGB(1, CMaterial::Modulate);
01010         _SimpleWaterMat.texEnvOpAlpha(1, CMaterial::Modulate);
01011         _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
01012         _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
01013         _SimpleWaterMat.texEnvArg1RGB(0, CMaterial::Previous, CMaterial::SrcColor);
01014         _SimpleWaterMat.texEnvArg1Alpha(0, CMaterial::Previous, CMaterial::SrcAlpha);
01015 
01016         init = true;
01017     }
01018     // envmap is always present and is in stage 0
01019     CScene *scene = getOwnerScene();
01020     if (!above && shape->_EnvMap[1])
01021     {
01022         if (shape->_UsesSceneWaterEnvMap[1])
01023         {
01024             if (scene->getWaterEnvMap())
01025             {
01026                 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
01027             }
01028             else
01029             {
01030                 _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
01031             }
01032         }
01033         else
01034         {
01035             _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
01036         }
01037     }
01038     else
01039     {
01040         if (shape->_UsesSceneWaterEnvMap[0])
01041         {
01042             if (scene->getWaterEnvMap())
01043             {
01044                 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
01045             }
01046             else
01047             {
01048                 _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
01049             }
01050         }
01051         else
01052         {
01053             _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
01054         }
01055     }
01056     //
01057     if (shape->_ColorMap == NULL)
01058     {
01059         // version with no color map
01060         if (!_EmbossTexture)
01061         {
01062             _EmbossTexture = new CTextureEmboss;
01063             _EmbossTexture->setSlopeFactor(4.f);
01064         }
01065         if (shape->_BumpMap[1] && shape->_BumpMap[1]->isBumpMap())
01066         {
01067             CTextureBump *bm = static_cast<CTextureBump *>((ITexture *) shape->_BumpMap[1]);
01068             if (bm->getHeightMap())
01069             {
01070                 _EmbossTexture->setHeightMap(bm->getHeightMap());
01071             }
01072         }
01073         _SimpleWaterMat.setTexture(1, _EmbossTexture);
01074         _SimpleWaterMat.setTexCoordGen(1, true);
01075         _SimpleWaterMat.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace);
01076         double date  = scene->getCurrentTime();
01077         CMatrix texMat;
01078         texMat.scale(CVector(shape->_HeightMapScale[1].x, shape->_HeightMapScale[1].y, 1.f));
01079         texMat.setPos(CVector(fmodf(shape->_HeightMapScale[1].x * obsPos.x, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[1].x, 1),
01080                       fmodf(shape->_HeightMapScale[1].y * obsPos.y, 1.f) + (float) fmod(date * shape->_HeightMapSpeed[1].y, 1),
01081                       1.f)
01082                      );
01083         _SimpleWaterMat.enableUserTexMat(1, true);
01084         _SimpleWaterMat.setUserTexMat(1, texMat);
01085     }
01086     else
01087     {
01088         updateDiffuseMapMatrix();
01089         // version with a color map : it remplace the emboss texture
01090         _SimpleWaterMat.setTexture(1, shape->_ColorMap);
01091         _SimpleWaterMat.setTexCoordGen(1, true);
01092         _SimpleWaterMat.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace);
01093         CMatrix texMat;
01094         /*
01095         float mat[16] =
01096         {
01097             _ColorMapMatColumn0.x, _ColorMapMatColumn1.x, 0, _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x},
01098             _ColorMapMatColumn0.y, _ColorMapMatColumn1.y, 0, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y,
01099             0.f, 0.f, 1.f, 0.f,
01100             0.f, 0.f, 0.f, 1.f
01101         }
01102         */
01103         float mat[16] =
01104         {
01105             _ColorMapMatColumn0.x, _ColorMapMatColumn0.y, 0.f, 0.f,
01106             _ColorMapMatColumn1.x, _ColorMapMatColumn1.y, 0.f, 0.f,
01107             0.f,                   0.f,                   1.f, 0.f,
01108             _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y, 0.f, 1.f
01109         };
01110         texMat.set(mat);
01111         _SimpleWaterMat.enableUserTexMat(1, true);
01112         _SimpleWaterMat.setUserTexMat(1, texMat);
01113     }
01114 }
01115 
01116 
01117 //================================================
01118 void CWaterModel::computeClippedPoly()
01119 {
01120     CWaterShape *shape = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
01121     const std::vector<CPlane>   &worldPyramid   = getOwnerScene()->getClipTrav().WorldFrustumPyramid;
01122     _ClippedPoly.Vertices.resize(shape->_Poly.Vertices.size());
01123     uint k;
01124     for (k = 0; k < shape->_Poly.Vertices.size(); ++k)
01125     {
01126         _ClippedPoly.Vertices[k].set(shape->_Poly.Vertices[k].x,
01127                                      shape->_Poly.Vertices[k].y,
01128                                      0.f
01129                                     );
01130     }
01131     /*
01132     NLMISC::CPlane plvect[6];
01133     const NLMISC::CMatrix &viewMat = clipTrav.ViewMatrix;
01134 
01135     const sint numStepX = CWaterShape::getScreenXGridSize();
01136     const sint numStepY = CWaterShape::getScreenYGridSize();
01137     // Build the view pyramid. We need to rebuild it because we use a wider one to avoid holes on the border of the screen due to water animation
01138     float centerX = 0.5f  * (clipTrav.Right + clipTrav.Left);
01139     const float fRight = centerX + (clipTrav.Right -  centerX) * (-(float) CWaterShape::_XGridBorder +  (float) numStepX) / numStepX;
01140     const float fLeft = centerX + (clipTrav.Left -  centerX) * (-(float) CWaterShape::_XGridBorder +  (float) numStepX) / numStepX;
01141     float centerY = 0.5f  * (clipTrav.Bottom + clipTrav.Top);
01142     const float fTop   = centerY + (clipTrav.Top - centerY)  * (-(float) CWaterShape::_YGridBorder +  (float) numStepY) / numStepY;
01143     const float fBottom   = centerY + (clipTrav.Bottom - centerY)  * (-(float) CWaterShape::_YGridBorder +  (float) numStepY) / numStepY;
01144     // build pyramid corners
01145     const float nearDist        = clipTrav.Near;
01146     const float farDist         = clipTrav.Far;
01147     //
01148     const NLMISC::CVector       pfoc(0,0,0);
01149     const NLMISC::CVector       lb( fLeft,  nearDist, fBottom );
01150     const NLMISC::CVector       lt( fLeft,  nearDist, fTop  );
01151     const NLMISC::CVector       rb( fRight,  nearDist, fBottom );
01152     const NLMISC::CVector       rt(fRight,  nearDist, fTop  );
01153     const NLMISC::CVector       lbfarDist(fLeft, farDist, fBottom);
01154     const NLMISC::CVector       ltfarDist(fLeft, farDist, fTop );
01155     const NLMISC::CVector       rtfarDist(fRight , farDist, fTop  );
01156     //
01157     plvect[0].make(lt, lb, rt);                         // near plane
01158     plvect[1].make(lbfarDist, ltfarDist, rtfarDist);    // far plane
01159     plvect[2].make(pfoc, lt, lb);
01160     plvect[3].make(pfoc, rt, lt);
01161     plvect[4].make(pfoc, rb, rt);
01162     plvect[5].make(pfoc, lb, rb);
01163     const NLMISC::CMatrix pyramidMat = viewMat * getWorldMatrix();
01164     for (k = 0; k < worldPyramid.size(); ++k)
01165     {
01166         plvect[k] = plvect[k] * pyramidMat; // put the plane in object space
01167     }
01168     _ClippedPoly.clip(plvect, 6);
01169     */
01170     static std::vector<CPlane> tp;
01171     tp.resize(worldPyramid.size());
01172     for(uint k = 0; k < tp.size(); ++k)
01173     {
01174         tp[k] = worldPyramid[k] * getWorldMatrix();
01175     }
01176     _ClippedPoly.clip(tp);
01177 }
01178 
01179 //***********************************************************************************************************
01180 void CWaterModel::unlink()
01181 {
01182     if (!_Prev)
01183     {
01184         nlassert(!_Next);
01185         return;
01186     }
01187     if (_Next)
01188     {
01189         _Next->_Prev = _Prev;
01190     }
01191     *_Prev = _Next;
01192     _Next = NULL;
01193     _Prev = NULL;
01194 }
01195 
01196 //***********************************************************************************************************
01197 void CWaterModel::link()
01198 {
01199     nlassert(_Next == NULL);
01200     CScene *scene = getOwnerScene();
01201     nlassert(scene);
01202     CRenderTrav &rt = scene->getRenderTrav();
01203     _Prev = &rt._FirstWaterModel;
01204     _Next = rt._FirstWaterModel;
01205     if (_Next)
01206     {
01207         _Next->_Prev = &_Next;
01208     }
01209     rt._FirstWaterModel = this;
01210 }
01211 
01212 
01213 
01214 //***********************************************************************************************************
01215 uint CWaterModel::getNumWantedVertices()
01216 {
01217     H_AUTO( NL3D_Water_Render );
01218     nlassert(!_ClippedPoly.Vertices.empty());
01219     //
01220     CRenderTrav                 &renderTrav     = getOwnerScene()->getRenderTrav();
01221     if (!renderTrav.Perspective || forceWaterSimpleRender) return 0;
01222     // viewer pos in world space
01223     const NLMISC::CVector &obsPos = renderTrav.CamPos;
01224     // view matrix (inverted cam matrix)
01225     const NLMISC::CMatrix &viewMat = renderTrav.ViewMatrix;
01226     // plane z pos in world
01227     const float zHeight =  getWorldMatrix().getPos().z;
01228     const sint numStepX = CWaterShape::getScreenXGridSize();
01229     const sint numStepY = CWaterShape::getScreenYGridSize();
01230     NLMISC::CMatrix modelMat;
01231     modelMat.setPos(NLMISC::CVector(obsPos.x, obsPos.y, zHeight));
01232     static NLMISC::CPolygon2D projPoly; // projected poly
01233     projPoly.Vertices.resize(_ClippedPoly.Vertices.size());
01234     // factor to project to grid units
01235     const float xFactor = numStepX * renderTrav.Near / (renderTrav.Right - renderTrav.Left);
01236     const float yFactor = numStepY * renderTrav.Near  / (renderTrav.Top - renderTrav.Bottom);
01237     // project poly on near plane
01238     const NLMISC::CMatrix &projMat =  viewMat * getWorldMatrix();
01239     uint k;
01240     for (k = 0; k < _ClippedPoly.Vertices.size(); ++k)
01241     {
01242         // project points in the view
01243         NLMISC::CVector t = projMat * _ClippedPoly.Vertices[k];
01244         float invY = 1.f / t.y;
01245         projPoly.Vertices[k].set(xFactor * t.x * invY, yFactor * t.z * invY);
01246     }
01247     // compute grid cells that are entirely inside
01248     projPoly.computeInnerBorders(_Inside, _MinYInside);
01249     // compute grid cells that are touched
01250     static NLMISC::CPolygon2D::TRasterVect border;
01251     sint minYBorder;
01252     projPoly.computeOuterBorders(border, minYBorder);
01253     // border - inside -> gives grid cells that must be clipped to fit the shape boundaries
01254     // Make sure that rasters  array for inside has the same size that raster array for borders (by inserting NULL rasters)
01255     sint height = border.size();
01256     if (_Inside.empty())
01257     {
01258         _MinYInside = minYBorder;
01259     }
01260     sint bottomGap = border.size() - _Inside.size();
01261     _Inside.resize(height);
01262     nlassert(minYBorder == _MinYInside);
01263 
01264     nlassert(bottomGap >= 0);
01265     if (bottomGap)
01266     {
01267         for(sint y = height - bottomGap; y < height; ++y)
01268         {
01269             nlassert (y >= 0 && y < (sint)_Inside.size());
01270             _Inside[y].first =  border[y].first;
01271             _Inside[y].second = border[y].first - 1; // insert null raster
01272         }
01273     }
01274     //
01275     for(sint y = 0; y < height - bottomGap; ++y)
01276     {
01277         if (_Inside[y].first > _Inside[y].second)
01278         {
01279             nlassert (y >= 0 && y < (sint)_Inside.size());
01280             _Inside[y].first =  border[y].first;
01281             _Inside[y].second = border[y].first - 1;
01282         }
01283         else if (border[y].first > border[y].second)
01284         {
01285             nlassert (y >= 0 && y < (sint)_Inside.size());
01286             border[y].first = _Inside[y].first;
01287             border[y].second = _Inside[y].first - 1;
01288         }
01289     }
01290     // compute clip planes
01291     static std::vector<CPlane> clipPlanes;
01292 
01293     const CVector2f *prevVert = &projPoly.Vertices.back();
01294     const CVector2f *currVert = &projPoly.Vertices.front();
01295     uint numVerts = projPoly.Vertices.size();
01296     bool ccw = projPoly.isCCWOriented();
01297     clipPlanes.resize(numVerts);
01298     for(uint k = 0; k < numVerts; ++k)
01299     {
01300         NLMISC::CVector v0;
01301         NLMISC::CVector v1;
01302         NLMISC::CVector v2;
01303         v0.set(prevVert->x, prevVert->y, 0.f);
01304         v1.set(currVert->x, currVert->y, 0.f);
01305         v2.set(prevVert->x, prevVert->y, (*currVert - *prevVert).norm());
01306         clipPlanes[k].make(v0, v1, v2);
01307         if (!ccw)
01308         {
01309             clipPlanes[k].invert();
01310         }
01311         prevVert = currVert;
01312         ++ currVert;
01313     }
01314     // compute clipped tris
01315     _ClippedTriNumVerts.clear();
01316     _ClippedTris.clear();
01317     static NLMISC::CPolygon clipPoly;
01318     uint totalNumVertices = 0;
01319     // compute number of vertices for whole grid cells
01320     for(sint k = 0; k < (sint) border.size(); ++k)
01321     {
01322         // left clipped blocks
01323         for (sint x = border[k].first; x < _Inside[k].first; ++x)
01324         {
01325             clipPoly.Vertices.resize(4);
01326             clipPoly.Vertices[0].set((float) x, (float) (k + _MinYInside), 0.f);
01327             clipPoly.Vertices[1].set((float) (x + 1), (float) (k + _MinYInside), 0.f);
01328             clipPoly.Vertices[2].set((float) (x + 1), (float) (k + _MinYInside + 1), 0.f);
01329             clipPoly.Vertices[3].set((float) x, (float) (k + _MinYInside + 1), 0.f);
01330             clipPoly.clip(clipPlanes);
01331             if (!clipPoly.Vertices.empty())
01332             {
01333                 // backup result (will be unprojected later)
01334                 _ClippedTriNumVerts.push_back(clipPoly.Vertices.size());
01335                 uint prevSize = _ClippedTris.size();
01336                 _ClippedTris.resize(_ClippedTris.size() + clipPoly.Vertices.size());
01337                 std::copy(clipPoly.Vertices.begin(), clipPoly.Vertices.end(), _ClippedTris.begin() + prevSize); // append to packed list
01338                 totalNumVertices += (clipPoly.Vertices.size() - 2) * 3;
01339             }
01340         }
01341         // middle block, are not clipped, but count the number of wanted vertices
01342         if (_Inside[k].first <= _Inside[k].second)
01343         {
01344             totalNumVertices += 6 * (_Inside[k].second - _Inside[k].first + 1);
01345         }
01346         // right clipped blocks
01347         for (sint x = _Inside[k].second + 1; x <= border[k].second; ++x)
01348         {
01349             clipPoly.Vertices.resize(4);
01350             clipPoly.Vertices[0].set((float) x, (float)  (k + _MinYInside), 0.f);
01351             clipPoly.Vertices[1].set((float) (x + 1), (float)  (k + _MinYInside), 0.f);
01352             clipPoly.Vertices[2].set((float) (x + 1), (float)  (k + _MinYInside + 1), 0.f);
01353             clipPoly.Vertices[3].set((float) x, (float)  (k + _MinYInside + 1), 0.f);
01354             clipPoly.clip(clipPlanes);
01355             if (!clipPoly.Vertices.empty())
01356             {
01357                 // backup result (will be unprojected later)
01358                 _ClippedTriNumVerts.push_back(clipPoly.Vertices.size());
01359                 uint prevSize = _ClippedTris.size();
01360                 _ClippedTris.resize(_ClippedTris.size() + clipPoly.Vertices.size());
01361                 std::copy(clipPoly.Vertices.begin(), clipPoly.Vertices.end(), _ClippedTris.begin() + prevSize); // append to packed list
01362                 totalNumVertices += (clipPoly.Vertices.size() - 2) * 3;
01363             }
01364         }
01365     }
01366     return totalNumVertices;
01367 }
01368 
01369 //***********************************************************************************************************
01370 uint CWaterModel::fillVB(void *datas, uint startTri, IDriver &drv)
01371 {
01372     H_AUTO( NL3D_Water_Render );
01373     if (drv.isWaterShaderSupported())
01374     {
01375         return fillVBHard(datas, startTri);
01376     }
01377     else
01378     {
01379         return fillVBSoft(datas, startTri);
01380     }
01381 }
01382 
01383 
01384 
01385 static const double WATER_WAVE_SPEED = 1.7;
01386 static const double WATER_WAVE_SCALE = 0.05;
01387 static const double WATER_WAVE_FREQ = 0.3;
01388 static const float WATER_WAVE_ATTEN = 0.2f;
01389 
01390 
01391 
01392 
01393 // compute single water vertex in software mode
01394 static
01395 #ifndef NL_DEBUG
01396     inline
01397 #endif
01398 void computeWaterVertexSoft(float px, float py, CVector &pos, CVector2f &envMapTexCoord, const CVector &camI, const CVector &camJ, const CVector &camK, float denom, double date, const CVector &camPos)
01399 {
01400     CVector d = px * camI + py * camK + camJ;
01401     //nlassert(d.z > 0.f);
01402     float intersectionDist = denom / d.z;
01403     pos.x  = intersectionDist * d.x;
01404     pos.y  = intersectionDist * d.y;
01405     pos.z  = 0.f;
01406     //
01407     CVector R(- pos.x,
01408               - pos.y,
01409               - denom
01410              );
01411     float dist = R.norm();
01412     if (dist)
01413     {
01414         R /= dist;
01415     }
01416     envMapTexCoord.set(- 0.5f * R.x + 0.5f, - 0.5f * R.y + 0.5f);
01417     if (dist)
01418     {
01419         float invDist = 1.f / (WATER_WAVE_ATTEN * dist);
01420         if (invDist > 1.f) invDist = 1.f;
01421         // TODO : optimize cos if need (for now there are not much call per frame ...)
01422         envMapTexCoord.x += (float) (invDist * WATER_WAVE_SCALE * (float) cos(date + WATER_WAVE_FREQ * (camPos.x + pos.x)));
01423     }
01424 }
01425 
01426 //***********************************************************************************************************
01427 uint CWaterModel::fillVBSoft(void *datas, uint startTri)
01428 {
01429     _StartTri = (uint32) startTri;
01430     CRenderTrav           &renderTrav       = getOwnerScene()->getRenderTrav();
01431     const NLMISC::CMatrix &camMat = renderTrav.CamMatrix;
01432     const sint numStepX = CWaterShape::getScreenXGridSize();
01433     const sint numStepY = CWaterShape::getScreenYGridSize();
01434     CVector camI = camMat.getI() * (1.f / numStepX) * (renderTrav.Right - renderTrav.Left) / renderTrav.Near;
01435     CVector camJ = camMat.getJ();
01436     CVector camK = camMat.getK() * (1.f / numStepY) * (renderTrav.Top - renderTrav.Bottom) / renderTrav.Near;
01437     float obsZ = camMat.getPos().z;
01438     float denom = getWorldMatrix().getPos().z - obsZ;
01439     uint8 *dest = (uint8 *) datas + startTri * 3 * WATER_VERTEX_SOFT_SIZE;
01440     /*NLMISC::CVector eye = renderTrav.CamPos;
01441     eye.z -= getWorldMatrix().getPos().z;   */
01442     NLMISC::CVector eye(0.f, 0.f, - denom);
01443     CVector R;
01444     CScene *scene = getOwnerScene();
01445     double date = WATER_WAVE_SPEED * scene->getCurrentTime();
01446     if (!_ClippedTriNumVerts.empty())
01447     {
01448         const CVector2f *currVert =  &_ClippedTris.front();
01449         static std::vector<CVector> unprojectedTriSoft;
01450         static std::vector<CVector2f> envMap;
01451         for(uint k = 0; k < _ClippedTriNumVerts.size(); ++k)
01452         {
01453             unprojectedTriSoft.resize(_ClippedTriNumVerts[k]);
01454             envMap.resize(_ClippedTriNumVerts[k]);
01455             uint numVerts = _ClippedTriNumVerts[k];
01456             for(uint l = 0; l < _ClippedTriNumVerts[k]; ++l)
01457             {
01458                 computeWaterVertexSoft(currVert->x, currVert->y, unprojectedTriSoft[l], envMap[l], camI, camJ, camK, denom, date, camMat.getPos());
01459                 ++ currVert;
01460             }
01461             for(uint l = 0; l < numVerts - 2; ++l)
01462             {
01463                 *(CVector *) dest = unprojectedTriSoft[0];
01464                 dest += sizeof(float[3]);
01465                 *(CVector2f *) dest = envMap[0];
01466                 dest += sizeof(float[2]);
01467                 *(CVector *) dest = unprojectedTriSoft[l + 1];
01468                 dest += sizeof(float[3]);
01469                 *(CVector2f *) dest = envMap[l + 1];
01470                 dest += sizeof(float[2]);
01471                 *(CVector *) dest = unprojectedTriSoft[l + 2];
01472                 dest += sizeof(float[3]);
01473                 *(CVector2f *) dest = envMap[l + 2];
01474                 dest += sizeof(float[2]);
01475             }
01476         }
01477     }
01478     //  TODO : optimize if needed
01479     for(sint k = 0; k < (sint) _Inside.size(); ++k)
01480     {
01481         sint y = k + _MinYInside;
01482         CVector proj[4];
01483         CVector2f envMap[4];
01484         if (_Inside[k].first <= _Inside[k].second)
01485         {
01486             // middle block, are not clipped, but count the number of wanted vertices
01487             for(sint x = _Inside[k].first; x <= _Inside[k].second; ++x)
01488             {
01489                 computeWaterVertexSoft((float) x, (float) y, proj[0], envMap[0], camI, camJ, camK, denom, date, camMat.getPos());
01490                 computeWaterVertexSoft((float)(x + 1), (float) y, proj[1], envMap[1], camI, camJ, camK, denom, date, camMat.getPos());
01491                 computeWaterVertexSoft((float) (x + 1), (float) (y + 1), proj[2], envMap[2], camI, camJ, camK, denom, date, camMat.getPos());
01492                 computeWaterVertexSoft((float) x, (float) (y + 1), proj[3], envMap[3], camI, camJ, camK, denom, date, camMat.getPos());
01493                 //
01494                 *(CVector *) dest = proj[0];
01495                 dest += sizeof(float[3]);
01496                 *(CVector2f *) dest = envMap[0];
01497                 dest += sizeof(float[2]);
01498                 *(CVector *) dest = proj[2];
01499                 dest += sizeof(float[3]);
01500                 *(CVector2f *) dest = envMap[2];
01501                 dest += sizeof(float[2]);
01502                 *(CVector *) dest = proj[1];
01503                 dest += sizeof(float[3]);
01504                 *(CVector2f *) dest = envMap[1];
01505                 dest += sizeof(float[2]);
01506                 *(CVector *) dest = proj[0];
01507                 dest += sizeof(float[3]);
01508                 *(CVector2f *) dest = envMap[0];
01509                 dest += sizeof(float[2]);
01510                 *(CVector *) dest = proj[3];
01511                 dest += sizeof(float[3]);
01512                 *(CVector2f *) dest = envMap[3];
01513                 dest += sizeof(float[2]);
01514                 *(CVector *) dest = proj[2];
01515                 dest += sizeof(float[3]);
01516                 *(CVector2f *) dest = envMap[2];
01517                 dest += sizeof(float[2]);
01518             }
01519         }
01520     }
01521     nlassert((dest - (uint8 * ) datas) % (3 * WATER_VERTEX_SOFT_SIZE) == 0);
01522     uint endTri = (dest - (uint8 * ) datas) / (3 * WATER_VERTEX_SOFT_SIZE);
01523     _NumTris = endTri - _StartTri;
01524     return endTri;
01525 }
01526 
01527 // compute single water vertex for hardware render
01528 static
01529 #ifndef NL_DEBUG
01530 inline
01531 #endif
01532 void computeWaterVertexHard(float px, float py, CVector &pos, const CVector &camI, const CVector &camJ, const CVector &camK, float denom)
01533 {
01534     CVector d = px * camI + py * camK + camJ;
01535     float intersectionDist = denom / d.z;
01536     pos.x  = intersectionDist * d.x;
01537     pos.y  = intersectionDist * d.y;
01538     pos.z  = 0.f;
01539 }
01540 
01541 //***********************************************************************************************************
01542 uint CWaterModel::fillVBHard(void *datas, uint startTri)
01543 {
01544     _StartTri = (uint32) startTri;
01545     CRenderTrav           &renderTrav       = getOwnerScene()->getRenderTrav();
01546     const NLMISC::CMatrix &camMat = renderTrav.CamMatrix;
01547     const sint numStepX = CWaterShape::getScreenXGridSize();
01548     const sint numStepY = CWaterShape::getScreenYGridSize();
01549     CVector camI = camMat.getI() * (1.f / numStepX) * (renderTrav.Right - renderTrav.Left) / renderTrav.Near;
01550     CVector camJ = camMat.getJ();
01551     CVector camK = camMat.getK() * (1.f / numStepY) * (renderTrav.Top - renderTrav.Bottom) / renderTrav.Near;
01552     float obsZ = camMat.getPos().z;
01553     float denom = getWorldMatrix().getPos().z - obsZ;
01554     uint8 *dest = (uint8 *) datas + startTri * WATER_VERTEX_HARD_SIZE * 3;
01555     if (!_ClippedTriNumVerts.empty())
01556     {
01557         const CVector2f *currVert =  &_ClippedTris.front();
01558         static std::vector<CVector> unprojectedTri;
01559         for(uint k = 0; k < _ClippedTriNumVerts.size(); ++k)
01560         {
01561             unprojectedTri.resize(_ClippedTriNumVerts[k]);
01562             uint numVerts = _ClippedTriNumVerts[k];
01563             for(uint l = 0; l < _ClippedTriNumVerts[k]; ++l)
01564             {
01565                 computeWaterVertexHard(currVert->x, currVert->y, unprojectedTri[l], camI, camJ, camK, denom);
01566                 ++ currVert;
01567             }
01568             for(uint l = 0; l < numVerts - 2; ++l)
01569             {
01570                 *(CVector *) dest = unprojectedTri[0];
01571                 dest += WATER_VERTEX_HARD_SIZE;
01572                 *(CVector *) dest = unprojectedTri[l + 1];
01573                 dest += WATER_VERTEX_HARD_SIZE;
01574                 *(CVector *) dest = unprojectedTri[l + 2];
01575                 dest += WATER_VERTEX_HARD_SIZE;
01576             }
01577         }
01578     }
01579     //  TODO : optimize if needed
01580     for(sint k = 0; k < (sint) _Inside.size(); ++k)
01581     {
01582         sint y = k + _MinYInside;
01583         CVector proj[4];
01584         if (_Inside[k].first <= _Inside[k].second)
01585         {
01586             // middle block, are not clipped, but count the number of wanted vertices
01587             for(sint x = _Inside[k].first; x <= _Inside[k].second; ++x)
01588             {
01589                 computeWaterVertexHard((float) x, (float) y, proj[0], camI, camJ, camK, denom);
01590                 computeWaterVertexHard((float) (x + 1), (float) y, proj[1], camI, camJ, camK, denom);
01591                 computeWaterVertexHard((float) (x + 1), (float) (y + 1), proj[2], camI, camJ, camK, denom);
01592                 computeWaterVertexHard((float) x, (float) (y + 1), proj[3], camI, camJ, camK, denom);
01593                 //
01594                 *(CVector *) dest = proj[0];
01595                 dest += WATER_VERTEX_HARD_SIZE;
01596                 *(CVector *) dest = proj[2];
01597                 dest += WATER_VERTEX_HARD_SIZE;
01598                 *(CVector *) dest = proj[1];
01599                 dest += WATER_VERTEX_HARD_SIZE;
01600                 *(CVector *) dest = proj[0];
01601                 dest += WATER_VERTEX_HARD_SIZE;
01602                 *(CVector *) dest = proj[3];
01603                 dest += WATER_VERTEX_HARD_SIZE;
01604                 *(CVector *) dest = proj[2];
01605                 dest += WATER_VERTEX_HARD_SIZE;
01606             }
01607         }
01608     }
01609     nlassert((dest - (uint8 * ) datas) % (3 * WATER_VERTEX_HARD_SIZE) == 0);
01610     uint endTri = (dest - (uint8 * ) datas) / (3 * WATER_VERTEX_HARD_SIZE);
01611     _NumTris = endTri - _StartTri;
01612     return endTri;
01613 }
01614 
01615 
01616 
01617 
01618 
01619 //***************************************************************************************************************
01620 void    CWaterModel::traverseRender()
01621 {
01622     H_AUTO( NL3D_Water_Render );
01623 
01624     CRenderTrav                 &renderTrav     = getOwnerScene()->getRenderTrav();
01625     IDriver                     *drv            = renderTrav.getDriver();
01626     CWaterShape                 *shape          = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
01627     const NLMISC::CVector       &obsPos         = renderTrav.CamPos;
01628     const float                 zHeight         =  getWorldMatrix().getPos().z;
01629 
01630     if (!renderTrav.Perspective || forceWaterSimpleRender)
01631     {
01632         // not supported, simple uniform render
01633         drv->setupModelMatrix(getWorldMatrix());
01634         static CMaterial waterMat;
01635         static bool initDone = false;
01636         if (!initDone)
01637         {
01638             waterMat.initUnlit();
01639             waterMat.setBlend(true);
01640             waterMat.setSrcBlend(CMaterial::srcalpha);
01641             waterMat.setDstBlend(CMaterial::invsrcalpha);
01642             waterMat.setBlend(true);
01643             waterMat.setDoubleSided(true);
01644             waterMat.setLighting(false);
01645         }
01646         waterMat.setColor(shape->computeEnvMapMeanColor());
01647         static std::vector<NLMISC::CTriangleUV> tris;
01648         const NLMISC::CPolygon2D &poly = shape->getShape();
01649         tris.clear();
01650         for(sint k = 0; k < (sint) poly.Vertices.size() - 2; ++k)
01651         {
01652             NLMISC::CTriangleUV truv;
01653             truv.V0.set(poly.Vertices[0].x, poly.Vertices[0].y, 0.f);
01654             truv.V1.set(poly.Vertices[k + 1].x, poly.Vertices[k + 1].y, 0.f);
01655             truv.V2.set(poly.Vertices[k + 2].x, poly.Vertices[k + 2].y, 0.f);
01656             tris.push_back(truv);
01657         }
01658         CDRU::drawTrianglesUnlit(tris, waterMat, *drv);
01659     }
01660     else
01661     {
01662         NLMISC::CMatrix modelMat;
01663         modelMat.setPos(NLMISC::CVector(obsPos.x, obsPos.y, zHeight));
01664         drv->setupModelMatrix(modelMat);
01665         bool isAbove = obsPos.z > getWorldMatrix().getPos().z;
01666         CVertexBuffer &vb = renderTrav.Scene->getWaterVB();
01667         if (drv->isWaterShaderSupported())
01668         {
01669             setupMaterialNVertexShader(drv, shape, obsPos, isAbove, zHeight);
01670             nlassert(vb.getNumVertices() > 0);
01671             drv->activeVertexBuffer(vb);
01672             drv->renderRawTriangles(CWaterModel::_WaterMat, _StartTri, _NumTris);
01673             drv->activeVertexProgram(NULL);
01674         }
01675         else
01676         {
01677             setupSimpleRender(shape, obsPos, isAbove);
01678             drv->activeVertexBuffer(vb);
01679             drv->activeVertexProgram(NULL);
01680             drv->renderRawTriangles(CWaterModel::_SimpleWaterMat, _StartTri, _NumTris);
01681         }
01682     }
01683 }
01684 
01685 
01686 
01687 //***********************************************************************************************************
01688 bool CWaterModel::clip()
01689 {
01690     H_AUTO( NL3D_Water_Render );
01691     CRenderTrav         &renderTrav= getOwnerScene()->getRenderTrav();
01692     if (renderTrav.CamPos.z == getWorldMatrix().getPos().z) return false;
01693     if(Shape)
01694     {
01695         computeClippedPoly();
01696         if (_ClippedPoly.Vertices.empty()) return false;
01697         // unlink from water model list
01698         unlink();
01699         // link into water model list
01700         link();
01701         return true;
01702     }
01703     else
01704         return false;
01705 }
01706 
01707 
01708 /*
01709 // struct used to build vertices for the simple shader
01710 struct CSimpleVertexInfo
01711 {
01712     NLMISC::CVector XFormPos;
01713     NLMISC::CUV     UV;
01714 };
01715 */
01716 
01717 //***********************************************************************************************************
01718 /*
01719 void CWaterModel::doSimpleRender(IDriver *drv)
01720 {
01721     if (_ClippedPoly.Vertices.empty()) return;
01722     // rendering of water when no vertex / pixel shaders are available
01723     CWaterShape *shape = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
01724     CRenderTrav &renderTrav     = getOwnerScene()->getRenderTrav();
01725     static bool init = false;
01726     if (!init)
01727     {
01728         // setup the material, no special shader is used here
01729         _SimpleWaterMat.setLighting(false);
01730         _SimpleWaterMat.setDoubleSided(true);
01731         _SimpleWaterMat.setColor(NLMISC::CRGBA::White);
01732 
01733         _SimpleWaterMat.setBlend(true);
01734         _SimpleWaterMat.setSrcBlend(CMaterial::srcalpha);
01735         _SimpleWaterMat.setDstBlend(CMaterial::invsrcalpha);
01736         _SimpleWaterMat.setZWrite(true);
01737         _SimpleWaterMat.setShader(CMaterial::Normal);
01738 
01739         // stage 0
01740         _SimpleWaterMat.texEnvOpRGB(0, CMaterial::Replace);
01741         _SimpleWaterMat.texEnvOpAlpha(0, CMaterial::Replace);
01742         _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
01743         _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
01744 
01745         // stage 1
01746         _SimpleWaterMat.texEnvOpRGB(1, CMaterial::Modulate);
01747         _SimpleWaterMat.texEnvOpAlpha(1, CMaterial::Modulate);
01748         _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
01749         _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
01750         _SimpleWaterMat.texEnvArg1RGB(0, CMaterial::Previous, CMaterial::SrcColor);
01751         _SimpleWaterMat.texEnvArg1Alpha(0, CMaterial::Previous, CMaterial::SrcAlpha);
01752 
01753         // setup the vb : one position & two tex coords
01754         _SimpleRenderVB.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::TexCoord1Flag);
01755         init = true;
01756     }
01757 
01758     const NLMISC::CMatrix &worldMatrix = getWorldMatrix();
01759     const NLMISC::CVector &obsPos = renderTrav.CamPos;
01760 
01761     // setup the material
01762     bool isAbove = obsPos.z > worldMatrix.getPos().z;
01763 
01764     // envmap is always present and is in stage 0
01765     CScene *scene = getOwnerScene();
01766     if (!isAbove && shape->_EnvMap[1])
01767     {
01768         if (shape->_UsesSceneWaterEnvMap[1])
01769         {
01770             if (scene->getWaterEnvMap())
01771             {
01772                 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
01773             }
01774             else
01775             {
01776                 _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
01777             }
01778         }
01779         else
01780         {
01781             _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
01782         }
01783     }
01784     else
01785     {
01786         if (shape->_UsesSceneWaterEnvMap[0])
01787         {
01788             if (scene->getWaterEnvMap())
01789             {
01790                 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
01791             }
01792             else
01793             {
01794                 _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
01795             }
01796         }
01797         else
01798         {
01799             _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
01800         }
01801     }
01802     //
01803     static std::vector<CSimpleVertexInfo> verts;
01804     static CIndexBuffer indices;
01805     //
01806     NLMISC::CPolygon2D &poly = shape->_Poly;
01807     uint numVerts = poly.Vertices.size();
01808     uint k;
01809     //
01810     if (shape->_ColorMap == NULL)
01811     {
01812         // version with no color map
01813         if (!_EmbossTexture)
01814         {
01815             _EmbossTexture = new CTextureEmboss;
01816             _EmbossTexture->setSlopeFactor(4.f);
01817         }
01818         if (shape->_BumpMap[1] && shape->_BumpMap[1]->isBumpMap())
01819         {
01820             CTextureBump *bm = static_cast<CTextureBump *>((ITexture *) shape->_BumpMap[1]);
01821             if (bm->getHeightMap())
01822             {
01823                 _EmbossTexture->setHeightMap(bm->getHeightMap());
01824             }
01825         }
01826         _SimpleWaterMat.setTexture(1, _EmbossTexture);
01827         _SimpleRenderVB.setNumVertices(numVerts);
01828         // retrieve current time
01829         float date  = 0.001f * (NLMISC::CTime::getLocalTime() & 0xffffff); // must keep some precision.
01830         // Compute tex coordinates for emboss first.
01831         // On some 3D chip, textures coords can't grow too mush or texture filtering loose accuracy.
01832         // So we must keep texCoord as low as possible.
01833         //
01834         verts.resize(numVerts);
01835         for(k = 0; k < numVerts; ++k)
01836         {
01837             verts[k].XFormPos = worldMatrix * NLMISC::CVector(poly.Vertices[k].x, poly.Vertices[k].y ,0.f);
01838             verts[k].UV.U = shape->_HeightMapScale[0].x * verts[k].XFormPos.x + date * shape->_HeightMapSpeed[0].x;
01839             verts[k].UV.V = shape->_HeightMapScale[0].y * verts[k].XFormPos.y + date * shape->_HeightMapSpeed[0].y;
01840         }
01841         // get min tex coords
01842         float minU = verts[0].UV.U;
01843         float minV = verts[0].UV.V;
01844         for(k = 1; k < numVerts; ++k)
01845         {
01846             minU = std::min(minU, verts[k].UV.U);
01847             minV = std::min(minV, verts[k].UV.V);
01848         }
01849         //
01850         minU = floorf(minU);
01851         minV = floorf(minV);
01852         //
01853         CVertexBufferReadWrite vba;
01854         _SimpleRenderVB.lock (vba);
01855         uint8 *data = (uint8 *) vba.getVertexCoordPointer();
01856         for(k = 0; k < numVerts; ++k)
01857         {
01858             ((NLMISC::CVector *) data)->set(poly.Vertices[k].x, poly.Vertices[k].y, 0.f);
01859             data += sizeof(NLMISC::CVector);
01860             // texture coord 0 is reflected vector into envmap
01861             // xform position in world space to compute the reflection
01862             CVector surfToEye = (obsPos - verts[k].XFormPos).normed();
01863             // we assume that normal is (0, 0, 1)
01864             * (float *) data = 0.5f - 0.5f * surfToEye.x;
01865             ((float *) data)[1] = 0.5f  - 0.5f * surfToEye.y;
01866             data += sizeof(float[2]);
01867             // texture coord 1 is the embossed map
01868             * (float *) data = verts[k].UV.U - minU;
01869             ((float *) data)[1] = verts[k].UV.V - minV;
01870             data += sizeof(float[2]);
01871         }
01872     }
01873     else
01874     {
01875         // version with a color map : it remplace the emboss texture
01876         _SimpleWaterMat.setTexture(1, shape->_ColorMap);
01877         _SimpleRenderVB.setNumVertices(numVerts);
01878         CVertexBufferReadWrite vba;
01879         _SimpleRenderVB.lock (vba);
01880         //
01881         uint8 *data = (uint8 *) vba.getVertexCoordPointer();
01882         for(k = 0; k < numVerts; ++k)
01883         {
01884             * (NLMISC::CVector *) data = poly.Vertices[k];
01885             data += sizeof(CVector);
01886             // texture coord 0 is reflected vector into envmap
01887             // xform position in world space to compute the reflection
01888             NLMISC::CVector xformPos = worldMatrix * poly.Vertices[k];
01889             NLMISC::CVector surfToEye = (obsPos - xformPos).normed();
01890             // we assume that normal is (0, 0, 1)
01891             * (float *) data = 0.5f - 0.5f * surfToEye.x;
01892             ((float *) data)[1] = 0.5f * - 0.5f * surfToEye.y;
01893             data += sizeof(float[2]);
01894             // texture coord 1 is the color map
01895             * (float *) data = shape->_ColorMapMatColumn0.x * xformPos.x + shape->_ColorMapMatColumn1.x * xformPos.y + shape->_ColorMapMatPos.x;
01896             ((float *) data)[1] = shape->_ColorMapMatColumn0.y * xformPos.x + shape->_ColorMapMatColumn1.y * xformPos.y + shape->_ColorMapMatPos.y;
01897             data += sizeof(float[2]);
01898         }
01899     }
01900 
01901     drv->activeVertexProgram(NULL);
01902     drv->setupModelMatrix(worldMatrix);
01903     drv->activeVertexBuffer(_SimpleRenderVB);
01904 
01905     // create an index buffer to do the display
01906     indices.setNumIndexes((numVerts - 2) * 3);
01907     {
01908         CIndexBufferReadWrite ibaWrite;
01909         indices.lock (ibaWrite);
01910         uint32 *ptr = ibaWrite.getPtr();
01911         for(k = 0; k < (numVerts - 2); ++k)
01912         {
01913 
01914             ptr[ k * 3      ] = 0;
01915             ptr[ k * 3  + 1 ] = k + 1;
01916             ptr[ k * 3  + 2 ] = k + 2;
01917         }
01918     }
01919     drv->setupMaterial(_SimpleWaterMat);
01920     drv->activeIndexBuffer(indices);
01921     drv->renderSimpleTriangles(0, numVerts - 2);
01922 }
01923 */
01924 
01925 //***********************************************************************************************************
01926 void CWaterModel::updateDiffuseMapMatrix(bool force /* = false*/)
01927 {
01928     if (compareMatrixDate(_MatrixUpdateDate) ||force)
01929     {
01930         CWaterShape *shape = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
01931         if (shape)
01932         {
01933             _MatrixUpdateDate = getMatrixDate();
01934             // update the uv matrix
01935             CMatrix uvMat;
01936             uvMat.setRot(CVector(shape->_ColorMapMatColumn0.x, shape->_ColorMapMatColumn0.y, 0.f),
01937                          CVector(shape->_ColorMapMatColumn1.x, shape->_ColorMapMatColumn1.y, 0.f),
01938                          CVector(shape->_ColorMapMatPos.x, shape->_ColorMapMatPos.y, 1.f));
01939             CMatrix xformMat;
01940             CMatrix invMat = this->getWorldMatrix().inverted();
01941             xformMat.setRot(CVector(invMat.getI().x, invMat.getI().y, 0.f),
01942                             CVector(invMat.getJ().x, invMat.getJ().y, 0.f),
01943                             CVector(invMat.getPos().x, invMat.getPos().y, 1.f));
01944             uvMat = uvMat * xformMat;
01945             _ColorMapMatColumn0.set(uvMat.getI().x, uvMat.getI().y);
01946             _ColorMapMatColumn1.set(uvMat.getJ().x, uvMat.getJ().y);
01947             _ColorMapMatPos.set(uvMat.getK().x, uvMat.getK().y);
01948         }
01949     }
01950 }
01951 
01952 // ***************************************************************************
01953 void CWaterModel::debugDumpMem(void* &clippedPolyBegin, void* &clippedPolyEnd)
01954 {
01955     clippedPolyBegin= (void*)(&*_ClippedPoly.Vertices.begin());
01956     clippedPolyEnd= (void*)(&*_ClippedPoly.Vertices.end());
01957 }
01958 
01959 // ***************************************************************************
01960 void CWaterModel::debugClearClippedPoly()
01961 {
01962     _ClippedPoly.Vertices.clear();
01963 }
01964 
01965 //=======================================================================================
01966 //                          wave maker implementation
01967 //=======================================================================================
01968 
01969 CWaveMakerModel::CWaveMakerModel() : _Time(0)
01970 {
01971     // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
01972     CTransform::setIsForceAnimDetail(true);
01973 }
01974 
01975 //================================================
01976 
01977 void CWaveMakerModel::registerBasic()
01978 {
01979     CScene::registerModel(WaveMakerModelClassId, TransformShapeId, CWaveMakerModel::creator);
01980 }
01981 
01982 //================================================
01983 
01984 ITrack* CWaveMakerModel::getDefaultTrack (uint valueId)
01985 {
01986     nlassert(Shape);
01987     CWaveMakerShape *ws = NLMISC::safe_cast<CWaveMakerShape *>((IShape *) Shape);
01988     switch (valueId)
01989     {
01990     case PosValue:          return ws->getDefaultPos(); break;
01991     default: // delegate to parent
01992         return CTransformShape::getDefaultTrack(valueId);
01993         break;
01994     }
01995 }
01996 
01997 //================================================
01998 void    CWaveMakerModel::traverseAnimDetail()
01999 {
02000     CTransformShape::traverseAnimDetail();
02001     nlassert(getOwnerScene());
02003     CWaveMakerShape *wms = NLMISC::safe_cast<CWaveMakerShape *>((IShape *) Shape);
02004     const NLMISC::CVector   worldPos = getWorldMatrix().getPos();
02005     const CVector2f pos2d(worldPos.x, worldPos.y);
02007     CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(wms->_PoolID);
02008     // get the time delta
02009     const TAnimationTime deltaT  = std::min(getOwnerScene()->getEllapsedTime(), (TAnimationTime) whm.getPropagationTime());
02010     _Time += deltaT;
02011     if (!wms->_ImpulsionMode)
02012     {
02013         whm.perturbate(pos2d, wms->_Intensity * cosf(2.f / wms->_Period * (float) NLMISC::Pi * _Time), wms->_Radius);
02014     }
02015     else
02016     {
02017         if (_Time > wms->_Period)
02018         {
02019             _Time -= wms->_Period;
02020             whm.perturbate(pos2d, wms->_Intensity, wms->_Radius);
02021         }
02022     }
02023 }
02024 
02025 } // NL3D

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