Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / precipitation.cpp
blob40e9ec7c65e2bdc12a0c7492f77e2408a9d80120
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
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.
8 //
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/>.
19 #include "stdpch.h"
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);
48 release();
49 _Strenght = 0;
50 _Desc = desc;
51 if (!_Desc.ReleasableModel)
53 allocateFXs(); // keep fxs allocated;
54 forceSetStrenght(0); // no precipitation is the default
56 _ClipGrid = NULL;
57 _Touched = true;
60 //============================================================
61 void CPrecipitation::allocateFXs()
63 H_AUTO_USE(RZ_Precipitation)
64 if (!Scene) return;
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());
74 release();
75 return;
77 _Blocks[k].forceInstanciate();
79 if (_Desc.UseBBoxSize)
81 NLMISC::CAABBox bbox;
82 getBlock(0, 0).getShapeAABBox(bbox);
83 _XSize = 2.f * bbox.getHalfSize().x;
84 _YSize = 2.f * bbox.getHalfSize().y;
86 else
88 _XSize = _YSize = _Desc.Size;
91 // get the associated precipitation clipGrid if it hasn't yet
93 if (!_ClipGrid)
95 NLMISC::CVector2f gridSize(_XSize, _YSize);
96 TClipGridMap::iterator it = _PrecipitationClipGripMap.find(gridSize);
97 if (it != _PrecipitationClipGripMap.end())
99 _ClipGrid = &it->second;
101 else
103 _ClipGrid = &(_PrecipitationClipGripMap[gridSize]);
104 _ClipGrid->initGrid(_Desc.GridSize, _XSize, _YSize);
110 //============================================================
111 void CPrecipitation::deallocateFXs()
113 H_AUTO_USE(RZ_Precipitation)
114 if (Scene)
116 for(uint k = 0; k < _Blocks.size(); ++k)
118 Scene->deleteInstance(_Blocks[k]);
120 NLMISC::contReset(_Blocks);
122 _TimeOut = 0.f;
123 _Touched = true;
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)
141 if (strenght > 0)
143 if (!areFXsAllocated())
145 allocateFXs();
149 NLMISC::clamp(strenght, 0, 1);
150 if (_Desc.GridSize == 0) return;
151 if (!areFXsAllocated()) return;
152 if (strenght <= 0.f)
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);
164 else
166 _TimeOut = 0.f;
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)
184 deallocateFXs();
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;
197 return false;
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)
212 if (_TimeOut != 0.f)
214 nlassert(_Strenght == 0.f);
215 _TimeOut -= DT;
216 if (_TimeOut <= 0.f)
218 _TimeOut = 0.f;
219 deallocateFXs();
220 return;
223 if (_Desc.ReleasableModel)
225 if (_Strenght == 0.f && areFXsAllocated()) // no more precipitations & FXs are still allocated ? This means that there are particles left
227 if (!isRunning())
229 deallocateFXs();
230 return;
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)
246 _Touched = false;
247 _OldX = worldX;
248 _OldY = worldY;
251 if (_ClipGrid)
253 _ClipGrid->updateGrid(userPos, retriever);
258 // snap the user pos
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());
272 /*if (!_ClipGrid)
274 getBlock(l, k).setPos(hPos);
275 hPos.x += _XSize;
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();
292 else
294 NL3D::UParticleSystemInstance psi = getBlock(l, k);
295 psi.show();
296 // take the mean height
297 hPos.z = 0.25f * (p0->MeanHeight + p1->MeanHeight + p2->MeanHeight + p3->MeanHeight);
298 psi.setPos(hPos);
301 else
303 getBlock(l, k).setPos(hPos);
305 hPos.x += _XSize;
309 snappedPos.y += _YSize;
314 //============================================================
315 void CPrecipitation::drawClipGrid(NL3D::UDriver &drv) const
317 if (!_ClipGrid) return;
318 _ClipGrid->display(drv);