Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
Terrain.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2016 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods 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 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Terrain.h"
23
24#include "Actor.h"
25#include "ActorManager.h"
26#include "CacheSystem.h"
27#include "Collisions.h"
28#include "ContentManager.h"
29#include "Renderdash.h"
30#include "GfxScene.h"
31#include "GUIManager.h"
32#include "GUI_LoadingWindow.h"
33#include "GUI_SurveyMap.h"
34#include "HydraxWater.h"
35#include "Language.h"
36#include "ScriptEngine.h"
37#include "ShadowManager.h"
38#include "SkyManager.h"
39#include "SkyXManager.h"
42#include "Terrn2FileFormat.h"
43#include "Utils.h"
44#include "GfxWater.h"
45
46#include <Terrain/OgreTerrainPaging.h>
47#include <Terrain/OgreTerrainGroup.h>
48
49#include <algorithm>
50
51using namespace RoR;
52using namespace Ogre;
53
55 : m_collisions(0)
56 , m_geometry_manager(0)
57 , m_object_manager(0)
58 , m_shadow_manager(0)
59 , m_sky_manager(0)
60 , SkyX_manager(0)
61 , m_sight_range(1000)
62 , m_main_light(0)
63 , m_paged_detail_factor(0.0f)
64 , m_cur_gravity(DEFAULT_GRAVITY)
65 , m_hydrax_water(nullptr)
66 , m_cache_entry(entry)
67 , m_def(def)
68{
69}
70
72{
73 if (!m_disposed)
74 {
75 this->dispose();
76 }
77}
78
80{
81 if (App::app_state->getEnum<AppState>() == AppState::SHUTDOWN)
82 {
83 // Rush to exit
84 return;
85 }
86
87 //I think that the order is important
88
89#ifdef USE_CAELUM
90 if (m_sky_manager != nullptr)
91 {
92 delete(m_sky_manager);
93 m_sky_manager = nullptr;
94 }
95#endif // USE_CAELUM
96
97 if (SkyX_manager != nullptr)
98 {
99 delete(SkyX_manager);
100 SkyX_manager = nullptr;
101 }
102
103 if (m_main_light != nullptr)
104 {
105 App::GetGfxScene()->GetSceneManager()->destroyAllLights();
106 m_main_light = nullptr;
107 }
108
109 if (m_hydrax_water != nullptr)
110 {
111 m_gfx_water.reset(); // TODO: Currently needed - research and get rid of this ~ only_a_ptr, 08/2018
112 }
113
114 if (m_object_manager != nullptr)
115 {
116 delete(m_object_manager);
117 m_object_manager = nullptr;
118 }
119
120 if (m_geometry_manager != nullptr)
121 {
122 delete(m_geometry_manager);
123 m_geometry_manager = nullptr;
124 }
125
126 if (m_shadow_manager != nullptr)
127 {
128 delete(m_shadow_manager);
129 m_shadow_manager = nullptr;
130 }
131
132 if (m_collisions != nullptr)
133 {
134 delete(m_collisions);
135 m_collisions = nullptr;
136 }
137
138 if (m_wavefield)
139 {
140 m_wavefield.reset();
141 }
142
144 {
145 App::GetScriptEngine()->unloadScript(App::GetScriptEngine()->getTerrainScriptUnit());
146 }
147
148 m_disposed = true;
149}
150
152{
153 auto* loading_window = &App::GetGuiManager()->LoadingWindow;
154
155 this->setGravity(this->m_def->gravity);
156
157 loading_window->SetProgress(10, _L("Initializing Object Subsystem"));
158 this->initObjects(); // *.odef files
159
160 loading_window->SetProgress(14, _L("Initializing Shadow Subsystem"));
161 this->initShadows();
162
163 loading_window->SetProgress(17, _L("Initializing Geometry Subsystem"));
164 this->m_geometry_manager = new TerrainGeometryManager(this);
165
166 loading_window->SetProgress(23, _L("Initializing Camera Subsystem"));
167 this->initCamera();
168
169 // sky, must come after camera due to m_sight_range
170 loading_window->SetProgress(25, _L("Initializing Sky Subsystem"));
171 this->initSkySubSystem();
172
173 loading_window->SetProgress(27, _L("Initializing Light Subsystem"));
174 this->initLight();
175
176 if (App::gfx_sky_mode->getEnum<GfxSkyMode>() != GfxSkyMode::CAELUM) //Caelum has its own fog management
177 {
178 loading_window->SetProgress(29, _L("Initializing Fog Subsystem"));
179 this->initFog();
180 }
181
182 loading_window->SetProgress(31, _L("Initializing Vegetation Subsystem"));
183 this->initVegetation();
184
185 this->fixCompositorClearColor();
186
187 loading_window->SetProgress(40, _L("Loading Terrain Geometry"));
188 if (!this->m_geometry_manager->InitTerrain(this->m_def->ogre_ter_conf_filename))
189 {
190 return false; // Error already reported
191 }
192
193 loading_window->SetProgress(60, _L("Initializing Collision Subsystem"));
194 this->m_collisions = new Collisions(this->getMaxTerrainSize());
195
196 loading_window->SetProgress(75, _L("Initializing Script Subsystem"));
197 this->initScripting();
198 this->initAiPresets();
199
200 loading_window->SetProgress(77, _L("Initializing Water Subsystem"));
201 this->initWater();
202
203 loading_window->SetProgress(80, _L("Loading Terrain Objects"));
204 this->loadTerrainObjects(); // *.tobj files
205
206 // init things after loading the terrain
207 this->initTerrainCollisions();
208
209 loading_window->SetProgress(90, _L("Initializing terrain light properties"));
210 this->m_geometry_manager->UpdateMainLightPosition(); // Initial update takes a while
211 this->m_collisions->finishLoadingTerrain();
212
213 this->LoadTelepoints(); // *.terrn2 file feature
214
215 App::GetGfxScene()->CreateDustPools(); // Particle effects
216
217 loading_window->SetProgress(92, _L("Initializing Overview Map Subsystem"));
218 App::GetGuiManager()->SurveyMap.CreateTerrainTextures(); // Should be done before actors are loaded, otherwise they'd show up in the static texture
219
220 LOG(" ===== LOADING TERRAIN ACTORS " + m_cache_entry->fname);
221 loading_window->SetProgress(95, _L("Loading Terrain Actors"));
222 this->LoadPredefinedActors();
223
224 LOG(" ===== TERRAIN LOADING DONE " + m_cache_entry->fname);
225
226 App::sim_terrain_name->setStr(m_cache_entry->fname);
227 App::sim_terrain_gui_name->setStr(this->m_def->name);
228
229 return this;
230}
231
233{
234 App::GetCameraManager()->GetCamera()->getViewport()->setBackgroundColour(m_def->ambient_color);
235 App::GetCameraManager()->GetCameraNode()->setPosition(m_def->start_position);
236
237 if (App::gfx_sky_mode->getEnum<GfxSkyMode>() == GfxSkyMode::SKYX)
238 {
239 m_sight_range = 5000; //Force unlimited for SkyX, lower settings are glitchy
240 }
241 else
242 {
243 m_sight_range = App::gfx_sight_range->getInt();
244 }
245
246 if (m_sight_range < UNLIMITED_SIGHTRANGE && App::gfx_sky_mode->getEnum<GfxSkyMode>() != GfxSkyMode::SKYX)
247 {
248 App::GetCameraManager()->GetCamera()->setFarClipDistance(m_sight_range);
249 }
250 else
251 {
252 // disabled in global config
253 if (App::gfx_water_mode->getEnum<GfxWaterMode>() != GfxWaterMode::HYDRAX)
254 App::GetCameraManager()->GetCamera()->setFarClipDistance(0); //Unlimited
255 else
256 App::GetCameraManager()->GetCamera()->setFarClipDistance(9999 * 6); //Unlimited for hydrax and stuff
257 }
258}
259
261{
262#ifdef USE_CAELUM
263 // Caelum skies
264 if (App::gfx_sky_mode->getEnum<GfxSkyMode>() == GfxSkyMode::CAELUM)
265 {
266 m_sky_manager = new SkyManager();
267
268 // try to load caelum config
269 if (!m_def->caelum_config.empty() && ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(m_def->caelum_config))
270 {
271 // config provided and existing, use it :)
272 m_sky_manager->LoadCaelumScript(m_def->caelum_config, m_def->caelum_fog_start, m_def->caelum_fog_end);
273 }
274 else
275 {
276 // no config provided, fall back to the default one
277 m_sky_manager->LoadCaelumScript("ror_default_sky");
278 }
279 }
280 else
281#endif //USE_CAELUM
282 // SkyX skies
283 if (App::gfx_sky_mode->getEnum<GfxSkyMode>() == GfxSkyMode::SKYX)
284 {
285 // try to load SkyX config
286 if (!m_def->skyx_config.empty() && ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(m_def->skyx_config))
287 SkyX_manager = new SkyXManager(m_def->skyx_config);
288 else
289 SkyX_manager = new SkyXManager("SkyXDefault.skx");
290 }
291 else
292 {
293 if (!m_def->cubemap_config.empty())
294 {
295 // use custom
296 App::GetGfxScene()->GetSceneManager()->setSkyBox(true, m_def->cubemap_config, 100, true);
297 }
298 else
299 {
300 // use default
301 App::GetGfxScene()->GetSceneManager()->setSkyBox(true, "tracks/skyboxcol", 100, true);
302 }
303 }
304}
305
307{
308 if (App::gfx_sky_mode->getEnum<GfxSkyMode>() == GfxSkyMode::CAELUM)
309 {
310#ifdef USE_CAELUM
311 m_main_light = m_sky_manager->GetSkyMainLight();
312#endif
313 }
314 else if (App::gfx_sky_mode->getEnum<GfxSkyMode>() == GfxSkyMode::SKYX)
315 {
316 m_main_light = SkyX_manager->getMainLight();
317 }
318 else
319 {
320 // screw caelum, we will roll our own light
321
322 // Create a light
323 m_main_light = App::GetGfxScene()->GetSceneManager()->createLight("MainLight");
324 //directional light for shadow
325 m_main_light->setType(Light::LT_DIRECTIONAL);
326 m_main_light->setDirection(Ogre::Vector3(0.785, -0.423, 0.453).normalisedCopy());
327
328 m_main_light->setDiffuseColour(m_def->ambient_color);
329 m_main_light->setSpecularColour(m_def->ambient_color);
330 m_main_light->setCastShadows(true);
331 m_main_light->setShadowFarDistance(1000.0f);
332 m_main_light->setShadowNearClipDistance(-1);
333 }
334}
335
337{
338 if (m_sight_range >= UNLIMITED_SIGHTRANGE)
339 App::GetGfxScene()->GetSceneManager()->setFog(FOG_NONE);
340 else
341 App::GetGfxScene()->GetSceneManager()->setFog(FOG_LINEAR, m_def->ambient_color, 0.000f, m_sight_range * 0.65f, m_sight_range*0.9);
342}
343
345{
346 switch (App::gfx_vegetation_mode->getEnum<GfxVegetation>())
347 {
349 m_paged_detail_factor = 0.2f;
350 break;
352 m_paged_detail_factor = 0.5f;
353 break;
355 m_paged_detail_factor = 1.0f;
356 break;
357 default:
358 m_paged_detail_factor = 0.0f;
359 break;
360 }
361}
362
364{
365 // hack
366 // now with extensive error checking
367 if (CompositorManager::getSingleton().hasCompositorChain(App::GetCameraManager()->GetCamera()->getViewport()))
368 {
369 CompositorInstance* co = CompositorManager::getSingleton().getCompositorChain(App::GetCameraManager()->GetCamera()->getViewport())->_getOriginalSceneCompositor();
370 if (co)
371 {
372 CompositionTechnique* ct = co->getTechnique();
373 if (ct)
374 {
375 CompositionTargetPass* ctp = ct->getOutputTargetPass();
376 if (ctp)
377 {
378 ROR_ASSERT(ctp->getPasses().size() > 0);
379 CompositionPass* p = ctp->getPasses()[0];
380 if (p)
381 {
382 p->setClearColour(Ogre::ColourValue::Black);
383 }
384 }
385 }
386 }
387 }
388}
389
391{
392 // disabled in global config
393 if (App::gfx_water_mode->getEnum<GfxWaterMode>() == GfxWaterMode::NONE)
394 return;
395
396 // disabled in map config
397 if (!m_def->has_water)
398 {
399 return;
400 }
401
402 m_wavefield = std::unique_ptr<Wavefield>(new Wavefield(this->getMaxTerrainSize()));
403 m_wavefield->SetStaticWaterHeight(m_def->water_height);
404
405 if (App::gfx_water_mode->getEnum<GfxWaterMode>() == GfxWaterMode::HYDRAX)
406 {
407 // try to load hydrax config
408 if (!m_def->hydrax_conf_file.empty() && ResourceGroupManager::getSingleton().resourceExistsInAnyGroup(m_def->hydrax_conf_file))
409 {
410 m_hydrax_water = new HydraxWater(m_def->water_height, m_def->hydrax_conf_file);
411 }
412 else
413 {
414 // no config provided, fall back to the default one
415 m_hydrax_water = new HydraxWater(m_def->water_height);
416 }
417
418 m_gfx_water = std::unique_ptr<IGfxWater>(m_hydrax_water);
419
420 //Apply depth technique to the terrain
421 TerrainGroup::TerrainIterator ti = m_geometry_manager->getTerrainGroup()->getTerrainIterator();
422 while (ti.hasMoreElements())
423 {
424 Ogre::Terrain* t = ti.getNext()->instance;
425 MaterialPtr ptr = t->getMaterial();
426 m_hydrax_water->GetHydrax()->getMaterialManager()->addDepthTechnique(ptr->createTechnique());
427 }
428 }
429 else
430 {
431 m_gfx_water = std::unique_ptr<IGfxWater>(new GfxWater(this->getMaxTerrainSize(), m_def->water_height));
432 m_gfx_water->SetWaterBottomHeight(m_def->water_bottom_height);
433 }
434}
435
437{
438 m_shadow_manager = new ShadowManager();
439 m_shadow_manager->loadConfiguration();
440}
441
443{
444 for (std::string tobj_filename : m_def->tobj_files)
445 {
446 m_object_manager->LoadTObjFile(tobj_filename);
447 }
448}
449
451{
452 if (!m_def->traction_map_file.empty())
453 {
454 m_collisions->setupLandUse(m_def->traction_map_file.c_str());
455 }
456}
457
459{
460#ifdef USE_ANGELSCRIPT
461 // suspend AS logging, so we dont spam the users screen with initialization messages
463
464 bool loaded = false;
465
466 for (std::string as_filename : m_def->as_files)
467 {
468 loaded |= this->getObjectManager()->LoadTerrainScript(as_filename);
469 }
470
471 if (!loaded)
472 {
473 // load a default script that does the most basic things
474 this->getObjectManager()->LoadTerrainScript(DEFAULT_TERRAIN_SCRIPT);
475 }
476
477 // finally resume AS logging
479#endif //USE_ANGELSCRIPT
480}
481
483{
484 // Load 'bundled' AI presets - see section `[AI Presets]` in terrn2 file format
485 // ----------------------------------------------------------------------------
486
488}
489
491{
492 m_cur_gravity = value;
493}
494
496{
497 m_object_manager = new TerrainObjectManager(this);
498}
499
501{
502 return m_collisions->getCollisionAAB();
503}
504
506{
507 if (!m_geometry_manager)
508 return Vector3::ZERO;
509 return m_geometry_manager->getMaxTerrainSize();
510}
511
512float RoR::Terrain::getHeightAt(float x, float z)
513{
514 return m_geometry_manager->getHeightAt(x, z);
515}
516
517Ogre::Vector3 RoR::Terrain::GetNormalAt(float x, float y, float z)
518{
519 return m_geometry_manager->getNormalAt(x, y, z);
520}
521
523{
524 return m_sky_manager;
525}
526
528{
529 if (m_disposed)
530 return false;
531 else
532 return m_geometry_manager->isFlat();
533}
534
536{
537 if (m_object_manager)
538 m_object_manager->LoadTelepoints();
539}
540
542{
543 if (m_object_manager)
544 m_object_manager->LoadPredefinedActors();
545}
546
548{
549 if (m_object_manager)
550 return m_object_manager->HasPredefinedActors();
551 return false;
552}
553
555{
556 return m_object_manager->getProceduralManager();
557}
558
560{
561 return m_cache_entry->fname;
562}
563
565{
566 return m_cache_entry->resource_group;
567}
568
569void RoR::Terrain::addSurveyMapEntity(const std::string& type, const std::string& filename, const std::string& resource_group, const std::string& caption, const Ogre::Vector3& pos, float angle, int id)
570{
571 m_object_manager->m_map_entities.push_back(SurveyMapEntity(type, caption, filename, resource_group, pos, Ogre::Radian(angle), id));
572}
573
575{
576 EraseIf(m_object_manager->m_map_entities, [id](const SurveyMapEntity& e) { return e.id == id; });
577}
578
580{
581 return m_object_manager->m_map_entities;
582}
583
585
586std::string RoR::Terrain::getTerrainName() const { return m_def->name; }
587
588std::string RoR::Terrain::getGUID() const { return m_def->guid; }
589
590int RoR::Terrain::getVersion() const { return m_def->version; }
591
593
594Ogre::Vector3 RoR::Terrain::getSpawnPos() { return m_def->start_position; }
595
596Ogre::Degree RoR::Terrain::getSpawnRot() { return m_def->start_rotation; }
597
598float RoR::Terrain::getWaterHeight() const { return m_def->water_height; }
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
void LOG(const char *msg)
Legacy alias - formerly a macro.
A database of user-installed content alias 'mods' (vehicles, terrains...)
#define _L
#define DEFAULT_TERRAIN_SCRIPT
void setStr(std::string const &str)
Definition CVar.h:83
int getInt() const
Definition CVar.h:97
Ogre::SceneNode * GetCameraNode()
Ogre::Camera * GetCamera()
void LoadBundledAiPresets(TerrainPtr terrain)
Loads JSON files from [AI Presets] section in .terrn2 file format.
GUI::TopMenubar TopMenubar
Definition GUIManager.h:133
GUI::LoadingWindow LoadingWindow
Definition GUIManager.h:132
GUI::SurveyMap SurveyMap
Definition GUIManager.h:135
void CreateDustPools()
Definition GfxScene.cpp:50
Ogre::SceneManager * GetSceneManager()
Definition GfxScene.h:83
ScriptUnitID_t getTerrainScriptUnit() const
void setForwardScriptLogToConsole(bool doForward)
void unloadScript(ScriptUnitID_t unique_id)
Unloads a script.
this class handles all interactions with the Ogre Terrain system
void setGravity(float value)
Definition Terrain.cpp:490
std::string getTerrainFileResourceGroup()
Definition Terrain.cpp:564
void delSurveyMapEntities(int id)
Definition Terrain.cpp:574
void fixCompositorClearColor()
Definition Terrain.cpp:363
Ogre::Vector3 getMaxTerrainSize()
Definition Terrain.cpp:505
void initVegetation()
Definition Terrain.cpp:344
void initWater()
Definition Terrain.cpp:390
int getVersion() const
Definition Terrain.cpp:590
void LoadTelepoints()
Definition Terrain.cpp:535
void initAiPresets()
Definition Terrain.cpp:482
void initShadows()
Definition Terrain.cpp:436
float getWaterHeight() const
Definition Terrain.cpp:598
bool initialize()
Definition Terrain.cpp:151
void loadTerrainObjects()
Definition Terrain.cpp:442
bool HasPredefinedActors()
Definition Terrain.cpp:547
void initCamera()
Definition Terrain.cpp:232
SkyManager * getSkyManager()
Definition Terrain.cpp:522
SurveyMapEntityVec & getSurveyMapEntities()
Definition Terrain.cpp:579
std::string getTerrainName() const
Definition Terrain.cpp:586
void initFog()
Definition Terrain.cpp:336
void initTerrainCollisions()
Definition Terrain.cpp:450
float getHeightAt(float x, float z)
Definition Terrain.cpp:512
void initScripting()
Definition Terrain.cpp:458
void initSkySubSystem()
Definition Terrain.cpp:260
std::string getTerrainFileName()
Definition Terrain.cpp:559
void initObjects()
Definition Terrain.cpp:495
void addSurveyMapEntity(const std::string &type, const std::string &filename, const std::string &resource_group, const std::string &caption, const Ogre::Vector3 &pos, float angle, int id)
Definition Terrain.cpp:569
CacheEntryPtr getCacheEntry()
Definition Terrain.cpp:592
Ogre::Degree getSpawnRot()
Definition Terrain.cpp:596
Ogre::Vector3 GetNormalAt(float x, float y, float z)
Definition Terrain.cpp:517
bool isFlat()
Definition Terrain.cpp:527
std::string getGUID() const
Definition Terrain.cpp:588
Terrain(CacheEntryPtr entry, Terrn2DocumentPtr def)
Definition Terrain.cpp:54
Ogre::AxisAlignedBox getTerrainCollisionAAB()
Definition Terrain.cpp:500
void dispose()
Definition Terrain.cpp:79
void LoadPredefinedActors()
Definition Terrain.cpp:541
Ogre::Vector3 getSpawnPos()
Definition Terrain.cpp:594
void initLight()
Definition Terrain.cpp:306
virtual ~Terrain() override
Definition Terrain.cpp:71
ProceduralManagerPtr getProceduralManager()
Definition Terrain.cpp:554
Terrn2DocumentPtr GetDef()
Definition Terrain.cpp:584
< Water physics, see 'wavefield.cfg' in your config directory.
Definition Wavefield.h:33
static const float DEFAULT_GRAVITY
earth gravity
std::vector< SurveyMapEntity > SurveyMapEntityVec
CVar * gfx_sky_mode
CVar * gfx_water_mode
CVar * sim_terrain_name
CVar * sim_terrain_gui_name
CameraManager * GetCameraManager()
CVar * gfx_sight_range
GUIManager * GetGuiManager()
GfxScene * GetGfxScene()
CVar * app_state
CVar * gfx_vegetation_mode
ScriptEngine * GetScriptEngine()
std::shared_ptr< Terrn2Document > Terrn2DocumentPtr
static const ScriptUnitID_t SCRIPTUNITID_INVALID
@ CAELUM
Caelum (best looking, slower)
@ SKYX
SkyX (best looking, slower)
void EraseIf(std::vector< T, A > &c, Predicate pred)
Definition Utils.h:75