1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2014-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
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/>.
26 #include "nel/3d/u_instance_group.h"
27 #include "nel/misc/path.h"
28 #include "nel/misc/progress_callback.h"
31 #include "streamable_ig.h"
32 #include "continent_manager.h"
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
);
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
)
71 removeLoadedIGFromMap();
72 for(uint k
= 0; k
< _IGs
.size(); ++k
)
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
);
93 //=================================================================================
94 /*virtual*/ void CStreamableIG::loadAsync()
96 H_AUTO_USE(RZ_StremableIG
)
101 nlwarning("Loading async %p", this);
104 //nlinfo("Loading async : %s", Name.c_str());
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
);
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
;
146 //=================================================================================
147 /*virtual*/ void CStreamableIG::load(NLMISC::IProgressCallback
&progress
)
149 H_AUTO_USE(RZ_StremableIG
)
152 nlwarning("Load %p", this);
154 //nlinfo("Loading : %s", Name.c_str());
156 std::vector
<bool> waitForIg
;
157 waitForIg
.resize(_IGs
.size());
158 for(uint k
= 0; k
< _IGs
.size(); ++k
)
161 //nlinfo("Loading ig %s", _IGs[k].Name.c_str());
163 progress
.progress((float)k
/((float)_IGs
.size()*2.f
));
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");
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 */
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
));
201 //nlinfo("wait for end of blockin load");
206 // wait till loaded...
207 _Scene
->updateWaitingInstances(1000); /* set a high value to upload texture at a fast rate */
209 _IGs
[k
].Loading
= false;
217 //=================================================================================
218 /*virtual*/ void CStreamableIG::unload()
220 H_AUTO_USE(RZ_StremableIG
)
222 // nlinfo("Unloading : %s", Name.c_str());
226 nlwarning("Unloading %p", this);
228 removeLoadedIGFromMap();
229 for(uint k
= 0; k
< _IGs
.size(); ++k
)
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
244 _Scene
->stopCreatingAndAddingIG(&_IGs
[k
].IG
);
246 _IGs
[k
].Loading
= false;
251 if (_IGs
[k
].IG
&& _IGs
[k
].IG
!= (NL3D::UInstanceGroup
*)-1) // -1 signal that async loading failed
253 //nlinfo("unload 2");
255 _IGs
[k
].IG
->removeFromScene(*_Scene
);
256 _Scene
->deleteInstanceGroup (_IGs
[k
].IG
);
257 this->notifyIGRemoved(_IGs
[k
].IG
);
265 //=================================================================================
266 void CStreamableIG::forceUnload()
268 H_AUTO_USE(RZ_StremableIG
)
273 //===================================================================================
274 bool CStreamableIG::setIG(uint ig
, const std::string
&name
, const std::string
&parentName
)
276 H_AUTO_USE(RZ_StremableIG
)
280 if (_IGs
[ig
].Loading
)
284 _Scene
->stopCreatingAndAddingIG(&_IGs
[ig
].IG
);
285 this->notifyIGRemoved(_IGs
[ig
].IG
);
286 _IGs
[ig
].Loading
= false;
292 if (_IGs
[ig
].IG
&& _IGs
[ig
].IG
!= (NL3D::UInstanceGroup
*)-1) // -1 signal that async loading failed
295 _IGs
[ig
].IG
->removeFromScene(*_Scene
);
296 _Scene
->deleteInstanceGroup (_IGs
[ig
].IG
);
297 this->notifyIGRemoved(_IGs
[ig
].IG
);
303 _IGs
[ig
].Name
= NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(name
));
304 _IGs
[ig
].ParentName
= NLMISC::toLowerAscii(NLMISC::CFile::getFilenameWithoutExtension(parentName
));
306 _IGs
[ig
].Loading
= 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
)
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)
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());
358 //=================================================================================
359 void CStreamableIG::reserve(uint size
)
361 H_AUTO_USE(RZ_StremableIG
)
365 //=================================================================================
366 void CStreamableIG::setLoadedIGMap(CStreamableIG::TString2IG
*igMap
)
368 H_AUTO_USE(RZ_StremableIG
)
369 removeLoadedIGFromMap();
374 //=================================================================================
375 void CStreamableIG::addLoadedIGToMap()
377 H_AUTO_USE(RZ_StremableIG
)
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
)
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())
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
);