1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 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/>.
21 #include "main_loop_utilities.h"
23 #include <nel/3d/u_driver.h>
24 #include <nel/3d/u_cloud_scape.h>
25 #include <nel/3d/fxaa.h>
26 #include <nel/3d/stereo_display.h>
28 #include "game_share/scenario_entry_points.h"
30 #include "client_cfg.h"
33 #include "world_database_manager.h"
34 #include "continent_manager.h"
35 #include "user_entity.h"
37 #include "ig_client.h"
40 #include "sound_manager.h"
42 #include "interface_v3/interface_manager.h"
44 using namespace NLMISC
;
47 void updateVRDevicesComboUI(); // from action_handler_game.cpp
48 void initStereoDisplayDevice(); // from init.cpp
49 void releaseStereoDisplayDevice(); // from release.cpp
51 //---------------------------------------------------
52 // Compare ClientCfg and LastClientCfg to know what we must update
53 //---------------------------------------------------
54 void updateFromClientCfg()
56 CClientConfig::setValues();
57 ClientCfg
.IsInvalidated
= false;
59 if ((ClientCfg
.VREnable
!= LastClientCfg
.VREnable
)
60 || (ClientCfg
.VREnable
&& (
61 ClientCfg
.VRDisplayDevice
!= LastClientCfg
.VRDisplayDevice
62 || ClientCfg
.VRDisplayDeviceId
!= LastClientCfg
.VRDisplayDeviceId
65 nldebug("Apply VR device change");
66 // detach display mode
67 if (StereoDisplay
&& StereoDisplayAttached
)
68 StereoDisplay
->detachFromDisplay();
69 StereoDisplayAttached
= false;
71 releaseStereoDisplayDevice();
72 initStereoDisplayDevice();
73 // try attach display mode
75 StereoDisplayAttached
= StereoDisplay
->attachToDisplay();
76 // set latest config display mode if not attached
77 if (!StereoDisplayAttached
)
78 setVideoMode(UDriver::CMode(ClientCfg
.Width
, ClientCfg
.Height
, (uint8
)ClientCfg
.Depth
,
79 ClientCfg
.Windowed
, ClientCfg
.Frequency
, -1, ClientCfg
.MonitorName
));
80 // force software cursor when attached
81 InitMouseWithCursor(ClientCfg
.HardwareCursor
&& !StereoDisplayAttached
);
85 //---------------------------------------------------
86 if ((ClientCfg
.Windowed
!= LastClientCfg
.Windowed
) ||
87 (ClientCfg
.Width
!= LastClientCfg
.Width
) ||
88 (ClientCfg
.Height
!= LastClientCfg
.Height
) ||
89 (ClientCfg
.Depth
!= LastClientCfg
.Depth
) ||
90 (ClientCfg
.Frequency
!= LastClientCfg
.Frequency
)||
91 (ClientCfg
.MonitorName
!= LastClientCfg
.MonitorName
))
93 if (!StereoDisplayAttached
)
95 setVideoMode(UDriver::CMode(ClientCfg
.Width
, ClientCfg
.Height
, (uint8
)ClientCfg
.Depth
,
96 ClientCfg
.Windowed
, ClientCfg
.Frequency
, -1, ClientCfg
.MonitorName
));
100 if (ClientCfg
.DivideTextureSizeBy2
!= LastClientCfg
.DivideTextureSizeBy2
)
102 if (ClientCfg
.DivideTextureSizeBy2
)
103 Driver
->forceTextureResize(2);
105 Driver
->forceTextureResize(1);
108 if (ClientCfg
.InterfaceScale
!= LastClientCfg
.InterfaceScale
|| ClientCfg
.InterfaceScaleAuto
!= LastClientCfg
.InterfaceScaleAuto
)
109 CInterfaceManager::getInstance()->setInterfaceScale(ClientCfg
.InterfaceScale
, ClientCfg
.InterfaceScaleAuto
);
111 if (ClientCfg
.BilinearUI
!= LastClientCfg
.BilinearUI
)
112 CViewRenderer::getInstance()->setBilinearFiltering(ClientCfg
.BilinearUI
);
114 CWidgetManager::getInstance()->setWindowSnapInvert(ClientCfg
.WindowSnapInvert
);
115 CWidgetManager::getInstance()->setWindowSnapDistance(ClientCfg
.WindowSnapDistance
);
117 //---------------------------------------------------
118 if (ClientCfg
.WaitVBL
!= LastClientCfg
.WaitVBL
)
120 if(ClientCfg
.WaitVBL
)
121 Driver
->setSwapVBLInterval(1);
123 Driver
->setSwapVBLInterval(0);
126 // GRAPHICS - LANDSCAPE
127 //---------------------------------------------------
128 if (ClientCfg
.LandscapeThreshold
!= LastClientCfg
.LandscapeThreshold
)
130 if (Landscape
) Landscape
->setThreshold(ClientCfg
.getActualLandscapeThreshold());
133 //---------------------------------------------------
134 if (ClientCfg
.LandscapeTileNear
!= LastClientCfg
.LandscapeTileNear
)
136 if (Landscape
) Landscape
->setTileNear(ClientCfg
.LandscapeTileNear
);
139 //---------------------------------------------------
142 if (ClientCfg
.Vision
!= LastClientCfg
.Vision
)
144 if (!ClientCfg
.Light
)
146 // Not in an indoor ?
147 if (ContinentMngr
.cur() && !ContinentMngr
.cur()->Indoor
)
149 // Refresh All Zone in streaming according to the refine position
150 std::vector
<string
> zonesAdded
;
151 std::vector
<string
> zonesRemoved
;
152 const R2::CScenarioEntryPoints::CCompleteIsland
*ci
= R2::CScenarioEntryPoints::getInstance().getCompleteIslandFromCoords(CVector2f((float) UserEntity
->pos().x
, (float) UserEntity
->pos().y
));
153 Landscape
->refreshAllZonesAround(View
.refinePos(), ClientCfg
.Vision
+ ExtraZoneLoadingVision
, zonesAdded
, zonesRemoved
, ProgressBar
, ci
? &(ci
->ZoneIDs
) : NULL
);
154 LandscapeIGManager
.unloadArrayZoneIG(zonesRemoved
);
155 LandscapeIGManager
.loadArrayZoneIG(zonesAdded
);
161 //---------------------------------------------------
162 if (ClientCfg
.Vision
!= LastClientCfg
.Vision
|| ClientCfg
.FoV
!=LastClientCfg
.FoV
||
163 ClientCfg
.Windowed
!= LastClientCfg
.Windowed
|| ClientCfg
.ScreenAspectRatio
!= LastClientCfg
.ScreenAspectRatio
)
165 updateCameraPerspective();
168 //---------------------------------------------------
171 if (ClientCfg
.MicroVeget
!= LastClientCfg
.MicroVeget
)
173 if(ClientCfg
.MicroVeget
)
175 // if configured, enable the vegetable and load the texture.
176 Landscape
->enableVegetable(true);
177 // Default setup. TODO later by gameDev.
178 Landscape
->setVegetableWind(CVector(0.5, 0.5, 0).normed(), 0.5, 1, 0);
179 // Default setup. should work well for night/day transition in 30 minutes.
180 // Because all vegetables will be updated every 20 seconds => 90 steps.
181 Landscape
->setVegetableUpdateLightingFrequency(1/20.f
);
182 // Density (percentage to ratio)
183 Landscape
->setVegetableDensity(ClientCfg
.MicroVegetDensity
/100.f
);
187 Landscape
->enableVegetable(false);
192 //---------------------------------------------------
193 if (ClientCfg
.MicroVegetDensity
!= LastClientCfg
.MicroVegetDensity
)
195 // Density (percentage to ratio)
196 if (Landscape
) Landscape
->setVegetableDensity(ClientCfg
.MicroVegetDensity
/100.f
);
199 // GRAPHICS - SPECIAL EFFECTS
200 //---------------------------------------------------
201 if (ClientCfg
.FxNbMaxPoly
!= LastClientCfg
.FxNbMaxPoly
)
203 if (Scene
->getGroupLoadMaxPolygon("Fx") != ClientCfg
.FxNbMaxPoly
)
204 Scene
->setGroupLoadMaxPolygon("Fx", ClientCfg
.FxNbMaxPoly
);
207 //---------------------------------------------------
208 if (ClientCfg
.Cloud
!= LastClientCfg
.Cloud
)
212 InitCloudScape
= true;
213 CloudScape
= Scene
->createCloudScape();
217 if (CloudScape
!= NULL
)
218 Scene
->deleteCloudScape(CloudScape
);
223 //---------------------------------------------------
224 if (ClientCfg
.CloudQuality
!= LastClientCfg
.CloudQuality
)
226 if (CloudScape
!= NULL
)
227 CloudScape
->setQuality(ClientCfg
.CloudQuality
);
230 //---------------------------------------------------
231 if (ClientCfg
.CloudUpdate
!= LastClientCfg
.CloudUpdate
)
233 if (CloudScape
!= NULL
)
234 CloudScape
->setNbCloudToUpdateIn80ms(ClientCfg
.CloudUpdate
);
237 //---------------------------------------------------
238 if (ClientCfg
.Shadows
!= LastClientCfg
.Shadows
)
240 // Enable/Disable Receive on Landscape
243 Landscape
->enableReceiveShadowMap(ClientCfg
.Shadows
);
245 // Enable/Disable Cast for all entities
246 for(uint i
=0;i
<EntitiesMngr
.entities().size();i
++)
248 CEntityCL
*ent
= EntitiesMngr
.entities()[i
];
250 ent
->updateCastShadowMap();
254 //---------------------------------------------------
255 if (ClientCfg
.AnisotropicFilter
!= LastClientCfg
.AnisotropicFilter
)
257 Driver
->setAnisotropicFilter(ClientCfg
.AnisotropicFilter
);
260 //---------------------------------------------------
261 if (ClientCfg
.FXAA
!= LastClientCfg
.FXAA
)
266 FXAA
= new NL3D::CFXAA(Driver
);
276 // GRAPHICS - CHARACTERS
277 //---------------------------------------------------
278 if (ClientCfg
.SkinNbMaxPoly
!= LastClientCfg
.SkinNbMaxPoly
)
280 if (Scene
->getGroupLoadMaxPolygon("Skin") != ClientCfg
.SkinNbMaxPoly
)
281 Scene
->setGroupLoadMaxPolygon("Skin", ClientCfg
.SkinNbMaxPoly
);
284 //---------------------------------------------------
285 if (ClientCfg
.NbMaxSkeletonNotCLod
!= LastClientCfg
.NbMaxSkeletonNotCLod
)
287 Scene
->setMaxSkeletonsInNotCLodForm(ClientCfg
.NbMaxSkeletonNotCLod
);
290 //---------------------------------------------------
291 if (ClientCfg
.CharacterFarClip
!= LastClientCfg
.CharacterFarClip
)
296 //---------------------------------------------------
297 if (ClientCfg
.HDEntityTexture
!= LastClientCfg
.HDEntityTexture
)
299 // Don't reload Texture, will be done at next Game Start
306 //---------------------------------------------------
307 if (ClientCfg
.CursorSpeed
!= LastClientCfg
.CursorSpeed
)
308 SetMouseSpeed (ClientCfg
.CursorSpeed
);
310 if (ClientCfg
.CursorAcceleration
!= LastClientCfg
.CursorAcceleration
)
311 SetMouseAcceleration (ClientCfg
.CursorAcceleration
);
313 if (ClientCfg
.HardwareCursor
!= LastClientCfg
.HardwareCursor
)
315 if (ClientCfg
.HardwareCursor
!= IsMouseCursorHardware())
317 InitMouseWithCursor (ClientCfg
.HardwareCursor
&& !StereoDisplayAttached
);
323 //---------------------------------------------------
324 bool mustReloadSoundMngrContinent
= false;
326 // disable/enable sound?
327 if (ClientCfg
.SoundOn
!= LastClientCfg
.SoundOn
)
329 if (SoundMngr
&& !ClientCfg
.SoundOn
)
331 nlwarning("Deleting sound manager...");
335 else if (SoundMngr
== NULL
&& ClientCfg
.SoundOn
)
337 nlwarning("Creating sound manager...");
338 SoundMngr
= new CSoundManager();
341 SoundMngr
->init(NULL
);
343 catch(const Exception
&e
)
345 nlwarning("init : Error when creating 'SoundMngr' : %s", e
.what());
350 // re-init with good SFX/Music Volume
353 SoundMngr
->setSFXVolume(ClientCfg
.SoundSFXVolume
);
354 SoundMngr
->setGameMusicVolume(ClientCfg
.SoundGameMusicVolume
);
359 nlwarning("Sound config error !");
362 mustReloadSoundMngrContinent
= true;
366 if ( SoundMngr
&& LastClientCfg
.SoundOn
&&
367 (ClientCfg
.UseEax
!= LastClientCfg
.UseEax
) )
371 mustReloadSoundMngrContinent
= true;
374 // change SoundForceSoftwareBuffer?
375 if ( SoundMngr
&& LastClientCfg
.SoundOn
&&
376 (ClientCfg
.SoundForceSoftwareBuffer
!= LastClientCfg
.SoundForceSoftwareBuffer
) )
380 mustReloadSoundMngrContinent
= true;
383 // change MaxTrack? don't reset
384 if ( SoundMngr
&& LastClientCfg
.SoundOn
&&
385 (ClientCfg
.MaxTrack
!= LastClientCfg
.MaxTrack
))
387 SoundMngr
->getMixer()->changeMaxTrack(ClientCfg
.MaxTrack
);
390 // change SoundFX Volume? don't reset
391 if (SoundMngr
&& ClientCfg
.SoundSFXVolume
!= LastClientCfg
.SoundSFXVolume
)
393 SoundMngr
->setSFXVolume(ClientCfg
.SoundSFXVolume
);
396 // change Game Music Volume? don't reset
397 if (SoundMngr
&& ClientCfg
.SoundGameMusicVolume
!= LastClientCfg
.SoundGameMusicVolume
)
399 SoundMngr
->setGameMusicVolume(ClientCfg
.SoundGameMusicVolume
);
402 // reload only if active and reseted
403 if (mustReloadSoundMngrContinent
&& SoundMngr
&& ContinentMngr
.cur() && !ContinentMngr
.cur()->Indoor
&& UserEntity
)
405 SoundMngr
->loadContinent(ContinentMngr
.getCurrentContinentSelectName(), UserEntity
->pos());
408 // Ok backup the new clientcfg
409 LastClientCfg
= ClientCfg
;