1/**************************************************************************/
2/* visible_on_screen_notifier_3d_gizmo_plugin.cpp */
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#include "visible_on_screen_notifier_3d_gizmo_plugin.h"
32
33#include "editor/editor_settings.h"
34#include "editor/editor_undo_redo_manager.h"
35#include "editor/plugins/node_3d_editor_plugin.h"
36#include "scene/3d/visible_on_screen_notifier_3d.h"
37
38VisibleOnScreenNotifier3DGizmoPlugin::VisibleOnScreenNotifier3DGizmoPlugin() {
39 Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/visibility_notifier", Color(0.8, 0.5, 0.7));
40 create_material("visibility_notifier_material", gizmo_color);
41 gizmo_color.a = 0.1;
42 create_material("visibility_notifier_solid_material", gizmo_color);
43 create_handle_material("handles");
44}
45
46bool VisibleOnScreenNotifier3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
47 return Object::cast_to<VisibleOnScreenNotifier3D>(p_spatial) != nullptr;
48}
49
50String VisibleOnScreenNotifier3DGizmoPlugin::get_gizmo_name() const {
51 return "VisibleOnScreenNotifier3D";
52}
53
54int VisibleOnScreenNotifier3DGizmoPlugin::get_priority() const {
55 return -1;
56}
57
58String VisibleOnScreenNotifier3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
59 switch (p_id) {
60 case 0:
61 return "Size X";
62 case 1:
63 return "Size Y";
64 case 2:
65 return "Size Z";
66 case 3:
67 return "Pos X";
68 case 4:
69 return "Pos Y";
70 case 5:
71 return "Pos Z";
72 }
73
74 return "";
75}
76
77Variant VisibleOnScreenNotifier3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
78 VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
79 return notifier->get_aabb();
80}
81
82void VisibleOnScreenNotifier3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
83 VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
84
85 Transform3D gt = notifier->get_global_transform();
86
87 Transform3D gi = gt.affine_inverse();
88
89 bool move = p_id >= 3;
90 p_id = p_id % 3;
91
92 AABB aabb = notifier->get_aabb();
93 Vector3 ray_from = p_camera->project_ray_origin(p_point);
94 Vector3 ray_dir = p_camera->project_ray_normal(p_point);
95
96 Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
97
98 Vector3 ofs = aabb.get_center();
99
100 Vector3 axis;
101 axis[p_id] = 1.0;
102
103 if (move) {
104 Vector3 ra, rb;
105 Geometry3D::get_closest_points_between_segments(ofs - axis * 4096, ofs + axis * 4096, sg[0], sg[1], ra, rb);
106
107 float d = ra[p_id];
108 if (Node3DEditor::get_singleton()->is_snap_enabled()) {
109 d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
110 }
111
112 aabb.position[p_id] = d - 1.0 - aabb.size[p_id] * 0.5;
113 notifier->set_aabb(aabb);
114
115 } else {
116 Vector3 ra, rb;
117 Geometry3D::get_closest_points_between_segments(ofs, ofs + axis * 4096, sg[0], sg[1], ra, rb);
118
119 float d = ra[p_id] - ofs[p_id];
120 if (Node3DEditor::get_singleton()->is_snap_enabled()) {
121 d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
122 }
123
124 if (d < 0.001) {
125 d = 0.001;
126 }
127 //resize
128 aabb.position[p_id] = (aabb.position[p_id] + aabb.size[p_id] * 0.5) - d;
129 aabb.size[p_id] = d * 2;
130 notifier->set_aabb(aabb);
131 }
132}
133
134void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
135 VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
136
137 if (p_cancel) {
138 notifier->set_aabb(p_restore);
139 return;
140 }
141
142 EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
143 ur->create_action(TTR("Change Notifier AABB"));
144 ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
145 ur->add_undo_method(notifier, "set_aabb", p_restore);
146 ur->commit_action();
147}
148
149void VisibleOnScreenNotifier3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
150 VisibleOnScreenNotifier3D *notifier = Object::cast_to<VisibleOnScreenNotifier3D>(p_gizmo->get_node_3d());
151
152 p_gizmo->clear();
153
154 Vector<Vector3> lines;
155 AABB aabb = notifier->get_aabb();
156
157 for (int i = 0; i < 12; i++) {
158 Vector3 a, b;
159 aabb.get_edge(i, a, b);
160 lines.push_back(a);
161 lines.push_back(b);
162 }
163
164 Vector<Vector3> handles;
165
166 for (int i = 0; i < 3; i++) {
167 Vector3 ax;
168 ax[i] = aabb.position[i] + aabb.size[i];
169 ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
170 ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
171 handles.push_back(ax);
172 }
173
174 Vector3 center = aabb.get_center();
175 for (int i = 0; i < 3; i++) {
176 Vector3 ax;
177 ax[i] = 1.0;
178 handles.push_back(center + ax);
179 lines.push_back(center);
180 lines.push_back(center + ax);
181 }
182
183 Ref<Material> material = get_material("visibility_notifier_material", p_gizmo);
184
185 p_gizmo->add_lines(lines, material);
186 p_gizmo->add_collision_segments(lines);
187
188 if (p_gizmo->is_selected()) {
189 Ref<Material> solid_material = get_material("visibility_notifier_solid_material", p_gizmo);
190 p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
191 }
192
193 p_gizmo->add_handles(handles, get_material("handles"));
194}
195