1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2018 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2014-2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "nel/3d/u_instance.h"
31 #include "nel/3d/u_scene.h"
32 #include "nel/3d/u_water.h"
33 #include "nel/3d/u_landscape.h"
36 #include "light_cycle_manager.h"
37 #include "client_cfg.h"
38 #include "ig_client.h"
39 #include "user_entity.h"
40 #include "pacs_client.h"
41 #include "world_database_manager.h"
42 #include "continent_manager.h"
43 #include "continent.h"
45 #include "ig_callback.h"
46 #include "pacs_client.h"
47 #include "sound_manager.h"
48 #include "weather_manager_client.h"
50 #include "interface_v3/interface_manager.h"
52 //#include "sound_manager.h" // \todo GUIGUI : uncomment after new FE done and class modified
55 H_AUTO_DECL(RZ_LightCycleManager
)
60 using namespace NLMISC
;
62 using namespace NLPACS
;
69 extern UDriver
*Driver
;
71 extern UScene
*SceneRoot
;
73 extern EGSPD::CSeason::TSeason CurrSeason
;
79 extern ULandscape
*Landscape
;
81 static uint
diffColors(CRGBA c1
, CRGBA c2
)
83 return (uint
) maxof(abs((sint
) c1
.R
- c2
.R
), abs((sint
) c1
.G
- c2
.G
), abs((sint
) c1
.B
- c2
.B
));
86 //-----------------------------------------------
87 float CLightCycleDesc::getNightTransitionLength() const
89 H_AUTO_USE(RZ_LightCycleManager
)
90 return NightTransitionEndHour
>= NightTransitionStartHour
? NightTransitionEndHour
- NightTransitionStartHour
91 : NightTransitionEndHour
+ NumHours
- NightTransitionStartHour
;
94 //-----------------------------------------------
95 float CLightCycleDesc::getDawnTransitionLength() const
97 H_AUTO_USE(RZ_LightCycleManager
)
98 return DawnTransitionEndHour
>= DawnTransitionStartHour
? DawnTransitionEndHour
- DawnTransitionStartHour
99 : DawnTransitionEndHour
+ NumHours
- DawnTransitionStartHour
;
102 //-----------------------------------------------
103 CLightCycleManager::CLightCycleManager() :
109 _LastWeatherLighting(0),
111 _State(StateUnknown
),
112 _PrevState(StateUnknown
)
114 H_AUTO_USE(RZ_LightCycleManager
)
118 //-----------------------------------------------
119 void CLightCycleManager::getLandscapeLightColor(NLMISC::CRGBA
&diffuse
, NLMISC::CRGBA
&ambiant
)
121 H_AUTO_USE(RZ_LightCycleManager
)
122 nlassert(_LightLevel
>= 0 && _LightLevel
<= 1.f
);
124 if(ContinentMngr
.cur())
129 if (_LightLevel
<= _Desc
.DuskRatio
)
132 uint level
= (uint
) (256.f
* (_Desc
.DuskRatio
!= 0.f
? _LightLevel
/ _Desc
.DuskRatio
: 0.f
));
133 diffuse
.blendFromui(ContinentMngr
.cur()->LandscapeLightDay
.Diffuse
, ContinentMngr
.cur()->LandscapeLightDusk
.Diffuse
, level
);
134 ambiant
.blendFromui(ContinentMngr
.cur()->LandscapeLightDay
.Ambiant
, ContinentMngr
.cur()->LandscapeLightDusk
.Ambiant
, level
);
139 uint level
= (uint
) (256.f
* (_Desc
.DuskRatio
!= 1.f
? (_LightLevel
- _Desc
.DuskRatio
) / (1.f
- _Desc
.DuskRatio
) : 0.f
));
140 diffuse
.blendFromui(ContinentMngr
.cur()->LandscapeLightDusk
.Diffuse
, ContinentMngr
.cur()->LandscapeLightNight
.Diffuse
, level
);
141 ambiant
.blendFromui(ContinentMngr
.cur()->LandscapeLightDusk
.Ambiant
, ContinentMngr
.cur()->LandscapeLightNight
.Ambiant
, level
);
145 uint level
= (uint
) (256.f
* _LightLevel
);
146 diffuse
.blendFromui(ContinentMngr
.cur()->LandscapeLightDay
.Diffuse
, ContinentMngr
.cur()->LandscapeLightNight
.Diffuse
, level
);
147 ambiant
.blendFromui(ContinentMngr
.cur()->LandscapeLightDay
.Ambiant
, ContinentMngr
.cur()->LandscapeLightNight
.Ambiant
, level
);
154 //-----------------------------------------------
155 bool CLightCycleManager::setLightDesc(const CLightCycleDesc
&desc
)
157 H_AUTO_USE(RZ_LightCycleManager
)
158 if (desc
.NightTransitionStartHour
> desc
.NumHours
)
160 nlwarning ("NightTransitionStartHour (%d) > NumHours (%d)", desc
.NightTransitionStartHour
, desc
.NumHours
);
161 _State
= StateUnknown
;
165 if (desc
.NightTransitionEndHour
> desc
.NumHours
)
167 nlwarning ("NightTransitionEndHour (%d) > NumHours (%d)", desc
.NightTransitionEndHour
, desc
.NumHours
);
168 _State
= StateUnknown
;
172 if (desc
.DawnTransitionStartHour
> desc
.NumHours
)
174 nlwarning ("DawnTransitionStartHour (%d) > NumHours (%d)", desc
.DawnTransitionStartHour
, desc
.NumHours
);
175 _State
= StateUnknown
;
178 if (desc
.DawnTransitionEndHour
> desc
.NumHours
)
180 nlwarning ("DawnTransitionEndHour (%d) > NumHours (%d)", desc
.DawnTransitionEndHour
, desc
.NumHours
);
181 _State
= StateUnknown
;
185 // test if intervals are not overlapping
186 if (!(desc
.DawnTransitionStartHour
>= desc
.NightTransitionEndHour
187 || desc
.DawnTransitionEndHour
<= desc
.NightTransitionStartHour
191 nlwarning("!(DawnTransitionStartHour (%d) >= NightTransitionEndHour (%d) || DawnTransitionEndHour (%d) <= NightTransitionStartHour (%d))",
192 desc
.DawnTransitionStartHour
, desc
.NightTransitionEndHour
, desc
.DawnTransitionEndHour
, desc
.NightTransitionStartHour
);
193 _State
= StateUnknown
;
206 //-----------------------------------------------
207 float CLightCycleManager::getUpdateDuration() const
209 H_AUTO_USE(RZ_LightCycleManager
)
210 if (!_ValidDesc
|| _UpdateFreq
== 0.f
) return 0.f
;
211 return (1.f
/ _UpdateFreq
) / _Desc
.RealDayLength
* _Desc
.NumHours
;
215 //-----------------------------------------------
216 std::string
CLightCycleManager::getStateString() const
218 H_AUTO_USE(RZ_LightCycleManager
)
221 case NightToDay
: return "night->day";
222 case DayToNight
: return "day->night";
223 case Day
: return "day";
224 case Night
: return "night";
231 //-----------------------------------------------
232 void CLightCycleManager::updateState()
234 H_AUTO_USE(RZ_LightCycleManager
)
236 if(isInInterval(_Desc
.DawnTransitionStartHour
, _Desc
.DawnTransitionEndHour
, _Hour
))
242 else if(isInInterval(_Desc
.DawnTransitionEndHour
, _Desc
.NightTransitionStartHour
, _Hour
))
248 else if(isInInterval(_Desc
.NightTransitionStartHour
, _Desc
.NightTransitionEndHour
, _Hour
))
254 else if(isInInterval(_Desc
.NightTransitionEndHour
, _Desc
.DawnTransitionStartHour
, _Hour
))
257 if( _PrevState
!= Night
&& _PrevState
!= StateUnknown
)
259 CInterfaceManager
* pIM
= CInterfaceManager::getInstance();
262 CAHManager::getInstance()->runActionHandler("set",NULL
,"dblink=UI:VARIABLES:NIGHT_WARNING_WANTED|value=1");
268 _State
= StateUnknown
;
273 //-----------------------------------------------
274 bool CLightCycleManager::isInTransition() const
276 H_AUTO_USE(RZ_LightCycleManager
)
277 return isInInterval(_Desc
.DawnTransitionStartHour
, _Desc
.DawnTransitionEndHour
, _Hour
)
278 || isInInterval(_Desc
.NightTransitionStartHour
, _Desc
.DawnTransitionEndHour
, _Hour
);
281 //-----------------------------------------------
282 void CLightCycleManager::setHour(float hour
, const CWeatherManagerClient
&wm
, NLMISC::CRGBA lightningColor
)
284 H_AUTO_USE(RZ_LightCycleManager
)
285 if (!_ValidDesc
) return;
286 if (hour
< 0) hour
= 0;
287 if (hour
> _Desc
.NumHours
)
289 hour
-= ::floorf(hour
/ _Desc
.NumHours
) * _Desc
.NumHours
;
291 float updateDuration
= getUpdateDuration();
292 if (fabs(_Hour
- hour
) >= (4.f
* updateDuration
))
297 _LightLevel
= getLightLevel(hour
);
298 clamp(_LightLevel
, 0.f
, 1.f
); // should not be necessary, but we avoid imprecisions
301 _WeatherLighting
= wm
.getCurrWeatherState().Lighting
;
303 // Change water lighting
304 NL3D::UWaterHeightMapManager::setBlendFactor(Driver
, _LightLevel
);
306 if (_PrevState
!= _State
)
308 if (_State
== Night
|| _State
== Day
)
310 // a transiation has ended, so release textures used for the blend
311 NL3D::UWaterHeightMapManager::releaseBlendTextures();
315 // directionnal lights
316 // (override the global light by the light in the weather manager : during bad weather, the scene can be darker)
317 setupCanopyLight(_WeatherLighting
);
318 setupMainLight(_WeatherLighting
);
320 // landscape lighting
321 CRGBA diffuse
, ambiant
;
322 getLandscapeLightColor(diffuse
, ambiant
);
324 bool colorTouched
= diffuse
!= _LastDiffuse
|| ambiant
!= _LastAmbient
;
327 _LastDiffuse
= diffuse
;
328 _LastAmbient
= ambiant
;
333 if(ContinentMngr
.cur())
334 Landscape
->setupStaticLight(diffuse
, ambiant
, ContinentMngr
.cur()->StaticLightingFactor
[CurrSeason
]);
336 Landscape
->setupStaticLight(diffuse
, ambiant
, 1.f
);
337 _UpdateFreq
= getLandscapePatchUpdateFreq();
340 Landscape
->updateLightingAll();
341 Landscape
->setUpdateLightingFrequency(0);
345 Landscape
->setUpdateLightingFrequency(_UpdateFreq
);
352 // Set the Sun color only if not indoor
353 if (ContinentMngr
.cur() && ContinentMngr
.cur()->Indoor
)
355 Scene
->setSunAmbient(CRGBA(150, 150, 150, 255));
360 color
.add(_LastDiffuse
, lightningColor
);
361 Scene
->setLightGroupColor(LightGroupLandscapeDiffuse
, color
);
362 color
.add(_LastAmbient
, lightningColor
);
363 Scene
->setLightGroupColor(LightGroupLandscapeAmbient
, color
);
364 float nightLevel
= _LightLevel
*255.f
;
365 clamp (nightLevel
, 0, 255);
366 uint8 nightLevelColor
= (uint8
)nightLevel
;
367 color
.set (nightLevelColor
, nightLevelColor
, nightLevelColor
);
368 Scene
->setLightGroupColor (LightGroupNightCycle
, color
);
369 uint8 dayLevelColor
= 255 - nightLevel
;
370 color
.set (dayLevelColor
, dayLevelColor
, dayLevelColor
);
371 Scene
->setLightGroupColor (LightGroupDayCycle
, color
);
376 if (!isInInterval(_Desc
.DawnTransitionStartHour
, _Desc
.DawnTransitionEndHour
+ 4.f
* updateDuration
, hour
)
377 && !isInInterval(_Desc
.NightTransitionStartHour
, _Desc
.NightTransitionEndHour
+ 4.f
* updateDuration
, hour
)
380 Landscape
->setUpdateLightingFrequency(0);
387 if(isInDayInterval(_Desc.DawnTransitionStartHour, _Desc.DawnTransitionEndHour, _Desc.NumHours, hour, ratio))
390 SoundMngr->setDayNightRatio (1.0f-ratio);
392 else if(isInDayInterval(_Desc.DawnTransitionEndHour, _Desc.NightTransitionStartHour, _Desc.NumHours, hour, ratio))
395 SoundMngr->setDayNightRatio (0.0f);
397 else if(isInDayInterval(_Desc.NightTransitionStartHour, _Desc.NightTransitionEndHour, _Desc.NumHours, hour, ratio))
400 SoundMngr->setDayNightRatio (ratio);
402 else if(isInDayInterval(_Desc.NightTransitionEndHour, _Desc.DawnTransitionStartHour, _Desc.NumHours, hour, ratio))
405 SoundMngr->setDayNightRatio (1.0f);
412 //-----------------------------------------------
413 // NB : interval can be reversed
414 bool CLightCycleManager::isInInterval(float start
, float end
, float value
)
416 H_AUTO_USE(RZ_LightCycleManager
)
417 return start
<= end
? value
>= start
&& value
< end
418 : value
>= start
|| value
< end
;
422 //-----------------------------------------------
423 // NB : interval can be reversed
424 bool CLightCycleManager::isInDayInterval(float startHour
, float endHour
, float dayDuration
, float hour
, float &ratio
)
426 H_AUTO_USE(RZ_LightCycleManager
)
427 if (startHour
<= endHour
)
429 if (hour
>= startHour
&& hour
< endHour
)
431 ratio
= startHour
!= endHour
? (hour
- startHour
) / (endHour
- startHour
)
440 if (hour
>= startHour
|| hour
< endHour
)
442 ratio
= hour
>= startHour
? (hour
- startHour
) / (dayDuration
- startHour
+ endHour
)
443 : (hour
+ dayDuration
- startHour
) / (dayDuration
- startHour
+ endHour
);
451 //-----------------------------------------------
452 float CLightCycleManager::getLightLevel(float hour
) const
454 H_AUTO_USE(RZ_LightCycleManager
)
455 float lightValue
= 0.f
;
456 if (isInDayInterval(_Desc
.NightTransitionStartHour
, _Desc
.NightTransitionEndHour
, _Desc
.NumHours
, hour
, lightValue
))
458 if (isInDayInterval(_Desc
.DawnTransitionStartHour
, _Desc
.DawnTransitionEndHour
, _Desc
.NumHours
, hour
, lightValue
))
459 return 1.f
- lightValue
;
461 // No transition, it is night or day
462 if (_Desc
.DawnTransitionEndHour
<= _Desc
.NightTransitionStartHour
)
464 return hour
>= _Desc
.DawnTransitionEndHour
&& hour
< _Desc
.NightTransitionStartHour
? 0.f
: 1.f
;
468 return hour
>= _Desc
.DawnTransitionEndHour
|| hour
< _Desc
.NightTransitionStartHour
? 0.f
: 1.f
;
472 //-----------------------------------------------
473 void CLightCycleManager::create()
475 H_AUTO_USE(RZ_LightCycleManager
)
476 Driver
->enableLight(0, true);
479 //-----------------------------------------------
480 void CLightCycleManager::setDirLight(const CDirLightSetup
&setup0
, const CDirLightSetup
&setup1
, float level
, float intensity
,NL3D::UScene
&scene
)
482 H_AUTO_USE(RZ_LightCycleManager
)
483 CDirLightSetup resultSetup
;
484 resultSetup
.blend(setup0
, setup1
, level
);
485 resultSetup
.modulate(intensity
);
487 scene
.setSunAmbient (resultSetup
.Ambiant
);
488 scene
.setSunDiffuse (resultSetup
.Diffuse
);
489 scene
.setSunSpecular (resultSetup
.Specular
);
490 scene
.setSunDirection(resultSetup
.Direction
);
493 //-----------------------------------------------
494 float CLightCycleManager::getLandscapePatchUpdateFreq() const
496 H_AUTO_USE(RZ_LightCycleManager
)
500 if(ContinentMngr
.cur() == 0)
503 // transition duration in seconds
504 float dt
= std::min(_Desc
.getDawnTransitionLength(), _Desc
.getNightTransitionLength()) * _Desc
.RealDayLength
/ _Desc
.NumHours
;
505 uint numStep
= std::max(diffColors(ContinentMngr
.cur()->LandscapeLightDay
.Diffuse
, ContinentMngr
.cur()->LandscapeLightNight
.Diffuse
),
506 diffColors(ContinentMngr
.cur()->LandscapeLightDay
.Ambiant
, ContinentMngr
.cur()->LandscapeLightNight
.Ambiant
)
508 numStep
= std::min(numStep
, _Desc
.MaxNumColorSteps
);
509 return (float) numStep
/ dt
;
512 //-----------------------------------------------
513 void CLightCycleManager::touch()
515 H_AUTO_USE(RZ_LightCycleManager
)
520 //-----------------------------------------------
521 void CLightCycleManager::instanceGroupAdded(NL3D::UInstanceGroup
* /* ig */)
523 H_AUTO_USE(RZ_LightCycleManager
)
527 //-----------------------------------------------
529 // Set the light to render the root.
530 //-----------------------------------------------
531 void CLightCycleManager::setupCanopyLight(float intensity
)
533 H_AUTO_USE(RZ_LightCycleManager
)
537 if(ContinentMngr
.cur())
541 case DayToNight
: // blend form day to night with dusk transition
542 setupDayToNightLight(*SceneRoot
, ContinentMngr
.cur()->RootLightDay
, ContinentMngr
.cur()->RootLightDusk
, ContinentMngr
.cur()->RootLightNight
, intensity
);
544 default: // blend from night to day with no other transition
545 setDirLight(ContinentMngr
.cur()->RootLightDay
, ContinentMngr
.cur()->RootLightNight
, _LightLevel
, intensity
, *SceneRoot
);
549 }// setupCanopyLight //
551 //-----------------------------------------------
553 // Set the light to render the main scene
554 //-----------------------------------------------
555 void CLightCycleManager::setupMainLight(float intensity
)
557 H_AUTO_USE(RZ_LightCycleManager
)
560 if(ContinentMngr
.cur())
564 case DayToNight
: // blend form day to night with dusk transition
565 setupDayToNightLight(*Scene
, ContinentMngr
.cur()->EntityLightDay
, ContinentMngr
.cur()->EntityLightDusk
, ContinentMngr
.cur()->EntityLightNight
, intensity
);
567 default: // blend from night to day with no other transition
568 setDirLight(ContinentMngr
.cur()->EntityLightDay
, ContinentMngr
.cur()->EntityLightNight
, _LightLevel
, intensity
, *Scene
);
572 }// setupMainLight //
574 //-----------------------------------------------
575 void CLightCycleManager::setupDayToNightLight(NL3D::UScene
&scene
, const CDirLightSetup
&dayLight
, const CDirLightSetup
&duskLight
, const CDirLightSetup
&nightLight
, float lightIntensity
)
577 H_AUTO_USE(RZ_LightCycleManager
)
579 if (_LightLevel
<= _Desc
.DuskRatio
)
581 blendFactor
= _Desc
.DuskRatio
!= 0 ? _LightLevel
/ _Desc
.DuskRatio
: 0.f
;
582 setDirLight(dayLight
,
591 blendFactor
= _Desc
.DuskRatio
!= 1.f
? (_LightLevel
- _Desc
.DuskRatio
) / (1.f
- _Desc
.DuskRatio
) : 0.f
;
592 setDirLight(duskLight
,