RigsofRods
Soft-body Physics Simulation
TerrainEditor.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-2020 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 "TerrainEditor.h"
23 
24 #include "AppContext.h"
25 #include "CameraManager.h"
26 #include "Console.h"
27 #include "ContentManager.h"
28 #include "GameContext.h"
29 #include "GfxScene.h"
30 #include "InputEngine.h"
31 #include "OgreImGui.h"
32 #include "Terrain.h"
33 #include "TerrainObjectManager.h"
34 #include "PlatformUtils.h"
35 
36 using namespace RoR;
37 using namespace Ogre;
38 
40 {
41  auto& object_list = App::GetGameContext()->GetTerrain()->getObjectManager()->GetEditorObjects();
42  bool update = false;
43 
44  if (ImGui::IsMouseClicked(2)) // Middle button
45  {
46  ImVec2 mouse_screen = ImGui::GetIO().MousePos / ImGui::GetIO().DisplaySize;
47  Ogre::Ray terrain_editor_mouse_ray = App::GetCameraManager()->GetCamera()->getCameraToViewportRay(mouse_screen.x, mouse_screen.y);
48 
49  float min_dist = std::numeric_limits<float>::max();
50  Vector3 origin = terrain_editor_mouse_ray.getOrigin();
51  Vector3 direction = terrain_editor_mouse_ray.getDirection();
52  for (int i = 0; i < (int)object_list.size(); i++)
53  {
54  Real ray_object_distance = direction.crossProduct(object_list[i].node->getPosition() - origin).length();
55  if (ray_object_distance < min_dist)
56  {
57  min_dist = ray_object_distance;
58  update = (m_object_index != i);
59  m_object_index = i;
60  }
61  }
62  }
63  if (m_object_index != -1)
64  {
65  m_last_object_name = object_list[m_object_index].name;
66  }
68  {
69  if (m_object_index == -1)
70  {
71  // Select nearest object
73  ? App::GetCameraManager()->GetCameraNode()->getPosition()
75  float min_dist = std::numeric_limits<float>::max();
76  for (int i = 0; i < (int)object_list.size(); i++)
77  {
78  float dist = ref_pos.squaredDistance(object_list[i].node->getPosition());
79  if (dist < min_dist)
80  {
81  m_object_index = i;
82  min_dist = dist;
83  update = true;
84  }
85  }
86  }
87  else
88  {
89  m_object_index = -1;
90  }
91  }
93  m_last_object_name != "")
94  {
96 
97  try
98  {
99  App::GetGameContext()->GetTerrain()->getObjectManager()->LoadTerrainObject(m_last_object_name, pos, Vector3::ZERO, "Console", "");
100 
101  App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_REPLY, _L("Spawned object at position: ") + String("x: ") + TOSTRING(pos.x) + String("z: ") + TOSTRING(pos.z), "world.png");
102  }
103  catch (std::exception& e)
104  {
106  }
107  }
108  else if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_ENTER_NEXT_TRUCK, 0.25f))
109  {
110  if (object_list.size() > 0)
111  {
112  m_object_index = (m_object_index + 1 + (int)object_list.size()) % object_list.size();
113  update = true;
114  }
115  }
117  {
118  if (object_list.size() > 0)
119  {
120  m_object_index = (m_object_index - 1 + (int)object_list.size()) % object_list.size();
121  update = true;
122  }
123  }
125  {
126  UTFString axis = _L("ry");
127  if (m_rotation_axis == 0)
128  {
129  axis = _L("ry");
130  m_rotation_axis = 1;
131  }
132  else if (m_rotation_axis == 1)
133  {
134  axis = _L("rz");
135  m_rotation_axis = 2;
136  }
137  else if (m_rotation_axis == 2)
138  {
139  axis = _L("rx");
140  m_rotation_axis = 0;
141  }
142  UTFString ssmsg = _L("Rotating: ") + axis;
144  }
145  if (App::GetInputEngine()->isKeyDownValueBounce(OIS::KC_SPACE))
146  {
147  m_object_tracking = !m_object_tracking;
148  UTFString ssmsg = m_object_tracking ? _L("Enabled object tracking") : _L("Disabled object tracking");
150  }
151  if (m_object_index != -1 && update)
152  {
153  String ssmsg = _L("Selected object: [") + TOSTRING(m_object_index) + "/" + TOSTRING(object_list.size()) + "] (" + object_list[m_object_index].name + ")";
155  if (m_object_tracking)
156  {
157  App::GetGameContext()->GetPlayerCharacter()->setPosition(object_list[m_object_index].node->getPosition());
158  }
159  }
160  if (m_object_index != -1 && App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_RESET_TRUCK))
161  {
162  SceneNode* sn = object_list[m_object_index].node;
163 
164  object_list[m_object_index].position = object_list[m_object_index].initial_position;
165  sn->setPosition(object_list[m_object_index].position);
166 
167  object_list[m_object_index].rotation = object_list[m_object_index].initial_rotation;
168  Vector3 rot = object_list[m_object_index].rotation;
169  sn->setOrientation(Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z));
170  sn->pitch(Degree(-90));
171  }
172  if (m_object_index != -1 && App::GetCameraManager()->GetCurrentBehavior() != CameraManager::CAMERA_BEHAVIOR_FREE)
173  {
174  SceneNode* sn = object_list[m_object_index].node;
175 
176  Vector3 translation = Vector3::ZERO;
177  float rotation = 0.0f;
178 
179  if (App::GetInputEngine()->getEventBoolValue(EV_TRUCK_STEER_LEFT))
180  {
181  rotation += 2.0f;
182  }
183  else if (App::GetInputEngine()->getEventBoolValue(EV_TRUCK_STEER_RIGHT))
184  {
185  rotation -= 2.0f;
186  }
187  if (App::GetInputEngine()->getEventBoolValue(EV_TRUCK_ACCELERATE))
188  {
189  translation.y += 0.5f;
190  }
191  else if (App::GetInputEngine()->getEventBoolValue(EV_TRUCK_BRAKE))
192  {
193  translation.y -= 0.5f;
194  }
195  if (App::GetInputEngine()->getEventBoolValue(EV_CHARACTER_FORWARD))
196  {
197  translation.x += 0.5f;
198  }
199  else if (App::GetInputEngine()->getEventBoolValue(EV_CHARACTER_BACKWARDS))
200  {
201  translation.x -= 0.5f;
202  }
203  if (App::GetInputEngine()->getEventBoolValue(EV_CHARACTER_SIDESTEP_RIGHT))
204  {
205  translation.z += 0.5f;
206  }
207  else if (App::GetInputEngine()->getEventBoolValue(EV_CHARACTER_SIDESTEP_LEFT))
208  {
209  translation.z -= 0.5f;
210  }
211 
212  if (translation != Vector3::ZERO || rotation != 0.0f)
213  {
214  float scale = App::GetInputEngine()->isKeyDown(OIS::KC_LMENU) ? 0.1f : 1.0f;
215  scale *= App::GetInputEngine()->isKeyDown(OIS::KC_LSHIFT) ? 3.0f : 1.0f;
216  scale *= App::GetInputEngine()->isKeyDown(OIS::KC_LCONTROL) ? 10.0f : 1.0f;
217 
218  object_list[m_object_index].position += translation * scale * dt;
219  sn->setPosition(object_list[m_object_index].position);
220 
221  object_list[m_object_index].rotation[m_rotation_axis] += rotation * scale * dt;
222  Vector3 rot = object_list[m_object_index].rotation;
223  sn->setOrientation(Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z));
224  sn->pitch(Degree(-90));
225 
226  if (m_object_tracking)
227  {
228  App::GetGameContext()->GetPlayerCharacter()->setPosition(sn->getPosition());
229  }
230  }
231  else if (m_object_tracking && App::GetGameContext()->GetPlayerCharacter()->getPosition() != sn->getPosition())
232  {
233  object_list[m_object_index].position = App::GetGameContext()->GetPlayerCharacter()->getPosition();
234  sn->setPosition(App::GetGameContext()->GetPlayerCharacter()->getPosition());
235  }
236  if (App::GetInputEngine()->getEventBoolValue(EV_COMMON_REMOVE_CURRENT_TRUCK))
237  {
238  App::GetGameContext()->GetTerrain()->getObjectManager()->unloadObject(object_list[m_object_index].instance_name);
239  }
240  }
241  else
242  {
244  }
245 
246  if (App::GetInputEngine()->getEventBoolValueBounce(EV_COMMON_TOGGLE_TERRAIN_EDITOR))
247  {
249  }
250 }
251 
253 {
254  const char* filename = "editor_out.log";
255  std::string editor_logpath = PathCombine(App::sys_logs_dir->getStr(), filename);
256  try
257  {
258  Ogre::DataStreamPtr stream
259  = Ogre::ResourceGroupManager::getSingleton().createResource(
260  editor_logpath, RGN_CONFIG, /*overwrite=*/true);
261 
262  for (auto object : App::GetGameContext()->GetTerrain()->getObjectManager()->GetEditorObjects())
263  {
264  SceneNode* sn = object.node;
265  if (sn != nullptr)
266  {
267  String pos = StringUtil::format("%8.3f, %8.3f, %8.3f" , object.position.x, object.position.y, object.position.z);
268  String rot = StringUtil::format("% 6.1f, % 6.1f, % 6.1f", object.rotation.x, object.rotation.y, object.rotation.z);
269 
270  String line = pos + ", " + rot + ", " + object.name + "\n";
271  stream->write(line.c_str(), line.length());
272  }
273  }
274 
275  // Export procedural roads
277  for (int i = 0; i < num_roads; i++)
278  {
280  int num_points = obj->getNumPoints();
281  if (num_points > 0)
282  {
283  stream->write("\nbegin_procedural_roads\n", 24);
284  std::string smoothing_line = fmt::format("\tsmoothing_num_splits {}\n", obj->smoothing_num_splits);
285  stream->write(smoothing_line.c_str(), smoothing_line.length());
286  for (int j = 0; j < num_points; j++)
287  {
288  ProceduralPointPtr point = obj->getPoint(j);
289  std::string type_str;
290  switch (point->type)
291  {
292  case RoadType::ROAD_AUTOMATIC: type_str = "both"; break; // ??
293  case RoadType::ROAD_FLAT: type_str = "flat"; break;
294  case RoadType::ROAD_LEFT: type_str = "left"; break;
295  case RoadType::ROAD_RIGHT: type_str = "right"; break;
296  case RoadType::ROAD_BOTH: type_str = "both"; break;
297  case RoadType::ROAD_BRIDGE: type_str = (point->pillartype == 1) ? "bridge" : "bridge_no_pillars"; break;
298  case RoadType::ROAD_MONORAIL: type_str = (point->pillartype == 2) ? "monorail" : "monorail2"; break;
299  }
300 
301  std::string line = fmt::format(
302  "\t{:13f}, {:13f}, {:13f}, 0, {:13f}, 0, {:13f}, {:13f}, {:13f}, {}\n",
303  point->position.x, point->position.y, point->position.z,
304  point->rotation.getYaw().valueDegrees(),
305  point->width, point->bwidth, point->bheight, type_str);
306  stream->write(line.c_str(), line.length());
307  }
308  stream->write("end_procedural_roads\n", 21);
309  }
310  }
311  }
312  catch (std::exception& e)
313  {
314  RoR::LogFormat("[RoR|MapEditor]"
315  "Error saving file '%s' (resource group '%s'), message: '%s'",
316  filename, RGN_CONFIG, e.what());
317  }
318 }
319 
321 {
322  m_object_index = -1;
323 }
GameContext.h
Game state manager and message-queue provider.
RoR::RoadType::ROAD_BOTH
@ ROAD_BOTH
RoR::Character::setPosition
void setPosition(Ogre::Vector3 position)
Definition: Character.cpp:85
RoR::TerrainEditor::UpdateInputEvents
void UpdateInputEvents(float dt)
Definition: TerrainEditor.cpp:39
RGN_CONFIG
#define RGN_CONFIG
Definition: Application.h:48
RoR::EV_COMMON_RESET_TRUCK
@ EV_COMMON_RESET_TRUCK
reset truck to original starting position
Definition: InputEngine.h:257
RoR::EV_COMMON_ENTER_OR_EXIT_TRUCK
@ EV_COMMON_ENTER_OR_EXIT_TRUCK
enter or exit a truck
Definition: InputEngine.h:229
RoR::App::GetCameraManager
CameraManager * GetCameraManager()
Definition: Application.cpp:275
RoR::RoadType::ROAD_AUTOMATIC
@ ROAD_AUTOMATIC
ContentManager.h
RoR::TerrainEditor::ClearSelection
void ClearSelection()
Definition: TerrainEditor.cpp:320
format
Truck file format(technical spec)
RoR::Terrain::getObjectManager
TerrainObjectManager * getObjectManager()
Definition: Terrain.h:77
RoR::CameraManager::CAMERA_BEHAVIOR_FREE
@ CAMERA_BEHAVIOR_FREE
Definition: CameraManager.h:52
RoR::GameContext::GetPlayerCharacter
Character * GetPlayerCharacter()
Definition: GameContext.cpp:873
RoR::EV_COMMON_ENTER_PREVIOUS_TRUCK
@ EV_COMMON_ENTER_PREVIOUS_TRUCK
enter previous truck
Definition: InputEngine.h:231
RoR::TerrainObjectManager::GetEditorObjects
std::vector< EditorObject > & GetEditorObjects()
Definition: TerrainObjectManager.h:71
RoR::EV_CHARACTER_BACKWARDS
@ EV_CHARACTER_BACKWARDS
step backwards with the character
Definition: InputEngine.h:129
CameraManager.h
RoR::LogFormat
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
Definition: Application.cpp:424
AppContext.h
System integration layer; inspired by OgreBites::ApplicationContext.
Console.h
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:97
RoR::ProceduralObject::getNumPoints
int getNumPoints() const
Definition: ProceduralManager.h:68
RoR::EV_COMMON_ENTER_NEXT_TRUCK
@ EV_COMMON_ENTER_NEXT_TRUCK
enter next truck
Definition: InputEngine.h:230
RoR::TerrainObjectManager::LoadTerrainObject
bool LoadTerrainObject(const Ogre::String &name, const Ogre::Vector3 &pos, const Ogre::Vector3 &rot, const Ogre::String &instancename, const Ogre::String &type, float rendering_distance=0, bool enable_collisions=true, int scripthandler=-1, bool uniquifyMaterial=false)
Definition: TerrainObjectManager.cpp:577
RoR::App::sys_logs_dir
CVar * sys_logs_dir
Definition: Application.cpp:167
RoR::CameraManager::GetCameraNode
Ogre::SceneNode * GetCameraNode()
Definition: CameraManager.h:63
TerrainObjectManager.h
RoR::InputEngine::getEventBoolValueBounce
bool getEventBoolValueBounce(int eventID, float time=0.2f)
Definition: InputEngine.cpp:762
OgreImGui.h
RefCountingObjectPtr< ProceduralObject >
RoR::Console::CONSOLE_SYSTEM_ERROR
@ CONSOLE_SYSTEM_ERROR
Definition: Console.h:52
RoR::Terrain::getProceduralManager
ProceduralManagerPtr getProceduralManager()
Definition: Terrain.cpp:545
RoR::InputEngine::isKeyDown
bool isKeyDown(OIS::KeyCode mod)
Asks OIS directly.
Definition: InputEngine.cpp:1170
RoR::Console::CONSOLE_SYSTEM_NOTICE
@ CONSOLE_SYSTEM_NOTICE
Definition: Console.h:51
RoR::EV_TRUCK_STEER_LEFT
@ EV_TRUCK_STEER_LEFT
steer left
Definition: InputEngine.h:357
RoR::CameraManager::GetCurrentBehavior
CameraBehaviors GetCurrentBehavior() const
Definition: CameraManager.h:62
Script2Game::KC_LSHIFT
enum Script2Game::inputEvents KC_LSHIFT
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::CameraManager::GetCamera
Ogre::Camera * GetCamera()
Definition: CameraManager.h:64
RoR::CharacterFactory::Update
void Update(float dt)
Definition: CharacterFactory.cpp:80
RoR::PathCombine
std::string PathCombine(std::string a, std::string b)
Definition: PlatformUtils.h:48
RoR::EV_COMMON_RESPAWN_LAST_TRUCK
@ EV_COMMON_RESPAWN_LAST_TRUCK
respawn last truck
Definition: InputEngine.h:233
RoR::EV_CHARACTER_SIDESTEP_RIGHT
@ EV_CHARACTER_SIDESTEP_RIGHT
sidestep to the right
Definition: InputEngine.h:138
RoR::RoadType::ROAD_BRIDGE
@ ROAD_BRIDGE
RoR::GameContext::PushMessage
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
Definition: GameContext.cpp:65
RoR::GameContext::GetCharacterFactory
CharacterFactory * GetCharacterFactory()
Definition: GameContext.h:150
GfxScene.h
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
Script2Game::KC_SPACE
enum Script2Game::inputEvents KC_SPACE
RoR::ProceduralManager::getObject
ProceduralObjectPtr getObject(int pos)
Definition: ProceduralManager.cpp:74
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:270
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::ProceduralObject::smoothing_num_splits
int smoothing_num_splits
Definition: ProceduralManager.h:76
TerrainEditor.h
RoR::Character::getPosition
Ogre::Vector3 getPosition()
Definition: Character.cpp:92
RoR::EV_CHARACTER_FORWARD
@ EV_CHARACTER_FORWARD
step forward with the character
Definition: InputEngine.h:130
RoR::EV_COMMON_TOGGLE_TERRAIN_EDITOR
@ EV_COMMON_TOGGLE_TERRAIN_EDITOR
toggle terrain editor
Definition: InputEngine.h:267
RoR::Console::CONSOLE_SYSTEM_REPLY
@ CONSOLE_SYSTEM_REPLY
Success.
Definition: Console.h:54
RoR::TerrainEditor::WriteOutputFile
void WriteOutputFile()
Definition: TerrainEditor.cpp:252
RoR::RoadType::ROAD_FLAT
@ ROAD_FLAT
RoR::RoadType::ROAD_MONORAIL
@ ROAD_MONORAIL
RoR::RoadType::ROAD_RIGHT
@ ROAD_RIGHT
RoR::EV_TRUCK_ACCELERATE
@ EV_TRUCK_ACCELERATE
accelerate the truck
Definition: InputEngine.h:297
RoR::ProceduralObject::getPoint
ProceduralPointPtr getPoint(int pos)
Definition: ProceduralManager.cpp:32
_L
#define _L
Definition: ErrorUtils.cpp:34
RoR::EV_TRUCK_STEER_RIGHT
@ EV_TRUCK_STEER_RIGHT
steer right
Definition: InputEngine.h:358
RoR::RoadType::ROAD_LEFT
@ ROAD_LEFT
RoR::MSG_EDI_LEAVE_TERRN_EDITOR_REQUESTED
@ MSG_EDI_LEAVE_TERRN_EDITOR_REQUESTED
Definition: Application.h:146
RoR::App::GetInputEngine
InputEngine * GetInputEngine()
Definition: Application.cpp:271
RoR::TerrainObjectManager::unloadObject
void unloadObject(const Ogre::String &instancename)
Definition: TerrainObjectManager.cpp:505
RoR::EV_CHARACTER_SIDESTEP_LEFT
@ EV_CHARACTER_SIDESTEP_LEFT
sidestep to the left
Definition: InputEngine.h:137
Terrain.h
InputEngine.h
Handles controller inputs from player. Defines input events and binding mechanism,...
Ogre
Definition: ExtinguishableFireAffector.cpp:35
RoR::Console::CONSOLE_MSGTYPE_INFO
@ CONSOLE_MSGTYPE_INFO
Generic message.
Definition: Console.h:60
RoR::ProceduralManager::getNumObjects
int getNumObjects()
Definition: ProceduralManager.h:91
RoR
Definition: AppContext.h:36
RoR::EV_COMMON_REMOVE_CURRENT_TRUCK
@ EV_COMMON_REMOVE_CURRENT_TRUCK
remove current truck
Definition: InputEngine.h:232
RoR::EV_COMMON_RESCUE_TRUCK
@ EV_COMMON_RESCUE_TRUCK
teleport to rescue truck
Definition: InputEngine.h:256
RoR::EV_TRUCK_BRAKE
@ EV_TRUCK_BRAKE
brake
Definition: InputEngine.h:306
RoR::GameContext::GetTerrain
const TerrainPtr & GetTerrain()
Definition: GameContext.h:117