1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "precipitation.h"
21 #include "time_client.h"
23 #include "nel/misc/matrix.h"
24 #include "nel/misc/vector.h"
25 #include "nel/3d/u_particle_system_instance.h"
27 extern NL3D::UScene
*Scene
;
30 H_AUTO_DECL(RZ_Precipitation
)
32 CPrecipitation::TClipGridMap
CPrecipitation::_PrecipitationClipGripMap
;
34 static const float DEFAUT_PRECIPITATION_TIMEOUT
= 10.f
; // at most 10 second before precipitations are removed
37 //============================================================
38 CPrecipitation::CPrecipitation() : _ClipGrid(NULL
), _Strenght(0), _TimeOut(0.f
), _XSize(0), _YSize(0), _OldX(0), _OldY(0), _Touched(false)
40 H_AUTO_USE(RZ_Precipitation
)
43 //============================================================
44 void CPrecipitation::init(const CPrecipitationDesc
&desc
)
46 H_AUTO_USE(RZ_Precipitation
)
47 nlassert(desc
.GridSize
> 0);
51 if (!_Desc
.ReleasableModel
)
53 allocateFXs(); // keep fxs allocated;
54 forceSetStrenght(0); // no precipitation is the default
60 //============================================================
61 void CPrecipitation::allocateFXs()
63 H_AUTO_USE(RZ_Precipitation
)
65 nlassert(_Blocks
.empty()); // should be called only once
66 _Blocks
.resize(_Desc
.GridSize
* _Desc
.GridSize
);
67 std::fill(_Blocks
.begin(), _Blocks
.end(), NL3D::UParticleSystemInstance ());
68 for(uint k
= 0; k
< _Desc
.GridSize
* _Desc
.GridSize
; ++k
)
70 _Blocks
[k
].cast (Scene
->createInstance(_Desc
.FxName
.c_str()));
71 if (_Blocks
[k
].empty())
73 nlwarning("can't find %s", _Desc
.FxName
.c_str());
77 _Blocks
[k
].forceInstanciate();
79 if (_Desc
.UseBBoxSize
)
82 getBlock(0, 0).getShapeAABBox(bbox
);
83 _XSize
= 2.f
* bbox
.getHalfSize().x
;
84 _YSize
= 2.f
* bbox
.getHalfSize().y
;
88 _XSize
= _YSize
= _Desc
.Size
;
91 // get the associated precipitation clipGrid if it hasn't yet
95 NLMISC::CVector2f gridSize(_XSize, _YSize);
96 TClipGridMap::iterator it = _PrecipitationClipGripMap.find(gridSize);
97 if (it != _PrecipitationClipGripMap.end())
99 _ClipGrid = &it->second;
103 _ClipGrid = &(_PrecipitationClipGripMap[gridSize]);
104 _ClipGrid->initGrid(_Desc.GridSize, _XSize, _YSize);
110 //============================================================
111 void CPrecipitation::deallocateFXs()
113 H_AUTO_USE(RZ_Precipitation
)
116 for(uint k
= 0; k
< _Blocks
.size(); ++k
)
118 Scene
->deleteInstance(_Blocks
[k
]);
120 NLMISC::contReset(_Blocks
);
127 //============================================================
128 void CPrecipitation::setStrenght(float strenght
)
130 H_AUTO_USE(RZ_Precipitation
)
131 if (strenght
== _Strenght
) return;
132 forceSetStrenght(strenght
);
135 //============================================================
136 void CPrecipitation::forceSetStrenght(float strenght
)
138 H_AUTO_USE(RZ_Precipitation
)
139 if (_Desc
.ReleasableModel
)
143 if (!areFXsAllocated())
149 NLMISC::clamp(strenght
, 0, 1);
150 if (_Desc
.GridSize
== 0) return;
151 if (!areFXsAllocated()) return;
154 if (_Strenght
!= 0.f
)
156 _TimeOut
= DEFAUT_PRECIPITATION_TIMEOUT
;
158 for(uint k
= 0; k
< _Blocks
.size(); ++k
)
160 _Blocks
[k
].activateEmitters(false);
161 _Blocks
[k
].setUserParam(0, strenght
);
167 for(uint k
= 0; k
< _Blocks
.size(); ++k
)
169 if (_Strenght
== 0.f
)
171 _Blocks
[k
].activateEmitters(true);
173 _Blocks
[k
].setUserParam(0, strenght
);
177 _Strenght
= strenght
;
180 //============================================================
181 void CPrecipitation::release()
183 H_AUTO_USE(RZ_Precipitation
)
187 //============================================================
188 bool CPrecipitation::isRunning() const
190 H_AUTO_USE(RZ_Precipitation
)
191 if (!areFXsAllocated()) return false;
192 // if the last particles have been removed, we can remove the models
193 for(uint k
= 0; k
< _Blocks
.size(); ++k
)
195 if (_Blocks
[k
].hasParticles()) return true;
200 //============================================================
201 // snap a float by the given factor
202 static inline float fsnapf(float v
, float mod
)
204 H_AUTO_USE(RZ_Precipitation
)
205 return mod
* floorf(v
/ mod
);
208 //============================================================
209 void CPrecipitation::update(const NLMISC::CMatrix
&camMat
, NLPACS::UGlobalRetriever
* /* retriever */)
211 H_AUTO_USE(RZ_Precipitation
)
214 nlassert(_Strenght
== 0.f
);
223 if (_Desc
.ReleasableModel
)
225 if (_Strenght
== 0.f
&& areFXsAllocated()) // no more precipitations & FXs are still allocated ? This means that there are particles left
234 if (!areFXsAllocated()) return;
235 NLMISC::CVector userPos
= camMat
.getPos();
237 if (_XSize
== 0 || _YSize
== 0) return;
239 // get world position of the user in grid units
240 sint worldX
= (sint
) floorf(userPos
.x
/ _XSize
);
241 sint worldY
= (sint
) floorf(userPos
.y
/ _YSize
);
243 // See if we need to update pos
244 if (_Touched
|| worldX
!= _OldX
|| worldY
!= _OldY
)
253 _ClipGrid->updateGrid(userPos, retriever);
260 NLMISC::CVector
snappedPos(fsnapf(userPos
.x
, _XSize
), fsnapf(userPos
.y
, _YSize
), userPos
.z
);
261 snappedPos
-= NLMISC::CVector((float(_Desc
.GridSize
>> 1) - 0.5f
) * _XSize
, (float(_Desc
.GridSize
>> 1) - 0.5f
) * _YSize
, 0);
262 // get world position of grid corner
263 // sint gridCornerX = worldX - (_Desc.GridSize >> 1);
264 // sint gridCornerY = worldY - (_Desc.GridSize >> 1);
265 // move / show / hide each block
266 for(uint k
= 0; k
< _Desc
.GridSize
; ++k
)
268 NLMISC::CVector hPos
= snappedPos
;
269 for(uint l
= 0; l
< _Desc
.GridSize
; ++l
)
271 nlassert(!getBlock(l
, k
).empty());
274 getBlock(l
, k
).setPos(hPos
);
278 else // use the clip grid to see if that block should be activated, and at what height it should be put
280 typedef CPrecipitationClipGrid::CGridPoint CGridPoint; // alias CGridPoint
281 const CGridPoint *p0 = _ClipGrid->get(l + gridCornerX, k + gridCornerY);
282 const CGridPoint *p1 = _ClipGrid->get(l + gridCornerX + 1, k + gridCornerY);
283 const CGridPoint *p2 = _ClipGrid->get(l + gridCornerX + 1, k + gridCornerY + 1);
284 const CGridPoint *p3 = _ClipGrid->get(l + gridCornerX, k + gridCornerY + 1);
285 if (p0 && p1 && p2 && p3)
287 // if one of the 4 corners is in an interior, don't display the precipiations
288 if (p0->Clipped || p1->Clipped || p2->Clipped || p3->Clipped)
290 getBlock(l, k).hide();
294 NL3D::UParticleSystemInstance psi = getBlock(l, k);
296 // take the mean height
297 hPos.z = 0.25f * (p0->MeanHeight + p1->MeanHeight + p2->MeanHeight + p3->MeanHeight);
303 getBlock(l, k).setPos(hPos);
309 snappedPos
.y
+= _YSize
;
314 //============================================================
315 void CPrecipitation::drawClipGrid(NL3D::UDriver
&drv
) const
317 if (!_ClipGrid
) return;
318 _ClipGrid
->display(drv
);