Linux multi-monitor fullscreen support
[ryzomcore.git] / ryzom / client / src / main_loop_utilities.cpp
blob95dcf82c8510c229659fd760c634fa985b3a1493
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2020 Winch Gate Property Limited
3 //
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 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"
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"
31 #include "misc.h"
32 #include "global.h"
33 #include "world_database_manager.h"
34 #include "continent_manager.h"
35 #include "user_entity.h"
36 #include "view.h"
37 #include "ig_client.h"
38 #include "entities.h"
39 #include "input.h"
40 #include "sound_manager.h"
41 #include "camera.h"
42 #include "interface_v3/interface_manager.h"
44 using namespace NLMISC;
45 using namespace NL3D;
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
63 )))
65 nldebug("Apply VR device change");
66 // detach display mode
67 if (StereoDisplay && StereoDisplayAttached)
68 StereoDisplay->detachFromDisplay();
69 StereoDisplayAttached = false;
70 // re-init
71 releaseStereoDisplayDevice();
72 initStereoDisplayDevice();
73 // try attach display mode
74 if (StereoDisplay)
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);
84 // GRAPHICS - GENERAL
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);
104 else
105 Driver->forceTextureResize(1);
108 if (ClientCfg.InterfaceScale != LastClientCfg.InterfaceScale)
109 CInterfaceManager::getInstance()->setInterfaceScale(ClientCfg.InterfaceScale);
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);
122 else
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 //---------------------------------------------------
140 if (Landscape)
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 //---------------------------------------------------
169 if (Landscape)
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);
185 else
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)
210 if (ClientCfg.Cloud)
212 InitCloudScape = true;
213 CloudScape = Scene->createCloudScape();
215 else
217 if (CloudScape != NULL)
218 Scene->deleteCloudScape(CloudScape);
219 CloudScape = NULL;
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
241 if(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];
249 if(ent)
250 ent->updateCastShadowMap();
254 //---------------------------------------------------
255 if (ClientCfg.AnisotropicFilter != LastClientCfg.AnisotropicFilter)
257 Driver->setAnisotropicFilter(ClientCfg.AnisotropicFilter);
260 //---------------------------------------------------
261 if (ClientCfg.FXAA != LastClientCfg.FXAA)
263 if (ClientCfg.FXAA)
265 nlassert(!FXAA);
266 FXAA = new NL3D::CFXAA(Driver);
268 else
270 nlassert(FXAA);
271 delete FXAA;
272 FXAA = NULL;
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)
293 // Nothing to do
296 //---------------------------------------------------
297 if (ClientCfg.HDEntityTexture != LastClientCfg.HDEntityTexture)
299 // Don't reload Texture, will be done at next Game Start
302 // INTERFACE works
305 // INPUTS
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);
322 // SOUND
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...");
332 delete SoundMngr;
333 SoundMngr = NULL;
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());
346 delete SoundMngr;
347 SoundMngr = NULL;
350 // re-init with good SFX/Music Volume
351 if(SoundMngr)
353 SoundMngr->setSFXVolume(ClientCfg.SoundSFXVolume);
354 SoundMngr->setGameMusicVolume(ClientCfg.SoundGameMusicVolume);
357 else
359 nlwarning("Sound config error !");
362 mustReloadSoundMngrContinent= true;
365 // change EAX?
366 if ( SoundMngr && LastClientCfg.SoundOn &&
367 (ClientCfg.UseEax != LastClientCfg.UseEax) )
369 SoundMngr->reset();
371 mustReloadSoundMngrContinent= true;
374 // change SoundForceSoftwareBuffer?
375 if ( SoundMngr && LastClientCfg.SoundOn &&
376 (ClientCfg.SoundForceSoftwareBuffer != LastClientCfg.SoundForceSoftwareBuffer) )
378 SoundMngr->reset();
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;
412 /* end of file */