1 | /**************************************************************************/ |
2 | /* node_3d_editor_plugin.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef NODE_3D_EDITOR_PLUGIN_H |
32 | #define NODE_3D_EDITOR_PLUGIN_H |
33 | |
34 | #include "editor/editor_plugin.h" |
35 | #include "editor/editor_scale.h" |
36 | #include "editor/plugins/node_3d_editor_gizmos.h" |
37 | #include "scene/gui/box_container.h" |
38 | #include "scene/gui/button.h" |
39 | #include "scene/gui/spin_box.h" |
40 | |
41 | class AcceptDialog; |
42 | class CheckBox; |
43 | class ColorPickerButton; |
44 | class ConfirmationDialog; |
45 | class DirectionalLight3D; |
46 | class EditorData; |
47 | class EditorSelection; |
48 | class EditorSpinSlider; |
49 | class HSplitContainer; |
50 | class LineEdit; |
51 | class ; |
52 | class Node3DEditor; |
53 | class Node3DEditorViewport; |
54 | class OptionButton; |
55 | class PanelContainer; |
56 | class ProceduralSkyMaterial; |
57 | class SubViewport; |
58 | class SubViewportContainer; |
59 | class VSeparator; |
60 | class VSplitContainer; |
61 | class ViewportNavigationControl; |
62 | class WorldEnvironment; |
63 | |
64 | class ViewportRotationControl : public Control { |
65 | GDCLASS(ViewportRotationControl, Control); |
66 | |
67 | struct Axis2D { |
68 | Vector2i screen_point; |
69 | float z_axis = -99.0; |
70 | int axis = -1; |
71 | }; |
72 | |
73 | struct Axis2DCompare { |
74 | _FORCE_INLINE_ bool operator()(const Axis2D &l, const Axis2D &r) const { |
75 | return l.z_axis < r.z_axis; |
76 | } |
77 | }; |
78 | |
79 | Node3DEditorViewport *viewport = nullptr; |
80 | Vector<Color> axis_colors; |
81 | Vector<int> ; |
82 | Vector2i orbiting_mouse_start; |
83 | int orbiting_index = -1; |
84 | int focused_axis = -2; |
85 | |
86 | const float AXIS_CIRCLE_RADIUS = 8.0f * EDSCALE; |
87 | |
88 | protected: |
89 | void _notification(int p_what); |
90 | virtual void gui_input(const Ref<InputEvent> &p_event) override; |
91 | void _draw(); |
92 | void _draw_axis(const Axis2D &p_axis); |
93 | void _get_sorted_axis(Vector<Axis2D> &r_axis); |
94 | void _update_focus(); |
95 | void _on_mouse_exited(); |
96 | void _process_click(int p_index, Vector2 p_position, bool p_pressed); |
97 | void _process_drag(Ref<InputEventWithModifiers> p_event, int p_index, Vector2 p_position, Vector2 p_relative_position); |
98 | |
99 | public: |
100 | void set_viewport(Node3DEditorViewport *p_viewport); |
101 | }; |
102 | |
103 | class Node3DEditorViewport : public Control { |
104 | GDCLASS(Node3DEditorViewport, Control); |
105 | friend class Node3DEditor; |
106 | friend class ViewportNavigationControl; |
107 | friend class ViewportRotationControl; |
108 | enum { |
109 | VIEW_TOP, |
110 | VIEW_BOTTOM, |
111 | VIEW_LEFT, |
112 | VIEW_RIGHT, |
113 | VIEW_FRONT, |
114 | VIEW_REAR, |
115 | VIEW_CENTER_TO_ORIGIN, |
116 | VIEW_CENTER_TO_SELECTION, |
117 | VIEW_ALIGN_TRANSFORM_WITH_VIEW, |
118 | VIEW_ALIGN_ROTATION_WITH_VIEW, |
119 | VIEW_PERSPECTIVE, |
120 | VIEW_ENVIRONMENT, |
121 | VIEW_ORTHOGONAL, |
122 | VIEW_SWITCH_PERSPECTIVE_ORTHOGONAL, |
123 | VIEW_HALF_RESOLUTION, |
124 | VIEW_AUDIO_LISTENER, |
125 | VIEW_AUDIO_DOPPLER, |
126 | VIEW_GIZMOS, |
127 | VIEW_INFORMATION, |
128 | VIEW_FRAME_TIME, |
129 | |
130 | // < Keep in sync with menu. |
131 | VIEW_DISPLAY_NORMAL, |
132 | VIEW_DISPLAY_WIREFRAME, |
133 | VIEW_DISPLAY_OVERDRAW, |
134 | VIEW_DISPLAY_LIGHTING, |
135 | VIEW_DISPLAY_UNSHADED, |
136 | VIEW_DISPLAY_ADVANCED, |
137 | // Advanced menu: |
138 | VIEW_DISPLAY_DEBUG_PSSM_SPLITS, |
139 | VIEW_DISPLAY_NORMAL_BUFFER, |
140 | VIEW_DISPLAY_DEBUG_SHADOW_ATLAS, |
141 | VIEW_DISPLAY_DEBUG_DIRECTIONAL_SHADOW_ATLAS, |
142 | VIEW_DISPLAY_DEBUG_DECAL_ATLAS, |
143 | VIEW_DISPLAY_DEBUG_VOXEL_GI_ALBEDO, |
144 | VIEW_DISPLAY_DEBUG_VOXEL_GI_LIGHTING, |
145 | VIEW_DISPLAY_DEBUG_VOXEL_GI_EMISSION, |
146 | VIEW_DISPLAY_DEBUG_SDFGI, |
147 | VIEW_DISPLAY_DEBUG_SDFGI_PROBES, |
148 | VIEW_DISPLAY_DEBUG_SCENE_LUMINANCE, |
149 | VIEW_DISPLAY_DEBUG_SSAO, |
150 | VIEW_DISPLAY_DEBUG_SSIL, |
151 | VIEW_DISPLAY_DEBUG_GI_BUFFER, |
152 | VIEW_DISPLAY_DEBUG_DISABLE_LOD, |
153 | VIEW_DISPLAY_DEBUG_CLUSTER_OMNI_LIGHTS, |
154 | VIEW_DISPLAY_DEBUG_CLUSTER_SPOT_LIGHTS, |
155 | VIEW_DISPLAY_DEBUG_CLUSTER_DECALS, |
156 | VIEW_DISPLAY_DEBUG_CLUSTER_REFLECTION_PROBES, |
157 | VIEW_DISPLAY_DEBUG_OCCLUDERS, |
158 | VIEW_DISPLAY_MOTION_VECTORS, |
159 | VIEW_DISPLAY_MAX, |
160 | // > Keep in sync with menu. |
161 | |
162 | VIEW_LOCK_ROTATION, |
163 | VIEW_CINEMATIC_PREVIEW, |
164 | VIEW_AUTO_ORTHOGONAL, |
165 | VIEW_MAX |
166 | }; |
167 | |
168 | enum ViewType { |
169 | VIEW_TYPE_USER, |
170 | VIEW_TYPE_TOP, |
171 | VIEW_TYPE_BOTTOM, |
172 | VIEW_TYPE_LEFT, |
173 | VIEW_TYPE_RIGHT, |
174 | VIEW_TYPE_FRONT, |
175 | VIEW_TYPE_REAR, |
176 | }; |
177 | |
178 | public: |
179 | enum { |
180 | GIZMO_BASE_LAYER = 27, |
181 | GIZMO_EDIT_LAYER = 26, |
182 | GIZMO_GRID_LAYER = 25, |
183 | MISC_TOOL_LAYER = 24, |
184 | |
185 | FRAME_TIME_HISTORY = 20, |
186 | }; |
187 | |
188 | enum NavigationScheme { |
189 | NAVIGATION_GODOT, |
190 | NAVIGATION_MAYA, |
191 | NAVIGATION_MODO, |
192 | }; |
193 | |
194 | enum FreelookNavigationScheme { |
195 | FREELOOK_DEFAULT, |
196 | FREELOOK_PARTIALLY_AXIS_LOCKED, |
197 | FREELOOK_FULLY_AXIS_LOCKED, |
198 | }; |
199 | |
200 | private: |
201 | double cpu_time_history[FRAME_TIME_HISTORY]; |
202 | int cpu_time_history_index; |
203 | double gpu_time_history[FRAME_TIME_HISTORY]; |
204 | int gpu_time_history_index; |
205 | |
206 | int index; |
207 | ViewType view_type; |
208 | void (int p_option); |
209 | void _set_auto_orthogonal(); |
210 | Node3D *preview_node = nullptr; |
211 | bool update_preview_node = false; |
212 | Point2 preview_node_viewport_pos; |
213 | Vector3 preview_node_pos; |
214 | AABB *preview_bounds = nullptr; |
215 | Vector<String> selected_files; |
216 | AcceptDialog *accept = nullptr; |
217 | |
218 | Node *target_node = nullptr; |
219 | Point2 drop_pos; |
220 | |
221 | EditorSelection *editor_selection = nullptr; |
222 | |
223 | CheckBox *preview_camera = nullptr; |
224 | SubViewportContainer *subviewport_container = nullptr; |
225 | |
226 | MenuButton * = nullptr; |
227 | PopupMenu * = nullptr; |
228 | |
229 | Control *surface = nullptr; |
230 | SubViewport *viewport = nullptr; |
231 | Camera3D *camera = nullptr; |
232 | bool transforming = false; |
233 | bool orthogonal; |
234 | bool auto_orthogonal; |
235 | bool lock_rotation; |
236 | real_t gizmo_scale; |
237 | |
238 | bool freelook_active; |
239 | real_t freelook_speed; |
240 | Vector2 previous_mouse_position; |
241 | |
242 | Label *info_label = nullptr; |
243 | Label *cinema_label = nullptr; |
244 | Label *locked_label = nullptr; |
245 | Label *zoom_limit_label = nullptr; |
246 | |
247 | Label *preview_material_label = nullptr; |
248 | Label *preview_material_label_desc = nullptr; |
249 | |
250 | VBoxContainer *top_right_vbox = nullptr; |
251 | VBoxContainer *bottom_center_vbox = nullptr; |
252 | ViewportNavigationControl *position_control = nullptr; |
253 | ViewportNavigationControl *look_control = nullptr; |
254 | ViewportRotationControl *rotation_control = nullptr; |
255 | Gradient *frame_time_gradient = nullptr; |
256 | Label *cpu_time_label = nullptr; |
257 | Label *gpu_time_label = nullptr; |
258 | Label *fps_label = nullptr; |
259 | |
260 | struct _RayResult { |
261 | Node3D *item = nullptr; |
262 | real_t depth = 0; |
263 | _FORCE_INLINE_ bool operator<(const _RayResult &p_rr) const { return depth < p_rr.depth; } |
264 | }; |
265 | |
266 | void _update_name(); |
267 | void _compute_edit(const Point2 &p_point); |
268 | void _clear_selected(); |
269 | void _select_clicked(bool p_allow_locked); |
270 | ObjectID _select_ray(const Point2 &p_pos) const; |
271 | void _find_items_at_pos(const Point2 &p_pos, Vector<_RayResult> &r_results, bool p_include_locked); |
272 | Vector3 _get_ray_pos(const Vector2 &p_pos) const; |
273 | Vector3 _get_ray(const Vector2 &p_pos) const; |
274 | Point2 _point_to_screen(const Vector3 &p_point); |
275 | Transform3D _get_camera_transform() const; |
276 | int get_selected_count() const; |
277 | void cancel_transform(); |
278 | void _update_shrink(); |
279 | |
280 | Vector3 _get_camera_position() const; |
281 | Vector3 _get_camera_normal() const; |
282 | Vector3 _get_screen_to_space(const Vector3 &p_vector3); |
283 | |
284 | void _select_region(); |
285 | bool _transform_gizmo_select(const Vector2 &p_screenpos, bool p_highlight_only = false); |
286 | void _transform_gizmo_apply(Node3D *p_node, const Transform3D &p_transform, bool p_local); |
287 | |
288 | void _nav_pan(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); |
289 | void _nav_zoom(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); |
290 | void _nav_orbit(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); |
291 | void _nav_look(Ref<InputEventWithModifiers> p_event, const Vector2 &p_relative); |
292 | |
293 | float get_znear() const; |
294 | float get_zfar() const; |
295 | float get_fov() const; |
296 | |
297 | ObjectID clicked; |
298 | ObjectID material_target; |
299 | Vector<_RayResult> selection_results; |
300 | Vector<_RayResult> ; |
301 | bool clicked_wants_append = false; |
302 | bool selection_in_progress = false; |
303 | |
304 | PopupMenu * = nullptr; |
305 | |
306 | enum NavigationZoomStyle { |
307 | NAVIGATION_ZOOM_VERTICAL, |
308 | NAVIGATION_ZOOM_HORIZONTAL |
309 | }; |
310 | |
311 | enum NavigationMode { |
312 | NAVIGATION_NONE, |
313 | NAVIGATION_PAN, |
314 | NAVIGATION_ZOOM, |
315 | NAVIGATION_ORBIT, |
316 | NAVIGATION_LOOK, |
317 | NAVIGATION_MOVE |
318 | }; |
319 | enum TransformMode { |
320 | TRANSFORM_NONE, |
321 | TRANSFORM_ROTATE, |
322 | TRANSFORM_TRANSLATE, |
323 | TRANSFORM_SCALE |
324 | |
325 | }; |
326 | enum TransformPlane { |
327 | TRANSFORM_VIEW, |
328 | TRANSFORM_X_AXIS, |
329 | TRANSFORM_Y_AXIS, |
330 | TRANSFORM_Z_AXIS, |
331 | TRANSFORM_YZ, |
332 | TRANSFORM_XZ, |
333 | TRANSFORM_XY, |
334 | }; |
335 | |
336 | struct EditData { |
337 | TransformMode mode; |
338 | TransformPlane plane; |
339 | Transform3D original; |
340 | Vector3 click_ray; |
341 | Vector3 click_ray_pos; |
342 | Vector3 center; |
343 | Point2 mouse_pos; |
344 | Point2 original_mouse_pos; |
345 | bool snap = false; |
346 | bool show_rotation_line = false; |
347 | Ref<EditorNode3DGizmo> gizmo; |
348 | int gizmo_handle = 0; |
349 | bool gizmo_handle_secondary = false; |
350 | Variant gizmo_initial_value; |
351 | bool original_local; |
352 | bool instant; |
353 | |
354 | // Numeric blender-style transforms (e.g. 'g5x'). |
355 | // numeric_input tracks the current input value, e.g. 1.23. |
356 | // numeric_negate indicates whether '-' has been pressed to negate the value |
357 | // while numeric_next_decimal is 0, numbers are input before the decimal point |
358 | // after pressing '.', numeric next decimal changes to -1, and decrements after each press. |
359 | double numeric_input = 0.0; |
360 | bool numeric_negate = false; |
361 | int numeric_next_decimal = 0; |
362 | } _edit; |
363 | |
364 | struct Cursor { |
365 | Vector3 pos; |
366 | real_t x_rot, y_rot, distance, fov_scale; |
367 | Vector3 eye_pos; // Used in freelook mode |
368 | bool region_select; |
369 | Point2 region_begin, region_end; |
370 | |
371 | Cursor() { |
372 | // These rotations place the camera in +X +Y +Z, aka south east, facing north west. |
373 | x_rot = 0.5; |
374 | y_rot = -0.5; |
375 | distance = 4; |
376 | fov_scale = 1.0; |
377 | region_select = false; |
378 | } |
379 | }; |
380 | // Viewport camera supports movement smoothing, |
381 | // so one cursor is the real cursor, while the other can be an interpolated version. |
382 | Cursor cursor; // Immediate cursor |
383 | Cursor camera_cursor; // That one may be interpolated (don't modify this one except for smoothing purposes) |
384 | |
385 | void scale_fov(real_t p_fov_offset); |
386 | void reset_fov(); |
387 | void scale_cursor_distance(real_t scale); |
388 | |
389 | void set_freelook_active(bool active_now); |
390 | void scale_freelook_speed(real_t scale); |
391 | |
392 | real_t zoom_indicator_delay; |
393 | int zoom_failed_attempts_count = 0; |
394 | |
395 | RID move_gizmo_instance[3], move_plane_gizmo_instance[3], rotate_gizmo_instance[4], scale_gizmo_instance[3], scale_plane_gizmo_instance[3], axis_gizmo_instance[3]; |
396 | |
397 | String last_message; |
398 | String message; |
399 | double message_time; |
400 | |
401 | void set_message(String p_message, float p_time = 5); |
402 | |
403 | void _view_settings_confirmed(real_t p_interp_delta); |
404 | void _update_camera(real_t p_interp_delta); |
405 | void _update_navigation_controls_visibility(); |
406 | Transform3D to_camera_transform(const Cursor &p_cursor) const; |
407 | void _draw(); |
408 | |
409 | void _surface_mouse_enter(); |
410 | void _surface_mouse_exit(); |
411 | void _surface_focus_enter(); |
412 | void _surface_focus_exit(); |
413 | |
414 | void input(const Ref<InputEvent> &p_event) override; |
415 | void _sinput(const Ref<InputEvent> &p_event); |
416 | void _update_freelook(real_t delta); |
417 | Node3DEditor *spatial_editor = nullptr; |
418 | |
419 | Camera3D *previewing = nullptr; |
420 | Camera3D *preview = nullptr; |
421 | |
422 | bool previewing_camera = false; |
423 | bool previewing_cinema = false; |
424 | bool _is_node_locked(const Node *p_node); |
425 | void _preview_exited_scene(); |
426 | void _toggle_camera_preview(bool); |
427 | void _toggle_cinema_preview(bool); |
428 | void _init_gizmo_instance(int p_idx); |
429 | void _finish_gizmo_instances(); |
430 | void _selection_result_pressed(int); |
431 | void (); |
432 | void _list_select(Ref<InputEventMouseButton> b); |
433 | Point2i _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_ev_mouse_motion) const; |
434 | |
435 | Vector3 _get_instance_position(const Point2 &p_pos) const; |
436 | static AABB _calculate_spatial_bounds(const Node3D *p_parent, bool p_exclude_top_level_transform = true); |
437 | |
438 | Node *_sanitize_preview_node(Node *p_node) const; |
439 | |
440 | void _create_preview_node(const Vector<String> &files) const; |
441 | void _remove_preview_node(); |
442 | bool _apply_preview_material(ObjectID p_target, const Point2 &p_point) const; |
443 | void _reset_preview_material() const; |
444 | void _remove_preview_material(); |
445 | bool _cyclical_dependency_exists(const String &p_target_scene_path, Node *p_desired_node); |
446 | bool _create_instance(Node *parent, String &path, const Point2 &p_point); |
447 | void _perform_drop_data(); |
448 | |
449 | bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); |
450 | void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); |
451 | |
452 | void _project_settings_changed(); |
453 | |
454 | Transform3D _compute_transform(TransformMode p_mode, const Transform3D &p_original, const Transform3D &p_original_local, Vector3 p_motion, double , bool p_local, bool p_orthogonal); |
455 | |
456 | void begin_transform(TransformMode p_mode, bool instant); |
457 | void commit_transform(); |
458 | void apply_transform(Vector3 p_motion, double p_snap); |
459 | void update_transform(bool p_shift); |
460 | void update_transform_numeric(); |
461 | void finish_transform(); |
462 | |
463 | void register_shortcut_action(const String &p_path, const String &p_name, Key p_keycode, bool p_physical = false); |
464 | void shortcut_changed_callback(const Ref<Shortcut> p_shortcut, const String &p_shortcut_path); |
465 | |
466 | void _set_lock_view_rotation(bool p_lock_rotation); |
467 | |
468 | protected: |
469 | void _notification(int p_what); |
470 | static void _bind_methods(); |
471 | |
472 | public: |
473 | void update_surface() { surface->queue_redraw(); } |
474 | void update_transform_gizmo_view(); |
475 | |
476 | void set_can_preview(Camera3D *p_preview); |
477 | void set_state(const Dictionary &p_state); |
478 | Dictionary get_state() const; |
479 | void reset(); |
480 | bool is_freelook_active() const { return freelook_active; } |
481 | |
482 | void focus_selection(); |
483 | |
484 | void assign_pending_data_pointers( |
485 | Node3D *p_preview_node, |
486 | AABB *p_preview_bounds, |
487 | AcceptDialog *p_accept); |
488 | |
489 | SubViewport *get_viewport_node() { return viewport; } |
490 | Camera3D *get_camera_3d() { return camera; } // return the default camera object. |
491 | |
492 | Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p_index); |
493 | ~Node3DEditorViewport(); |
494 | }; |
495 | |
496 | class Node3DEditorSelectedItem : public Object { |
497 | GDCLASS(Node3DEditorSelectedItem, Object); |
498 | |
499 | public: |
500 | AABB aabb; |
501 | Transform3D original; // original location when moving |
502 | Transform3D original_local; |
503 | Transform3D last_xform; // last transform |
504 | bool last_xform_dirty; |
505 | Node3D *sp = nullptr; |
506 | RID sbox_instance; |
507 | RID sbox_instance_offset; |
508 | RID sbox_instance_xray; |
509 | RID sbox_instance_xray_offset; |
510 | Ref<EditorNode3DGizmo> gizmo; |
511 | HashMap<int, Transform3D> subgizmos; // map ID -> initial transform |
512 | |
513 | Node3DEditorSelectedItem() { |
514 | sp = nullptr; |
515 | last_xform_dirty = true; |
516 | } |
517 | ~Node3DEditorSelectedItem(); |
518 | }; |
519 | |
520 | class Node3DEditorViewportContainer : public Container { |
521 | GDCLASS(Node3DEditorViewportContainer, Container); |
522 | |
523 | public: |
524 | enum View { |
525 | VIEW_USE_1_VIEWPORT, |
526 | VIEW_USE_2_VIEWPORTS, |
527 | VIEW_USE_2_VIEWPORTS_ALT, |
528 | VIEW_USE_3_VIEWPORTS, |
529 | VIEW_USE_3_VIEWPORTS_ALT, |
530 | VIEW_USE_4_VIEWPORTS, |
531 | }; |
532 | |
533 | private: |
534 | View view; |
535 | bool mouseover; |
536 | real_t ratio_h; |
537 | real_t ratio_v; |
538 | |
539 | bool hovering_v; |
540 | bool hovering_h; |
541 | |
542 | bool dragging_v; |
543 | bool dragging_h; |
544 | Vector2 drag_begin_pos; |
545 | Vector2 drag_begin_ratio; |
546 | |
547 | virtual void gui_input(const Ref<InputEvent> &p_event) override; |
548 | |
549 | protected: |
550 | void _notification(int p_what); |
551 | |
552 | public: |
553 | void set_view(View p_view); |
554 | View get_view(); |
555 | |
556 | Node3DEditorViewportContainer(); |
557 | }; |
558 | |
559 | class Node3DEditor : public VBoxContainer { |
560 | GDCLASS(Node3DEditor, VBoxContainer); |
561 | |
562 | public: |
563 | static const unsigned int VIEWPORTS_COUNT = 4; |
564 | |
565 | enum ToolMode { |
566 | TOOL_MODE_SELECT, |
567 | TOOL_MODE_MOVE, |
568 | TOOL_MODE_ROTATE, |
569 | TOOL_MODE_SCALE, |
570 | TOOL_MODE_LIST_SELECT, |
571 | TOOL_LOCK_SELECTED, |
572 | TOOL_UNLOCK_SELECTED, |
573 | TOOL_GROUP_SELECTED, |
574 | TOOL_UNGROUP_SELECTED, |
575 | TOOL_MAX |
576 | }; |
577 | |
578 | enum ToolOptions { |
579 | TOOL_OPT_LOCAL_COORDS, |
580 | TOOL_OPT_USE_SNAP, |
581 | TOOL_OPT_OVERRIDE_CAMERA, |
582 | TOOL_OPT_MAX |
583 | |
584 | }; |
585 | |
586 | private: |
587 | EditorSelection *editor_selection = nullptr; |
588 | |
589 | Node3DEditorViewportContainer *viewport_base = nullptr; |
590 | Node3DEditorViewport *viewports[VIEWPORTS_COUNT]; |
591 | VSplitContainer *shader_split = nullptr; |
592 | HSplitContainer *left_panel_split = nullptr; |
593 | HSplitContainer *right_panel_split = nullptr; |
594 | |
595 | ///// |
596 | |
597 | ToolMode tool_mode; |
598 | |
599 | RID origin; |
600 | RID origin_instance; |
601 | bool origin_enabled = false; |
602 | RID grid[3]; |
603 | RID grid_instance[3]; |
604 | bool grid_visible[3] = { false, false, false }; //currently visible |
605 | bool grid_enable[3] = { false, false, false }; //should be always visible if true |
606 | bool grid_enabled = false; |
607 | bool grid_init_draw = false; |
608 | Camera3D::ProjectionType grid_camera_last_update_perspective = Camera3D::PROJECTION_PERSPECTIVE; |
609 | Vector3 grid_camera_last_update_position; |
610 | |
611 | Ref<ArrayMesh> move_gizmo[3], move_plane_gizmo[3], rotate_gizmo[4], scale_gizmo[3], scale_plane_gizmo[3], axis_gizmo[3]; |
612 | Ref<StandardMaterial3D> gizmo_color[3]; |
613 | Ref<StandardMaterial3D> plane_gizmo_color[3]; |
614 | Ref<ShaderMaterial> rotate_gizmo_color[3]; |
615 | Ref<StandardMaterial3D> gizmo_color_hl[3]; |
616 | Ref<StandardMaterial3D> plane_gizmo_color_hl[3]; |
617 | Ref<ShaderMaterial> rotate_gizmo_color_hl[3]; |
618 | |
619 | Ref<Node3DGizmo> current_hover_gizmo; |
620 | int current_hover_gizmo_handle; |
621 | bool current_hover_gizmo_handle_secondary; |
622 | |
623 | real_t snap_translate_value; |
624 | real_t snap_rotate_value; |
625 | real_t snap_scale_value; |
626 | |
627 | Ref<ArrayMesh> selection_box_xray; |
628 | Ref<ArrayMesh> selection_box; |
629 | RID indicators; |
630 | RID indicators_instance; |
631 | RID cursor_mesh; |
632 | RID cursor_instance; |
633 | Ref<StandardMaterial3D> indicator_mat; |
634 | Ref<ShaderMaterial> grid_mat[3]; |
635 | Ref<StandardMaterial3D> cursor_material; |
636 | |
637 | // Scene drag and drop support |
638 | Node3D *preview_node = nullptr; |
639 | AABB preview_bounds; |
640 | |
641 | Ref<Material> preview_material; |
642 | Ref<Material> preview_reset_material; |
643 | ObjectID preview_material_target; |
644 | int preview_material_surface = -1; |
645 | |
646 | struct Gizmo { |
647 | bool visible = false; |
648 | real_t scale = 0; |
649 | Transform3D transform; |
650 | } gizmo; |
651 | |
652 | enum { |
653 | , |
654 | , |
655 | , |
656 | , |
657 | , |
658 | , |
659 | , |
660 | , |
661 | , |
662 | , |
663 | , |
664 | , |
665 | , |
666 | , |
667 | , |
668 | , |
669 | , |
670 | , |
671 | , |
672 | , |
673 | , |
674 | , |
675 | , |
676 | , |
677 | |
678 | }; |
679 | |
680 | Button *tool_button[TOOL_MAX]; |
681 | Button *tool_option_button[TOOL_OPT_MAX]; |
682 | |
683 | MenuButton * = nullptr; |
684 | PopupMenu * = nullptr; |
685 | MenuButton * = nullptr; |
686 | |
687 | AcceptDialog *accept = nullptr; |
688 | |
689 | ConfirmationDialog *snap_dialog = nullptr; |
690 | ConfirmationDialog *xform_dialog = nullptr; |
691 | ConfirmationDialog *settings_dialog = nullptr; |
692 | |
693 | bool snap_enabled; |
694 | bool snap_key_enabled; |
695 | LineEdit *snap_translate = nullptr; |
696 | LineEdit *snap_rotate = nullptr; |
697 | LineEdit *snap_scale = nullptr; |
698 | |
699 | LineEdit *xform_translate[3]; |
700 | LineEdit *xform_rotate[3]; |
701 | LineEdit *xform_scale[3]; |
702 | OptionButton *xform_type = nullptr; |
703 | |
704 | VBoxContainer *settings_vbc = nullptr; |
705 | SpinBox *settings_fov = nullptr; |
706 | SpinBox *settings_znear = nullptr; |
707 | SpinBox *settings_zfar = nullptr; |
708 | |
709 | void _snap_changed(); |
710 | void _snap_update(); |
711 | void _xform_dialog_action(); |
712 | void (int p_option); |
713 | void (bool pressed, int p_option); |
714 | void (int p_option); |
715 | void _update_camera_override_button(bool p_game_running); |
716 | void _update_camera_override_viewport(Object *p_viewport); |
717 | // Used for secondary menu items which are displayed depending on the currently selected node |
718 | // (such as MeshInstance's "Mesh" menu). |
719 | PanelContainer *context_toolbar_panel = nullptr; |
720 | HBoxContainer *context_toolbar_hbox = nullptr; |
721 | HashMap<Control *, VSeparator *> context_toolbar_separators; |
722 | |
723 | void _update_context_toolbar(); |
724 | |
725 | void _generate_selection_boxes(); |
726 | |
727 | int camera_override_viewport_id; |
728 | |
729 | void _init_indicators(); |
730 | void (); |
731 | void (); |
732 | void _init_grid(); |
733 | void _finish_indicators(); |
734 | void _finish_grid(); |
735 | |
736 | void _toggle_maximize_view(Object *p_viewport); |
737 | |
738 | Node *custom_camera = nullptr; |
739 | |
740 | Object *_get_editor_data(Object *p_what); |
741 | |
742 | Ref<Environment> viewport_environment; |
743 | |
744 | Node3D *selected = nullptr; |
745 | |
746 | void _request_gizmo(Object *p_obj); |
747 | void _request_gizmo_for_id(ObjectID p_id); |
748 | void _set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D()); |
749 | void _clear_subgizmo_selection(Object *p_obj = nullptr); |
750 | |
751 | static Node3DEditor *singleton; |
752 | |
753 | void _node_added(Node *p_node); |
754 | void _node_removed(Node *p_node); |
755 | Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_priority; |
756 | Vector<Ref<EditorNode3DGizmoPlugin>> gizmo_plugins_by_name; |
757 | |
758 | void _register_all_gizmos(); |
759 | |
760 | void _selection_changed(); |
761 | void (); |
762 | |
763 | bool do_snap_selected_nodes_to_floor = false; |
764 | void _snap_selected_nodes_to_floor(); |
765 | |
766 | // Preview Sun and Environment |
767 | |
768 | uint32_t world_env_count = 0; |
769 | uint32_t directional_light_count = 0; |
770 | |
771 | Button *sun_button = nullptr; |
772 | Label *sun_state = nullptr; |
773 | Label *sun_title = nullptr; |
774 | VBoxContainer *sun_vb = nullptr; |
775 | Popup * = nullptr; |
776 | Control *sun_direction = nullptr; |
777 | EditorSpinSlider *sun_angle_altitude = nullptr; |
778 | EditorSpinSlider *sun_angle_azimuth = nullptr; |
779 | ColorPickerButton *sun_color = nullptr; |
780 | EditorSpinSlider *sun_energy = nullptr; |
781 | EditorSpinSlider *sun_max_distance = nullptr; |
782 | Button *sun_add_to_scene = nullptr; |
783 | |
784 | void _sun_direction_draw(); |
785 | void _sun_direction_input(const Ref<InputEvent> &p_event); |
786 | void _sun_direction_angle_set(); |
787 | |
788 | Vector2 sun_rotation; |
789 | |
790 | Ref<Shader> sun_direction_shader; |
791 | Ref<ShaderMaterial> sun_direction_material; |
792 | |
793 | Button *environ_button = nullptr; |
794 | Label *environ_state = nullptr; |
795 | Label *environ_title = nullptr; |
796 | VBoxContainer *environ_vb = nullptr; |
797 | ColorPickerButton *environ_sky_color = nullptr; |
798 | ColorPickerButton *environ_ground_color = nullptr; |
799 | EditorSpinSlider *environ_energy = nullptr; |
800 | Button *environ_ao_button = nullptr; |
801 | Button *environ_glow_button = nullptr; |
802 | Button *environ_tonemap_button = nullptr; |
803 | Button *environ_gi_button = nullptr; |
804 | Button *environ_add_to_scene = nullptr; |
805 | |
806 | Button *sun_environ_settings = nullptr; |
807 | |
808 | DirectionalLight3D *preview_sun = nullptr; |
809 | bool preview_sun_dangling = false; |
810 | WorldEnvironment *preview_environment = nullptr; |
811 | bool preview_env_dangling = false; |
812 | Ref<Environment> environment; |
813 | Ref<CameraAttributesPractical> camera_attributes; |
814 | Ref<ProceduralSkyMaterial> sky_material; |
815 | |
816 | bool sun_environ_updating = false; |
817 | |
818 | void _load_default_preview_settings(); |
819 | void _update_preview_environment(); |
820 | |
821 | void _preview_settings_changed(); |
822 | void _sun_environ_settings_pressed(); |
823 | |
824 | void _add_sun_to_scene(bool p_already_added_environment = false); |
825 | void _add_environment_to_scene(bool p_already_added_sun = false); |
826 | |
827 | void _update_theme(); |
828 | |
829 | protected: |
830 | void _notification(int p_what); |
831 | //void _gui_input(InputEvent p_event); |
832 | virtual void shortcut_input(const Ref<InputEvent> &p_event) override; |
833 | |
834 | static void _bind_methods(); |
835 | |
836 | public: |
837 | static Node3DEditor *get_singleton() { return singleton; } |
838 | |
839 | Vector3 snap_point(Vector3 p_target, Vector3 p_start = Vector3(0, 0, 0)) const; |
840 | |
841 | float get_znear() const { return settings_znear->get_value(); } |
842 | float get_zfar() const { return settings_zfar->get_value(); } |
843 | float get_fov() const { return settings_fov->get_value(); } |
844 | |
845 | Transform3D get_gizmo_transform() const { return gizmo.transform; } |
846 | bool is_gizmo_visible() const; |
847 | |
848 | ToolMode get_tool_mode() const { return tool_mode; } |
849 | bool are_local_coords_enabled() const { return tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->is_pressed(); } |
850 | void set_local_coords_enabled(bool on) const { tool_option_button[Node3DEditor::TOOL_OPT_LOCAL_COORDS]->set_pressed(on); } |
851 | bool is_snap_enabled() const { return snap_enabled ^ snap_key_enabled; } |
852 | double get_translate_snap() const; |
853 | double get_rotate_snap() const; |
854 | double get_scale_snap() const; |
855 | |
856 | Ref<ArrayMesh> get_move_gizmo(int idx) const { return move_gizmo[idx]; } |
857 | Ref<ArrayMesh> get_axis_gizmo(int idx) const { return axis_gizmo[idx]; } |
858 | Ref<ArrayMesh> get_move_plane_gizmo(int idx) const { return move_plane_gizmo[idx]; } |
859 | Ref<ArrayMesh> get_rotate_gizmo(int idx) const { return rotate_gizmo[idx]; } |
860 | Ref<ArrayMesh> get_scale_gizmo(int idx) const { return scale_gizmo[idx]; } |
861 | Ref<ArrayMesh> get_scale_plane_gizmo(int idx) const { return scale_plane_gizmo[idx]; } |
862 | |
863 | void update_grid(); |
864 | void update_transform_gizmo(); |
865 | void update_all_gizmos(Node *p_node = nullptr); |
866 | void snap_selected_nodes_to_floor(); |
867 | void select_gizmo_highlight_axis(int p_axis); |
868 | void set_custom_camera(Node *p_camera) { custom_camera = p_camera; } |
869 | |
870 | Dictionary get_state() const; |
871 | void set_state(const Dictionary &p_state); |
872 | |
873 | Ref<Environment> get_viewport_environment() { return viewport_environment; } |
874 | |
875 | void (Control *p_control); |
876 | void (Control *p_control); |
877 | |
878 | void add_control_to_left_panel(Control *p_control); |
879 | void remove_control_from_left_panel(Control *p_control); |
880 | |
881 | void add_control_to_right_panel(Control *p_control); |
882 | void remove_control_from_right_panel(Control *p_control); |
883 | |
884 | void move_control_to_left_panel(Control *p_control); |
885 | void move_control_to_right_panel(Control *p_control); |
886 | |
887 | VSplitContainer *get_shader_split(); |
888 | |
889 | Node3D *get_single_selected_node() { return selected; } |
890 | bool is_current_selected_gizmo(const EditorNode3DGizmo *p_gizmo); |
891 | bool is_subgizmo_selected(int p_id); |
892 | Vector<int> get_subgizmo_selection(); |
893 | |
894 | Ref<EditorNode3DGizmo> get_current_hover_gizmo() const { return current_hover_gizmo; } |
895 | void set_current_hover_gizmo(Ref<EditorNode3DGizmo> p_gizmo) { current_hover_gizmo = p_gizmo; } |
896 | |
897 | void set_current_hover_gizmo_handle(int p_id, bool p_secondary) { |
898 | current_hover_gizmo_handle = p_id; |
899 | current_hover_gizmo_handle_secondary = p_secondary; |
900 | } |
901 | |
902 | int get_current_hover_gizmo_handle(bool &r_secondary) const { |
903 | r_secondary = current_hover_gizmo_handle_secondary; |
904 | return current_hover_gizmo_handle; |
905 | } |
906 | |
907 | void set_can_preview(Camera3D *p_preview); |
908 | |
909 | void set_preview_material(Ref<Material> p_material) { preview_material = p_material; } |
910 | Ref<Material> get_preview_material() { return preview_material; } |
911 | void set_preview_reset_material(Ref<Material> p_material) { preview_reset_material = p_material; } |
912 | Ref<Material> get_preview_reset_material() const { return preview_reset_material; } |
913 | void set_preview_material_target(ObjectID p_object_id) { preview_material_target = p_object_id; } |
914 | ObjectID get_preview_material_target() const { return preview_material_target; } |
915 | void set_preview_material_surface(int p_surface) { preview_material_surface = p_surface; } |
916 | int get_preview_material_surface() const { return preview_material_surface; } |
917 | |
918 | Node3DEditorViewport *get_editor_viewport(int p_idx) { |
919 | ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), nullptr); |
920 | return viewports[p_idx]; |
921 | } |
922 | |
923 | void add_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); |
924 | void remove_gizmo_plugin(Ref<EditorNode3DGizmoPlugin> p_plugin); |
925 | |
926 | void edit(Node3D *p_spatial); |
927 | void clear(); |
928 | |
929 | Node3DEditor(); |
930 | ~Node3DEditor(); |
931 | }; |
932 | |
933 | class Node3DEditorPlugin : public EditorPlugin { |
934 | GDCLASS(Node3DEditorPlugin, EditorPlugin); |
935 | |
936 | Node3DEditor *spatial_editor = nullptr; |
937 | |
938 | public: |
939 | Node3DEditor *get_spatial_editor() { return spatial_editor; } |
940 | virtual String get_name() const override { return "3D" ; } |
941 | bool has_main_screen() const override { return true; } |
942 | virtual void make_visible(bool p_visible) override; |
943 | virtual void edit(Object *p_object) override; |
944 | virtual bool handles(Object *p_object) const override; |
945 | |
946 | virtual Dictionary get_state() const override; |
947 | virtual void set_state(const Dictionary &p_state) override; |
948 | virtual void clear() override { spatial_editor->clear(); } |
949 | |
950 | virtual void edited_scene_changed() override; |
951 | |
952 | Node3DEditorPlugin(); |
953 | ~Node3DEditorPlugin(); |
954 | }; |
955 | |
956 | class ViewportNavigationControl : public Control { |
957 | GDCLASS(ViewportNavigationControl, Control); |
958 | |
959 | Node3DEditorViewport *viewport = nullptr; |
960 | Vector2i focused_mouse_start; |
961 | Vector2 focused_pos; |
962 | bool hovered = false; |
963 | int focused_index = -1; |
964 | Node3DEditorViewport::NavigationMode nav_mode = Node3DEditorViewport::NavigationMode::NAVIGATION_NONE; |
965 | |
966 | const float AXIS_CIRCLE_RADIUS = 30.0f * EDSCALE; |
967 | |
968 | protected: |
969 | void _notification(int p_what); |
970 | virtual void gui_input(const Ref<InputEvent> &p_event) override; |
971 | void _draw(); |
972 | void _on_mouse_entered(); |
973 | void _on_mouse_exited(); |
974 | void _process_click(int p_index, Vector2 p_position, bool p_pressed); |
975 | void _process_drag(int p_index, Vector2 p_position, Vector2 p_relative_position); |
976 | void _update_navigation(); |
977 | |
978 | public: |
979 | void set_navigation_mode(Node3DEditorViewport::NavigationMode p_nav_mode); |
980 | void set_viewport(Node3DEditorViewport *p_viewport); |
981 | }; |
982 | |
983 | #endif // NODE_3D_EDITOR_PLUGIN_H |
984 | |