2010-05-06 00:08:41 +00:00
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "std3d.h"
# include "nel/misc/vector_2f.h"
# include "nel/misc/vector_h.h"
# include "nel/misc/hierarchical_timer.h"
# include "nel/3d/animation_time.h"
# include "nel/3d/water_model.h"
# include "nel/3d/water_shape.h"
# include "nel/3d/water_pool_manager.h"
# include "nel/3d/water_height_map.h"
# include "nel/3d/dru.h"
# include "nel/3d/scene.h"
# include "nel/3d/driver.h"
# include "nel/3d/render_trav.h"
# include "nel/3d/anim_detail_trav.h"
# include "nel/3d/texture_emboss.h"
# include "nel/3d/texture_bump.h"
# include "nel/3d/water_env_map.h"
using NLMISC : : CVector2f ;
namespace NL3D {
// for normal rendering
CMaterial CWaterModel : : _WaterMat ;
// for simple rendering
CMaterial CWaterModel : : _SimpleWaterMat ;
const uint WATER_MODEL_DEFAULT_NUM_VERTICES = 5000 ;
NLMISC : : CRefPtr < IDriver > CWaterModel : : _CurrDrv ;
// TMP
volatile bool forceWaterSimpleRender = false ;
//=======================================================================
void CWaterModel : : setupVertexBuffer ( CVertexBuffer & vb , uint numWantedVertices , IDriver * drv )
{
if ( ! numWantedVertices ) return ;
if ( vb . getNumVertices ( ) = = 0 | | drv ! = _CurrDrv ) // not setupped yet, or driver changed ?
{
vb . setNumVertices ( 0 ) ;
vb . setName ( " Water " ) ;
vb . setPreferredMemory ( CVertexBuffer : : AGPPreferred , false ) ;
if ( drv - > isWaterShaderSupported ( ) )
{
vb . setVertexFormat ( CVertexBuffer : : PositionFlag ) ;
}
else
{
vb . setVertexFormat ( CVertexBuffer : : PositionFlag | CVertexBuffer : : TexCoord0Flag ) ;
}
_CurrDrv = drv ;
}
uint numVerts = std : : max ( numWantedVertices , WATER_MODEL_DEFAULT_NUM_VERTICES ) ;
if ( numVerts > vb . getNumVertices ( ) )
{
const uint vb_INCREASE_SIZE = 1000 ;
numVerts = vb_INCREASE_SIZE * ( ( numVerts + ( vb_INCREASE_SIZE - 1 ) ) / vb_INCREASE_SIZE ) ; // snap size
vb . setNumVertices ( ( uint32 ) numVerts ) ;
}
}
//=======================================================================
CWaterModel : : CWaterModel ( )
{
setOpacity ( false ) ;
setTransparency ( true ) ;
setOrderingLayer ( 1 ) ;
// RenderFilter: We are a SegRemanece
_RenderFilterType = UScene : : FilterWater ;
_Prev = NULL ;
_Next = NULL ;
_MatrixUpdateDate = 0 ;
}
//=======================================================================
CWaterModel : : ~ CWaterModel ( )
{
CScene * scene = getOwnerScene ( ) ;
if ( scene & & scene - > getWaterCallback ( ) )
{
nlassert ( Shape ) ;
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
scene - > getWaterCallback ( ) - > waterSurfaceRemoved ( ws - > getUseSceneWaterEnvMap ( 0 ) | | ws - > getUseSceneWaterEnvMap ( 1 ) ) ;
}
// should be already unlinked, but security
unlink ( ) ;
}
//=======================================================================
void CWaterModel : : registerBasic ( )
{
CScene : : registerModel ( WaterModelClassId , TransformShapeId , CWaterModel : : creator ) ;
}
//=======================================================================
ITrack * CWaterModel : : getDefaultTrack ( uint valueId )
{
nlassert ( Shape ) ;
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
switch ( valueId )
{
case PosValue : return ws - > getDefaultPos ( ) ; break ;
case ScaleValue : return ws - > getDefaultScale ( ) ; break ;
case RotQuatValue : return ws - > getDefaultRotQuat ( ) ; break ;
default : // delegate to parent
return CTransformShape : : getDefaultTrack ( valueId ) ;
break ;
}
}
//=======================================================================
uint32 CWaterModel : : getWaterHeightMapID ( ) const
{
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
return ws - > _WaterPoolID ;
}
//=======================================================================
float CWaterModel : : getHeightFactor ( ) const
{
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
return ws - > _WaveHeightFactor ;
}
//=======================================================================
float CWaterModel : : getHeight ( const CVector2f & pos )
{
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
CWaterHeightMap & whm = GetWaterPoolManager ( ) . getPoolByID ( ws - > _WaterPoolID ) ;
const float height = whm . getHeight ( pos ) ;
return height * ws - > _WaveHeightFactor + this - > getPos ( ) . z ;
}
//=======================================================================
float CWaterModel : : getAttenuatedHeight ( const CVector2f & pos , const NLMISC : : CVector & viewer )
{
CWaterShape * ws = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
CWaterHeightMap & whm = GetWaterPoolManager ( ) . getPoolByID ( ws - > _WaterPoolID ) ;
const float maxDist = whm . getUnitSize ( ) * ( whm . getSize ( ) > > 1 ) ;
const NLMISC : : CVector planePos ( pos . x , pos . y , this - > getMatrix ( ) . getPos ( ) . z ) ;
const float userDist = ( planePos - viewer ) . norm ( ) ;
if ( userDist > maxDist )
{
return this - > getMatrix ( ) . getPos ( ) . z ;
}
else
{
const float height = whm . getHeight ( pos ) ;
return ws - > _WaveHeightFactor * height * ( 1.f - userDist / maxDist ) + this - > getMatrix ( ) . getPos ( ) . z ;
}
}
//=======================================================================
// perform a bilinear on 4 values
// 0---1
// | |
// 3---2
/*
static float inline BilinFilter ( float v0 , float v1 , float v2 , float v3 , float u , float v )
{
float g = v * v3 + ( 1.f - v ) * v0 ;
float h = v * v2 + ( 1.f - v ) * v1 ;
return u * h + ( 1.f - u ) * g ;
}
*/
//=======================================================================
/// store a value in a water vertex buffer, and increment the pointer
/*
static void inline FillWaterVB ( uint8 * & vbPointer , float x , float y , float z , float nx , float ny )
{
* ( float * ) vbPointer = x ;
( ( float * ) vbPointer ) [ 1 ] = y ;
( ( float * ) vbPointer ) [ 2 ] = z ;
* ( ( float * ) ( vbPointer + 3 * sizeof ( float ) ) ) = nx ;
* ( ( float * ) ( vbPointer + 4 * sizeof ( float ) ) ) = ny ;
vbPointer + = 5 * sizeof ( float ) ;
}
*/
//***************************************************************************************************************
/*
# ifdef NL_OS_WINDOWS
__forceinline
# endif
static void SetupWaterVertex ( sint qLeft ,
sint qRight ,
sint qUp ,
sint qDown ,
sint qSubLeft ,
sint qSubDown ,
const NLMISC : : CVector & inter ,
float invWaterRatio ,
sint doubleWaterHeightMapSize ,
CWaterHeightMap & whm ,
uint8 * & vbPointer ,
float offsetX ,
float offsetY
)
{
const float wXf = invWaterRatio * ( inter . x + offsetX ) ;
const float wYf = invWaterRatio * ( inter . y + offsetY ) ;
sint wx = ( sint ) floorf ( wXf ) ;
sint wy = ( sint ) floorf ( wYf ) ;
if ( !
( wx > = qLeft & & wx < qRight & & wy < qUp & & wy > = qDown )
)
{
// no perturbation is visible
FillWaterVB ( vbPointer , inter . x , inter . y , 0 , 0 , 0 ) ;
}
else
{
// filter height and gradient at the given point
const sint stride = doubleWaterHeightMapSize ;
const uint xm = ( uint ) ( wx - qSubLeft ) ;
const uint ym = ( uint ) ( wy - qSubDown ) ;
const sint offset = xm + stride * ym ;
const float * ptWater = whm . getPointer ( ) + offset ;
float deltaU = wXf - wx ;
float deltaV = wYf - wy ;
//nlassert(deltaU >= 0.f && deltaU <= 1.f && deltaV >= 0.f && deltaV <= 1.f);
const float * ptWaterPrev = whm . getPrevPointer ( ) + offset ;
float g0x , g1x , g2x , g3x ; // x gradient for current
float g0xp , g1xp , g2xp , g3xp ;
float gradCurrX , gradCurrY ;
float g0y , g1y , g2y , g3y ; // y gradient for previous map
float g0yp , g1yp , g2yp , g3yp ;
float gradPrevX , gradPrevY ;
/// curr gradient
g0x = ptWater [ 1 ] - ptWater [ - 1 ] ;
g1x = ptWater [ 2 ] - ptWater [ 0 ] ;
g2x = ptWater [ 2 + stride ] - ptWater [ stride ] ;
g3x = ptWater [ 1 + stride ] - ptWater [ - 1 + stride ] ;
gradCurrX = BilinFilter ( g0x , g1x , g2x , g3x , deltaU , deltaV ) ;
g0y = ptWater [ stride ] - ptWater [ - stride ] ;
g1y = ptWater [ stride + 1 ] - ptWater [ - stride + 1 ] ;
g2y = ptWater [ ( stride < < 1 ) + 1 ] - ptWater [ 1 ] ;
g3y = ptWater [ ( stride < < 1 ) ] - ptWater [ 0 ] ;
gradCurrY = BilinFilter ( g0y , g1y , g2y , g3y , deltaU , deltaV ) ;
/// prev gradient
g0xp = ptWaterPrev [ 1 ] - ptWaterPrev [ - 1 ] ;
g1xp = ptWaterPrev [ 2 ] - ptWaterPrev [ 0 ] ;
g2xp = ptWaterPrev [ 2 + stride ] - ptWaterPrev [ + stride ] ;
g3xp = ptWaterPrev [ 1 + stride ] - ptWaterPrev [ - 1 + stride ] ;
gradPrevX = BilinFilter ( g0xp , g1xp , g2xp , g3xp , deltaU , deltaV ) ;
g0yp = ptWaterPrev [ stride ] - ptWaterPrev [ - stride ] ;
g1yp = ptWaterPrev [ stride + 1 ] - ptWaterPrev [ - stride + 1 ] ;
g2yp = ptWaterPrev [ ( stride < < 1 ) + 1 ] - ptWaterPrev [ 1 ] ;
g3yp = ptWaterPrev [ ( stride < < 1 ) ] - ptWaterPrev [ 0 ] ;
gradPrevY = BilinFilter ( g0yp , g1yp , g2yp , g3yp , deltaU , deltaV ) ;
/// current height
float h = BilinFilter ( ptWater [ 0 ] , ptWater [ + 1 ] , ptWater [ 1 + stride ] , ptWater [ stride ] , deltaU , deltaV ) ;
/// previous height
float hPrev = BilinFilter ( ptWaterPrev [ 0 ] , ptWaterPrev [ 1 ] , ptWaterPrev [ 1 + stride ] , ptWaterPrev [ stride ] , deltaU , deltaV ) ;
float timeRatio = whm . getBufferRatio ( ) ;
FillWaterVB ( vbPointer , inter . x , inter . y , timeRatio * h + ( 1.f - timeRatio ) * hPrev ,
4.5f * ( timeRatio * gradCurrX + ( 1.f - timeRatio ) * gradPrevX ) ,
4.5f * ( timeRatio * gradCurrY + ( 1.f - timeRatio ) * gradPrevY )
) ;
//NLMISC::CVector2f *ptGrad = whm.getGradPointer() + offset;
}
}
*/
//*****************************************************************************************************
/*
static void DrawPoly2D ( CVertexBuffer & vb , IDriver * drv , const NLMISC : : CMatrix & mat , const NLMISC : : CPolygon & p )
{
uint k ;
{
CVertexBufferReadWrite vba ;
vb . lock ( vba ) ;
for ( k = 0 ; k < p . Vertices . size ( ) ; + + k )
{
NLMISC : : CVector tPos = mat * NLMISC : : CVector ( p . Vertices [ k ] . x , p . Vertices [ k ] . y , 0 ) ;
vba . setValueFloat3Ex ( WATER_VB_POS , k , tPos . x , tPos . y , tPos . z ) ;
vba . setValueFloat2Ex ( WATER_VB_DX , k , 0 , 0 ) ;
}
}
static CIndexBuffer ib ;
ib . setNumIndexes ( 3 * p . Vertices . size ( ) ) ;
{
CIndexBufferReadWrite ibaWrite ;
ib . lock ( ibaWrite ) ;
uint32 * ptr = ibaWrite . getPtr ( ) ;
for ( k = 0 ; k < p . Vertices . size ( ) - 2 ; + + k )
{
ptr [ k * 3 ] = 0 ;
ptr [ k * 3 + 1 ] = k + 1 ;
ptr [ k * 3 + 2 ] = k + 2 ;
}
}
drv - > activeIndexBuffer ( ib ) ;
drv - > renderSimpleTriangles ( 0 , p . Vertices . size ( ) - 2 ) ;
}
*/
//***************************************************************************************************************
/*
void CWaterModel : : traverseRender ( )
{
H_AUTO ( NL3D_Water_Render ) ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
IDriver * drv = renderTrav . getDriver ( ) ;
# ifndef FORCE_SIMPLE_WATER_RENDER
if ( ! drv - > isWaterShaderSupported ( ) )
# endif
{
doSimpleRender ( drv ) ;
return ;
}
CWaterShape * shape = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
if ( shape - > _GridSizeTouched )
{
shape - > setupVertexBuffer ( ) ;
}
// inverted object world matrix
//NLMISC::CMatrix invObjMat = getWorldMatrix().inverted();
// viewer pos in world space
const NLMISC : : CVector & obsPos = renderTrav . CamPos ;
// camera matrix in world space
const NLMISC : : CMatrix & camMat = renderTrav . CamMatrix ;
// view matrix (inverted cam matrix)
const NLMISC : : CMatrix & viewMat = renderTrav . ViewMatrix ;
// compute the camera matrix such as there is no rotation around the y axis
NLMISC : : CMatrix camMatUp ;
ComputeUpMatrix ( camMat . getJ ( ) , camMatUp , camMat ) ;
camMatUp . setPos ( camMat . getPos ( ) ) ;
const NLMISC : : CMatrix matViewUp = camMatUp . inverted ( ) ;
// plane z pos in world
const float zHeight = getWorldMatrix ( ) . getPos ( ) . z ;
const sint numStepX = CWaterShape : : getScreenXGridSize ( ) ;
const sint numStepY = CWaterShape : : getScreenYGridSize ( ) ;
const float invNumStepX = 1.f / numStepX ;
const float invNumStepY = 1.f / numStepY ;
const uint rotBorderSize = ( shape - > _MaxGridSize + ( shape - > _XGridBorder < < 1 ) - numStepX ) > > 1 ;
const sint isAbove = obsPos . z > zHeight ? 1 : 0 ;
# ifdef NO_WATER_TESSEL
const float transitionDist = renderTrav . Near * 0.99f ;
# else
const float transitionDist = shape - > _TransitionRatio * renderTrav . Far ;
# endif
NLMISC : : CMatrix modelMat ;
modelMat . setPos ( NLMISC : : CVector ( obsPos . x , obsPos . y , zHeight ) ) ;
drv - > setupModelMatrix ( modelMat ) ;
//==================//
// material setup //
//==================//
CWaterHeightMap & whm = GetWaterPoolManager ( ) . getPoolByID ( shape - > _WaterPoolID ) ;
setupMaterialNVertexShader ( drv , shape , obsPos , isAbove > 0 , whm . getUnitSize ( ) * ( whm . getSize ( ) > > 1 ) , zHeight ) ;
drv - > setupMaterial ( CWaterModel : : _WaterMat ) ;
sint numPass = drv - > beginMaterialMultiPass ( ) ;
nlassert ( numPass = = 1 ) ; // for now, we assume water is always rendered in a single pass !
drv - > setupMaterialPass ( 0 ) ;
//setAttenuationFactor(drv, false, obsPos, camMat.getJ(), farDist);
//disableAttenuation(drv);
//================================//
// Vertex buffer setup //
//================================//
drv - > activeVertexBuffer ( shape - > _VB ) ;
//================================//
// tesselated part of the poly //
//================================//
if ( _ClippedPoly . Vertices . size ( ) )
{
//======================================//
// Polygon projection on the near plane //
//======================================//
static NLMISC : : CPolygon2D projPoly ; // projected poly
projPoly . Vertices . resize ( _ClippedPoly . Vertices . size ( ) ) ;
const float Near = renderTrav . Near ;
const float xFactor = numStepX * Near / ( renderTrav . Right - renderTrav . Left ) ;
const float xOffset = numStepX * ( - renderTrav . Left / ( renderTrav . Right - renderTrav . Left ) ) + 0.5f ;
const float yFactor = numStepY * Near / ( renderTrav . Bottom - renderTrav . Top ) ;
const float yOffset = numStepY * ( - renderTrav . Top / ( renderTrav . Bottom - renderTrav . Top ) ) - 0.5f * isAbove ;
const NLMISC : : CMatrix projMat = matViewUp * getWorldMatrix ( ) ;
uint k ;
for ( k = 0 ; k < _ClippedPoly . Vertices . size ( ) ; + + k )
{
// project points in the view
NLMISC : : CVector t = projMat * _ClippedPoly . Vertices [ k ] ;
float invY = 1.f / t . y ;
projPoly . Vertices [ k ] . set ( xFactor * t . x * invY + xOffset , yFactor * t . z * invY + yOffset ) ;
}
//=============================================//
// compute borders of poly at a low resolution //
//=============================================//
NLMISC : : CPolygon2D : : TRasterVect rasters ;
sint startY ;
projPoly . computeBorders ( rasters , startY ) ;
if ( rasters . size ( ) )
{
//===========================//
// perform Water animation //
//===========================//
const float WaterRatio = whm . getUnitSize ( ) ;
const float invWaterRatio = 1.f / WaterRatio ;
const uint WaterHeightMapSize = whm . getSize ( ) ;
const uint doubleWaterHeightMapSize = ( WaterHeightMapSize < < 1 ) ;
sint64 idate = getOwnerScene ( ) - > getHrcTrav ( ) . CurrentDate ;
if ( idate ! = whm . Date )
{
whm . setUserPos ( ( sint ) ( obsPos . x * invWaterRatio ) - ( WaterHeightMapSize > > 1 ) ,
( sint ) ( obsPos . y * invWaterRatio ) - ( WaterHeightMapSize > > 1 )
) ;
nlassert ( getOwnerScene ( ) ) ; // this object should have been created from a CWaterShape!
whm . animate ( ( float ) ( getOwnerScene ( ) - > getEllapsedTime ( ) ) ) ;
whm . Date = idate ;
}
//float startDate = (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()));
//=====================================//
// compute heightmap useful area //
//=====================================//
// We don't store a heighmap for a complete Water area
// we just consider the height of Water columns that are near the observer
//
// Compute a quad in Water height field space that contains the useful heights
// This helps us to decide whether we should do a lookup in the height map
sint mapPosX , mapPosY ;
/// get the pos used in the height map (may not be the same than our current pos, has it is taken in account
/// every 'PropagationTime' second
whm . getUserPos ( mapPosX , mapPosY ) ;
const uint mapBorder = 3 ;
const sint qRight = ( sint ) mapPosX + WaterHeightMapSize - mapBorder ;
sint qLeft = ( sint ) mapPosX ;
const sint qUp = ( sint ) mapPosY + WaterHeightMapSize - mapBorder ;
sint qDown = ( sint ) mapPosY ;
/// 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
const sint qSubLeft = qLeft - ( uint ) qLeft % WaterHeightMapSize ;
const sint qSubDown = qDown - ( uint ) qDown % WaterHeightMapSize ;
qLeft + = mapBorder ;
qDown + = mapBorder ;
//==============================================//
// setup rays to be traced, and their increment //
//==============================================//
// compute camera rays in world space
NLMISC : : CVector currHV = renderTrav . Left * camMatUp . getI ( ) + renderTrav . Near * camMatUp . getJ ( ) + renderTrav . Top * camMatUp . getK ( ) ; // current border vector, incremented at each line
NLMISC : : CVector currV ; // current ray vector
NLMISC : : CVector xStep = ( renderTrav . Right - renderTrav . Left ) * invNumStepX * camMatUp . getI ( ) ; // xStep for the ray vector
NLMISC : : CVector yStep = ( renderTrav . Bottom - renderTrav . Top ) * invNumStepY * camMatUp . getK ( ) ; // yStep for the ray vector
//===============================================//
// perform display //
//===============================================//
// scale currHV at the top of the poly
currHV + = ( startY - 0.5f * isAbove ) * yStep ;
// current index buffer used. We swap each time a row has been drawn
CIndexBuffer * currIB = & CWaterShape : : _IBUpDown , * otherIB = & CWaterShape : : _IBDownUp ;
sint vIndex = 0 ; // index in vertices
// current raster position
sint oldStartX , oldEndX , realStartX , realEndX ;
//float invNearWidth = numStepX / (renderTrav.Right - renderTrav.Left);
//nlinfo("size = %d, maxSize = ", rasters.size(), numStepY);
const uint wqHeight = rasters . size ( ) ;
if ( wqHeight )
{
// denominator of the intersection equation
const float denom = - obsPos . z + zHeight ;
// test the upper raster
// if it is above the horizon, we modify it to reach the correct location
const float horizonEpsilon = 10E-4 f ; // we must be a little below the horizon
// distance from the viewer along the traced ray
float t ;
NLMISC : : CPolygon2D : : TRasterVect : : const_iterator it = rasters . begin ( ) ;
for ( uint l = 0 ; l < = wqHeight ; + + l )
{
//nlinfo("start = %d, end = %d", it->first, it->second);
const sint startX = it - > first ;
const sint endX = ( it - > second + 1 ) ;
nlassert ( startX > = - ( sint ) rotBorderSize ) ;
nlassert ( endX < = ( sint ) ( numStepX + rotBorderSize ) ) ;
if ( l ! = 0 )
{
realStartX = std : : min ( startX , oldStartX ) ;
realEndX = std : : max ( endX , oldEndX ) ;
}
else
{
realStartX = startX ;
realEndX = endX ;
}
// current view vector
currV = currHV + ( realStartX - 0.5f ) * xStep ;
if ( l = = 0 )
{
if ( isAbove )
{
// test whether the first row is out of horizon.
// if this is the case, we make a correction
if ( denom * currV . z < = 0 )
{
// correct for the first line only by adding a y offset
currV + = yStep * ( ( denom > 0 ? horizonEpsilon : - horizonEpsilon ) - currV . z ) / yStep . z ;
}
// now, for the transition, check whether the first raster does not go over the transition dist
t = denom / currV . z ;
const float VJ = camMat . getJ ( ) * currV ;
if ( t * VJ > transitionDist )
{
float delta = ( 1.f / yStep . z ) * ( denom * VJ / transitionDist - currV . z ) ;
// correct the first line to reach that position
currV + = delta * yStep ;
}
}
}
{
CVertexBufferReadWrite vba ;
shape - > _VB . lock ( vba ) ;
uint8 * vbPointer = ( uint8 * ) vba . getVertexCoordPointer ( ) + shape - > _VB . getVertexSize ( ) * ( vIndex + realStartX + rotBorderSize ) ;
for ( sint k = realStartX ; k < = realEndX ; + + k )
{
t = denom / currV . z ;
// compute intersection with plane
NLMISC : : CVector inter = t * currV ;
inter . z + = obsPos . z ;
SetupWaterVertex ( qLeft , qRight , qUp , qDown , qSubLeft , qSubDown , inter , invWaterRatio , doubleWaterHeightMapSize , whm , vbPointer , obsPos . x , obsPos . y ) ;
currV + = xStep ;
}
}
if ( l ! = 0 ) // 2 line of the ib done ?
{
sint count = oldEndX - oldStartX ;
if ( count > 0 )
{
drv - > activeIndexBuffer ( * currIB ) ;
drv - > renderSimpleTriangles ( ( oldStartX + rotBorderSize ) * 6 , 2 * count ) ;
}
}
oldStartX = startX ;
oldEndX = endX ;
currHV + = yStep ;
vIndex = ( numStepX + 2 * rotBorderSize + 1 ) - vIndex ; // swap first row and second row
std : : swap ( currIB , otherIB ) ;
if ( l < ( wqHeight - 1 ) )
{
+ + it ;
}
else
{
if ( ! isAbove )
{
// last line
// test whether we are out of horizon
if ( denom * currHV . z < = 0 )
{
// correct for the first line only by adding a y offset
currHV + = yStep * ( ( denom > 0 ? horizonEpsilon : - horizonEpsilon ) - currHV . z ) / yStep . z ;
}
// now, for the transition, check whether the first raster does not go over the transition dist
t = denom / currHV . z ;
const float VJ = camMat . getJ ( ) * currHV ;
if ( t * VJ > transitionDist )
{
float delta = ( 1.f / yStep . z ) * ( denom * VJ / transitionDist - currHV . z ) ;
// correct the first line to reach that position
currHV + = delta * yStep ;
}
}
}
}
}
//nlinfo("display: %f ms", (float) (1000.f * NLMISC::CTime::ticksToSecond(NLMISC::CTime::getPerformanceTime()) - startDate));
}
}
//=========================================//
// display end poly //
//=========================================//
if ( _EndClippedPoly . Vertices . size ( ) ! = 0 )
{
CMatrix xform = _WorldMatrix ;
xform . movePos ( NLMISC : : CVector ( - obsPos . x , - obsPos . y , _WorldMatrix . getPos ( ) . z ) ) ;
DrawPoly2D ( shape - > _VB , drv , xform , _EndClippedPoly ) ;
}
drv - > endMaterialMultiPass ( ) ;
drv - > activeVertexProgram ( NULL ) ;
}
*/
//***********************
// Water MATERIAL SETUP //
//***********************
/*
void CWaterModel : : setupMaterialNVertexShader ( IDriver * drv , CWaterShape * shape , const NLMISC : : CVector & obsPos , bool above , float maxDist , float zHeight )
{
static bool matSetupped = false ;
if ( ! matSetupped )
{
_WaterMat . setLighting ( false ) ;
_WaterMat . setDoubleSided ( true ) ;
_WaterMat . setColor ( NLMISC : : CRGBA : : White ) ;
_WaterMat . setBlend ( true ) ;
_WaterMat . setSrcBlend ( CMaterial : : srcalpha ) ;
_WaterMat . setDstBlend ( CMaterial : : invsrcalpha ) ;
_WaterMat . setZWrite ( true ) ;
_WaterMat . setShader ( CMaterial : : Water ) ;
}
const uint cstOffset = 4 ; // 4 places for the matrix
NLMISC : : CVectorH cst [ 13 ] ;
//=========================//
// setup Water material //
//=========================//
CWaterModel : : _WaterMat . setTexture ( 0 , shape - > _BumpMap [ 0 ] ) ;
CWaterModel : : _WaterMat . setTexture ( 1 , shape - > _BumpMap [ 1 ] ) ;
CWaterModel : : _WaterMat . setTexture ( 3 , shape - > _ColorMap ) ;
CScene * scene = getOwnerScene ( ) ;
if ( ! above & & shape - > _EnvMap [ 1 ] )
{
if ( shape - > _UsesSceneWaterEnvMap [ 1 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
CWaterModel : : _WaterMat . setTexture ( 2 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
if ( shape - > _UsesSceneWaterEnvMap [ 0 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
CWaterModel : : _WaterMat . setTexture ( 2 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 0 ] ) ;
}
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 0 ] ) ;
}
}
shape - > envMapUpdate ( ) ;
const uint alphaMapStage = 3 ;
if ( shape - > _ColorMap )
{
//WaterMat.setTexture(alphaMapStage, shape->_ColorMap);
//if (shape->_ColorMap->supportSharing()) nlinfo(shape->_ColorMap->getShareName().c_str());
// setup 2x3 matrix for lookup in diffuse map
updateDiffuseMapMatrix ( ) ;
cst [ 13 - cstOffset ] . set ( _ColorMapMatColumn0 . x , _ColorMapMatColumn1 . x , 0 , _ColorMapMatColumn0 . x * obsPos . x + _ColorMapMatColumn1 . x * obsPos . y + _ColorMapMatPos . x ) ;
cst [ 14 - cstOffset ] . set ( _ColorMapMatColumn0 . y , _ColorMapMatColumn1 . y , 0 , _ColorMapMatColumn0 . y * obsPos . x + _ColorMapMatColumn1 . y * obsPos . y + _ColorMapMatPos . y ) ;
}
else
{
cst [ 13 - cstOffset ] . set ( 0 , 0 , 0 , 0 ) ;
cst [ 14 - cstOffset ] . set ( 0 , 0 , 0 , 0 ) ;
}
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
// 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
cst [ 5 - cstOffset ] . set ( 0.f , 0.f , 0.f , 0.f ) ; // claping negative values to 0
// slope of attenuation of normal / height with distance
const float invMaxDist = shape - > _WaveHeightFactor / maxDist ;
cst [ 6 - cstOffset ] . set ( invMaxDist , shape - > _WaveHeightFactor , 0 , 0 ) ;
/// set matrix
drv - > setConstantMatrix ( 0 , IDriver : : ModelViewProjection , IDriver : : Identity ) ;
drv - > setConstantFog ( 18 ) ;
// retrieve current time
float date = 0.001f * ( NLMISC : : CTime : : getLocalTime ( ) & 0xffffff ) ; // must keep some precision.
// set bumpmaps pos
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
cst [ 10 - cstOffset ] . set ( shape - > _HeightMapScale [ 0 ] . x , shape - > _HeightMapScale [ 0 ] . y , 0 , 0 ) ; // bump map 0 scale
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
cst [ 12 - cstOffset ] . set ( shape - > _HeightMapScale [ 1 ] . x , shape - > _HeightMapScale [ 1 ] . y , 0 , 0 ) ; // bump map 1 scale
cst [ 4 - cstOffset ] . set ( 1.f , 1.f , 1.f , 1.f ) ; // use with min man, and to get the 1 constant
cst [ 7 - cstOffset ] . set ( 0 , 0 , obsPos . z - zHeight , 1.f ) ;
cst [ 8 - cstOffset ] . set ( 0.5f , 0.5f , 0.f , 1.f ) ; // used to scale reflected ray into the envmap
/// set all our constants in one call
drv - > setConstant ( 4 , sizeof ( cst ) / sizeof ( cst [ 0 ] ) , ( float * ) & cst [ 0 ] ) ;
shape - > initVertexProgram ( ) ;
bool result ;
//if (useBumpedVersion)
//{
// if (!useEMBM)
// {
// result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
// : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
// }
// else
// {
// result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump1Diffuse).get())
// : drv->activeVertexProgram((shape->_VertexProgramBump1).get());
// }
//}
//else
//{
// result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramNoBumpDiffuse).get())
// : drv->activeVertexProgram((shape->_VertexProgramNoBump).get());
//}
//result = shape->getColorMap() ? drv->activeVertexProgram((shape->_VertexProgramBump2Diffuse).get())
// : drv->activeVertexProgram((shape->_VertexProgramBump2).get());
//
//if (!result) nlwarning("no vertex program setuped");
}
*/
void CWaterModel : : setupMaterialNVertexShader ( IDriver * drv , CWaterShape * shape , const NLMISC : : CVector & obsPos , bool above , float zHeight )
{
static bool matSetupped = false ;
if ( ! matSetupped )
{
_WaterMat . setLighting ( false ) ;
_WaterMat . setDoubleSided ( true ) ;
_WaterMat . setColor ( NLMISC : : CRGBA : : White ) ;
_WaterMat . setBlend ( true ) ;
_WaterMat . setSrcBlend ( CMaterial : : srcalpha ) ;
_WaterMat . setDstBlend ( CMaterial : : invsrcalpha ) ;
_WaterMat . setZWrite ( true ) ;
_WaterMat . setShader ( CMaterial : : Water ) ;
}
const uint cstOffset = 5 ; // 4 places for the matrix
NLMISC : : CVectorH cst [ 13 ] ;
//=========================//
// setup Water material //
//=========================//
CWaterModel : : _WaterMat . setTexture ( 0 , shape - > _BumpMap [ 0 ] ) ;
CWaterModel : : _WaterMat . setTexture ( 1 , shape - > _BumpMap [ 1 ] ) ;
CWaterModel : : _WaterMat . setTexture ( 3 , shape - > _ColorMap ) ;
CScene * scene = getOwnerScene ( ) ;
if ( ! above & & shape - > _EnvMap [ 1 ] )
{
if ( shape - > _UsesSceneWaterEnvMap [ 1 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
CWaterModel : : _WaterMat . setTexture ( 2 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
if ( shape - > _UsesSceneWaterEnvMap [ 0 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
CWaterModel : : _WaterMat . setTexture ( 2 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 0 ] ) ;
}
}
else
{
CWaterModel : : _WaterMat . setTexture ( 2 , shape - > _EnvMap [ 0 ] ) ;
}
}
shape - > envMapUpdate ( ) ;
if ( shape - > _ColorMap )
{
// setup 2x3 matrix for lookup in diffuse map
updateDiffuseMapMatrix ( ) ;
cst [ 11 ] . set ( _ColorMapMatColumn0 . x , _ColorMapMatColumn1 . x , 0 , _ColorMapMatColumn0 . x * obsPos . x + _ColorMapMatColumn1 . x * obsPos . y + _ColorMapMatPos . x ) ;
cst [ 12 ] . set ( _ColorMapMatColumn0 . y , _ColorMapMatColumn1 . y , 0 , _ColorMapMatColumn0 . y * obsPos . x + _ColorMapMatColumn1 . y * obsPos . y + _ColorMapMatPos . y ) ;
}
/// set matrix
drv - > setConstantMatrix ( 0 , IDriver : : ModelViewProjection , IDriver : : Identity ) ;
// retrieve current time
double date = scene - > getCurrentTime ( ) ;
// set bumpmaps pos
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
cst [ 5 ] . set ( shape - > _HeightMapScale [ 0 ] . x , shape - > _HeightMapScale [ 0 ] . y , 0 , 0 ) ; // bump map 0 scale
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
cst [ 7 ] . set ( shape - > _HeightMapScale [ 1 ] . x , shape - > _HeightMapScale [ 1 ] . y , 0 , 0 ) ; // bump map 1 scale
cst [ 9 ] . set ( 0 , 0 , obsPos . z - zHeight , 1.f ) ;
cst [ 10 ] . set ( 0.5f , 0.5f , 0.f , 1.f ) ; // used to scale reflected ray into the envmap
/// set all our constants in one call
drv - > setConstant ( cstOffset , sizeof ( cst ) / sizeof ( cst [ 0 ] ) - cstOffset , ( float * ) & cst [ cstOffset ] ) ;
shape - > initVertexProgram ( ) ;
drv - > activeVertexProgram ( shape - > _ColorMap ? CWaterShape : : _VertexProgramNoWaveDiffuse . get ( ) : CWaterShape : : _VertexProgramNoWave . get ( ) ) ;
drv - > setConstantFog ( 4 ) ;
}
//================================================
void CWaterModel : : setupSimpleRender ( CWaterShape * shape , const NLMISC : : CVector & obsPos , bool above )
{
// rendering of water when no vertex / pixel shaders are available
static bool init = false ;
if ( ! init )
{
// setup the material, no special shader is used here
_SimpleWaterMat . setLighting ( false ) ;
_SimpleWaterMat . setDoubleSided ( true ) ;
_SimpleWaterMat . setColor ( NLMISC : : CRGBA : : White ) ;
_SimpleWaterMat . setBlend ( true ) ;
_SimpleWaterMat . setSrcBlend ( CMaterial : : srcalpha ) ;
_SimpleWaterMat . setDstBlend ( CMaterial : : invsrcalpha ) ;
_SimpleWaterMat . setZWrite ( true ) ;
_SimpleWaterMat . setShader ( CMaterial : : Normal ) ;
// stage 0
_SimpleWaterMat . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
_SimpleWaterMat . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
_SimpleWaterMat . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
// stage 1
_SimpleWaterMat . texEnvOpRGB ( 1 , CMaterial : : Modulate ) ;
_SimpleWaterMat . texEnvOpAlpha ( 1 , CMaterial : : Modulate ) ;
_SimpleWaterMat . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
_SimpleWaterMat . texEnvArg1RGB ( 0 , CMaterial : : Previous , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg1Alpha ( 0 , CMaterial : : Previous , CMaterial : : SrcAlpha ) ;
init = true ;
}
// envmap is always present and is in stage 0
CScene * scene = getOwnerScene ( ) ;
if ( ! above & & shape - > _EnvMap [ 1 ] )
{
if ( shape - > _UsesSceneWaterEnvMap [ 1 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
_SimpleWaterMat . setTexture ( 0 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
if ( shape - > _UsesSceneWaterEnvMap [ 0 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
_SimpleWaterMat . setTexture ( 0 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 0 ] ) ;
}
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 0 ] ) ;
}
}
//
if ( shape - > _ColorMap = = NULL )
{
// version with no color map
if ( ! _EmbossTexture )
{
_EmbossTexture = new CTextureEmboss ;
_EmbossTexture - > setSlopeFactor ( 4.f ) ;
}
if ( shape - > _BumpMap [ 1 ] & & shape - > _BumpMap [ 1 ] - > isBumpMap ( ) )
{
CTextureBump * bm = static_cast < CTextureBump * > ( ( ITexture * ) shape - > _BumpMap [ 1 ] ) ;
if ( bm - > getHeightMap ( ) )
{
_EmbossTexture - > setHeightMap ( bm - > getHeightMap ( ) ) ;
}
}
_SimpleWaterMat . setTexture ( 1 , _EmbossTexture ) ;
_SimpleWaterMat . setTexCoordGen ( 1 , true ) ;
_SimpleWaterMat . setTexCoordGenMode ( 1 , CMaterial : : TexCoordGenObjectSpace ) ;
double date = scene - > getCurrentTime ( ) ;
CMatrix texMat ;
texMat . scale ( CVector ( shape - > _HeightMapScale [ 1 ] . x , shape - > _HeightMapScale [ 1 ] . y , 1.f ) ) ;
texMat . setPos ( CVector ( 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 ) ,
1.f )
) ;
_SimpleWaterMat . enableUserTexMat ( 1 , true ) ;
_SimpleWaterMat . setUserTexMat ( 1 , texMat ) ;
}
else
{
updateDiffuseMapMatrix ( ) ;
// version with a color map : it remplace the emboss texture
_SimpleWaterMat . setTexture ( 1 , shape - > _ColorMap ) ;
_SimpleWaterMat . setTexCoordGen ( 1 , true ) ;
_SimpleWaterMat . setTexCoordGenMode ( 1 , CMaterial : : TexCoordGenObjectSpace ) ;
CMatrix texMat ;
/*
float mat [ 16 ] =
{
_ColorMapMatColumn0 . x , _ColorMapMatColumn1 . x , 0 , _ColorMapMatColumn0 . x * obsPos . x + _ColorMapMatColumn1 . x * obsPos . y + _ColorMapMatPos . x } ,
_ColorMapMatColumn0 . y , _ColorMapMatColumn1 . y , 0 , _ColorMapMatColumn0 . y * obsPos . x + _ColorMapMatColumn1 . y * obsPos . y + _ColorMapMatPos . y ,
0.f , 0.f , 1.f , 0.f ,
0.f , 0.f , 0.f , 1.f
}
*/
float mat [ 16 ] =
{
_ColorMapMatColumn0 . x , _ColorMapMatColumn0 . y , 0.f , 0.f ,
_ColorMapMatColumn1 . x , _ColorMapMatColumn1 . y , 0.f , 0.f ,
0.f , 0.f , 1.f , 0.f ,
_ColorMapMatColumn0 . x * obsPos . x + _ColorMapMatColumn1 . x * obsPos . y + _ColorMapMatPos . x , _ColorMapMatColumn0 . y * obsPos . x + _ColorMapMatColumn1 . y * obsPos . y + _ColorMapMatPos . y , 0.f , 1.f
} ;
texMat . set ( mat ) ;
_SimpleWaterMat . enableUserTexMat ( 1 , true ) ;
_SimpleWaterMat . setUserTexMat ( 1 , texMat ) ;
}
}
//================================================
void CWaterModel : : computeClippedPoly ( )
{
CWaterShape * shape = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
const std : : vector < CPlane > & worldPyramid = getOwnerScene ( ) - > getClipTrav ( ) . WorldFrustumPyramid ;
_ClippedPoly . Vertices . resize ( shape - > _Poly . Vertices . size ( ) ) ;
uint k ;
for ( k = 0 ; k < shape - > _Poly . Vertices . size ( ) ; + + k )
{
_ClippedPoly . Vertices [ k ] . set ( shape - > _Poly . Vertices [ k ] . x ,
shape - > _Poly . Vertices [ k ] . y ,
0.f
) ;
}
/*
NLMISC : : CPlane plvect [ 6 ] ;
const NLMISC : : CMatrix & viewMat = clipTrav . ViewMatrix ;
const sint numStepX = CWaterShape : : getScreenXGridSize ( ) ;
const sint numStepY = CWaterShape : : getScreenYGridSize ( ) ;
// 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
float centerX = 0.5f * ( clipTrav . Right + clipTrav . Left ) ;
const float fRight = centerX + ( clipTrav . Right - centerX ) * ( - ( float ) CWaterShape : : _XGridBorder + ( float ) numStepX ) / numStepX ;
const float fLeft = centerX + ( clipTrav . Left - centerX ) * ( - ( float ) CWaterShape : : _XGridBorder + ( float ) numStepX ) / numStepX ;
float centerY = 0.5f * ( clipTrav . Bottom + clipTrav . Top ) ;
const float fTop = centerY + ( clipTrav . Top - centerY ) * ( - ( float ) CWaterShape : : _YGridBorder + ( float ) numStepY ) / numStepY ;
const float fBottom = centerY + ( clipTrav . Bottom - centerY ) * ( - ( float ) CWaterShape : : _YGridBorder + ( float ) numStepY ) / numStepY ;
// build pyramid corners
const float nearDist = clipTrav . Near ;
const float farDist = clipTrav . Far ;
//
const NLMISC : : CVector pfoc ( 0 , 0 , 0 ) ;
const NLMISC : : CVector lb ( fLeft , nearDist , fBottom ) ;
const NLMISC : : CVector lt ( fLeft , nearDist , fTop ) ;
const NLMISC : : CVector rb ( fRight , nearDist , fBottom ) ;
const NLMISC : : CVector rt ( fRight , nearDist , fTop ) ;
const NLMISC : : CVector lbfarDist ( fLeft , farDist , fBottom ) ;
const NLMISC : : CVector ltfarDist ( fLeft , farDist , fTop ) ;
const NLMISC : : CVector rtfarDist ( fRight , farDist , fTop ) ;
//
plvect [ 0 ] . make ( lt , lb , rt ) ; // near plane
plvect [ 1 ] . make ( lbfarDist , ltfarDist , rtfarDist ) ; // far plane
plvect [ 2 ] . make ( pfoc , lt , lb ) ;
plvect [ 3 ] . make ( pfoc , rt , lt ) ;
plvect [ 4 ] . make ( pfoc , rb , rt ) ;
plvect [ 5 ] . make ( pfoc , lb , rb ) ;
const NLMISC : : CMatrix pyramidMat = viewMat * getWorldMatrix ( ) ;
for ( k = 0 ; k < worldPyramid . size ( ) ; + + k )
{
plvect [ k ] = plvect [ k ] * pyramidMat ; // put the plane in object space
}
_ClippedPoly . clip ( plvect , 6 ) ;
*/
static std : : vector < CPlane > tp ;
tp . resize ( worldPyramid . size ( ) ) ;
for ( uint k = 0 ; k < tp . size ( ) ; + + k )
{
tp [ k ] = worldPyramid [ k ] * getWorldMatrix ( ) ;
}
_ClippedPoly . clip ( tp ) ;
}
//***********************************************************************************************************
void CWaterModel : : unlink ( )
{
if ( ! _Prev )
{
nlassert ( ! _Next ) ;
return ;
}
if ( _Next )
{
_Next - > _Prev = _Prev ;
}
* _Prev = _Next ;
_Next = NULL ;
_Prev = NULL ;
}
//***********************************************************************************************************
void CWaterModel : : link ( )
{
nlassert ( _Next = = NULL ) ;
CScene * scene = getOwnerScene ( ) ;
nlassert ( scene ) ;
CRenderTrav & rt = scene - > getRenderTrav ( ) ;
_Prev = & rt . _FirstWaterModel ;
_Next = rt . _FirstWaterModel ;
if ( _Next )
{
_Next - > _Prev = & _Next ;
}
rt . _FirstWaterModel = this ;
}
//***********************************************************************************************************
uint CWaterModel : : getNumWantedVertices ( )
{
H_AUTO ( NL3D_Water_Render ) ;
nlassert ( ! _ClippedPoly . Vertices . empty ( ) ) ;
//
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
if ( ! renderTrav . Perspective | | forceWaterSimpleRender ) return 0 ;
// viewer pos in world space
const NLMISC : : CVector & obsPos = renderTrav . CamPos ;
// view matrix (inverted cam matrix)
const NLMISC : : CMatrix & viewMat = renderTrav . ViewMatrix ;
// plane z pos in world
const float zHeight = getWorldMatrix ( ) . getPos ( ) . z ;
const sint numStepX = CWaterShape : : getScreenXGridSize ( ) ;
const sint numStepY = CWaterShape : : getScreenYGridSize ( ) ;
NLMISC : : CMatrix modelMat ;
modelMat . setPos ( NLMISC : : CVector ( obsPos . x , obsPos . y , zHeight ) ) ;
static NLMISC : : CPolygon2D projPoly ; // projected poly
projPoly . Vertices . resize ( _ClippedPoly . Vertices . size ( ) ) ;
// factor to project to grid units
const float xFactor = numStepX * renderTrav . Near / ( renderTrav . Right - renderTrav . Left ) ;
const float yFactor = numStepY * renderTrav . Near / ( renderTrav . Top - renderTrav . Bottom ) ;
// project poly on near plane
const NLMISC : : CMatrix & projMat = viewMat * getWorldMatrix ( ) ;
uint k ;
for ( k = 0 ; k < _ClippedPoly . Vertices . size ( ) ; + + k )
{
// project points in the view
NLMISC : : CVector t = projMat * _ClippedPoly . Vertices [ k ] ;
float invY = 1.f / t . y ;
projPoly . Vertices [ k ] . set ( xFactor * t . x * invY , yFactor * t . z * invY ) ;
}
// compute grid cells that are entirely inside
projPoly . computeInnerBorders ( _Inside , _MinYInside ) ;
// compute grid cells that are touched
static NLMISC : : CPolygon2D : : TRasterVect border ;
sint minYBorder ;
projPoly . computeOuterBorders ( border , minYBorder ) ;
// border - inside -> gives grid cells that must be clipped to fit the shape boundaries
// Make sure that rasters array for inside has the same size that raster array for borders (by inserting NULL rasters)
2010-05-13 20:14:36 +00:00
sint height = ( sint ) border . size ( ) ;
2010-05-06 00:08:41 +00:00
if ( _Inside . empty ( ) )
{
_MinYInside = minYBorder ;
}
2010-05-13 20:14:36 +00:00
sint bottomGap = ( sint ) ( border . size ( ) - _Inside . size ( ) ) ;
2010-05-06 00:08:41 +00:00
_Inside . resize ( height ) ;
nlassert ( minYBorder = = _MinYInside ) ;
nlassert ( bottomGap > = 0 ) ;
if ( bottomGap )
{
for ( sint y = height - bottomGap ; y < height ; + + y )
{
nlassert ( y > = 0 & & y < ( sint ) _Inside . size ( ) ) ;
_Inside [ y ] . first = border [ y ] . first ;
_Inside [ y ] . second = border [ y ] . first - 1 ; // insert null raster
}
}
//
for ( sint y = 0 ; y < height - bottomGap ; + + y )
{
if ( _Inside [ y ] . first > _Inside [ y ] . second )
{
nlassert ( y > = 0 & & y < ( sint ) _Inside . size ( ) ) ;
_Inside [ y ] . first = border [ y ] . first ;
_Inside [ y ] . second = border [ y ] . first - 1 ;
}
else if ( border [ y ] . first > border [ y ] . second )
{
nlassert ( y > = 0 & & y < ( sint ) _Inside . size ( ) ) ;
border [ y ] . first = _Inside [ y ] . first ;
border [ y ] . second = _Inside [ y ] . first - 1 ;
}
}
// compute clip planes
static std : : vector < CPlane > clipPlanes ;
const CVector2f * prevVert = & projPoly . Vertices . back ( ) ;
const CVector2f * currVert = & projPoly . Vertices . front ( ) ;
2010-05-13 20:14:36 +00:00
uint numVerts = ( uint ) projPoly . Vertices . size ( ) ;
2010-05-06 00:08:41 +00:00
bool ccw = projPoly . isCCWOriented ( ) ;
clipPlanes . resize ( numVerts ) ;
for ( uint k = 0 ; k < numVerts ; + + k )
{
NLMISC : : CVector v0 ;
NLMISC : : CVector v1 ;
NLMISC : : CVector v2 ;
v0 . set ( prevVert - > x , prevVert - > y , 0.f ) ;
v1 . set ( currVert - > x , currVert - > y , 0.f ) ;
v2 . set ( prevVert - > x , prevVert - > y , ( * currVert - * prevVert ) . norm ( ) ) ;
clipPlanes [ k ] . make ( v0 , v1 , v2 ) ;
if ( ! ccw )
{
clipPlanes [ k ] . invert ( ) ;
}
prevVert = currVert ;
+ + currVert ;
}
// compute clipped tris
_ClippedTriNumVerts . clear ( ) ;
_ClippedTris . clear ( ) ;
static NLMISC : : CPolygon clipPoly ;
uint totalNumVertices = 0 ;
// compute number of vertices for whole grid cells
for ( sint k = 0 ; k < ( sint ) border . size ( ) ; + + k )
{
// left clipped blocks
for ( sint x = border [ k ] . first ; x < _Inside [ k ] . first ; + + x )
{
clipPoly . Vertices . resize ( 4 ) ;
clipPoly . Vertices [ 0 ] . set ( ( float ) x , ( float ) ( k + _MinYInside ) , 0.f ) ;
clipPoly . Vertices [ 1 ] . set ( ( float ) ( x + 1 ) , ( float ) ( k + _MinYInside ) , 0.f ) ;
clipPoly . Vertices [ 2 ] . set ( ( float ) ( x + 1 ) , ( float ) ( k + _MinYInside + 1 ) , 0.f ) ;
clipPoly . Vertices [ 3 ] . set ( ( float ) x , ( float ) ( k + _MinYInside + 1 ) , 0.f ) ;
clipPoly . clip ( clipPlanes ) ;
if ( ! clipPoly . Vertices . empty ( ) )
{
// backup result (will be unprojected later)
2010-05-13 20:14:36 +00:00
_ClippedTriNumVerts . push_back ( ( uint ) clipPoly . Vertices . size ( ) ) ;
uint prevSize = ( uint ) _ClippedTris . size ( ) ;
2010-05-06 00:08:41 +00:00
_ClippedTris . resize ( _ClippedTris . size ( ) + clipPoly . Vertices . size ( ) ) ;
std : : copy ( clipPoly . Vertices . begin ( ) , clipPoly . Vertices . end ( ) , _ClippedTris . begin ( ) + prevSize ) ; // append to packed list
2010-05-13 20:14:36 +00:00
totalNumVertices + = ( ( uint ) clipPoly . Vertices . size ( ) - 2 ) * 3 ;
2010-05-06 00:08:41 +00:00
}
}
// middle block, are not clipped, but count the number of wanted vertices
if ( _Inside [ k ] . first < = _Inside [ k ] . second )
{
totalNumVertices + = 6 * ( _Inside [ k ] . second - _Inside [ k ] . first + 1 ) ;
}
// right clipped blocks
for ( sint x = _Inside [ k ] . second + 1 ; x < = border [ k ] . second ; + + x )
{
clipPoly . Vertices . resize ( 4 ) ;
clipPoly . Vertices [ 0 ] . set ( ( float ) x , ( float ) ( k + _MinYInside ) , 0.f ) ;
clipPoly . Vertices [ 1 ] . set ( ( float ) ( x + 1 ) , ( float ) ( k + _MinYInside ) , 0.f ) ;
clipPoly . Vertices [ 2 ] . set ( ( float ) ( x + 1 ) , ( float ) ( k + _MinYInside + 1 ) , 0.f ) ;
clipPoly . Vertices [ 3 ] . set ( ( float ) x , ( float ) ( k + _MinYInside + 1 ) , 0.f ) ;
clipPoly . clip ( clipPlanes ) ;
if ( ! clipPoly . Vertices . empty ( ) )
{
// backup result (will be unprojected later)
2010-05-13 20:14:36 +00:00
_ClippedTriNumVerts . push_back ( ( uint ) clipPoly . Vertices . size ( ) ) ;
uint prevSize = ( uint ) _ClippedTris . size ( ) ;
2010-05-06 00:08:41 +00:00
_ClippedTris . resize ( _ClippedTris . size ( ) + clipPoly . Vertices . size ( ) ) ;
std : : copy ( clipPoly . Vertices . begin ( ) , clipPoly . Vertices . end ( ) , _ClippedTris . begin ( ) + prevSize ) ; // append to packed list
2010-05-13 20:14:36 +00:00
totalNumVertices + = ( ( uint ) clipPoly . Vertices . size ( ) - 2 ) * 3 ;
2010-05-06 00:08:41 +00:00
}
}
}
return totalNumVertices ;
}
//***********************************************************************************************************
uint CWaterModel : : fillVB ( void * datas , uint startTri , IDriver & drv )
{
H_AUTO ( NL3D_Water_Render ) ;
if ( drv . isWaterShaderSupported ( ) )
{
return fillVBHard ( datas , startTri ) ;
}
else
{
return fillVBSoft ( datas , startTri ) ;
}
}
static const double WATER_WAVE_SPEED = 1.7 ;
static const double WATER_WAVE_SCALE = 0.05 ;
static const double WATER_WAVE_FREQ = 0.3 ;
static const float WATER_WAVE_ATTEN = 0.2f ;
// compute single water vertex in software mode
static
# ifndef NL_DEBUG
inline
# endif
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 )
{
CVector d = px * camI + py * camK + camJ ;
//nlassert(d.z > 0.f);
float intersectionDist = denom / d . z ;
pos . x = intersectionDist * d . x ;
pos . y = intersectionDist * d . y ;
pos . z = 0.f ;
//
CVector R ( - pos . x ,
- pos . y ,
- denom
) ;
float dist = R . norm ( ) ;
if ( dist )
{
R / = dist ;
}
envMapTexCoord . set ( - 0.5f * R . x + 0.5f , - 0.5f * R . y + 0.5f ) ;
if ( dist )
{
float invDist = 1.f / ( WATER_WAVE_ATTEN * dist ) ;
if ( invDist > 1.f ) invDist = 1.f ;
// TODO : optimize cos if need (for now there are not much call per frame ...)
envMapTexCoord . x + = ( float ) ( invDist * WATER_WAVE_SCALE * ( float ) cos ( date + WATER_WAVE_FREQ * ( camPos . x + pos . x ) ) ) ;
}
}
//***********************************************************************************************************
uint CWaterModel : : fillVBSoft ( void * datas , uint startTri )
{
_StartTri = ( uint32 ) startTri ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
const NLMISC : : CMatrix & camMat = renderTrav . CamMatrix ;
const sint numStepX = CWaterShape : : getScreenXGridSize ( ) ;
const sint numStepY = CWaterShape : : getScreenYGridSize ( ) ;
CVector camI = camMat . getI ( ) * ( 1.f / numStepX ) * ( renderTrav . Right - renderTrav . Left ) / renderTrav . Near ;
CVector camJ = camMat . getJ ( ) ;
CVector camK = camMat . getK ( ) * ( 1.f / numStepY ) * ( renderTrav . Top - renderTrav . Bottom ) / renderTrav . Near ;
float obsZ = camMat . getPos ( ) . z ;
float denom = getWorldMatrix ( ) . getPos ( ) . z - obsZ ;
uint8 * dest = ( uint8 * ) datas + startTri * 3 * WATER_VERTEX_SOFT_SIZE ;
/*NLMISC::CVector eye = renderTrav.CamPos;
eye . z - = getWorldMatrix ( ) . getPos ( ) . z ; */
NLMISC : : CVector eye ( 0.f , 0.f , - denom ) ;
CVector R ;
CScene * scene = getOwnerScene ( ) ;
double date = WATER_WAVE_SPEED * scene - > getCurrentTime ( ) ;
if ( ! _ClippedTriNumVerts . empty ( ) )
{
const CVector2f * currVert = & _ClippedTris . front ( ) ;
static std : : vector < CVector > unprojectedTriSoft ;
static std : : vector < CVector2f > envMap ;
for ( uint k = 0 ; k < _ClippedTriNumVerts . size ( ) ; + + k )
{
unprojectedTriSoft . resize ( _ClippedTriNumVerts [ k ] ) ;
envMap . resize ( _ClippedTriNumVerts [ k ] ) ;
uint numVerts = _ClippedTriNumVerts [ k ] ;
for ( uint l = 0 ; l < _ClippedTriNumVerts [ k ] ; + + l )
{
computeWaterVertexSoft ( currVert - > x , currVert - > y , unprojectedTriSoft [ l ] , envMap [ l ] , camI , camJ , camK , denom , date , camMat . getPos ( ) ) ;
+ + currVert ;
}
for ( uint l = 0 ; l < numVerts - 2 ; + + l )
{
* ( CVector * ) dest = unprojectedTriSoft [ 0 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 0 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = unprojectedTriSoft [ l + 1 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ l + 1 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = unprojectedTriSoft [ l + 2 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ l + 2 ] ;
dest + = sizeof ( float [ 2 ] ) ;
}
}
}
// TODO : optimize if needed
for ( sint k = 0 ; k < ( sint ) _Inside . size ( ) ; + + k )
{
sint y = k + _MinYInside ;
CVector proj [ 4 ] ;
CVector2f envMap [ 4 ] ;
if ( _Inside [ k ] . first < = _Inside [ k ] . second )
{
// middle block, are not clipped, but count the number of wanted vertices
for ( sint x = _Inside [ k ] . first ; x < = _Inside [ k ] . second ; + + x )
{
computeWaterVertexSoft ( ( float ) x , ( float ) y , proj [ 0 ] , envMap [ 0 ] , camI , camJ , camK , denom , date , camMat . getPos ( ) ) ;
computeWaterVertexSoft ( ( float ) ( x + 1 ) , ( float ) y , proj [ 1 ] , envMap [ 1 ] , camI , camJ , camK , denom , date , camMat . getPos ( ) ) ;
computeWaterVertexSoft ( ( float ) ( x + 1 ) , ( float ) ( y + 1 ) , proj [ 2 ] , envMap [ 2 ] , camI , camJ , camK , denom , date , camMat . getPos ( ) ) ;
computeWaterVertexSoft ( ( float ) x , ( float ) ( y + 1 ) , proj [ 3 ] , envMap [ 3 ] , camI , camJ , camK , denom , date , camMat . getPos ( ) ) ;
//
* ( CVector * ) dest = proj [ 0 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 0 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = proj [ 2 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 2 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = proj [ 1 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 1 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = proj [ 0 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 0 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = proj [ 3 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 3 ] ;
dest + = sizeof ( float [ 2 ] ) ;
* ( CVector * ) dest = proj [ 2 ] ;
dest + = sizeof ( float [ 3 ] ) ;
* ( CVector2f * ) dest = envMap [ 2 ] ;
dest + = sizeof ( float [ 2 ] ) ;
}
}
}
nlassert ( ( dest - ( uint8 * ) datas ) % ( 3 * WATER_VERTEX_SOFT_SIZE ) = = 0 ) ;
2010-05-13 20:14:36 +00:00
uint endTri = ( uint ) ( dest - ( uint8 * ) datas ) / ( 3 * WATER_VERTEX_SOFT_SIZE ) ;
2010-05-06 00:08:41 +00:00
_NumTris = endTri - _StartTri ;
return endTri ;
}
// compute single water vertex for hardware render
static
# ifndef NL_DEBUG
inline
# endif
void computeWaterVertexHard ( float px , float py , CVector & pos , const CVector & camI , const CVector & camJ , const CVector & camK , float denom )
{
CVector d = px * camI + py * camK + camJ ;
float intersectionDist = denom / d . z ;
pos . x = intersectionDist * d . x ;
pos . y = intersectionDist * d . y ;
pos . z = 0.f ;
}
//***********************************************************************************************************
uint CWaterModel : : fillVBHard ( void * datas , uint startTri )
{
_StartTri = ( uint32 ) startTri ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
const NLMISC : : CMatrix & camMat = renderTrav . CamMatrix ;
const sint numStepX = CWaterShape : : getScreenXGridSize ( ) ;
const sint numStepY = CWaterShape : : getScreenYGridSize ( ) ;
CVector camI = camMat . getI ( ) * ( 1.f / numStepX ) * ( renderTrav . Right - renderTrav . Left ) / renderTrav . Near ;
CVector camJ = camMat . getJ ( ) ;
CVector camK = camMat . getK ( ) * ( 1.f / numStepY ) * ( renderTrav . Top - renderTrav . Bottom ) / renderTrav . Near ;
float obsZ = camMat . getPos ( ) . z ;
float denom = getWorldMatrix ( ) . getPos ( ) . z - obsZ ;
uint8 * dest = ( uint8 * ) datas + startTri * WATER_VERTEX_HARD_SIZE * 3 ;
if ( ! _ClippedTriNumVerts . empty ( ) )
{
const CVector2f * currVert = & _ClippedTris . front ( ) ;
static std : : vector < CVector > unprojectedTri ;
for ( uint k = 0 ; k < _ClippedTriNumVerts . size ( ) ; + + k )
{
unprojectedTri . resize ( _ClippedTriNumVerts [ k ] ) ;
uint numVerts = _ClippedTriNumVerts [ k ] ;
for ( uint l = 0 ; l < _ClippedTriNumVerts [ k ] ; + + l )
{
computeWaterVertexHard ( currVert - > x , currVert - > y , unprojectedTri [ l ] , camI , camJ , camK , denom ) ;
+ + currVert ;
}
for ( uint l = 0 ; l < numVerts - 2 ; + + l )
{
* ( CVector * ) dest = unprojectedTri [ 0 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = unprojectedTri [ l + 1 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = unprojectedTri [ l + 2 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
}
}
}
// TODO : optimize if needed
for ( sint k = 0 ; k < ( sint ) _Inside . size ( ) ; + + k )
{
sint y = k + _MinYInside ;
CVector proj [ 4 ] ;
if ( _Inside [ k ] . first < = _Inside [ k ] . second )
{
// middle block, are not clipped, but count the number of wanted vertices
for ( sint x = _Inside [ k ] . first ; x < = _Inside [ k ] . second ; + + x )
{
computeWaterVertexHard ( ( float ) x , ( float ) y , proj [ 0 ] , camI , camJ , camK , denom ) ;
computeWaterVertexHard ( ( float ) ( x + 1 ) , ( float ) y , proj [ 1 ] , camI , camJ , camK , denom ) ;
computeWaterVertexHard ( ( float ) ( x + 1 ) , ( float ) ( y + 1 ) , proj [ 2 ] , camI , camJ , camK , denom ) ;
computeWaterVertexHard ( ( float ) x , ( float ) ( y + 1 ) , proj [ 3 ] , camI , camJ , camK , denom ) ;
//
* ( CVector * ) dest = proj [ 0 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = proj [ 2 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = proj [ 1 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = proj [ 0 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = proj [ 3 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
* ( CVector * ) dest = proj [ 2 ] ;
dest + = WATER_VERTEX_HARD_SIZE ;
}
}
}
nlassert ( ( dest - ( uint8 * ) datas ) % ( 3 * WATER_VERTEX_HARD_SIZE ) = = 0 ) ;
2010-05-13 20:14:36 +00:00
uint endTri = ( uint ) ( dest - ( uint8 * ) datas ) / ( 3 * WATER_VERTEX_HARD_SIZE ) ;
2010-05-06 00:08:41 +00:00
_NumTris = endTri - _StartTri ;
return endTri ;
}
//***************************************************************************************************************
void CWaterModel : : traverseRender ( )
{
H_AUTO ( NL3D_Water_Render ) ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
IDriver * drv = renderTrav . getDriver ( ) ;
CWaterShape * shape = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
const NLMISC : : CVector & obsPos = renderTrav . CamPos ;
const float zHeight = getWorldMatrix ( ) . getPos ( ) . z ;
if ( ! renderTrav . Perspective | | forceWaterSimpleRender )
{
// not supported, simple uniform render
drv - > setupModelMatrix ( getWorldMatrix ( ) ) ;
static CMaterial waterMat ;
static bool initDone = false ;
if ( ! initDone )
{
waterMat . initUnlit ( ) ;
waterMat . setBlend ( true ) ;
waterMat . setSrcBlend ( CMaterial : : srcalpha ) ;
waterMat . setDstBlend ( CMaterial : : invsrcalpha ) ;
waterMat . setBlend ( true ) ;
waterMat . setDoubleSided ( true ) ;
waterMat . setLighting ( false ) ;
}
waterMat . setColor ( shape - > computeEnvMapMeanColor ( ) ) ;
static std : : vector < NLMISC : : CTriangleUV > tris ;
const NLMISC : : CPolygon2D & poly = shape - > getShape ( ) ;
tris . clear ( ) ;
for ( sint k = 0 ; k < ( sint ) poly . Vertices . size ( ) - 2 ; + + k )
{
NLMISC : : CTriangleUV truv ;
truv . V0 . set ( poly . Vertices [ 0 ] . x , poly . Vertices [ 0 ] . y , 0.f ) ;
truv . V1 . set ( poly . Vertices [ k + 1 ] . x , poly . Vertices [ k + 1 ] . y , 0.f ) ;
truv . V2 . set ( poly . Vertices [ k + 2 ] . x , poly . Vertices [ k + 2 ] . y , 0.f ) ;
tris . push_back ( truv ) ;
}
CDRU : : drawTrianglesUnlit ( tris , waterMat , * drv ) ;
}
else
{
NLMISC : : CMatrix modelMat ;
modelMat . setPos ( NLMISC : : CVector ( obsPos . x , obsPos . y , zHeight ) ) ;
drv - > setupModelMatrix ( modelMat ) ;
bool isAbove = obsPos . z > getWorldMatrix ( ) . getPos ( ) . z ;
CVertexBuffer & vb = renderTrav . Scene - > getWaterVB ( ) ;
if ( drv - > isWaterShaderSupported ( ) )
{
setupMaterialNVertexShader ( drv , shape , obsPos , isAbove , zHeight ) ;
nlassert ( vb . getNumVertices ( ) > 0 ) ;
drv - > activeVertexBuffer ( vb ) ;
drv - > renderRawTriangles ( CWaterModel : : _WaterMat , _StartTri , _NumTris ) ;
drv - > activeVertexProgram ( NULL ) ;
}
else
{
setupSimpleRender ( shape , obsPos , isAbove ) ;
drv - > activeVertexBuffer ( vb ) ;
drv - > activeVertexProgram ( NULL ) ;
drv - > renderRawTriangles ( CWaterModel : : _SimpleWaterMat , _StartTri , _NumTris ) ;
}
}
}
//***********************************************************************************************************
bool CWaterModel : : clip ( )
{
H_AUTO ( NL3D_Water_Render ) ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
if ( renderTrav . CamPos . z = = getWorldMatrix ( ) . getPos ( ) . z ) return false ;
if ( Shape )
{
computeClippedPoly ( ) ;
if ( _ClippedPoly . Vertices . empty ( ) ) return false ;
// unlink from water model list
unlink ( ) ;
// link into water model list
link ( ) ;
return true ;
}
else
return false ;
}
/*
// struct used to build vertices for the simple shader
struct CSimpleVertexInfo
{
NLMISC : : CVector XFormPos ;
NLMISC : : CUV UV ;
} ;
*/
//***********************************************************************************************************
/*
void CWaterModel : : doSimpleRender ( IDriver * drv )
{
if ( _ClippedPoly . Vertices . empty ( ) ) return ;
// rendering of water when no vertex / pixel shaders are available
CWaterShape * shape = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
CRenderTrav & renderTrav = getOwnerScene ( ) - > getRenderTrav ( ) ;
static bool init = false ;
if ( ! init )
{
// setup the material, no special shader is used here
_SimpleWaterMat . setLighting ( false ) ;
_SimpleWaterMat . setDoubleSided ( true ) ;
_SimpleWaterMat . setColor ( NLMISC : : CRGBA : : White ) ;
_SimpleWaterMat . setBlend ( true ) ;
_SimpleWaterMat . setSrcBlend ( CMaterial : : srcalpha ) ;
_SimpleWaterMat . setDstBlend ( CMaterial : : invsrcalpha ) ;
_SimpleWaterMat . setZWrite ( true ) ;
_SimpleWaterMat . setShader ( CMaterial : : Normal ) ;
// stage 0
_SimpleWaterMat . texEnvOpRGB ( 0 , CMaterial : : Replace ) ;
_SimpleWaterMat . texEnvOpAlpha ( 0 , CMaterial : : Replace ) ;
_SimpleWaterMat . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
// stage 1
_SimpleWaterMat . texEnvOpRGB ( 1 , CMaterial : : Modulate ) ;
_SimpleWaterMat . texEnvOpAlpha ( 1 , CMaterial : : Modulate ) ;
_SimpleWaterMat . texEnvArg0RGB ( 0 , CMaterial : : Texture , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg0Alpha ( 0 , CMaterial : : Texture , CMaterial : : SrcAlpha ) ;
_SimpleWaterMat . texEnvArg1RGB ( 0 , CMaterial : : Previous , CMaterial : : SrcColor ) ;
_SimpleWaterMat . texEnvArg1Alpha ( 0 , CMaterial : : Previous , CMaterial : : SrcAlpha ) ;
// setup the vb : one position & two tex coords
_SimpleRenderVB . setVertexFormat ( CVertexBuffer : : PositionFlag | CVertexBuffer : : TexCoord0Flag | CVertexBuffer : : TexCoord1Flag ) ;
init = true ;
}
const NLMISC : : CMatrix & worldMatrix = getWorldMatrix ( ) ;
const NLMISC : : CVector & obsPos = renderTrav . CamPos ;
// setup the material
bool isAbove = obsPos . z > worldMatrix . getPos ( ) . z ;
// envmap is always present and is in stage 0
CScene * scene = getOwnerScene ( ) ;
if ( ! isAbove & & shape - > _EnvMap [ 1 ] )
{
if ( shape - > _UsesSceneWaterEnvMap [ 1 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
_SimpleWaterMat . setTexture ( 0 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 1 ] ) ;
}
}
else
{
if ( shape - > _UsesSceneWaterEnvMap [ 0 ] )
{
if ( scene - > getWaterEnvMap ( ) )
{
_SimpleWaterMat . setTexture ( 0 , scene - > getWaterEnvMap ( ) - > getEnvMap2D ( ) ) ;
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 0 ] ) ;
}
}
else
{
_SimpleWaterMat . setTexture ( 0 , shape - > _EnvMap [ 0 ] ) ;
}
}
//
static std : : vector < CSimpleVertexInfo > verts ;
static CIndexBuffer indices ;
//
NLMISC : : CPolygon2D & poly = shape - > _Poly ;
uint numVerts = poly . Vertices . size ( ) ;
uint k ;
//
if ( shape - > _ColorMap = = NULL )
{
// version with no color map
if ( ! _EmbossTexture )
{
_EmbossTexture = new CTextureEmboss ;
_EmbossTexture - > setSlopeFactor ( 4.f ) ;
}
if ( shape - > _BumpMap [ 1 ] & & shape - > _BumpMap [ 1 ] - > isBumpMap ( ) )
{
CTextureBump * bm = static_cast < CTextureBump * > ( ( ITexture * ) shape - > _BumpMap [ 1 ] ) ;
if ( bm - > getHeightMap ( ) )
{
_EmbossTexture - > setHeightMap ( bm - > getHeightMap ( ) ) ;
}
}
_SimpleWaterMat . setTexture ( 1 , _EmbossTexture ) ;
_SimpleRenderVB . setNumVertices ( numVerts ) ;
// retrieve current time
float date = 0.001f * ( NLMISC : : CTime : : getLocalTime ( ) & 0xffffff ) ; // must keep some precision.
// Compute tex coordinates for emboss first.
// On some 3D chip, textures coords can't grow too mush or texture filtering loose accuracy.
// So we must keep texCoord as low as possible.
//
verts . resize ( numVerts ) ;
for ( k = 0 ; k < numVerts ; + + k )
{
verts [ k ] . XFormPos = worldMatrix * NLMISC : : CVector ( poly . Vertices [ k ] . x , poly . Vertices [ k ] . y , 0.f ) ;
verts [ k ] . UV . U = shape - > _HeightMapScale [ 0 ] . x * verts [ k ] . XFormPos . x + date * shape - > _HeightMapSpeed [ 0 ] . x ;
verts [ k ] . UV . V = shape - > _HeightMapScale [ 0 ] . y * verts [ k ] . XFormPos . y + date * shape - > _HeightMapSpeed [ 0 ] . y ;
}
// get min tex coords
float minU = verts [ 0 ] . UV . U ;
float minV = verts [ 0 ] . UV . V ;
for ( k = 1 ; k < numVerts ; + + k )
{
minU = std : : min ( minU , verts [ k ] . UV . U ) ;
minV = std : : min ( minV , verts [ k ] . UV . V ) ;
}
//
minU = floorf ( minU ) ;
minV = floorf ( minV ) ;
//
CVertexBufferReadWrite vba ;
_SimpleRenderVB . lock ( vba ) ;
uint8 * data = ( uint8 * ) vba . getVertexCoordPointer ( ) ;
for ( k = 0 ; k < numVerts ; + + k )
{
( ( NLMISC : : CVector * ) data ) - > set ( poly . Vertices [ k ] . x , poly . Vertices [ k ] . y , 0.f ) ;
data + = sizeof ( NLMISC : : CVector ) ;
// texture coord 0 is reflected vector into envmap
// xform position in world space to compute the reflection
CVector surfToEye = ( obsPos - verts [ k ] . XFormPos ) . normed ( ) ;
// we assume that normal is (0, 0, 1)
* ( float * ) data = 0.5f - 0.5f * surfToEye . x ;
( ( float * ) data ) [ 1 ] = 0.5f - 0.5f * surfToEye . y ;
data + = sizeof ( float [ 2 ] ) ;
// texture coord 1 is the embossed map
* ( float * ) data = verts [ k ] . UV . U - minU ;
( ( float * ) data ) [ 1 ] = verts [ k ] . UV . V - minV ;
data + = sizeof ( float [ 2 ] ) ;
}
}
else
{
// version with a color map : it remplace the emboss texture
_SimpleWaterMat . setTexture ( 1 , shape - > _ColorMap ) ;
_SimpleRenderVB . setNumVertices ( numVerts ) ;
CVertexBufferReadWrite vba ;
_SimpleRenderVB . lock ( vba ) ;
//
uint8 * data = ( uint8 * ) vba . getVertexCoordPointer ( ) ;
for ( k = 0 ; k < numVerts ; + + k )
{
* ( NLMISC : : CVector * ) data = poly . Vertices [ k ] ;
data + = sizeof ( CVector ) ;
// texture coord 0 is reflected vector into envmap
// xform position in world space to compute the reflection
NLMISC : : CVector xformPos = worldMatrix * poly . Vertices [ k ] ;
NLMISC : : CVector surfToEye = ( obsPos - xformPos ) . normed ( ) ;
// we assume that normal is (0, 0, 1)
* ( float * ) data = 0.5f - 0.5f * surfToEye . x ;
( ( float * ) data ) [ 1 ] = 0.5f * - 0.5f * surfToEye . y ;
data + = sizeof ( float [ 2 ] ) ;
// texture coord 1 is the color map
* ( float * ) data = shape - > _ColorMapMatColumn0 . x * xformPos . x + shape - > _ColorMapMatColumn1 . x * xformPos . y + shape - > _ColorMapMatPos . x ;
( ( float * ) data ) [ 1 ] = shape - > _ColorMapMatColumn0 . y * xformPos . x + shape - > _ColorMapMatColumn1 . y * xformPos . y + shape - > _ColorMapMatPos . y ;
data + = sizeof ( float [ 2 ] ) ;
}
}
drv - > activeVertexProgram ( NULL ) ;
drv - > setupModelMatrix ( worldMatrix ) ;
drv - > activeVertexBuffer ( _SimpleRenderVB ) ;
// create an index buffer to do the display
indices . setNumIndexes ( ( numVerts - 2 ) * 3 ) ;
{
CIndexBufferReadWrite ibaWrite ;
indices . lock ( ibaWrite ) ;
uint32 * ptr = ibaWrite . getPtr ( ) ;
for ( k = 0 ; k < ( numVerts - 2 ) ; + + k )
{
ptr [ k * 3 ] = 0 ;
ptr [ k * 3 + 1 ] = k + 1 ;
ptr [ k * 3 + 2 ] = k + 2 ;
}
}
drv - > setupMaterial ( _SimpleWaterMat ) ;
drv - > activeIndexBuffer ( indices ) ;
drv - > renderSimpleTriangles ( 0 , numVerts - 2 ) ;
}
*/
//***********************************************************************************************************
void CWaterModel : : updateDiffuseMapMatrix ( bool force /* = false*/ )
{
if ( compareMatrixDate ( _MatrixUpdateDate ) | | force )
{
CWaterShape * shape = NLMISC : : safe_cast < CWaterShape * > ( ( IShape * ) Shape ) ;
if ( shape )
{
_MatrixUpdateDate = getMatrixDate ( ) ;
// update the uv matrix
CMatrix uvMat ;
uvMat . setRot ( CVector ( shape - > _ColorMapMatColumn0 . x , shape - > _ColorMapMatColumn0 . y , 0.f ) ,
CVector ( shape - > _ColorMapMatColumn1 . x , shape - > _ColorMapMatColumn1 . y , 0.f ) ,
CVector ( shape - > _ColorMapMatPos . x , shape - > _ColorMapMatPos . y , 1.f ) ) ;
CMatrix xformMat ;
CMatrix invMat = this - > getWorldMatrix ( ) . inverted ( ) ;
xformMat . setRot ( CVector ( invMat . getI ( ) . x , invMat . getI ( ) . y , 0.f ) ,
CVector ( invMat . getJ ( ) . x , invMat . getJ ( ) . y , 0.f ) ,
CVector ( invMat . getPos ( ) . x , invMat . getPos ( ) . y , 1.f ) ) ;
uvMat = uvMat * xformMat ;
_ColorMapMatColumn0 . set ( uvMat . getI ( ) . x , uvMat . getI ( ) . y ) ;
_ColorMapMatColumn1 . set ( uvMat . getJ ( ) . x , uvMat . getJ ( ) . y ) ;
_ColorMapMatPos . set ( uvMat . getK ( ) . x , uvMat . getK ( ) . y ) ;
}
}
}
// ***************************************************************************
void CWaterModel : : debugDumpMem ( void * & clippedPolyBegin , void * & clippedPolyEnd )
{
clippedPolyBegin = ( void * ) ( & * _ClippedPoly . Vertices . begin ( ) ) ;
clippedPolyEnd = ( void * ) ( & * _ClippedPoly . Vertices . end ( ) ) ;
}
// ***************************************************************************
void CWaterModel : : debugClearClippedPoly ( )
{
_ClippedPoly . Vertices . clear ( ) ;
}
//=======================================================================================
// wave maker implementation
//=======================================================================================
CWaveMakerModel : : CWaveMakerModel ( ) : _Time ( 0 )
{
// AnimDetail behavior: Must be traversed in AnimDetail, even if no channel mixer registered
CTransform : : setIsForceAnimDetail ( true ) ;
}
//================================================
void CWaveMakerModel : : registerBasic ( )
{
CScene : : registerModel ( WaveMakerModelClassId , TransformShapeId , CWaveMakerModel : : creator ) ;
}
//================================================
ITrack * CWaveMakerModel : : getDefaultTrack ( uint valueId )
{
nlassert ( Shape ) ;
CWaveMakerShape * ws = NLMISC : : safe_cast < CWaveMakerShape * > ( ( IShape * ) Shape ) ;
switch ( valueId )
{
case PosValue : return ws - > getDefaultPos ( ) ; break ;
default : // delegate to parent
return CTransformShape : : getDefaultTrack ( valueId ) ;
break ;
}
}
//================================================
void CWaveMakerModel : : traverseAnimDetail ( )
{
CTransformShape : : traverseAnimDetail ( ) ;
nlassert ( getOwnerScene ( ) ) ;
/// get the shape
CWaveMakerShape * wms = NLMISC : : safe_cast < CWaveMakerShape * > ( ( IShape * ) Shape ) ;
const NLMISC : : CVector worldPos = getWorldMatrix ( ) . getPos ( ) ;
const CVector2f pos2d ( worldPos . x , worldPos . y ) ;
/// get the water height map
CWaterHeightMap & whm = GetWaterPoolManager ( ) . getPoolByID ( wms - > _PoolID ) ;
// get the time delta
const TAnimationTime deltaT = std : : min ( getOwnerScene ( ) - > getEllapsedTime ( ) , ( TAnimationTime ) whm . getPropagationTime ( ) ) ;
_Time + = deltaT ;
if ( ! wms - > _ImpulsionMode )
{
whm . perturbate ( pos2d , wms - > _Intensity * cosf ( 2.f / wms - > _Period * ( float ) NLMISC : : Pi * _Time ) , wms - > _Radius ) ;
}
else
{
if ( _Time > wms - > _Period )
{
_Time - = wms - > _Period ;
whm . perturbate ( pos2d , wms - > _Intensity , wms - > _Radius ) ;
}
}
}
} // NL3D