mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 18:07:29 +01:00
feat(editor): edit session (-edit) and scenery layers
This commit is contained in:
@@ -1145,6 +1145,16 @@ int eu07_application::init_settings(int Argc, char *Argv[])
|
||||
Global.local_start_vehicle = ToLower(Argv[++i]);
|
||||
}
|
||||
}
|
||||
else if (token == "-edit")
|
||||
{
|
||||
// edit session: the scenery is loaded without player vehicle, straight into the editor
|
||||
if (i + 1 < Argc)
|
||||
{
|
||||
Global.SceneryFile = ToLower(Argv[++i]);
|
||||
Global.local_start_vehicle = "ghostview";
|
||||
Global.editor_session = true;
|
||||
}
|
||||
}
|
||||
else if (token == "-seed")
|
||||
{
|
||||
// a number is the seed; anything else is a word that stands for one. said in the
|
||||
@@ -1159,6 +1169,7 @@ int eu07_application::init_settings(int Argc, char *Argv[])
|
||||
{
|
||||
std::cout << "usage: " << std::string(Argv[0]) << " [-s sceneryfilepath]"
|
||||
<< " [-v vehiclename]"
|
||||
<< " [-edit sceneryfilepath]"
|
||||
<< " [-seed number|word]" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -412,6 +412,14 @@ bool driver_mode::update()
|
||||
|
||||
simulation::is_ready = simulation::is_ready || (simulation::Train != nullptr && simulation::Train->is_cab_initialized) || Global.local_start_vehicle == "ghostview";
|
||||
|
||||
if (m_editorpending)
|
||||
{
|
||||
// edit session starts in the editor. the switch is made after the initial update on purpose, so the
|
||||
// simulation state is set up the same way as when the editor is entered by hand right after the load
|
||||
m_editorpending = false;
|
||||
Application.push_mode(eu07_application::mode::editor);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -458,6 +466,8 @@ void driver_mode::enter()
|
||||
Timer::ResetTimers();
|
||||
|
||||
set_picking(!Global.captureonstart);
|
||||
|
||||
m_editorpending = Global.editor_session;
|
||||
}
|
||||
|
||||
// maintenance method, called when the mode is deactivated
|
||||
|
||||
@@ -116,4 +116,5 @@ private:
|
||||
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
||||
command_relay m_relay;
|
||||
std::string change_train; // train name awaiting entering
|
||||
bool m_editorpending { false }; // scenery was opened for editing, switch to the editor after the initial update
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "model/Model3d.h"
|
||||
#include "utilities/Float3d.h"
|
||||
#include "scene/scene.h"
|
||||
#include "scene/scenelayers.h"
|
||||
#include "utilities/parser.h"
|
||||
#include "utilities/utilities.h"
|
||||
|
||||
@@ -891,6 +892,14 @@ bool editor_mode::update()
|
||||
// variable step routines
|
||||
update_camera(deltarealtime);
|
||||
|
||||
// drop the selection if its layer was hidden or locked in the meantime
|
||||
if (m_node != nullptr && false == scene::Layers.editable(m_node->layer()))
|
||||
{
|
||||
m_node = nullptr;
|
||||
m_dragging = false;
|
||||
ui()->set_node(nullptr);
|
||||
}
|
||||
|
||||
simulation::Region->update_sounds();
|
||||
audio::renderer.update(Global.iPause ? 0.0 : deltarealtime);
|
||||
|
||||
@@ -1522,10 +1531,24 @@ void editor_mode::save_scene_with_terrain()
|
||||
m_streamer.flush(); // save resident edited chunks to disk
|
||||
|
||||
// export scenery; the exported .scm now carries an `editorterrain` directive (streamer is active)
|
||||
simulation::State.export_as_text(Global.SceneryFile);
|
||||
export_scenery();
|
||||
WriteLog("Editor: saved scene + terrain", logtype::generic);
|
||||
}
|
||||
|
||||
void editor_mode::export_scenery()
|
||||
{
|
||||
// hiding a layer clears the visibility flag of its nodes, and the flag is a part of exported node data.
|
||||
// show the hidden layers for the duration of the export, so the files get the visibility defined in the scenery
|
||||
auto const hiddenlayers = scene::Layers.hidden();
|
||||
for (auto const layer : hiddenlayers)
|
||||
scene::Layers.visible(layer, true);
|
||||
|
||||
simulation::State.export_as_text(Global.SceneryFile);
|
||||
|
||||
for (auto const layer : hiddenlayers)
|
||||
scene::Layers.visible(layer, false);
|
||||
}
|
||||
|
||||
void editor_mode::handle_terrain_sculpt(double Deltatime)
|
||||
{
|
||||
// world point under the cursor (Mouse_Position is camera-relative, like the brush placement uses)
|
||||
@@ -2126,6 +2149,7 @@ void editor_mode::exit()
|
||||
m_fill_last.clear();
|
||||
m_orthophoto.cancel_pending();
|
||||
m_orthophoto.detach_scene(); // the layer is an editor aid, keep it out of the other modes
|
||||
scene::Layers.show_all(); // likewise for hidden scenery layers, the other modes get the scenery as it was defined
|
||||
|
||||
// drop selection so a stale/dangling node pointer isn't used on the next editor session
|
||||
m_node = nullptr;
|
||||
@@ -2204,7 +2228,7 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
|
||||
}
|
||||
else if (Global.ctrlState && Global.shiftState)
|
||||
{
|
||||
simulation::State.export_as_text(Global.SceneryFile);
|
||||
export_scenery();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2340,6 +2364,10 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const
|
||||
|
||||
m_node = nullptr;
|
||||
|
||||
// nodes of locked layers can't be selected
|
||||
if (node && false == scene::Layers.editable(node->layer()))
|
||||
node = nullptr;
|
||||
|
||||
// ignore picks that are beyond allowed placement distance
|
||||
if (node) {
|
||||
double const dist = glm::distance(node->location(), glm::dvec3{Global.pCamera.Pos});
|
||||
|
||||
@@ -162,6 +162,8 @@ class editor_mode : public application_mode
|
||||
void handle_chunk_edit_click(bool DeleteMode);
|
||||
// commits authored terrain to disk, enables streaming, and exports the scenery (Ctrl+S)
|
||||
void save_scene_with_terrain();
|
||||
// exports the scenery in legacy (text) format, with layers hidden in the editor left out of the picture
|
||||
void export_scenery();
|
||||
// raises/lowers terrain under the cursor while the left mouse button is held in sculpt mode
|
||||
void handle_terrain_sculpt(double Deltatime);
|
||||
// returns the terrain patch (if any) whose footprint covers the given world point
|
||||
|
||||
@@ -13,6 +13,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/Globals.h"
|
||||
#include "utilities/utilities.h"
|
||||
#include "scene/scenenode.h"
|
||||
#include "scene/scenelayers.h"
|
||||
#include "rendering/renderer.h"
|
||||
|
||||
editor_ui::editor_ui()
|
||||
@@ -99,6 +100,98 @@ void editor_ui::render_header_sections()
|
||||
m_itempropertiespanel.render_body();
|
||||
ImGui::Unindent();
|
||||
}
|
||||
if (ImGui::CollapsingHeader("Layers"))
|
||||
{
|
||||
ImGui::Indent();
|
||||
render_layers();
|
||||
ImGui::Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
void editor_ui::render_layers()
|
||||
{
|
||||
if (scene::Layers.empty())
|
||||
{
|
||||
// layers are established only when the scenery is loaded for editing, regular load skips the bookkeeping
|
||||
ImGui::TextDisabled("Scenery layers are available in an edit session.\nStart the simulator with: -edit <scenery file>");
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::TextDisabled("visible, locked, layer file (click: make active)");
|
||||
|
||||
std::pair<char const *, scene::layer_item> const itemlabels[] = {{"models", scene::layer_item::model},
|
||||
{"tracks", scene::layer_item::track},
|
||||
{"traction", scene::layer_item::traction},
|
||||
{"power sources", scene::layer_item::powersource},
|
||||
{"memory cells", scene::layer_item::memcell},
|
||||
{"event launchers", scene::layer_item::launcher},
|
||||
{"events", scene::layer_item::event},
|
||||
{"vehicles", scene::layer_item::vehicle},
|
||||
{"sounds", scene::layer_item::sound},
|
||||
{"terrain shapes", scene::layer_item::shape},
|
||||
{"lines", scene::layer_item::lines}};
|
||||
|
||||
for (std::size_t idx = 1; idx <= scene::Layers.size(); ++idx)
|
||||
{
|
||||
auto const handle{static_cast<scene::layer_handle>(idx)};
|
||||
auto const &layer{scene::Layers.layer(handle)};
|
||||
auto const isactive{handle == scene::Layers.active()};
|
||||
|
||||
ImGui::PushID(static_cast<int>(idx));
|
||||
// active layer receives new nodes, so it can't be hidden nor locked
|
||||
if (isactive)
|
||||
{
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
|
||||
}
|
||||
auto visible{layer.visible};
|
||||
if (ImGui::Checkbox("##visible", &visible) && false == isactive)
|
||||
{
|
||||
scene::Layers.visible(handle, visible);
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("%s", isactive ? "Active layer is always visible" : "Show or hide models, tracks and traction of the layer");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
auto locked{layer.locked};
|
||||
if (ImGui::Checkbox("##locked", &locked) && false == isactive)
|
||||
{
|
||||
scene::Layers.locked(handle, locked);
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("%s", isactive ? "Active layer can't be locked" : "Nodes of locked layer can't be selected in the viewport");
|
||||
}
|
||||
if (isactive)
|
||||
{
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
// layers are listed in the order the files were first opened, so indentation alone shows the include tree
|
||||
auto const label{std::string(2 * scene::Layers.depth(handle), ' ') + Bezogonkow(layer.name) + " (" + (layer.binary ? "binary terrain" : std::to_string(layer.item_count())) + ")"};
|
||||
if (ImGui::Selectable(label.c_str(), isactive))
|
||||
{
|
||||
scene::Layers.active(handle);
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
std::string content{isactive ? "Active layer, nodes created in the editor are placed here" : "Click to make this the active layer"};
|
||||
if (layer.binary)
|
||||
{
|
||||
content += "\nThe file wasn't parsed, its content was loaded from binary terrain file";
|
||||
}
|
||||
for (auto const &itemlabel : itemlabels)
|
||||
{
|
||||
auto const count{layer.items[static_cast<std::size_t>(itemlabel.second)]};
|
||||
if (count > 0)
|
||||
{
|
||||
content += "\n" + std::string{itemlabel.first} + ": " + std::to_string(count);
|
||||
}
|
||||
}
|
||||
ImGui::SetTooltip("%s", content.c_str());
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
}
|
||||
|
||||
void editor_ui::render_rotation_controls()
|
||||
|
||||
@@ -58,6 +58,8 @@ class editor_ui : public ui_layer
|
||||
// methods
|
||||
void render_mode_options(nodebank_panel::edit_mode const Mode);
|
||||
void render_header_sections();
|
||||
// list of scenery layers: visibility, selection lock and choice of the layer receiving new nodes
|
||||
void render_layers();
|
||||
// members
|
||||
itemproperties_panel m_itempropertiespanel{"Node Properties", true}; // not a window of its own, drawn in the toolset window
|
||||
functions_panel m_functionspanel{"Functions", true}; // not a window of its own, its settings are drawn in the toolset tabs
|
||||
|
||||
@@ -10,6 +10,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "stdafx.h"
|
||||
#include "application/editoruipanels.h"
|
||||
#include "scene/scenenodegroups.h"
|
||||
#include "scene/scenelayers.h"
|
||||
|
||||
#include "utilities/Globals.h"
|
||||
#include "vehicle/Camera.h"
|
||||
@@ -78,6 +79,10 @@ void itemproperties_panel::update(scene::basic_node *Node)
|
||||
textline = "name: " + (node->name().empty() ? "(none)" : Bezogonkow(node->name())) + "\ntype: " + node->node_type + "\nlocation: [" + to_string(node->location().x, 2) + ", " + to_string(node->location().y, 2) + ", " +
|
||||
to_string(node->location().z, 2) + "]" +
|
||||
" (distance: " + to_string(glm::length(glm::dvec3{node->location().x, 0.0, node->location().z} - glm::dvec3{camera.Pos.x, 0.0, camera.Pos.z}), 1) + " m)" + "\nUUID: " + node->uuid.to_string();
|
||||
if (scene::Layers.valid(node->layer()))
|
||||
{
|
||||
textline += "\nlayer: " + Bezogonkow(scene::Layers.layer(node->layer()).name);
|
||||
}
|
||||
text_lines.emplace_back(textline, Global.UITextColor);
|
||||
|
||||
// subclass-specific data
|
||||
|
||||
Reference in New Issue
Block a user