Resolve "Toggle Free Look with Hotkey"
[ryzomcore.git] / ryzom / client / src / sky.cpp
blobbca0a0d3ed80817d1401afea27acdb62bbb7bfba
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/>.
20 #include "stdpch.h"
22 #include "sky.h"
23 #include "client_sheets/sky_sheet.h"
25 #ifdef DEBUG_NEW
26 #define new DEBUG_NEW
27 #endif
29 using namespace NL3D;
30 using namespace NLMISC;
33 /////////////
34 // GLOBALS //
35 /////////////
37 // Hierarchical timer
38 H_AUTO_DECL ( RZ_Client_Render_Sky )
41 // *************************************************************************************************
42 CSky::CSky()
44 _Scene = NULL;
45 _Driver = NULL;
46 _IG = NULL;
47 _AnimationSet = NULL;
48 _NumHourInDay = 24;
49 _PlayListManager = NULL;
50 _PlayList = NULL;
51 _AnimationSet = NULL;
52 _AnimLengthInSeconds = 3.f;
53 _AmbientSunLight = NULL;
54 _DiffuseSunLight = NULL;
55 _FogColor = NULL;
56 _WaterEnvMapCameraHeight = 0.f;
57 _WaterEnvMapAlpha = 255;
60 // *************************************************************************************************
61 CSky::~CSky()
63 release();
66 // *************************************************************************************************
67 void CSky::release()
69 if (_PlayListManager)
71 if (_PlayList)
73 _PlayListManager->deletePlayList(_PlayList);
74 _PlayList = NULL;
76 if (_AnimationSet && _Driver)
78 _Driver->deleteAnimationSet(_AnimationSet);
79 _AnimationSet = NULL;
81 if (_Scene)
83 _Scene->deletePlayListManager(_PlayListManager);
85 _PlayListManager = NULL;
87 for(uint k = 0; k < _Bitmaps.size(); ++k)
89 delete _Bitmaps[k];
91 _Bitmaps.clear();
92 if (_Scene)
94 if (_IG) _IG->removeFromScene(*_Scene);
95 _Objects.clear();
96 _Driver->deleteScene(_Scene);
97 _Scene = NULL;
98 _Driver = NULL;
102 // *************************************************************************************************
103 void CSky::init(UDriver *drv, const CSkySheet &sheet, bool forceFallbackVersion /*= false*/, float numHourInDay /*= 24.f*/, std::vector<std::string> *unsupportedObjects /*= NULL*/)
105 release();
106 if(!drv) return;
107 _Driver = drv;
108 // create a new scene for the sky
109 _Scene = _Driver->createScene(true);
110 _Scene->setupTransparencySorting(99, 1); // only sort by priority (99 of them)
111 _AnimLengthInSeconds = sheet.AnimLengthInSeconds;
112 // create animation set
113 if (!sheet.AnimationName.empty())
115 _PlayListManager = _Scene->createPlayListManager();
116 if (_PlayListManager)
118 _AnimationSet = _Driver->createAnimationSet();
119 _PlayList = _PlayListManager->createPlayList(_AnimationSet);
120 if (_AnimationSet && _PlayList)
122 uint animationID = _AnimationSet->addAnimation(sheet.AnimationName.c_str(), sheet.AnimationName.c_str());
123 if (animationID != UAnimationSet::NotFound)
125 _AnimationSet->build();
126 _PlayList->setAnimation(0, animationID);
127 _PlayList->setTimeOrigin(0, 0);
128 _PlayList->setWrapMode(0, UPlayList::Repeat);
130 else
132 // no animation loaded
133 _PlayListManager->deletePlayList(_PlayList);
134 _Scene->deletePlayListManager(_PlayListManager);
135 _Driver->deleteAnimationSet(_AnimationSet);
136 _PlayListManager = NULL;
137 _PlayList = NULL;
138 _AnimationSet = NULL;
143 // load instance group of sky
144 _IG = UInstanceGroup::createInstanceGroup(sheet.InstanceGroupName);
145 if (!_IG)
147 nlwarning("Couldn't load sky ig : %s", sheet.InstanceGroupName.c_str());
148 release();
149 return;
151 _IG->addToScene(*_Scene, drv);
152 _Objects.reserve(sheet.Objects.size());
153 // dump name of objects in the scene
154 //nlinfo("Sky scene objects : ");
155 for(uint k = 0; k < _IG->getNumInstance(); ++k)
157 //nlinfo(_IG->getInstanceName(k).c_str());
158 UInstance i = _IG->getInstance(k); // hide all instances by default
159 if (!i.empty()) i.hide();
161 if (unsupportedObjects) unsupportedObjects->clear();
162 // map name of a bitmap to the actual bitmap (for reuse of bitmaps)
163 std::map<std::string, CBitmap *> buildShareBitmapByName;
165 for(uint k = 0; k < sheet.Objects.size(); ++k)
167 UInstance instance;
168 instance = _IG->getByName(sheet.Objects[k].Std.ShapeName);
169 // should main instance if driver supports its rendering
170 // hide all the instance at start
171 if (!instance.empty() && !instance.supportMaterialRendering(*drv, forceFallbackVersion))
173 if (unsupportedObjects)
175 unsupportedObjects->push_back(sheet.Objects[k].Std.ShapeName);
177 instance.hide();
178 // build fallbacks
179 for(uint l = 0; l < 2; ++l)
181 UInstance fallbackInstance = _IG->getByName(sheet.Objects[k].FallbackPass[l].ShapeName);
182 if (!fallbackInstance.empty())
184 fallbackInstance.hide();
185 CSkyObject so;
186 so.init(sheet.Objects[k].FallbackPass[l], fallbackInstance, buildShareBitmapByName, _Bitmaps, sheet.Objects[k].VisibleInMainScene, sheet.Objects[k].VisibleInEnvMap);
187 _Objects.push_back(so);
188 if (_PlayList)
190 _PlayList->registerTransform(fallbackInstance, (sheet.Objects[k].FallbackPass[l].ShapeName + ".").c_str());
195 else if (!instance.empty())
197 instance.hide();
198 // uses main instance and hides fallback instances
199 CSkyObject so;
200 so.init(sheet.Objects[k].Std, instance, buildShareBitmapByName, _Bitmaps, sheet.Objects[k].VisibleInMainScene, sheet.Objects[k].VisibleInEnvMap);
201 _Objects.push_back(so);
202 for(uint l = 0; l < 2; ++l)
204 UInstance fallbackInstance = _IG->getByName(sheet.Objects[k].FallbackPass[l].ShapeName);
205 if (!fallbackInstance.empty()) fallbackInstance.hide();
207 if (_PlayList)
209 _PlayList->registerTransform(instance, (sheet.Objects[k].Std.ShapeName + ".").c_str());
212 else
214 nlwarning("Object not found in scene : %s", sheet.Objects[k].Std.ShapeName.c_str());
217 // get gradient that gives sun light color
218 bool alreadyBuilt;
219 _AmbientSunLight = buildSharedBitmap(sheet.AmbientSunLightBitmap, buildShareBitmapByName, _Bitmaps, alreadyBuilt);
220 _DiffuseSunLight = buildSharedBitmap(sheet.DiffuseSunLightBitmap, buildShareBitmapByName, _Bitmaps, alreadyBuilt);
222 _FogColor = buildSharedBitmap(sheet.FogColorBitmap, buildShareBitmapByName, _Bitmaps, alreadyBuilt);
224 _NumHourInDay = numHourInDay;
225 _WaterEnvMapCameraHeight = sheet.WaterEnvMapCameraHeight;
226 _WaterEnvMapAlpha= sheet.WaterEnvMapAlpha;
229 // *************************************************************************************************
230 uint CSky::setup(const CClientDate &date, const CClientDate &animationDate, float weatherLevel, CRGBA fogColor, const NLMISC::CVector &sunLightDir, bool envMapScene)
232 if (!_Scene) return 0;
233 uint numVisibleObjects = 0;
234 uint numObjects = (uint)_Objects.size();
235 float dayPart = date.Hour / _NumHourInDay;
236 clamp(dayPart, 0.f, 1.f);
237 clamp(weatherLevel, 0.f, 1.f);
238 for(uint k = 0; k < numObjects; ++k)
240 if (_Objects[k].setup(date, animationDate, _NumHourInDay, weatherLevel, fogColor, envMapScene)) ++ numVisibleObjects;
242 // animate objects
243 if (_PlayListManager)
245 double globalDate = (double)date.Hour / (double)_NumHourInDay;
246 //nlinfo("global date = %f", (float) globalDate);
247 _PlayListManager->animate(_AnimLengthInSeconds * globalDate);
249 // compute sunlight for the scene
250 if (_AmbientSunLight)
252 _Scene->setSunAmbient(_AmbientSunLight->getColor(dayPart, weatherLevel, true, false));
254 else
256 _Scene->setSunAmbient(CRGBA::White);
258 if (_DiffuseSunLight)
260 _Scene->setSunDiffuse(_DiffuseSunLight->getColor(dayPart, weatherLevel, true, false));
262 else
264 _Scene->setSunDiffuse(CRGBA::White);
266 _Scene->setSunSpecular(CRGBA::Black); // specular not useful for sky
267 _Scene->setSunDirection(sunLightDir);
268 return numVisibleObjects;
271 // *************************************************************************************************
272 NLMISC::CRGBA CSky::computeFogColor(const CClientDate &date, float weatherLevel) const
274 if (!_FogColor) return CRGBA::White;
275 float dayPart = date.Hour / _NumHourInDay;
276 clamp(dayPart, 0.f, 1.f);
277 clamp(weatherLevel, 0.f, 1.f);
278 return _FogColor->getColor(dayPart, weatherLevel, true, false);
282 // *************************************************************************************************
283 CBitmap *buildSharedBitmap(const std::string &filename,
284 std::map<std::string, CBitmap *> &bitmapByName,
285 std::vector<CBitmap *> &builtBitmaps,
286 bool &alreadyBuilt
289 alreadyBuilt = false;
290 if (filename.empty()) return NULL;
291 std::string lcBMFilename = toLowerAscii(CFile::getFilenameWithoutExtension(filename));
292 std::map<std::string, CBitmap *>::iterator it = bitmapByName.find(lcBMFilename);
293 if (it != bitmapByName.end())
295 alreadyBuilt = true;
296 // bitmap already loaded so reuse it
297 return it->second;
299 else
301 // load the bitmap
302 std::string path = CPath::lookup(filename, false);
303 if (path.empty()) return NULL;
304 CUniquePtr<CBitmap> bm(new CBitmap);
307 CIFile f;
308 f.open(path);
309 if (bm->load(f, 0) == 0) return NULL;
310 builtBitmaps.push_back(bm.release());
311 bitmapByName[lcBMFilename] = builtBitmaps.back();
312 // dump bitmap fisrt line
313 return builtBitmaps.back();
315 catch(const EStream &)
317 return NULL;