Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/editor/scene/3d/gizmos/gizmo_3d_helper.cpp
9906 views
1
/**************************************************************************/
2
/* gizmo_3d_helper.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 "gizmo_3d_helper.h"
32
33
#include "editor/editor_undo_redo_manager.h"
34
#include "editor/scene/3d/node_3d_editor_plugin.h"
35
#include "scene/3d/camera_3d.h"
36
37
void Gizmo3DHelper::initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform) {
38
initial_value = p_initial_value;
39
initial_transform = p_initial_transform;
40
}
41
42
void Gizmo3DHelper::get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment) {
43
Transform3D gt = initial_transform;
44
Transform3D gi = gt.affine_inverse();
45
46
Vector3 ray_from = p_camera->project_ray_origin(p_point);
47
Vector3 ray_dir = p_camera->project_ray_normal(p_point);
48
49
r_segment[0] = gi.xform(ray_from);
50
r_segment[1] = gi.xform(ray_from + ray_dir * 4096);
51
}
52
53
Vector<Vector3> Gizmo3DHelper::box_get_handles(const Vector3 &p_box_size) {
54
Vector<Vector3> handles;
55
for (int i = 0; i < 3; i++) {
56
Vector3 ax;
57
ax[i] = p_box_size[i] / 2;
58
handles.push_back(ax);
59
handles.push_back(-ax);
60
}
61
return handles;
62
}
63
64
String Gizmo3DHelper::box_get_handle_name(int p_id) const {
65
switch (p_id) {
66
case 0:
67
case 1:
68
return "Size X";
69
case 2:
70
case 3:
71
return "Size Y";
72
case 4:
73
case 5:
74
return "Size Z";
75
}
76
return "";
77
}
78
79
void Gizmo3DHelper::box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position) {
80
int axis = p_id / 2;
81
int sign = p_id % 2 * -2 + 1;
82
83
Vector3 initial_size = initial_value;
84
float neg_end = initial_size[axis] * -0.5;
85
float pos_end = initial_size[axis] * 0.5;
86
87
Vector3 axis_segment[2] = { Vector3(), Vector3() };
88
axis_segment[0][axis] = 4096.0;
89
axis_segment[1][axis] = -4096.0;
90
Vector3 ra, rb;
91
Geometry3D::get_closest_points_between_segments(axis_segment[0], axis_segment[1], p_segment[0], p_segment[1], ra, rb);
92
93
// Calculate new size.
94
r_box_size = initial_size;
95
if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
96
r_box_size[axis] = ra[axis] * sign * 2;
97
} else {
98
r_box_size[axis] = sign > 0 ? ra[axis] - neg_end : pos_end - ra[axis];
99
}
100
101
// Snap to grid.
102
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
103
r_box_size[axis] = Math::snapped(r_box_size[axis], Node3DEditor::get_singleton()->get_translate_snap());
104
}
105
r_box_size[axis] = MAX(r_box_size[axis], 0.001);
106
107
// Adjust position.
108
if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
109
r_box_position = initial_transform.get_origin();
110
} else {
111
if (sign > 0) {
112
pos_end = neg_end + r_box_size[axis];
113
} else {
114
neg_end = pos_end - r_box_size[axis];
115
}
116
117
Vector3 offset;
118
offset[axis] = (pos_end + neg_end) * 0.5;
119
r_box_position = initial_transform.xform(offset);
120
}
121
}
122
123
void Gizmo3DHelper::box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object, const StringName &p_position_property, const StringName &p_size_property) {
124
if (!p_size_object) {
125
p_size_object = p_position_object;
126
}
127
128
if (p_cancel) {
129
p_size_object->set(p_size_property, initial_value);
130
p_position_object->set(p_position_property, initial_transform.get_origin());
131
return;
132
}
133
134
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
135
ur->create_action(p_action_name);
136
ur->add_do_property(p_size_object, p_size_property, p_size_object->get(p_size_property));
137
ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));
138
ur->add_undo_property(p_size_object, p_size_property, initial_value);
139
ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
140
ur->commit_action();
141
}
142
143
Vector<Vector3> Gizmo3DHelper::cylinder_get_handles(real_t p_height, real_t p_radius) {
144
Vector<Vector3> handles;
145
handles.push_back(Vector3(p_radius, 0, 0));
146
handles.push_back(Vector3(0, p_height * 0.5, 0));
147
handles.push_back(Vector3(0, p_height * -0.5, 0));
148
return handles;
149
}
150
151
String Gizmo3DHelper::cylinder_get_handle_name(int p_id) const {
152
if (p_id == 0) {
153
return "Radius";
154
} else {
155
return "Height";
156
}
157
}
158
159
void Gizmo3DHelper::_cylinder_or_capsule_set_handle(const Vector3 p_segment[2], int p_id, real_t &r_height, real_t &r_radius, Vector3 &r_cylinder_position, bool p_is_capsule) {
160
real_t initial_radius = initial_value.operator Vector2().x;
161
real_t initial_height = initial_value.operator Vector2().y;
162
163
int sign = p_id == 2 ? -1 : 1;
164
int axis = p_id == 0 ? 0 : 1;
165
166
Vector3 axis_vector;
167
axis_vector[axis] = sign;
168
Vector3 ra, rb;
169
Geometry3D::get_closest_points_between_segments(axis_vector * -4096, axis_vector * 4096, p_segment[0], p_segment[1], ra, rb);
170
float d = axis_vector.dot(ra);
171
172
// Snap to grid.
173
if (Node3DEditor::get_singleton()->is_snap_enabled()) {
174
d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
175
}
176
177
if (p_id == 0) {
178
// Adjust radius.
179
if (d < 0.001) {
180
d = 0.001;
181
}
182
r_radius = d;
183
r_cylinder_position = initial_transform.get_origin();
184
185
if (p_is_capsule) {
186
r_height = MAX(initial_height, r_radius * 2.0);
187
} else {
188
r_height = initial_height;
189
}
190
} else if (p_id == 1 || p_id == 2) {
191
// Adjust height.
192
if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
193
r_height = d * 2.0;
194
} else {
195
r_height = (initial_height * 0.5) + d;
196
}
197
198
if (r_height < 0.001) {
199
r_height = 0.001;
200
}
201
202
// Adjust position.
203
if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
204
r_cylinder_position = initial_transform.get_origin();
205
} else {
206
Vector3 offset;
207
offset[axis] = (r_height - initial_height) * 0.5 * sign;
208
r_cylinder_position = initial_transform.xform(offset);
209
}
210
211
if (p_is_capsule) {
212
r_radius = MIN(initial_radius, r_height / 2.0);
213
} else {
214
r_radius = initial_radius;
215
}
216
}
217
}
218
219
void Gizmo3DHelper::cylinder_commit_handle(int p_id, const String &p_radius_action_name, const String &p_height_action_name, bool p_cancel, Object *p_position_object, Object *p_height_object, Object *p_radius_object, const StringName &p_position_property, const StringName &p_height_property, const StringName &p_radius_property) {
220
if (!p_height_object) {
221
p_height_object = p_position_object;
222
}
223
if (!p_radius_object) {
224
p_radius_object = p_position_object;
225
}
226
227
if (p_cancel) {
228
p_radius_object->set(p_radius_property, initial_value.operator Vector2().x);
229
p_height_object->set(p_height_property, initial_value.operator Vector2().y);
230
p_position_object->set(p_position_property, initial_transform.get_origin());
231
return;
232
}
233
234
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
235
ur->create_action(p_id == 0 ? p_radius_action_name : p_height_action_name);
236
ur->add_do_property(p_radius_object, p_radius_property, p_radius_object->get(p_radius_property));
237
ur->add_undo_property(p_radius_object, p_radius_property, initial_value.operator Vector2().x);
238
ur->add_do_property(p_height_object, p_height_property, p_height_object->get(p_height_property));
239
ur->add_undo_property(p_height_object, p_height_property, initial_value.operator Vector2().y);
240
ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));
241
ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
242
ur->commit_action();
243
}
244
245