waterBlock.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "environment/waterBlock.h"
  24. #include "core/util/safeDelete.h"
  25. #include "scene/sceneRenderState.h"
  26. #include "scene/sceneManager.h"
  27. #include "lighting/lightInfo.h"
  28. #include "core/stream/bitStream.h"
  29. #include "math/mathIO.h"
  30. #include "console/consoleTypes.h"
  31. #include "gui/3d/guiTSControl.h"
  32. #include "gfx/primBuilder.h"
  33. #include "gfx/gfxTransformSaver.h"
  34. #include "gfx/gfxDebugEvent.h"
  35. #include "gfx/gfxOcclusionQuery.h"
  36. #include "renderInstance/renderPassManager.h"
  37. #include "sim/netConnection.h"
  38. #include "scene/reflectionManager.h"
  39. #include "ts/tsShapeInstance.h"
  40. #include "postFx/postEffect.h"
  41. #include "math/util/matrixSet.h"
  42. #include "console/typeValidators.h"
  43. IMPLEMENT_CO_NETOBJECT_V1(WaterBlock);
  44. ConsoleDocClass( WaterBlock,
  45. "@brief A block shaped water volume defined by a 3D scale and orientation.\n\n"
  46. "@see WaterObject for inherited functionality.\n\n"
  47. "@ingroup Water"
  48. );
  49. WaterBlock::WaterBlock()
  50. {
  51. mGridElementSize = 5.0f;
  52. mObjScale.set( 100.0f, 100.0f, 10.0f );
  53. mWidth = 2;
  54. mHeight = 2;
  55. mNetFlags.set(Ghostable | ScopeAlways);
  56. mObjBox.minExtents.set( -0.5f, -0.5f, -0.5f );
  57. mObjBox.maxExtents.set( 0.5f, 0.5f, 0.5f );
  58. mElapsedTime = 0.0f;
  59. mGenerateVB = true;
  60. }
  61. WaterBlock::~WaterBlock()
  62. {
  63. }
  64. bool WaterBlock::onAdd()
  65. {
  66. if ( !Parent::onAdd() )
  67. return false;
  68. resetWorldBox();
  69. addToScene();
  70. return true;
  71. }
  72. void WaterBlock::onRemove()
  73. {
  74. clearVertBuffers();
  75. removeFromScene();
  76. Parent::onRemove();
  77. }
  78. //-----------------------------------------------------------------------------
  79. // packUpdate
  80. //-----------------------------------------------------------------------------
  81. U32 WaterBlock::packUpdate(NetConnection* con, U32 mask, BitStream* stream)
  82. {
  83. U32 retMask = Parent::packUpdate(con, mask, stream);
  84. stream->write( mGridElementSize );
  85. if ( stream->writeFlag( mask & UpdateMask ) )
  86. {
  87. // This is set to allow the user to modify the size of the water dynamically
  88. // in the editor
  89. mathWrite( *stream, mObjScale );
  90. stream->writeAffineTransform( mObjToWorld );
  91. }
  92. return retMask;
  93. }
  94. //-----------------------------------------------------------------------------
  95. // unpackUpdate
  96. //-----------------------------------------------------------------------------
  97. void WaterBlock::unpackUpdate(NetConnection* con, BitStream* stream)
  98. {
  99. Parent::unpackUpdate(con, stream);
  100. F32 gridSize = mGridElementSize;
  101. stream->read( &mGridElementSize );
  102. if ( gridSize != mGridElementSize )
  103. mGenerateVB = true;
  104. if( stream->readFlag() ) // UpdateMask
  105. {
  106. Point3F scale;
  107. mathRead( *stream, &scale );
  108. setScale( scale );
  109. MatrixF objToWorld;
  110. stream->readAffineTransform( &objToWorld );
  111. setTransform( objToWorld );
  112. }
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Setup vertex and index buffers
  116. //-----------------------------------------------------------------------------
  117. void WaterBlock::setupVBIB()
  118. {
  119. clearVertBuffers();
  120. const U32 maxIndexedVerts = 65536; // max number of indexed verts with U16 size indices
  121. if( mObjScale.x < mGridElementSize ||
  122. mObjScale.y < mGridElementSize )
  123. {
  124. F32 oldGridSize = mGridElementSize;
  125. mGridElementSize = getMin(mObjScale.x, mObjScale.y);
  126. logWarning("gridElementSize %g is larger than scale (%g, %g), clamping gridElementSize to %g",
  127. oldGridSize, mObjScale.x, mObjScale.y, mGridElementSize);
  128. }
  129. Point3F div = getScale() / mGridElementSize;
  130. // Add one to width and height for the edge.
  131. mWidth = (U32)mCeil(div.x) + 1;
  132. mHeight = (U32)mCeil(div.y) + 1;
  133. if( mWidth > maxIndexedVerts / 2 )
  134. mWidth = maxIndexedVerts / 2;
  135. // figure out how many blocks are needed and their size
  136. U32 maxBlockRows = maxIndexedVerts / mWidth;
  137. U32 rowOffset = 0;
  138. while( (rowOffset+1) < mHeight )
  139. {
  140. U32 numRows = mHeight - rowOffset;
  141. if( numRows == 1 ) numRows++;
  142. if( numRows > maxBlockRows )
  143. {
  144. numRows = maxBlockRows;
  145. }
  146. setupVertexBlock( mWidth, numRows, rowOffset );
  147. setupPrimitiveBlock( mWidth, numRows );
  148. rowOffset += numRows - 1;
  149. }
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Set up a block of vertices - the width is always the width of the entire
  153. // waterBlock, so this is a block of full rows.
  154. //-----------------------------------------------------------------------------
  155. void WaterBlock::setupVertexBlock( U32 width, U32 height, U32 rowOffset )
  156. {
  157. RayInfo rInfo;
  158. VectorF sunVector(-0.61f, 0.354f, 0.707f);
  159. if ( LIGHTMGR )
  160. {
  161. LightInfo* linfo = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
  162. if ( linfo )
  163. sunVector = linfo->getDirection();
  164. }
  165. sunVector.normalize();
  166. U32 numVerts = width * height;
  167. GFXWaterVertex *verts = new GFXWaterVertex[ numVerts ];
  168. U32 index = 0;
  169. for( U32 i=0; i<height; i++ )
  170. {
  171. for( U32 j=0; j<width; j++, index++ )
  172. {
  173. F32 vertX = getMin((-mObjScale.x / 2.0f) + mGridElementSize * j, mObjScale.x / 2.0f);
  174. F32 vertY = getMin((-mObjScale.y / 2.0f) + mGridElementSize * (i + rowOffset), mObjScale.y / 2.0f);
  175. GFXWaterVertex *vert = &verts[index];
  176. vert->point.x = vertX;
  177. vert->point.y = vertY;
  178. vert->point.z = 0.0;
  179. vert->normal.set(0,0,1);
  180. vert->undulateData.set( vertX, vertY );
  181. vert->horizonFactor.set( 0, 0, 0, 0 );
  182. // Calculate the water depth
  183. /*
  184. vert->depthData.set( 0.0f, 0.0f );
  185. Point3F start, end;
  186. Point3F worldPoint = vert->point + pos;
  187. start.x = end.x = worldPoint.x;
  188. start.y = end.y = worldPoint.y;
  189. start.z = -2000; // Really high, might be over kill
  190. end.z = 2000; // really low, might be overkill
  191. // Cast a ray to see how deep the water is. We are
  192. // currently just testing for terrain and atlas
  193. // objects, but potentially any object that responds
  194. // to a ray cast could detected.
  195. if(gClientContainer.castRay(start, end,
  196. //StaticObjectType |
  197. //InteriorObjectType |
  198. //ShapeBaseObjectType |
  199. //StaticShapeObjectType |
  200. //ItemObjectType |
  201. //StaticTSObjectType |
  202. TerrainObjectType
  203. , &rInfo))
  204. {
  205. F32 depth = -(rInfo.point.z - pos.z);
  206. if(depth <= 0.0f)
  207. {
  208. depth = 1.0f;
  209. }
  210. else
  211. {
  212. depth = depth / mVisibilityDepth;
  213. if(depth > 1.0f)
  214. {
  215. depth = 1.0f;
  216. }
  217. depth = 1.0f - depth;
  218. }
  219. vert->depthData.x = depth;
  220. }
  221. else
  222. {
  223. vert->depthData.x = 0.0f;
  224. }
  225. // Cast a ray to do some AO-style shadowing.
  226. F32 &shadow = vert->depthData.y;
  227. if(gClientContainer.castRay(worldPoint, worldPoint + sunVector * 9000.f,
  228. //StaticObjectType |
  229. //InteriorObjectType |
  230. //ShapeBaseObjectType |
  231. //StaticShapeObjectType |
  232. //ItemObjectType |
  233. //StaticTSObjectType |
  234. TerrainObjectType
  235. , &rInfo))
  236. {
  237. shadow = 0.f;
  238. }
  239. else
  240. {
  241. shadow = 1.f;
  242. }
  243. */
  244. }
  245. }
  246. // copy to vertex buffer
  247. GFXVertexBufferHandle <GFXWaterVertex> * vertBuff = new GFXVertexBufferHandle <GFXWaterVertex>;
  248. vertBuff->set( GFX, numVerts, GFXBufferTypeStatic );
  249. GFXWaterVertex *vbVerts = vertBuff->lock();
  250. dMemcpy( vbVerts, verts, sizeof(GFXWaterVertex) * numVerts );
  251. vertBuff->unlock();
  252. mVertBuffList.push_back( vertBuff );
  253. delete [] verts;
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Set up a block of indices to match the block of vertices. The width is
  257. // always the width of the entire waterBlock, so this is a block of full rows.
  258. //-----------------------------------------------------------------------------
  259. void WaterBlock::setupPrimitiveBlock( U32 width, U32 height )
  260. {
  261. AssertFatal( height > 1, "WaterBlock::setupPrimitiveBlock() - invalid height" );
  262. // setup vertex / primitive buffers
  263. U32 numIndices = (width-1) * (height-1) * 6;
  264. U16 *indices = new U16[ numIndices ];
  265. U32 numVerts = width * height;
  266. // This uses indexed triangle lists instead of strips, but it shouldn't be
  267. // significantly slower if the indices cache well.
  268. // Rough diagram of the index order
  269. // 0----2----+ ...
  270. // | / | |
  271. // |/ | |
  272. // 1----3----+ ...
  273. // | | |
  274. // | | |
  275. // +----+----+ ...
  276. U32 index = 0;
  277. for( U32 i=0; i<(height-1); i++ )
  278. {
  279. for( U32 j=0; j<(width-1); j++, index+=6 )
  280. {
  281. // Process one quad at a time. Note it will re-use the same indices from
  282. // previous quad, thus optimizing vert cache. Cache will run out at
  283. // end of each row with this implementation however.
  284. indices[index+0] = (i) * mWidth + j; // 0
  285. indices[index+1] = (i+1) * mWidth + j; // 1
  286. indices[index+2] = i * mWidth + j+1; // 2
  287. indices[index+3] = (i+1) * mWidth + j; // 1
  288. indices[index+4] = (i+1) * mWidth + j+1; // 3
  289. indices[index+5] = i * mWidth + j+1; // 2
  290. }
  291. }
  292. GFXPrimitiveBufferHandle *indexBuff = new GFXPrimitiveBufferHandle;
  293. GFXPrimitive pInfo;
  294. pInfo.type = GFXTriangleList;
  295. pInfo.numPrimitives = numIndices / 3;
  296. pInfo.startIndex = 0;
  297. pInfo.minIndex = 0;
  298. pInfo.numVertices = numVerts;
  299. U16 *ibIndices;
  300. GFXPrimitive *piInput;
  301. indexBuff->set( GFX, numIndices, 1, GFXBufferTypeStatic );
  302. indexBuff->lock( &ibIndices, &piInput );
  303. dMemcpy( ibIndices, indices, numIndices * sizeof(U16) );
  304. dMemcpy( piInput, &pInfo, sizeof(GFXPrimitive) );
  305. indexBuff->unlock();
  306. mPrimBuffList.push_back( indexBuff );
  307. delete [] indices;
  308. }
  309. //------------------------------------------------------------------------------
  310. // Setup scenegraph data structure for materials
  311. //------------------------------------------------------------------------------
  312. SceneData WaterBlock::setupSceneGraphInfo( SceneRenderState *state )
  313. {
  314. SceneData sgData;
  315. sgData.lights[0] = LIGHTMGR->getSpecialLight( LightManager::slSunLightType );
  316. // fill in water's transform
  317. sgData.objTrans = &getRenderTransform();
  318. // fog
  319. sgData.setFogParams( state->getSceneManager()->getFogData() );
  320. // misc
  321. sgData.backBuffTex = REFLECTMGR->getRefractTex();
  322. sgData.reflectTex = mPlaneReflector.reflectTex;
  323. sgData.wireframe = GFXDevice::getWireframe() || smWireframe;
  324. return sgData;
  325. }
  326. //-----------------------------------------------------------------------------
  327. // set shader parameters
  328. //-----------------------------------------------------------------------------
  329. void WaterBlock::setShaderParams( SceneRenderState *state, BaseMatInstance *mat, const WaterMatParams &paramHandles)
  330. {
  331. // Set variables that will be assigned to shader consts within WaterCommon
  332. // before calling Parent::setShaderParams
  333. mUndulateMaxDist = F32_MAX;
  334. Parent::setShaderParams( state, mat, paramHandles );
  335. // Now set the rest of the shader consts that are either unique to this
  336. // class or that WaterObject leaves to us to handle...
  337. MaterialParameters* matParams = mat->getMaterialParameters();
  338. // set vertex shader constants
  339. //-----------------------------------
  340. MatrixF modelMat( getRenderTransform() );
  341. if ( paramHandles.mModelMatSC->isValid() )
  342. matParams->set(paramHandles.mModelMatSC, modelMat, GFXSCT_Float4x4);
  343. matParams->setSafe(paramHandles.mGridElementSizeSC, (F32)mGridElementSize);
  344. // set pixel shader constants
  345. //-----------------------------------
  346. LinearColorF c( mWaterFogData.color );
  347. matParams->setSafe( paramHandles.mBaseColorSC, c );
  348. // By default we need to show a true reflection is fullReflect is enabled and
  349. // we are above water.
  350. F32 reflect = mPlaneReflector.isEnabled() && !isUnderwater( state->getCameraPosition() );
  351. // If we were occluded the last frame a query was fetched ( not necessarily last frame )
  352. // and we weren't updated last frame... we don't have a valid texture to show
  353. // so use the cubemap / fake reflection color this frame.
  354. if ( mPlaneReflector.lastUpdateMs != REFLECTMGR->getLastUpdateMs() && mPlaneReflector.isOccluded() )
  355. reflect = false;
  356. Point4F reflectParams( mWaterPos.z, 0.0f, 1000.0f, !reflect );
  357. matParams->setSafe( paramHandles.mReflectParamsSC, reflectParams );
  358. VectorF reflectNorm = mReflectNormalUp ? VectorF(0,0,1) : static_cast<VectorF>(mPlaneReflector.refplane);
  359. matParams->setSafe(paramHandles.mReflectNormalSC, reflectNorm );
  360. }
  361. void WaterBlock::innerRender( SceneRenderState *state )
  362. {
  363. GFXDEBUGEVENT_SCOPE( WaterBlock_innerRender, ColorI( 255, 0, 0 ) );
  364. if ( mGenerateVB )
  365. {
  366. setupVBIB();
  367. mGenerateVB = false;
  368. }
  369. // Setup SceneData
  370. SceneData sgData = setupSceneGraphInfo( state );
  371. const Point3F &camPosition = state->getCameraPosition();
  372. // set the material
  373. S32 matIdx = getMaterialIndex( camPosition );
  374. if ( !initMaterial( matIdx ) )
  375. return;
  376. BaseMatInstance *mat = mMatInstances[matIdx];
  377. WaterMatParams matParams = mMatParamHandles[matIdx];
  378. // render the geometry
  379. if ( mat )
  380. {
  381. // setup proj/world transform
  382. mMatrixSet->setWorld(getRenderTransform());
  383. mMatrixSet->restoreSceneViewProjection();
  384. setShaderParams( state, mat, matParams );
  385. while ( mat->setupPass( state, sgData ) )
  386. {
  387. mat->setSceneInfo(state, sgData);
  388. mat->setTransforms(*mMatrixSet, state);
  389. setCustomTextures( matIdx, mat->getCurPass(), matParams );
  390. for ( U32 i = 0; i < mVertBuffList.size(); i++ )
  391. {
  392. GFX->setVertexBuffer( *mVertBuffList[i] );
  393. GFXPrimitiveBuffer *primBuff = *mPrimBuffList[i];
  394. GFX->setPrimitiveBuffer( primBuff );
  395. GFX->drawPrimitives();
  396. }
  397. }
  398. }
  399. }
  400. bool WaterBlock::setGridSizeProperty( void *obj, const char *index, const char *data )
  401. {
  402. WaterBlock* object = static_cast<WaterBlock*>(obj);
  403. F32 gridSize = dAtof(data);
  404. Point3F scale = object->getScale();
  405. if(gridSize < 0.001f)
  406. {
  407. object->logWarning("gridSize cannot be <= 0, clamping to scale");
  408. gridSize = getMin(scale.x, scale.y);
  409. }
  410. if(gridSize > scale.x || gridSize > scale.y)
  411. {
  412. object->logWarning("gridSize cannot be > scale. Your scale is (%g, %g) and your gridsize is %g",
  413. scale.x, scale.y, gridSize);
  414. gridSize = getMin(scale.x, scale.y);
  415. }
  416. object->mGridElementSize = gridSize;
  417. // This is a hack so the console system doesn't go in and set our variable
  418. // again, after we've already set it (possibly with a different value...)
  419. return false;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // initPersistFields
  423. //-----------------------------------------------------------------------------
  424. void WaterBlock::initPersistFields()
  425. {
  426. docsURL;
  427. addGroup( "WaterBlock" );
  428. addProtectedFieldV("gridSize", TypeRangedF32, Offset(mGridElementSize, WaterBlock), &setGridSizeProperty, &defaultProtectedGetFn, &CommonValidators::PositiveFloat,
  429. "Spacing between vertices in the WaterBlock mesh");
  430. addProtectedFieldV("gridElementSize", TypeRangedF32, Offset(mGridElementSize, WaterBlock), &setGridSizeProperty, &defaultProtectedGetFn, &CommonValidators::PositiveFloat, "Duplicate of gridElementSize for backwards compatility");
  431. Parent::initPersistFields();
  432. }
  433. bool WaterBlock::isUnderwater( const Point3F &pnt ) const
  434. {
  435. // Transform point into object space so we can test if it is within
  436. // the WaterBlock's object box, include rotation/scale.
  437. Point3F objPnt = pnt;
  438. mWorldToObj.mulP( pnt, &objPnt );
  439. objPnt.z -= 0.1f;
  440. Box3F testBox = mObjBox;
  441. testBox.scale( mObjScale );
  442. // We already tested if below the surface plane,
  443. // so clamping the z height of the box is not really necessary.
  444. testBox.maxExtents.z = testBox.getCenter().z;
  445. if ( testBox.isContained( objPnt ) )
  446. return true;
  447. return false;
  448. }
  449. void WaterBlock::clearVertBuffers()
  450. {
  451. for( U32 i=0; i<mVertBuffList.size(); i++ )
  452. delete mVertBuffList[i];
  453. mVertBuffList.clear();
  454. for( U32 i=0; i<mPrimBuffList.size(); i++ )
  455. delete mPrimBuffList[i];
  456. mPrimBuffList.clear();
  457. }
  458. void WaterBlock::inspectPostApply()
  459. {
  460. Parent::inspectPostApply();
  461. VectorF scale = getScale();
  462. if( scale.x < mGridElementSize )
  463. scale.x = mGridElementSize;
  464. if( scale.y < mGridElementSize )
  465. scale.y = mGridElementSize;
  466. if( scale != getScale() )
  467. setScale( scale );
  468. setMaskBits( UpdateMask );
  469. }
  470. void WaterBlock::setTransform( const MatrixF &mat )
  471. {
  472. // If our transform changes we need to recalculate the
  473. // per vertex depth/shadow info. Would be nice if this could
  474. // be done independently of generating the whole VBIB...
  475. Parent::setTransform( mat );
  476. // We don't need to regen our vb anymore since we aren't calculating
  477. // per vert depth/shadow on the cpu anymore.
  478. //if ( oldMat != mObjToWorld )
  479. // mGenerateVB = true;
  480. // Keep mWaterPlane up to date.
  481. mWaterFogData.plane.set( 0, 0, 1, -getPosition().z );
  482. }
  483. void WaterBlock::setScale( const Point3F &scale )
  484. {
  485. Point3F oldScale = mObjScale;
  486. Parent::setScale( scale );
  487. if ( oldScale != mObjScale )
  488. mGenerateVB = true;
  489. }
  490. void WaterBlock::onStaticModified( const char* slotName, const char*newValue )
  491. {
  492. Parent::onStaticModified( slotName, newValue );
  493. if ( dStricmp( slotName, "surfMaterial" ) == 0 )
  494. setMaskBits( MaterialMask );
  495. if ( dStricmp( slotName, "gridElementSize" ) == 0 )
  496. {
  497. mGenerateVB = true;
  498. setMaskBits( UpdateMask );
  499. }
  500. }
  501. bool WaterBlock::castRay( const Point3F &start, const Point3F &end, RayInfo *info )
  502. {
  503. // Simply look for the hit on the water plane
  504. // and ignore any future issues with waves, etc.
  505. const Point3F norm(0,0,1);
  506. PlaneF plane( Point3F::Zero, norm );
  507. F32 hit = plane.intersect( start, end );
  508. if ( hit < 0.0f || hit > 1.0f )
  509. return false;
  510. info->t = hit;
  511. info->object = this;
  512. info->point = start + ( ( end - start ) * hit );
  513. info->normal = norm;
  514. info->material = mMatInstances[WaterMat];
  515. return mObjBox.isContained(info->point);
  516. }
  517. bool WaterBlock::buildPolyList( PolyListContext context, AbstractPolyList* polyList, const Box3F& box, const SphereF& )
  518. {
  519. if(context == PLC_Navigation && box.isOverlapped(mWorldBox))
  520. {
  521. polyList->setObject( this );
  522. MatrixF mat(true);
  523. Point3F pos = getPosition();
  524. pos.x = pos.y = 0;
  525. mat.setPosition(pos);
  526. polyList->setTransform( &mat, Point3F(1, 1, 1) );
  527. Box3F ov = box.getOverlap(mWorldBox);
  528. Point3F
  529. p0(ov.minExtents.x, ov.maxExtents.y, 0),
  530. p1(ov.maxExtents.x, ov.maxExtents.y, 0),
  531. p2(ov.maxExtents.x, ov.minExtents.y, 0),
  532. p3(ov.minExtents.x, ov.minExtents.y, 0);
  533. // Add vertices to poly list.
  534. U32 v0 = polyList->addPoint(p0);
  535. polyList->addPoint(p1);
  536. polyList->addPoint(p2);
  537. polyList->addPoint(p3);
  538. // Add plane between first three vertices.
  539. polyList->begin(0, 0);
  540. polyList->vertex(v0);
  541. polyList->vertex(v0+1);
  542. polyList->vertex(v0+2);
  543. polyList->plane(v0, v0+1, v0+2);
  544. polyList->end();
  545. // Add plane between last three vertices.
  546. polyList->begin(0, 1);
  547. polyList->vertex(v0+2);
  548. polyList->vertex(v0+3);
  549. polyList->vertex(v0);
  550. polyList->plane(v0+2, v0+3, v0);
  551. polyList->end();
  552. return true;
  553. }
  554. return false;
  555. }
  556. F32 WaterBlock::getWaterCoverage( const Box3F &testBox ) const
  557. {
  558. Box3F wbox = getWorldBox();
  559. wbox.maxExtents.z = wbox.getCenter().z;
  560. F32 coverage = 0.0f;
  561. if ( wbox.isOverlapped(testBox) )
  562. {
  563. if (wbox.maxExtents.z < testBox.maxExtents.z)
  564. coverage = (wbox.maxExtents.z - testBox.minExtents.z) / (testBox.maxExtents.z - testBox.minExtents.z);
  565. else
  566. coverage = 1.0f;
  567. }
  568. return coverage;
  569. }
  570. F32 WaterBlock::getSurfaceHeight( const Point2F &pos ) const
  571. {
  572. if ( !mWorldBox.isContained( pos ) )
  573. return -1.0f;
  574. return getPosition().z;
  575. }
  576. void WaterBlock::_getWaterPlane( const Point3F &camPos, PlaneF &outPlane, Point3F &outPos )
  577. {
  578. outPos = getPosition();
  579. if ( mReflectNormalUp )
  580. outPlane.set( outPos, Point3F(0,0,1) );
  581. else
  582. {
  583. Point3F normal;
  584. getRenderTransform().getColumn( 2, &normal );
  585. outPlane.set( outPos, normal );
  586. }
  587. }
  588. F32 WaterBlock::distanceTo( const Point3F& point ) const
  589. {
  590. Box3F waterBox = getWorldBox();
  591. waterBox.maxExtents.z = getPosition().z;
  592. return waterBox.getDistanceToPoint( point );
  593. }