Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / streamable_ig.cpp
blob3e633cb73f3d3b68140db5818285fc6726f138c2
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "stdpch.h"
26 #include "nel/3d/u_instance_group.h"
27 #include "nel/misc/path.h"
28 #include "nel/misc/progress_callback.h"
30 #include "ig_enum.h"
31 #include "streamable_ig.h"
32 #include "continent_manager.h"
34 #ifdef DEBUG_NEW
35 #define new DEBUG_NEW
36 #endif
38 extern CContinentManager ContinentMngr;
40 H_AUTO_DECL(RZ_StremableIG)
42 //=================================================================================
43 CStreamableIG::CStreamableIG() : _Scene(NULL), _Linked(false), _IGMap(NULL)
45 H_AUTO_USE(RZ_StremableIG)
48 //=================================================================================
49 void CStreamableIG::init(NL3D::UScene *owningScene, const NLMISC::CVector &pos,float forceLoadRadius,float loadRadius,float unloadRadius)
51 H_AUTO_USE(RZ_StremableIG)
52 nlassert(_Scene == NULL); // init should be called once
53 nlassert(owningScene);
54 _Scene = owningScene;
55 if (!(unloadRadius >= loadRadius && loadRadius >= forceLoadRadius && forceLoadRadius >= 0))
57 nlwarning("CStreamableIG::init : invalid radius have been used !");
59 CStreamableEntity::setForceLoadRadius(forceLoadRadius);
60 CStreamableEntity::setLoadRadius(loadRadius);
61 CStreamableEntity::setUnloadRadius(unloadRadius);
62 CStreamableEntity::setPos(pos);
65 //=================================================================================
66 CStreamableIG::~CStreamableIG()
68 H_AUTO_USE(RZ_StremableIG)
69 if (_Scene)
71 removeLoadedIGFromMap();
72 for(uint k = 0; k < _IGs.size(); ++k)
74 if (_IGs[k].Loading)
76 _Scene->stopCreatingAndAddingIG(&_IGs[k].IG);
78 else if(_IGs[k].IG && _IGs[k].IG != (NL3D::UInstanceGroup *)-1)
80 notifyIGRemoved(_IGs[k].IG);
83 if (_IGs[k].IG && _IGs[k].IG != (NL3D::UInstanceGroup *)-1)
85 _IGs[k].IG->removeFromScene(*_Scene);
86 _Scene->deleteInstanceGroup(_IGs[k].IG);
87 _IGs[k].IG= NULL;
93 //=================================================================================
94 /*virtual*/ void CStreamableIG::loadAsync()
96 H_AUTO_USE(RZ_StremableIG)
97 if (!_Linked)
99 #ifdef NL_DEBUG
100 if(!ClientCfg.Light)
101 nlwarning("Loading async %p", this);
102 #endif
103 #ifdef NL_DEBUG
104 //nlinfo("Loading async : %s", Name.c_str());
105 #endif
106 bool canLinkNow = true;
107 for(uint k = 0; k < _IGs.size(); ++k)
109 if (!_IGs[k].Loading && !_IGs[k].IG)
111 // Current continent season
112 EGSPD::CSeason::TSeason season = ContinentMngr.cur()->Season;
114 //nlinfo("started load async");
115 _IGs[k].Loading = true;
116 _Callback.Owner = this;
117 _Scene->createInstanceGroupAndAddToSceneAsync(_IGs[k].Name + ".ig", &_IGs[k].IG, _IGs[k].Pos, _IGs[k].Rot, season, &_Callback);
119 else
121 if (_IGs[k].Loading && _IGs[k].IG)
123 //nlinfo("loading finiched");
124 // loading has finished
125 _IGs[k].Loading = false;
127 if (_IGs[k].IG != (NL3D::UInstanceGroup *)-1 && _IGMap)
129 (*_IGMap)[_IGs[k].Name] = _IGs[k].IG;
130 this->notifyIGAdded(_IGs[k].IG);
135 // Load is not finished
136 canLinkNow &= !_IGs[k].Loading;
139 if (canLinkNow)
141 linkInstances();
146 //=================================================================================
147 /*virtual*/ void CStreamableIG::load(NLMISC::IProgressCallback &progress)
149 H_AUTO_USE(RZ_StremableIG)
150 if (!_Linked)
152 nlwarning("Load %p", this);
153 #ifdef NL_DEBUG
154 //nlinfo("Loading : %s", Name.c_str());
155 #endif
156 std::vector<bool> waitForIg;
157 waitForIg.resize(_IGs.size());
158 for(uint k = 0; k < _IGs.size(); ++k)
160 #ifdef NL_DEBUG
161 //nlinfo("Loading ig %s", _IGs[k].Name.c_str());
162 #endif
163 progress.progress((float)k/((float)_IGs.size()*2.f));
165 if (!_IGs[k].IG)
167 //nlinfo("blocking load");
168 if (!_IGs[k].Loading)
170 // Current continent season
171 EGSPD::CSeason::TSeason season = ContinentMngr.cur()->Season;
173 //nlinfo("start blocking load");
174 // blocking load
175 // block after queueing all
176 _Callback.Owner = this;
177 _Scene->createInstanceGroupAndAddToSceneAsync(_IGs[k].Name + ".ig", &_IGs[k].IG, _IGs[k].Pos, _IGs[k].Rot, season, &_Callback);
178 _IGs[k].Loading = true;
181 _Scene->updateWaitingInstances(1000); /* set a high value to upload texture at a fast rate */
183 waitForIg[k] = true;
185 else
187 if (_IGs[k].Loading && _IGs[k].IG)
189 _IGs[k].Loading = false;
192 waitForIg[k] = false;
195 for(uint k = 0; k < _IGs.size(); ++k)
197 progress.progress(((float)k + (float)_IGs.size())/((float)_IGs.size()*2.f));
199 if (waitForIg[k])
201 //nlinfo("wait for end of blockin load");
202 // blocking call
203 while (!_IGs[k].IG)
205 NLMISC::nlSleep(1);
206 // wait till loaded...
207 _Scene->updateWaitingInstances(1000); /* set a high value to upload texture at a fast rate */
209 _IGs[k].Loading = false;
212 linkInstances();
213 addLoadedIGToMap();
217 //=================================================================================
218 /*virtual*/ void CStreamableIG::unload()
220 H_AUTO_USE(RZ_StremableIG)
221 #ifdef NL_DEBUG
222 // nlinfo("Unloading : %s", Name.c_str());
223 #endif
224 if (_Linked)
226 nlwarning("Unloading %p", this);
228 removeLoadedIGFromMap();
229 for(uint k = 0; k < _IGs.size(); ++k)
231 if (_IGs[k].Loading)
233 if (_IGs[k].IG)
235 if (_IGs[k].IG != (NL3D::UInstanceGroup *)-1)
237 // the ig has just finished loading, and loading hasn't failed
238 _IGs[k].IG->removeFromScene(*_Scene);
239 // notifyIGAdded has not been called yet, so no need to call notifyIGRemoved
242 else
244 _Scene->stopCreatingAndAddingIG(&_IGs[k].IG);
246 _IGs[k].Loading = false;
247 _IGs[k].IG = NULL;
249 else
251 if (_IGs[k].IG && _IGs[k].IG != (NL3D::UInstanceGroup *)-1) // -1 signal that async loading failed
253 //nlinfo("unload 2");
254 nlassert(_Scene);
255 _IGs[k].IG->removeFromScene(*_Scene);
256 _Scene->deleteInstanceGroup (_IGs[k].IG);
257 this->notifyIGRemoved(_IGs[k].IG);
259 _IGs[k].IG = NULL;
262 _Linked = false;
265 //=================================================================================
266 void CStreamableIG::forceUnload()
268 H_AUTO_USE(RZ_StremableIG)
269 unload();
273 //===================================================================================
274 bool CStreamableIG::setIG(uint ig, const std::string &name, const std::string &parentName)
276 H_AUTO_USE(RZ_StremableIG)
277 if (ig<_IGs.size())
279 // Destroy this IG
280 if (_IGs[ig].Loading)
282 if (!_IGs[ig].IG)
284 _Scene->stopCreatingAndAddingIG(&_IGs[ig].IG);
285 this->notifyIGRemoved(_IGs[ig].IG);
286 _IGs[ig].Loading = false;
287 _IGs[ig].IG = NULL;
290 else
292 if (_IGs[ig].IG && _IGs[ig].IG != (NL3D::UInstanceGroup *)-1) // -1 signal that async loading failed
294 nlassert(_Scene);
295 _IGs[ig].IG->removeFromScene(*_Scene);
296 _Scene->deleteInstanceGroup (_IGs[ig].IG);
297 this->notifyIGRemoved(_IGs[ig].IG);
299 _IGs[ig].IG = NULL;
302 // Load this IG
303 _IGs[ig].Name = NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(name));
304 _IGs[ig].ParentName = NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(parentName));
305 _IGs[ig].IG = NULL;
306 _IGs[ig].Loading = false;
307 _Linked = false;
308 return true;
310 return false;
313 //=================================================================================
314 void CStreamableIG::addIG(const std::string &name,const std::string &parentName, const NLMISC::CVector &pos, const NLMISC::CQuat &rot)
316 H_AUTO_USE(RZ_StremableIG)
317 _IGs.push_back(CIGNode ());
318 _IGs.back().Name = NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(name));
319 _IGs.back().ParentName = NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(parentName));
320 _IGs.back().IG = NULL;
321 _IGs.back().Loading = false;
322 _IGs.back().Pos = pos;
323 _IGs.back().Rot = rot;
326 //=================================================================================
327 void CStreamableIG::linkInstances()
329 H_AUTO_USE(RZ_StremableIG)
330 if (_Linked)
331 return;
332 for(uint k = 0; k < _IGs.size(); ++k)
334 /** There are few igs at the same time, so a linear search should suffice for now
336 if (_IGs[k].IG != (NL3D::UInstanceGroup *)-1)
338 // search the parent
339 if (!_IGs[k].ParentName.empty())
341 for(uint l = 0; l < _IGs.size(); ++l)
343 if (l == k) continue; // can't be a parent of itself
344 if (_IGs[l].IG != (NL3D::UInstanceGroup *)-1 && _IGs[k].ParentName == _IGs[l].Name)
346 if (!_IGs[k].IG->linkToParentCluster(_IGs[l].IG))
348 nlwarning("Failed to link cluster %s to its parent %s", _IGs[k].Name.c_str(), _IGs[k].ParentName.c_str());
355 _Linked = true;
358 //=================================================================================
359 void CStreamableIG::reserve(uint size)
361 H_AUTO_USE(RZ_StremableIG)
362 _IGs.reserve(size);
365 //=================================================================================
366 void CStreamableIG::setLoadedIGMap(CStreamableIG::TString2IG *igMap)
368 H_AUTO_USE(RZ_StremableIG)
369 removeLoadedIGFromMap();
370 _IGMap = igMap;
371 addLoadedIGToMap();
374 //=================================================================================
375 void CStreamableIG::addLoadedIGToMap()
377 H_AUTO_USE(RZ_StremableIG)
378 if (!_IGMap) return;
379 for(uint k = 0; k < _IGs.size(); ++k)
381 if (_IGs[k].IG && _IGs[k].IG != (NL3D::UInstanceGroup *)-1) // is this a successfully loaded ig ?
383 // insert the new ig if it hasn't before..
384 if( _IGMap->insert(std::make_pair(NLMISC::toLowerAscii(_IGs[k].Name), _IGs[k].IG)).second )
385 // if inserted, must notify IG Added, else already notifiyed by loadAsync()
386 this->notifyIGAdded(_IGs[k].IG);
391 //=================================================================================
392 void CStreamableIG::removeLoadedIGFromMap()
394 H_AUTO_USE(RZ_StremableIG)
395 if (!_IGMap) return;
396 for(uint k = 0; k < _IGs.size(); ++k)
398 if (_IGs[k].IG && _IGs[k].IG != (NL3D::UInstanceGroup *)-1) // is this a successfully loaded ig ?
400 TString2IG::iterator it = _IGMap->find(_IGs[k].Name);
401 if (it != _IGMap->end())
403 _IGMap->erase(it);
410 //=================================================================================
411 bool CStreamableIG::enumIGs(IIGEnum *callback)
413 H_AUTO_USE(RZ_StremableIG)
414 bool continueEnum = true;
415 for(TIGArray::iterator it = _IGs.begin(); it != _IGs.end() && continueEnum; ++it)
417 if (it->IG && it->IG != (NL3D::UInstanceGroup *)-1)
418 continueEnum = callback->enumIG(it->IG);
420 return continueEnum;