waterPlane.cpp

Engine/source/environment/waterPlane.cpp

More...

Public Defines

define

Public Variables

Public Functions

ConsoleDocClass(WaterPlane , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> large body of water stretching <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the horizon in all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">directions.\n\n</a>" "<a href="/coding/class/classwaterplane/">WaterPlane</a>'s position is defined only height, the z element of position, " "it is infinite in xy and depth. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> represent the " "ocean on an island scene and viewed from ground level;other uses may not " "be appropriate and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classwaterblock/">WaterBlock</a> may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">used.\n\n</a>" " @see <a href="/coding/class/classwaterobject/">WaterObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> inherited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">functionality.\n\n</a>" "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Limitations:\n\n</a>" "Because %<a href="/coding/class/classwaterplane/">WaterPlane</a> cannot be projected exactly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the far-clip distance, " "other objects nearing this distance can have noticible artifacts as they " "clip through first the %<a href="/coding/class/classwaterplane/">WaterPlane</a> and then the far <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">plane.\n\n</a>" "To avoid this large objects should be positioned such that they will not line up with " "the far-clip from vantage points the player is expected <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be. In particular, " "your <a href="/coding/class/classterrainblock/">TerrainBlock</a> should be completely contained by the far-clip <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">distance.\n\n</a>" "Viewing %<a href="/coding/class/classwaterplane/">WaterPlane</a> from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> high altitude with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tight far-clip distance " "will accentuate this limitation. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is primarily designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "be viewed from ground <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" " @ingroup Water" )

Detailed Description

Public Defines

BLEND_TEX_SIZE() 256
V_SHADER_PARAM_OFFSET() 50

Public Variables

ColorI gCanvasClearColor 

Public Functions

