mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-04 03:02:05 +01:00
feat(editor): edit session (-edit) and scenery layers
This commit is contained in:
@@ -178,6 +178,7 @@ set(SOURCES
|
|||||||
"application/scenarioloadermode.cpp"
|
"application/scenarioloadermode.cpp"
|
||||||
"application/scenarioloaderuilayer.cpp"
|
"application/scenarioloaderuilayer.cpp"
|
||||||
"scene/scenenodegroups.cpp"
|
"scene/scenenodegroups.cpp"
|
||||||
|
"scene/scenelayers.cpp"
|
||||||
"simulation/simulationenvironment.cpp"
|
"simulation/simulationenvironment.cpp"
|
||||||
"simulation/simulationstateserializer.cpp"
|
"simulation/simulationstateserializer.cpp"
|
||||||
"rendering/precipitation.cpp"
|
"rendering/precipitation.cpp"
|
||||||
|
|||||||
@@ -1145,6 +1145,16 @@ int eu07_application::init_settings(int Argc, char *Argv[])
|
|||||||
Global.local_start_vehicle = ToLower(Argv[++i]);
|
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")
|
else if (token == "-seed")
|
||||||
{
|
{
|
||||||
// a number is the seed; anything else is a word that stands for one. said in the
|
// 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]"
|
std::cout << "usage: " << std::string(Argv[0]) << " [-s sceneryfilepath]"
|
||||||
<< " [-v vehiclename]"
|
<< " [-v vehiclename]"
|
||||||
|
<< " [-edit sceneryfilepath]"
|
||||||
<< " [-seed number|word]" << std::endl;
|
<< " [-seed number|word]" << std::endl;
|
||||||
return -1;
|
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";
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,6 +466,8 @@ void driver_mode::enter()
|
|||||||
Timer::ResetTimers();
|
Timer::ResetTimers();
|
||||||
|
|
||||||
set_picking(!Global.captureonstart);
|
set_picking(!Global.captureonstart);
|
||||||
|
|
||||||
|
m_editorpending = Global.editor_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintenance method, called when the mode is deactivated
|
// maintenance method, called when the mode is deactivated
|
||||||
|
|||||||
@@ -116,4 +116,5 @@ private:
|
|||||||
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
int iPause { 0 }; // wykrywanie zmian w zapauzowaniu
|
||||||
command_relay m_relay;
|
command_relay m_relay;
|
||||||
std::string change_train; // train name awaiting entering
|
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 "model/Model3d.h"
|
||||||
#include "utilities/Float3d.h"
|
#include "utilities/Float3d.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
#include "utilities/parser.h"
|
#include "utilities/parser.h"
|
||||||
#include "utilities/utilities.h"
|
#include "utilities/utilities.h"
|
||||||
|
|
||||||
@@ -891,6 +892,14 @@ bool editor_mode::update()
|
|||||||
// variable step routines
|
// variable step routines
|
||||||
update_camera(deltarealtime);
|
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();
|
simulation::Region->update_sounds();
|
||||||
audio::renderer.update(Global.iPause ? 0.0 : deltarealtime);
|
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
|
m_streamer.flush(); // save resident edited chunks to disk
|
||||||
|
|
||||||
// export scenery; the exported .scm now carries an `editorterrain` directive (streamer is active)
|
// 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);
|
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)
|
void editor_mode::handle_terrain_sculpt(double Deltatime)
|
||||||
{
|
{
|
||||||
// world point under the cursor (Mouse_Position is camera-relative, like the brush placement uses)
|
// 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_fill_last.clear();
|
||||||
m_orthophoto.cancel_pending();
|
m_orthophoto.cancel_pending();
|
||||||
m_orthophoto.detach_scene(); // the layer is an editor aid, keep it out of the other modes
|
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
|
// drop selection so a stale/dangling node pointer isn't used on the next editor session
|
||||||
m_node = nullptr;
|
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)
|
else if (Global.ctrlState && Global.shiftState)
|
||||||
{
|
{
|
||||||
simulation::State.export_as_text(Global.SceneryFile);
|
export_scenery();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -2340,6 +2364,10 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const
|
|||||||
|
|
||||||
m_node = nullptr;
|
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
|
// ignore picks that are beyond allowed placement distance
|
||||||
if (node) {
|
if (node) {
|
||||||
double const dist = glm::distance(node->location(), glm::dvec3{Global.pCamera.Pos});
|
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);
|
void handle_chunk_edit_click(bool DeleteMode);
|
||||||
// commits authored terrain to disk, enables streaming, and exports the scenery (Ctrl+S)
|
// commits authored terrain to disk, enables streaming, and exports the scenery (Ctrl+S)
|
||||||
void save_scene_with_terrain();
|
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
|
// raises/lowers terrain under the cursor while the left mouse button is held in sculpt mode
|
||||||
void handle_terrain_sculpt(double Deltatime);
|
void handle_terrain_sculpt(double Deltatime);
|
||||||
// returns the terrain patch (if any) whose footprint covers the given world point
|
// 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/Globals.h"
|
||||||
#include "utilities/utilities.h"
|
#include "utilities/utilities.h"
|
||||||
#include "scene/scenenode.h"
|
#include "scene/scenenode.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
#include "rendering/renderer.h"
|
#include "rendering/renderer.h"
|
||||||
|
|
||||||
editor_ui::editor_ui()
|
editor_ui::editor_ui()
|
||||||
@@ -99,6 +100,98 @@ void editor_ui::render_header_sections()
|
|||||||
m_itempropertiespanel.render_body();
|
m_itempropertiespanel.render_body();
|
||||||
ImGui::Unindent();
|
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()
|
void editor_ui::render_rotation_controls()
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ class editor_ui : public ui_layer
|
|||||||
// methods
|
// methods
|
||||||
void render_mode_options(nodebank_panel::edit_mode const Mode);
|
void render_mode_options(nodebank_panel::edit_mode const Mode);
|
||||||
void render_header_sections();
|
void render_header_sections();
|
||||||
|
// list of scenery layers: visibility, selection lock and choice of the layer receiving new nodes
|
||||||
|
void render_layers();
|
||||||
// members
|
// members
|
||||||
itemproperties_panel m_itempropertiespanel{"Node Properties", true}; // not a window of its own, drawn in the toolset window
|
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
|
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 "stdafx.h"
|
||||||
#include "application/editoruipanels.h"
|
#include "application/editoruipanels.h"
|
||||||
#include "scene/scenenodegroups.h"
|
#include "scene/scenenodegroups.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
|
|
||||||
#include "utilities/Globals.h"
|
#include "utilities/Globals.h"
|
||||||
#include "vehicle/Camera.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) + ", " +
|
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) + "]" +
|
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();
|
" (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);
|
text_lines.emplace_back(textline, Global.UITextColor);
|
||||||
|
|
||||||
// subclass-specific data
|
// subclass-specific data
|
||||||
|
|||||||
194
scene/scenelayers.cpp
Normal file
194
scene/scenelayers.cpp
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stdafx.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
|
|
||||||
|
#include "simulation/simulation.h"
|
||||||
|
#include "model/AnimModel.h"
|
||||||
|
#include "world/Track.h"
|
||||||
|
#include "world/Traction.h"
|
||||||
|
|
||||||
|
namespace scene
|
||||||
|
{
|
||||||
|
|
||||||
|
node_layers Layers;
|
||||||
|
|
||||||
|
std::size_t basic_layer::item_count() const
|
||||||
|
{
|
||||||
|
return std::accumulate(std::begin(items), std::end(items), std::size_t{0});
|
||||||
|
}
|
||||||
|
|
||||||
|
// indicates start of content of specified scenery file. returns: handle to the layer of the file
|
||||||
|
layer_handle node_layers::open(std::string const &Name)
|
||||||
|
{
|
||||||
|
// the same file can be included more than once, all its content goes to a single layer then
|
||||||
|
auto const lookup{std::find_if(std::begin(m_layers), std::end(m_layers), [&](basic_layer const &Layer) { return Layer.name == Name; })};
|
||||||
|
auto layerhandle{static_cast<layer_handle>(std::distance(std::begin(m_layers), lookup) + 1)};
|
||||||
|
if (lookup == std::end(m_layers))
|
||||||
|
{
|
||||||
|
if (m_layers.size() < static_cast<std::size_t>(std::numeric_limits<layer_handle>::max()))
|
||||||
|
{
|
||||||
|
m_layers.emplace_back();
|
||||||
|
m_layers.back().name = Name;
|
||||||
|
m_layers.back().parent = handle();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// out of handles, content of the file is attributed to the parent layer
|
||||||
|
layerhandle = handle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// NOTE: the stack receives an entry even if the layer wasn't created, to keep it in sync with close() calls
|
||||||
|
m_stack.emplace_back(layerhandle);
|
||||||
|
|
||||||
|
return layerhandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// indicates end of content of the current scenery file. returns: handle to the parent layer, or null_handle if the stack is empty
|
||||||
|
layer_handle node_layers::close()
|
||||||
|
{
|
||||||
|
if (false == m_stack.empty())
|
||||||
|
{
|
||||||
|
m_stack.pop_back();
|
||||||
|
}
|
||||||
|
return handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_layers::clear()
|
||||||
|
{
|
||||||
|
m_layers.clear();
|
||||||
|
m_stack.clear();
|
||||||
|
m_active = null_handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int node_layers::depth(layer_handle Layer) const
|
||||||
|
{
|
||||||
|
auto depth{0};
|
||||||
|
// NOTE: parent is always created before its children, which rules out cycles
|
||||||
|
while (valid(Layer) && layer(Layer).parent != null_handle && layer(Layer).parent < Layer)
|
||||||
|
{
|
||||||
|
Layer = layer(Layer).parent;
|
||||||
|
++depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_layers::count(layer_handle const Layer, layer_item const Item, int const Change)
|
||||||
|
{
|
||||||
|
if (false == valid(Layer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto &itemcount{layer(Layer).items[static_cast<std::size_t>(Item)]};
|
||||||
|
if (Change >= 0)
|
||||||
|
{
|
||||||
|
itemcount += static_cast<std::size_t>(Change);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itemcount -= std::min(itemcount, static_cast<std::size_t>(-Change));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_layers::active(layer_handle const Layer)
|
||||||
|
{
|
||||||
|
if (false == valid(Layer))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// new items land in the active layer, they'd be out of reach right away if it was hidden or locked
|
||||||
|
visible(Layer, true);
|
||||||
|
locked(Layer, false);
|
||||||
|
m_active = Layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shows or hides nodes of specified layer. visibility defined in the scenery is preserved, hidden layer only overrides it
|
||||||
|
void node_layers::visible(layer_handle const Layer, bool const Visible)
|
||||||
|
{
|
||||||
|
if (false == valid(Layer) || layer(Layer).visible == Visible)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layer(Layer).visible = Visible;
|
||||||
|
|
||||||
|
auto const update_node = [Layer, Visible](basic_node *Node) {
|
||||||
|
if (Node == nullptr || Node->layer() != Layer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Visible)
|
||||||
|
{
|
||||||
|
if (Node->m_layerhidden)
|
||||||
|
{
|
||||||
|
Node->visible(true);
|
||||||
|
Node->m_layerhidden = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Node->visible())
|
||||||
|
{
|
||||||
|
// nodes which are invisible on their own aren't marked, so they stay that way when the layer is shown again
|
||||||
|
Node->visible(false);
|
||||||
|
Node->m_layerhidden = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// only these node types are drawn by the renderers basing on their visibility flag
|
||||||
|
for (auto *instance : simulation::Instances.sequence())
|
||||||
|
{
|
||||||
|
update_node(instance);
|
||||||
|
}
|
||||||
|
for (auto *path : simulation::Paths.sequence())
|
||||||
|
{
|
||||||
|
update_node(path);
|
||||||
|
}
|
||||||
|
for (auto *traction : simulation::Traction.sequence())
|
||||||
|
{
|
||||||
|
update_node(traction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_layers::locked(layer_handle const Layer, bool const Locked)
|
||||||
|
{
|
||||||
|
if (valid(Layer))
|
||||||
|
{
|
||||||
|
layer(Layer).locked = Locked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// true if nodes of specified layer can be selected and modified in the editor
|
||||||
|
bool node_layers::editable(layer_handle const Layer) const
|
||||||
|
{
|
||||||
|
// nodes without a layer (regular load, or created by the simulation) aren't restricted
|
||||||
|
return false == valid(Layer) || (layer(Layer).visible && false == layer(Layer).locked);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<layer_handle> node_layers::hidden() const
|
||||||
|
{
|
||||||
|
std::vector<layer_handle> layers;
|
||||||
|
for (std::size_t idx = 0; idx < m_layers.size(); ++idx)
|
||||||
|
{
|
||||||
|
if (false == m_layers[idx].visible)
|
||||||
|
{
|
||||||
|
layers.emplace_back(static_cast<layer_handle>(idx + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return layers;
|
||||||
|
}
|
||||||
|
|
||||||
|
void node_layers::show_all()
|
||||||
|
{
|
||||||
|
for (auto const hiddenlayer : hidden())
|
||||||
|
{
|
||||||
|
visible(hiddenlayer, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace scene
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
117
scene/scenelayers.h
Normal file
117
scene/scenelayers.h
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
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 "scene/scenenode.h"
|
||||||
|
|
||||||
|
namespace scene
|
||||||
|
{
|
||||||
|
|
||||||
|
// kinds of scenery items a layer keeps count of
|
||||||
|
enum class layer_item
|
||||||
|
{
|
||||||
|
model,
|
||||||
|
track,
|
||||||
|
traction,
|
||||||
|
powersource,
|
||||||
|
memcell,
|
||||||
|
launcher,
|
||||||
|
event,
|
||||||
|
vehicle,
|
||||||
|
sound,
|
||||||
|
shape,
|
||||||
|
lines,
|
||||||
|
count_
|
||||||
|
};
|
||||||
|
|
||||||
|
// scenery layer: content of a single scenery file (.scn, .scm, .ctr...) other than an .inc node template
|
||||||
|
struct basic_layer
|
||||||
|
{
|
||||||
|
std::string name; // file name, relative to the scenery directory
|
||||||
|
layer_handle parent{null_handle}; // layer of the file this one was included from
|
||||||
|
bool visible{true};
|
||||||
|
bool locked{false}; // items of locked layer can't be selected in the editor
|
||||||
|
bool binary{false}; // the file wasn't parsed, its content came from binary terrain file
|
||||||
|
std::array<std::size_t, static_cast<std::size_t>(layer_item::count_)> items{}; // amount of items of each kind
|
||||||
|
|
||||||
|
std::size_t item_count() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// holds scenery layers, established during load of scenery opened for editing (-edit)
|
||||||
|
// NOTE: regular load doesn't create any layers, all nodes are left with null_handle
|
||||||
|
class node_layers
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// methods
|
||||||
|
// indicates start of content of specified scenery file. returns: handle to the layer of the file
|
||||||
|
layer_handle open(std::string const &Name);
|
||||||
|
// indicates end of content of the current scenery file. returns: handle to the parent layer, or null_handle if the stack is empty
|
||||||
|
layer_handle close();
|
||||||
|
// returns layer of the scenery file being loaded, or null_handle if there's none
|
||||||
|
layer_handle handle() const
|
||||||
|
{
|
||||||
|
return m_stack.empty() ? null_handle : m_stack.back();
|
||||||
|
}
|
||||||
|
// removes all layers; layer handles stored in the nodes aren't touched
|
||||||
|
void clear();
|
||||||
|
bool empty() const
|
||||||
|
{
|
||||||
|
return m_layers.empty();
|
||||||
|
}
|
||||||
|
std::size_t size() const
|
||||||
|
{
|
||||||
|
return m_layers.size();
|
||||||
|
}
|
||||||
|
bool valid(layer_handle const Layer) const
|
||||||
|
{
|
||||||
|
return Layer != null_handle && Layer <= m_layers.size();
|
||||||
|
}
|
||||||
|
// grants direct access to specified layer. NOTE: handle has to be valid
|
||||||
|
basic_layer &layer(layer_handle const Layer)
|
||||||
|
{
|
||||||
|
return m_layers[Layer - 1];
|
||||||
|
}
|
||||||
|
basic_layer const &layer(layer_handle const Layer) const
|
||||||
|
{
|
||||||
|
return m_layers[Layer - 1];
|
||||||
|
}
|
||||||
|
// number of layers between specified layer and the scenario file
|
||||||
|
int depth(layer_handle Layer) const;
|
||||||
|
// adjusts item count of specified layer
|
||||||
|
void count(layer_handle const Layer, layer_item const Item, int const Change = 1);
|
||||||
|
// layer receiving the items created in the editor, or null_handle if there's none
|
||||||
|
layer_handle active() const
|
||||||
|
{
|
||||||
|
return m_active;
|
||||||
|
}
|
||||||
|
// NOTE: active layer is made visible and unlocked
|
||||||
|
void active(layer_handle const Layer);
|
||||||
|
// shows or hides nodes of specified layer. visibility defined in the scenery is preserved, hidden layer only overrides it
|
||||||
|
void visible(layer_handle const Layer, bool const Visible);
|
||||||
|
void locked(layer_handle const Layer, bool const Locked);
|
||||||
|
// true if nodes of specified layer can be selected and modified in the editor
|
||||||
|
bool editable(layer_handle const Layer) const;
|
||||||
|
// handles of layers which are currently hidden
|
||||||
|
std::vector<layer_handle> hidden() const;
|
||||||
|
// restores visibility of all layers
|
||||||
|
void show_all();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// members
|
||||||
|
std::vector<basic_layer> m_layers; // layer handle is index in the vector + 1
|
||||||
|
std::vector<layer_handle> m_stack; // helper, layers of scenery files being loaded
|
||||||
|
layer_handle m_active{null_handle};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern node_layers Layers;
|
||||||
|
|
||||||
|
} // namespace scene
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
@@ -717,7 +717,8 @@ memory_node::deserialize( cParser &Input, node_data const &Nodedata ) {
|
|||||||
|
|
||||||
|
|
||||||
basic_node::basic_node( scene::node_data const &Nodedata ) :
|
basic_node::basic_node( scene::node_data const &Nodedata ) :
|
||||||
m_name( Nodedata.name )
|
m_name( Nodedata.name ),
|
||||||
|
m_layer( Nodedata.layer )
|
||||||
{
|
{
|
||||||
uuid = UID::random();
|
uuid = UID::random();
|
||||||
node_type = Nodedata.type;
|
node_type = Nodedata.type;
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ struct node_data {
|
|||||||
double range_max { std::numeric_limits<double>::max() };
|
double range_max { std::numeric_limits<double>::max() };
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string type;
|
std::string type;
|
||||||
|
layer_handle layer { null_handle }; // scenery layer the node is defined in, if any
|
||||||
};
|
};
|
||||||
|
|
||||||
// holds unique piece of geometry, covered with single material
|
// holds unique piece of geometry, covered with single material
|
||||||
@@ -359,6 +360,10 @@ public:
|
|||||||
group( scene::group_handle Group );
|
group( scene::group_handle Group );
|
||||||
scene::group_handle
|
scene::group_handle
|
||||||
group() const;
|
group() const;
|
||||||
|
void
|
||||||
|
layer( scene::layer_handle Layer );
|
||||||
|
scene::layer_handle
|
||||||
|
layer() const;
|
||||||
void
|
void
|
||||||
mark_dirty() { m_dirty = true; }
|
mark_dirty() { m_dirty = true; }
|
||||||
bool
|
bool
|
||||||
@@ -375,6 +380,8 @@ public:
|
|||||||
bool m_visible { true }; // visibility flag
|
bool m_visible { true }; // visibility flag
|
||||||
std::string m_name;
|
std::string m_name;
|
||||||
bool m_dirty { false };
|
bool m_dirty { false };
|
||||||
|
bool m_layerhidden { false }; // the node was visible until its scenery layer was hidden
|
||||||
|
scene::layer_handle m_layer { null_handle }; // scenery layer this node belongs to, if any
|
||||||
UID uuid;
|
UID uuid;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -443,6 +450,18 @@ basic_node::group() const {
|
|||||||
return m_group;
|
return m_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
void
|
||||||
|
basic_node::layer( scene::layer_handle Layer ) {
|
||||||
|
m_layer = Layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
scene::layer_handle
|
||||||
|
basic_node::layer() const {
|
||||||
|
return m_layer;
|
||||||
|
}
|
||||||
|
|
||||||
} // scene
|
} // scene
|
||||||
|
|
||||||
//---------------------------------------------------------------------------
|
//---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "rendering/lightarray.h"
|
#include "rendering/lightarray.h"
|
||||||
#include "rendering/particles.h"
|
#include "rendering/particles.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
#include "vehicle/Train.h"
|
#include "vehicle/Train.h"
|
||||||
#include "application/application.h"
|
#include "application/application.h"
|
||||||
#include "utilities/Logs.h"
|
#include "utilities/Logs.h"
|
||||||
@@ -493,6 +494,7 @@ TEventLauncher * state_manager::create_eventlauncher(const std::string &src, con
|
|||||||
}
|
}
|
||||||
|
|
||||||
void state_manager::delete_model(TAnimModel *model) {
|
void state_manager::delete_model(TAnimModel *model) {
|
||||||
|
scene::Layers.count(model->layer(), scene::layer_item::model, -1);
|
||||||
Region->erase(model);
|
Region->erase(model);
|
||||||
Instances.purge(model);
|
Instances.purge(model);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "simulation/simulationsounds.h"
|
#include "simulation/simulationsounds.h"
|
||||||
#include "simulation/simulationenvironment.h"
|
#include "simulation/simulationenvironment.h"
|
||||||
#include "scene/scenenodegroups.h"
|
#include "scene/scenenodegroups.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
#include "rendering/particles.h"
|
#include "rendering/particles.h"
|
||||||
#include "world/Event.h"
|
#include "world/Event.h"
|
||||||
#include "world/MemCell.h"
|
#include "world/MemCell.h"
|
||||||
@@ -73,6 +74,14 @@ state_serializer::deserialize_begin( std::string const &Scenariofile ) {
|
|||||||
}
|
}
|
||||||
scene::Groups.create();
|
scene::Groups.create();
|
||||||
|
|
||||||
|
scene::Layers.clear();
|
||||||
|
if( true == Global.editor_session ) {
|
||||||
|
// scenery opened for editing: keep track of which scenery file defines each node.
|
||||||
|
// the scenario file itself is the root layer, and the default target for nodes created in the editor
|
||||||
|
state->input.sceneryLayers = true;
|
||||||
|
scene::Layers.active( scene::Layers.open( Scenariofile ) );
|
||||||
|
}
|
||||||
|
|
||||||
if( false == state->input.ok() )
|
if( false == state->input.ok() )
|
||||||
throw invalid_scenery_exception();
|
throw invalid_scenery_exception();
|
||||||
|
|
||||||
@@ -155,6 +164,7 @@ state_serializer::deserialize_continue(std::shared_ptr<deserializer_state> state
|
|||||||
}
|
}
|
||||||
|
|
||||||
scene::Groups.close();
|
scene::Groups.close();
|
||||||
|
scene::Layers.close();
|
||||||
|
|
||||||
scene::Groups.update_map();
|
scene::Groups.update_map();
|
||||||
Region->create_map_geometry();
|
Region->create_map_geometry();
|
||||||
@@ -345,6 +355,7 @@ state_serializer::deserialize_event( cParser &Input, scene::scratch_data &Scratc
|
|||||||
|
|
||||||
if( true == simulation::Events.insert( event ) ) {
|
if( true == simulation::Events.insert( event ) ) {
|
||||||
scene::Groups.insert( scene::Groups.handle(), event );
|
scene::Groups.insert( scene::Groups.handle(), event );
|
||||||
|
scene::Layers.count( scene::Layers.handle(), scene::layer_item::event );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
delete event;
|
delete event;
|
||||||
@@ -436,6 +447,7 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
|||||||
>> nodedata.name
|
>> nodedata.name
|
||||||
>> nodedata.type;
|
>> nodedata.type;
|
||||||
if( nodedata.name == "none" ) { nodedata.name.clear(); }
|
if( nodedata.name == "none" ) { nodedata.name.clear(); }
|
||||||
|
nodedata.layer = scene::Layers.handle();
|
||||||
// type-based deserialization. not elegant but it'll do
|
// type-based deserialization. not elegant but it'll do
|
||||||
if( nodedata.type == "dynamic" ) {
|
if( nodedata.type == "dynamic" ) {
|
||||||
|
|
||||||
@@ -643,6 +655,34 @@ state_serializer::deserialize_node( cParser &Input, scene::scratch_data &Scratch
|
|||||||
simulation::Region->insert( sound );
|
simulation::Region->insert( sound );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( nodedata.layer != null_handle ) {
|
||||||
|
// scenery opened for editing: keep count of what the scenery file contains
|
||||||
|
// NOTE: node types which failed to load bail out earlier and aren't counted
|
||||||
|
static std::unordered_map<std::string, scene::layer_item> const itemtypes {
|
||||||
|
{ "dynamic", scene::layer_item::vehicle },
|
||||||
|
{ "track", scene::layer_item::track },
|
||||||
|
{ "traction", scene::layer_item::traction },
|
||||||
|
{ "tractionpowersource", scene::layer_item::powersource },
|
||||||
|
{ "model", scene::layer_item::model },
|
||||||
|
{ "triangles", scene::layer_item::shape },
|
||||||
|
{ "triangle_strip", scene::layer_item::shape },
|
||||||
|
{ "triangle_fan", scene::layer_item::shape },
|
||||||
|
{ "lines", scene::layer_item::lines },
|
||||||
|
{ "line_strip", scene::layer_item::lines },
|
||||||
|
{ "line_loop", scene::layer_item::lines },
|
||||||
|
{ "memcell", scene::layer_item::memcell },
|
||||||
|
{ "eventlauncher", scene::layer_item::launcher },
|
||||||
|
{ "sound", scene::layer_item::sound } };
|
||||||
|
auto const lookup { itemtypes.find( nodedata.type ) };
|
||||||
|
if( lookup != itemtypes.end() ) {
|
||||||
|
scene::Layers.count(
|
||||||
|
nodedata.layer,
|
||||||
|
// models with negative minimum range are 3d terrain, converted to shapes
|
||||||
|
( lookup->second == scene::layer_item::model && nodedata.range_min < 0.0 ) ?
|
||||||
|
scene::layer_item::shape :
|
||||||
|
lookup->second );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1328,6 +1368,7 @@ TAnimModel *state_serializer::create_model(const std::string &src, const std::st
|
|||||||
parser.getTokens(2); // name, type
|
parser.getTokens(2); // name, type
|
||||||
nodedata.name = name;
|
nodedata.name = name;
|
||||||
nodedata.type = "model";
|
nodedata.type = "model";
|
||||||
|
nodedata.layer = scene::Layers.active(); // null_handle unless the scenery was opened for editing
|
||||||
|
|
||||||
scene::scratch_data scratch;
|
scene::scratch_data scratch;
|
||||||
|
|
||||||
@@ -1340,6 +1381,7 @@ TAnimModel *state_serializer::create_model(const std::string &src, const std::st
|
|||||||
cloned->location(position);
|
cloned->location(position);
|
||||||
simulation::Instances.insert(cloned);
|
simulation::Instances.insert(cloned);
|
||||||
simulation::Region->insert(cloned);
|
simulation::Region->insert(cloned);
|
||||||
|
scene::Layers.count(cloned->layer(), scene::layer_item::model);
|
||||||
|
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ namespace scene {
|
|||||||
struct node_data;
|
struct node_data;
|
||||||
class basic_node;
|
class basic_node;
|
||||||
using group_handle = std::size_t;
|
using group_handle = std::size_t;
|
||||||
|
using layer_handle = std::uint16_t;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Mtable
|
namespace Mtable
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ struct global_settings {
|
|||||||
std::string szDefaultExt{ szTexturesDDS };
|
std::string szDefaultExt{ szTexturesDDS };
|
||||||
std::string SceneryFile;
|
std::string SceneryFile;
|
||||||
std::string local_start_vehicle{ "EU07-424" };
|
std::string local_start_vehicle{ "EU07-424" };
|
||||||
|
bool editor_session{ false }; // scenery was opened for editing (-edit): loader keeps track of scenery layers and hands over to the editor
|
||||||
int iConvertModels{ 0 }; // tworzenie plików binarnych
|
int iConvertModels{ 0 }; // tworzenie plików binarnych
|
||||||
int iConvertIndexRange{ 1000 }; // range of duplicate vertex scan
|
int iConvertIndexRange{ 1000 }; // range of duplicate vertex scan
|
||||||
bool file_binary_terrain{ true }; // enable binary terrain (de)serialization
|
bool file_binary_terrain{ true }; // enable binary terrain (de)serialization
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ http://mozilla.org/MPL/2.0/.
|
|||||||
#include "utilities/Logs.h"
|
#include "utilities/Logs.h"
|
||||||
|
|
||||||
#include "scene/scenenodegroups.h"
|
#include "scene/scenenodegroups.h"
|
||||||
|
#include "scene/scenelayers.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MaSzyna EU07 locomotive simulator parser
|
MaSzyna EU07 locomotive simulator parser
|
||||||
@@ -118,6 +119,11 @@ cParser::~cParser()
|
|||||||
// wrap up the node group holding content of processed file
|
// wrap up the node group holding content of processed file
|
||||||
scene::Groups.close();
|
scene::Groups.close();
|
||||||
}
|
}
|
||||||
|
if (true == mLayerFile)
|
||||||
|
{
|
||||||
|
// content of the processed file ended, following nodes belong to the parent layer again
|
||||||
|
scene::Layers.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> glm::vec3 cParser::getToken(bool const ToLower, char const *Break)
|
template <> glm::vec3 cParser::getToken(bool const ToLower, char const *Break)
|
||||||
@@ -336,6 +342,12 @@ void cParser::startIncludeFromParser(cParser& srcParser, bool ToLower, std::stri
|
|||||||
if (isTerrain && true == Global.file_binary_terrain_state) {
|
if (isTerrain && true == Global.file_binary_terrain_state) {
|
||||||
WriteLog("SBT found, ignoring: " + includefile);
|
WriteLog("SBT found, ignoring: " + includefile);
|
||||||
readParameters(srcParser); // preserve original side-effect: still consume parameters
|
readParameters(srcParser); // preserve original side-effect: still consume parameters
|
||||||
|
if (sceneryLayers)
|
||||||
|
{
|
||||||
|
// the file is still a part of the scenery, even though its content comes from the binary terrain file
|
||||||
|
scene::Layers.layer(scene::Layers.open(includefile)).binary = true;
|
||||||
|
scene::Layers.close();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +367,18 @@ void cParser::startIncludeFromParser(cParser& srcParser, bool ToLower, std::stri
|
|||||||
if (mIncludeParser->mSize <= 0) {
|
if (mIncludeParser->mSize <= 0) {
|
||||||
ErrorLog("Bad include: can't open file \"" + includefile + "\"");
|
ErrorLog("Bad include: can't open file \"" + includefile + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sceneryLayers)
|
||||||
|
{
|
||||||
|
mIncludeParser->sceneryLayers = true;
|
||||||
|
// content of an included scenery file forms a layer of its own. *.inc files are node templates
|
||||||
|
// reused all over the scenery, so their content stays in the layer of the file which includes them
|
||||||
|
if (false == mIncludeParser->mIncFile && mIncludeParser->mSize > 0)
|
||||||
|
{
|
||||||
|
scene::Layers.open(includefile);
|
||||||
|
mIncludeParser->mLayerFile = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cParser::handleIncludeIfPresent(std::string& token, bool ToLower, const char* Break) {
|
bool cParser::handleIncludeIfPresent(std::string& token, bool ToLower, const char* Break) {
|
||||||
@@ -524,6 +548,7 @@ void cParser::injectString(const std::string &str)
|
|||||||
{
|
{
|
||||||
mIncludeParser = std::make_shared<cParser>(str, buffer_TEXT, "", LoadTraction, std::vector<std::string>(), allowRandomIncludes);
|
mIncludeParser = std::make_shared<cParser>(str, buffer_TEXT, "", LoadTraction, std::vector<std::string>(), allowRandomIncludes);
|
||||||
mIncludeParser->autoclear(m_autoclear);
|
mIncludeParser->autoclear(m_autoclear);
|
||||||
|
mIncludeParser->sceneryLayers = sceneryLayers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ class cParser //: public std::stringstream
|
|||||||
bool expandIncludes = true;
|
bool expandIncludes = true;
|
||||||
bool allowRandomIncludes = false;
|
bool allowRandomIncludes = false;
|
||||||
bool skipComments = true;
|
bool skipComments = true;
|
||||||
|
bool sceneryLayers = false; // included scenery files are registered as scenery layers (scenery opened for editing)
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startIncludeFromParser(cParser &srcParser, bool ToLower, std::string includefile);
|
void startIncludeFromParser(cParser &srcParser, bool ToLower, std::string includefile);
|
||||||
@@ -118,6 +119,7 @@ class cParser //: public std::stringstream
|
|||||||
std::streamoff mSize { 0 }; // size of open stream, for progress report.
|
std::streamoff mSize { 0 }; // size of open stream, for progress report.
|
||||||
std::size_t mLine { 0 }; // currently processed line
|
std::size_t mLine { 0 }; // currently processed line
|
||||||
bool mIncFile { false }; // the parser is processing an *.inc file
|
bool mIncFile { false }; // the parser is processing an *.inc file
|
||||||
|
bool mLayerFile { false }; // the parser is processing a file registered as scenery layer
|
||||||
bool mFirstToken { true }; // processing first token in the current file; helper used when checking for utf bom
|
bool mFirstToken { true }; // processing first token in the current file; helper used when checking for utf bom
|
||||||
typedef std::map<std::string, std::string> commentmap;
|
typedef std::map<std::string, std::string> commentmap;
|
||||||
commentmap mComments {
|
commentmap mComments {
|
||||||
|
|||||||
Reference in New Issue
Block a user