Files
godot/editor/scene/3d/node_3d_editor_plugin.h
T
smix8 eb00a8546d Split Node3DEditorViewport into a dedicated file
Splits `Node3DEditorViewport` into a dedicated file.

The main `Node3DEditorPlugin` file was one if the biggest files of the entire engine. It was getting way too big to be viewed, parsed and displayed effectively (e.g. GitHub, certain IDEs). While still big after this PR it at least splits it more or less in half.

- Moves `Node3DEditorViewport` and related helper classes to its own file `node_3d_editor_viewport` file.
- Moves the (shared) constexpr to its own file `node_3d_editor_constants` file.
- Forward declares many more classes.
- Removes unnecessary includes.
- Fixes classes that needed the actual Node3DViewport class.
2026-06-19 17:30:50 +02:00

535 lines
18 KiB
C++

/**************************************************************************/
/* node_3d_editor_plugin.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "core/math/dynamic_bvh.h"
#include "editor/plugins/editor_plugin.h"
#include "editor/scene/3d/node_3d_editor_gizmos.h"
#include "scene/debugger/view_3d_controller.h"
#include "scene/gui/box_container.h"
#include "scene/gui/popup.h"
class AcceptDialog;
class Button;
class ColorPickerButton;
class ConfirmationDialog;
class DirectionalLight3D;
class EditorSelection;
class EditorSpinSlider;
class HSplitContainer;
class LineEdit;
class MenuButton;
class Node3DEditorViewport;
class Node3DEditorViewportContainer;
class OptionButton;
class PanelContainer;
class ProceduralSkyMaterial;
class SpinBox;
class VSeparator;
class VSplitContainer;
class WorldEnvironment;
class Node3DEditor : public VBoxContainer {
GDCLASS(Node3DEditor, VBoxContainer);
public:
static const unsigned int VIEWPORTS_COUNT = 4;
enum ToolMode {
TOOL_MODE_TRANSFORM,
TOOL_MODE_MOVE,
TOOL_MODE_ROTATE,
TOOL_MODE_SCALE,
TOOL_MODE_SELECT,
TOOL_MODE_LIST_SELECT,
TOOL_LOCK_SELECTED,
TOOL_UNLOCK_SELECTED,
TOOL_GROUP_SELECTED,
TOOL_UNGROUP_SELECTED,
TOOL_RULER,
TOOL_MAX
};
enum ToolOptions {
TOOL_OPT_LOCAL_COORDS,
TOOL_OPT_USE_SNAP,
TOOL_OPT_USE_TRACKBALL,
TOOL_OPT_PRESERVE_CHILDREN_TRANSFORM,
TOOL_OPT_MAX
};
enum TransformMode {
TRANSFORM_MODE_GLOBAL = 1,
TRANSFORM_MODE_LOCAL = 2,
};
real_t gizmo_view_rotation_scale = 1.0;
private:
EditorSelection *editor_selection = nullptr;
Node3DEditorViewportContainer *viewport_base = nullptr;
Node3DEditorViewport *viewports[VIEWPORTS_COUNT];
int last_used_viewport = 0;
VSplitContainer *shader_split = nullptr;
HSplitContainer *left_panel_split = nullptr;
HSplitContainer *right_panel_split = nullptr;
/////
ToolMode tool_mode = TOOL_MODE_TRANSFORM;
RID origin_mesh;
RID origin_multimesh;
RID origin_instance;
bool origin_enabled = false;
RID grid[3];
RID grid_instance[3];
bool grid_visible[3] = { false, false, false }; //currently visible
bool grid_enable[3] = { false, false, false }; //should be always visible if true
bool grid_enabled = false;
bool grid_init_draw = false;
Camera3D::ProjectionType grid_camera_last_update_perspective = Camera3D::PROJECTION_PERSPECTIVE;
Vector3 grid_camera_last_update_position;
Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3];
Ref<ArrayMesh> trackball_sphere_gizmo;
Ref<StandardMaterial3D> gizmo_color[3];
Ref<StandardMaterial3D> plane_gizmo_color[3];
Ref<ShaderMaterial> rotate_gizmo_color[4];
Ref<StandardMaterial3D> gizmo_color_hl[3];
Ref<StandardMaterial3D> plane_gizmo_color_hl[3];
Ref<ShaderMaterial> rotate_gizmo_color_hl[4];
Ref<StandardMaterial3D> trackball_sphere_material;
Ref<StandardMaterial3D> trackball_sphere_material_hl;
Ref<Node3DGizmo> current_hover_gizmo;
int current_hover_gizmo_handle;
bool current_hover_gizmo_handle_secondary;
DynamicBVH gizmo_bvh;
real_t snap_translate_value = 0;
real_t snap_rotate_value = 0;
real_t snap_scale_value = 0;
Ref<ArrayMesh> active_selection_box_xray;
Ref<ArrayMesh> active_selection_box;
Ref<ArrayMesh> selection_box_xray;
Ref<ArrayMesh> selection_box;
Ref<StandardMaterial3D> selection_box_mat;
Ref<StandardMaterial3D> selection_box_mat_xray;
Ref<StandardMaterial3D> active_selection_box_mat;
Ref<StandardMaterial3D> active_selection_box_mat_xray;
RID indicators;
RID indicators_instance;
RID cursor_mesh;
RID cursor_instance;
Ref<ShaderMaterial> origin_mat;
Ref<ShaderMaterial> grid_mat[3];
Ref<StandardMaterial3D> cursor_material;
// Scene drag and drop support
Node3D *preview_node = nullptr;
AABB preview_bounds;
Ref<Material> preview_material;
Ref<Material> preview_reset_material;
ObjectID preview_material_target;
int preview_material_surface = -1;
struct Gizmo {
bool visible = false;
real_t scale = 0;
Transform3D transform;
} gizmo;
enum MenuOption {
MENU_TOOL_TRANSFORM,
MENU_TOOL_MOVE,
MENU_TOOL_ROTATE,
MENU_TOOL_SCALE,
MENU_TOOL_SELECT,
MENU_TOOL_LIST_SELECT,
MENU_TOOL_LOCAL_COORDS,
MENU_TOOL_USE_SNAP,
MENU_TOOL_USE_TRACKBALL,
MENU_TOOL_PRESERVE_CHILDREN_TRANSFORM,
MENU_TRANSFORM_CONFIGURE_SNAP,
MENU_TRANSFORM_DIALOG,
MENU_VIEW_USE_1_VIEWPORT,
MENU_VIEW_USE_2_VIEWPORTS,
MENU_VIEW_USE_2_VIEWPORTS_ALT,
MENU_VIEW_USE_3_VIEWPORTS,
MENU_VIEW_USE_3_VIEWPORTS_ALT,
MENU_VIEW_USE_4_VIEWPORTS,
MENU_VIEW_ORIGIN,
MENU_VIEW_GRID,
MENU_VIEW_GIZMOS_3D_ICONS,
MENU_VIEW_CAMERA_SETTINGS,
MENU_LOCK_SELECTED,
MENU_UNLOCK_SELECTED,
MENU_GROUP_SELECTED,
MENU_UNGROUP_SELECTED,
MENU_SNAP_TO_FLOOR,
MENU_RULER,
MENU_VERTEX_SNAP_BASE_VERTEX,
MENU_VERTEX_SNAP_BASE_ORIGIN,
MENU_VERTEX_SNAP_SOURCE_MESH,
MENU_VERTEX_SNAP_SOURCE_COLLISION,
};
Button *tool_button[TOOL_MAX];
Button *tool_option_button[TOOL_OPT_MAX];
MenuButton *transform_menu = nullptr;
PopupMenu *gizmos_menu = nullptr;
MenuButton *view_layout_menu = nullptr;
AcceptDialog *accept = nullptr;
ConfirmationDialog *snap_dialog = nullptr;
ConfirmationDialog *xform_dialog = nullptr;
ConfirmationDialog *settings_dialog = nullptr;
bool snap_enabled = false;
bool snap_key_enabled = false;
bool vertex_snap_origin_mode = false;
bool vertex_snap_use_collision = false;
EditorSpinSlider *snap_translate = nullptr;
EditorSpinSlider *snap_rotate = nullptr;
EditorSpinSlider *snap_scale = nullptr;
bool trackball_enabled = false;
LineEdit *xform_translate[3];
LineEdit *xform_rotate[3];
LineEdit *xform_scale[3];
OptionButton *xform_type = nullptr;
VBoxContainer *settings_vbc = nullptr;
SpinBox *settings_fov = nullptr;
SpinBox *settings_znear = nullptr;
SpinBox *settings_zfar = nullptr;
void _snap_changed();
void _snap_update();
void _update_vertex_snap_tooltips();
void _xform_dialog_action();
void _menu_item_pressed(int p_option);
void _menu_item_toggled(bool pressed, int p_option);
void _menu_gizmo_toggled(int p_option);
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
PanelContainer *context_toolbar_panel = nullptr;
HBoxContainer *context_toolbar_hbox = nullptr;
HashMap<Control *, VSeparator *> context_toolbar_separators;
void _update_context_toolbar();
void _generate_selection_boxes();
void _init_indicators();
void _update_gizmos_menu();
void _update_gizmos_menu_theme();
void _init_grid();
void _finish_indicators();
void _finish_grid();
void _toggle_maximize_view(Object *p_viewport);
void _viewport_clicked(int p_viewport_idx);
Node *custom_camera = nullptr;
Object *_get_editor_data(Object *p_what);
Ref<Environment> viewport_environment;
Node3D *selected = nullptr;
Node3DEditorViewport *freelook_viewport = nullptr;
void _request_gizmo(Object *p_obj);
void _request_gizmo_for_id(ObjectID p_id);
void _set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D());
void _clear_subgizmo_selection(Object *p_obj = nullptr);
bool gizmos_dirty = false;
static Node3DEditor *singleton;
void _node_added(Node *p_node);
void _node_removed(Node *p_node);
Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_priority;
Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_name;
void _register_all_gizmos();
void _selection_changed();
void _refresh_menu_icons();
bool do_snap_selected_nodes_to_floor = false;
void _snap_selected_nodes_to_floor();
// Preview Sun and Environment
class PreviewSunEnvPopup : public PopupPanel {
GDCLASS(PreviewSunEnvPopup, PopupPanel);
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
};
uint32_t world_env_count = 0;
uint32_t directional_light_count = 0;
Button *sun_button = nullptr;
Label *sun_state = nullptr;
Label *sun_title = nullptr;
VBoxContainer *sun_vb = nullptr;
Popup *sun_environ_popup = nullptr;
Control *sun_direction = nullptr;
EditorSpinSlider *sun_angle_altitude = nullptr;
EditorSpinSlider *sun_angle_azimuth = nullptr;
ColorPickerButton *sun_color = nullptr;
EditorSpinSlider *sun_energy = nullptr;
EditorSpinSlider *sun_shadow_max_distance = nullptr;
Button *sun_add_to_scene = nullptr;
Vector2 sun_rotation;
Ref<Shader> sun_direction_shader;
Ref<ShaderMaterial> sun_direction_material;
Button *environ_button = nullptr;
Label *environ_state = nullptr;
Label *environ_title = nullptr;
VBoxContainer *environ_vb = nullptr;
ColorPickerButton *environ_sky_color = nullptr;
ColorPickerButton *environ_ground_color = nullptr;
EditorSpinSlider *environ_energy = nullptr;
Button *environ_ao_button = nullptr;
Button *environ_glow_button = nullptr;
Button *environ_tonemap_button = nullptr;
Button *environ_gi_button = nullptr;
Button *environ_add_to_scene = nullptr;
Button *sun_environ_settings = nullptr;
DirectionalLight3D *preview_sun = nullptr;
bool preview_sun_dangling = false;
WorldEnvironment *preview_environment = nullptr;
bool preview_env_dangling = false;
Ref<Environment> environment;
Ref<CameraAttributesPractical> camera_attributes;
Ref<ProceduralSkyMaterial> sky_material;
bool sun_environ_updating = false;
void _sun_direction_draw();
void _sun_direction_input(const Ref<InputEvent> &p_event);
void _sun_direction_set_altitude(float p_altitude);
void _sun_direction_set_azimuth(float p_azimuth);
void _sun_set_color(const Color &p_color);
void _sun_set_energy(float p_energy);
void _sun_set_shadow_max_distance(float p_shadow_max_distance);
void _environ_set_sky_color(const Color &p_color);
void _environ_set_ground_color(const Color &p_color);
void _environ_set_sky_energy(float p_energy);
void _environ_set_ao();
void _environ_set_glow();
void _environ_set_tonemap();
void _environ_set_gi();
void _load_default_preview_settings();
void _update_preview_environment();
void _preview_settings_changed();
void _sun_environ_settings_pressed();
void _add_sun_to_scene(bool p_already_added_environment = false);
void _add_environment_to_scene(bool p_already_added_sun = false);
void _update_theme();
void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, const String &p_property, const Variant &p_new_value);
protected:
void _notification(int p_what);
//void _gui_input(InputEvent p_event);
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
static void _bind_methods();
public:
static Node3DEditor *get_singleton() { return singleton; }
static Size2i get_camera_viewport_size(Camera3D *p_camera);
Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const;
float get_znear() const;
float get_zfar() const;
float get_fov() const;
Transform3D get_gizmo_transform() const { return gizmo.transform; }
bool is_gizmo_visible() const;
ToolMode get_tool_mode() const { return tool_mode; }
bool are_local_coords_enabled() const;
void set_local_coords_enabled(bool on) const;
bool is_preserve_children_transform_enabled() const;
bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; }
bool is_vertex_snap_origin_mode() const { return vertex_snap_origin_mode; }
bool is_vertex_snap_use_collision() const;
real_t get_translate_snap() const;
real_t get_rotate_snap() const;
real_t get_scale_snap() const;
bool is_trackball_enabled() const { return trackball_enabled; }
Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; }
Ref<ArrayMesh> get_axis_gizmo(int idx) const { return axis_gizmo[idx]; }
Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; }
Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; }
Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; }
Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; }
Ref<ArrayMesh> get_trackball_sphere_gizmo() const { return trackball_sphere_gizmo; }
void update_grid();
void update_transform_gizmo();
void update_all_gizmos(Node *p_node = nullptr);
void update_gizmo_opacity();
void snap_selected_nodes_to_floor();
void select_gizmo_highlight_axis(int p_axis);
void set_custom_camera(Node *p_camera) { custom_camera = p_camera; }
Dictionary get_state() const;
void set_state(const Dictionary &p_state);
Ref<Environment> get_viewport_environment() { return viewport_environment; }
void add_control_to_menu_panel(Control *p_control);
void remove_control_from_menu_panel(Control *p_control);
void add_control_to_left_panel(Control *p_control);
void remove_control_from_left_panel(Control *p_control);
void add_control_to_right_panel(Control *p_control);
void remove_control_from_right_panel(Control *p_control);
void move_control_to_left_panel(Control *p_control);
void move_control_to_right_panel(Control *p_control);
VSplitContainer *get_shader_split();
Node3D *get_single_selected_node() { return selected; }
bool is_current_selected_gizmo(const EditorNode3DGizmo *p_gizmo);
bool is_subgizmo_selected(int p_id);
Vector<int> get_subgizmo_selection();
void clear_subgizmo_selection(Object *p_obj = nullptr);
void refresh_dirty_gizmos();
Ref<EditorNode3DGizmo> get_current_hover_gizmo() const { return current_hover_gizmo; }
void set_current_hover_gizmo(Ref<EditorNode3DGizmo> p_gizmo) { current_hover_gizmo = p_gizmo; }
void set_current_hover_gizmo_handle(int p_id, bool p_secondary) {
current_hover_gizmo_handle = p_id;
current_hover_gizmo_handle_secondary = p_secondary;
}
int get_current_hover_gizmo_handle(bool &r_secondary) const {
r_secondary = current_hover_gizmo_handle_secondary;
return current_hover_gizmo_handle;
}
void set_can_preview(Camera3D *p_preview);
void set_preview_material(Ref<Material> p_material) { preview_material = p_material; }
Ref<Material> get_preview_material() { return preview_material; }
void set_preview_reset_material(Ref<Material> p_material) { preview_reset_material = p_material; }
Ref<Material> get_preview_reset_material() const { return preview_reset_material; }
void set_preview_material_target(ObjectID p_object_id) { preview_material_target = p_object_id; }
ObjectID get_preview_material_target() const { return preview_material_target; }
void set_preview_material_surface(int p_surface) { preview_material_surface = p_surface; }
int get_preview_material_surface() const { return preview_material_surface; }
Node3DEditorViewport *get_editor_viewport(int p_idx) {
ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr);
return viewports[p_idx];
}
Node3DEditorViewport *get_last_used_viewport();
void set_freelook_viewport(Node3DEditorViewport *p_viewport);
Node3DEditorViewport *get_freelook_viewport() const;
void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin);
DynamicBVH::ID insert_gizmo_bvh_node(Node3D *p_node, const AABB &p_aabb);
void update_gizmo_bvh_node(DynamicBVH::ID p_id, const AABB &p_aabb);
void remove_gizmo_bvh_node(DynamicBVH::ID p_id);
Vector<Node3D *> gizmo_bvh_ray_query(const Vector3 &p_ray_start, const Vector3 &p_ray_end);
Vector<Node3D *> gizmo_bvh_frustum_query(const Vector<Plane> &p_frustum);
void edit(Node3D *p_spatial);
void clear();
Node3DEditor();
~Node3DEditor();
};
class Node3DEditorPlugin : public EditorPlugin {
GDCLASS(Node3DEditorPlugin, EditorPlugin);
Node3DEditor *spatial_editor = nullptr;
public:
Node3DEditor *get_spatial_editor() { return spatial_editor; }
virtual String get_plugin_name() const override { return TTRC("3D"); }
bool has_main_screen() const override { return true; }
virtual void make_visible(bool p_visible) override;
virtual void edit(Object *p_object) override;
virtual bool handles(Object *p_object) const override;
virtual Dictionary get_state() const override;
virtual void set_state(const Dictionary &p_state) override;
virtual void clear() override { spatial_editor->clear(); }
virtual void edited_scene_changed() override;
Node3DEditorPlugin();
};