ConsoleDocClass(WaterPlane , "@brief Represents <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> large body of water stretching <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the horizon in all <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">directions.\n\n</a>" "<a href="/coding/class/classwaterplane/">WaterPlane</a>'s position is defined only height, the z element of position, " "it is infinite in xy and depth. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> represent the " "ocean on an island scene and viewed from ground level;other uses may not " "be appropriate and <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> <a href="/coding/class/classwaterblock/">WaterBlock</a> may be <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">used.\n\n</a>" " @see <a href="/coding/class/classwaterobject/">WaterObject</a> <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1a2732ab74fa0237854c2ba0f75f88a624">for</a> inherited <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">functionality.\n\n</a>" "<a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">Limitations:\n\n</a>" "Because %<a href="/coding/class/classwaterplane/">WaterPlane</a> cannot be projected exactly <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> the far-clip distance, " "other objects nearing this distance can have noticible artifacts as they " "clip through first the %<a href="/coding/class/classwaterplane/">WaterPlane</a> and then the far <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">plane.\n\n</a>" "To avoid this large objects should be positioned such that they will not line up with " "the far-clip from vantage points the player is expected <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> be. In particular, " "your <a href="/coding/class/classterrainblock/">TerrainBlock</a> should be completely contained by the far-clip <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">distance.\n\n</a>" "Viewing %<a href="/coding/class/classwaterplane/">WaterPlane</a> from <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> high altitude with <a href="/coding/file/pointer_8h/#pointer_8h_1aeeddce917cf130d62c370b8f216026dd">a</a> tight far-clip distance " "will accentuate this limitation. %<a href="/coding/class/classwaterplane/">WaterPlane</a> is primarily designed <a href="/coding/file/cmdgram_8cpp/#cmdgram_8cpp_1a5bafda9519252aa2d0fd038153f77dca">to</a> " "be viewed from ground <a href="/coding/file/cmdscan_8cpp/#cmdscan_8cpp_1aeab71244afb687f16d8c4f5ee9d6ef0e">level.\n\n</a>" " @ingroup Water" )

IMPLEMENT_CO_NETOBJECT_V1(WaterPlane )

   1
   2//-----------------------------------------------------------------------------
   3// Copyright (c) 2012 GarageGames, LLC
   4//
   5// Permission is hereby granted, free of charge, to any person obtaining a copy
   6// of this software and associated documentation files (the "Software"), to
   7// deal in the Software without restriction, including without limitation the
   8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   9// sell copies of the Software, and to permit persons to whom the Software is
  10// furnished to do so, subject to the following conditions:
  11//
  12// The above copyright notice and this permission notice shall be included in
  13// all copies or substantial portions of the Software.
  14//
  15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21// IN THE SOFTWARE.
  22//-----------------------------------------------------------------------------
  23
  24#include "platform/platform.h"
  25#include "environment/waterPlane.h"
  26
  27#include "core/util/safeDelete.h"
  28#include "scene/sceneRenderState.h"
  29#include "scene/sceneManager.h"
  30#include "lighting/lightInfo.h"
  31#include "core/stream/bitStream.h"
  32#include "math/mathIO.h"
  33#include "math/mathUtils.h"
  34#include "console/consoleTypes.h"
  35#include "gui/3d/guiTSControl.h"
  36#include "gfx/primBuilder.h"
  37#include "gfx/gfxTransformSaver.h"
  38#include "gfx/gfxDebugEvent.h"
  39#include "gfx/gfxOcclusionQuery.h"
  40#include "renderInstance/renderPassManager.h"
  41#include "sim/netConnection.h"
  42#include "scene/reflectionManager.h"
  43#include "ts/tsShapeInstance.h"
  44#include "T3D/gameFunctions.h"
  45#include "postFx/postEffect.h"
  46#include "math/util/matrixSet.h"
  47
  48extern ColorI gCanvasClearColor;
  49
  50#define BLEND_TEX_SIZE 256
  51#define V_SHADER_PARAM_OFFSET 50
  52
  53IMPLEMENT_CO_NETOBJECT_V1(WaterPlane);
  54
  55ConsoleDocClass( WaterPlane,
  56   "@brief Represents a large body of water stretching to the horizon in all directions.\n\n"
  57
  58   "WaterPlane's position is defined only height, the z element of position, "
  59   "it is infinite in xy and depth. %WaterPlane is designed to represent the "
  60   "ocean on an island scene and viewed from ground level; other uses may not "
  61   "be appropriate and a WaterBlock may be used.\n\n"
  62
  63   "@see WaterObject for inherited functionality.\n\n"
  64
  65   "Limitations:\n\n"
  66   
  67   "Because %WaterPlane cannot be projected exactly to the far-clip distance, "
  68   "other objects nearing this distance can have noticible artifacts as they "
  69   "clip through first the %WaterPlane and then the far plane.\n\n"
  70   
  71   "To avoid this large objects should be positioned such that they will not line up with "
  72   "the far-clip from vantage points the player is expected to be. In particular, "
  73   "your TerrainBlock should be completely contained by the far-clip distance.\n\n"
  74   
  75   "Viewing %WaterPlane from a high altitude with a tight far-clip distance "
  76   "will accentuate this limitation. %WaterPlane is primarily designed to "
  77   "be viewed from ground level.\n\n"
  78      
  79   "@ingroup Water"
  80);
  81
  82WaterPlane::WaterPlane()
  83{
  84   mGridElementSize = 1.0f;
  85   mGridSize = 101;
  86   mGridSizeMinusOne = mGridSize - 1;
  87
  88   mNetFlags.set(Ghostable | ScopeAlways);
  89
  90   mVertCount = 0;
  91   mIndxCount = 0;
  92   mPrimCount = 0;   
  93}
  94
  95WaterPlane::~WaterPlane()
  96{
  97}
  98
  99bool WaterPlane::onAdd()
 100{
 101   if ( !Parent::onAdd() )
 102      return false;
 103   
 104   setGlobalBounds();
 105   resetWorldBox();
 106   addToScene();
 107
 108   mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
 109
 110   return true;
 111}
 112
 113void WaterPlane::onRemove()
 114{   
 115   removeFromScene();
 116
 117   Parent::onRemove();
 118}
 119
 120void WaterPlane::initPersistFields()
 121{
 122   addGroup( "WaterPlane" );     
 123
 124      addProtectedField( "gridSize", TypeS32, Offset( mGridSize, WaterPlane ), &protectedSetGridSize, &defaultProtectedGetFn,
 125        "Spacing between vertices in the WaterBlock mesh" );
 126
 127      addProtectedField( "gridElementSize", TypeF32, Offset( mGridElementSize, WaterPlane ), &protectedSetGridElementSize, &defaultProtectedGetFn,
 128        "Duplicate of gridElementSize for backwards compatility");
 129
 130   endGroup( "WaterPlane" );
 131
 132   Parent::initPersistFields();
 133
 134   removeField( "rotation" );
 135   removeField( "scale" );
 136}
 137
 138U32 WaterPlane::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
 139{
 140   U32 retMask = Parent::packUpdate(con, mask, stream);
 141
 142   stream->write( mGridSize );
 143   stream->write( mGridElementSize );   
 144
 145   if ( stream->writeFlag( mask & UpdateMask ) )
 146   {
 147      stream->write( getPosition().z );        
 148   }
 149
 150   return retMask;
 151}
 152
 153void WaterPlane::unpackUpdate(NetConnection* con, BitStream* stream)
 154{
 155   Parent::unpackUpdate(con, stream);
 156
 157   U32 inGridSize;
 158   stream->read( &inGridSize );
 159   setGridSize( inGridSize );
 160
 161   F32 inGridElementSize;
 162   stream->read( &inGridElementSize );
 163   setGridElementSize( inGridElementSize );
 164
 165   if( stream->readFlag() ) // UpdateMask
 166   {
 167      F32 posZ;
 168      stream->read( &posZ );
 169      Point3F newPos = getPosition();
 170      newPos.z = posZ;
 171      setPosition( newPos );
 172   }  
 173}
 174
 175void WaterPlane::setupVBIB( SceneRenderState *state )
 176{
 177   const Frustum &frustum = state->getCullingFrustum();
 178   
 179   // World-Up vector, assigned as normal for all verts.
 180   const Point3F worldUp( 0.0f, 0.0f, 1.0f );
 181
 182   // World-unit size of a grid cell.
 183   const F32 squareSize = mGridElementSize;
 184
 185   // Column/Row count.
 186   // So we don't neet to access class-specific member variables
 187   // in the code below.
 188   const U32 gridSize = mGridSize;
 189
 190   // Number of verts in one column / row
 191   const U32 gridStride = gridSize + 1;
 192
 193   // Grid is filled in this order...
 194   
 195   // Ex. Grid with gridSize of 2.
 196   //
 197   // Letters are cells.
 198   // Numbers are verts, enumerated in their order within the vert buffer.       
 199   //
 200   // 6  7  8   
 201   // (c) (d)
 202   // 3  4  5
 203   // (a) (b)
 204   // 0  1  2
 205   //   
 206   // Note...
 207   //   Camera would be positioned at vert 4 ( in this particular grid not a constant ).
 208   //   Positive Y points UP the diagram ( verts 0, 3, 6 ).
 209   //   Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
 210
 211   // Length of a grid row/column divided by two.
 212   F32 gridSideHalfLen = squareSize * gridSize * 0.5f;
 213
 214   // Position of the first vertex in the grid.
 215   // Relative to the camera this is the "Back Left" corner vert.
 216   const Point3F cornerPosition( -gridSideHalfLen, -gridSideHalfLen, 0.0f );   
 217
 218   // Number of verts in the grid centered on the camera.
 219   const U32 gridVertCount = gridStride * gridStride;
 220
 221   // Number of verts surrounding the grid, projected by the frustum.
 222   const U32 borderVertCount = gridSize * 4;
 223
 224   // Number of verts in the front-most row which are raised to the horizon.
 225   const U32 horizonVertCount = gridStride;
 226
 227   // Total number of verts. Calculation explained above.
 228   mVertCount = gridVertCount + borderVertCount + horizonVertCount;
 229
 230   
 231   // Fill the vertex buffer...
 232
 233   mVertBuff.set( GFX, mVertCount, GFXBufferTypeStatic );
 234
 235   GFXWaterVertex *vertPtr = mVertBuff.lock();
 236
 237   // Fill verts in the camera centered grid...
 238
 239   // Temorary storage for calculation of vert position.
 240   F32 xVal, yVal;
 241
 242   for ( U32 i = 0; i < gridStride; i++ )
 243   {
 244      yVal = cornerPosition.y + (F32)( i * squareSize );
 245
 246      for ( U32 j = 0; j < gridStride; j++ )
 247      {
 248         xVal = cornerPosition.x + (F32)( j * squareSize );
 249
 250         vertPtr->point.set( xVal, yVal, 0.0f );
 251         vertPtr->normal = worldUp;
 252         vertPtr->undulateData.set( xVal, yVal );
 253         vertPtr->horizonFactor.set( 0, 0, 0, 0 );
 254         vertPtr++;
 255      }
 256   }
 257
 258   // Fill in 'border' verts, surrounding the grid, projected by the frustum.
 259
 260   // Ex. Grid with gridSize of 2.
 261   //
 262   // Letters in parenthesis are cells.
 263   // x's are grid-verts ( we have already filled ).
 264   // Numbers are border verts, enumerated in their order within the vert buffer.       
 265   // 
 266   // Lines connecting verts explained in the code below.
 267   //
 268   //      Front
 269   //
 270   //  L   0------1      2   R
 271   //  e       x  x  x   |   i
 272   //  f       (c) (d)   |   g
 273   //  t   7   x  x  x   3   h
 274   //      |   (a) (b)       t
 275   //      |   x  x  x       
 276   //      6      5------4
 277   //
 278   //      Back
 279   //   
 280   // As in previous diagram...
 281   //   Camera would be positioned at vert 4 ( in this particular grid not a constant ).
 282   //   Positive Y points UP the diagram ( verts 6, 7, 0 ).
 283   //   Positive X points RIGHT across the diagram ( verts 0, 1, 2 ).
 284
 285
 286   // Iterator i is looping through the 4 'sides' of the grid.
 287   // Inner loop ( using iterator j ) will fill in a number of verts   
 288   // where that count is 'gridSize'.
 289   //    
 290   // 
 291   // Ex. Given the grid with gridSize of 2 diagramed above,
 292   // Outer loop iterates through: Front, Right, Back, Left
 293   // Inner loop fills 2 verts per iteration of the outer loop: { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }
 294
 295   // Grid-space vectors indexed by 'side'.
 296   // Each vector describes the direction we iterate when
 297   // filling in verts ( mathematically the tangent ).
 298   const Point2F sBorderTangentVec [4] = {
 299      Point2F(  1,  0 ), // Front ( 0 )
 300      Point2F(  0, -1 ), // Right ( 1 )
 301      Point2F( -1,  0 ), // Back  ( 2 )
 302      Point2F(  0,  1 )  // Left  ( 3 )
 303   };
 304   
 305
 306   // Normalized positions indexed by 'side'
 307   // Defines the 'start' position of each side, eg. the position of the first vert.
 308   // See Diagram below.
 309   const Point2F sBorderStartPos [4] = {
 310      Point2F( -1,  1 ), // Front ( 0 )
 311      Point2F(  1,  1 ), // Right ( 1 )
 312      Point2F(  1, -1 ), // Back  ( 2 )
 313      Point2F( -1, -1 )  // Left  ( 3 )
 314   };
 315
 316   // Diagram of Start vert position per Side.
 317   //
 318   // Labeling convention for verts is 'As' where A is the first letter of 
 319   // that side's descriptive name and lower-case s indicates 'start'. 
 320   // 
 321   // 
 322   //
 323   //          Front
 324   //          (-1,1)
 325   //          Fs------o-----Rs(1,1)R
 326   //          |             |      i
 327   //          |             |      g
 328   //          o     (0,0)   o      h
 329   //          |             |      t
 330   //          |             |     
 331   //  L(-1,-1)Ls------o-----Bs
 332   //  e                     (1,-1)   
 333   //  f                     Back
 334   //  t
 335
 336   // Calculate the world-space dimension of the border-vert-ring...
 337
 338   // Diagram shows overall layout of the WaterPlane with a gridSize of 1,
 339   // with all 'quads' enumerated.
 340   // center-grid ( 1 ), border ( 2, 3, 4, 5 ), and horizon ( 6 ).
 341   //
 342   //
 343   //   x------------x
 344   //    \      6     \    <- horizon quad is really 'above' the front border
 345   //      x ---------  x     not in front of it
 346   //      | \    2   / |
 347   //      |   x---- x  |
 348   //      |   |     |  |
 349   //      |  5|  1  |3 |
 350   //      |   x --- x  |
 351   //      | /    4    \|
 352   //      x------------x
 353
 354
 355   // WaterPlane renders relative to the camera rotation around z and xy position.
 356   //
 357   // That is, it rotates around the z-up axis with the camera such that the
 358   // camera is always facing towards the front border unless looking straight
 359   // down or up.
 360   //
 361   // Also note that the horizon verts are pulled straight up from the front
 362   // border verts.
 363   //
 364   // Therefore...
 365   //
 366   // The front border must be as close to the farclip plane as possible 
 367   // so distant objects clip through the horizon and  farplane at the same time.
 368   // 
 369   // The left and right borders must be pulled outward a distance such
 370   // that water extends horizontally across the entire viewable area while
 371   // looking straight forward +y or straight down -z.
 372   //
 373
 374   // 
 375   const F32 farDistScale = 0.99f;
 376
 377   // 
 378   F32 farDist = frustum.getFarDist() * farDistScale;
 379   
 380   //
 381   F32 farWidth = (F32)state->getViewport().extent.x * farDist / state->getWorldToScreenScale().x;
 382
 383   Point2F borderExtents( farWidth * 2.0f, farDist * 2.0f );
 384   Point2F borderHalfExtents( farWidth, farDist );   
 385
 386   Point2F borderDir;
 387   Point2F borderStart;
 388
 389   for ( U32 i = 0; i < 4; i++ )
 390   {
 391      borderDir = sBorderTangentVec[i];
 392      borderStart = sBorderStartPos[i];
 393
 394      for ( U32 j = 0; j < gridSize; j++ )
 395      {
 396         F32 frac = (F32)j / (F32)gridSize;
 397
 398         Point2F pos( borderStart * borderHalfExtents );
 399         pos += borderDir * borderExtents * frac;
 400
 401         vertPtr->point.set( pos.x, pos.y, 0.0f );
 402         vertPtr->undulateData.set( pos.x, pos.y );
 403         vertPtr->horizonFactor.set( 0, 0, 0, 0 );
 404         vertPtr->normal = worldUp;         
 405         vertPtr++;
 406      }
 407   }
 408
 409   // Fill in row of horizion verts.
 410   // Verts are positioned identical to the front border, but will be
 411   // manipulated in z within the shader.
 412   //
 413   // Z position of 50.0f is unimportant unless you want to disable
 414   // shader manipulation and render in wireframe for debugging.
 415
 416   for ( U32 i = 0; i < gridStride; i++ )
 417   {
 418      F32 frac = (F32)i / (F32)gridSize;
 419      
 420      Point2F pos( sBorderStartPos[0] * borderHalfExtents );
 421      pos += sBorderTangentVec[0] * borderExtents * frac;
 422
 423      vertPtr->point.set( pos.x, pos.y, 50.0f );
 424      vertPtr->undulateData.set( pos.x, pos.y );
 425      vertPtr->horizonFactor.set( 1, 0, 0, 0 );
 426      vertPtr->normal = worldUp;
 427      vertPtr++;
 428   }
 429
 430   mVertBuff.unlock();
 431
 432
 433   // Fill in the PrimitiveBuffer...
 434
 435   // 2 triangles per cell/quad   
 436   const U32 gridTriCount = gridSize * gridSize * 2;
 437
 438   // 4 sides, mGridSize quads per side, 2 triangles per quad
 439   const U32 borderTriCount = 4 * gridSize * 2;
 440
 441   // 1 quad per gridSize, 2 triangles per quad
 442   // i.e. an extra row of 'cells' leading the front side of the grid
 443   const U32 horizonTriCount = gridSize * 2;
 444   
 445   mPrimCount = gridTriCount + borderTriCount + horizonTriCount;
 446
 447   // 3 indices per triangle.
 448   mIndxCount = mPrimCount * 3; 
 449
 450   mPrimBuff.set( GFX, mIndxCount, mPrimCount, GFXBufferTypeStatic );
 451   U16 *idxPtr;
 452   mPrimBuff.lock(&idxPtr);        
 453
 454   // Temporaries to hold indices for the corner points of a quad.
 455   U32 p00, p01, p11, p10;
 456   U32 offset = 0;
 457
 458   // Given a single cell of the grid diagramed below,
 459   // quad indice variables are in this orientation.
 460   //
 461   // p01 --- p11
 462   //  |       |
 463   //  |       |
 464   // p00 --- p10
 465   //
 466   //   Positive Y points UP the diagram ( p00, p01 ).
 467   //   Positive X points RIGHT across the diagram ( p00, p10 )
 468   //
 469
 470   // i iterates bottom to top "column-wise"
 471   for ( U32 i = 0; i < mGridSize; i++ )
 472   {
 473      // j iterates left to right "row-wise"
 474      for ( U32 j = 0; j < mGridSize; j++ )
 475      {
 476         // where (j,i) is a particular cell.
 477         p00 = offset;
 478         p10 = offset + 1;
 479         p01 = offset + gridStride;
 480         p11 = offset + 1 + gridStride;
 481
 482         // Top Left Triangle
 483
 484         *idxPtr = p00;
 485         idxPtr++;
 486         *idxPtr = p01;
 487         idxPtr++;
 488         *idxPtr = p11;
 489         idxPtr++;
 490
 491         // Bottom Right Triangle
 492
 493         *idxPtr = p00;
 494         idxPtr++;
 495         *idxPtr = p11;
 496         idxPtr++;
 497         *idxPtr = p10;
 498         idxPtr++;
 499
 500         offset += 1;
 501      }
 502
 503      offset += 1;
 504   }
 505
 506   // Fill border indices...
 507
 508   // Given a grid size of 1, 
 509   // the grid / border verts are in the vertex buffer in this order.
 510   //
 511   //
 512   // 4           5  
 513   //    2 --- 3
 514   //    |     |
 515   //    |     |
 516   //    0 --- 1
 517   // 7           6
 518   //
 519   //   Positive Y points UP the diagram ( p00, p01 ).
 520   //   Positive X points RIGHT across the diagram ( p00, p10 )
 521   //
 522   //  Note we duplicate the first border vert ( 4 ) since it is also the last
 523   //  and this makes our loop easier.
 524
 525   const U32 sBorderStartVert [4] = {
 526      gridStride * gridSize,              // Index to the Top-Left grid vert.
 527      gridStride * gridSize + gridSize,   // Index to the Top-Right grid vert.
 528      gridSize,                           // Index to the Bottom-Right grid vert.
 529      0,                                  // Index to the Bottom-Left grid vert.
 530   };
 531
 532   const S32 sBorderStepSize [4] = {
 533      // Step size to the next grid vert along the specified side....
 534      1,             // Top
 535      -(S32)gridStride,   // Right
 536      -1,             // Bottom
 537      (S32)gridStride,    // Left
 538   };
 539
 540   const U32 firstBorderVert = gridStride * gridSize + gridStride;
 541   const U32 lastBorderVert = firstBorderVert + ( borderVertCount - 1 );
 542   U32 startBorderVert = firstBorderVert;
 543   U32 startGridVert;
 544   U32 curStepSize;
 545   
 546   
 547   for ( U32 i = 0; i < 4; i++ )
 548   {
 549      startGridVert = sBorderStartVert[i];
 550      curStepSize = sBorderStepSize[i];
 551      
 552      for ( U32 j = 0; j < gridSize; j++ )
 553      {
 554         // Each border cell is 1 quad, 2 triangles.
 555
 556         p00 = startGridVert;
 557         p10 = startGridVert + curStepSize;
 558         p01 = startBorderVert;
 559         p11 = startBorderVert + 1;
 560         
 561         if ( p11 > lastBorderVert )
 562            p11 = firstBorderVert;
 563
 564         // Top Left Triangle
 565
 566         *idxPtr = p00;
 567         idxPtr++;
 568         *idxPtr = p01;
 569         idxPtr++;
 570         *idxPtr = p11;
 571         idxPtr++;
 572
 573         // Bottom Right Triangle
 574
 575         *idxPtr = p00;
 576         idxPtr++;
 577         *idxPtr = p11;
 578         idxPtr++;
 579         *idxPtr = p10;
 580         idxPtr++;
 581
 582         startBorderVert++;
 583         startGridVert += curStepSize;
 584      }
 585   }
 586
 587   // Fill in 'horizon' triangles.
 588
 589   U32 curHorizonVert = lastBorderVert + 1;
 590   U32 curBorderVert = firstBorderVert;
 591
 592   for ( U32 i = 0; i < gridSize; i++ )
 593   {
 594      p00 = curBorderVert;
 595      p10 = curBorderVert + 1;
 596      p01 = curHorizonVert;
 597      p11 = curHorizonVert + 1;
 598      
 599      // Top Left Triangle
 600
 601      *idxPtr = p00;
 602      idxPtr++;
 603      *idxPtr = p01;
 604      idxPtr++;
 605      *idxPtr = p11;
 606      idxPtr++;
 607
 608      // Bottom Right Triangle
 609
 610      *idxPtr = p00;
 611      idxPtr++;
 612      *idxPtr = p11;
 613      idxPtr++;
 614      *idxPtr = p10;
 615      idxPtr++;
 616
 617      curBorderVert++;
 618      curHorizonVert++;
 619   }
 620
 621   mPrimBuff.unlock();
 622}
 623
 624SceneData WaterPlane::setupSceneGraphInfo( SceneRenderState *state )
 625{
 626   SceneData sgData;
 627
 628   sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
 629
 630   // fill in water's transform
 631   sgData.objTrans = &getRenderTransform();
 632
 633   // fog
 634   sgData.setFogParams( state->getSceneManager()->getFogData() );
 635
 636   // misc
 637   sgData.backBuffTex = REFLECTMGR->getRefractTex();
 638   sgData.reflectTex = mPlaneReflector.reflectTex;
 639   sgData.wireframe = GFXDevice::getWireframe() || smWireframe;
 640
 641   return sgData;
 642}
 643
 644void WaterPlane::setShaderParams( SceneRenderState *state, BaseMatInstance* mat, const WaterMatParams& paramHandles)
 645{
 646   // Set variables that will be assigned to shader consts within WaterCommon
 647   // before calling Parent::setShaderParams
 648
 649   mUndulateMaxDist = mGridElementSize * mGridSizeMinusOne * 0.5f;
 650
 651   Parent::setShaderParams( state, mat, paramHandles );   
 652
 653   // Now set the rest of the shader consts that are either unique to this
 654   // class or that WaterObject leaves to us to handle...    
 655
 656   MaterialParameters* matParams = mat->getMaterialParameters();
 657
 658   // set vertex shader constants
 659   //-----------------------------------   
 660   matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize);
 661   //matParams->setSafe( paramHandles.mReflectTexSizeSC, mReflectTexSize );
 662   if ( paramHandles.mModelMatSC->isValid() )
 663      matParams->set(paramHandles.mModelMatSC, getRenderTransform(), GFXSCT_Float4x4);
 664
 665   // set pixel shader constants
 666   //-----------------------------------
 667
 668   LinearColorF c( mWaterFogData.color );
 669   matParams->setSafe( paramHandles.mBaseColorSC, c );   
 670   
 671   // By default we need to show a true reflection is fullReflect is enabled and
 672   // we are above water.
 673   F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() );
 674   
 675   // If we were occluded the last frame a query was fetched ( not necessarily last frame )
 676   // and we weren't updated last frame... we don't have a valid texture to show
 677   // so use the cubemap / fake reflection color this frame.
 678   if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() )
 679      reflect = false;
 680
 681   //Point4F reflectParams( getRenderPosition().z, mReflectMinDist, mReflectMaxDist, reflect );
 682   Point4F reflectParams( getRenderPosition().z, 0.0f, 1000.0f, !reflect );
 683   
 684   // TODO: This is a hack... why is this broken... check after
 685   // we merge advanced lighting with trunk!
 686   //
 687   reflectParams.z = 0.0f;
 688   matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams );
 689
 690   VectorF reflectNorm( 0, 0, 1 );
 691   matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm ); 
 692}
 693
 694void WaterPlane::prepRenderImage( SceneRenderState *state )
 695{
 696   PROFILE_SCOPE(WaterPlane_prepRenderImage);
 697
 698   if( !state->isDiffusePass() )
 699      return;
 700
 701   mBasicLighting = dStricmp( LIGHTMGR->getId(), "BLM" ) == 0;
 702   mUnderwater = isUnderwater( state->getCameraPosition() );
 703
 704   mMatrixSet->setSceneView(GFX->getWorldMatrix());
 705   
 706   const Frustum &frustum = state->getCameraFrustum();
 707
 708   if ( mPrimBuff.isNull() || 
 709        mGenerateVB ||         
 710        frustum != mFrustum )
 711   {      
 712      mFrustum = frustum;
 713      setupVBIB( state );
 714      mGenerateVB = false;
 715
 716      MatrixF proj( true );
 717      MathUtils::getZBiasProjectionMatrix( 0.0001f, mFrustum, &proj );
 718      mMatrixSet->setSceneProjection(proj);
 719   }
 720
 721   _getWaterPlane( state->getCameraPosition(), mWaterPlane, mWaterPos );
 722   mWaterFogData.plane = mWaterPlane;
 723   mPlaneReflector.refplane = mWaterPlane;
 724   updateUnderwaterEffect( state );
 725
 726   ObjectRenderInst *ri = state->getRenderPass()->allocInst<ObjectRenderInst>();
 727   ri->renderDelegate.bind( this, &WaterObject::renderObject );
 728   ri->type = RenderPassManager::RIT_Water;
 729   state->getRenderPass()->addInst( ri );
 730
 731   //mRenderUpdateCount++;
 732}
 733
 734void WaterPlane::innerRender( SceneRenderState *state )
 735{
 736   GFXDEBUGEVENT_SCOPE( WaterPlane_innerRender, ColorI( 255, 0, 0 ) );
 737
 738   const Point3F &camPosition = state->getCameraPosition();
 739
 740   Point3F rvec, fvec, uvec, pos;
 741
 742   const MatrixF &objMat = getTransform(); //getRenderTransform();
 743   const MatrixF &camMat = state->getCameraTransform();
 744
 745   MatrixF renderMat( true );
 746
 747   camMat.getColumn( 1, &fvec );
 748   uvec.set( 0, 0, 1 );
 749   rvec = mCross( fvec, uvec );
 750   rvec.normalize();   
 751   fvec = mCross( uvec, rvec );
 752   pos = camPosition;
 753   pos.z = objMat.getPosition().z;      
 754
 755   renderMat.setColumn( 0, rvec );
 756   renderMat.setColumn( 1, fvec );
 757   renderMat.setColumn( 2, uvec );
 758   renderMat.setColumn( 3, pos );
 759
 760   setRenderTransform( renderMat );
 761
 762   // Setup SceneData
 763   SceneData sgData = setupSceneGraphInfo( state );   
 764
 765   // set the material
 766   S32 matIdx = getMaterialIndex( camPosition );
 767   
 768   if ( !initMaterial( matIdx ) )
 769      return;
 770
 771   BaseMatInstance *mat = mMatInstances[matIdx];
 772   WaterMatParams matParams = mMatParamHandles[matIdx];
 773
 774   // render the geometry
 775   if ( mat )
 776   {      
 777      // setup proj/world transform
 778      mMatrixSet->restoreSceneViewProjection();
 779      mMatrixSet->setWorld(getRenderTransform());
 780
 781      setShaderParams( state, mat, matParams );     
 782
 783      while( mat->setupPass( state, sgData ) )
 784      {    
 785         mat->setSceneInfo(state, sgData);
 786         mat->setTransforms(*mMatrixSet, state);
 787         setCustomTextures( matIdx, mat->getCurPass(), matParams );
 788
 789         // set vert/prim buffer
 790         GFX->setVertexBuffer( mVertBuff );
 791         GFX->setPrimitiveBuffer( mPrimBuff );
 792         GFX->drawIndexedPrimitive( GFXTriangleList, 0, 0, mVertCount, 0, mPrimCount );
 793      }
 794   }
 795}
 796
 797bool WaterPlane::isUnderwater( const Point3F &pnt ) const
 798{
 799   F32 height = getPosition().z;
 800
 801   F32 diff = pnt.z - height;
 802
 803   return ( diff < 0.1 );
 804}
 805
 806F32 WaterPlane::distanceTo( const Point3F& point ) const
 807{
 808   if( isUnderwater( point ) )
 809      return 0.f;
 810   else
 811      return ( point.z - getPosition().z );
 812}
 813
 814bool WaterPlane::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
 815{
 816   if(context == PLC_Navigation)
 817   {
 818      polyList->setObject( this );
 819      polyList->setTransform( &MatrixF::Identity, Point3F( 1.0f, 1.0f, 1.0f ) );
 820
 821      F32 z = getPosition().z;
 822      Point3F
 823         p0(box.minExtents.x, box.maxExtents.y, z),
 824         p1(box.maxExtents.x, box.maxExtents.y, z),
 825         p2(box.maxExtents.x, box.minExtents.y, z),
 826         p3(box.minExtents.x, box.minExtents.y, z);
 827
 828      // Add vertices to poly list.
 829      U32 v0 = polyList->addPoint(p0);
 830      polyList->addPoint(p1);
 831      polyList->addPoint(p2);
 832      polyList->addPoint(p3);
 833
 834      // Add plane between first three vertices.
 835      polyList->begin(0, 0);
 836      polyList->vertex(v0);
 837      polyList->vertex(v0+1);
 838      polyList->vertex(v0+2);
 839      polyList->plane(v0, v0+1, v0+2);
 840      polyList->end();
 841
 842      // Add plane between last three vertices.
 843      polyList->begin(0, 1);
 844      polyList->vertex(v0+2);
 845      polyList->vertex(v0+3);
 846      polyList->vertex(v0);
 847      polyList->plane(v0+2, v0+3, v0);
 848      polyList->end();
 849
 850      return true;
 851   }
 852
 853   return false;
 854}
 855
 856void WaterPlane::inspectPostApply()
 857{
 858   Parent::inspectPostApply();
 859
 860   setMaskBits( UpdateMask );
 861}
 862
 863void WaterPlane::setTransform( const MatrixF &mat )
 864{
 865   // We only accept the z value from the new transform.
 866
 867   MatrixF newMat( true );
 868   
 869   Point3F newPos = getPosition();
 870   newPos.z = mat.getPosition().z;  
 871   newMat.setPosition( newPos );
 872
 873   Parent::setTransform( newMat );
 874
 875   // Parent::setTransforms ends up setting our worldBox to something other than
 876   // global, so we have to set it back... but we can't actually call setGlobalBounds
 877   // again because it does extra work adding and removing us from the container.
 878
 879   mGlobalBounds = true;
 880   mObjBox.minExtents.set(-1e10, -1e10, -1e10);
 881   mObjBox.maxExtents.set( 1e10,  1e10,  1e10);
 882
 883   // Keep mWaterPlane up to date.
 884   mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );   
 885}
 886
 887void WaterPlane::onStaticModified( const char* slotName, const char*newValue )
 888{
 889   Parent::onStaticModified( slotName, newValue );
 890
 891   if ( dStricmp( slotName, "surfMaterial" ) == 0 )
 892      setMaskBits( MaterialMask );
 893}
 894
 895bool WaterPlane::castRay(const Point3F& start, const Point3F& end, RayInfo* info )
 896{
 897   // Simply look for the hit on the water plane
 898   // and ignore any future issues with waves, etc.
 899   const Point3F norm(0,0,1);
 900   PlaneF plane( Point3F::Zero, norm );
 901
 902   F32 hit = plane.intersect( start, end );
 903   if ( hit < 0.0f || hit > 1.0f )
 904      return false;
 905   
 906   info->t = hit;
 907   info->object = this;
 908   info->point = start + ( ( end - start ) * hit );
 909   info->normal = norm;
 910   info->material = mMatInstances[ WaterMat ];
 911
 912   return true;
 913}
 914
 915F32 WaterPlane::getWaterCoverage( const Box3F &testBox ) const
 916{
 917   F32 posZ = getPosition().z;
 918   
 919   F32 coverage = 0.0f;
 920
 921   if ( posZ > testBox.minExtents.z ) 
 922   {
 923      if ( posZ < testBox.maxExtents.z )
 924         coverage = (posZ - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z);
 925      else
 926         coverage = 1.0f;
 927   }
 928
 929   return coverage;
 930}
 931
 932F32 WaterPlane::getSurfaceHeight( const Point2F &pos ) const
 933{
 934   return getPosition().z;   
 935}
 936
 937void WaterPlane::onReflectionInfoChanged()
 938{
 939   /*
 940   if ( isClientObject() && GFX->getPixelShaderVersion() >= 1.4 )
 941   {
 942      if ( mFullReflect )
 943         REFLECTMGR->registerObject( this, ReflectDelegate( this, &WaterPlane::updateReflection ), mReflectPriority, mReflectMaxRateMs, mReflectMaxDist );
 944      else
 945      {
 946         REFLECTMGR->unregisterObject( this );
 947         mReflectTex = NULL;
 948      }
 949   }
 950   */
 951}
 952
 953void WaterPlane::setGridSize( U32 inSize )
 954{
 955   if ( inSize == mGridSize )
 956      return;
 957
 958   // GridSize must be an odd number.
 959   //if ( inSize % 2 == 0 )
 960   //   inSize++;
 961
 962   // GridSize must be at least 1
 963   inSize = getMax( inSize, (U32)1 );
 964
 965   mGridSize = inSize;
 966   mGridSizeMinusOne = mGridSize - 1;
 967   mGenerateVB = true;
 968   setMaskBits( UpdateMask );
 969}
 970
 971void WaterPlane::setGridElementSize( F32 inSize )
 972{
 973   if ( inSize == mGridElementSize )
 974      return;
 975
 976   // GridElementSize must be greater than 0
 977   inSize = getMax( inSize, 0.0001f );
 978
 979   mGridElementSize = inSize;
 980   mGenerateVB = true;
 981   setMaskBits( UpdateMask );
 982}
 983
 984bool WaterPlane::protectedSetGridSize( void *obj, const char *index, const char *data )
 985{
 986   WaterPlane *object = static_cast<WaterPlane*>(obj);
 987   S32 size = dAtoi( data );
 988
 989   object->setGridSize( size );
 990
 991   // We already set the field.
 992   return false;
 993}
 994
 995bool WaterPlane::protectedSetGridElementSize( void *obj, const char *index, const char *data )
 996{
 997   WaterPlane *object = static_cast<WaterPlane*>(obj);
 998   F32 size = dAtof( data );
 999
1000   object->setGridElementSize( size );
1001
1002   // We already set the field.
1003   return false;
1004}
1005
1006void WaterPlane::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos )
1007{
1008   outPos = getPosition();   
1009   outPlane.set( outPos, Point3F(0,0,1) );   
1010}
1011