mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 16:49:21 +02:00
311 lines
15 KiB
C++
311 lines
15 KiB
C++
/*
|
|
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/applicationmode.h"
|
|
#include "application/editoruipanels.h"
|
|
#include "input/editormouseinput.h"
|
|
#include "input/editorkeyboardinput.h"
|
|
#include "vehicle/Camera.h"
|
|
#include "scene/sceneeditor.h"
|
|
#include "scene/scenenode.h"
|
|
#include "editor/editorTerrain.hpp"
|
|
#include "editor/editorTerrainStreamer.hpp"
|
|
#include "editor/editorOrthophoto.hpp"
|
|
#include "editor/editorTrack.hpp"
|
|
|
|
#include <array>
|
|
#include <chrono>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class TAnimModel;
|
|
class TTrack;
|
|
|
|
class editor_mode : public application_mode
|
|
{
|
|
|
|
public:
|
|
// constructors
|
|
editor_mode();
|
|
// methods
|
|
// initializes internal data structures of the mode. returns: true on success, false otherwise
|
|
bool init() override;
|
|
// mode-specific update of simulation data. returns: false on error, true otherwise
|
|
bool update() override;
|
|
// maintenance method, called when the mode is activated
|
|
void enter() override;
|
|
// maintenance method, called when the mode is deactivated
|
|
void exit() override;
|
|
// input handlers
|
|
void on_key(int Key, int Scancode, int Action, int Mods) override;
|
|
void on_cursor_pos(double Horizontal, double Vertical) override;
|
|
void on_mouse_button(int Button, int Action, int Mods) override;
|
|
void on_scroll(double const Xoffset, double const Yoffset) override
|
|
{
|
|
;
|
|
}
|
|
void on_window_resize(int w, int h) override
|
|
{
|
|
;
|
|
}
|
|
void on_event_poll() override;
|
|
bool is_command_processor() const override;
|
|
void undo_last();
|
|
static bool focus_active();
|
|
static void set_focus_active(bool isActive);
|
|
static TCamera& get_camera() { return Camera; }
|
|
static bool change_history() { return m_change_history; }
|
|
static void set_change_history(bool enabled) { m_change_history = enabled; }
|
|
static bool settings_open() { return m_settings_open; }
|
|
static void set_settings_open(bool enabled) { m_settings_open = enabled; }
|
|
private:
|
|
// types
|
|
struct editormode_input
|
|
{
|
|
|
|
editormouse_input mouse;
|
|
editorkeyboard_input keyboard;
|
|
|
|
bool init();
|
|
void poll();
|
|
};
|
|
|
|
struct state_backup
|
|
{
|
|
|
|
TCamera camera;
|
|
bool freefly;
|
|
bool picking;
|
|
};
|
|
|
|
struct EditorSnapshot
|
|
{
|
|
enum class Action { Move, Rotate, Scale, Add, Delete, TrackEdit, Other };
|
|
|
|
Action action{Action::Other};
|
|
std::string node_name; // node identifier (basic_node::name())
|
|
// direct pointer to node when available; used for in-memory undo/redo lookup
|
|
scene::basic_node *node_ptr{nullptr};
|
|
std::string serialized; // full text for recreate (used for Add/Delete)
|
|
glm::dvec3 position{0.0, 0.0, 0.0};
|
|
glm::vec3 rotation{0.0f, 0.0f, 0.0f};
|
|
glm::vec3 scale{1.0f, 1.0f, 1.0f};
|
|
UID uuid; // node UUID for reference, used as fallback lookup for deleted/recreated nodes
|
|
scene::layer_handle layer{null_handle}; // scenery layer of the node, so a recreated node returns to it
|
|
scene::instance_handle instance{0}; // include of a scenery template which was placed or removed, instead of a node
|
|
// TrackEdit: state of all paths modified by the change (the edited path and neighbours dragged along)
|
|
std::vector<std::pair<TTrack *, editor_track::state>> tracks;
|
|
|
|
};
|
|
void push_snapshot(scene::basic_node *node, EditorSnapshot::Action Action = EditorSnapshot::Action::Move, std::string const &Serialized = std::string());
|
|
|
|
std::vector<EditorSnapshot> m_history; // history of changes to nodes, used for undo functionality
|
|
std::vector<EditorSnapshot> g_redo;
|
|
// methods
|
|
void update_camera(double const Deltatime);
|
|
|
|
editor_ui *ui() const;
|
|
void redo_last();
|
|
void handle_brush_mouse_hold(int Action, int Button);
|
|
void apply_rotation_for_new_node(scene::basic_node *node, int rotation_mode, float fixed_rotation_value);
|
|
// members
|
|
state_backup m_statebackup; // helper, cached variables to be restored on mode exit
|
|
editormode_input m_input;
|
|
static TCamera Camera;
|
|
|
|
// focus (smooth camera fly-to) state
|
|
static bool m_focus_active;
|
|
glm::dvec3 m_focus_start_pos{0.0,0.0,0.0};
|
|
glm::dvec3 m_focus_target_pos{0.0,0.0,0.0};
|
|
glm::vec3 m_focus_start_angle{0.0f}; // camera pitch/yaw/roll at focus start
|
|
glm::vec3 m_focus_target_angle{0.0f}; // camera pitch/yaw/roll facing the focused object
|
|
double m_focus_time{0.0};
|
|
double m_focus_duration{0.6};
|
|
|
|
double fTime50Hz{0.0}; // bufor czasu dla komunikacji z PoKeys
|
|
scene::basic_editor m_editor;
|
|
scene::basic_node *m_node{nullptr}; // currently selected scene node
|
|
scene::instance_handle m_instance{0}; // currently selected include of a scenery template; these are handled as a whole
|
|
include_selection m_include; // parameters of the selected include, changed with the gizmo and in the node properties
|
|
bool m_include_gesture{false}; // a change of the selected include is under way, and has its undo snapshot already
|
|
std::vector<std::pair<TAnimModel *, int>> m_retired; // models replaced after changes of includes, with the frames left until they're destroyed
|
|
bool m_takesnapshot{true}; // helper, hints whether snapshot of selected node(s) should be taken before modification
|
|
bool m_dragging = false;
|
|
glm::dvec3 oldPos; // world position of the last brush placement
|
|
bool m_brush_has_last{false}; // false at the start of a brush stroke, so the first placement ignores spacing
|
|
bool mouseHold{false};
|
|
float kMaxPlacementDistance = 200.0f;
|
|
static bool m_change_history;
|
|
static bool m_settings_open;
|
|
|
|
// camera fly-mode (right mouse button held); used to flush motion when it's released
|
|
command_relay m_camera_relay;
|
|
bool m_camera_flying{false};
|
|
|
|
// UI/history settings
|
|
int m_max_history_size{200};
|
|
int m_selected_history_idx{-1};
|
|
glm::dvec3 clamp_mouse_offset_to_max(const glm::dvec3 &offset);
|
|
|
|
// focus camera smoothly on specified node
|
|
void start_focus(scene::basic_node *node, double duration = 0.6);
|
|
|
|
// drops the node straight down onto the nearest surface below (terrain or another object)
|
|
void snap_to_ground(scene::basic_node *node);
|
|
|
|
// editable terrain patches created in the editor
|
|
void render_terrain_ui();
|
|
// creates a large terrain as a grid of adjacent chunks (each its own editable patch)
|
|
void create_chunked_terrain();
|
|
// manual grid-aligned chunks: add/remove single chunks for fine control
|
|
float chunk_grid_size() const { return m_terrain_cells * m_terrain_cellsize; }
|
|
void add_grid_chunk(int Cx, int Cz);
|
|
void remove_grid_chunk(int Cx, int Cz);
|
|
// handles a click in chunk-edit mode (add a neighbour, or Shift = delete the clicked chunk)
|
|
void handle_chunk_edit_click(bool DeleteMode);
|
|
// commits authored terrain to disk, enables streaming, and exports the scenery
|
|
void save_scene_with_terrain();
|
|
// commits authored terrain to disk and enables streaming
|
|
void commit_terrain();
|
|
// writes the changes to the files of scenery opened for editing (Ctrl+S)
|
|
void save();
|
|
// places include of specified scenery template at the cursor, in the active layer
|
|
void place_include(std::string const &File, int RotationMode, float FixedRotation);
|
|
// undo and redo of placing or removing an include: brings removed include back, or removes it
|
|
void toggle_include(scene::instance_handle Instance);
|
|
// makes specified include the selected one, 0 clears the selection
|
|
void select_include(scene::instance_handle Instance);
|
|
// writes parameter values of the selected include to its directive, and shows the outcome in the scene
|
|
void apply_include();
|
|
// replaces directive of specified include, and the models shown for it
|
|
void set_include_directive(scene::instance_handle Instance, std::string const &Directive);
|
|
// undo and redo of an include snapshot
|
|
void restore_include(EditorSnapshot &Snapshot);
|
|
// gizmo for the selected include, limited to what the parameters of its template can express
|
|
void render_include_gizmo(glm::mat4 const &View, glm::mat4 const &Projection, glm::dvec3 const &Camerapos);
|
|
// 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
|
|
editor_terrain *terrain_at(double X, double Z);
|
|
// gathers every active terrain patch: manually-created ones plus streamed chunks
|
|
std::vector<editor_terrain *> active_terrains();
|
|
// samples the selected model instance's geometry into a new editable terrain patch, then removes it
|
|
void capture_terrain();
|
|
std::vector<std::unique_ptr<editor_terrain>> m_terrains;
|
|
// grid-aligned manual chunks, keyed by (cx,cz) on the global chunk grid
|
|
std::map<std::pair<int, int>, std::unique_ptr<editor_terrain>> m_grid_chunks;
|
|
bool m_terrain_sculpt{false}; // when true, LMB sculpts terrain instead of picking
|
|
bool m_chunk_edit{false}; // when true, LMB adds/removes whole chunks
|
|
int m_terrain_cells{32}; // grid resolution (quads per side)
|
|
int m_terrain_chunks{4}; // chunks per side for a chunked terrain
|
|
float m_terrain_cellsize{2.0f}; // metres per quad
|
|
float m_terrain_baseheight{0.0f}; // flat starting height
|
|
float m_terrain_brush_radius{12.0f};
|
|
float m_terrain_brush_strength{4.0f}; // metres per second while held (one-shot for the buttons)
|
|
float m_terrain_simplify_error{0.5f}; // flatness tolerance (m) for mesh simplification
|
|
bool m_terrain_auto_optimize{false}; // auto-simplify edited chunks after sculpting settles
|
|
double m_terrain_idle{0.0}; // seconds since the last sculpt edit (debounce timer)
|
|
char m_terrain_texture[128]{""}; // optional ground texture name
|
|
|
|
// streaming terrain that follows the camera (open-world); the editor shares the single
|
|
// simulation-level instance so authored terrain also renders in the driver / other modes
|
|
terrain_streamer &m_streamer{EditorTerrain};
|
|
int m_stream_radius{2};
|
|
bool m_stream_persist{true}; // save edited chunks to disk and load them back
|
|
|
|
// geoportal orthophoto layer drawn under the other viewport overlays
|
|
void render_orthophoto_ui();
|
|
void draw_orthophoto();
|
|
// picks up the stored settings and the origin of the current scenery
|
|
void load_orthophoto_settings();
|
|
void save_orthophoto_settings();
|
|
editor_orthophoto m_orthophoto;
|
|
std::string m_orthophoto_scenery; // scenery whose origin is loaded
|
|
glm::dvec2 m_orthophoto_origin_edit{0.0}; // origin being typed in (northing, easting); applied when editing ends
|
|
|
|
// hierarchy management
|
|
void add_to_hierarchy(scene::basic_node *node);
|
|
void remove_from_hierarchy(scene::basic_node *node);
|
|
scene::basic_node* find_in_hierarchy(const std::string &uuid_str);
|
|
scene::basic_node* find_node_by_any(scene::basic_node *node_ptr, const std::string &uuid_str, const std::string &name);
|
|
|
|
// clear history/redo pointers that reference the given node (prevent dangling pointers)
|
|
void nullify_history_pointers(scene::basic_node *node);
|
|
void render_change_history();
|
|
void render_settings();
|
|
|
|
// area fill: scatters models from a package over a polygon outlined in the viewport
|
|
void render_area_fill();
|
|
void draw_area_fill_outline() const;
|
|
void add_area_fill_point();
|
|
void run_area_fill();
|
|
void undo_last_area_fill();
|
|
std::vector<glm::dvec3> m_fill_points; // outline vertices (world space) in click order
|
|
std::vector<TAnimModel *> m_fill_last; // instances created by the most recent fill, for "Undo last fill"
|
|
std::vector<std::string> m_fill_custom; // user-assembled package of node templates
|
|
int m_fill_custom_idx{-1};
|
|
model_set_ref m_fill_source; // manual = m_fill_custom, otherwise a user set or node bank group
|
|
float m_fill_density{200.0f}; // objects per hectare
|
|
float m_fill_min_spacing{2.0f}; // minimal distance between placed objects (m)
|
|
bool m_fill_random_rotation{true}; // random yaw; otherwise the Functions panel rotation settings apply
|
|
float m_fill_scale_min{1.0f};
|
|
float m_fill_scale_max{1.0f};
|
|
bool m_fill_models_as_ground{true}; // large model instances (terrain tiles) count as ground
|
|
std::string m_fill_status; // result of the last fill, shown in the panel
|
|
|
|
// ImGuizmo-based transform gizmo for the selected node
|
|
enum class gizmo_operation { translate, rotate, scale };
|
|
void render_gizmo();
|
|
// gizmo settings, drawn in the toolset window
|
|
void render_gizmo_options();
|
|
bool m_gizmo_enabled{true}; // master switch for the in-viewport gizmo
|
|
bool m_gizmo_using{false}; // tracks an ongoing drag, so a single undo snapshot is taken per drag
|
|
bool m_gizmo_local{false}; // manipulate in the object's local space instead of world space
|
|
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
|
|
|
|
// path (track) editing, implemented in editormodetrack.cpp
|
|
TTrack *selected_track() const;
|
|
// settings and parameters of the selected path, drawn in the node bank tab of the track mode
|
|
void render_track_ui();
|
|
// curve and point handles of the selected path
|
|
void draw_track_overlay() const;
|
|
// selects the point handle of the selected path located under the cursor. returns: true if a handle was hit
|
|
bool pick_track_handle();
|
|
// selects the path picked in the viewport
|
|
void select_track(scene::basic_node *Node);
|
|
// gizmo for the selected path: moves the selected point handle, or the whole path
|
|
void render_track_gizmo();
|
|
// rebuilds paths modified by the ongoing drag; unless forced, at most a few times per second
|
|
void commit_track_drag(bool const Force);
|
|
// records provided state of paths in the undo history
|
|
void push_track_snapshot(std::vector<std::pair<TTrack *, editor_track::state>> States);
|
|
// restores state of paths stored in the history, moving their current state to the opposite stack
|
|
void restore_track_snapshot(EditorSnapshot const &Snapshot, std::vector<EditorSnapshot> &Opposite);
|
|
editor_track::point_ref m_track_point; // selected point handle of the selected path
|
|
std::vector<TTrack *> m_track_drag; // paths modified by the ongoing gizmo drag
|
|
std::vector<std::pair<TTrack *, editor_track::point_ref>> m_track_drag_points; // end points of neighbours dragged along
|
|
editor_track::snap_target m_track_snap; // connection made at the end of the ongoing drag
|
|
glm::dvec3 m_track_pivot{0.0}; // rotation pivot of the ongoing drag
|
|
glm::mat4 m_track_gizmo{1.0f}; // gizmo matrix, kept for the duration of a drag
|
|
bool m_track_gizmo_using{false};
|
|
bool m_track_dirty{false}; // drag changes waiting for rebuild
|
|
std::chrono::steady_clock::time_point m_track_last_commit;
|
|
editor_track::state m_track_field_before; // state of the path before the ongoing field edit
|
|
std::array<std::array<char, 256>, 3> m_track_materials{}; // material names being edited
|
|
float m_track_snap_radius{1.0f};
|
|
bool m_track_align_tangent{true};
|
|
bool m_track_drag_connected{true};
|
|
};
|