mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 02:49:19 +02:00
feat(editor): edit session (-edit) and scenery layers
This commit is contained in:
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 ) :
|
||||
m_name( Nodedata.name )
|
||||
m_name( Nodedata.name ),
|
||||
m_layer( Nodedata.layer )
|
||||
{
|
||||
uuid = UID::random();
|
||||
node_type = Nodedata.type;
|
||||
|
||||
@@ -70,6 +70,7 @@ struct node_data {
|
||||
double range_max { std::numeric_limits<double>::max() };
|
||||
std::string name;
|
||||
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
|
||||
@@ -359,6 +360,10 @@ public:
|
||||
group( scene::group_handle Group );
|
||||
scene::group_handle
|
||||
group() const;
|
||||
void
|
||||
layer( scene::layer_handle Layer );
|
||||
scene::layer_handle
|
||||
layer() const;
|
||||
void
|
||||
mark_dirty() { m_dirty = true; }
|
||||
bool
|
||||
@@ -375,6 +380,8 @@ public:
|
||||
bool m_visible { true }; // visibility flag
|
||||
std::string m_name;
|
||||
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;
|
||||
|
||||
private:
|
||||
@@ -443,6 +450,18 @@ basic_node::group() const {
|
||||
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
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user