mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-11-07 00:22:56 +01:00
feat(editor): layers window, scenery save and include descriptions
This commit is contained in:
@@ -11,6 +11,9 @@ http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "scene/scenenode.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
|
||||
namespace scene
|
||||
{
|
||||
|
||||
@@ -31,6 +34,39 @@ enum class layer_item
|
||||
count_
|
||||
};
|
||||
|
||||
// placement applied to scenery statements by the origin, rotate and scale directives in effect
|
||||
struct layer_context
|
||||
{
|
||||
glm::dvec3 offset{0.0};
|
||||
glm::vec3 rotation{0.f};
|
||||
glm::vec3 scale{1.f};
|
||||
|
||||
// converts world space location to the one which produces it when loaded with this context in effect
|
||||
glm::dvec3 to_local(glm::dvec3 Location) const;
|
||||
bool matches(layer_context const &Other) const;
|
||||
};
|
||||
|
||||
// location of a piece of text in a scenery file, as byte offsets
|
||||
struct source_span
|
||||
{
|
||||
std::streamoff begin{-1};
|
||||
std::streamoff end{-1};
|
||||
|
||||
bool valid() const
|
||||
{
|
||||
return begin >= 0 && end > begin;
|
||||
}
|
||||
};
|
||||
|
||||
// include directive bringing a scenery file into another one
|
||||
struct include_site
|
||||
{
|
||||
layer_handle parent{null_handle}; // layer of the file holding the directive
|
||||
source_span span; // location of the whole directive in that file
|
||||
bool parameters{false}; // the file is included with parameters
|
||||
bool fixed{false}; // the directive can't be rewritten: it's a part of an *.inc template, or its location is unknown
|
||||
};
|
||||
|
||||
// scenery layer: content of a single scenery file (.scn, .scm, .ctr...) other than an .inc node template
|
||||
struct basic_layer
|
||||
{
|
||||
@@ -40,18 +76,51 @@ struct basic_layer
|
||||
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
|
||||
// source data, used by the scenery save
|
||||
std::vector<include_site> sites; // include directives bringing the file in; empty for the scenario file
|
||||
layer_context context_begin; // placement in effect at the start of the file...
|
||||
layer_context context_end; // ...and right after its end
|
||||
std::uintmax_t filesize{0}; // state of the file when it was loaded or saved the last time
|
||||
std::filesystem::file_time_type filetime{};
|
||||
// pending changes, applied by the scenery save
|
||||
bool created{false}; // layer was created in the editor, its file doesn't exist yet
|
||||
bool editormade{false}; // the file was made by the editor during this session, there's no original content to keep a backup of
|
||||
layer_handle anchor{null_handle}; // for created layer: sibling its include directive goes after
|
||||
bool removed{false}; // layer is to be dropped from the scenery
|
||||
layer_handle merged{null_handle}; // layer which took over the content of this one
|
||||
bool dead{false}; // removal or merge of the layer was saved, it's no longer a part of the scenery
|
||||
|
||||
std::size_t item_count() const;
|
||||
};
|
||||
|
||||
// origin of a node defined in a scenery layer file, with the placement it was loaded with
|
||||
struct node_source
|
||||
{
|
||||
layer_handle layer{null_handle}; // layer of the file holding the node definition
|
||||
source_span span; // location of the definition in that file
|
||||
layer_context context; // placement in effect at the definition
|
||||
glm::dvec3 location{0.0};
|
||||
glm::vec3 angles{0.f};
|
||||
glm::vec3 scale{1.f};
|
||||
};
|
||||
|
||||
struct save_result
|
||||
{
|
||||
bool success{false};
|
||||
std::vector<std::string> files; // names of saved files
|
||||
std::string message; // summary, or cause of the failure
|
||||
};
|
||||
|
||||
// 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
|
||||
// indicates start of content of the scenario file. returns: handle to its layer
|
||||
layer_handle open(std::string const &Name);
|
||||
// indicates start of content of specified scenery file, included by specified directive. returns: handle to the layer of the file
|
||||
layer_handle open(std::string const &Name, include_site Site);
|
||||
// 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
|
||||
@@ -82,32 +151,110 @@ class node_layers
|
||||
{
|
||||
return m_layers[Layer - 1];
|
||||
}
|
||||
// follows layer merges. returns: handle of the layer which currently holds content of specified layer
|
||||
layer_handle resolve(layer_handle Layer) const;
|
||||
// true if the layer is a part of the scenery and should be presented to the user
|
||||
bool listed(layer_handle const Layer) const
|
||||
{
|
||||
return valid(Layer) && false == layer(Layer).dead && layer(Layer).merged == null_handle;
|
||||
}
|
||||
// number of layers between specified layer and the scenario file
|
||||
int depth(layer_handle Layer) const;
|
||||
// handles of the layers to present to the user, each followed by the layers it includes
|
||||
std::vector<layer_handle> tree() const;
|
||||
// adjusts item count of specified layer
|
||||
void count(layer_handle const Layer, layer_item const Item, int const Change = 1);
|
||||
void count(layer_handle 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);
|
||||
void active(layer_handle 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);
|
||||
void visible(layer_handle Layer, bool const Visible);
|
||||
void locked(layer_handle Layer, bool const Locked);
|
||||
// true if the file of specified layer can be rewritten with changed nodes. optionally explains why it can't
|
||||
bool writable(layer_handle Layer, std::string *Reason = nullptr) const;
|
||||
// true if nodes of specified layer can be selected and modified in the editor
|
||||
bool editable(layer_handle const Layer) const;
|
||||
bool editable(layer_handle Layer) const;
|
||||
// true if specified node can be selected and modified in the editor. optionally explains why it can't
|
||||
bool editable(basic_node const *Node, std::string *Reason = nullptr) const;
|
||||
// moves specified node to specified layer
|
||||
void move(basic_node *Node, layer_handle Layer);
|
||||
// handles of layers which are currently hidden
|
||||
std::vector<layer_handle> hidden() const;
|
||||
// restores visibility of all layers
|
||||
void show_all();
|
||||
|
||||
// scenery load bookkeeping
|
||||
// registers *.inc template used by the scenery
|
||||
void template_used(std::string const &Name)
|
||||
{
|
||||
m_templates.emplace(Name);
|
||||
}
|
||||
std::set<std::string> const &templates() const
|
||||
{
|
||||
return m_templates;
|
||||
}
|
||||
// updates placement in effect for the statements which follow
|
||||
void context(layer_context const &Context)
|
||||
{
|
||||
m_context = Context;
|
||||
}
|
||||
// stores origin of a node defined directly in a layer file, to allow rewriting its definition on save
|
||||
void track(basic_node const *Node, source_span const &Span, glm::vec3 const &Angles = glm::vec3{0.f}, glm::vec3 const &Scale = glm::vec3{1.f});
|
||||
// indicates specified node was removed from the scene
|
||||
void forget(basic_node const *Node);
|
||||
// notes the scenery already holds the directive setting up terrain made in the editor
|
||||
void terrain_directive(bool const Present)
|
||||
{
|
||||
m_terraindirective = Present;
|
||||
}
|
||||
bool terrain_directive() const
|
||||
{
|
||||
return m_terraindirective;
|
||||
}
|
||||
|
||||
// layer management. changes are applied to the scenery files by save()
|
||||
// creates empty layer, included from specified one. returns: handle to the new layer, or null_handle with the explanation in Reason
|
||||
layer_handle create(std::string Name, layer_handle Parent, std::string &Reason);
|
||||
bool can_remove(layer_handle Layer, std::string &Reason) const;
|
||||
// marks specified layer and the layers it includes as dropped from the scenery. their files are left on the disk
|
||||
bool remove(layer_handle Layer);
|
||||
// takes back remove() which wasn't saved yet
|
||||
void restore(layer_handle Layer);
|
||||
bool can_merge(layer_handle Source, layer_handle Target, std::string &Reason) const;
|
||||
// moves content of the source layer to the target layer
|
||||
bool merge(layer_handle Source, layer_handle Target);
|
||||
// true if there are layer changes awaiting save. NOTE: doesn't account for modified nodes
|
||||
bool pending() const;
|
||||
// true if specified layer is included, directly or not, by the other one
|
||||
bool is_descendant(layer_handle Layer, layer_handle const Ancestor) const;
|
||||
|
||||
// writes changes made in the editor to the scenery files: changed, created and deleted model instances and
|
||||
// memory cells, and layer changes. the files are left intact unless the whole operation can be performed.
|
||||
// Rootstatements: additional statements to place at the end of the scenario file
|
||||
save_result save(std::vector<std::string> const &Rootstatements = {});
|
||||
|
||||
private:
|
||||
// types
|
||||
struct file_patch;
|
||||
struct composition;
|
||||
struct save_state;
|
||||
// methods
|
||||
std::string path(layer_handle const Layer) const;
|
||||
void stat(layer_handle const Layer);
|
||||
bool compose(save_state &State, layer_handle const Layer, composition &Output, int const Depth) const;
|
||||
// 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};
|
||||
layer_context m_context; // placement in effect at the current point of scenery load
|
||||
std::unordered_map<basic_node const *, node_source> m_sources; // origins of nodes which can be rewritten on save
|
||||
std::vector<std::pair<layer_handle, source_span>> m_erased; // definitions of nodes deleted since the load or the last save
|
||||
std::set<std::string> m_templates; // *.inc templates used by the scenery
|
||||
bool m_terraindirective{false};
|
||||
};
|
||||
|
||||
extern node_layers Layers;
|
||||
|
||||
Reference in New Issue
Block a user