mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-14 01:57:58 +01:00
refactor(editor): the trainset is a tool of its own
The fourth tool out of editor_mode. The track under the cursor and the first steps of the tutorial become types of their own, which the editor gives to the tools, and a tool shown as a tab of the lineside panel keeps its open and expanded flags in a tool_tab. The trainsets waiting for the save are handed to the editor by the tool, which hears back when they were written. The self-test command trainset moves with it.
This commit is contained in:
@@ -1286,9 +1286,8 @@ bool editor_mode::update()
|
|||||||
{
|
{
|
||||||
Global.editor_tracks = (current_work_area() == work_area::tracks);
|
Global.editor_tracks = (current_work_area() == work_area::tracks);
|
||||||
selftest_step();
|
selftest_step();
|
||||||
if (m_vehicle.leave)
|
if (m_vehicle.take_leave())
|
||||||
{
|
{
|
||||||
m_vehicle.leave = false;
|
|
||||||
Application.pop_mode();
|
Application.pop_mode();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1456,7 +1455,7 @@ bool editor_mode::update()
|
|||||||
{
|
{
|
||||||
draw_hekto_overlay();
|
draw_hekto_overlay();
|
||||||
draw_fouling_overlay();
|
draw_fouling_overlay();
|
||||||
draw_vehicle_marker();
|
m_vehicle.draw_overlay();
|
||||||
}
|
}
|
||||||
render_track_context();
|
render_track_context();
|
||||||
update_build_tools();
|
update_build_tools();
|
||||||
@@ -2937,13 +2936,7 @@ bool editor_mode::save()
|
|||||||
auto const controls{turntable_controls(rootstatements)};
|
auto const controls{turntable_controls(rootstatements)};
|
||||||
auto const noses{nose_controls(rootstatements)};
|
auto const noses{nose_controls(rootstatements)};
|
||||||
std::vector<std::string> trailing;
|
std::vector<std::string> trailing;
|
||||||
std::erase_if(m_vehicle.trainsets, [](auto const &Trainset) {
|
auto const placed{m_vehicle.trainset_lines(trailing)};
|
||||||
auto const *track{simulation::Paths.find(Trainset.track)};
|
|
||||||
return track == nullptr || track->m_editorremoved;
|
|
||||||
});
|
|
||||||
auto const placed{m_vehicle.trainsets.size()};
|
|
||||||
for (auto const &trainset : m_vehicle.trainsets)
|
|
||||||
trailing.insert(trailing.end(), trainset.lines.begin(), trainset.lines.end());
|
|
||||||
if (placed == 0)
|
if (placed == 0)
|
||||||
starter_trainset(trailing);
|
starter_trainset(trailing);
|
||||||
auto const result = scene::Layers.save(rootstatements, trailing);
|
auto const result = scene::Layers.save(rootstatements, trailing);
|
||||||
@@ -2952,10 +2945,7 @@ bool editor_mode::save()
|
|||||||
if (result.success && noses)
|
if (result.success && noses)
|
||||||
m_nose_included = true;
|
m_nose_included = true;
|
||||||
if (result.success && placed > 0)
|
if (result.success && placed > 0)
|
||||||
{
|
m_vehicle.trainsets_written();
|
||||||
m_vehicle.trainsets.clear();
|
|
||||||
m_vehicle.status = format(STR_C("%d trainset(s) written to the scenery"), static_cast<int>(placed));
|
|
||||||
}
|
|
||||||
if (result.success && placed == 0 && trailing.size() == 3)
|
if (result.success && placed == 0 && trailing.size() == 3)
|
||||||
{
|
{
|
||||||
std::istringstream header{trailing.front()};
|
std::istringstream header{trailing.front()};
|
||||||
@@ -5301,12 +5291,12 @@ void editor_mode::render_first_steps()
|
|||||||
}
|
}
|
||||||
case trial::trainset:
|
case trial::trainset:
|
||||||
{
|
{
|
||||||
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::lineside && m_vehicle.open);
|
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::lineside && m_vehicle.tab().open);
|
||||||
if (ImGui::Button(STR_C("The trainset tool")))
|
if (ImGui::Button(STR_C("The trainset tool")))
|
||||||
{
|
{
|
||||||
choose_work_area(work_area::tracks);
|
choose_work_area(work_area::tracks);
|
||||||
show_track_tab(track_tab::lineside);
|
show_track_tab(track_tab::lineside);
|
||||||
m_vehicle.expand = true;
|
m_vehicle.tab().expand = true;
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "application/editormodegauge.h"
|
#include "application/editormodegauge.h"
|
||||||
#include "application/editormodejoints.h"
|
#include "application/editormodejoints.h"
|
||||||
#include "application/editormodespeed.h"
|
#include "application/editormodespeed.h"
|
||||||
|
#include "application/editormodevehicle.h"
|
||||||
#include "application/editortool.h"
|
#include "application/editortool.h"
|
||||||
#include "scene/sceneeditor.h"
|
#include "scene/sceneeditor.h"
|
||||||
#include "scene/scenenode.h"
|
#include "scene/scenenode.h"
|
||||||
@@ -55,12 +56,6 @@ class TAnimModel;
|
|||||||
// a tool of a field of work of the editor, a button in the toolbar and over the 3d view
|
// a tool of a field of work of the editor, a button in the toolbar and over the 3d view
|
||||||
struct editor_tool_button;
|
struct editor_tool_button;
|
||||||
class TTrack;
|
class TTrack;
|
||||||
namespace ui
|
|
||||||
{
|
|
||||||
class vehicles_bank;
|
|
||||||
struct vehicle_desc;
|
|
||||||
struct skin_set;
|
|
||||||
}
|
|
||||||
|
|
||||||
class editor_mode : public application_mode, private editor_track::observer, private editor_services
|
class editor_mode : public application_mode, private editor_track::observer, private editor_services
|
||||||
{
|
{
|
||||||
@@ -240,9 +235,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
void render_help_menu();
|
void render_help_menu();
|
||||||
void render_shortcuts_window();
|
void render_shortcuts_window();
|
||||||
bool m_shortcuts_open{false};
|
bool m_shortcuts_open{false};
|
||||||
enum class first_step { tracks, lay, laid, wheel, join, turnout, undo, save, drive, look, top, select, shape, profile, profile_point, profile_apply, terrain, nmt, plan, plan_band, plan_apply, signal, posts, count };
|
using first_step = editor_first_step;
|
||||||
void render_first_steps();
|
void render_first_steps();
|
||||||
void first_step_done(first_step const Step);
|
void first_step_done(first_step const Step) override;
|
||||||
bool m_first_steps_open{false};
|
bool m_first_steps_open{false};
|
||||||
std::array<bool, static_cast<std::size_t>(first_step::count)> m_first_steps_done{};
|
std::array<bool, static_cast<std::size_t>(first_step::count)> m_first_steps_done{};
|
||||||
int m_tutorial_page{0};
|
int m_tutorial_page{0};
|
||||||
@@ -718,6 +713,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
bool track_editing() const override;
|
bool track_editing() const override;
|
||||||
std::size_t history_size() const override;
|
std::size_t history_size() const override;
|
||||||
glm::dvec3 camera_position() const override;
|
glm::dvec3 camera_position() const override;
|
||||||
|
track_hover const &hovered_track() const override;
|
||||||
void render_path_ui();
|
void render_path_ui();
|
||||||
void draw_track_overlay() const;
|
void draw_track_overlay() const;
|
||||||
editor_track::point_ref track_handle_hit() const;
|
editor_track::point_ref track_handle_hit() const;
|
||||||
@@ -1516,13 +1512,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
// a scenery with no tracks yet: in the middle of the view, how the first one is laid
|
// a scenery with no tracks yet: in the middle of the view, how the first one is laid
|
||||||
void draw_empty_scenery_hint();
|
void draw_empty_scenery_hint();
|
||||||
// path under the cursor, outlined before a click so it's known which one the click takes
|
// path under the cursor, outlined before a click so it's known which one the click takes
|
||||||
struct track_hover
|
using track_hover = ::track_hover;
|
||||||
{
|
|
||||||
TTrack *track{nullptr};
|
|
||||||
int path{0};
|
|
||||||
glm::dvec3 point{0.0};
|
|
||||||
double since{0.0};
|
|
||||||
};
|
|
||||||
track_hover m_hover;
|
track_hover m_hover;
|
||||||
track_hover track_under_cursor(TTrack const *Only = nullptr, float const Pixels = 0.0f) const;
|
track_hover track_under_cursor(TTrack const *Only = nullptr, float const Pixels = 0.0f) const;
|
||||||
track_hover split_spot() const;
|
track_hover split_spot() const;
|
||||||
@@ -1925,49 +1915,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
void render_fouling_ui();
|
void render_fouling_ui();
|
||||||
void draw_fouling_overlay() const;
|
void draw_fouling_overlay() const;
|
||||||
|
|
||||||
// a trainset put on the selected path, written to the scenery on save, or only to be driven
|
|
||||||
struct vehicle_tool
|
|
||||||
{
|
|
||||||
bool open{false};
|
|
||||||
bool expand{false};
|
|
||||||
std::shared_ptr<ui::vehicles_bank> bank;
|
|
||||||
char search[64]{};
|
|
||||||
bool controllable_only{true};
|
|
||||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
|
||||||
std::shared_ptr<ui::skin_set> skin;
|
|
||||||
int driver{0}; // 0: a driver, to be driven; 1: nobody, parked
|
|
||||||
TTrack *track{nullptr};
|
|
||||||
glm::dvec3 point{0.0};
|
|
||||||
std::string placed;
|
|
||||||
std::string status;
|
|
||||||
bool leave{false}; // the editor gives way to the driving at the start of the next frame
|
|
||||||
struct consist_vehicle
|
|
||||||
{
|
|
||||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
|
||||||
std::shared_ptr<ui::skin_set> skin;
|
|
||||||
bool turned{false};
|
|
||||||
};
|
|
||||||
std::vector<consist_vehicle> consist;
|
|
||||||
int picked{-1}; // vehicle of the train whose buttons are shown
|
|
||||||
std::set<ui::skin_set const *> minis; // skins whose side view was asked for
|
|
||||||
int facing{1};
|
|
||||||
bool write{true};
|
|
||||||
char timetable[64]{"none"};
|
|
||||||
double velocity{0.0};
|
|
||||||
struct trainset
|
|
||||||
{
|
|
||||||
std::string head;
|
|
||||||
std::string track;
|
|
||||||
std::vector<std::string> lines;
|
|
||||||
};
|
|
||||||
std::vector<trainset> trainsets;
|
|
||||||
};
|
|
||||||
vehicle_tool m_vehicle;
|
|
||||||
void vehicle_start(TTrack &Track, glm::dvec3 const &Point);
|
|
||||||
bool vehicle_place();
|
|
||||||
void render_vehicle_ui();
|
|
||||||
void draw_vehicle_marker() const;
|
|
||||||
|
|
||||||
struct signal_template
|
struct signal_template
|
||||||
{
|
{
|
||||||
std::string file;
|
std::string file;
|
||||||
@@ -2445,7 +2392,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
|||||||
gauge_tool m_gauge{*this};
|
gauge_tool m_gauge{*this};
|
||||||
speed_tool m_speed{*this};
|
speed_tool m_speed{*this};
|
||||||
joints_tool m_joints{*this};
|
joints_tool m_joints{*this};
|
||||||
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints};
|
vehicle_tool m_vehicle{*this};
|
||||||
|
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints, &m_vehicle};
|
||||||
|
|
||||||
void infra_rebase();
|
void infra_rebase();
|
||||||
void render_infra_search();
|
void render_infra_search();
|
||||||
|
|||||||
@@ -293,29 +293,6 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm
|
|||||||
WriteLog(format("SELFTEST mapstate orthophoto %d top %d extent %.0f mark %s camera %.1f %.1f %.1f", m_orthophoto.enabled() ? 1 : 0, Global.EditorOrtho ? 1 : 0, Global.EditorOrthoExtent, marked.empty() ? "-" : marked.front().c_str(), Camera.Pos.x, Camera.Pos.y, Camera.Pos.z));
|
WriteLog(format("SELFTEST mapstate orthophoto %d top %d extent %.0f mark %s camera %.1f %.1f %.1f", m_orthophoto.enabled() ? 1 : 0, Global.EditorOrtho ? 1 : 0, Global.EditorOrthoExtent, marked.empty() ? "-" : marked.front().c_str(), Camera.Pos.x, Camera.Pos.y, Camera.Pos.z));
|
||||||
return selftest_result::handled;
|
return selftest_result::handled;
|
||||||
}
|
}
|
||||||
if (command == "trainset")
|
|
||||||
{
|
|
||||||
std::string name;
|
|
||||||
std::string vehicle;
|
|
||||||
std::string skin;
|
|
||||||
int facing{1};
|
|
||||||
words >> name >> vehicle >> skin >> facing >> m_vehicle.velocity;
|
|
||||||
auto *track{simulation::Paths.find(name)};
|
|
||||||
if (track == nullptr)
|
|
||||||
return selftest_result::handled;
|
|
||||||
auto desc{std::make_shared<ui::vehicle_desc>()};
|
|
||||||
desc->path = vehicle;
|
|
||||||
auto set{std::make_shared<ui::skin_set>()};
|
|
||||||
set->skin = skin;
|
|
||||||
m_vehicle.consist.clear();
|
|
||||||
m_vehicle.vehicle = desc;
|
|
||||||
m_vehicle.skin = set;
|
|
||||||
vehicle_start(*track, geometry::bezier{track->m_paths.front()}.point(0.5));
|
|
||||||
m_vehicle.facing = facing;
|
|
||||||
auto const placed{vehicle_place()};
|
|
||||||
WriteLog(format("SELFTEST trainset %s placed %d pending %d: %s", name.c_str(), placed ? 1 : 0, static_cast<int>(m_vehicle.trainsets.size()), m_vehicle.status.c_str()));
|
|
||||||
return selftest_result::handled;
|
|
||||||
}
|
|
||||||
if (command == "selectmodel")
|
if (command == "selectmodel")
|
||||||
{
|
{
|
||||||
glm::dvec3 point{0.0};
|
glm::dvec3 point{0.0};
|
||||||
|
|||||||
@@ -388,7 +388,7 @@ editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &comm
|
|||||||
std::string tab;
|
std::string tab;
|
||||||
words >> tab;
|
words >> tab;
|
||||||
show_track_tab(tab == "parallel" ? track_tab::parallel : track_tab::lineside);
|
show_track_tab(tab == "parallel" ? track_tab::parallel : track_tab::lineside);
|
||||||
(tab == "vehicle" ? m_vehicle.expand : tab == "hekto" ? m_hekto.expand : tab == "fouling" ? m_fouling.expand : m_parallel.expand) = true;
|
(tab == "vehicle" ? m_vehicle.tab().expand : tab == "hekto" ? m_hekto.expand : tab == "fouling" ? m_fouling.expand : m_parallel.expand) = true;
|
||||||
return selftest_result::handled;
|
return selftest_result::handled;
|
||||||
}
|
}
|
||||||
if (command == "bendpanel")
|
if (command == "bendpanel")
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ editor_mode::selftest_result editor_mode::selftest_track(std::string const &comm
|
|||||||
m_hekto.expand = tab == 1;
|
m_hekto.expand = tab == 1;
|
||||||
m_fouling.expand = tab == 2;
|
m_fouling.expand = tab == 2;
|
||||||
m_parallel.expand = tab == 3;
|
m_parallel.expand = tab == 3;
|
||||||
m_vehicle.expand = tab == 4;
|
m_vehicle.tab().expand = tab == 4;
|
||||||
return selftest_result::handled;
|
return selftest_result::handled;
|
||||||
}
|
}
|
||||||
if (command == "curve")
|
if (command == "curve")
|
||||||
|
|||||||
@@ -67,6 +67,11 @@ glm::dvec3 editor_mode::camera_position() const
|
|||||||
return Camera.Pos;
|
return Camera.Pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editor_mode::track_hover const &editor_mode::hovered_track() const
|
||||||
|
{
|
||||||
|
return m_hover;
|
||||||
|
}
|
||||||
|
|
||||||
void editor_mode::set_current_node(scene::basic_node *Node)
|
void editor_mode::set_current_node(scene::basic_node *Node)
|
||||||
{
|
{
|
||||||
m_node = Node;
|
m_node = Node;
|
||||||
@@ -554,7 +559,7 @@ void editor_mode::render_track_inspector()
|
|||||||
m_hekto.open = false;
|
m_hekto.open = false;
|
||||||
m_fouling.open = false;
|
m_fouling.open = false;
|
||||||
m_parallel.open = false;
|
m_parallel.open = false;
|
||||||
m_vehicle.open = false;
|
m_vehicle.tab().open = false;
|
||||||
}
|
}
|
||||||
ui()->set_track(m_track_window_open);
|
ui()->set_track(m_track_window_open);
|
||||||
if (false == m_track_window_open)
|
if (false == m_track_window_open)
|
||||||
|
|||||||
@@ -793,7 +793,7 @@ void editor_mode::render_track_context()
|
|||||||
if (ImGui::MenuItem(STR_C("Place a vehicle here")))
|
if (ImGui::MenuItem(STR_C("Place a vehicle here")))
|
||||||
{
|
{
|
||||||
show_track_tab(track_tab::lineside);
|
show_track_tab(track_tab::lineside);
|
||||||
vehicle_start(*track, point);
|
m_vehicle.start(*track, point);
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem(STR_C("Hectometre posts from here")))
|
if (ImGui::MenuItem(STR_C("Hectometre posts from here")))
|
||||||
{
|
{
|
||||||
@@ -1479,7 +1479,7 @@ void editor_mode::render_lineside_ui()
|
|||||||
std::array<tab, 3> const tabs{{
|
std::array<tab, 3> const tabs{{
|
||||||
{"Hectometre posts", &m_hekto.open, &m_hekto.expand, [this]() { render_hekto_ui(); }},
|
{"Hectometre posts", &m_hekto.open, &m_hekto.expand, [this]() { render_hekto_ui(); }},
|
||||||
{"Fouling points", &m_fouling.open, &m_fouling.expand, [this]() { render_fouling_ui(); }},
|
{"Fouling points", &m_fouling.open, &m_fouling.expand, [this]() { render_fouling_ui(); }},
|
||||||
{"Trainset", &m_vehicle.open, &m_vehicle.expand, [this]() { render_vehicle_ui(); }},
|
{"Trainset", &m_vehicle.tab().open, &m_vehicle.tab().expand, [this]() { m_vehicle.render_options(); }},
|
||||||
}};
|
}};
|
||||||
if (selected_track() == nullptr)
|
if (selected_track() == nullptr)
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: the line the objects go along"));
|
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: the line the objects go along"));
|
||||||
|
|||||||
@@ -8,8 +8,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "application/editormode.h"
|
#include "application/editormodevehicle.h"
|
||||||
#include "application/editoruilayer.h"
|
|
||||||
#include "application/editorprojection.h"
|
#include "application/editorprojection.h"
|
||||||
#include "application/editormodeshared.h"
|
#include "application/editormodeshared.h"
|
||||||
#include "application/application.h"
|
#include "application/application.h"
|
||||||
@@ -154,18 +153,18 @@ double distance_along(TTrack const &Track, int const Path, glm::dvec3 const &Poi
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void editor_mode::vehicle_start(TTrack &Track, glm::dvec3 const &Point)
|
void vehicle_tool::start(TTrack &Track, glm::dvec3 const &Point)
|
||||||
{
|
{
|
||||||
m_vehicle.track = &Track;
|
m_vehicle.track = &Track;
|
||||||
m_vehicle.point = Point;
|
m_vehicle.point = Point;
|
||||||
m_vehicle.expand = true;
|
m_tab.expand = true;
|
||||||
m_vehicle.status.clear();
|
m_vehicle.status.clear();
|
||||||
auto const heading{heading_at(Track, Track.eType == tt_Switch ? path_under(Track, Point) : 0, Point)};
|
auto const heading{heading_at(Track, Track.eType == tt_Switch ? path_under(Track, Point) : 0, Point)};
|
||||||
glm::dvec2 const away{Point.x - Global.pCamera.Pos.x, Point.z - Global.pCamera.Pos.z};
|
glm::dvec2 const away{Point.x - Global.pCamera.Pos.x, Point.z - Global.pCamera.Pos.z};
|
||||||
m_vehicle.facing = glm::dot(heading, away) >= 0.0 ? 1 : -1;
|
m_vehicle.facing = glm::dot(heading, away) >= 0.0 ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool editor_mode::vehicle_place()
|
bool vehicle_tool::place()
|
||||||
{
|
{
|
||||||
auto &tool{m_vehicle};
|
auto &tool{m_vehicle};
|
||||||
if (tool.track == nullptr || tool.track->m_editorremoved)
|
if (tool.track == nullptr || tool.track->m_editorremoved)
|
||||||
@@ -210,7 +209,7 @@ bool editor_mode::vehicle_place()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tool.placed = head;
|
tool.placed = head;
|
||||||
first_step_done(first_step::drive);
|
m_services.first_step_done(editor_first_step::drive);
|
||||||
auto const trackname{tool.track->name().empty() ? std::string{STR("(no name)")} : tool.track->name()};
|
auto const trackname{tool.track->name().empty() ? std::string{STR("(no name)")} : tool.track->name()};
|
||||||
auto const behind{static_cast<int>(vehicles.size()) - 1};
|
auto const behind{static_cast<int>(vehicles.size()) - 1};
|
||||||
tool.status = behind > 0 ? format(STR_P("%s and %d vehicle behind it stand on %s", "%s and %d vehicles behind it stand on %s", behind), head.c_str(), behind, trackname.c_str()) : format(STR_C("%s stands on %s"), head.c_str(), trackname.c_str());
|
tool.status = behind > 0 ? format(STR_P("%s and %d vehicle behind it stand on %s", "%s and %d vehicles behind it stand on %s", behind), head.c_str(), behind, trackname.c_str()) : format(STR_C("%s stands on %s"), head.c_str(), trackname.c_str());
|
||||||
@@ -220,7 +219,7 @@ bool editor_mode::vehicle_place()
|
|||||||
{
|
{
|
||||||
std::string timetable{tool.timetable};
|
std::string timetable{tool.timetable};
|
||||||
timetable.erase(std::remove_if(timetable.begin(), timetable.end(), [](unsigned char const Character) { return std::isspace(Character) != 0; }), timetable.end());
|
timetable.erase(std::remove_if(timetable.begin(), timetable.end(), [](unsigned char const Character) { return std::isspace(Character) != 0; }), timetable.end());
|
||||||
vehicle_tool::trainset entry{head, tool.track->name(), {}};
|
vehicle_state::trainset entry{head, tool.track->name(), {}};
|
||||||
entry.lines.push_back("trainset " + (timetable.empty() ? std::string{"none"} : timetable) + " " + tool.track->name() + " " + to_string(offset, 2) + " " + to_string(tool.velocity, 0));
|
entry.lines.push_back("trainset " + (timetable.empty() ? std::string{"none"} : timetable) + " " + tool.track->name() + " " + to_string(offset, 2) + " " + to_string(tool.velocity, 0));
|
||||||
if (against)
|
if (against)
|
||||||
entry.lines.push_back("reversed");
|
entry.lines.push_back("reversed");
|
||||||
@@ -238,14 +237,15 @@ bool editor_mode::vehicle_place()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_mode::render_vehicle_ui()
|
void vehicle_tool::render_options()
|
||||||
{
|
{
|
||||||
auto &tool{m_vehicle};
|
auto &tool{m_vehicle};
|
||||||
auto *selected{selected_track()};
|
auto *selected{m_services.selected_track()};
|
||||||
if (selected != nullptr && selected == tool.track && m_hover.track == selected && ImGui::IsMouseClicked(0) && false == ImGui::GetIO().WantCaptureMouse)
|
auto const &hover{m_services.hovered_track()};
|
||||||
vehicle_start(*selected, m_hover.point);
|
if (selected != nullptr && selected == tool.track && hover.track == selected && ImGui::IsMouseClicked(0) && false == ImGui::GetIO().WantCaptureMouse)
|
||||||
|
start(*selected, hover.point);
|
||||||
else if (selected != nullptr && selected != tool.track)
|
else if (selected != nullptr && selected != tool.track)
|
||||||
vehicle_start(*selected, m_hover.track == selected ? m_hover.point : bezier{selected->m_paths.front()}.point(0.5));
|
start(*selected, hover.track == selected ? hover.point : bezier{selected->m_paths.front()}.point(0.5));
|
||||||
if (tool.track == nullptr)
|
if (tool.track == nullptr)
|
||||||
{
|
{
|
||||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: where the vehicle stands"));
|
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: where the vehicle stands"));
|
||||||
@@ -430,11 +430,11 @@ void editor_mode::render_vehicle_ui()
|
|||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.55f, 0.25f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.55f, 0.25f, 1.0f));
|
||||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.65f, 0.3f, 1.0f));
|
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.65f, 0.3f, 1.0f));
|
||||||
if (ImGui::Button(STR_C("Place"), ImVec2(half, tall)))
|
if (ImGui::Button(STR_C("Place"), ImVec2(half, tall)))
|
||||||
vehicle_place();
|
place();
|
||||||
item_tooltip("A trainset on the track, placed where the track was clicked, or in the middle of the path");
|
item_tooltip("A trainset on the track, placed where the track was clicked, or in the middle of the path");
|
||||||
ImGui::PopStyleColor(2);
|
ImGui::PopStyleColor(2);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
if (ImGui::Button(STR_C("Place and drive"), ImVec2(-1.0f, tall)) && vehicle_place())
|
if (ImGui::Button(STR_C("Place and drive"), ImVec2(-1.0f, tall)) && place())
|
||||||
{
|
{
|
||||||
Global.editor_enter_vehicle = tool.placed;
|
Global.editor_enter_vehicle = tool.placed;
|
||||||
tool.leave = true;
|
tool.leave = true;
|
||||||
@@ -461,10 +461,10 @@ void editor_mode::render_vehicle_ui()
|
|||||||
tool.trainsets.erase(tool.trainsets.begin() + static_cast<std::ptrdiff_t>(*drop));
|
tool.trainsets.erase(tool.trainsets.begin() + static_cast<std::ptrdiff_t>(*drop));
|
||||||
}
|
}
|
||||||
|
|
||||||
void editor_mode::draw_vehicle_marker() const
|
void vehicle_tool::draw_overlay() const
|
||||||
{
|
{
|
||||||
auto const &tool{m_vehicle};
|
auto const &tool{m_vehicle};
|
||||||
if (false == tool.open || tool.track == nullptr)
|
if (false == m_tab.open || tool.track == nullptr)
|
||||||
return;
|
return;
|
||||||
screen_projection const projection;
|
screen_projection const projection;
|
||||||
ImVec2 screen;
|
ImVec2 screen;
|
||||||
@@ -490,3 +490,53 @@ void editor_mode::draw_vehicle_marker() const
|
|||||||
ImVec2 const side{-unit.y, unit.x};
|
ImVec2 const side{-unit.y, unit.x};
|
||||||
drawlist->AddTriangleFilled(ImVec2(end.x + unit.x * 10.0f, end.y + unit.y * 10.0f), ImVec2(end.x + side.x * 7.0f, end.y + side.y * 7.0f), ImVec2(end.x - side.x * 7.0f, end.y - side.y * 7.0f), colour);
|
drawlist->AddTriangleFilled(ImVec2(end.x + unit.x * 10.0f, end.y + unit.y * 10.0f), ImVec2(end.x + side.x * 7.0f, end.y + side.y * 7.0f), ImVec2(end.x - side.x * 7.0f, end.y - side.y * 7.0f), colour);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool vehicle_tool::take_leave()
|
||||||
|
{
|
||||||
|
return std::exchange(m_vehicle.leave, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t vehicle_tool::trainset_lines(std::vector<std::string> &Lines)
|
||||||
|
{
|
||||||
|
std::erase_if(m_vehicle.trainsets, [](auto const &Trainset) {
|
||||||
|
auto const *track{simulation::Paths.find(Trainset.track)};
|
||||||
|
return track == nullptr || track->m_editorremoved;
|
||||||
|
});
|
||||||
|
for (auto const &trainset : m_vehicle.trainsets)
|
||||||
|
Lines.insert(Lines.end(), trainset.lines.begin(), trainset.lines.end());
|
||||||
|
return m_vehicle.trainsets.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vehicle_tool::trainsets_written()
|
||||||
|
{
|
||||||
|
m_vehicle.status = format(STR_C("%d trainset(s) written to the scenery"), static_cast<int>(m_vehicle.trainsets.size()));
|
||||||
|
m_vehicle.trainsets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
editor_selftest_result vehicle_tool::selftest(std::string const &Command, std::istringstream &Words)
|
||||||
|
{
|
||||||
|
if (Command == "trainset")
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string vehicle;
|
||||||
|
std::string skin;
|
||||||
|
int facing{1};
|
||||||
|
Words >> name >> vehicle >> skin >> facing >> m_vehicle.velocity;
|
||||||
|
auto *track{simulation::Paths.find(name)};
|
||||||
|
if (track == nullptr)
|
||||||
|
return editor_selftest_result::handled;
|
||||||
|
auto desc{std::make_shared<ui::vehicle_desc>()};
|
||||||
|
desc->path = vehicle;
|
||||||
|
auto set{std::make_shared<ui::skin_set>()};
|
||||||
|
set->skin = skin;
|
||||||
|
m_vehicle.consist.clear();
|
||||||
|
m_vehicle.vehicle = desc;
|
||||||
|
m_vehicle.skin = set;
|
||||||
|
start(*track, geometry::bezier{track->m_paths.front()}.point(0.5));
|
||||||
|
m_vehicle.facing = facing;
|
||||||
|
auto const placed{place()};
|
||||||
|
WriteLog(format("SELFTEST trainset %s placed %d pending %d: %s", name.c_str(), placed ? 1 : 0, static_cast<int>(m_vehicle.trainsets.size()), m_vehicle.status.c_str()));
|
||||||
|
return editor_selftest_result::handled;
|
||||||
|
}
|
||||||
|
return editor_selftest_result::unhandled;
|
||||||
|
}
|
||||||
|
|||||||
79
application/editormodevehicle.h
Normal file
79
application/editormodevehicle.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
This Source Code Form is subject to the
|
||||||
|
terms of the Mozilla Public License, v.
|
||||||
|
2.0. If a copy of the MPL was not
|
||||||
|
distributed with this file, You can
|
||||||
|
obtain one at
|
||||||
|
http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "application/editortool.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
class vehicles_bank;
|
||||||
|
struct vehicle_desc;
|
||||||
|
struct skin_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
// a trainset put on the selected path, written to the scenery on save, or only to be driven
|
||||||
|
class vehicle_tool final : public editor_tool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit vehicle_tool(editor_services &Services) : m_services{Services} {}
|
||||||
|
void draw_overlay() const override;
|
||||||
|
void render_options() override;
|
||||||
|
editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) override;
|
||||||
|
tool_tab &tab() { return m_tab; }
|
||||||
|
void start(TTrack &Track, glm::dvec3 const &Point);
|
||||||
|
bool take_leave();
|
||||||
|
std::size_t trainset_lines(std::vector<std::string> &Lines);
|
||||||
|
void trainsets_written();
|
||||||
|
|
||||||
|
private:
|
||||||
|
editor_services &m_services;
|
||||||
|
tool_tab m_tab;
|
||||||
|
struct vehicle_state
|
||||||
|
{
|
||||||
|
std::shared_ptr<ui::vehicles_bank> bank;
|
||||||
|
char search[64]{};
|
||||||
|
bool controllable_only{true};
|
||||||
|
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||||
|
std::shared_ptr<ui::skin_set> skin;
|
||||||
|
int driver{0}; // 0: a driver, to be driven; 1: nobody, parked
|
||||||
|
TTrack *track{nullptr};
|
||||||
|
glm::dvec3 point{0.0};
|
||||||
|
std::string placed;
|
||||||
|
std::string status;
|
||||||
|
bool leave{false}; // the editor gives way to the driving at the start of the next frame
|
||||||
|
struct consist_vehicle
|
||||||
|
{
|
||||||
|
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||||
|
std::shared_ptr<ui::skin_set> skin;
|
||||||
|
bool turned{false};
|
||||||
|
};
|
||||||
|
std::vector<consist_vehicle> consist;
|
||||||
|
int picked{-1}; // vehicle of the train whose buttons are shown
|
||||||
|
std::set<ui::skin_set const *> minis; // skins whose side view was asked for
|
||||||
|
int facing{1};
|
||||||
|
bool write{true};
|
||||||
|
char timetable[64]{"none"};
|
||||||
|
double velocity{0.0};
|
||||||
|
struct trainset
|
||||||
|
{
|
||||||
|
std::string head;
|
||||||
|
std::string track;
|
||||||
|
std::vector<std::string> lines;
|
||||||
|
};
|
||||||
|
std::vector<trainset> trainsets;
|
||||||
|
};
|
||||||
|
vehicle_state m_vehicle;
|
||||||
|
bool place();
|
||||||
|
};
|
||||||
@@ -160,7 +160,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
|||||||
}
|
}
|
||||||
case work_area::tracks:
|
case work_area::tracks:
|
||||||
{
|
{
|
||||||
auto const vehicle{m_track_tab == track_tab::lineside && m_vehicle.open};
|
auto const vehicle{m_track_tab == track_tab::lineside && m_vehicle.tab().open};
|
||||||
auto const add = [&](track_tab const Tab, bool const Group) {
|
auto const add = [&](track_tab const Tab, bool const Group) {
|
||||||
auto const &modes{track_modes()};
|
auto const &modes{track_modes()};
|
||||||
auto const found{std::find_if(modes.begin(), modes.end(), [&](track_mode const &Mode) { return Mode.tab == Tab; })};
|
auto const found{std::find_if(modes.begin(), modes.end(), [&](track_mode const &Mode) { return Mode.tab == Tab; })};
|
||||||
@@ -191,7 +191,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
|||||||
add(track_tab::lineside, false);
|
add(track_tab::lineside, false);
|
||||||
Buttons.push_back({icon::vehicle, STR_C("Trainset"), nullptr, STR_C("A trainset on the selected track: written to the scenery on save, and to drive at once"), vehicle, [this, vehicle]() {
|
Buttons.push_back({icon::vehicle, STR_C("Trainset"), nullptr, STR_C("A trainset on the selected track: written to the scenery on save, and to drive at once"), vehicle, [this, vehicle]() {
|
||||||
show_track_tab(vehicle ? track_tab::path : track_tab::lineside);
|
show_track_tab(vehicle ? track_tab::path : track_tab::lineside);
|
||||||
m_vehicle.expand = false == vehicle;
|
m_vehicle.tab().expand = false == vehicle;
|
||||||
}});
|
}});
|
||||||
Buttons.back().accent = family_colour(1);
|
Buttons.back().accent = family_colour(1);
|
||||||
add(track_tab::profile, true);
|
add(track_tab::profile, true);
|
||||||
|
|||||||
@@ -34,6 +34,22 @@ enum class editor_selftest_result
|
|||||||
again
|
again
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class editor_first_step { tracks, lay, laid, wheel, join, turnout, undo, save, drive, look, top, select, shape, profile, profile_point, profile_apply, terrain, nmt, plan, plan_band, plan_apply, signal, posts, count };
|
||||||
|
|
||||||
|
struct track_hover
|
||||||
|
{
|
||||||
|
TTrack *track{nullptr};
|
||||||
|
int path{0};
|
||||||
|
glm::dvec3 point{0.0};
|
||||||
|
double since{0.0};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tool_tab
|
||||||
|
{
|
||||||
|
bool open{false};
|
||||||
|
bool expand{false};
|
||||||
|
};
|
||||||
|
|
||||||
struct nmt_place
|
struct nmt_place
|
||||||
{
|
{
|
||||||
glm::dvec3 position{0.0}; // on the axis of the path
|
glm::dvec3 position{0.0}; // on the axis of the path
|
||||||
@@ -52,6 +68,8 @@ class editor_services
|
|||||||
virtual bool track_editing() const = 0;
|
virtual bool track_editing() const = 0;
|
||||||
virtual std::size_t history_size() const = 0;
|
virtual std::size_t history_size() const = 0;
|
||||||
virtual glm::dvec3 camera_position() const = 0;
|
virtual glm::dvec3 camera_position() const = 0;
|
||||||
|
virtual track_hover const &hovered_track() const = 0;
|
||||||
|
virtual void first_step_done(editor_first_step const Step) = 0;
|
||||||
virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0;
|
virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0;
|
||||||
virtual void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point) = 0;
|
virtual void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point) = 0;
|
||||||
virtual void set_current_node(scene::basic_node *Node) = 0;
|
virtual void set_current_node(scene::basic_node *Node) = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user