1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "nel/misc/vector_2f.h"
23 #include "nel/misc/vector_h.h"
24 #include "nel/misc/hierarchical_timer.h"
25 #include "nel/3d/animation_time.h"
26 #include "nel/3d/water_model.h"
27 #include "nel/3d/water_shape.h"
28 #include "nel/3d/water_pool_manager.h"
29 #include "nel/3d/water_height_map.h"
30 #include "nel/3d/dru.h"
31 #include "nel/3d/scene.h"
32 #include "nel/3d/driver.h"
33 #include "nel/3d/render_trav.h"
34 #include "nel/3d/anim_detail_trav.h"
35 #include "nel/3d/texture_emboss.h"
36 #include "nel/3d/texture_bump.h"
37 #include "nel/3d/water_env_map.h"
40 using NLMISC::CVector2f
;
48 // for normal rendering
49 CMaterial
CWaterModel::_WaterMat
;
50 // for simple rendering
51 CMaterial
CWaterModel::_SimpleWaterMat
;
52 const uint WATER_MODEL_DEFAULT_NUM_VERTICES
= 5000;
54 NLMISC::CRefPtr
<IDriver
> CWaterModel::_CurrDrv
;
59 volatile bool forceWaterSimpleRender
= false;
61 //=======================================================================
62 void CWaterModel::setupVertexBuffer(CVertexBuffer
&vb
, uint numWantedVertices
, IDriver
*drv
)
64 if (!numWantedVertices
) return;
65 if (vb
.getNumVertices() == 0 || drv
!= _CurrDrv
) // not setupped yet, or driver changed ?
69 vb
.setPreferredMemory(CVertexBuffer::AGPPreferred
, false);
70 if (drv
->supportWaterShader())
72 vb
.setVertexFormat(CVertexBuffer::PositionFlag
);
76 vb
.setVertexFormat(CVertexBuffer::PositionFlag
| CVertexBuffer::TexCoord0Flag
);
80 uint numVerts
= std::max(numWantedVertices
, WATER_MODEL_DEFAULT_NUM_VERTICES
);
81 if (numVerts
> vb
.getNumVertices())
83 const uint vb_INCREASE_SIZE
= 1000;
84 numVerts
= vb_INCREASE_SIZE
* ((numVerts
+ (vb_INCREASE_SIZE
- 1)) / vb_INCREASE_SIZE
); // snap size
85 vb
.setNumVertices((uint32
) numVerts
);
89 //=======================================================================
90 CWaterModel::CWaterModel()
93 setTransparency(true);
95 // RenderFilter: We are a SegRemanece
96 _RenderFilterType
= UScene::FilterWater
;
99 _MatrixUpdateDate
= 0;
102 //=======================================================================
103 CWaterModel::~CWaterModel()
105 CScene
*scene
= getOwnerScene();
106 if (scene
&& scene
->getWaterCallback())
109 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
110 scene
->getWaterCallback()->waterSurfaceRemoved(ws
->getUseSceneWaterEnvMap(0) || ws
->getUseSceneWaterEnvMap(1));
112 // should be already unlinked, but security
116 //=======================================================================
117 void CWaterModel::registerBasic()
119 CScene::registerModel(WaterModelClassId
, TransformShapeId
, CWaterModel::creator
);
123 //=======================================================================
124 ITrack
* CWaterModel::getDefaultTrack (uint valueId
)
127 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
130 case PosValue
: return ws
->getDefaultPos(); break;
131 case ScaleValue
: return ws
->getDefaultScale(); break;
132 case RotQuatValue
: return ws
->getDefaultRotQuat(); break;
133 default: // delegate to parent
134 return CTransformShape::getDefaultTrack(valueId
);
140 //=======================================================================
141 uint32
CWaterModel::getWaterHeightMapID() const
143 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
144 return ws
->_WaterPoolID
;
147 //=======================================================================
148 float CWaterModel::getHeightFactor() const
150 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
151 return ws
->_WaveHeightFactor
;
155 //=======================================================================
156 float CWaterModel::getHeight(const CVector2f
&pos
)
158 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
159 CWaterHeightMap
&whm
= GetWaterPoolManager().getPoolByID(ws
->_WaterPoolID
);
160 const float height
= whm
.getHeight(pos
);
161 return height
* ws
->_WaveHeightFactor
+ this->getPos().z
;
164 //=======================================================================
165 float CWaterModel::getAttenuatedHeight(const CVector2f
&pos
, const NLMISC::CVector
&viewer
)
167 CWaterShape
*ws
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
168 CWaterHeightMap
&whm
= GetWaterPoolManager().getPoolByID(ws
->_WaterPoolID
);
169 const float maxDist
= whm
.getUnitSize() * (whm
.getSize() >> 1);
170 const NLMISC::CVector
planePos(pos
.x
, pos
.y
, this->getMatrix().getPos().z
);
171 const float userDist
= (planePos
- viewer
).norm();
173 if (userDist
> maxDist
)
175 return this->getMatrix().getPos().z
;
179 const float height
= whm
.getHeight(pos
);
180 return ws
->_WaveHeightFactor
* height
* (1.f
- userDist
/ maxDist
) + this->getMatrix().getPos().z
;
185 //=======================================================================
187 // perform a bilinear on 4 values
193 static float inline BilinFilter(float v0, float v1, float v2, float v3, float u, float v)
195 float g = v * v3 + (1.f - v) * v0;
196 float h = v * v2 + (1.f - v) * v1;
197 return u * h + (1.f - u) * g;
202 //=======================================================================
204 /// store a value in a water vertex buffer, and increment the pointer
206 static void inline FillWaterVB(uint8 *&vbPointer, float x, float y, float z, float nx, float ny)
208 * (float *) vbPointer = x;
209 ((float *) vbPointer)[1] = y;
210 ((float *) vbPointer)[2] = z;
211 *((float *) (vbPointer + 3 * sizeof(float))) = nx;
212 *((float *) (vbPointer + 4 * sizeof(float))) = ny;
213 vbPointer += 5 * sizeof(float);
217 // ***************************************************************************************************************
222 static void SetupWaterVertex( sint qLeft,
228 const NLMISC::CVector &inter,
230 sint doubleWaterHeightMapSize,
231 CWaterHeightMap &whm,
237 const float wXf = invWaterRatio * (inter.x + offsetX);
238 const float wYf = invWaterRatio * (inter.y + offsetY);
240 sint wx = (sint) floorf(wXf);
241 sint wy = (sint) floorf(wYf);
246 (wx >= qLeft && wx < qRight && wy < qUp && wy >= qDown)
249 // no perturbation is visible
250 FillWaterVB(vbPointer, inter.x, inter.y, 0, 0, 0);
256 // filter height and gradient at the given point
257 const sint stride = doubleWaterHeightMapSize;
260 const uint xm = (uint) (wx - qSubLeft);
261 const uint ym = (uint) (wy - qSubDown);
262 const sint offset = xm + stride * ym;
263 const float *ptWater = whm.getPointer() + offset;
266 float deltaU = wXf - wx;
267 float deltaV = wYf - wy;
268 //nlassert(deltaU >= 0.f && deltaU <= 1.f && deltaV >= 0.f && deltaV <= 1.f);
270 const float *ptWaterPrev = whm.getPrevPointer() + offset;
274 float g0x, g1x, g2x, g3x; // x gradient for current
275 float g0xp, g1xp, g2xp, g3xp;
277 float gradCurrX, gradCurrY;
279 float g0y, g1y, g2y, g3y; // y gradient for previous map
280 float g0yp, g1yp, g2yp, g3yp;
282 float gradPrevX, gradPrevY;
286 g0x = ptWater[ 1] - ptWater[ - 1];
287 g1x = ptWater[ 2] - ptWater[ 0 ];
288 g2x = ptWater[ 2 + stride] - ptWater[ stride];
289 g3x = ptWater[ 1 + stride] - ptWater[ - 1 + stride];
291 gradCurrX = BilinFilter(g0x, g1x, g2x, g3x, deltaU, deltaV);
294 g0y = ptWater[ stride] - ptWater[ - stride];
295 g1y = ptWater[ stride + 1] - ptWater[ - stride + 1];
296 g2y = ptWater[ (stride << 1) + 1] - ptWater[ 1];
297 g3y = ptWater[ (stride << 1)] - ptWater[0];
299 gradCurrY = BilinFilter(g0y, g1y, g2y, g3y, deltaU, deltaV);
303 g0xp = ptWaterPrev[ 1] - ptWaterPrev[ - 1];
304 g1xp = ptWaterPrev[ 2] - ptWaterPrev[ 0 ];
305 g2xp = ptWaterPrev[ 2 + stride] - ptWaterPrev[ + stride];
306 g3xp = ptWaterPrev[ 1 + stride] - ptWaterPrev[ - 1 + stride];
308 gradPrevX = BilinFilter(g0xp, g1xp, g2xp, g3xp, deltaU, deltaV);
311 g0yp = ptWaterPrev[ stride] - ptWaterPrev[ - stride];
312 g1yp = ptWaterPrev[ stride + 1] - ptWaterPrev[ - stride + 1];
313 g2yp = ptWaterPrev[ (stride << 1) + 1] - ptWaterPrev[ 1 ];
314 g3yp = ptWaterPrev[ (stride << 1)] - ptWaterPrev[ 0 ];
316 gradPrevY = BilinFilter(g0yp, g1yp, g2yp, g3yp, deltaU, deltaV);
320 float h = BilinFilter(ptWater[ 0 ], ptWater[ + 1], ptWater[ 1 + stride], ptWater[stride], deltaU, deltaV);
323 float hPrev = BilinFilter(ptWaterPrev[ 0 ], ptWaterPrev[ 1], ptWaterPrev[ 1 + stride], ptWaterPrev[stride], deltaU, deltaV);
326 float timeRatio = whm.getBufferRatio();
329 FillWaterVB(vbPointer, inter.x, inter.y, timeRatio * h + (1.f - timeRatio) * hPrev,
330 4.5f * (timeRatio * gradCurrX + (1.f - timeRatio) * gradPrevX),
331 4.5f * (timeRatio * gradCurrY + (1.f - timeRatio) * gradPrevY)
334 //NLMISC::CVector2f *ptGrad = whm.getGradPointer() + offset;
340 // *****************************************************************************************************
342 static void DrawPoly2D(CVertexBuffer &vb, IDriver *drv, const NLMISC::CMatrix &mat, const NLMISC::CPolygon &p)
347 CVertexBufferReadWrite vba;
349 for (k = 0; k < p.Vertices.size(); ++k)
351 NLMISC::CVector tPos = mat * NLMISC::CVector(p.Vertices[k].x, p.Vertices[k].y, 0);
352 vba.setValueFloat3Ex (WATER_VB_POS, k, tPos.x, tPos.y, tPos.z);
353 vba.setValueFloat2Ex (WATER_VB_DX, k, 0, 0);
356 static CIndexBuffer ib;
357 ib.setNumIndexes(3 * p.Vertices.size());
359 CIndexBufferReadWrite ibaWrite;
361 uint32 *ptr = ibaWrite.getPtr();
362 for (k = 0; k < p.Vertices.size() - 2; ++k)
365 ptr[ k * 3 + 1 ] = k + 1;
366 ptr[ k * 3 + 2 ] = k + 2;
369 drv->activeIndexBuffer(ib);
370 drv->renderSimpleTriangles(0, p.Vertices.size() - 2);
375 // ***************************************************************************************************************
377 void CWaterModel::traverseRender()
379 H_AUTO( NL3D_Water_Render );
381 CRenderTrav &renderTrav = getOwnerScene()->getRenderTrav();
382 IDriver *drv = renderTrav.getDriver();
385 #ifndef FORCE_SIMPLE_WATER_RENDER
386 if (!drv->supportWaterShader())
393 CWaterShape *shape = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
396 if (shape->_GridSizeTouched)
398 shape->setupVertexBuffer();
401 // inverted object world matrix
402 //NLMISC::CMatrix invObjMat = getWorldMatrix().inverted();
404 // viewer pos in world space
405 const NLMISC::CVector &obsPos = renderTrav.CamPos;
407 // camera matrix in world space
408 const NLMISC::CMatrix &camMat = renderTrav.CamMatrix;
410 // view matrix (inverted cam matrix)
411 const NLMISC::CMatrix &viewMat = renderTrav.ViewMatrix;
413 // compute the camera matrix such as there is no rotation around the y axis
414 NLMISC::CMatrix camMatUp;
415 ComputeUpMatrix(camMat.getJ(), camMatUp, camMat);
416 camMatUp.setPos(camMat.getPos());
418 const NLMISC::CMatrix matViewUp = camMatUp.inverted();
420 // plane z pos in world
421 const float zHeight = getWorldMatrix().getPos().z;
423 const sint numStepX = CWaterShape::getScreenXGridSize();
424 const sint numStepY = CWaterShape::getScreenYGridSize();
426 const float invNumStepX = 1.f / numStepX;
427 const float invNumStepY = 1.f / numStepY;
429 const uint rotBorderSize = (shape->_MaxGridSize + (shape->_XGridBorder << 1) - numStepX) >> 1;
431 const sint isAbove = obsPos.z > zHeight ? 1 : 0;
434 #ifdef NO_WATER_TESSEL
435 const float transitionDist = renderTrav.Near * 0.99f;
437 const float transitionDist = shape->_TransitionRatio * renderTrav.Far;
441 NLMISC::CMatrix modelMat;
442 modelMat.setPos(NLMISC::CVector(obsPos.x, obsPos.y, zHeight));
443 drv->setupModelMatrix(modelMat);
445 //==================//
447 //==================//
449 CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(shape->_WaterPoolID);
451 setupMaterialNVertexShader(drv, shape, obsPos, isAbove > 0, whm.getUnitSize() * (whm.getSize() >> 1), zHeight);
454 drv->setupMaterial(CWaterModel::_WaterMat);
456 sint numPass = drv->beginMaterialMultiPass();
457 nlassert(numPass == 1); // for now, we assume water is always rendered in a single pass !
458 drv->setupMaterialPass(0);
461 //setAttenuationFactor(drv, false, obsPos, camMat.getJ(), farDist);
462 //disableAttenuation(drv);
465 //================================//
466 // Vertex buffer setup //
467 //================================//
469 drv->activeVertexBuffer(shape->_VB);
471 //================================//
472 // tesselated part of the poly //
473 //================================//
475 if (_ClippedPoly.Vertices.size())
477 //======================================//
478 // Polygon projection on the near plane //
479 //======================================//
481 static NLMISC::CPolygon2D projPoly; // projected poly
482 projPoly.Vertices.resize(_ClippedPoly.Vertices.size());
483 const float Near = renderTrav.Near;
486 const float xFactor = numStepX * Near / (renderTrav.Right - renderTrav.Left);
487 const float xOffset = numStepX * (-renderTrav.Left / (renderTrav.Right - renderTrav.Left)) + 0.5f;
488 const float yFactor = numStepY * Near / (renderTrav.Bottom - renderTrav.Top);
489 const float yOffset = numStepY * (-renderTrav.Top / (renderTrav.Bottom - renderTrav.Top)) - 0.5f * isAbove;
491 const NLMISC::CMatrix projMat = matViewUp * getWorldMatrix();
493 for (k = 0; k < _ClippedPoly.Vertices.size(); ++k)
495 // project points in the view
496 NLMISC::CVector t = projMat * _ClippedPoly.Vertices[k];
497 float invY = 1.f / t.y;
498 projPoly.Vertices[k].set(xFactor * t.x * invY + xOffset, yFactor * t.z * invY + yOffset);
501 //=============================================//
502 // compute borders of poly at a low resolution //
503 //=============================================//
505 NLMISC::CPolygon2D::TRasterVect rasters;
507 projPoly.computeBorders(rasters, startY);
509 if (!rasters.empty())
511 //===========================//
512 // perform Water animation //
513 //===========================//
515 const float WaterRatio = whm.getUnitSize();
516 const float invWaterRatio = 1.f / WaterRatio;
517 const uint WaterHeightMapSize = whm.getSize();
518 const uint doubleWaterHeightMapSize = (WaterHeightMapSize << 1);
521 sint64 idate = getOwnerScene()->getHrcTrav().CurrentDate;
525 if (idate != whm.Date)
527 whm.setUserPos((sint) (obsPos.x * invWaterRatio) - (WaterHeightMapSize >> 1),
528 (sint) (obsPos.y * invWaterRatio) - (WaterHeightMapSize >> 1)
530 nlassert(getOwnerScene()); // this object should have been created from a CWaterShape!
531 whm.animate((float) (getOwnerScene()->getEllapsedTime()));
535 //float startDate = (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()));
537 //=====================================//
538 // compute heightmap useful area //
539 //=====================================//
541 // We don't store a heighmap for a complete Water area
542 // we just consider the height of Water columns that are near the observer
544 // Compute a quad in Water height field space that contains the useful heights
545 // This helps us to decide whether we should do a lookup in the height map
547 sint mapPosX, mapPosY;
549 /// get the pos used in the height map (may not be the same than our current pos, has it is taken in account
550 /// every 'PropagationTime' second
551 whm.getUserPos(mapPosX, mapPosY);
553 const uint mapBorder = 3;
555 const sint qRight = (sint) mapPosX + WaterHeightMapSize - mapBorder;
556 sint qLeft = (sint) mapPosX;
557 const sint qUp = (sint) mapPosY + WaterHeightMapSize - mapBorder;
558 sint qDown = (sint) mapPosY;
560 /// Compute the origin of the area of Water covered by the height map. We use this to converted from object space to 2d map space
561 const sint qSubLeft = qLeft - (uint) qLeft % WaterHeightMapSize;
562 const sint qSubDown = qDown - (uint) qDown % WaterHeightMapSize;
567 //==============================================//
568 // setup rays to be traced, and their increment //
569 //==============================================//
572 // compute camera rays in world space
573 NLMISC::CVector currHV = renderTrav.Left * camMatUp.getI() + renderTrav.Near * camMatUp.getJ() + renderTrav.Top * camMatUp.getK(); // current border vector, incremented at each line
574 NLMISC::CVector currV; // current ray vector
575 NLMISC::CVector xStep = (renderTrav.Right - renderTrav.Left) * invNumStepX * camMatUp.getI(); // xStep for the ray vector
576 NLMISC::CVector yStep = (renderTrav.Bottom - renderTrav.Top) * invNumStepY * camMatUp.getK(); // yStep for the ray vector
578 //===============================================//
579 // perform display //
580 //===============================================//
582 // scale currHV at the top of the poly
583 currHV += (startY - 0.5f * isAbove) * yStep;
585 // current index buffer used. We swap each time a row has been drawn
586 CIndexBuffer *currIB = &CWaterShape::_IBUpDown, *otherIB = &CWaterShape::_IBDownUp;
589 sint vIndex = 0; // index in vertices
591 // current raster position
592 sint oldStartX, oldEndX, realStartX, realEndX;
593 //float invNearWidth = numStepX / (renderTrav.Right - renderTrav.Left);
595 //nlinfo("size = %d, maxSize = ", rasters.size(), numStepY);
598 const uint wqHeight = rasters.size();
601 // denominator of the intersection equation
602 const float denom = - obsPos.z + zHeight;
603 // test the upper raster
604 // if it is above the horizon, we modify it to reach the correct location
605 const float horizonEpsilon = 10E-4f; // we must be a little below the horizon
607 // distance from the viewer along the traced ray
610 NLMISC::CPolygon2D::TRasterVect::const_iterator it = rasters.begin();
611 for (uint l = 0; l <= wqHeight; ++l)
613 //nlinfo("start = %d, end = %d", it->first, it->second);
614 const sint startX = it->first;
615 const sint endX = (it->second + 1);
617 nlassert(startX >= - (sint) rotBorderSize);
618 nlassert(endX <= (sint) (numStepX + rotBorderSize));
622 realStartX = std::min(startX, oldStartX);
623 realEndX = std::max(endX, oldEndX);
632 // current view vector
633 currV = currHV + (realStartX - 0.5f) * xStep;
639 // test whether the first row is out of horizon.
640 // if this is the case, we make a correction
641 if (denom * currV.z <= 0)
643 // correct for the first line only by adding a y offset
644 currV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon) - currV.z) / yStep.z;
647 // now, for the transition, check whether the first raster does not go over the transition dist
650 const float VJ = camMat.getJ() * currV;
651 if ( t * VJ > transitionDist)
653 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currV.z);
654 // correct the first line to reach that position
655 currV += delta * yStep;
662 CVertexBufferReadWrite vba;
663 shape->_VB.lock (vba);
664 uint8 *vbPointer = (uint8 *) vba.getVertexCoordPointer() + shape->_VB.getVertexSize() * (vIndex + realStartX + rotBorderSize);
667 for (sint k = realStartX; k <= realEndX; ++k)
670 // compute intersection with plane
671 NLMISC::CVector inter = t * currV;
673 SetupWaterVertex(qLeft, qRight, qUp, qDown, qSubLeft, qSubDown, inter, invWaterRatio, doubleWaterHeightMapSize, whm, vbPointer, obsPos.x, obsPos.y);
678 if (l != 0) // 2 line of the ib done ?
680 sint count = oldEndX - oldStartX;
683 drv->activeIndexBuffer(*currIB);
684 drv->renderSimpleTriangles((oldStartX + rotBorderSize) * 6, 2 * count );
691 vIndex = (numStepX + 2 * rotBorderSize + 1) - vIndex; // swap first row and second row
692 std::swap(currIB, otherIB);
693 if (l < (wqHeight - 1))
702 // test whether we are out of horizon
703 if (denom * currHV.z <= 0)
705 // correct for the first line only by adding a y offset
706 currHV += yStep * ((denom > 0 ? horizonEpsilon : - horizonEpsilon) - currHV.z) / yStep.z;
709 // now, for the transition, check whether the first raster does not go over the transition dist
711 t = denom / currHV.z;
712 const float VJ = camMat.getJ() * currHV;
713 if ( t * VJ > transitionDist)
715 float delta = (1.f / yStep.z) * ( denom * VJ / transitionDist - currHV.z);
716 // correct the first line to reach that position
717 currHV += delta * yStep;
725 //nlinfo("display: %f ms", (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()) - startDate));
729 //=========================================//
730 // display end poly //
731 //=========================================//
733 if (_EndClippedPoly.Vertices.size() != 0)
736 CMatrix xform = _WorldMatrix;
737 xform.movePos(NLMISC::CVector(- obsPos.x, - obsPos.y, _WorldMatrix.getPos().z));
738 DrawPoly2D(shape->_VB, drv, xform, _EndClippedPoly);
741 drv->endMaterialMultiPass();
744 drv->activeVertexProgram(NULL);
749 // ***********************
750 // Water MATERIAL SETUP //
751 // ***********************
753 void CWaterModel::setupMaterialNVertexShader(IDriver *drv, CWaterShape *shape, const NLMISC::CVector &obsPos, bool above, float maxDist, float zHeight)
755 static bool matSetupped = false;
758 _WaterMat.setLighting(false);
759 _WaterMat.setDoubleSided(true);
760 _WaterMat.setColor(NLMISC::CRGBA::White);
761 _WaterMat.setBlend(true);
762 _WaterMat.setSrcBlend(CMaterial::srcalpha);
763 _WaterMat.setDstBlend(CMaterial::invsrcalpha);
764 _WaterMat.setZWrite(true);
765 _WaterMat.setShader(CMaterial::Water);
769 const uint cstOffset = 4; // 4 places for the matrix
770 NLMISC::CVectorH cst[13];
773 //=========================//
774 // setup Water material //
775 //=========================//
777 CWaterModel::_WaterMat.setTexture(0, shape->_BumpMap[0]);
778 CWaterModel::_WaterMat.setTexture(1, shape->_BumpMap[1]);
779 CWaterModel::_WaterMat.setTexture(3, shape->_ColorMap);
781 CScene *scene = getOwnerScene();
782 if (!above && shape->_EnvMap[1])
784 if (shape->_UsesSceneWaterEnvMap[1])
786 if (scene->getWaterEnvMap())
788 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
792 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
797 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[1]);
802 if (shape->_UsesSceneWaterEnvMap[0])
804 if (scene->getWaterEnvMap())
806 CWaterModel::_WaterMat.setTexture(2, scene->getWaterEnvMap()->getEnvMap2D());
810 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
815 CWaterModel::_WaterMat.setTexture(2, shape->_EnvMap[0]);
819 shape->envMapUpdate();
821 const uint alphaMapStage = 3;
822 if (shape->_ColorMap)
824 //WaterMat.setTexture(alphaMapStage, shape->_ColorMap);
825 //if (shape->_ColorMap->supportSharing()) nlinfo(shape->_ColorMap->getShareName().c_str());
828 // setup 2x3 matrix for lookup in diffuse map
829 updateDiffuseMapMatrix();
830 cst[13 - cstOffset].set(_ColorMapMatColumn0.x, _ColorMapMatColumn1.x, 0, _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x);
831 cst[14 - cstOffset].set(_ColorMapMatColumn0.y, _ColorMapMatColumn1.y, 0, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y);
835 cst[13 - cstOffset].set(0, 0, 0, 0);
836 cst[14 - cstOffset].set(0, 0, 0, 0);
839 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
840 // 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
842 cst[5 - cstOffset].set(0.f, 0.f, 0.f, 0.f); // claping negative values to 0
844 // slope of attenuation of normal / height with distance
845 const float invMaxDist = shape->_WaveHeightFactor / maxDist;
846 cst[6 - cstOffset].set(invMaxDist, shape->_WaveHeightFactor, 0, 0);
849 drv->setConstantMatrix(0, IDriver::ModelViewProjection, IDriver::Identity);
850 drv->setConstantFog(18);
852 // retrieve current time
853 float date = 0.001f * (NLMISC::CTime::getLocalTime() & 0xffffff); // must keep some precision.
855 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
856 cst[10 - cstOffset].set(shape->_HeightMapScale[0].x, shape->_HeightMapScale[0].y, 0, 0); // bump map 0 scale
857 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
858 cst[12 - cstOffset].set(shape->_HeightMapScale[1].x, shape->_HeightMapScale[1].y, 0, 0); // bump map 1 scale
860 cst[4 - cstOffset].set(1.f, 1.f, 1.f, 1.f); // use with min man, and to get the 1 constant
861 cst[7 - cstOffset].set(0, 0, obsPos.z - zHeight, 1.f);
862 cst[8 - cstOffset].set(0.5f, 0.5f, 0.f, 1.f); // used to scale reflected ray into the envmap
864 /// set all our constants in one call
865 drv->setConstant(4, sizeof(cst) / sizeof(cst[0]), (float *) &cst[0]);
867 shape->initVertexProgram();
870 //if (useBumpedVersion)
874 // result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
875 // : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
879 // result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump1Diffuse).get())
880 // : drv->activeVertexProgram((shape->_VertexProgramBump1).get());
885 // result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramNoBumpDiffuse).get())
886 // : drv->activeVertexProgram((shape->_VertexProgramNoBump).get());
889 //result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
890 // : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
892 //if (!result) nlwarning("no vertex program setuped");
898 void CWaterModel::setupMaterialNVertexShader(IDriver
*drv
, CWaterShape
*shape
, const NLMISC::CVector
&obsPos
, bool above
, float zHeight
)
900 static bool matSetupped
= false;
903 _WaterMat
.setLighting(false);
904 _WaterMat
.setDoubleSided(true);
905 _WaterMat
.setColor(NLMISC::CRGBA::White
);
906 _WaterMat
.setBlend(true);
907 _WaterMat
.setSrcBlend(CMaterial::srcalpha
);
908 _WaterMat
.setDstBlend(CMaterial::invsrcalpha
);
909 _WaterMat
.setZWrite(true);
910 _WaterMat
.setShader(CMaterial::Water
);
912 //=========================//
913 // setup Water material //
914 //=========================//
915 shape
->initVertexProgram();
916 CVertexProgramWaterVPNoWave
*program
= shape
->_ColorMap
? CWaterShape::_VertexProgramNoWaveDiffuse
: CWaterShape::_VertexProgramNoWave
;
917 drv
->activeVertexProgram(program
);
918 CWaterModel::_WaterMat
.setTexture(0, shape
->_BumpMap
[0]);
919 CWaterModel::_WaterMat
.setTexture(1, shape
->_BumpMap
[1]);
920 CWaterModel::_WaterMat
.setTexture(3, shape
->_ColorMap
);
921 CScene
*scene
= getOwnerScene();
922 if (!above
&& shape
->_EnvMap
[1])
924 if (shape
->_UsesSceneWaterEnvMap
[1])
926 if (scene
->getWaterEnvMap())
928 CWaterModel::_WaterMat
.setTexture(2, scene
->getWaterEnvMap()->getEnvMap2D());
932 CWaterModel::_WaterMat
.setTexture(2, shape
->_EnvMap
[1]);
937 CWaterModel::_WaterMat
.setTexture(2, shape
->_EnvMap
[1]);
942 if (shape
->_UsesSceneWaterEnvMap
[0])
944 if (scene
->getWaterEnvMap())
946 CWaterModel::_WaterMat
.setTexture(2, scene
->getWaterEnvMap()->getEnvMap2D());
950 CWaterModel::_WaterMat
.setTexture(2, shape
->_EnvMap
[0]);
955 CWaterModel::_WaterMat
.setTexture(2, shape
->_EnvMap
[0]);
958 shape
->envMapUpdate();
959 if (shape
->_ColorMap
)
961 // setup 2x3 matrix for lookup in diffuse map
962 updateDiffuseMapMatrix();
963 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().DiffuseMapVector0
, _ColorMapMatColumn0
.x
, _ColorMapMatColumn1
.x
, 0, _ColorMapMatColumn0
.x
* obsPos
.x
+ _ColorMapMatColumn1
.x
* obsPos
.y
+ _ColorMapMatPos
.x
);
964 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().DiffuseMapVector1
, _ColorMapMatColumn0
.y
, _ColorMapMatColumn1
.y
, 0, _ColorMapMatColumn0
.y
* obsPos
.x
+ _ColorMapMatColumn1
.y
* obsPos
.y
+ _ColorMapMatPos
.y
);
967 drv
->setUniformMatrix(IDriver::VertexProgram
, program
->getUniformIndex(CProgramIndex::ModelViewProjection
), IDriver::ModelViewProjection
, IDriver::Identity
);
968 drv
->setUniformFog(IDriver::VertexProgram
, program
->getUniformIndex(CProgramIndex::Fog
));
969 // retrieve current time
970 double date
= scene
->getCurrentTime();
972 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().BumpMap0Offset
, 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
973 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().BumpMap0Scale
, shape
->_HeightMapScale
[0].x
, shape
->_HeightMapScale
[0].y
, 0, 0); // bump map 0 scale
974 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().BumpMap1Offset
, 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
975 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().BumpMap1Scale
, shape
->_HeightMapScale
[1].x
, shape
->_HeightMapScale
[1].y
, 0, 0); // bump map 1 scale
976 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().ObserverHeight
, 0, 0, obsPos
.z
- zHeight
, 1.f
);
977 drv
->setUniform4f(IDriver::VertexProgram
, program
->idx().ScaleReflectedRay
, 0.5f
, 0.5f
, 0.f
, 1.f
); // used to scale reflected ray into the envmap
980 //================================================
981 void CWaterModel::setupSimpleRender(CWaterShape
*shape
, const NLMISC::CVector
&obsPos
, bool above
)
983 // rendering of water when no vertex / pixel shaders are available
984 static bool init
= false;
987 // setup the material, no special shader is used here
988 _SimpleWaterMat
.setLighting(false);
989 _SimpleWaterMat
.setDoubleSided(true);
990 _SimpleWaterMat
.setColor(NLMISC::CRGBA::White
);
992 _SimpleWaterMat
.setBlend(true);
993 _SimpleWaterMat
.setSrcBlend(CMaterial::srcalpha
);
994 _SimpleWaterMat
.setDstBlend(CMaterial::invsrcalpha
);
995 _SimpleWaterMat
.setZWrite(true);
996 _SimpleWaterMat
.setShader(CMaterial::Normal
);
999 _SimpleWaterMat
.texEnvOpRGB(0, CMaterial::Replace
);
1000 _SimpleWaterMat
.texEnvOpAlpha(0, CMaterial::Replace
);
1001 _SimpleWaterMat
.texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
1002 _SimpleWaterMat
.texEnvArg0Alpha(0, CMaterial::Texture
, CMaterial::SrcAlpha
);
1005 _SimpleWaterMat
.texEnvOpRGB(1, CMaterial::Modulate
);
1006 _SimpleWaterMat
.texEnvOpAlpha(1, CMaterial::Modulate
);
1007 _SimpleWaterMat
.texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
1008 _SimpleWaterMat
.texEnvArg0Alpha(0, CMaterial::Texture
, CMaterial::SrcAlpha
);
1009 _SimpleWaterMat
.texEnvArg1RGB(0, CMaterial::Previous
, CMaterial::SrcColor
);
1010 _SimpleWaterMat
.texEnvArg1Alpha(0, CMaterial::Previous
, CMaterial::SrcAlpha
);
1014 // envmap is always present and is in stage 0
1015 CScene
*scene
= getOwnerScene();
1016 if (!above
&& shape
->_EnvMap
[1])
1018 if (shape
->_UsesSceneWaterEnvMap
[1])
1020 if (scene
->getWaterEnvMap())
1022 _SimpleWaterMat
.setTexture(0, scene
->getWaterEnvMap()->getEnvMap2D());
1026 _SimpleWaterMat
.setTexture(0, shape
->_EnvMap
[1]);
1031 _SimpleWaterMat
.setTexture(0, shape
->_EnvMap
[1]);
1036 if (shape
->_UsesSceneWaterEnvMap
[0])
1038 if (scene
->getWaterEnvMap())
1040 _SimpleWaterMat
.setTexture(0, scene
->getWaterEnvMap()->getEnvMap2D());
1044 _SimpleWaterMat
.setTexture(0, shape
->_EnvMap
[0]);
1049 _SimpleWaterMat
.setTexture(0, shape
->_EnvMap
[0]);
1053 if (shape
->_ColorMap
== NULL
)
1055 // version with no color map
1056 if (!_EmbossTexture
)
1058 _EmbossTexture
= new CTextureEmboss
;
1059 _EmbossTexture
->setSlopeFactor(4.f
);
1061 if (shape
->_BumpMap
[1] && shape
->_BumpMap
[1]->isBumpMap())
1063 CTextureBump
*bm
= static_cast<CTextureBump
*>((ITexture
*) shape
->_BumpMap
[1]);
1064 if (bm
->getHeightMap())
1066 _EmbossTexture
->setHeightMap(bm
->getHeightMap());
1069 _SimpleWaterMat
.setTexture(1, _EmbossTexture
);
1070 _SimpleWaterMat
.setTexCoordGen(1, true);
1071 _SimpleWaterMat
.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace
);
1072 double date
= scene
->getCurrentTime();
1074 texMat
.scale(CVector(shape
->_HeightMapScale
[1].x
, shape
->_HeightMapScale
[1].y
, 1.f
));
1075 texMat
.setPos(CVector(fmodf(shape
->_HeightMapScale
[1].x
* obsPos
.x
, 1.f
) + (float) fmod(date
* shape
->_HeightMapSpeed
[1].x
, 1),
1076 fmodf(shape
->_HeightMapScale
[1].y
* obsPos
.y
, 1.f
) + (float) fmod(date
* shape
->_HeightMapSpeed
[1].y
, 1),
1079 _SimpleWaterMat
.enableUserTexMat(1, true);
1080 _SimpleWaterMat
.setUserTexMat(1, texMat
);
1084 updateDiffuseMapMatrix();
1085 // version with a color map : it remplace the emboss texture
1086 _SimpleWaterMat
.setTexture(1, shape
->_ColorMap
);
1087 _SimpleWaterMat
.setTexCoordGen(1, true);
1088 _SimpleWaterMat
.setTexCoordGenMode(1, CMaterial::TexCoordGenObjectSpace
);
1093 _ColorMapMatColumn0.x, _ColorMapMatColumn1.x, 0, _ColorMapMatColumn0.x * obsPos.x + _ColorMapMatColumn1.x * obsPos.y + _ColorMapMatPos.x},
1094 _ColorMapMatColumn0.y, _ColorMapMatColumn1.y, 0, _ColorMapMatColumn0.y * obsPos.x + _ColorMapMatColumn1.y * obsPos.y + _ColorMapMatPos.y,
1101 _ColorMapMatColumn0
.x
, _ColorMapMatColumn0
.y
, 0.f
, 0.f
,
1102 _ColorMapMatColumn1
.x
, _ColorMapMatColumn1
.y
, 0.f
, 0.f
,
1104 _ColorMapMatColumn0
.x
* obsPos
.x
+ _ColorMapMatColumn1
.x
* obsPos
.y
+ _ColorMapMatPos
.x
, _ColorMapMatColumn0
.y
* obsPos
.x
+ _ColorMapMatColumn1
.y
* obsPos
.y
+ _ColorMapMatPos
.y
, 0.f
, 1.f
1107 _SimpleWaterMat
.enableUserTexMat(1, true);
1108 _SimpleWaterMat
.setUserTexMat(1, texMat
);
1113 //================================================
1114 void CWaterModel::computeClippedPoly()
1116 CWaterShape
*shape
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
1117 const std::vector
<CPlane
> &worldPyramid
= getOwnerScene()->getClipTrav().WorldFrustumPyramid
;
1118 _ClippedPoly
.Vertices
.resize(shape
->_Poly
.Vertices
.size());
1120 for (k
= 0; k
< shape
->_Poly
.Vertices
.size(); ++k
)
1122 _ClippedPoly
.Vertices
[k
].set(shape
->_Poly
.Vertices
[k
].x
,
1123 shape
->_Poly
.Vertices
[k
].y
,
1128 NLMISC::CPlane plvect[6];
1129 const NLMISC::CMatrix &viewMat = clipTrav.ViewMatrix;
1131 const sint numStepX = CWaterShape::getScreenXGridSize();
1132 const sint numStepY = CWaterShape::getScreenYGridSize();
1133 // 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
1134 float centerX = 0.5f * (clipTrav.Right + clipTrav.Left);
1135 const float fRight = centerX + (clipTrav.Right - centerX) * (-(float) CWaterShape::_XGridBorder + (float) numStepX) / numStepX;
1136 const float fLeft = centerX + (clipTrav.Left - centerX) * (-(float) CWaterShape::_XGridBorder + (float) numStepX) / numStepX;
1137 float centerY = 0.5f * (clipTrav.Bottom + clipTrav.Top);
1138 const float fTop = centerY + (clipTrav.Top - centerY) * (-(float) CWaterShape::_YGridBorder + (float) numStepY) / numStepY;
1139 const float fBottom = centerY + (clipTrav.Bottom - centerY) * (-(float) CWaterShape::_YGridBorder + (float) numStepY) / numStepY;
1140 // build pyramid corners
1141 const float nearDist = clipTrav.Near;
1142 const float farDist = clipTrav.Far;
1144 const NLMISC::CVector pfoc(0,0,0);
1145 const NLMISC::CVector lb( fLeft, nearDist, fBottom );
1146 const NLMISC::CVector lt( fLeft, nearDist, fTop );
1147 const NLMISC::CVector rb( fRight, nearDist, fBottom );
1148 const NLMISC::CVector rt(fRight, nearDist, fTop );
1149 const NLMISC::CVector lbfarDist(fLeft, farDist, fBottom);
1150 const NLMISC::CVector ltfarDist(fLeft, farDist, fTop );
1151 const NLMISC::CVector rtfarDist(fRight , farDist, fTop );
1153 plvect[0].make(lt, lb, rt); // near plane
1154 plvect[1].make(lbfarDist, ltfarDist, rtfarDist); // far plane
1155 plvect[2].make(pfoc, lt, lb);
1156 plvect[3].make(pfoc, rt, lt);
1157 plvect[4].make(pfoc, rb, rt);
1158 plvect[5].make(pfoc, lb, rb);
1159 const NLMISC::CMatrix pyramidMat = viewMat * getWorldMatrix();
1160 for (k = 0; k < worldPyramid.size(); ++k)
1162 plvect[k] = plvect[k] * pyramidMat; // put the plane in object space
1164 _ClippedPoly.clip(plvect, 6);
1166 static std::vector
<CPlane
> tp
;
1167 tp
.resize(worldPyramid
.size());
1168 for(uint k
= 0; k
< tp
.size(); ++k
)
1170 tp
[k
] = worldPyramid
[k
] * getWorldMatrix();
1172 _ClippedPoly
.clip(tp
);
1175 // ***********************************************************************************************************
1176 void CWaterModel::unlink()
1185 _Next
->_Prev
= _Prev
;
1192 // ***********************************************************************************************************
1193 void CWaterModel::link()
1195 nlassert(_Next
== NULL
);
1196 CScene
*scene
= getOwnerScene();
1198 CRenderTrav
&rt
= scene
->getRenderTrav();
1199 _Prev
= &rt
._FirstWaterModel
;
1200 _Next
= rt
._FirstWaterModel
;
1203 _Next
->_Prev
= &_Next
;
1205 rt
._FirstWaterModel
= this;
1210 // ***********************************************************************************************************
1211 uint
CWaterModel::getNumWantedVertices()
1213 H_AUTO( NL3D_Water_Render
);
1214 nlassert(!_ClippedPoly
.Vertices
.empty());
1216 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
1217 if (!renderTrav
.Perspective
|| forceWaterSimpleRender
) return 0;
1218 // viewer pos in world space
1219 const NLMISC::CVector
&obsPos
= renderTrav
.CamPos
;
1220 // view matrix (inverted cam matrix)
1221 const NLMISC::CMatrix
&viewMat
= renderTrav
.ViewMatrix
;
1222 // plane z pos in world
1223 const float zHeight
= getWorldMatrix().getPos().z
;
1224 const sint numStepX
= CWaterShape::getScreenXGridSize();
1225 const sint numStepY
= CWaterShape::getScreenYGridSize();
1226 NLMISC::CMatrix modelMat
;
1227 modelMat
.setPos(NLMISC::CVector(obsPos
.x
, obsPos
.y
, zHeight
));
1228 static NLMISC::CPolygon2D projPoly
; // projected poly
1229 projPoly
.Vertices
.resize(_ClippedPoly
.Vertices
.size());
1230 // factor to project to grid units
1231 const float xFactor
= numStepX
* renderTrav
.Near
/ (renderTrav
.Right
- renderTrav
.Left
);
1232 const float yFactor
= numStepY
* renderTrav
.Near
/ (renderTrav
.Top
- renderTrav
.Bottom
);
1233 // project poly on near plane
1234 const NLMISC::CMatrix
&projMat
= viewMat
* getWorldMatrix();
1236 for (k
= 0; k
< _ClippedPoly
.Vertices
.size(); ++k
)
1238 // project points in the view
1239 NLMISC::CVector t
= projMat
* _ClippedPoly
.Vertices
[k
];
1240 float invY
= 1.f
/ t
.y
;
1241 projPoly
.Vertices
[k
].set(xFactor
* t
.x
* invY
, yFactor
* t
.z
* invY
);
1243 // compute grid cells that are entirely inside
1244 projPoly
.computeInnerBorders(_Inside
, _MinYInside
);
1245 // compute grid cells that are touched
1246 static NLMISC::CPolygon2D::TRasterVect border
;
1248 projPoly
.computeOuterBorders(border
, minYBorder
);
1249 // border - inside -> gives grid cells that must be clipped to fit the shape boundaries
1250 // Make sure that rasters array for inside has the same size that raster array for borders (by inserting NULL rasters)
1251 sint height
= (sint
)border
.size();
1252 if (_Inside
.empty())
1254 _MinYInside
= minYBorder
;
1256 sint bottomGap
= (sint
)(border
.size() - _Inside
.size());
1257 _Inside
.resize(height
);
1258 nlassert(minYBorder
== _MinYInside
);
1260 nlassert(bottomGap
>= 0);
1263 for(sint y
= height
- bottomGap
; y
< height
; ++y
)
1265 nlassert (y
>= 0 && y
< (sint
)_Inside
.size());
1266 _Inside
[y
].first
= border
[y
].first
;
1267 _Inside
[y
].second
= border
[y
].first
- 1; // insert null raster
1271 for(sint y
= 0; y
< height
- bottomGap
; ++y
)
1273 if (_Inside
[y
].first
> _Inside
[y
].second
)
1275 nlassert (y
>= 0 && y
< (sint
)_Inside
.size());
1276 _Inside
[y
].first
= border
[y
].first
;
1277 _Inside
[y
].second
= border
[y
].first
- 1;
1279 else if (border
[y
].first
> border
[y
].second
)
1281 nlassert (y
>= 0 && y
< (sint
)_Inside
.size());
1282 border
[y
].first
= _Inside
[y
].first
;
1283 border
[y
].second
= _Inside
[y
].first
- 1;
1286 // compute clip planes
1287 static std::vector
<CPlane
> clipPlanes
;
1289 const CVector2f
*prevVert
= &projPoly
.Vertices
.back();
1290 const CVector2f
*currVert
= &projPoly
.Vertices
.front();
1291 uint numVerts
= (uint
)projPoly
.Vertices
.size();
1292 bool ccw
= projPoly
.isCCWOriented();
1293 clipPlanes
.resize(numVerts
);
1294 for(uint k
= 0; k
< numVerts
; ++k
)
1299 v0
.set(prevVert
->x
, prevVert
->y
, 0.f
);
1300 v1
.set(currVert
->x
, currVert
->y
, 0.f
);
1301 v2
.set(prevVert
->x
, prevVert
->y
, (*currVert
- *prevVert
).norm());
1302 clipPlanes
[k
].make(v0
, v1
, v2
);
1305 clipPlanes
[k
].invert();
1307 prevVert
= currVert
;
1310 // compute clipped tris
1311 _ClippedTriNumVerts
.clear();
1312 _ClippedTris
.clear();
1313 static NLMISC::CPolygon clipPoly
;
1314 uint totalNumVertices
= 0;
1315 // compute number of vertices for whole grid cells
1316 for(sint k
= 0; k
< (sint
) border
.size(); ++k
)
1318 // left clipped blocks
1319 for (sint x
= border
[k
].first
; x
< _Inside
[k
].first
; ++x
)
1321 clipPoly
.Vertices
.resize(4);
1322 clipPoly
.Vertices
[0].set((float) x
, (float) (k
+ _MinYInside
), 0.f
);
1323 clipPoly
.Vertices
[1].set((float) (x
+ 1), (float) (k
+ _MinYInside
), 0.f
);
1324 clipPoly
.Vertices
[2].set((float) (x
+ 1), (float) (k
+ _MinYInside
+ 1), 0.f
);
1325 clipPoly
.Vertices
[3].set((float) x
, (float) (k
+ _MinYInside
+ 1), 0.f
);
1326 clipPoly
.clip(clipPlanes
);
1327 if (!clipPoly
.Vertices
.empty())
1329 // backup result (will be unprojected later)
1330 _ClippedTriNumVerts
.push_back((uint
)clipPoly
.Vertices
.size());
1331 uint prevSize
= (uint
)_ClippedTris
.size();
1332 _ClippedTris
.resize(_ClippedTris
.size() + clipPoly
.Vertices
.size());
1333 std::copy(clipPoly
.Vertices
.begin(), clipPoly
.Vertices
.end(), _ClippedTris
.begin() + prevSize
); // append to packed list
1334 totalNumVertices
+= ((uint
)clipPoly
.Vertices
.size() - 2) * 3;
1337 // middle block, are not clipped, but count the number of wanted vertices
1338 if (_Inside
[k
].first
<= _Inside
[k
].second
)
1340 totalNumVertices
+= 6 * (_Inside
[k
].second
- _Inside
[k
].first
+ 1);
1342 // right clipped blocks
1343 for (sint x
= _Inside
[k
].second
+ 1; x
<= border
[k
].second
; ++x
)
1345 clipPoly
.Vertices
.resize(4);
1346 clipPoly
.Vertices
[0].set((float) x
, (float) (k
+ _MinYInside
), 0.f
);
1347 clipPoly
.Vertices
[1].set((float) (x
+ 1), (float) (k
+ _MinYInside
), 0.f
);
1348 clipPoly
.Vertices
[2].set((float) (x
+ 1), (float) (k
+ _MinYInside
+ 1), 0.f
);
1349 clipPoly
.Vertices
[3].set((float) x
, (float) (k
+ _MinYInside
+ 1), 0.f
);
1350 clipPoly
.clip(clipPlanes
);
1351 if (!clipPoly
.Vertices
.empty())
1353 // backup result (will be unprojected later)
1354 _ClippedTriNumVerts
.push_back((uint
)clipPoly
.Vertices
.size());
1355 uint prevSize
= (uint
)_ClippedTris
.size();
1356 _ClippedTris
.resize(_ClippedTris
.size() + clipPoly
.Vertices
.size());
1357 std::copy(clipPoly
.Vertices
.begin(), clipPoly
.Vertices
.end(), _ClippedTris
.begin() + prevSize
); // append to packed list
1358 totalNumVertices
+= ((uint
)clipPoly
.Vertices
.size() - 2) * 3;
1362 return totalNumVertices
;
1365 // ***********************************************************************************************************
1366 uint
CWaterModel::fillVB(void *datas
, uint startTri
, IDriver
&drv
)
1368 H_AUTO( NL3D_Water_Render
);
1369 if (drv
.supportWaterShader())
1371 return fillVBHard(datas
, startTri
);
1375 return fillVBSoft(datas
, startTri
);
1381 static const double WATER_WAVE_SPEED
= 1.7;
1382 static const double WATER_WAVE_SCALE
= 0.05;
1383 static const double WATER_WAVE_FREQ
= 0.3;
1384 static const float WATER_WAVE_ATTEN
= 0.2f
;
1389 // compute single water vertex in software mode
1394 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
)
1396 CVector d
= px
* camI
+ py
* camK
+ camJ
;
1397 //nlassert(d.z > 0.f);
1398 float intersectionDist
= denom
/ d
.z
;
1399 pos
.x
= intersectionDist
* d
.x
;
1400 pos
.y
= intersectionDist
* d
.y
;
1407 float dist
= R
.norm();
1412 envMapTexCoord
.set(- 0.5f
* R
.x
+ 0.5f
, - 0.5f
* R
.y
+ 0.5f
);
1415 float invDist
= 1.f
/ (WATER_WAVE_ATTEN
* dist
);
1416 if (invDist
> 1.f
) invDist
= 1.f
;
1417 // TODO : optimize cos if need (for now there are not much call per frame ...)
1418 envMapTexCoord
.x
+= (float) (invDist
* WATER_WAVE_SCALE
* (float) cos(date
+ WATER_WAVE_FREQ
* (camPos
.x
+ pos
.x
)));
1422 // ***********************************************************************************************************
1423 uint
CWaterModel::fillVBSoft(void *datas
, uint startTri
)
1425 _StartTri
= (uint32
) startTri
;
1426 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
1427 const NLMISC::CMatrix
&camMat
= renderTrav
.CamMatrix
;
1428 const sint numStepX
= CWaterShape::getScreenXGridSize();
1429 const sint numStepY
= CWaterShape::getScreenYGridSize();
1430 CVector camI
= camMat
.getI() * (1.f
/ numStepX
) * (renderTrav
.Right
- renderTrav
.Left
) / renderTrav
.Near
;
1431 CVector camJ
= camMat
.getJ();
1432 CVector camK
= camMat
.getK() * (1.f
/ numStepY
) * (renderTrav
.Top
- renderTrav
.Bottom
) / renderTrav
.Near
;
1433 float obsZ
= camMat
.getPos().z
;
1434 float denom
= getWorldMatrix().getPos().z
- obsZ
;
1435 uint8
*dest
= (uint8
*) datas
+ startTri
* 3 * WATER_VERTEX_SOFT_SIZE
;
1436 /*NLMISC::CVector eye = renderTrav.CamPos;
1437 eye.z -= getWorldMatrix().getPos().z; */
1438 NLMISC::CVector
eye(0.f
, 0.f
, - denom
);
1440 CScene
*scene
= getOwnerScene();
1441 double date
= WATER_WAVE_SPEED
* scene
->getCurrentTime();
1442 if (!_ClippedTriNumVerts
.empty())
1444 const CVector2f
*currVert
= &_ClippedTris
.front();
1445 static std::vector
<CVector
> unprojectedTriSoft
;
1446 static std::vector
<CVector2f
> envMap
;
1447 for(uint k
= 0; k
< _ClippedTriNumVerts
.size(); ++k
)
1449 unprojectedTriSoft
.resize(_ClippedTriNumVerts
[k
]);
1450 envMap
.resize(_ClippedTriNumVerts
[k
]);
1451 uint numVerts
= _ClippedTriNumVerts
[k
];
1452 for(uint l
= 0; l
< _ClippedTriNumVerts
[k
]; ++l
)
1454 computeWaterVertexSoft(currVert
->x
, currVert
->y
, unprojectedTriSoft
[l
], envMap
[l
], camI
, camJ
, camK
, denom
, date
, camMat
.getPos());
1457 for(uint l
= 0; l
< numVerts
- 2; ++l
)
1459 *(CVector
*) dest
= unprojectedTriSoft
[0];
1460 dest
+= sizeof(float[3]);
1461 *(CVector2f
*) dest
= envMap
[0];
1462 dest
+= sizeof(float[2]);
1463 *(CVector
*) dest
= unprojectedTriSoft
[l
+ 1];
1464 dest
+= sizeof(float[3]);
1465 *(CVector2f
*) dest
= envMap
[l
+ 1];
1466 dest
+= sizeof(float[2]);
1467 *(CVector
*) dest
= unprojectedTriSoft
[l
+ 2];
1468 dest
+= sizeof(float[3]);
1469 *(CVector2f
*) dest
= envMap
[l
+ 2];
1470 dest
+= sizeof(float[2]);
1474 // TODO : optimize if needed
1475 for(sint k
= 0; k
< (sint
) _Inside
.size(); ++k
)
1477 sint y
= k
+ _MinYInside
;
1479 CVector2f envMap
[4];
1480 if (_Inside
[k
].first
<= _Inside
[k
].second
)
1482 // middle block, are not clipped, but count the number of wanted vertices
1483 for(sint x
= _Inside
[k
].first
; x
<= _Inside
[k
].second
; ++x
)
1485 computeWaterVertexSoft((float) x
, (float) y
, proj
[0], envMap
[0], camI
, camJ
, camK
, denom
, date
, camMat
.getPos());
1486 computeWaterVertexSoft((float)(x
+ 1), (float) y
, proj
[1], envMap
[1], camI
, camJ
, camK
, denom
, date
, camMat
.getPos());
1487 computeWaterVertexSoft((float) (x
+ 1), (float) (y
+ 1), proj
[2], envMap
[2], camI
, camJ
, camK
, denom
, date
, camMat
.getPos());
1488 computeWaterVertexSoft((float) x
, (float) (y
+ 1), proj
[3], envMap
[3], camI
, camJ
, camK
, denom
, date
, camMat
.getPos());
1490 *(CVector
*) dest
= proj
[0];
1491 dest
+= sizeof(float[3]);
1492 *(CVector2f
*) dest
= envMap
[0];
1493 dest
+= sizeof(float[2]);
1494 *(CVector
*) dest
= proj
[2];
1495 dest
+= sizeof(float[3]);
1496 *(CVector2f
*) dest
= envMap
[2];
1497 dest
+= sizeof(float[2]);
1498 *(CVector
*) dest
= proj
[1];
1499 dest
+= sizeof(float[3]);
1500 *(CVector2f
*) dest
= envMap
[1];
1501 dest
+= sizeof(float[2]);
1502 *(CVector
*) dest
= proj
[0];
1503 dest
+= sizeof(float[3]);
1504 *(CVector2f
*) dest
= envMap
[0];
1505 dest
+= sizeof(float[2]);
1506 *(CVector
*) dest
= proj
[3];
1507 dest
+= sizeof(float[3]);
1508 *(CVector2f
*) dest
= envMap
[3];
1509 dest
+= sizeof(float[2]);
1510 *(CVector
*) dest
= proj
[2];
1511 dest
+= sizeof(float[3]);
1512 *(CVector2f
*) dest
= envMap
[2];
1513 dest
+= sizeof(float[2]);
1517 nlassert((dest
- (uint8
* ) datas
) % (3 * WATER_VERTEX_SOFT_SIZE
) == 0);
1518 uint endTri
= (uint
)(dest
- (uint8
* ) datas
) / (3 * WATER_VERTEX_SOFT_SIZE
);
1519 _NumTris
= endTri
- _StartTri
;
1523 // compute single water vertex for hardware render
1528 void computeWaterVertexHard(float px
, float py
, CVector
&pos
, const CVector
&camI
, const CVector
&camJ
, const CVector
&camK
, float denom
)
1530 CVector d
= px
* camI
+ py
* camK
+ camJ
;
1531 float intersectionDist
= denom
/ d
.z
;
1532 pos
.x
= intersectionDist
* d
.x
;
1533 pos
.y
= intersectionDist
* d
.y
;
1537 // ***********************************************************************************************************
1538 uint
CWaterModel::fillVBHard(void *datas
, uint startTri
)
1540 _StartTri
= (uint32
) startTri
;
1541 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
1542 const NLMISC::CMatrix
&camMat
= renderTrav
.CamMatrix
;
1543 const sint numStepX
= CWaterShape::getScreenXGridSize();
1544 const sint numStepY
= CWaterShape::getScreenYGridSize();
1545 CVector camI
= camMat
.getI() * (1.f
/ numStepX
) * (renderTrav
.Right
- renderTrav
.Left
) / renderTrav
.Near
;
1546 CVector camJ
= camMat
.getJ();
1547 CVector camK
= camMat
.getK() * (1.f
/ numStepY
) * (renderTrav
.Top
- renderTrav
.Bottom
) / renderTrav
.Near
;
1548 float obsZ
= camMat
.getPos().z
;
1549 float denom
= getWorldMatrix().getPos().z
- obsZ
;
1550 uint8
*dest
= (uint8
*) datas
+ startTri
* WATER_VERTEX_HARD_SIZE
* 3;
1551 if (!_ClippedTriNumVerts
.empty())
1553 const CVector2f
*currVert
= &_ClippedTris
.front();
1554 static std::vector
<CVector
> unprojectedTri
;
1555 for(uint k
= 0; k
< _ClippedTriNumVerts
.size(); ++k
)
1557 unprojectedTri
.resize(_ClippedTriNumVerts
[k
]);
1558 uint numVerts
= _ClippedTriNumVerts
[k
];
1559 for(uint l
= 0; l
< _ClippedTriNumVerts
[k
]; ++l
)
1561 computeWaterVertexHard(currVert
->x
, currVert
->y
, unprojectedTri
[l
], camI
, camJ
, camK
, denom
);
1564 for(uint l
= 0; l
< numVerts
- 2; ++l
)
1566 *(CVector
*) dest
= unprojectedTri
[0];
1567 dest
+= WATER_VERTEX_HARD_SIZE
;
1568 *(CVector
*) dest
= unprojectedTri
[l
+ 1];
1569 dest
+= WATER_VERTEX_HARD_SIZE
;
1570 *(CVector
*) dest
= unprojectedTri
[l
+ 2];
1571 dest
+= WATER_VERTEX_HARD_SIZE
;
1575 // TODO : optimize if needed
1576 for(sint k
= 0; k
< (sint
) _Inside
.size(); ++k
)
1578 sint y
= k
+ _MinYInside
;
1580 if (_Inside
[k
].first
<= _Inside
[k
].second
)
1582 // middle block, are not clipped, but count the number of wanted vertices
1583 for(sint x
= _Inside
[k
].first
; x
<= _Inside
[k
].second
; ++x
)
1585 computeWaterVertexHard((float) x
, (float) y
, proj
[0], camI
, camJ
, camK
, denom
);
1586 computeWaterVertexHard((float) (x
+ 1), (float) y
, proj
[1], camI
, camJ
, camK
, denom
);
1587 computeWaterVertexHard((float) (x
+ 1), (float) (y
+ 1), proj
[2], camI
, camJ
, camK
, denom
);
1588 computeWaterVertexHard((float) x
, (float) (y
+ 1), proj
[3], camI
, camJ
, camK
, denom
);
1590 *(CVector
*) dest
= proj
[0];
1591 dest
+= WATER_VERTEX_HARD_SIZE
;
1592 *(CVector
*) dest
= proj
[2];
1593 dest
+= WATER_VERTEX_HARD_SIZE
;
1594 *(CVector
*) dest
= proj
[1];
1595 dest
+= WATER_VERTEX_HARD_SIZE
;
1596 *(CVector
*) dest
= proj
[0];
1597 dest
+= WATER_VERTEX_HARD_SIZE
;
1598 *(CVector
*) dest
= proj
[3];
1599 dest
+= WATER_VERTEX_HARD_SIZE
;
1600 *(CVector
*) dest
= proj
[2];
1601 dest
+= WATER_VERTEX_HARD_SIZE
;
1605 nlassert((dest
- (uint8
* ) datas
) % (3 * WATER_VERTEX_HARD_SIZE
) == 0);
1606 uint endTri
= (uint
)(dest
- (uint8
* ) datas
) / (3 * WATER_VERTEX_HARD_SIZE
);
1607 _NumTris
= endTri
- _StartTri
;
1615 // ***************************************************************************************************************
1616 void CWaterModel::traverseRender()
1618 H_AUTO( NL3D_Water_Render
);
1620 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
1621 IDriver
*drv
= renderTrav
.getDriver();
1622 CWaterShape
*shape
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
1623 const NLMISC::CVector
&obsPos
= renderTrav
.CamPos
;
1624 const float zHeight
= getWorldMatrix().getPos().z
;
1626 if (!renderTrav
.Perspective
|| forceWaterSimpleRender
)
1628 // not supported, simple uniform render
1629 drv
->setupModelMatrix(getWorldMatrix());
1630 static CMaterial waterMat
;
1631 static bool initDone
= false;
1634 waterMat
.initUnlit();
1635 waterMat
.setBlend(true);
1636 waterMat
.setSrcBlend(CMaterial::srcalpha
);
1637 waterMat
.setDstBlend(CMaterial::invsrcalpha
);
1638 waterMat
.setBlend(true);
1639 waterMat
.setDoubleSided(true);
1640 waterMat
.setLighting(false);
1642 waterMat
.setColor(shape
->computeEnvMapMeanColor());
1643 static std::vector
<NLMISC::CTriangleUV
> tris
;
1644 const NLMISC::CPolygon2D
&poly
= shape
->getShape();
1646 for(sint k
= 0; k
< (sint
) poly
.Vertices
.size() - 2; ++k
)
1648 NLMISC::CTriangleUV truv
;
1649 truv
.Uv0
.set(0.f
, 0.f
);
1650 truv
.Uv1
.set(0.f
, 0.f
);
1651 truv
.Uv2
.set(0.f
, 0.f
);
1652 truv
.V0
.set(poly
.Vertices
[0].x
, poly
.Vertices
[0].y
, 0.f
);
1653 truv
.V1
.set(poly
.Vertices
[k
+ 1].x
, poly
.Vertices
[k
+ 1].y
, 0.f
);
1654 truv
.V2
.set(poly
.Vertices
[k
+ 2].x
, poly
.Vertices
[k
+ 2].y
, 0.f
);
1655 tris
.push_back(truv
);
1657 CDRU::drawTrianglesUnlit(tris
, waterMat
, *drv
);
1661 NLMISC::CMatrix modelMat
;
1662 modelMat
.setPos(NLMISC::CVector(obsPos
.x
, obsPos
.y
, zHeight
));
1663 drv
->setupModelMatrix(modelMat
);
1664 bool isAbove
= obsPos
.z
> getWorldMatrix().getPos().z
;
1665 CVertexBuffer
&vb
= renderTrav
.Scene
->getWaterVB();
1666 if (drv
->supportWaterShader())
1668 setupMaterialNVertexShader(drv
, shape
, obsPos
, isAbove
, zHeight
);
1669 nlassert(vb
.getNumVertices() > 0);
1670 drv
->activeVertexBuffer(vb
);
1671 drv
->renderRawTriangles(CWaterModel::_WaterMat
, _StartTri
, _NumTris
);
1672 drv
->activeVertexProgram(NULL
);
1676 setupSimpleRender(shape
, obsPos
, isAbove
);
1677 drv
->activeVertexBuffer(vb
);
1678 drv
->activeVertexProgram(NULL
);
1679 drv
->renderRawTriangles(CWaterModel::_SimpleWaterMat
, _StartTri
, _NumTris
);
1686 // ***********************************************************************************************************
1687 bool CWaterModel::clip()
1689 H_AUTO( NL3D_Water_Render
);
1690 CRenderTrav
&renderTrav
= getOwnerScene()->getRenderTrav();
1691 if (renderTrav
.CamPos
.z
== getWorldMatrix().getPos().z
) return false;
1694 computeClippedPoly();
1695 if (_ClippedPoly
.Vertices
.empty()) return false;
1696 // unlink from water model list
1698 // link into water model list
1708 // struct used to build vertices for the simple shader
1709 struct CSimpleVertexInfo
1711 NLMISC::CVector XFormPos;
1716 // ***********************************************************************************************************
1718 void CWaterModel::doSimpleRender(IDriver *drv)
1720 if (_ClippedPoly.Vertices.empty()) return;
1721 // rendering of water when no vertex / pixel shaders are available
1722 CWaterShape *shape = NLMISC::safe_cast<CWaterShape *>((IShape *) Shape);
1723 CRenderTrav &renderTrav = getOwnerScene()->getRenderTrav();
1724 static bool init = false;
1727 // setup the material, no special shader is used here
1728 _SimpleWaterMat.setLighting(false);
1729 _SimpleWaterMat.setDoubleSided(true);
1730 _SimpleWaterMat.setColor(NLMISC::CRGBA::White);
1732 _SimpleWaterMat.setBlend(true);
1733 _SimpleWaterMat.setSrcBlend(CMaterial::srcalpha);
1734 _SimpleWaterMat.setDstBlend(CMaterial::invsrcalpha);
1735 _SimpleWaterMat.setZWrite(true);
1736 _SimpleWaterMat.setShader(CMaterial::Normal);
1739 _SimpleWaterMat.texEnvOpRGB(0, CMaterial::Replace);
1740 _SimpleWaterMat.texEnvOpAlpha(0, CMaterial::Replace);
1741 _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
1742 _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
1745 _SimpleWaterMat.texEnvOpRGB(1, CMaterial::Modulate);
1746 _SimpleWaterMat.texEnvOpAlpha(1, CMaterial::Modulate);
1747 _SimpleWaterMat.texEnvArg0RGB(0, CMaterial::Texture, CMaterial::SrcColor);
1748 _SimpleWaterMat.texEnvArg0Alpha(0, CMaterial::Texture, CMaterial::SrcAlpha);
1749 _SimpleWaterMat.texEnvArg1RGB(0, CMaterial::Previous, CMaterial::SrcColor);
1750 _SimpleWaterMat.texEnvArg1Alpha(0, CMaterial::Previous, CMaterial::SrcAlpha);
1752 // setup the vb : one position & two tex coords
1753 _SimpleRenderVB.setVertexFormat(CVertexBuffer::PositionFlag | CVertexBuffer::TexCoord0Flag | CVertexBuffer::TexCoord1Flag);
1757 const NLMISC::CMatrix &worldMatrix = getWorldMatrix();
1758 const NLMISC::CVector &obsPos = renderTrav.CamPos;
1760 // setup the material
1761 bool isAbove = obsPos.z > worldMatrix.getPos().z;
1763 // envmap is always present and is in stage 0
1764 CScene *scene = getOwnerScene();
1765 if (!isAbove && shape->_EnvMap[1])
1767 if (shape->_UsesSceneWaterEnvMap[1])
1769 if (scene->getWaterEnvMap())
1771 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
1775 _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
1780 _SimpleWaterMat.setTexture(0, shape->_EnvMap[1]);
1785 if (shape->_UsesSceneWaterEnvMap[0])
1787 if (scene->getWaterEnvMap())
1789 _SimpleWaterMat.setTexture(0, scene->getWaterEnvMap()->getEnvMap2D());
1793 _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
1798 _SimpleWaterMat.setTexture(0, shape->_EnvMap[0]);
1802 static std::vector<CSimpleVertexInfo> verts;
1803 static CIndexBuffer indices;
1805 NLMISC::CPolygon2D &poly = shape->_Poly;
1806 uint numVerts = poly.Vertices.size();
1809 if (shape->_ColorMap == NULL)
1811 // version with no color map
1812 if (!_EmbossTexture)
1814 _EmbossTexture = new CTextureEmboss;
1815 _EmbossTexture->setSlopeFactor(4.f);
1817 if (shape->_BumpMap[1] && shape->_BumpMap[1]->isBumpMap())
1819 CTextureBump *bm = static_cast<CTextureBump *>((ITexture *) shape->_BumpMap[1]);
1820 if (bm->getHeightMap())
1822 _EmbossTexture->setHeightMap(bm->getHeightMap());
1825 _SimpleWaterMat.setTexture(1, _EmbossTexture);
1826 _SimpleRenderVB.setNumVertices(numVerts);
1827 // retrieve current time
1828 float date = 0.001f * (NLMISC::CTime::getLocalTime() & 0xffffff); // must keep some precision.
1829 // Compute tex coordinates for emboss first.
1830 // On some 3D chip, textures coords can't grow too mush or texture filtering loose accuracy.
1831 // So we must keep texCoord as low as possible.
1833 verts.resize(numVerts);
1834 for(k = 0; k < numVerts; ++k)
1836 verts[k].XFormPos = worldMatrix * NLMISC::CVector(poly.Vertices[k].x, poly.Vertices[k].y ,0.f);
1837 verts[k].UV.U = shape->_HeightMapScale[0].x * verts[k].XFormPos.x + date * shape->_HeightMapSpeed[0].x;
1838 verts[k].UV.V = shape->_HeightMapScale[0].y * verts[k].XFormPos.y + date * shape->_HeightMapSpeed[0].y;
1840 // get min tex coords
1841 float minU = verts[0].UV.U;
1842 float minV = verts[0].UV.V;
1843 for(k = 1; k < numVerts; ++k)
1845 minU = std::min(minU, verts[k].UV.U);
1846 minV = std::min(minV, verts[k].UV.V);
1849 minU = floorf(minU);
1850 minV = floorf(minV);
1852 CVertexBufferReadWrite vba;
1853 _SimpleRenderVB.lock (vba);
1854 uint8 *data = (uint8 *) vba.getVertexCoordPointer();
1855 for(k = 0; k < numVerts; ++k)
1857 ((NLMISC::CVector *) data)->set(poly.Vertices[k].x, poly.Vertices[k].y, 0.f);
1858 data += sizeof(NLMISC::CVector);
1859 // texture coord 0 is reflected vector into envmap
1860 // xform position in world space to compute the reflection
1861 CVector surfToEye = (obsPos - verts[k].XFormPos).normed();
1862 // we assume that normal is (0, 0, 1)
1863 * (float *) data = 0.5f - 0.5f * surfToEye.x;
1864 ((float *) data)[1] = 0.5f - 0.5f * surfToEye.y;
1865 data += sizeof(float[2]);
1866 // texture coord 1 is the embossed map
1867 * (float *) data = verts[k].UV.U - minU;
1868 ((float *) data)[1] = verts[k].UV.V - minV;
1869 data += sizeof(float[2]);
1874 // version with a color map : it remplace the emboss texture
1875 _SimpleWaterMat.setTexture(1, shape->_ColorMap);
1876 _SimpleRenderVB.setNumVertices(numVerts);
1877 CVertexBufferReadWrite vba;
1878 _SimpleRenderVB.lock (vba);
1880 uint8 *data = (uint8 *) vba.getVertexCoordPointer();
1881 for(k = 0; k < numVerts; ++k)
1883 * (NLMISC::CVector *) data = poly.Vertices[k];
1884 data += sizeof(CVector);
1885 // texture coord 0 is reflected vector into envmap
1886 // xform position in world space to compute the reflection
1887 NLMISC::CVector xformPos = worldMatrix * poly.Vertices[k];
1888 NLMISC::CVector surfToEye = (obsPos - xformPos).normed();
1889 // we assume that normal is (0, 0, 1)
1890 * (float *) data = 0.5f - 0.5f * surfToEye.x;
1891 ((float *) data)[1] = 0.5f * - 0.5f * surfToEye.y;
1892 data += sizeof(float[2]);
1893 // texture coord 1 is the color map
1894 * (float *) data = shape->_ColorMapMatColumn0.x * xformPos.x + shape->_ColorMapMatColumn1.x * xformPos.y + shape->_ColorMapMatPos.x;
1895 ((float *) data)[1] = shape->_ColorMapMatColumn0.y * xformPos.x + shape->_ColorMapMatColumn1.y * xformPos.y + shape->_ColorMapMatPos.y;
1896 data += sizeof(float[2]);
1900 drv->activeVertexProgram(NULL);
1901 drv->setupModelMatrix(worldMatrix);
1902 drv->activeVertexBuffer(_SimpleRenderVB);
1904 // create an index buffer to do the display
1905 indices.setNumIndexes((numVerts - 2) * 3);
1907 CIndexBufferReadWrite ibaWrite;
1908 indices.lock (ibaWrite);
1909 uint32 *ptr = ibaWrite.getPtr();
1910 for(k = 0; k < (numVerts - 2); ++k)
1914 ptr[ k * 3 + 1 ] = k + 1;
1915 ptr[ k * 3 + 2 ] = k + 2;
1918 drv->setupMaterial(_SimpleWaterMat);
1919 drv->activeIndexBuffer(indices);
1920 drv->renderSimpleTriangles(0, numVerts - 2);
1924 // ***********************************************************************************************************
1925 void CWaterModel::updateDiffuseMapMatrix(bool force
/* = false*/)
1927 if (compareMatrixDate(_MatrixUpdateDate
) ||force
)
1929 CWaterShape
*shape
= NLMISC::safe_cast
<CWaterShape
*>((IShape
*) Shape
);
1932 _MatrixUpdateDate
= getMatrixDate();
1933 // update the uv matrix
1935 uvMat
.setRot(CVector(shape
->_ColorMapMatColumn0
.x
, shape
->_ColorMapMatColumn0
.y
, 0.f
),
1936 CVector(shape
->_ColorMapMatColumn1
.x
, shape
->_ColorMapMatColumn1
.y
, 0.f
),
1937 CVector(shape
->_ColorMapMatPos
.x
, shape
->_ColorMapMatPos
.y
, 1.f
));
1939 CMatrix invMat
= this->getWorldMatrix().inverted();
1940 xformMat
.setRot(CVector(invMat
.getI().x
, invMat
.getI().y
, 0.f
),
1941 CVector(invMat
.getJ().x
, invMat
.getJ().y
, 0.f
),
1942 CVector(invMat
.getPos().x
, invMat
.getPos().y
, 1.f
));
1943 uvMat
= uvMat
* xformMat
;
1944 _ColorMapMatColumn0
.set(uvMat
.getI().x
, uvMat
.getI().y
);
1945 _ColorMapMatColumn1
.set(uvMat
.getJ().x
, uvMat
.getJ().y
);
1946 _ColorMapMatPos
.set(uvMat
.getK().x
, uvMat
.getK().y
);
1951 // ***************************************************************************
1952 void CWaterModel::debugDumpMem(void* &clippedPolyBegin
, void* &clippedPolyEnd
)
1954 clippedPolyBegin
= (void*)(&*_ClippedPoly
.Vertices
.begin());
1955 clippedPolyEnd
= (void*)(&*_ClippedPoly
.Vertices
.end());
1958 // ***************************************************************************
1959 void CWaterModel::debugClearClippedPoly()
1961 _ClippedPoly
.Vertices
.clear();
1964 //=======================================================================================
1965 // wave maker implementation
1966 //=======================================================================================
1968 CWaveMakerModel::CWaveMakerModel() : _Time(0)
1970 // AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
1971 CTransform::setIsForceAnimDetail(true);
1974 //================================================
1976 void CWaveMakerModel::registerBasic()
1978 CScene::registerModel(WaveMakerModelClassId
, TransformShapeId
, CWaveMakerModel::creator
);
1981 //================================================
1983 ITrack
* CWaveMakerModel::getDefaultTrack (uint valueId
)
1986 CWaveMakerShape
*ws
= NLMISC::safe_cast
<CWaveMakerShape
*>((IShape
*) Shape
);
1989 case PosValue
: return ws
->getDefaultPos(); break;
1990 default: // delegate to parent
1991 return CTransformShape::getDefaultTrack(valueId
);
1996 //================================================
1997 void CWaveMakerModel::traverseAnimDetail()
1999 CTransformShape::traverseAnimDetail();
2000 nlassert(getOwnerScene());
2002 CWaveMakerShape
*wms
= NLMISC::safe_cast
<CWaveMakerShape
*>((IShape
*) Shape
);
2003 const NLMISC::CVector worldPos
= getWorldMatrix().getPos();
2004 const CVector2f
pos2d(worldPos
.x
, worldPos
.y
);
2005 /// get the water height map
2006 CWaterHeightMap
&whm
= GetWaterPoolManager().getPoolByID(wms
->_PoolID
);
2007 // get the time delta
2008 const TAnimationTime deltaT
= std::min(getOwnerScene()->getEllapsedTime(), (TAnimationTime
) whm
.getPropagationTime());
2010 if (!wms
->_ImpulsionMode
)
2012 whm
.perturbate(pos2d
, wms
->_Intensity
* cosf(2.f
/ wms
->_Period
* (float) NLMISC::Pi
* _Time
), wms
->_Radius
);
2016 if (_Time
> wms
->_Period
)
2018 _Time
-= wms
->_Period
;
2019 whm
.perturbate(pos2d
, wms
->_Intensity
, wms
->_Radius
);