mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-26 15:54:53 +01:00
refactor(editor): the structure gauge is a tool of its own
The first step of taking the tools out of editor_mode: a tool keeps its own state and reaches the editor through editor_services, the few things it needs from it, instead of through every member of the editor. The editor holds its tools in a list for the hooks they share: a deleted node is forgotten by all of them in one place, and a self-test command the editor doesn't know goes to each of them. The gauge moves with its state, its window and its self-test command; the ImGui ids and the texts stay the same, and the self-test gives the same hits on the test scenery as before.
This commit is contained in:
@@ -873,6 +873,8 @@ void editor_mode::nullify_history_pointers(scene::basic_node *node)
|
||||
if (ui()->node() == node)
|
||||
ui()->set_node(nullptr);
|
||||
infra_forget(node);
|
||||
for (auto *tool : m_tools)
|
||||
tool->forget(node);
|
||||
|
||||
auto const followed = [node](infra::object_state const &State) { return State.saved.node == node; };
|
||||
for (auto &s : m_history)
|
||||
@@ -1480,8 +1482,8 @@ bool editor_mode::update()
|
||||
bend_drag_update();
|
||||
draw_bend_overlay();
|
||||
}
|
||||
update_gauge();
|
||||
render_gauge_window();
|
||||
m_gauge.update();
|
||||
m_gauge.render_windows();
|
||||
|
||||
// roads: trajectories of the lanes, and the tools of the road window
|
||||
update_road_tool();
|
||||
@@ -3549,8 +3551,8 @@ void editor_mode::render_view_menu()
|
||||
ImGui::MenuItem(STR_C("Show lanes"), nullptr, &m_roadtool.lanes);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", STR_C("The lanes of the roads drawn as the paths the vehicles take"));
|
||||
if (ImGui::MenuItem(STR_C("Structure gauge"), nullptr, m_gauge.open))
|
||||
m_gauge.open = !m_gauge.open;
|
||||
if (ImGui::MenuItem(STR_C("Structure gauge"), nullptr, m_gauge.is_open()))
|
||||
m_gauge.toggle();
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)"));
|
||||
ImGui::Separator();
|
||||
|
||||
@@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "input/editormouseinput.h"
|
||||
#include "input/editorkeyboardinput.h"
|
||||
#include "vehicle/Camera.h"
|
||||
#include "application/editormodegauge.h"
|
||||
#include "application/editortool.h"
|
||||
#include "scene/sceneeditor.h"
|
||||
#include "scene/scenenode.h"
|
||||
#include "editor/editorTerrain.hpp"
|
||||
@@ -58,20 +60,10 @@ struct vehicle_desc;
|
||||
struct skin_set;
|
||||
}
|
||||
|
||||
class editor_mode : public application_mode, private editor_track::observer
|
||||
class editor_mode : public application_mode, private editor_track::observer, private editor_services
|
||||
{
|
||||
|
||||
public:
|
||||
// model entering the structure gauge, at its deepest place
|
||||
struct gauge_hit
|
||||
{
|
||||
std::string model;
|
||||
glm::dvec3 point{0.0};
|
||||
double depth{0.0}; // m
|
||||
TTrack const *track{nullptr}; // nearest one, may be gone by now
|
||||
int path{0};
|
||||
glm::dvec2 direction{0.0, 1.0}; // of the track there, in the plan
|
||||
};
|
||||
// joint of the paths found wrong by the joints check
|
||||
struct joint_issue
|
||||
{
|
||||
@@ -742,7 +734,10 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
gizmo_operation m_gizmo_op{gizmo_operation::translate}; // current transform mode (translate/rotate/scale)
|
||||
float m_gizmo_snap{1.0f}; // translation snap step (metres) applied while Ctrl is held
|
||||
|
||||
TTrack *selected_track() const;
|
||||
TTrack *selected_track() const override;
|
||||
bool track_editing() const override;
|
||||
std::size_t history_size() const override;
|
||||
glm::dvec3 camera_position() const override;
|
||||
void render_path_ui();
|
||||
void draw_track_overlay() const;
|
||||
editor_track::point_ref track_handle_hit() const;
|
||||
@@ -862,55 +857,8 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
std::string m_track_events_missing;
|
||||
void render_path_events(TTrack &Track);
|
||||
std::string m_track_mode_notice;
|
||||
// structure gauge along the line of the selected path, shown in the 3d view
|
||||
struct gauge_state
|
||||
{
|
||||
bool open{false}; // window
|
||||
bool enabled{true}; // tunnel along the selected path
|
||||
std::vector<gauge::profile> profiles;
|
||||
int profile{0}; // railway
|
||||
int road{-1};
|
||||
TTrack const *track{nullptr}; // scanned
|
||||
std::size_t history{0};
|
||||
bool pending{false}; // rescan once the edit ends
|
||||
struct
|
||||
{
|
||||
std::vector<glm::dvec3> surface; // triangles of the tunnel
|
||||
std::vector<glm::dvec3> edges; // lines
|
||||
std::vector<gauge_hit> hits;
|
||||
} line; // along the selected path
|
||||
struct
|
||||
{
|
||||
bool scanned{false};
|
||||
std::size_t history{0};
|
||||
std::string profile;
|
||||
std::vector<gauge_hit> hits;
|
||||
} map; // whole scenery
|
||||
struct
|
||||
{
|
||||
std::vector<glm::dvec3> surface;
|
||||
std::vector<glm::dvec3> edges;
|
||||
} spot; // tunnel around the hit the camera went to
|
||||
int current{-1}; // hit the camera went to
|
||||
bool published{false}; // overlay up to date
|
||||
std::shared_ptr<struct gauge_scan> scan; // of the whole scenery, done in slices over the frames
|
||||
} m_gauge;
|
||||
void gauge_load();
|
||||
// the chosen railway and road outlines
|
||||
gauge::choice gauge_choice() const;
|
||||
std::vector<gauge_hit> const &gauge_hits() const;
|
||||
void update_gauge();
|
||||
void scan_gauge(TTrack &Track);
|
||||
void scan_gauge_map();
|
||||
void step_gauge_map();
|
||||
void finish_gauge_map();
|
||||
void gauge_publish();
|
||||
void gauge_focus(int Index);
|
||||
void gauge_spot(gauge_hit const &Hit);
|
||||
void render_gauge_window();
|
||||
void render_gauge_hits();
|
||||
bool render_gauge_choice(char const *Label, int &Index, bool Road);
|
||||
bool render_gauge_outline(int Index);
|
||||
gauge_tool m_gauge{*this};
|
||||
std::vector<editor_tool *> m_tools{&m_gauge};
|
||||
struct route_design
|
||||
{
|
||||
TTrack *from{nullptr};
|
||||
@@ -1673,7 +1621,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
void split_track_at(TTrack &Track, glm::dvec3 const &Point);
|
||||
void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point);
|
||||
// the camera flies over Duration seconds to the place Distance back from the target along Look, looking along it
|
||||
void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6);
|
||||
void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) override;
|
||||
// paths found by their names
|
||||
struct track_search
|
||||
{
|
||||
@@ -2273,12 +2221,7 @@ class editor_mode : public application_mode, private editor_track::observer
|
||||
scripted_input input;
|
||||
};
|
||||
selftest m_selftest;
|
||||
enum class selftest_result
|
||||
{
|
||||
unhandled,
|
||||
handled,
|
||||
pause
|
||||
};
|
||||
using selftest_result = editor_selftest_result;
|
||||
selftest_result selftest_scene(std::string const &command, std::istringstream &words);
|
||||
selftest_result selftest_sleepers(std::string const &command, std::istringstream &words);
|
||||
selftest_result selftest_sweep(std::string const &command, std::istringstream &words);
|
||||
|
||||
@@ -8,7 +8,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "application/editormode.h"
|
||||
#include "application/editormodegauge.h"
|
||||
#include "editor/editorTrack.hpp"
|
||||
#include "application/editoruilayer.h"
|
||||
#include "editor/editorFormat.hpp"
|
||||
#include "editor/editorGauge.hpp"
|
||||
@@ -326,7 +327,7 @@ template <typename Visitor> void visit_triangles(TSubModel *Submodel, glm::dmat4
|
||||
}
|
||||
|
||||
// the triangle enters the gauge when any point of a grid spread over it does; the deepest such point goes to the hit
|
||||
void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, editor_mode::gauge_hit &Hit)
|
||||
void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, gauge_tool::gauge_hit &Hit)
|
||||
{
|
||||
auto const middle{(A + B + C) / 3.0};
|
||||
if (false == Space.close(middle, std::max({glm::distance(middle, A), glm::distance(middle, B), glm::distance(middle, C)})))
|
||||
@@ -353,24 +354,24 @@ void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const
|
||||
}
|
||||
|
||||
// the deepest place of the model in the gauge, added to the hits when it enters it
|
||||
void scan_model(corridor const &Space, TAnimModel &Instance, std::vector<editor_mode::gauge_hit> &Hits)
|
||||
void scan_model(corridor const &Space, TAnimModel &Instance, std::vector<gauge_tool::gauge_hit> &Hits)
|
||||
{
|
||||
if (false == Instance.visible() || Instance.Model() == nullptr || Instance.Model()->GetSMRoot() == nullptr)
|
||||
return;
|
||||
if (false == Space.nearby(Instance.location(), Instance.radius()))
|
||||
return;
|
||||
editor_mode::gauge_hit hit{Instance.name(), Instance.location()};
|
||||
gauge_tool::gauge_hit hit{Instance.name(), Instance.location()};
|
||||
visit_triangles(Instance.Model()->GetSMRoot(), placement(Instance), [&](glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C) { scan_triangle(Space, A, B, C, hit); });
|
||||
if (hit.depth > 0.0)
|
||||
Hits.push_back(std::move(hit));
|
||||
}
|
||||
|
||||
// the same for the copies of a model laid along a curve
|
||||
void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<editor_mode::gauge_hit> &Hits)
|
||||
void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<gauge_tool::gauge_hit> &Hits)
|
||||
{
|
||||
if (Sweep.m_editorremoved || false == Space.nearby(Sweep.location(), Sweep.radius()))
|
||||
return;
|
||||
editor_mode::gauge_hit hit{Sweep.name(), Sweep.location()};
|
||||
gauge_tool::gauge_hit hit{Sweep.name(), Sweep.location()};
|
||||
for (auto const &shape : Sweep.create_shapes())
|
||||
{
|
||||
auto const &vertices{shape.data().vertices};
|
||||
@@ -381,13 +382,13 @@ void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector<editor_mod
|
||||
Hits.push_back(std::move(hit));
|
||||
}
|
||||
|
||||
void sort_hits(std::vector<editor_mode::gauge_hit> &Hits)
|
||||
void sort_hits(std::vector<gauge_tool::gauge_hit> &Hits)
|
||||
{
|
||||
std::sort(Hits.begin(), Hits.end(), [](auto const &Left, auto const &Right) { return Left.depth > Right.depth; });
|
||||
}
|
||||
|
||||
// the models entering the gauge, the deepest first
|
||||
void scan_models(corridor const &Space, std::vector<editor_mode::gauge_hit> &Hits)
|
||||
void scan_models(corridor const &Space, std::vector<gauge_tool::gauge_hit> &Hits)
|
||||
{
|
||||
for (auto *instance : simulation::Instances.sequence())
|
||||
if (instance != nullptr)
|
||||
@@ -550,7 +551,7 @@ struct gauge_scan
|
||||
std::chrono::steady_clock::time_point started;
|
||||
};
|
||||
|
||||
void editor_mode::gauge_load()
|
||||
void gauge_tool::gauge_load()
|
||||
{
|
||||
if (m_gauge.profiles.empty())
|
||||
m_gauge.profiles = gauge::load_profiles(gauge_file);
|
||||
@@ -568,18 +569,18 @@ void editor_mode::gauge_load()
|
||||
}
|
||||
}
|
||||
|
||||
gauge::choice editor_mode::gauge_choice() const
|
||||
gauge::choice gauge_tool::gauge_choice() const
|
||||
{
|
||||
auto const pick{[&](int const Index) { return Index >= 0 ? &m_gauge.profiles[Index] : nullptr; }};
|
||||
return {pick(m_gauge.profile), pick(m_gauge.road)};
|
||||
}
|
||||
|
||||
std::vector<editor_mode::gauge_hit> const &editor_mode::gauge_hits() const
|
||||
std::vector<gauge_tool::gauge_hit> const &gauge_tool::gauge_hits() const
|
||||
{
|
||||
return m_gauge.map.scanned ? m_gauge.map.hits : m_gauge.line.hits;
|
||||
}
|
||||
|
||||
void editor_mode::update_gauge()
|
||||
void gauge_tool::update()
|
||||
{
|
||||
if (m_gauge.scan)
|
||||
step_gauge_map();
|
||||
@@ -590,9 +591,9 @@ void editor_mode::update_gauge()
|
||||
m_gauge.published = false;
|
||||
return;
|
||||
}
|
||||
auto *track{m_gauge.enabled ? selected_track() : nullptr};
|
||||
auto *track{m_gauge.enabled ? m_services.selected_track() : nullptr};
|
||||
// the geometry is rescanned once the edit ends
|
||||
if (ImGui::IsMouseDown(0) || m_track_gizmo_using || m_dragging)
|
||||
if (ImGui::IsMouseDown(0) || m_services.track_editing())
|
||||
m_gauge.pending = true;
|
||||
else if (track == nullptr)
|
||||
{
|
||||
@@ -603,19 +604,19 @@ void editor_mode::update_gauge()
|
||||
m_gauge.published = false;
|
||||
}
|
||||
}
|
||||
else if (track != m_gauge.track || m_history.size() != m_gauge.history || m_gauge.pending)
|
||||
else if (track != m_gauge.track || m_services.history_size() != m_gauge.history || m_gauge.pending)
|
||||
{
|
||||
m_gauge.track = track;
|
||||
m_gauge.history = m_history.size();
|
||||
m_gauge.history = m_services.history_size();
|
||||
m_gauge.pending = false;
|
||||
scan_gauge(*track);
|
||||
m_gauge.published = false;
|
||||
}
|
||||
if (false == m_gauge.published || glm::distance(Camera.Pos, EditorOverlay.origin) > gauge_origin_range)
|
||||
if (false == m_gauge.published || glm::distance(m_services.camera_position(), EditorOverlay.origin) > gauge_origin_range)
|
||||
gauge_publish();
|
||||
}
|
||||
|
||||
void editor_mode::scan_gauge(TTrack &Track)
|
||||
void gauge_tool::scan_gauge(TTrack &Track)
|
||||
{
|
||||
gauge_load();
|
||||
m_gauge.line = {};
|
||||
@@ -631,7 +632,7 @@ void editor_mode::scan_gauge(TTrack &Track)
|
||||
m_gauge.current = -1;
|
||||
}
|
||||
|
||||
void editor_mode::scan_gauge_map()
|
||||
void gauge_tool::scan_gauge_map()
|
||||
{
|
||||
gauge_load();
|
||||
auto scan{std::make_shared<gauge_scan>()};
|
||||
@@ -644,7 +645,7 @@ void editor_mode::scan_gauge_map()
|
||||
scan->space.emplace(scan->lines);
|
||||
m_gauge.map = {};
|
||||
m_gauge.map.scanned = true;
|
||||
m_gauge.map.history = m_history.size();
|
||||
m_gauge.map.history = m_services.history_size();
|
||||
auto const name{[](gauge::profile const *Profile) { return Profile != nullptr ? Profile->name : std::string{"-"}; }};
|
||||
m_gauge.map.profile = name(chosen.railway) + ", " + name(chosen.road);
|
||||
m_gauge.current = -1;
|
||||
@@ -652,7 +653,7 @@ void editor_mode::scan_gauge_map()
|
||||
m_gauge.scan = std::move(scan);
|
||||
}
|
||||
|
||||
void editor_mode::step_gauge_map()
|
||||
void gauge_tool::step_gauge_map()
|
||||
{
|
||||
auto &scan{*m_gauge.scan};
|
||||
auto const &instances{simulation::Instances.sequence()};
|
||||
@@ -675,7 +676,7 @@ void editor_mode::step_gauge_map()
|
||||
finish_gauge_map();
|
||||
}
|
||||
|
||||
void editor_mode::finish_gauge_map()
|
||||
void gauge_tool::finish_gauge_map()
|
||||
{
|
||||
auto const scan{std::move(m_gauge.scan)};
|
||||
auto &hits{m_gauge.map.hits};
|
||||
@@ -690,11 +691,11 @@ void editor_mode::finish_gauge_map()
|
||||
gauge_focus(0);
|
||||
}
|
||||
|
||||
void editor_mode::gauge_publish()
|
||||
void gauge_tool::gauge_publish()
|
||||
{
|
||||
m_gauge.published = true;
|
||||
EditorOverlay.clear();
|
||||
EditorOverlay.origin = Camera.Pos;
|
||||
EditorOverlay.origin = m_services.camera_position();
|
||||
auto const batch{[](glm::vec4 const &Color, unsigned int const Type, std::vector<glm::dvec3> const &Points) {
|
||||
gfx::editor_overlay::batch result{Color, Type};
|
||||
result.points.reserve(Points.size());
|
||||
@@ -717,7 +718,7 @@ void editor_mode::gauge_publish()
|
||||
batch({0.2f, 1.0f, 0.3f, 0.5f}, GL_LINES, m_gauge.spot.edges)};
|
||||
}
|
||||
|
||||
void editor_mode::gauge_focus(int const Index)
|
||||
void gauge_tool::gauge_focus(int const Index)
|
||||
{
|
||||
auto const &hits{gauge_hits()};
|
||||
if (hits.empty())
|
||||
@@ -729,12 +730,12 @@ void editor_mode::gauge_focus(int const Index)
|
||||
// along the track, tangent to the gauge at the height of the place, from the end nearer to the camera
|
||||
glm::dvec3 look{hit.direction.x, 0.0, hit.direction.y};
|
||||
look = glm::length(look) > 1e-6 ? glm::normalize(look) : glm::dvec3(0.0, 0.0, 1.0);
|
||||
if (glm::dot(Camera.Pos - hit.point, look) > 0.0)
|
||||
if (glm::dot(m_services.camera_position() - hit.point, look) > 0.0)
|
||||
look = -look;
|
||||
fly_to(hit.point, look, gauge_view_distance);
|
||||
m_services.fly_to(hit.point, look, gauge_view_distance);
|
||||
}
|
||||
|
||||
void editor_mode::gauge_spot(gauge_hit const &Hit)
|
||||
void gauge_tool::gauge_spot(gauge_hit const &Hit)
|
||||
{
|
||||
m_gauge.spot = {};
|
||||
auto const &paths{simulation::Paths.sequence()};
|
||||
@@ -751,7 +752,7 @@ void editor_mode::gauge_spot(gauge_hit const &Hit)
|
||||
build_tunnel(*line, m_gauge.spot.surface, m_gauge.spot.edges);
|
||||
}
|
||||
|
||||
void editor_mode::render_gauge_window()
|
||||
void gauge_tool::render_windows()
|
||||
{
|
||||
if (false == m_gauge.open)
|
||||
return;
|
||||
@@ -798,7 +799,7 @@ void editor_mode::render_gauge_window()
|
||||
m_gauge.current = -1;
|
||||
m_gauge.published = false;
|
||||
}
|
||||
else if (m_gauge.map.history != m_history.size())
|
||||
else if (m_gauge.map.history != m_services.history_size())
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.3f, 1.0f), STR_C("The scenery changed since the scan (%s)"), m_gauge.map.profile.c_str());
|
||||
}
|
||||
render_gauge_hits();
|
||||
@@ -809,7 +810,7 @@ void editor_mode::render_gauge_window()
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void editor_mode::render_gauge_hits()
|
||||
void gauge_tool::render_gauge_hits()
|
||||
{
|
||||
auto const &hits{gauge_hits()};
|
||||
if (false == m_gauge.map.scanned && (false == m_gauge.enabled || m_gauge.track == nullptr))
|
||||
@@ -841,7 +842,7 @@ void editor_mode::render_gauge_hits()
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const Road)
|
||||
bool gauge_tool::render_gauge_choice(char const *Label, int &Index, bool const Road)
|
||||
{
|
||||
bool changed{false};
|
||||
ImGui::PushID(Label);
|
||||
@@ -863,7 +864,7 @@ bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool editor_mode::render_gauge_outline(int const Index)
|
||||
bool gauge_tool::render_gauge_outline(int const Index)
|
||||
{
|
||||
if (Index < 0)
|
||||
return false;
|
||||
@@ -884,3 +885,23 @@ bool editor_mode::render_gauge_outline(int const Index)
|
||||
ImGui::TreePop();
|
||||
return edited;
|
||||
}
|
||||
|
||||
editor_selftest_result gauge_tool::selftest(std::string const &Command, std::istringstream &Words)
|
||||
{
|
||||
if (Command == "gauge")
|
||||
{
|
||||
std::string name;
|
||||
Words >> name;
|
||||
if (auto *track{simulation::Paths.find(name)})
|
||||
{
|
||||
scan_gauge(*track);
|
||||
WriteLog(format("SELFTEST gauge %s: %d hits", name.c_str(), static_cast<int>(m_gauge.line.hits.size())));
|
||||
for (auto const &hit : m_gauge.line.hits)
|
||||
WriteLog(format("SELFTEST gauge hit %s depth %.3f at %.2f %.2f %.2f", hit.model.c_str(), hit.depth, hit.point.x, hit.point.y, hit.point.z));
|
||||
}
|
||||
else
|
||||
WriteLog("SELFTEST gauge " + name + ": no such track");
|
||||
return editor_selftest_result::handled;
|
||||
}
|
||||
return editor_selftest_result::unhandled;
|
||||
}
|
||||
|
||||
88
application/editormodegauge.h
Normal file
88
application/editormodegauge.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 "editor/editorGauge.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class gauge_tool final : public editor_tool
|
||||
{
|
||||
public:
|
||||
// model entering the structure gauge, at its deepest place
|
||||
struct gauge_hit
|
||||
{
|
||||
std::string model;
|
||||
glm::dvec3 point{0.0};
|
||||
double depth{0.0}; // m
|
||||
TTrack const *track{nullptr}; // nearest one, may be gone by now
|
||||
int path{0};
|
||||
glm::dvec2 direction{0.0, 1.0}; // of the track there, in the plan
|
||||
};
|
||||
explicit gauge_tool(editor_services &Services) : m_services{Services} {}
|
||||
void update() override;
|
||||
void render_windows() override;
|
||||
editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) override;
|
||||
bool is_open() const { return m_gauge.open; }
|
||||
void toggle() { m_gauge.open = !m_gauge.open; }
|
||||
|
||||
private:
|
||||
editor_services &m_services;
|
||||
// structure gauge along the line of the selected path, shown in the 3d view
|
||||
struct gauge_state
|
||||
{
|
||||
bool open{false}; // window
|
||||
bool enabled{true}; // tunnel along the selected path
|
||||
std::vector<gauge::profile> profiles;
|
||||
int profile{0}; // railway
|
||||
int road{-1};
|
||||
TTrack const *track{nullptr}; // scanned
|
||||
std::size_t history{0};
|
||||
bool pending{false}; // rescan once the edit ends
|
||||
struct
|
||||
{
|
||||
std::vector<glm::dvec3> surface; // triangles of the tunnel
|
||||
std::vector<glm::dvec3> edges; // lines
|
||||
std::vector<gauge_hit> hits;
|
||||
} line; // along the selected path
|
||||
struct
|
||||
{
|
||||
bool scanned{false};
|
||||
std::size_t history{0};
|
||||
std::string profile;
|
||||
std::vector<gauge_hit> hits;
|
||||
} map; // whole scenery
|
||||
struct
|
||||
{
|
||||
std::vector<glm::dvec3> surface;
|
||||
std::vector<glm::dvec3> edges;
|
||||
} spot; // tunnel around the hit the camera went to
|
||||
int current{-1}; // hit the camera went to
|
||||
bool published{false}; // overlay up to date
|
||||
std::shared_ptr<struct gauge_scan> scan; // of the whole scenery, done in slices over the frames
|
||||
} m_gauge;
|
||||
void gauge_load();
|
||||
// the chosen railway and road outlines
|
||||
gauge::choice gauge_choice() const;
|
||||
std::vector<gauge_hit> const &gauge_hits() const;
|
||||
void scan_gauge(TTrack &Track);
|
||||
void scan_gauge_map();
|
||||
void step_gauge_map();
|
||||
void finish_gauge_map();
|
||||
void gauge_publish();
|
||||
void gauge_focus(int Index);
|
||||
void gauge_spot(gauge_hit const &Hit);
|
||||
void render_gauge_hits();
|
||||
bool render_gauge_choice(char const *Label, int &Index, bool Road);
|
||||
bool render_gauge_outline(int Index);
|
||||
};
|
||||
@@ -54,6 +54,9 @@ editor_mode::selftest_result editor_mode::selftest_dispatch(std::string const &c
|
||||
for (auto const group : {&editor_mode::selftest_scene, &editor_mode::selftest_sleepers, &editor_mode::selftest_sweep, &editor_mode::selftest_track, &editor_mode::selftest_switch, &editor_mode::selftest_rails, &editor_mode::selftest_join, &editor_mode::selftest_signal, &editor_mode::selftest_terrain, &editor_mode::selftest_props, &editor_mode::selftest_monkey})
|
||||
if (auto const result{(this->*group)(command, words)}; result != selftest_result::unhandled)
|
||||
return result;
|
||||
for (auto *tool : m_tools)
|
||||
if (auto const result{tool->selftest(command, words)}; result != selftest_result::unhandled)
|
||||
return result;
|
||||
return selftest_result::unhandled;
|
||||
}
|
||||
|
||||
|
||||
@@ -396,21 +396,6 @@ editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &comm
|
||||
ui()->expand_bend();
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "gauge")
|
||||
{
|
||||
std::string name;
|
||||
words >> name;
|
||||
if (auto *track{simulation::Paths.find(name)})
|
||||
{
|
||||
scan_gauge(*track);
|
||||
WriteLog(format("SELFTEST gauge %s: %d hits", name.c_str(), static_cast<int>(m_gauge.line.hits.size())));
|
||||
for (auto const &hit : m_gauge.line.hits)
|
||||
WriteLog(format("SELFTEST gauge hit %s depth %.3f at %.2f %.2f %.2f", hit.model.c_str(), hit.depth, hit.point.x, hit.point.y, hit.point.z));
|
||||
}
|
||||
else
|
||||
WriteLog("SELFTEST gauge " + name + ": no such track");
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "ttincludes")
|
||||
{
|
||||
std::string name;
|
||||
|
||||
@@ -52,6 +52,21 @@ TTrack *editor_mode::selected_track() const
|
||||
return dynamic_cast<TTrack *>(m_node);
|
||||
}
|
||||
|
||||
bool editor_mode::track_editing() const
|
||||
{
|
||||
return m_track_gizmo_using || m_dragging;
|
||||
}
|
||||
|
||||
std::size_t editor_mode::history_size() const
|
||||
{
|
||||
return m_history.size();
|
||||
}
|
||||
|
||||
glm::dvec3 editor_mode::camera_position() const
|
||||
{
|
||||
return Camera.Pos;
|
||||
}
|
||||
|
||||
void editor_mode::select_track(scene::basic_node *Node)
|
||||
{
|
||||
auto *track = dynamic_cast<TTrack *>(Node);
|
||||
|
||||
@@ -178,7 +178,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
add(track_tab::turnout, false);
|
||||
add(track_tab::parallel, false);
|
||||
auto const advanced{m_track_tab == track_tab::turntable || m_track_tab == track_tab::signals || m_track_tab == track_tab::lineside || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed ||
|
||||
m_track_tab == track_tab::joints || m_gauge.open};
|
||||
m_track_tab == track_tab::joints || m_gauge.is_open()};
|
||||
auto const more{EditorSettings.track_tools_more()};
|
||||
Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("Turntable, signals, objects, trainset, profile, speed, joints, gauge"), more, [more]() {
|
||||
EditorSettings.track_tools_more(false == more);
|
||||
@@ -197,8 +197,8 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
add(track_tab::profile, true);
|
||||
add(track_tab::speed, false);
|
||||
add(track_tab::joints, false);
|
||||
Buttons.push_back({icon::gauge, STR_C("Structure gauge"), nullptr, STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)"), m_gauge.open,
|
||||
[this]() { m_gauge.open = !m_gauge.open; }});
|
||||
Buttons.push_back({icon::gauge, STR_C("Structure gauge"), nullptr, STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)"), m_gauge.is_open(),
|
||||
[this]() { m_gauge.toggle(); }});
|
||||
Buttons.back().accent = family_colour(2);
|
||||
break;
|
||||
}
|
||||
|
||||
52
application/editortool.h
Normal file
52
application/editortool.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
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 <cstddef>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class TTrack;
|
||||
namespace scene
|
||||
{
|
||||
class basic_node;
|
||||
}
|
||||
|
||||
enum class editor_selftest_result
|
||||
{
|
||||
unhandled,
|
||||
handled,
|
||||
pause
|
||||
};
|
||||
|
||||
class editor_services
|
||||
{
|
||||
public:
|
||||
virtual TTrack *selected_track() const = 0;
|
||||
virtual bool track_editing() const = 0;
|
||||
virtual std::size_t history_size() const = 0;
|
||||
virtual glm::dvec3 camera_position() const = 0;
|
||||
virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0;
|
||||
|
||||
protected:
|
||||
~editor_services() = default;
|
||||
};
|
||||
|
||||
class editor_tool
|
||||
{
|
||||
public:
|
||||
virtual ~editor_tool() = default;
|
||||
virtual void update() {}
|
||||
virtual void render_windows() {}
|
||||
virtual void forget(scene::basic_node const *Node) {}
|
||||
virtual editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) { return editor_selftest_result::unhandled; }
|
||||
};
|
||||
Reference in New Issue
Block a user