00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "std3d.h"
00027
00028 #include "3d/water_shape.h"
00029 #include "3d/water_model.h"
00030 #include "3d/vertex_buffer.h"
00031 #include "3d/texture_bump.h"
00032 #include "3d/texture_blend.h"
00033 #include "3d/scene.h"
00034 #include "3d/water_pool_manager.h"
00035 #include "3d/water_height_map.h"
00036 #include <memory>
00037
00038
00039 namespace NL3D {
00040
00041
00042
00043
00044
00045
00046
00047
00048
00061 const char *WaterVPStartCode =
00062 "!!VP1.0\n\
00063 ADD R1, c[7], -v[0]; #r1 = eye - vertex \n\
00064 DP3 R2, R1, R1; #r1 = eye - vertex, r2 = (eye - vertex)² \n\
00065 MAX R2, R2, c[16]; # avoid imprecision around 0 \n\
00066 RSQ R2, R2.x; #r1 = eye - vertex, r2 = 1/d(eye, vertex) \n\
00067 RCP R3, R2.x; \n\
00068 MAD R3, c[6].xxxx, -R3, c[6].yyyy; \n\
00069 MAX R3, c[5], R3; \n\
00070 MUL R0, R3, v[8]; #attenuate normal with distance \n\
00071 MUL R4.z, R3, v[0]; #attenuate height with distance \n\
00072 MOV R4.xyw, v[0]; \n\
00073 MOV R0.z, c[4].x; #set normal z to 1 \n\
00074 DP3 R3.x, R0, R0; \n\
00075 RSQ R3.x, R3.x; #normalize normal in R3 \n\
00076 MUL R0, R0, R3.x; \n\
00077 DP4 o[HPOS].x, c[0], R4; #transform vertex in view space \n\
00078 DP4 o[HPOS].y, c[1], R4; \n\
00079 DP4 o[HPOS].z, c[2], R4; \n\
00080 DP4 o[HPOS].w, c[3], R4; \n\
00081 MUL R1, R1, R2.x; #normalize r1, r1 = (eye - vertex).normed \n\
00082 DP4 o[FOGC].x, c[2], R4; #setup fog \n\
00083 ";
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00114 const char *WaterVpBump2LayersCode = "MUL R3, v[0], c[10]; #compute bump 0 uv's \n\
00115 ADD o[TEX0].xy, R3, c[9]; \n\
00116 MUL R3, v[0], c[12]; #compute bump 1 uv's \n\
00117 ADD o[TEX1].xy, R3, c[11]; \n\
00118 DP3 R2.x, R1, R0; \n\
00119 MUL R0, R0, R2.x; \n\
00120 ADD R2, R0, R0; \n\
00121 ADD R0, R2, -R1; #compute reflection vector \n\
00122 MAD o[TEX2].xy, R0, c[8], c[8]; \n\
00123 ";
00124
00127 const char *WaterVpBump1LayersCode = "MUL R3, v[0], c[12]; #compute bump 1 uv's \n\
00128 ADD o[TEX0].xy, R3, c[11]; \n\
00129 DP3 R2.x, R1, R0; \n\
00130 MUL R0, R0, R2.x; \n\
00131 ADD R2, R0, R0; \n\
00132 ADD R0, R2, -R1; #compute reflection vector \n\
00133 MAD o[TEX1].xy, R0, c[8], c[8]; \n\
00134 ";
00135
00138 const char *WaterVpDiffuseMapStage3Code = "DP4 o[TEX3].x, R4, c[13]; #compute uv for diffuse texture \n\
00139 DP4 o[TEX3].y, R4, c[14]; \n\
00140 ";
00141
00144 const char *WaterVpDiffuseMapStage2Code = "DP4 o[TEX2].x, R4, c[13]; #compute uv for diffuse texture \n\
00145 DP4 o[TEX2].y, R4, c[14]; \n\
00146 ";
00147
00150 const char *WaterVpDiffuseMapStage1Code = "DP4 o[TEX1].x, R4, c[13]; #compute uv for diffuse texture \n\
00151 DP4 o[TEX1].y, R4, c[14]; \n\
00152 ";
00153
00154
00155
00156
00157 const char *WaterVpNoBumpCode = " DP3 R2.x, R1, R0; #project view vector on normal for symetry \n\
00158 MUL R0, R0, R2.x; \n\
00159 ADD R2, R0, R0; \n\
00160 ADD R0, R2, -R1; #compute reflection vector \n\
00161 MAD o[TEX0].xy, R0, c[8], c[8]; \n\
00162 DP4 o[FOGC].x, c[2], -R4; #setup fog \n\
00163 ";
00164
00165
00166
00167
00168 uint32 CWaterShape::_XScreenGridSize = 40;
00169 uint32 CWaterShape::_YScreenGridSize = 40;
00170 uint32 CWaterShape::_XGridBorder = 4;
00171 uint32 CWaterShape::_YGridBorder = 4;
00172 uint32 CWaterShape::_MaxGridSize;
00173 CVertexBuffer CWaterShape::_VB;
00174 std::vector<uint32> CWaterShape::_IBUpDown;
00175 std::vector<uint32> CWaterShape::_IBDownUp;
00176
00177 bool CWaterShape::_GridSizeTouched = true;
00178 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramBump1;
00179 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramBump2;
00180 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramBump1Diffuse;
00181 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramBump2Diffuse;
00182 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramNoBump;
00183 std::auto_ptr<CVertexProgram> CWaterShape::_VertexProgramNoBumpDiffuse;
00184
00185
00188 static CVertexProgram *BuildWaterVP(bool diffuseMap, bool bumpMap, bool use2BumpMap)
00189 {
00190 std::string vp = WaterVPStartCode;
00191 if (bumpMap && use2BumpMap)
00192 {
00193 vp += WaterVpBump2LayersCode;
00194 if (diffuseMap) vp += WaterVpDiffuseMapStage3Code;
00195 }
00196 else
00197 if (bumpMap)
00198 {
00199 vp += WaterVpBump2LayersCode;
00200 if (diffuseMap) vp += WaterVpDiffuseMapStage2Code;
00201 }
00202 else
00203 {
00204 vp += WaterVpNoBumpCode;
00205 if (diffuseMap) vp += WaterVpDiffuseMapStage1Code;
00206 }
00207
00208 vp += "\nEND";
00209 return new CVertexProgram(vp.c_str());
00210 }
00211
00212
00213
00214
00215
00216
00217
00218 CWaterShape::CWaterShape() : _WaterPoolID(0), _TransitionRatio(0.6f), _WaveHeightFactor(3), _ComputeLightmap(false)
00219 {
00220 _DefaultPos.setValue(NLMISC::CVector::Null);
00221 _DefaultScale.setValue(NLMISC::CVector(1, 1, 1));
00222 _DefaultRotQuat.setValue(CQuat::Identity);
00223
00224 for (sint k = 0; k < 2; ++k)
00225 {
00226 _HeightMapScale[k].set(1, 1);
00227 _HeightMapSpeed[k].set(0, 0);
00228 _HeightMapTouch[k] = true;
00229 }
00230 _ColorMapMatColumn0.set(1, 0);
00231 _ColorMapMatColumn1.set(0, 1);
00232 _ColorMapMatPos.set(0, 0);
00233 }
00234
00235
00236
00237 CWaterShape::~CWaterShape()
00238 {
00239 if (
00240 (_EnvMap[0] && dynamic_cast<CTextureBlend *>((ITexture *) _EnvMap[0]))
00241 || (_EnvMap[1] && dynamic_cast<CTextureBlend *>((ITexture *) _EnvMap[1]))
00242 )
00243 {
00244 GetWaterPoolManager().unRegisterWaterShape(this);
00245 }
00246 }
00247
00248
00249
00250 void CWaterShape::initVertexProgram()
00251 {
00252 static bool created = false;
00253 if (!created)
00254 {
00255
00256 _VertexProgramBump1 = std::auto_ptr<CVertexProgram>(BuildWaterVP(false, true, false));
00257 _VertexProgramBump2 = std::auto_ptr<CVertexProgram>(BuildWaterVP(false, true, true));
00258
00259 _VertexProgramBump1Diffuse = std::auto_ptr<CVertexProgram>(BuildWaterVP(true, true, false));
00260 _VertexProgramBump2Diffuse = std::auto_ptr<CVertexProgram>(BuildWaterVP(true, true, true));
00261
00262 _VertexProgramNoBump = std::auto_ptr<CVertexProgram>(BuildWaterVP(false, false, false));
00263 _VertexProgramNoBumpDiffuse = std::auto_ptr<CVertexProgram>(BuildWaterVP(true, false, false));
00264 created = true;
00265 }
00266 }
00267
00268
00269
00270
00271 void CWaterShape::setupVertexBuffer()
00272 {
00273 const uint rotLength = (uint) ::ceilf(::sqrtf((float) ((_XScreenGridSize >> 1) * (_XScreenGridSize >> 1)
00274 + (_YScreenGridSize >> 1) * (_YScreenGridSize >> 1))));
00275 _MaxGridSize = 2 * rotLength;
00276 const uint w = _MaxGridSize + 2 * _XGridBorder;
00277
00278 _VB.clearValueEx();
00279 _VB.addValueEx (WATER_VB_POS, CVertexBuffer::Float3);
00280 _VB.addValueEx (WATER_VB_DX, CVertexBuffer::Float2);
00281
00282 _VB.initEx();
00283 _VB.setNumVertices((w + 1) * 2);
00284
00285
00286
00287 uint x;
00288
00289
00290
00291
00292
00293 _IBUpDown.resize(6 * w);
00294 for (x = 0; x < w; ++x)
00295 {
00296 _IBUpDown [ 6 * x ] = x;
00297 _IBUpDown [ 6 * x + 1 ] = x + 1 + (w + 1);
00298 _IBUpDown [ 6 * x + 2 ] = x + 1;
00299
00300 _IBUpDown [ 6 * x + 3 ] = x;
00301 _IBUpDown [ 6 * x + 4 ] = x + 1 + (w + 1);
00302 _IBUpDown [ 6 * x + 5 ] = x + (w + 1);
00303
00304 }
00305
00306 _IBDownUp.resize(6 * w);
00307 for (x = 0; x < w; ++x)
00308 {
00309 _IBDownUp [ 6 * x ] = x;
00310 _IBDownUp [ 6 * x + 1 ] = x + 1;
00311 _IBDownUp [ 6 * x + 2 ] = x + 1 + (w + 1);
00312
00313 _IBDownUp [ 6 * x + 3 ] = x;
00314 _IBDownUp [ 6 * x + 4 ] = x + (w + 1);
00315 _IBDownUp [ 6 * x + 5 ] = x + 1 + (w + 1);
00316
00317 }
00318
00319 _GridSizeTouched = false;
00320 }
00321
00322
00323
00324 CTransformShape *CWaterShape::createInstance(CScene &scene)
00325 {
00326 CWaterModel *wm = NLMISC::safe_cast<CWaterModel *>(scene.createModel(WaterModelClassId) );
00327 wm->Shape = this;
00328
00329 wm->ITransformable::setPos( ((CAnimatedValueVector&)_DefaultPos.getValue()).Value );
00330 wm->ITransformable::setScale( ((CAnimatedValueVector&)_DefaultScale.getValue()).Value );
00331 wm->ITransformable::setRotQuat( ((CAnimatedValueQuat&)_DefaultRotQuat.getValue()).Value );
00332 wm->_Scene = &scene;
00333 return wm;
00334 }
00335
00336
00337
00338 float CWaterShape::getNumTriangles (float distance)
00339 {
00340
00341 return 0;
00342 }
00343
00344
00345
00346 void CWaterShape::flushTextures (IDriver &driver)
00347 {
00348
00349 if (
00350 (driver.supportTextureShaders() && driver.isTextureAddrModeSupported(CMaterial::OffsetTexture))
00351 || driver.supportEMBM()
00352 )
00353 {
00354 for (uint k = 0; k < 2; ++k)
00355 {
00356 if (_BumpMap[k] != NULL)
00357 driver.setupTexture(*_BumpMap[k]);
00358 if (_EnvMap[k] != NULL)
00359 driver.setupTexture(*_EnvMap[k]);
00360 }
00361 }
00362 if (_ColorMap != NULL)
00363 driver.setupTexture(*_ColorMap);
00364 }
00365
00366
00367
00368 void CWaterShape::setScreenGridSize(uint32 x, uint32 y)
00369 {
00370 nlassert(x > 0 && y > 0);
00371 _XScreenGridSize = x;
00372 _YScreenGridSize = y;
00373 _GridSizeTouched = true;
00374 }
00375
00376
00377
00378 void CWaterShape::setGridBorderSize(uint32 x, uint32 y)
00379 {
00380 _XGridBorder = x;
00381 _YGridBorder = y;
00382 _GridSizeTouched = true;
00383 }
00384
00385
00386
00387 void CWaterShape::setShape(const NLMISC::CPolygon2D &poly)
00388 {
00389 nlassert(poly.Vertices.size() != 0);
00390 _Poly = poly;
00391 computeBBox();
00392 }
00393
00394
00395
00396 void CWaterShape::computeBBox()
00397 {
00398 nlassert(_Poly.Vertices.size() != 0);
00399 NLMISC::CVector2f min, max;
00400 min = max = _Poly.Vertices[0];
00401 for (uint k = 1; k < _Poly.Vertices.size(); ++k)
00402 {
00403 min.minof(min, _Poly.Vertices[k]);
00404 max.maxof(max, _Poly.Vertices[k]);
00405 }
00406 _BBox.setMinMax(CVector(min.x, min.y, 0), CVector(max.x, max.y, 0));
00407
00408
00409 }
00410
00411
00412
00413 void CWaterShape::setHeightMap(uint k, ITexture *hm)
00414 {
00415 nlassert(k < 2);
00416 if (!_BumpMap[k])
00417 {
00418 _BumpMap[k] = new CTextureBump;
00419 }
00420 static_cast<CTextureBump *>( (ITexture *) _BumpMap[k])->forceNormalize(true);
00421 static_cast<CTextureBump *>( (ITexture *) _BumpMap[k])->setHeightMap(hm);
00422 _HeightMapTouch[k] = true;
00423 }
00424
00425
00426
00427 ITexture *CWaterShape::getHeightMap(uint k)
00428 {
00429 nlassert(k < 2);
00430 return ((CTextureBump *) (ITexture *) _BumpMap[k] )->getHeightMap();
00431 }
00432
00433
00434
00435 const ITexture *CWaterShape::getHeightMap(uint k) const
00436 {
00437 nlassert(k < 2);
00438 return ((CTextureBump *) (ITexture *) _BumpMap[k] )->getHeightMap();
00439 }
00440
00441
00442
00443 void CWaterShape::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00444 {
00445 sint ver = f.serialVersion(2);
00446
00447 f.serial(_Poly);
00448
00449 f.serial(_WaterPoolID);
00450
00451 ITexture *map = NULL;
00452 if (f.isReading())
00453 {
00454 f.serialPolyPtr(map); _EnvMap[0] = map;
00455 f.serialPolyPtr(map); _EnvMap[1] = map;
00456 f.serialPolyPtr(map); _BumpMap[0] = map;
00457 f.serialPolyPtr(map); _BumpMap[1] = map;
00458 f.serialPolyPtr(map); _ColorMap = map;
00459 computeBBox();
00460 }
00461 else
00462 {
00463 map = _EnvMap[0]; f.serialPolyPtr(map);
00464 map = _EnvMap[1]; f.serialPolyPtr(map);
00465 map = _BumpMap[0]; f.serialPolyPtr(map);
00466 map = _BumpMap[1]; f.serialPolyPtr(map);
00467 map = _ColorMap; f.serialPolyPtr(map);
00468 }
00469
00470 f.serial(_HeightMapScale[0], _HeightMapScale[1],
00471 _HeightMapSpeed[0], _HeightMapSpeed[1]);
00472
00473 f.serial(_ColorMapMatColumn0, _ColorMapMatColumn1, _ColorMapMatPos);
00474
00475
00476 f.serial(_DefaultPos);
00477 f.serial(_DefaultScale);
00478 f.serial(_DefaultRotQuat);
00479
00480 f.serial(_TransitionRatio);
00481
00482 f.serial(_WaveHeightFactor);
00483
00484 if (ver >= 1)
00485 f.serial (_ComputeLightmap);
00486
00487 if (ver >= 2)
00488 f.serial (_DistMax);
00489 }
00490
00491
00492
00493 bool CWaterShape::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
00494 {
00495 for (uint k = 0; k < pyramid.size(); ++k)
00496 {
00497 if (! _BBox.clipBack(pyramid[k] * worldMatrix)) return false;
00498 }
00499 return true;
00500 }
00501
00502
00503
00504 void CWaterShape::setHeightMapScale(uint k, const NLMISC::CVector2f &scale)
00505 {
00506 nlassert(k < 2);
00507 _HeightMapScale[k] = scale;
00508 }
00509
00510
00511
00512 NLMISC::CVector2f CWaterShape::getHeightMapScale(uint k) const
00513 {
00514 nlassert(k < 2);
00515 return _HeightMapScale[k];
00516 }
00517
00518
00519
00520 void CWaterShape::setHeightMapSpeed(uint k, const NLMISC::CVector2f &speed)
00521 {
00522 nlassert(k < 2);
00523 _HeightMapSpeed[k] = speed;
00524 }
00525
00526
00527
00528 NLMISC::CVector2f CWaterShape::getHeightMapSpeed(uint k) const
00529 {
00530 nlassert(k < 2);
00531 return _HeightMapSpeed[k];
00532 }
00533
00534
00535
00536 void CWaterShape::setColorMapMat(const NLMISC::CVector2f &column0, const NLMISC::CVector2f &column1, const NLMISC::CVector2f &pos)
00537 {
00538 _ColorMapMatColumn0 = column0;
00539 _ColorMapMatColumn1 = column1;
00540 _ColorMapMatPos = pos;
00541 }
00542
00543
00544
00545 void CWaterShape::getColorMapMat(NLMISC::CVector2f &column0, NLMISC::CVector2f &column1, NLMISC::CVector2f &pos)
00546 {
00547 column0 = _ColorMapMatColumn0;
00548 column1 = _ColorMapMatColumn1;
00549 pos = _ColorMapMatPos;
00550 }
00551
00552
00553
00554 void CWaterShape::envMapUpdate()
00555 {
00556
00557
00558 if (
00559 (_EnvMap[0] && dynamic_cast<CTextureBlend *>((ITexture *) _EnvMap[0]))
00560 || (_EnvMap[1] && dynamic_cast<CTextureBlend *>((ITexture *) _EnvMap[1]))
00561 )
00562 {
00563 if (!GetWaterPoolManager().isWaterShapeObserver(this))
00564 {
00565 GetWaterPoolManager().registerWaterShape(this);
00566 }
00567 }
00568 else
00569 {
00570 if (GetWaterPoolManager().isWaterShapeObserver(this))
00571 {
00572 GetWaterPoolManager().unRegisterWaterShape(this);
00573 }
00574 }
00575 }
00576
00577
00578
00579 void CWaterShape::setColorMap(ITexture *map)
00580 {
00581 _ColorMap = map;
00582
00583 }
00584
00585
00586
00587 void CWaterShape::setEnvMap(uint index, ITexture *envMap)
00588 {
00589 nlassert(index < 2);
00590 _EnvMap[index] = envMap;
00591 }
00592
00593
00594
00595 void CWaterShape::getShapeInWorldSpace(NLMISC::CPolygon &poly) const
00596 {
00597 poly.Vertices.resize(_Poly.Vertices.size());
00598
00599 NLMISC::CMatrix objMat;
00600 objMat.identity();
00601 objMat.translate(((CAnimatedValueVector *) &_DefaultPos.getValue())->Value);
00602 objMat.rotate(((CAnimatedValueQuat *) &_DefaultRotQuat.getValue())->Value);
00603 objMat.scale(((CAnimatedValueVector *) &_DefaultScale.getValue())->Value);
00604
00605 for (uint k = 0; k < _Poly.Vertices.size(); ++k)
00606 {
00607 poly.Vertices[k] = objMat * NLMISC::CVector(_Poly.Vertices[k].x, _Poly.Vertices[k].y, 0);
00608 }
00609 }
00610
00611
00612
00613 void CWaterShape::updateHeightMapNormalizationFactors()
00614 {
00615 for (uint k = 0; k < 2; ++k)
00616 {
00617 if (_HeightMapTouch[k])
00618 {
00619 if (_BumpMap[k] != NULL)
00620 {
00621 _BumpMap[k]->generate();
00622 _HeightMapNormalizationFactor[k] = NLMISC::safe_cast<CTextureBump *>((ITexture *)_BumpMap[k])->getNormalizationFactor();
00623 if (_BumpMap[k]->getReleasable())
00624 {
00625 _BumpMap[k]->release();
00626 }
00627 }
00628 else
00629 {
00630 _HeightMapNormalizationFactor[k] = 1.f;
00631 }
00632 _HeightMapTouch[k] = false;
00633 }
00634 }
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646 CWaveMakerShape::CWaveMakerShape() : _Period(1),
00647 _Radius(3),
00648 _PoolID(0),
00649 _Intensity(1),
00650 _ImpulsionMode(true)
00651 {
00652 }
00653
00654
00655
00656 CWaveMakerShape::~CWaveMakerShape()
00657 {
00658 }
00659
00660
00661
00662 void CWaveMakerShape::serial(NLMISC::IStream &f) throw(NLMISC::EStream)
00663 {
00664 f.serialVersion(0);
00665 f.serial(_Period, _Radius, _Intensity, _PoolID, _ImpulsionMode);
00666 }
00667
00668
00669
00670 CTransformShape *CWaveMakerShape::createInstance(CScene &scene)
00671 {
00672 CWaveMakerModel *wmm = NLMISC::safe_cast<CWaveMakerModel *>(scene.createModel(WaveMakerModelClassId) );
00673 wmm->Shape = this;
00674
00675 wmm->ITransformable::setPos( ((CAnimatedValueVector&)_DefaultPos.getValue()).Value );
00676 wmm->_Scene = &scene;
00677 return wmm;
00678 }
00679
00680
00681
00682 bool CWaveMakerShape::clip(const std::vector<CPlane> &pyramid, const CMatrix &worldMatrix)
00683 {
00684
00685 const CWaterHeightMap &whm = GetWaterPoolManager().getPoolByID(_PoolID);
00686 const float maxDist = 0.5f * whm.getUnitSize() * whm.getSize();
00687 const NLMISC::CVector pos = worldMatrix.getPos();
00688 for (std::vector<NLMISC::CPlane>::const_iterator it = pyramid.begin(); it != pyramid.end(); ++it)
00689 {
00690 if ((*it) * pos > maxDist) return false;
00691 }
00692 return true;
00693
00694 }
00695
00696
00697 void CWaveMakerShape::getAABBox(NLMISC::CAABBox &bbox) const
00698 {
00699
00700 bbox.setCenter(NLMISC::CVector::Null);
00701 bbox.setHalfSize(NLMISC::CVector::Null);
00702 }
00703
00704 }