Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/debugger/scene_debugger.cpp
9903 views
1
/**************************************************************************/
2
/* scene_debugger.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 "scene_debugger.h"
32
33
#include "core/debugger/debugger_marshalls.h"
34
#include "core/debugger/engine_debugger.h"
35
#include "core/io/dir_access.h"
36
#include "core/io/marshalls.h"
37
#include "core/math/math_fieldwise.h"
38
#include "core/object/script_language.h"
39
#include "core/os/time.h"
40
#include "core/templates/local_vector.h"
41
#include "scene/gui/popup_menu.h"
42
#include "scene/main/canvas_layer.h"
43
#include "scene/main/scene_tree.h"
44
#include "scene/main/window.h"
45
#include "scene/resources/packed_scene.h"
46
#include "scene/theme/theme_db.h"
47
#include "servers/audio_server.h"
48
49
#ifndef PHYSICS_2D_DISABLED
50
#include "scene/2d/physics/collision_object_2d.h"
51
#include "scene/2d/physics/collision_polygon_2d.h"
52
#include "scene/2d/physics/collision_shape_2d.h"
53
#endif // PHYSICS_2D_DISABLED
54
55
#ifndef _3D_DISABLED
56
#include "scene/3d/camera_3d.h"
57
#ifndef PHYSICS_3D_DISABLED
58
#include "scene/3d/physics/collision_object_3d.h"
59
#include "scene/3d/physics/collision_shape_3d.h"
60
#endif // PHYSICS_3D_DISABLED
61
#include "scene/3d/visual_instance_3d.h"
62
#include "scene/resources/3d/convex_polygon_shape_3d.h"
63
#include "scene/resources/surface_tool.h"
64
#endif // _3D_DISABLED
65
66
SceneDebugger::SceneDebugger() {
67
singleton = this;
68
69
#ifdef DEBUG_ENABLED
70
LiveEditor::singleton = memnew(LiveEditor);
71
RuntimeNodeSelect::singleton = memnew(RuntimeNodeSelect);
72
73
EngineDebugger::register_message_capture("scene", EngineDebugger::Capture(nullptr, SceneDebugger::parse_message));
74
#endif // DEBUG_ENABLED
75
}
76
77
SceneDebugger::~SceneDebugger() {
78
#ifdef DEBUG_ENABLED
79
if (LiveEditor::singleton) {
80
EngineDebugger::unregister_message_capture("scene");
81
memdelete(LiveEditor::singleton);
82
LiveEditor::singleton = nullptr;
83
}
84
85
if (RuntimeNodeSelect::singleton) {
86
memdelete(RuntimeNodeSelect::singleton);
87
RuntimeNodeSelect::singleton = nullptr;
88
}
89
#endif // DEBUG_ENABLED
90
91
singleton = nullptr;
92
}
93
94
void SceneDebugger::initialize() {
95
if (EngineDebugger::is_active()) {
96
#ifdef DEBUG_ENABLED
97
_init_message_handlers();
98
#endif
99
memnew(SceneDebugger);
100
}
101
}
102
103
void SceneDebugger::deinitialize() {
104
if (singleton) {
105
memdelete(singleton);
106
}
107
}
108
109
#ifdef DEBUG_ENABLED
110
111
void SceneDebugger::_handle_input(const Ref<InputEvent> &p_event, const Ref<Shortcut> &p_shortcut) {
112
Ref<InputEventKey> k = p_event;
113
if (p_shortcut.is_valid() && k.is_valid() && k->is_pressed() && !k->is_echo() && p_shortcut->matches_event(k)) {
114
EngineDebugger::get_singleton()->send_message("request_quit", Array());
115
}
116
}
117
118
void SceneDebugger::_handle_embed_input(const Ref<InputEvent> &p_event, const Dictionary &p_settings) {
119
Ref<InputEventKey> k = p_event;
120
if (k.is_null() || !k->is_pressed()) {
121
return;
122
}
123
124
Ref<Shortcut> p_shortcut = p_settings.get("editor/next_frame_embedded_project", Ref<Shortcut>());
125
if (p_shortcut.is_valid() && p_shortcut->matches_event(k)) {
126
EngineDebugger::get_singleton()->send_message("request_embed_next_frame", Array());
127
return;
128
}
129
130
if (k->is_echo()) {
131
return;
132
} // Shortcuts that doesn't need is_echo goes below here
133
134
p_shortcut = p_settings.get("editor/suspend_resume_embedded_project", Ref<Shortcut>());
135
if (p_shortcut.is_valid() && p_shortcut->matches_event(k)) {
136
EngineDebugger::get_singleton()->send_message("request_embed_suspend_toggle", Array());
137
return;
138
}
139
}
140
141
Error SceneDebugger::_msg_setup_scene(const Array &p_args) {
142
SceneTree::get_singleton()->get_root()->connect(SceneStringName(window_input), callable_mp_static(SceneDebugger::_handle_input).bind(DebuggerMarshalls::deserialize_key_shortcut(p_args)));
143
return OK;
144
}
145
146
Error SceneDebugger::_msg_request_scene_tree(const Array &p_args) {
147
LiveEditor::get_singleton()->_send_tree();
148
return OK;
149
}
150
151
Error SceneDebugger::_msg_save_node(const Array &p_args) {
152
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
153
_save_node(p_args[0], p_args[1]);
154
Array arr;
155
arr.append(p_args[1]);
156
EngineDebugger::get_singleton()->send_message("filesystem:update_file", { arr });
157
return OK;
158
}
159
160
Error SceneDebugger::_msg_inspect_objects(const Array &p_args) {
161
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
162
Vector<ObjectID> ids;
163
for (const Variant &id : (Array)p_args[0]) {
164
ids.append(ObjectID(id.operator uint64_t()));
165
}
166
_send_object_ids(ids, p_args[1]);
167
return OK;
168
}
169
170
#ifndef DISABLE_DEPRECATED
171
Error SceneDebugger::_msg_inspect_object(const Array &p_args) {
172
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
173
// Legacy compatibility: convert single object ID to new format, then send single object response.
174
Vector<ObjectID> ids;
175
ids.append(ObjectID(p_args[0].operator uint64_t()));
176
177
SceneDebuggerObject obj(ids[0]);
178
if (obj.id.is_null()) {
179
EngineDebugger::get_singleton()->send_message("scene:inspect_object", Array());
180
return OK;
181
}
182
183
Array arr;
184
obj.serialize(arr);
185
EngineDebugger::get_singleton()->send_message("scene:inspect_object", arr);
186
return OK;
187
}
188
#endif // DISABLE_DEPRECATED
189
190
Error SceneDebugger::_msg_clear_selection(const Array &p_args) {
191
RuntimeNodeSelect::get_singleton()->_clear_selection();
192
return OK;
193
}
194
195
Error SceneDebugger::_msg_suspend_changed(const Array &p_args) {
196
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
197
bool suspended = p_args[0];
198
SceneTree::get_singleton()->set_suspend(suspended);
199
RuntimeNodeSelect::get_singleton()->_update_input_state();
200
return OK;
201
}
202
203
Error SceneDebugger::_msg_next_frame(const Array &p_args) {
204
_next_frame();
205
return OK;
206
}
207
208
Error SceneDebugger::_msg_debug_mute_audio(const Array &p_args) {
209
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
210
bool do_mute = p_args[0];
211
AudioServer::get_singleton()->set_debug_mute(do_mute);
212
return OK;
213
}
214
215
Error SceneDebugger::_msg_override_cameras(const Array &p_args) {
216
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
217
bool enable = p_args[0];
218
bool from_editor = p_args[1];
219
SceneTree::get_singleton()->get_root()->enable_canvas_transform_override(enable);
220
#ifndef _3D_DISABLED
221
SceneTree::get_singleton()->get_root()->enable_camera_3d_override(enable);
222
#endif // _3D_DISABLED
223
RuntimeNodeSelect::get_singleton()->_set_camera_override_enabled(enable && !from_editor);
224
return OK;
225
}
226
227
Error SceneDebugger::_msg_transform_camera_2d(const Array &p_args) {
228
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
229
Transform2D transform = p_args[0];
230
SceneTree::get_singleton()->get_root()->set_canvas_transform_override(transform);
231
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
232
return OK;
233
}
234
235
#ifndef _3D_DISABLED
236
Error SceneDebugger::_msg_transform_camera_3d(const Array &p_args) {
237
ERR_FAIL_COND_V(p_args.size() < 5, ERR_INVALID_DATA);
238
Transform3D transform = p_args[0];
239
bool is_perspective = p_args[1];
240
float size_or_fov = p_args[2];
241
float depth_near = p_args[3];
242
float depth_far = p_args[4];
243
if (is_perspective) {
244
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(size_or_fov, depth_near, depth_far);
245
} else {
246
SceneTree::get_singleton()->get_root()->set_camera_3d_override_orthogonal(size_or_fov, depth_near, depth_far);
247
}
248
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(transform);
249
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
250
return OK;
251
}
252
#endif // _3D_DISABLED
253
254
Error SceneDebugger::_msg_set_object_property(const Array &p_args) {
255
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
256
_set_object_property(p_args[0], p_args[1], p_args[2]);
257
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
258
return OK;
259
}
260
261
Error SceneDebugger::_msg_set_object_property_field(const Array &p_args) {
262
ERR_FAIL_COND_V(p_args.size() < 4, ERR_INVALID_DATA);
263
_set_object_property(p_args[0], p_args[1], p_args[2], p_args[3]);
264
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
265
return OK;
266
}
267
268
Error SceneDebugger::_msg_reload_cached_files(const Array &p_args) {
269
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
270
PackedStringArray files = p_args[0];
271
reload_cached_files(files);
272
return OK;
273
}
274
275
Error SceneDebugger::_msg_setup_embedded_shortcuts(const Array &p_args) {
276
ERR_FAIL_COND_V(p_args.is_empty() || p_args[0].get_type() != Variant::DICTIONARY, ERR_INVALID_DATA);
277
Dictionary dict = p_args[0];
278
LocalVector<Variant> keys = dict.get_key_list();
279
280
for (const Variant &key : keys) {
281
dict[key] = DebuggerMarshalls::deserialize_key_shortcut(dict[key]);
282
}
283
284
SceneTree::get_singleton()->get_root()->connect(SceneStringName(window_input), callable_mp_static(SceneDebugger::_handle_embed_input).bind(dict));
285
return OK;
286
}
287
288
// region Live editing.
289
290
Error SceneDebugger::_msg_live_set_root(const Array &p_args) {
291
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
292
LiveEditor::get_singleton()->_root_func(p_args[0], p_args[1]);
293
return OK;
294
}
295
296
Error SceneDebugger::_msg_live_node_path(const Array &p_args) {
297
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
298
LiveEditor::get_singleton()->_node_path_func(p_args[0], p_args[1]);
299
return OK;
300
}
301
302
Error SceneDebugger::_msg_live_res_path(const Array &p_args) {
303
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
304
LiveEditor::get_singleton()->_res_path_func(p_args[0], p_args[1]);
305
return OK;
306
}
307
308
Error SceneDebugger::_msg_live_node_prop_res(const Array &p_args) {
309
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
310
LiveEditor::get_singleton()->_node_set_res_func(p_args[0], p_args[1], p_args[2]);
311
return OK;
312
}
313
314
Error SceneDebugger::_msg_live_node_prop(const Array &p_args) {
315
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
316
LiveEditor::get_singleton()->_node_set_func(p_args[0], p_args[1], p_args[2]);
317
return OK;
318
}
319
320
Error SceneDebugger::_msg_live_res_prop_res(const Array &p_args) {
321
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
322
LiveEditor::get_singleton()->_res_set_res_func(p_args[0], p_args[1], p_args[2]);
323
return OK;
324
}
325
326
Error SceneDebugger::_msg_live_res_prop(const Array &p_args) {
327
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
328
LiveEditor::get_singleton()->_res_set_func(p_args[0], p_args[1], p_args[2]);
329
return OK;
330
}
331
332
Error SceneDebugger::_msg_live_node_call(const Array &p_args) {
333
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
334
LocalVector<Variant> args;
335
LocalVector<Variant *> argptrs;
336
args.resize(p_args.size() - 2);
337
argptrs.resize(args.size());
338
for (uint32_t i = 0; i < args.size(); i++) {
339
args[i] = p_args[i + 2];
340
argptrs[i] = &args[i];
341
}
342
LiveEditor::get_singleton()->_node_call_func(p_args[0], p_args[1], argptrs.size() ? (const Variant **)argptrs.ptr() : nullptr, argptrs.size());
343
return OK;
344
}
345
346
Error SceneDebugger::_msg_live_res_call(const Array &p_args) {
347
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
348
LocalVector<Variant> args;
349
LocalVector<Variant *> argptrs;
350
args.resize(p_args.size() - 2);
351
argptrs.resize(args.size());
352
for (uint32_t i = 0; i < args.size(); i++) {
353
args[i] = p_args[i + 2];
354
argptrs[i] = &args[i];
355
}
356
LiveEditor::get_singleton()->_res_call_func(p_args[0], p_args[1], argptrs.size() ? (const Variant **)argptrs.ptr() : nullptr, argptrs.size());
357
return OK;
358
}
359
360
Error SceneDebugger::_msg_live_create_node(const Array &p_args) {
361
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
362
LiveEditor::get_singleton()->_create_node_func(p_args[0], p_args[1], p_args[2]);
363
return OK;
364
}
365
366
Error SceneDebugger::_msg_live_instantiate_node(const Array &p_args) {
367
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
368
LiveEditor::get_singleton()->_instance_node_func(p_args[0], p_args[1], p_args[2]);
369
return OK;
370
}
371
372
Error SceneDebugger::_msg_live_remove_node(const Array &p_args) {
373
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
374
LiveEditor::get_singleton()->_remove_node_func(p_args[0]);
375
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
376
return OK;
377
}
378
379
Error SceneDebugger::_msg_live_remove_and_keep_node(const Array &p_args) {
380
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
381
LiveEditor::get_singleton()->_remove_and_keep_node_func(p_args[0], p_args[1]);
382
RuntimeNodeSelect::get_singleton()->_queue_selection_update();
383
return OK;
384
}
385
386
Error SceneDebugger::_msg_live_restore_node(const Array &p_args) {
387
ERR_FAIL_COND_V(p_args.size() < 3, ERR_INVALID_DATA);
388
LiveEditor::get_singleton()->_restore_node_func(p_args[0], p_args[1], p_args[2]);
389
return OK;
390
}
391
392
Error SceneDebugger::_msg_live_duplicate_node(const Array &p_args) {
393
ERR_FAIL_COND_V(p_args.size() < 2, ERR_INVALID_DATA);
394
LiveEditor::get_singleton()->_duplicate_node_func(p_args[0], p_args[1]);
395
return OK;
396
}
397
398
Error SceneDebugger::_msg_live_reparent_node(const Array &p_args) {
399
ERR_FAIL_COND_V(p_args.size() < 4, ERR_INVALID_DATA);
400
LiveEditor::get_singleton()->_reparent_node_func(p_args[0], p_args[1], p_args[2], p_args[3]);
401
return OK;
402
}
403
404
// endregion
405
406
// region Runtime Node Selection.
407
408
Error SceneDebugger::_msg_runtime_node_select_setup(const Array &p_args) {
409
ERR_FAIL_COND_V(p_args.is_empty() || p_args[0].get_type() != Variant::DICTIONARY, ERR_INVALID_DATA);
410
RuntimeNodeSelect::get_singleton()->_setup(p_args[0]);
411
return OK;
412
}
413
414
Error SceneDebugger::_msg_runtime_node_select_set_type(const Array &p_args) {
415
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
416
RuntimeNodeSelect::NodeType type = (RuntimeNodeSelect::NodeType)(int)p_args[0];
417
RuntimeNodeSelect::get_singleton()->_node_set_type(type);
418
return OK;
419
}
420
421
Error SceneDebugger::_msg_runtime_node_select_set_mode(const Array &p_args) {
422
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
423
RuntimeNodeSelect::SelectMode mode = (RuntimeNodeSelect::SelectMode)(int)p_args[0];
424
RuntimeNodeSelect::get_singleton()->_select_set_mode(mode);
425
return OK;
426
}
427
428
Error SceneDebugger::_msg_runtime_node_select_set_visible(const Array &p_args) {
429
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
430
bool visible = p_args[0];
431
RuntimeNodeSelect::get_singleton()->_set_selection_visible(visible);
432
return OK;
433
}
434
435
Error SceneDebugger::_msg_runtime_node_select_reset_camera_2d(const Array &p_args) {
436
RuntimeNodeSelect::get_singleton()->_reset_camera_2d();
437
return OK;
438
}
439
#ifndef _3D_DISABLED
440
Error SceneDebugger::_msg_runtime_node_select_reset_camera_3d(const Array &p_args) {
441
RuntimeNodeSelect::get_singleton()->_reset_camera_3d();
442
return OK;
443
}
444
#endif // _3D_DISABLED
445
446
// endregion
447
448
// region Embedded process screenshot.
449
450
Error SceneDebugger::_msg_rq_screenshot(const Array &p_args) {
451
ERR_FAIL_COND_V(p_args.is_empty(), ERR_INVALID_DATA);
452
453
Viewport *viewport = SceneTree::get_singleton()->get_root();
454
ERR_FAIL_NULL_V_MSG(viewport, ERR_UNCONFIGURED, "Cannot get a viewport from the main screen.");
455
Ref<ViewportTexture> texture = viewport->get_texture();
456
ERR_FAIL_COND_V_MSG(texture.is_null(), ERR_UNCONFIGURED, "Cannot get a viewport texture from the main screen.");
457
Ref<Image> img = texture->get_image();
458
ERR_FAIL_COND_V_MSG(img.is_null(), ERR_UNCONFIGURED, "Cannot get an image from a viewport texture of the main screen.");
459
img->clear_mipmaps();
460
461
const String TEMP_DIR = OS::get_singleton()->get_temp_path();
462
uint32_t suffix_i = 0;
463
String path;
464
while (true) {
465
String datetime = Time::get_singleton()->get_datetime_string_from_system().remove_chars("-T:");
466
datetime += itos(Time::get_singleton()->get_ticks_usec());
467
String suffix = datetime + (suffix_i > 0 ? itos(suffix_i) : "");
468
path = TEMP_DIR.path_join("scr-" + suffix + ".png");
469
if (!DirAccess::exists(path)) {
470
break;
471
}
472
suffix_i += 1;
473
}
474
img->save_png(path);
475
476
Array arr;
477
arr.append(p_args[0]);
478
arr.append(img->get_width());
479
arr.append(img->get_height());
480
arr.append(path);
481
EngineDebugger::get_singleton()->send_message("game_view:get_screenshot", arr);
482
483
return OK;
484
}
485
486
// endregion
487
488
HashMap<String, SceneDebugger::ParseMessageFunc> SceneDebugger::message_handlers;
489
490
Error SceneDebugger::parse_message(void *p_user, const String &p_msg, const Array &p_args, bool &r_captured) {
491
ERR_FAIL_NULL_V(SceneTree::get_singleton(), ERR_UNCONFIGURED);
492
ERR_FAIL_NULL_V(LiveEditor::get_singleton(), ERR_UNCONFIGURED);
493
ERR_FAIL_NULL_V(RuntimeNodeSelect::get_singleton(), ERR_UNCONFIGURED);
494
495
ParseMessageFunc *fn_ptr = message_handlers.getptr(p_msg);
496
if (fn_ptr) {
497
r_captured = true;
498
return (*fn_ptr)(p_args);
499
}
500
501
if (p_msg.begins_with("live_") || p_msg.begins_with("runtime_node_select_")) {
502
// Messages with these prefixes are reserved and should be handled by the LiveEditor or RuntimeNodeSelect classes,
503
// so return ERR_SKIP.
504
r_captured = true;
505
return ERR_SKIP;
506
}
507
508
r_captured = false;
509
510
return OK;
511
}
512
513
void SceneDebugger::_init_message_handlers() {
514
message_handlers["setup_scene"] = _msg_setup_scene;
515
message_handlers["setup_embedded_shortcuts"] = _msg_setup_embedded_shortcuts;
516
message_handlers["request_scene_tree"] = _msg_request_scene_tree;
517
message_handlers["save_node"] = _msg_save_node;
518
message_handlers["inspect_objects"] = _msg_inspect_objects;
519
#ifndef DISABLE_DEPRECATED
520
message_handlers["inspect_object"] = _msg_inspect_object;
521
#endif // DISABLE_DEPRECATED
522
message_handlers["clear_selection"] = _msg_clear_selection;
523
message_handlers["suspend_changed"] = _msg_suspend_changed;
524
message_handlers["next_frame"] = _msg_next_frame;
525
message_handlers["debug_mute_audio"] = _msg_debug_mute_audio;
526
message_handlers["override_cameras"] = _msg_override_cameras;
527
message_handlers["transform_camera_2d"] = _msg_transform_camera_2d;
528
#ifndef _3D_DISABLED
529
message_handlers["transform_camera_3d"] = _msg_transform_camera_3d;
530
#endif
531
message_handlers["set_object_property"] = _msg_set_object_property;
532
message_handlers["set_object_property_field"] = _msg_set_object_property_field;
533
message_handlers["reload_cached_files"] = _msg_reload_cached_files;
534
message_handlers["live_set_root"] = _msg_live_set_root;
535
message_handlers["live_node_path"] = _msg_live_node_path;
536
message_handlers["live_res_path"] = _msg_live_res_path;
537
message_handlers["live_node_prop_res"] = _msg_live_node_prop_res;
538
message_handlers["live_node_prop"] = _msg_live_node_prop;
539
message_handlers["live_res_prop_res"] = _msg_live_res_prop_res;
540
message_handlers["live_res_prop"] = _msg_live_res_prop;
541
message_handlers["live_node_call"] = _msg_live_node_call;
542
message_handlers["live_res_call"] = _msg_live_res_call;
543
message_handlers["live_create_node"] = _msg_live_create_node;
544
message_handlers["live_instantiate_node"] = _msg_live_instantiate_node;
545
message_handlers["live_remove_node"] = _msg_live_remove_node;
546
message_handlers["live_remove_and_keep_node"] = _msg_live_remove_and_keep_node;
547
message_handlers["live_restore_node"] = _msg_live_restore_node;
548
message_handlers["live_duplicate_node"] = _msg_live_duplicate_node;
549
message_handlers["live_reparent_node"] = _msg_live_reparent_node;
550
message_handlers["runtime_node_select_setup"] = _msg_runtime_node_select_setup;
551
message_handlers["runtime_node_select_set_type"] = _msg_runtime_node_select_set_type;
552
message_handlers["runtime_node_select_set_mode"] = _msg_runtime_node_select_set_mode;
553
message_handlers["runtime_node_select_set_visible"] = _msg_runtime_node_select_set_visible;
554
message_handlers["runtime_node_select_reset_camera_2d"] = _msg_runtime_node_select_reset_camera_2d;
555
#ifndef _3D_DISABLED
556
message_handlers["runtime_node_select_reset_camera_3d"] = _msg_runtime_node_select_reset_camera_3d;
557
#endif
558
message_handlers["rq_screenshot"] = _msg_rq_screenshot;
559
}
560
561
void SceneDebugger::_save_node(ObjectID id, const String &p_path) {
562
Node *node = ObjectDB::get_instance<Node>(id);
563
ERR_FAIL_NULL(node);
564
565
#ifdef TOOLS_ENABLED
566
HashMap<const Node *, Node *> duplimap;
567
Node *copy = node->duplicate_from_editor(duplimap);
568
#else
569
Node *copy = node->duplicate();
570
#endif // TOOLS_ENABLED
571
572
// Handle Unique Nodes.
573
for (int i = 0; i < copy->get_child_count(false); i++) {
574
_set_node_owner_recursive(copy->get_child(i, false), copy);
575
}
576
// Root node cannot ever be unique name in its own Scene!
577
copy->set_unique_name_in_owner(false);
578
579
Ref<PackedScene> ps = memnew(PackedScene);
580
ps->pack(copy);
581
ResourceSaver::save(ps, p_path);
582
583
memdelete(copy);
584
}
585
586
void SceneDebugger::_set_node_owner_recursive(Node *p_node, Node *p_owner) {
587
if (!p_node->get_owner()) {
588
p_node->set_owner(p_owner);
589
}
590
591
for (int i = 0; i < p_node->get_child_count(false); i++) {
592
_set_node_owner_recursive(p_node->get_child(i, false), p_owner);
593
}
594
}
595
596
void SceneDebugger::_send_object_ids(const Vector<ObjectID> &p_ids, bool p_update_selection) {
597
Vector<ObjectID> ids = p_ids;
598
if (ids.size() > RuntimeNodeSelect::get_singleton()->max_selection) {
599
ids.resize(RuntimeNodeSelect::get_singleton()->max_selection);
600
EngineDebugger::get_singleton()->send_message("show_selection_limit_warning", Array());
601
}
602
603
LocalVector<Node *> nodes;
604
Array objs;
605
bool objs_missing = false;
606
for (const ObjectID &id : ids) {
607
SceneDebuggerObject obj(id);
608
if (obj.id.is_null()) {
609
objs_missing = true;
610
continue;
611
}
612
613
if (p_update_selection) {
614
if (Node *node = ObjectDB::get_instance<Node>(id)) {
615
nodes.push_back(node);
616
}
617
}
618
619
Array arr;
620
obj.serialize(arr);
621
objs.append(arr);
622
}
623
624
if (p_update_selection) {
625
RuntimeNodeSelect::get_singleton()->_set_selected_nodes(nodes);
626
}
627
628
if (objs_missing) {
629
Array invalid_selection;
630
for (const ObjectID &id : ids) {
631
invalid_selection.append(id);
632
}
633
634
Array arr;
635
arr.append(invalid_selection);
636
EngineDebugger::get_singleton()->send_message("remote_selection_invalidated", arr);
637
638
EngineDebugger::get_singleton()->send_message(objs.is_empty() ? "remote_nothing_selected" : "remote_objects_selected", objs);
639
} else {
640
EngineDebugger::get_singleton()->send_message(p_update_selection ? "remote_objects_selected" : "scene:inspect_objects", objs);
641
}
642
}
643
644
void SceneDebugger::_set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value, const String &p_field) {
645
Object *obj = ObjectDB::get_instance(p_id);
646
if (!obj) {
647
return;
648
}
649
650
String prop_name = p_property;
651
if (p_property.begins_with("Members/")) {
652
Vector<String> ss = p_property.split("/");
653
prop_name = ss[ss.size() - 1];
654
}
655
656
Variant value;
657
if (p_field.is_empty()) {
658
// Whole value.
659
value = p_value;
660
} else {
661
// Only one field.
662
value = fieldwise_assign(obj->get(prop_name), p_value, p_field);
663
}
664
665
obj->set(prop_name, value);
666
}
667
668
void SceneDebugger::_next_frame() {
669
SceneTree *scene_tree = SceneTree::get_singleton();
670
if (!scene_tree->is_suspended()) {
671
return;
672
}
673
674
scene_tree->set_suspend(false);
675
RenderingServer::get_singleton()->connect("frame_post_draw", callable_mp(scene_tree, &SceneTree::set_suspend).bind(true), Object::CONNECT_ONE_SHOT);
676
}
677
678
void SceneDebugger::add_to_cache(const String &p_filename, Node *p_node) {
679
LiveEditor *debugger = LiveEditor::get_singleton();
680
if (!debugger) {
681
return;
682
}
683
684
if (EngineDebugger::get_script_debugger() && !p_filename.is_empty()) {
685
debugger->live_scene_edit_cache[p_filename].insert(p_node);
686
}
687
}
688
689
void SceneDebugger::remove_from_cache(const String &p_filename, Node *p_node) {
690
LiveEditor *debugger = LiveEditor::get_singleton();
691
if (!debugger) {
692
return;
693
}
694
695
HashMap<String, HashSet<Node *>> &edit_cache = debugger->live_scene_edit_cache;
696
HashMap<String, HashSet<Node *>>::Iterator E = edit_cache.find(p_filename);
697
if (E) {
698
E->value.erase(p_node);
699
if (E->value.is_empty()) {
700
edit_cache.remove(E);
701
}
702
}
703
704
HashMap<Node *, HashMap<ObjectID, Node *>> &remove_list = debugger->live_edit_remove_list;
705
HashMap<Node *, HashMap<ObjectID, Node *>>::Iterator F = remove_list.find(p_node);
706
if (F) {
707
for (const KeyValue<ObjectID, Node *> &G : F->value) {
708
memdelete(G.value);
709
}
710
remove_list.remove(F);
711
}
712
}
713
714
void SceneDebugger::reload_cached_files(const PackedStringArray &p_files) {
715
for (const String &file : p_files) {
716
Ref<Resource> res = ResourceCache::get_ref(file);
717
if (res.is_valid()) {
718
res->reload_from_file();
719
}
720
}
721
}
722
723
/// SceneDebuggerObject
724
SceneDebuggerObject::SceneDebuggerObject(ObjectID p_id) {
725
id = ObjectID();
726
Object *obj = ObjectDB::get_instance(p_id);
727
if (!obj) {
728
return;
729
}
730
731
id = p_id;
732
class_name = obj->get_class();
733
734
if (ScriptInstance *si = obj->get_script_instance()) {
735
// Read script instance constants and variables
736
if (!si->get_script().is_null()) {
737
Script *s = si->get_script().ptr();
738
_parse_script_properties(s, si);
739
}
740
}
741
742
if (Node *node = Object::cast_to<Node>(obj)) {
743
// For debugging multiplayer.
744
{
745
PropertyInfo pi(Variant::INT, String("Node/multiplayer_authority"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY);
746
properties.push_back(SceneDebuggerProperty(pi, node->get_multiplayer_authority()));
747
}
748
749
// Add specialized NodePath info (if inside tree).
750
if (node->is_inside_tree()) {
751
PropertyInfo pi(Variant::NODE_PATH, String("Node/path"));
752
properties.push_back(SceneDebuggerProperty(pi, node->get_path()));
753
} else { // Can't ask for path if a node is not in tree.
754
PropertyInfo pi(Variant::STRING, String("Node/path"));
755
properties.push_back(SceneDebuggerProperty(pi, "[Orphan]"));
756
}
757
} else if (Script *s = Object::cast_to<Script>(obj)) {
758
// Add script constants (no instance).
759
_parse_script_properties(s, nullptr);
760
}
761
762
// Add base object properties.
763
List<PropertyInfo> pinfo;
764
obj->get_property_list(&pinfo, true);
765
for (const PropertyInfo &E : pinfo) {
766
if (E.usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) {
767
properties.push_back(SceneDebuggerProperty(E, obj->get(E.name)));
768
}
769
}
770
}
771
772
void SceneDebuggerObject::_parse_script_properties(Script *p_script, ScriptInstance *p_instance) {
773
typedef HashMap<const Script *, HashSet<StringName>> ScriptMemberMap;
774
typedef HashMap<const Script *, HashMap<StringName, Variant>> ScriptConstantsMap;
775
776
ScriptMemberMap members;
777
if (p_instance) {
778
members[p_script] = HashSet<StringName>();
779
p_script->get_members(&(members[p_script]));
780
}
781
782
ScriptConstantsMap constants;
783
constants[p_script] = HashMap<StringName, Variant>();
784
p_script->get_constants(&(constants[p_script]));
785
786
Ref<Script> base = p_script->get_base_script();
787
while (base.is_valid()) {
788
if (p_instance) {
789
members[base.ptr()] = HashSet<StringName>();
790
base->get_members(&(members[base.ptr()]));
791
}
792
793
constants[base.ptr()] = HashMap<StringName, Variant>();
794
base->get_constants(&(constants[base.ptr()]));
795
796
base = base->get_base_script();
797
}
798
799
// Members
800
for (KeyValue<const Script *, HashSet<StringName>> sm : members) {
801
for (const StringName &E : sm.value) {
802
Variant m;
803
if (p_instance->get(E, m)) {
804
String script_path = sm.key == p_script ? "" : sm.key->get_path().get_file() + "/";
805
PropertyInfo pi(m.get_type(), "Members/" + script_path + E);
806
properties.push_back(SceneDebuggerProperty(pi, m));
807
}
808
}
809
}
810
// Constants
811
for (KeyValue<const Script *, HashMap<StringName, Variant>> &sc : constants) {
812
for (const KeyValue<StringName, Variant> &E : sc.value) {
813
String script_path = sc.key == p_script ? "" : sc.key->get_path().get_file() + "/";
814
if (E.value.get_type() == Variant::OBJECT) {
815
Variant inst_id = ((Object *)E.value)->get_instance_id();
816
PropertyInfo pi(inst_id.get_type(), "Constants/" + E.key, PROPERTY_HINT_OBJECT_ID, "Object");
817
properties.push_back(SceneDebuggerProperty(pi, inst_id));
818
} else {
819
PropertyInfo pi(E.value.get_type(), "Constants/" + script_path + E.key);
820
properties.push_back(SceneDebuggerProperty(pi, E.value));
821
}
822
}
823
}
824
}
825
826
void SceneDebuggerObject::serialize(Array &r_arr, int p_max_size) {
827
Array send_props;
828
for (SceneDebuggerObject::SceneDebuggerProperty &property : properties) {
829
const PropertyInfo &pi = property.first;
830
Variant &var = property.second;
831
832
Ref<Resource> res = var;
833
834
Array prop = { pi.name, pi.type };
835
PropertyHint hint = pi.hint;
836
String hint_string = pi.hint_string;
837
if (res.is_valid() && !res->get_path().is_empty()) {
838
var = res->get_path();
839
} else { //only send information that can be sent..
840
int len = 0; //test how big is this to encode
841
encode_variant(var, nullptr, len);
842
if (len > p_max_size) { //limit to max size
843
hint = PROPERTY_HINT_OBJECT_TOO_BIG;
844
hint_string = "";
845
var = Variant();
846
}
847
}
848
prop.push_back(hint);
849
prop.push_back(hint_string);
850
prop.push_back(pi.usage);
851
prop.push_back(var);
852
send_props.push_back(prop);
853
}
854
r_arr.push_back(uint64_t(id));
855
r_arr.push_back(class_name);
856
r_arr.push_back(send_props);
857
}
858
859
void SceneDebuggerObject::deserialize(const Array &p_arr) {
860
#define CHECK_TYPE(p_what, p_type) ERR_FAIL_COND(p_what.get_type() != Variant::p_type);
861
ERR_FAIL_COND(p_arr.size() < 3);
862
CHECK_TYPE(p_arr[0], INT);
863
CHECK_TYPE(p_arr[1], STRING);
864
CHECK_TYPE(p_arr[2], ARRAY);
865
866
id = uint64_t(p_arr[0]);
867
class_name = p_arr[1];
868
Array props = p_arr[2];
869
870
for (int i = 0; i < props.size(); i++) {
871
CHECK_TYPE(props[i], ARRAY);
872
Array prop = props[i];
873
874
ERR_FAIL_COND(prop.size() != 6);
875
CHECK_TYPE(prop[0], STRING);
876
CHECK_TYPE(prop[1], INT);
877
CHECK_TYPE(prop[2], INT);
878
CHECK_TYPE(prop[3], STRING);
879
CHECK_TYPE(prop[4], INT);
880
881
PropertyInfo pinfo;
882
pinfo.name = prop[0];
883
pinfo.type = Variant::Type(int(prop[1]));
884
pinfo.hint = PropertyHint(int(prop[2]));
885
pinfo.hint_string = prop[3];
886
pinfo.usage = PropertyUsageFlags(int(prop[4]));
887
Variant var = prop[5];
888
889
if (pinfo.type == Variant::OBJECT) {
890
if (var.is_zero()) {
891
var = Ref<Resource>();
892
} else if (var.get_type() == Variant::OBJECT) {
893
if (((Object *)var)->is_class("EncodedObjectAsID")) {
894
var = Object::cast_to<EncodedObjectAsID>(var)->get_object_id();
895
pinfo.type = var.get_type();
896
pinfo.hint = PROPERTY_HINT_OBJECT_ID;
897
pinfo.hint_string = "Object";
898
}
899
}
900
}
901
properties.push_back(SceneDebuggerProperty(pinfo, var));
902
}
903
}
904
905
/// SceneDebuggerTree
906
SceneDebuggerTree::SceneDebuggerTree(Node *p_root) {
907
// Flatten tree into list, depth first, use stack to avoid recursion.
908
List<Node *> stack;
909
stack.push_back(p_root);
910
bool is_root = true;
911
const StringName &is_visible_sn = SNAME("is_visible");
912
const StringName &is_visible_in_tree_sn = SNAME("is_visible_in_tree");
913
while (stack.size()) {
914
Node *n = stack.front()->get();
915
stack.pop_front();
916
917
int count = n->get_child_count();
918
for (int i = 0; i < count; i++) {
919
stack.push_front(n->get_child(count - i - 1));
920
}
921
922
int view_flags = 0;
923
if (is_root) {
924
// Prevent root window visibility from being changed.
925
is_root = false;
926
} else if (n->has_method(is_visible_sn)) {
927
const Variant visible = n->call(is_visible_sn);
928
if (visible.get_type() == Variant::BOOL) {
929
view_flags = RemoteNode::VIEW_HAS_VISIBLE_METHOD;
930
view_flags |= uint8_t(visible) * RemoteNode::VIEW_VISIBLE;
931
}
932
if (n->has_method(is_visible_in_tree_sn)) {
933
const Variant visible_in_tree = n->call(is_visible_in_tree_sn);
934
if (visible_in_tree.get_type() == Variant::BOOL) {
935
view_flags |= uint8_t(visible_in_tree) * RemoteNode::VIEW_VISIBLE_IN_TREE;
936
}
937
}
938
}
939
940
String class_name;
941
ScriptInstance *script_instance = n->get_script_instance();
942
if (script_instance) {
943
Ref<Script> script = script_instance->get_script();
944
if (script.is_valid()) {
945
class_name = script->get_global_name();
946
947
if (class_name.is_empty()) {
948
// If there is no class_name in this script we just take the script path.
949
class_name = script->get_path();
950
}
951
}
952
}
953
nodes.push_back(RemoteNode(count, n->get_name(), class_name.is_empty() ? n->get_class() : class_name, n->get_instance_id(), n->get_scene_file_path(), view_flags));
954
}
955
}
956
957
void SceneDebuggerTree::serialize(Array &p_arr) {
958
for (const RemoteNode &n : nodes) {
959
p_arr.push_back(n.child_count);
960
p_arr.push_back(n.name);
961
p_arr.push_back(n.type_name);
962
p_arr.push_back(n.id);
963
p_arr.push_back(n.scene_file_path);
964
p_arr.push_back(n.view_flags);
965
}
966
}
967
968
void SceneDebuggerTree::deserialize(const Array &p_arr) {
969
int idx = 0;
970
while (p_arr.size() > idx) {
971
ERR_FAIL_COND(p_arr.size() < 6);
972
CHECK_TYPE(p_arr[idx], INT); // child_count.
973
CHECK_TYPE(p_arr[idx + 1], STRING); // name.
974
CHECK_TYPE(p_arr[idx + 2], STRING); // type_name.
975
CHECK_TYPE(p_arr[idx + 3], INT); // id.
976
CHECK_TYPE(p_arr[idx + 4], STRING); // scene_file_path.
977
CHECK_TYPE(p_arr[idx + 5], INT); // view_flags.
978
nodes.push_back(RemoteNode(p_arr[idx], p_arr[idx + 1], p_arr[idx + 2], p_arr[idx + 3], p_arr[idx + 4], p_arr[idx + 5]));
979
idx += 6;
980
}
981
}
982
983
/// LiveEditor
984
LiveEditor *LiveEditor::get_singleton() {
985
return singleton;
986
}
987
988
void LiveEditor::_send_tree() {
989
SceneTree *scene_tree = SceneTree::get_singleton();
990
if (!scene_tree) {
991
return;
992
}
993
994
Array arr;
995
// Encoded as a flat list depth first.
996
SceneDebuggerTree tree(scene_tree->root);
997
tree.serialize(arr);
998
EngineDebugger::get_singleton()->send_message("scene:scene_tree", arr);
999
}
1000
1001
void LiveEditor::_node_path_func(const NodePath &p_path, int p_id) {
1002
live_edit_node_path_cache[p_id] = p_path;
1003
}
1004
1005
void LiveEditor::_res_path_func(const String &p_path, int p_id) {
1006
live_edit_resource_cache[p_id] = p_path;
1007
}
1008
1009
void LiveEditor::_node_set_func(int p_id, const StringName &p_prop, const Variant &p_value) {
1010
SceneTree *scene_tree = SceneTree::get_singleton();
1011
if (!scene_tree) {
1012
return;
1013
}
1014
1015
if (!live_edit_node_path_cache.has(p_id)) {
1016
return;
1017
}
1018
1019
NodePath np = live_edit_node_path_cache[p_id];
1020
Node *base = nullptr;
1021
if (scene_tree->root->has_node(live_edit_root)) {
1022
base = scene_tree->root->get_node(live_edit_root);
1023
}
1024
1025
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1026
if (!E) {
1027
return; //scene not editable
1028
}
1029
1030
for (Node *F : E->value) {
1031
Node *n = F;
1032
1033
if (base && !base->is_ancestor_of(n)) {
1034
continue;
1035
}
1036
1037
if (!n->has_node(np)) {
1038
continue;
1039
}
1040
Node *n2 = n->get_node(np);
1041
1042
// Do not change transform of edited scene root, unless it's the scene being played.
1043
// See GH-86659 for additional context.
1044
bool keep_transform = (n2 == n) && (n2->get_parent() != scene_tree->root);
1045
Variant orig_tf;
1046
1047
if (keep_transform) {
1048
if (n2->is_class("Node3D")) {
1049
orig_tf = n2->call("get_transform");
1050
} else if (n2->is_class("CanvasItem")) {
1051
orig_tf = n2->call("_edit_get_state");
1052
}
1053
}
1054
1055
n2->set(p_prop, p_value);
1056
1057
if (keep_transform) {
1058
if (n2->is_class("Node3D")) {
1059
Variant new_tf = n2->call("get_transform");
1060
if (new_tf != orig_tf) {
1061
n2->call("set_transform", orig_tf);
1062
}
1063
} else if (n2->is_class("CanvasItem")) {
1064
Variant new_tf = n2->call("_edit_get_state");
1065
if (new_tf != orig_tf) {
1066
n2->call("_edit_set_state", orig_tf);
1067
}
1068
}
1069
}
1070
}
1071
}
1072
1073
void LiveEditor::_node_set_res_func(int p_id, const StringName &p_prop, const String &p_value) {
1074
Ref<Resource> r = ResourceLoader::load(p_value);
1075
if (r.is_null()) {
1076
return;
1077
}
1078
_node_set_func(p_id, p_prop, r);
1079
}
1080
1081
void LiveEditor::_node_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) {
1082
SceneTree *scene_tree = SceneTree::get_singleton();
1083
if (!scene_tree) {
1084
return;
1085
}
1086
if (!live_edit_node_path_cache.has(p_id)) {
1087
return;
1088
}
1089
1090
NodePath np = live_edit_node_path_cache[p_id];
1091
Node *base = nullptr;
1092
if (scene_tree->root->has_node(live_edit_root)) {
1093
base = scene_tree->root->get_node(live_edit_root);
1094
}
1095
1096
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1097
if (!E) {
1098
return; //scene not editable
1099
}
1100
1101
for (Node *F : E->value) {
1102
Node *n = F;
1103
1104
if (base && !base->is_ancestor_of(n)) {
1105
continue;
1106
}
1107
1108
if (!n->has_node(np)) {
1109
continue;
1110
}
1111
Node *n2 = n->get_node(np);
1112
1113
// Do not change transform of edited scene root, unless it's the scene being played.
1114
// See GH-86659 for additional context.
1115
bool keep_transform = (n2 == n) && (n2->get_parent() != scene_tree->root);
1116
Variant orig_tf;
1117
1118
if (keep_transform) {
1119
if (n2->is_class("Node3D")) {
1120
orig_tf = n2->call("get_transform");
1121
} else if (n2->is_class("CanvasItem")) {
1122
orig_tf = n2->call("_edit_get_state");
1123
}
1124
}
1125
1126
Callable::CallError ce;
1127
n2->callp(p_method, p_args, p_argcount, ce);
1128
1129
if (keep_transform) {
1130
if (n2->is_class("Node3D")) {
1131
Variant new_tf = n2->call("get_transform");
1132
if (new_tf != orig_tf) {
1133
n2->call("set_transform", orig_tf);
1134
}
1135
} else if (n2->is_class("CanvasItem")) {
1136
Variant new_tf = n2->call("_edit_get_state");
1137
if (new_tf != orig_tf) {
1138
n2->call("_edit_set_state", orig_tf);
1139
}
1140
}
1141
}
1142
}
1143
}
1144
1145
void LiveEditor::_res_set_func(int p_id, const StringName &p_prop, const Variant &p_value) {
1146
if (!live_edit_resource_cache.has(p_id)) {
1147
return;
1148
}
1149
1150
String resp = live_edit_resource_cache[p_id];
1151
1152
if (!ResourceCache::has(resp)) {
1153
return;
1154
}
1155
1156
Ref<Resource> r = ResourceCache::get_ref(resp);
1157
if (r.is_null()) {
1158
return;
1159
}
1160
1161
r->set(p_prop, p_value);
1162
}
1163
1164
void LiveEditor::_res_set_res_func(int p_id, const StringName &p_prop, const String &p_value) {
1165
Ref<Resource> r = ResourceLoader::load(p_value);
1166
if (r.is_null()) {
1167
return;
1168
}
1169
_res_set_func(p_id, p_prop, r);
1170
}
1171
1172
void LiveEditor::_res_call_func(int p_id, const StringName &p_method, const Variant **p_args, int p_argcount) {
1173
if (!live_edit_resource_cache.has(p_id)) {
1174
return;
1175
}
1176
1177
String resp = live_edit_resource_cache[p_id];
1178
1179
if (!ResourceCache::has(resp)) {
1180
return;
1181
}
1182
1183
Ref<Resource> r = ResourceCache::get_ref(resp);
1184
if (r.is_null()) {
1185
return;
1186
}
1187
1188
Callable::CallError ce;
1189
r->callp(p_method, p_args, p_argcount, ce);
1190
}
1191
1192
void LiveEditor::_root_func(const NodePath &p_scene_path, const String &p_scene_from) {
1193
live_edit_root = p_scene_path;
1194
live_edit_scene = p_scene_from;
1195
}
1196
1197
void LiveEditor::_create_node_func(const NodePath &p_parent, const String &p_type, const String &p_name) {
1198
SceneTree *scene_tree = SceneTree::get_singleton();
1199
if (!scene_tree) {
1200
return;
1201
}
1202
1203
Node *base = nullptr;
1204
if (scene_tree->root->has_node(live_edit_root)) {
1205
base = scene_tree->root->get_node(live_edit_root);
1206
}
1207
1208
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1209
if (!E) {
1210
return; //scene not editable
1211
}
1212
1213
for (Node *F : E->value) {
1214
Node *n = F;
1215
1216
if (base && !base->is_ancestor_of(n)) {
1217
continue;
1218
}
1219
1220
if (!n->has_node(p_parent)) {
1221
continue;
1222
}
1223
Node *n2 = n->get_node(p_parent);
1224
1225
Node *no = Object::cast_to<Node>(ClassDB::instantiate(p_type));
1226
if (!no) {
1227
continue;
1228
}
1229
1230
no->set_name(p_name);
1231
n2->add_child(no);
1232
}
1233
}
1234
1235
void LiveEditor::_instance_node_func(const NodePath &p_parent, const String &p_path, const String &p_name) {
1236
SceneTree *scene_tree = SceneTree::get_singleton();
1237
if (!scene_tree) {
1238
return;
1239
}
1240
1241
Ref<PackedScene> ps = ResourceLoader::load(p_path);
1242
1243
if (ps.is_null()) {
1244
return;
1245
}
1246
1247
Node *base = nullptr;
1248
if (scene_tree->root->has_node(live_edit_root)) {
1249
base = scene_tree->root->get_node(live_edit_root);
1250
}
1251
1252
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1253
if (!E) {
1254
return; //scene not editable
1255
}
1256
1257
for (Node *F : E->value) {
1258
Node *n = F;
1259
1260
if (base && !base->is_ancestor_of(n)) {
1261
continue;
1262
}
1263
1264
if (!n->has_node(p_parent)) {
1265
continue;
1266
}
1267
Node *n2 = n->get_node(p_parent);
1268
1269
Node *no = ps->instantiate();
1270
if (!no) {
1271
continue;
1272
}
1273
1274
no->set_name(p_name);
1275
n2->add_child(no);
1276
}
1277
}
1278
1279
void LiveEditor::_remove_node_func(const NodePath &p_at) {
1280
SceneTree *scene_tree = SceneTree::get_singleton();
1281
if (!scene_tree) {
1282
return;
1283
}
1284
1285
Node *base = nullptr;
1286
if (scene_tree->root->has_node(live_edit_root)) {
1287
base = scene_tree->root->get_node(live_edit_root);
1288
}
1289
1290
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1291
if (!E) {
1292
return; //scene not editable
1293
}
1294
1295
Vector<Node *> to_delete;
1296
1297
for (HashSet<Node *>::Iterator F = E->value.begin(); F; ++F) {
1298
Node *n = *F;
1299
1300
if (base && !base->is_ancestor_of(n)) {
1301
continue;
1302
}
1303
1304
if (!n->has_node(p_at)) {
1305
continue;
1306
}
1307
Node *n2 = n->get_node(p_at);
1308
1309
to_delete.push_back(n2);
1310
}
1311
1312
for (int i = 0; i < to_delete.size(); i++) {
1313
memdelete(to_delete[i]);
1314
}
1315
}
1316
1317
void LiveEditor::_remove_and_keep_node_func(const NodePath &p_at, ObjectID p_keep_id) {
1318
SceneTree *scene_tree = SceneTree::get_singleton();
1319
if (!scene_tree) {
1320
return;
1321
}
1322
1323
Node *base = nullptr;
1324
if (scene_tree->root->has_node(live_edit_root)) {
1325
base = scene_tree->root->get_node(live_edit_root);
1326
}
1327
1328
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1329
if (!E) {
1330
return; //scene not editable
1331
}
1332
1333
Vector<Node *> to_remove;
1334
for (HashSet<Node *>::Iterator F = E->value.begin(); F; ++F) {
1335
Node *n = *F;
1336
1337
if (base && !base->is_ancestor_of(n)) {
1338
continue;
1339
}
1340
1341
if (!n->has_node(p_at)) {
1342
continue;
1343
}
1344
1345
to_remove.push_back(n);
1346
}
1347
1348
for (int i = 0; i < to_remove.size(); i++) {
1349
Node *n = to_remove[i];
1350
Node *n2 = n->get_node(p_at);
1351
n2->get_parent()->remove_child(n2);
1352
live_edit_remove_list[n][p_keep_id] = n2;
1353
}
1354
}
1355
1356
void LiveEditor::_restore_node_func(ObjectID p_id, const NodePath &p_at, int p_at_pos) {
1357
SceneTree *scene_tree = SceneTree::get_singleton();
1358
if (!scene_tree) {
1359
return;
1360
}
1361
1362
Node *base = nullptr;
1363
if (scene_tree->root->has_node(live_edit_root)) {
1364
base = scene_tree->root->get_node(live_edit_root);
1365
}
1366
1367
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1368
if (!E) {
1369
return; //scene not editable
1370
}
1371
1372
for (HashSet<Node *>::Iterator F = E->value.begin(); F;) {
1373
HashSet<Node *>::Iterator N = F;
1374
++N;
1375
1376
Node *n = *F;
1377
1378
if (base && !base->is_ancestor_of(n)) {
1379
continue;
1380
}
1381
1382
if (!n->has_node(p_at)) {
1383
continue;
1384
}
1385
Node *n2 = n->get_node(p_at);
1386
1387
HashMap<Node *, HashMap<ObjectID, Node *>>::Iterator EN = live_edit_remove_list.find(n);
1388
1389
if (!EN) {
1390
continue;
1391
}
1392
1393
HashMap<ObjectID, Node *>::Iterator FN = EN->value.find(p_id);
1394
1395
if (!FN) {
1396
continue;
1397
}
1398
n2->add_child(FN->value);
1399
1400
EN->value.remove(FN);
1401
1402
if (EN->value.is_empty()) {
1403
live_edit_remove_list.remove(EN);
1404
}
1405
1406
F = N;
1407
}
1408
}
1409
1410
void LiveEditor::_duplicate_node_func(const NodePath &p_at, const String &p_new_name) {
1411
SceneTree *scene_tree = SceneTree::get_singleton();
1412
if (!scene_tree) {
1413
return;
1414
}
1415
1416
Node *base = nullptr;
1417
if (scene_tree->root->has_node(live_edit_root)) {
1418
base = scene_tree->root->get_node(live_edit_root);
1419
}
1420
1421
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1422
if (!E) {
1423
return; //scene not editable
1424
}
1425
1426
for (Node *F : E->value) {
1427
Node *n = F;
1428
1429
if (base && !base->is_ancestor_of(n)) {
1430
continue;
1431
}
1432
1433
if (!n->has_node(p_at)) {
1434
continue;
1435
}
1436
Node *n2 = n->get_node(p_at);
1437
1438
Node *dup = n2->duplicate(Node::DUPLICATE_SIGNALS | Node::DUPLICATE_GROUPS | Node::DUPLICATE_SCRIPTS);
1439
1440
if (!dup) {
1441
continue;
1442
}
1443
1444
dup->set_name(p_new_name);
1445
n2->get_parent()->add_child(dup);
1446
}
1447
}
1448
1449
void LiveEditor::_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) {
1450
SceneTree *scene_tree = SceneTree::get_singleton();
1451
if (!scene_tree) {
1452
return;
1453
}
1454
1455
Node *base = nullptr;
1456
if (scene_tree->root->has_node(live_edit_root)) {
1457
base = scene_tree->root->get_node(live_edit_root);
1458
}
1459
1460
HashMap<String, HashSet<Node *>>::Iterator E = live_scene_edit_cache.find(live_edit_scene);
1461
if (!E) {
1462
return; //scene not editable
1463
}
1464
1465
for (Node *F : E->value) {
1466
Node *n = F;
1467
1468
if (base && !base->is_ancestor_of(n)) {
1469
continue;
1470
}
1471
1472
if (!n->has_node(p_at)) {
1473
continue;
1474
}
1475
Node *nfrom = n->get_node(p_at);
1476
1477
if (!n->has_node(p_new_place)) {
1478
continue;
1479
}
1480
Node *nto = n->get_node(p_new_place);
1481
1482
nfrom->get_parent()->remove_child(nfrom);
1483
nfrom->set_name(p_new_name);
1484
1485
nto->add_child(nfrom);
1486
if (p_at_pos >= 0) {
1487
nto->move_child(nfrom, p_at_pos);
1488
}
1489
}
1490
}
1491
1492
/// RuntimeNodeSelect
1493
RuntimeNodeSelect *RuntimeNodeSelect::get_singleton() {
1494
return singleton;
1495
}
1496
1497
RuntimeNodeSelect::~RuntimeNodeSelect() {
1498
if (selection_list && !selection_list->is_visible()) {
1499
memdelete(selection_list);
1500
}
1501
1502
if (draw_canvas.is_valid()) {
1503
RS::get_singleton()->free(sel_drag_ci);
1504
RS::get_singleton()->free(sbox_2d_ci);
1505
RS::get_singleton()->free(draw_canvas);
1506
}
1507
}
1508
1509
void RuntimeNodeSelect::_setup(const Dictionary &p_settings) {
1510
Window *root = SceneTree::get_singleton()->get_root();
1511
ERR_FAIL_COND(root->is_connected(SceneStringName(window_input), callable_mp(this, &RuntimeNodeSelect::_root_window_input)));
1512
1513
root->connect(SceneStringName(window_input), callable_mp(this, &RuntimeNodeSelect::_root_window_input));
1514
root->connect("size_changed", callable_mp(this, &RuntimeNodeSelect::_queue_selection_update), CONNECT_DEFERRED);
1515
1516
max_selection = p_settings.get("debugger/max_node_selection", 1);
1517
1518
panner.instantiate();
1519
panner->set_callbacks(callable_mp(this, &RuntimeNodeSelect::_pan_callback), callable_mp(this, &RuntimeNodeSelect::_zoom_callback));
1520
1521
ViewPanner::ControlScheme panning_scheme = (ViewPanner::ControlScheme)p_settings.get("editors/panning/2d_editor_panning_scheme", 0).operator int();
1522
bool simple_panning = p_settings.get("editors/panning/simple_panning", false);
1523
int pan_speed = p_settings.get("editors/panning/2d_editor_pan_speed", 20);
1524
Array keys = p_settings.get("canvas_item_editor/pan_view", Array()).operator Array();
1525
panner->setup(panning_scheme, DebuggerMarshalls::deserialize_key_shortcut(keys), simple_panning);
1526
panner->setup_warped_panning(root, p_settings.get("editors/panning/warped_mouse_panning", true));
1527
panner->set_scroll_speed(pan_speed);
1528
1529
sel_2d_grab_dist = p_settings.get("editors/polygon_editor/point_grab_radius", 0);
1530
1531
selection_area_fill = p_settings.get("box_selection_fill_color", Color());
1532
selection_area_outline = p_settings.get("box_selection_stroke_color", Color());
1533
1534
draw_canvas = RS::get_singleton()->canvas_create();
1535
sel_drag_ci = RS::get_singleton()->canvas_item_create();
1536
1537
/// 2D Selection Box Generation
1538
1539
sbox_2d_ci = RS::get_singleton()->canvas_item_create();
1540
RS::get_singleton()->viewport_attach_canvas(root->get_viewport_rid(), draw_canvas);
1541
RS::get_singleton()->canvas_item_set_parent(sel_drag_ci, draw_canvas);
1542
RS::get_singleton()->canvas_item_set_parent(sbox_2d_ci, draw_canvas);
1543
1544
#ifndef _3D_DISABLED
1545
cursor = Cursor();
1546
1547
camera_fov = p_settings.get("editors/3d/default_fov", 70);
1548
camera_znear = p_settings.get("editors/3d/default_z_near", 0.05);
1549
camera_zfar = p_settings.get("editors/3d/default_z_far", 4'000);
1550
1551
invert_x_axis = p_settings.get("editors/3d/navigation/invert_x_axis", false);
1552
invert_y_axis = p_settings.get("editors/3d/navigation/invert_y_axis", false);
1553
warped_mouse_panning_3d = p_settings.get("editors/3d/navigation/warped_mouse_panning", true);
1554
1555
freelook_base_speed = p_settings.get("editors/3d/freelook/freelook_base_speed", 5);
1556
freelook_sensitivity = Math::deg_to_rad((real_t)p_settings.get("editors/3d/freelook/freelook_sensitivity", 0.25));
1557
orbit_sensitivity = Math::deg_to_rad((real_t)p_settings.get("editors/3d/navigation_feel/orbit_sensitivity", 0.004));
1558
translation_sensitivity = p_settings.get("editors/3d/navigation_feel/translation_sensitivity", 1);
1559
1560
/// 3D Selection Box Generation
1561
// Copied from the Node3DEditor implementation.
1562
1563
sbox_3d_color = p_settings.get("editors/3d/selection_box_color", Color());
1564
1565
// Use two AABBs to create the illusion of a slightly thicker line.
1566
AABB aabb(Vector3(), Vector3(1, 1, 1));
1567
1568
// Create a x-ray (visible through solid surfaces) and standard version of the selection box.
1569
// Both will be drawn at the same position, but with different opacity.
1570
// This lets the user see where the selection is while still having a sense of depth.
1571
Ref<SurfaceTool> st = memnew(SurfaceTool);
1572
Ref<SurfaceTool> st_xray = memnew(SurfaceTool);
1573
1574
st->begin(Mesh::PRIMITIVE_LINES);
1575
st_xray->begin(Mesh::PRIMITIVE_LINES);
1576
for (int i = 0; i < 12; i++) {
1577
Vector3 a, b;
1578
aabb.get_edge(i, a, b);
1579
1580
st->add_vertex(a);
1581
st->add_vertex(b);
1582
st_xray->add_vertex(a);
1583
st_xray->add_vertex(b);
1584
}
1585
1586
Ref<StandardMaterial3D> mat = memnew(StandardMaterial3D);
1587
mat->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1588
mat->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
1589
mat->set_albedo(sbox_3d_color);
1590
mat->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
1591
st->set_material(mat);
1592
sbox_3d_mesh = st->commit();
1593
1594
Ref<StandardMaterial3D> mat_xray = memnew(StandardMaterial3D);
1595
mat_xray->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
1596
mat_xray->set_flag(StandardMaterial3D::FLAG_DISABLE_FOG, true);
1597
mat_xray->set_flag(StandardMaterial3D::FLAG_DISABLE_DEPTH_TEST, true);
1598
mat_xray->set_albedo(sbox_3d_color * Color(1, 1, 1, 0.15));
1599
mat_xray->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
1600
st_xray->set_material(mat_xray);
1601
sbox_3d_mesh_xray = st_xray->commit();
1602
#endif // _3D_DISABLED
1603
1604
SceneTree::get_singleton()->connect("process_frame", callable_mp(this, &RuntimeNodeSelect::_process_frame));
1605
SceneTree::get_singleton()->connect("physics_frame", callable_mp(this, &RuntimeNodeSelect::_physics_frame));
1606
1607
// This function will be called before the root enters the tree at first when the Game view is passing its settings to
1608
// the debugger, so queue the update for after it enters.
1609
root->connect(SceneStringName(tree_entered), callable_mp(this, &RuntimeNodeSelect::_update_input_state), Object::CONNECT_ONE_SHOT);
1610
}
1611
1612
void RuntimeNodeSelect::_node_set_type(NodeType p_type) {
1613
node_select_type = p_type;
1614
_update_input_state();
1615
}
1616
1617
void RuntimeNodeSelect::_select_set_mode(SelectMode p_mode) {
1618
node_select_mode = p_mode;
1619
}
1620
1621
void RuntimeNodeSelect::_set_camera_override_enabled(bool p_enabled) {
1622
camera_override = p_enabled;
1623
1624
if (p_enabled) {
1625
_update_view_2d();
1626
}
1627
1628
#ifndef _3D_DISABLED
1629
if (camera_first_override) {
1630
_reset_camera_2d();
1631
_reset_camera_3d();
1632
1633
camera_first_override = false;
1634
} else if (p_enabled) {
1635
_update_view_2d();
1636
1637
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
1638
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
1639
}
1640
#endif // _3D_DISABLED
1641
}
1642
1643
void RuntimeNodeSelect::_root_window_input(const Ref<InputEvent> &p_event) {
1644
Window *root = SceneTree::get_singleton()->get_root();
1645
if (node_select_type == NODE_TYPE_NONE || (selection_list && selection_list->is_visible())) {
1646
// Workaround for platforms that don't allow subwindows.
1647
if (selection_list && selection_list->is_visible() && selection_list->is_embedded()) {
1648
root->set_disable_input_override(false);
1649
selection_list->push_input(p_event);
1650
callable_mp(root->get_viewport(), &Viewport::set_disable_input_override).call_deferred(true);
1651
}
1652
1653
return;
1654
}
1655
1656
bool is_dragging_camera = false;
1657
if (camera_override) {
1658
if (node_select_type == NODE_TYPE_2D) {
1659
is_dragging_camera = panner->gui_input(p_event, Rect2(Vector2(), root->get_visible_rect().get_size()));
1660
#ifndef _3D_DISABLED
1661
} else if (node_select_type == NODE_TYPE_3D && selection_drag_state == SELECTION_DRAG_NONE) {
1662
if (_handle_3d_input(p_event)) {
1663
return;
1664
}
1665
#endif // _3D_DISABLED
1666
}
1667
}
1668
1669
Ref<InputEventMouseButton> b = p_event;
1670
1671
if (selection_drag_state == SELECTION_DRAG_MOVE) {
1672
Ref<InputEventMouseMotion> m = p_event;
1673
if (m.is_valid()) {
1674
_update_selection_drag(root->get_screen_transform().affine_inverse().xform(m->get_position()));
1675
return;
1676
} else if (b.is_valid()) {
1677
// Account for actions like zooming.
1678
_update_selection_drag(root->get_screen_transform().affine_inverse().xform(b->get_position()));
1679
}
1680
}
1681
1682
if (b.is_null()) {
1683
return;
1684
}
1685
1686
// Ignore mouse wheel inputs.
1687
if (b->get_button_index() != MouseButton::LEFT && b->get_button_index() != MouseButton::RIGHT) {
1688
return;
1689
}
1690
1691
if (selection_drag_state == SELECTION_DRAG_MOVE && !b->is_pressed() && b->get_button_index() == MouseButton::LEFT) {
1692
selection_drag_state = SELECTION_DRAG_END;
1693
selection_drag_area = selection_drag_area.abs();
1694
_update_selection_drag();
1695
1696
// Trigger a selection in the position on release.
1697
if (multi_shortcut_pressed) {
1698
selection_position = root->get_screen_transform().affine_inverse().xform(b->get_position());
1699
}
1700
}
1701
1702
if (!is_dragging_camera && b->is_pressed()) {
1703
multi_shortcut_pressed = b->is_shift_pressed();
1704
list_shortcut_pressed = node_select_mode == SELECT_MODE_SINGLE && b->get_button_index() == MouseButton::RIGHT && b->is_alt_pressed();
1705
if (list_shortcut_pressed || b->get_button_index() == MouseButton::LEFT) {
1706
selection_position = root->get_screen_transform().affine_inverse().xform(b->get_position());
1707
}
1708
}
1709
}
1710
1711
void RuntimeNodeSelect::_items_popup_index_pressed(int p_index, PopupMenu *p_popup) {
1712
Object *obj = p_popup->get_item_metadata(p_index).get_validated_object();
1713
if (obj) {
1714
Vector<Node *> node;
1715
node.append(Object::cast_to<Node>(obj));
1716
_send_ids(node);
1717
}
1718
}
1719
1720
void RuntimeNodeSelect::_update_input_state() {
1721
SceneTree *scene_tree = SceneTree::get_singleton();
1722
// This function can be called at the very beginning, when the root hasn't entered the tree yet.
1723
// So check first to avoid a crash.
1724
if (!scene_tree->get_root()->is_inside_tree()) {
1725
return;
1726
}
1727
1728
bool disable_input = scene_tree->is_suspended() || node_select_type != RuntimeNodeSelect::NODE_TYPE_NONE;
1729
Input::get_singleton()->set_disable_input(disable_input);
1730
Input::get_singleton()->set_mouse_mode_override_enabled(disable_input);
1731
scene_tree->get_root()->set_disable_input_override(disable_input);
1732
}
1733
1734
void RuntimeNodeSelect::_process_frame() {
1735
#ifndef _3D_DISABLED
1736
if (camera_freelook) {
1737
Transform3D transform = _get_cursor_transform();
1738
Vector3 forward = transform.basis.xform(Vector3(0, 0, -1));
1739
const Vector3 right = transform.basis.xform(Vector3(1, 0, 0));
1740
Vector3 up = transform.basis.xform(Vector3(0, 1, 0));
1741
1742
Vector3 direction;
1743
1744
Input *input = Input::get_singleton();
1745
bool was_input_disabled = input->is_input_disabled();
1746
if (was_input_disabled) {
1747
input->set_disable_input(false);
1748
}
1749
1750
if (input->is_physical_key_pressed(Key::A)) {
1751
direction -= right;
1752
}
1753
if (input->is_physical_key_pressed(Key::D)) {
1754
direction += right;
1755
}
1756
if (input->is_physical_key_pressed(Key::W)) {
1757
direction += forward;
1758
}
1759
if (input->is_physical_key_pressed(Key::S)) {
1760
direction -= forward;
1761
}
1762
if (input->is_physical_key_pressed(Key::E)) {
1763
direction += up;
1764
}
1765
if (input->is_physical_key_pressed(Key::Q)) {
1766
direction -= up;
1767
}
1768
1769
real_t speed = freelook_base_speed;
1770
if (input->is_physical_key_pressed(Key::SHIFT)) {
1771
speed *= 3.0;
1772
}
1773
if (input->is_physical_key_pressed(Key::ALT)) {
1774
speed *= 0.333333;
1775
}
1776
1777
if (was_input_disabled) {
1778
input->set_disable_input(true);
1779
}
1780
1781
if (direction != Vector3()) {
1782
// Calculate the process time manually, as the time scale is frozen.
1783
const double process_time = (1.0 / Engine::get_singleton()->get_frames_per_second()) * Engine::get_singleton()->get_unfrozen_time_scale();
1784
const Vector3 motion = direction * speed * process_time;
1785
cursor.pos += motion;
1786
cursor.eye_pos += motion;
1787
1788
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
1789
}
1790
}
1791
#endif // _3D_DISABLED
1792
1793
if (selection_update_queued || !SceneTree::get_singleton()->is_suspended()) {
1794
selection_update_queued = false;
1795
if (has_selection) {
1796
_update_selection();
1797
}
1798
}
1799
}
1800
1801
void RuntimeNodeSelect::_physics_frame() {
1802
if (selection_drag_state != SELECTION_DRAG_END && (selection_drag_state == SELECTION_DRAG_MOVE || Math::is_inf(selection_position.x))) {
1803
return;
1804
}
1805
1806
Window *root = SceneTree::get_singleton()->get_root();
1807
bool selection_drag_valid = selection_drag_state == SELECTION_DRAG_END && selection_drag_area.get_area() > SELECTION_MIN_AREA;
1808
Vector<SelectResult> items;
1809
1810
if (node_select_type == NODE_TYPE_2D) {
1811
if (selection_drag_valid) {
1812
for (int i = 0; i < root->get_child_count(); i++) {
1813
_find_canvas_items_at_rect(selection_drag_area, root->get_child(i), items);
1814
}
1815
} else if (!Math::is_inf(selection_position.x)) {
1816
for (int i = 0; i < root->get_child_count(); i++) {
1817
_find_canvas_items_at_pos(selection_position, root->get_child(i), items);
1818
}
1819
}
1820
1821
// Remove possible duplicates.
1822
for (int i = 0; i < items.size(); i++) {
1823
Node *item = items[i].item;
1824
for (int j = 0; j < i; j++) {
1825
if (items[j].item == item) {
1826
items.remove_at(i);
1827
i--;
1828
1829
break;
1830
}
1831
}
1832
}
1833
#ifndef _3D_DISABLED
1834
} else if (node_select_type == NODE_TYPE_3D) {
1835
if (selection_drag_valid) {
1836
_find_3d_items_at_rect(selection_drag_area, items);
1837
} else {
1838
_find_3d_items_at_pos(selection_position, items);
1839
}
1840
#endif // _3D_DISABLED
1841
}
1842
1843
items.sort();
1844
1845
switch (selection_drag_state) {
1846
case SELECTION_DRAG_END: {
1847
selection_position = Point2(Math::INF, Math::INF);
1848
selection_drag_state = SELECTION_DRAG_NONE;
1849
1850
if (selection_drag_area.get_area() > SELECTION_MIN_AREA) {
1851
if (!items.is_empty()) {
1852
Vector<Node *> nodes;
1853
for (const SelectResult item : items) {
1854
nodes.append(item.item);
1855
}
1856
_send_ids(nodes, false);
1857
}
1858
1859
_update_selection_drag();
1860
return;
1861
}
1862
1863
_update_selection_drag();
1864
} break;
1865
1866
case SELECTION_DRAG_NONE: {
1867
if (node_select_mode == SELECT_MODE_LIST) {
1868
break;
1869
}
1870
1871
if (multi_shortcut_pressed) {
1872
// Allow forcing box selection when an item was clicked.
1873
selection_drag_state = SELECTION_DRAG_MOVE;
1874
} else if (items.is_empty()) {
1875
#ifdef _3D_DISABLED
1876
if (!selected_ci_nodes.is_empty()) {
1877
#else
1878
if (!selected_ci_nodes.is_empty() || !selected_3d_nodes.is_empty()) {
1879
#endif // _3D_DISABLED
1880
EngineDebugger::get_singleton()->send_message("remote_nothing_selected", Array());
1881
_clear_selection();
1882
}
1883
1884
selection_drag_state = SELECTION_DRAG_MOVE;
1885
} else {
1886
break;
1887
}
1888
1889
[[fallthrough]];
1890
}
1891
1892
case SELECTION_DRAG_MOVE: {
1893
selection_drag_area.position = selection_position;
1894
1895
// Stop selection on click, so it can happen on release if the selection area doesn't pass the threshold.
1896
if (multi_shortcut_pressed) {
1897
return;
1898
}
1899
}
1900
}
1901
1902
if (items.is_empty()) {
1903
selection_position = Point2(Math::INF, Math::INF);
1904
return;
1905
}
1906
if ((!list_shortcut_pressed && node_select_mode == SELECT_MODE_SINGLE) || items.size() == 1) {
1907
selection_position = Point2(Math::INF, Math::INF);
1908
1909
Vector<Node *> node;
1910
node.append(items[0].item);
1911
_send_ids(node);
1912
1913
return;
1914
}
1915
1916
if (!selection_list && (list_shortcut_pressed || node_select_mode == SELECT_MODE_LIST)) {
1917
_open_selection_list(items, selection_position);
1918
}
1919
1920
selection_position = Point2(Math::INF, Math::INF);
1921
}
1922
1923
void RuntimeNodeSelect::_send_ids(const Vector<Node *> &p_picked_nodes, bool p_invert_new_selections) {
1924
ERR_FAIL_COND(p_picked_nodes.is_empty());
1925
1926
Vector<Node *> picked_nodes = p_picked_nodes;
1927
Array message;
1928
1929
if (!multi_shortcut_pressed) {
1930
if (picked_nodes.size() > max_selection) {
1931
picked_nodes.resize(max_selection);
1932
EngineDebugger::get_singleton()->send_message("show_selection_limit_warning", Array());
1933
}
1934
1935
for (const Node *node : picked_nodes) {
1936
SceneDebuggerObject obj(node->get_instance_id());
1937
Array arr;
1938
obj.serialize(arr);
1939
message.append(arr);
1940
}
1941
1942
EngineDebugger::get_singleton()->send_message("remote_objects_selected", message);
1943
_set_selected_nodes(picked_nodes);
1944
1945
return;
1946
}
1947
1948
LocalVector<Node *> nodes;
1949
LocalVector<ObjectID> ids;
1950
for (Node *node : picked_nodes) {
1951
ObjectID id = node->get_instance_id();
1952
if (CanvasItem *ci = Object::cast_to<CanvasItem>(node)) {
1953
if (selected_ci_nodes.has(id)) {
1954
if (p_invert_new_selections) {
1955
selected_ci_nodes.erase(id);
1956
}
1957
} else {
1958
ids.push_back(id);
1959
nodes.push_back(ci);
1960
}
1961
} else {
1962
#ifndef _3D_DISABLED
1963
if (Node3D *node3d = Object::cast_to<Node3D>(node)) {
1964
if (selected_3d_nodes.has(id)) {
1965
if (p_invert_new_selections) {
1966
selected_3d_nodes.erase(id);
1967
}
1968
} else {
1969
ids.push_back(id);
1970
nodes.push_back(node3d);
1971
}
1972
}
1973
#endif // _3D_DISABLED
1974
}
1975
}
1976
1977
uint32_t limit = max_selection - selected_ci_nodes.size();
1978
#ifndef _3D_DISABLED
1979
limit -= selected_3d_nodes.size();
1980
#endif // _3D_DISABLED
1981
if (ids.size() > limit) {
1982
ids.resize(limit);
1983
nodes.resize(limit);
1984
EngineDebugger::get_singleton()->send_message("show_selection_limit_warning", Array());
1985
}
1986
1987
for (ObjectID id : selected_ci_nodes) {
1988
ids.push_back(id);
1989
nodes.push_back(ObjectDB::get_instance<Node>(id));
1990
}
1991
#ifndef _3D_DISABLED
1992
for (const KeyValue<ObjectID, Ref<SelectionBox3D>> &KV : selected_3d_nodes) {
1993
ids.push_back(KV.key);
1994
nodes.push_back(ObjectDB::get_instance<Node>(KV.key));
1995
}
1996
#endif // _3D_DISABLED
1997
1998
if (ids.is_empty()) {
1999
EngineDebugger::get_singleton()->send_message("remote_nothing_selected", message);
2000
} else {
2001
for (const ObjectID &id : ids) {
2002
SceneDebuggerObject obj(id);
2003
Array arr;
2004
obj.serialize(arr);
2005
message.append(arr);
2006
}
2007
2008
EngineDebugger::get_singleton()->send_message("remote_objects_selected", message);
2009
}
2010
2011
_set_selected_nodes(nodes);
2012
}
2013
2014
void RuntimeNodeSelect::_set_selected_nodes(const Vector<Node *> &p_nodes) {
2015
if (p_nodes.is_empty()) {
2016
_clear_selection();
2017
return;
2018
}
2019
2020
bool changed = false;
2021
LocalVector<ObjectID> nodes_ci;
2022
#ifndef _3D_DISABLED
2023
HashMap<ObjectID, Ref<SelectionBox3D>> nodes_3d;
2024
#endif // _3D_DISABLED
2025
2026
for (Node *node : p_nodes) {
2027
ObjectID id = node->get_instance_id();
2028
if (Object::cast_to<CanvasItem>(node)) {
2029
if (!changed || !selected_ci_nodes.has(id)) {
2030
changed = true;
2031
}
2032
2033
nodes_ci.push_back(id);
2034
} else {
2035
#ifndef _3D_DISABLED
2036
Node3D *node_3d = Object::cast_to<Node3D>(node);
2037
if (!node_3d || !node_3d->is_inside_world()) {
2038
continue;
2039
}
2040
2041
if (!changed || !selected_3d_nodes.has(id)) {
2042
changed = true;
2043
}
2044
2045
if (selected_3d_nodes.has(id)) {
2046
// Assign an already available visual instance.
2047
nodes_3d[id] = selected_3d_nodes.get(id);
2048
continue;
2049
}
2050
2051
if (sbox_3d_mesh.is_null() || sbox_3d_mesh_xray.is_null()) {
2052
continue;
2053
}
2054
2055
Ref<SelectionBox3D> sb;
2056
sb.instantiate();
2057
nodes_3d[id] = sb;
2058
2059
RID scenario = node_3d->get_world_3d()->get_scenario();
2060
2061
sb->instance = RS::get_singleton()->instance_create2(sbox_3d_mesh->get_rid(), scenario);
2062
sb->instance_ofs = RS::get_singleton()->instance_create2(sbox_3d_mesh->get_rid(), scenario);
2063
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(sb->instance, RS::SHADOW_CASTING_SETTING_OFF);
2064
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(sb->instance_ofs, RS::SHADOW_CASTING_SETTING_OFF);
2065
RS::get_singleton()->instance_geometry_set_flag(sb->instance, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
2066
RS::get_singleton()->instance_geometry_set_flag(sb->instance, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
2067
RS::get_singleton()->instance_geometry_set_flag(sb->instance_ofs, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
2068
RS::get_singleton()->instance_geometry_set_flag(sb->instance_ofs, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
2069
2070
sb->instance_xray = RS::get_singleton()->instance_create2(sbox_3d_mesh_xray->get_rid(), scenario);
2071
sb->instance_xray_ofs = RS::get_singleton()->instance_create2(sbox_3d_mesh_xray->get_rid(), scenario);
2072
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(sb->instance_xray, RS::SHADOW_CASTING_SETTING_OFF);
2073
RS::get_singleton()->instance_geometry_set_cast_shadows_setting(sb->instance_xray_ofs, RS::SHADOW_CASTING_SETTING_OFF);
2074
RS::get_singleton()->instance_geometry_set_flag(sb->instance_xray, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
2075
RS::get_singleton()->instance_geometry_set_flag(sb->instance_xray, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
2076
RS::get_singleton()->instance_geometry_set_flag(sb->instance_xray_ofs, RS::INSTANCE_FLAG_IGNORE_OCCLUSION_CULLING, true);
2077
RS::get_singleton()->instance_geometry_set_flag(sb->instance_xray_ofs, RS::INSTANCE_FLAG_USE_BAKED_LIGHT, false);
2078
#endif // _3D_DISABLED
2079
}
2080
}
2081
2082
#ifdef _3D_DISABLED
2083
if (!changed && nodes_ci.size() == selected_ci_nodes.size()) {
2084
return;
2085
}
2086
#else
2087
if (!changed && nodes_ci.size() == selected_ci_nodes.size() && nodes_3d.size() == selected_3d_nodes.size()) {
2088
return;
2089
}
2090
#endif // _3D_DISABLED
2091
2092
_clear_selection();
2093
selected_ci_nodes = nodes_ci;
2094
has_selection = !nodes_ci.is_empty();
2095
2096
#ifndef _3D_DISABLED
2097
if (!nodes_3d.is_empty()) {
2098
selected_3d_nodes = nodes_3d;
2099
has_selection = true;
2100
}
2101
#endif // _3D_DISABLED
2102
2103
_queue_selection_update();
2104
}
2105
2106
void RuntimeNodeSelect::_queue_selection_update() {
2107
if (has_selection && selection_visible) {
2108
if (SceneTree::get_singleton()->is_suspended()) {
2109
_update_selection();
2110
} else {
2111
selection_update_queued = true;
2112
}
2113
}
2114
}
2115
2116
void RuntimeNodeSelect::_update_selection() {
2117
Window *root = SceneTree::get_singleton()->get_root();
2118
2119
RS::get_singleton()->canvas_item_clear(sbox_2d_ci);
2120
RS::get_singleton()->canvas_item_set_visible(sbox_2d_ci, selection_visible);
2121
2122
for (LocalVector<ObjectID>::Iterator E = selected_ci_nodes.begin(); E != selected_ci_nodes.end(); ++E) {
2123
ObjectID id = *E;
2124
CanvasItem *ci = ObjectDB::get_instance<CanvasItem>(id);
2125
if (!ci) {
2126
selected_ci_nodes.erase(id);
2127
--E;
2128
continue;
2129
}
2130
2131
if (!ci->is_inside_tree()) {
2132
continue;
2133
}
2134
2135
Transform2D xform;
2136
// Cameras (overridden or not) don't affect `CanvasLayer`s.
2137
if (root->is_canvas_transform_override_enabled() && !(ci->get_canvas_layer_node() && !ci->get_canvas_layer_node()->is_following_viewport())) {
2138
xform = root->get_canvas_transform_override() * ci->get_global_transform();
2139
} else {
2140
xform = ci->get_global_transform_with_canvas();
2141
}
2142
2143
// Fallback.
2144
Rect2 rect = Rect2(Vector2(), Vector2(10, 10));
2145
2146
if (ci->_edit_use_rect()) {
2147
rect = ci->_edit_get_rect();
2148
} else {
2149
#ifndef PHYSICS_2D_DISABLED
2150
CollisionShape2D *collision_shape = Object::cast_to<CollisionShape2D>(ci);
2151
if (collision_shape) {
2152
Ref<Shape2D> shape = collision_shape->get_shape();
2153
if (shape.is_valid()) {
2154
rect = shape->get_rect();
2155
}
2156
}
2157
#endif // PHYSICS_2D_DISABLED
2158
}
2159
2160
const Vector2 endpoints[4] = {
2161
xform.xform(rect.position),
2162
xform.xform(rect.position + Point2(rect.size.x, 0)),
2163
xform.xform(rect.position + rect.size),
2164
xform.xform(rect.position + Point2(0, rect.size.y))
2165
};
2166
2167
const Color selection_color_2d = Color(1, 0.6, 0.4, 0.7);
2168
for (int i = 0; i < 4; i++) {
2169
RS::get_singleton()->canvas_item_add_line(sbox_2d_ci, endpoints[i], endpoints[(i + 1) % 4], selection_color_2d, 2);
2170
}
2171
}
2172
2173
#ifndef _3D_DISABLED
2174
for (HashMap<ObjectID, Ref<SelectionBox3D>>::ConstIterator KV = selected_3d_nodes.begin(); KV != selected_3d_nodes.end(); ++KV) {
2175
ObjectID id = KV->key;
2176
Node3D *node_3d = ObjectDB::get_instance<Node3D>(id);
2177
if (!node_3d) {
2178
selected_3d_nodes.erase(id);
2179
--KV;
2180
continue;
2181
}
2182
2183
if (!node_3d->is_inside_tree()) {
2184
continue;
2185
}
2186
2187
// Fallback.
2188
AABB bounds(Vector3(-0.5, -0.5, -0.5), Vector3(1, 1, 1));
2189
2190
VisualInstance3D *visual_instance = Object::cast_to<VisualInstance3D>(node_3d);
2191
if (visual_instance) {
2192
bounds = visual_instance->get_aabb();
2193
} else {
2194
#ifndef PHYSICS_3D_DISABLED
2195
CollisionShape3D *collision_shape = Object::cast_to<CollisionShape3D>(node_3d);
2196
if (collision_shape) {
2197
Ref<Shape3D> shape = collision_shape->get_shape();
2198
if (shape.is_valid()) {
2199
bounds = shape->get_debug_mesh()->get_aabb();
2200
}
2201
}
2202
#endif // PHYSICS_3D_DISABLED
2203
}
2204
2205
Transform3D xform_to_top_level_parent_space = node_3d->get_global_transform().affine_inverse() * node_3d->get_global_transform();
2206
bounds = xform_to_top_level_parent_space.xform(bounds);
2207
Transform3D t = node_3d->get_global_transform();
2208
2209
Ref<SelectionBox3D> sb = KV->value;
2210
if (t == sb->transform && bounds == sb->bounds) {
2211
continue; // Nothing changed.
2212
}
2213
sb->transform = t;
2214
sb->bounds = bounds;
2215
2216
Transform3D t_offset = t;
2217
2218
// Apply AABB scaling before item's global transform.
2219
{
2220
const Vector3 offset(0.005, 0.005, 0.005);
2221
Basis aabb_s;
2222
aabb_s.scale(bounds.size + offset);
2223
t.translate_local(bounds.position - offset / 2);
2224
t.basis = t.basis * aabb_s;
2225
}
2226
{
2227
const Vector3 offset(0.01, 0.01, 0.01);
2228
Basis aabb_s;
2229
aabb_s.scale(bounds.size + offset);
2230
t_offset.translate_local(bounds.position - offset / 2);
2231
t_offset.basis = t_offset.basis * aabb_s;
2232
}
2233
2234
RS::get_singleton()->instance_set_visible(sb->instance, selection_visible);
2235
RS::get_singleton()->instance_set_visible(sb->instance_ofs, selection_visible);
2236
RS::get_singleton()->instance_set_visible(sb->instance_xray, selection_visible);
2237
RS::get_singleton()->instance_set_visible(sb->instance_xray_ofs, selection_visible);
2238
2239
RS::get_singleton()->instance_set_transform(sb->instance, t);
2240
RS::get_singleton()->instance_set_transform(sb->instance_ofs, t_offset);
2241
RS::get_singleton()->instance_set_transform(sb->instance_xray, t);
2242
RS::get_singleton()->instance_set_transform(sb->instance_xray_ofs, t_offset);
2243
}
2244
#endif // _3D_DISABLED
2245
}
2246
2247
void RuntimeNodeSelect::_clear_selection() {
2248
selected_ci_nodes.clear();
2249
if (draw_canvas.is_valid()) {
2250
RS::get_singleton()->canvas_item_clear(sbox_2d_ci);
2251
}
2252
2253
#ifndef _3D_DISABLED
2254
selected_3d_nodes.clear();
2255
#endif // _3D_DISABLED
2256
2257
has_selection = false;
2258
}
2259
2260
void RuntimeNodeSelect::_update_selection_drag(const Point2 &p_end_pos) {
2261
RS::get_singleton()->canvas_item_clear(sel_drag_ci);
2262
2263
if (selection_drag_state != SELECTION_DRAG_MOVE) {
2264
return;
2265
}
2266
2267
selection_drag_area.size = p_end_pos - selection_drag_area.position;
2268
2269
if (selection_drag_state == SELECTION_DRAG_END) {
2270
return;
2271
}
2272
2273
Window *root = SceneTree::get_singleton()->get_root();
2274
Rect2 selection_drawing;
2275
int thickness;
2276
if (root->is_canvas_transform_override_enabled()) {
2277
Transform2D xform = root->get_canvas_transform_override();
2278
RS::get_singleton()->canvas_item_set_transform(sel_drag_ci, xform);
2279
RS::get_singleton()->canvas_item_reset_physics_interpolation(sel_drag_ci);
2280
2281
selection_drawing.position = xform.affine_inverse().xform(selection_drag_area.position);
2282
selection_drawing.size = xform.affine_inverse().xform(p_end_pos);
2283
thickness = MAX(1, Math::ceil(1 / view_2d_zoom));
2284
} else {
2285
RS::get_singleton()->canvas_item_set_transform(sel_drag_ci, Transform2D());
2286
RS::get_singleton()->canvas_item_reset_physics_interpolation(sel_drag_ci);
2287
2288
selection_drawing.position = selection_drag_area.position;
2289
selection_drawing.size = p_end_pos;
2290
thickness = 1;
2291
}
2292
selection_drawing.size -= selection_drawing.position;
2293
selection_drawing = selection_drawing.abs();
2294
2295
const Vector2 endpoints[4] = {
2296
selection_drawing.position,
2297
selection_drawing.position + Point2(selection_drawing.size.x, 0),
2298
selection_drawing.position + selection_drawing.size,
2299
selection_drawing.position + Point2(0, selection_drawing.size.y)
2300
};
2301
2302
// Draw fill.
2303
RS::get_singleton()->canvas_item_add_rect(sel_drag_ci, selection_drawing, selection_area_fill);
2304
// Draw outline.
2305
for (int i = 0; i < 4; i++) {
2306
RS::get_singleton()->canvas_item_add_line(sel_drag_ci, endpoints[i], endpoints[(i + 1) % 4], selection_area_outline, thickness);
2307
}
2308
}
2309
2310
void RuntimeNodeSelect::_open_selection_list(const Vector<SelectResult> &p_items, const Point2 &p_pos) {
2311
Window *root = SceneTree::get_singleton()->get_root();
2312
2313
selection_list = memnew(PopupMenu);
2314
selection_list->set_theme(ThemeDB::get_singleton()->get_default_theme());
2315
selection_list->set_auto_translate_mode(Node::AUTO_TRANSLATE_MODE_DISABLED);
2316
selection_list->set_force_native(true);
2317
selection_list->connect("index_pressed", callable_mp(this, &RuntimeNodeSelect::_items_popup_index_pressed).bind(selection_list));
2318
selection_list->connect("popup_hide", callable_mp(this, &RuntimeNodeSelect::_close_selection_list));
2319
2320
root->add_child(selection_list);
2321
2322
for (const SelectResult &I : p_items) {
2323
selection_list->add_item(I.item->get_name());
2324
selection_list->set_item_metadata(-1, I.item);
2325
}
2326
2327
selection_list->set_position(selection_list->is_embedded() ? p_pos : (Input::get_singleton()->get_mouse_position() + root->get_position()));
2328
selection_list->reset_size();
2329
selection_list->popup();
2330
// FIXME: Ugly hack that stops the popup from hiding when the button is released.
2331
selection_list->call_deferred(SNAME("set_position"), selection_list->get_position() + Point2(1, 0));
2332
}
2333
2334
void RuntimeNodeSelect::_close_selection_list() {
2335
selection_list->queue_free();
2336
selection_list = nullptr;
2337
}
2338
2339
void RuntimeNodeSelect::_set_selection_visible(bool p_visible) {
2340
selection_visible = p_visible;
2341
2342
if (has_selection) {
2343
_update_selection();
2344
}
2345
}
2346
2347
// Copied and trimmed from the CanvasItemEditor implementation.
2348
void RuntimeNodeSelect::_find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
2349
if (!p_node || Object::cast_to<Viewport>(p_node)) {
2350
return;
2351
}
2352
2353
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
2354
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
2355
if (ci) {
2356
if (!ci->is_set_as_top_level()) {
2357
_find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, p_parent_xform * ci->get_transform(), p_canvas_xform);
2358
} else {
2359
_find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, ci->get_transform(), p_canvas_xform);
2360
}
2361
} else {
2362
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
2363
_find_canvas_items_at_pos(p_pos, p_node->get_child(i), r_items, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
2364
}
2365
}
2366
2367
if (!ci || !ci->is_visible_in_tree()) {
2368
return;
2369
}
2370
2371
Transform2D xform = p_canvas_xform;
2372
if (!ci->is_set_as_top_level()) {
2373
xform *= p_parent_xform;
2374
}
2375
2376
Window *root = SceneTree::get_singleton()->get_root();
2377
Point2 pos;
2378
// Cameras (overridden or not) don't affect `CanvasLayer`s.
2379
if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) {
2380
pos = (root->is_canvas_transform_override_enabled() ? root->get_canvas_transform_override() : root->get_canvas_transform()).affine_inverse().xform(p_pos);
2381
} else {
2382
pos = p_pos;
2383
}
2384
2385
xform = (xform * ci->get_transform()).affine_inverse();
2386
const real_t local_grab_distance = xform.basis_xform(Vector2(sel_2d_grab_dist, 0)).length() / view_2d_zoom;
2387
if (ci->_edit_is_selected_on_click(xform.xform(pos), local_grab_distance)) {
2388
SelectResult res;
2389
res.item = ci;
2390
res.order = ci->get_effective_z_index() + ci->get_canvas_layer();
2391
r_items.push_back(res);
2392
2393
#ifndef PHYSICS_2D_DISABLED
2394
// If it's a shape, get the collision object it's from.
2395
// FIXME: If the collision object has multiple shapes, only the topmost will be above it in the list.
2396
if (Object::cast_to<CollisionShape2D>(ci) || Object::cast_to<CollisionPolygon2D>(ci)) {
2397
CollisionObject2D *collision_object = Object::cast_to<CollisionObject2D>(ci->get_parent());
2398
if (collision_object) {
2399
SelectResult res_col;
2400
res_col.item = ci->get_parent();
2401
res_col.order = collision_object->get_z_index() + ci->get_canvas_layer();
2402
r_items.push_back(res_col);
2403
}
2404
}
2405
#endif // PHYSICS_2D_DISABLED
2406
}
2407
}
2408
2409
// Copied and trimmed from the CanvasItemEditor implementation.
2410
void RuntimeNodeSelect::_find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
2411
if (!p_node || Object::cast_to<Viewport>(p_node)) {
2412
return;
2413
}
2414
2415
CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
2416
for (int i = p_node->get_child_count() - 1; i >= 0; i--) {
2417
if (ci) {
2418
if (!ci->is_set_as_top_level()) {
2419
_find_canvas_items_at_rect(p_rect, p_node->get_child(i), r_items, p_parent_xform * ci->get_transform(), p_canvas_xform);
2420
} else {
2421
_find_canvas_items_at_rect(p_rect, p_node->get_child(i), r_items, ci->get_transform(), p_canvas_xform);
2422
}
2423
} else {
2424
CanvasLayer *cl = Object::cast_to<CanvasLayer>(p_node);
2425
_find_canvas_items_at_rect(p_rect, p_node->get_child(i), r_items, Transform2D(), cl ? cl->get_transform() : p_canvas_xform);
2426
}
2427
}
2428
2429
if (!ci || !ci->is_visible_in_tree()) {
2430
return;
2431
}
2432
2433
Transform2D xform = p_canvas_xform;
2434
if (!ci->is_set_as_top_level()) {
2435
xform *= p_parent_xform;
2436
}
2437
2438
Window *root = SceneTree::get_singleton()->get_root();
2439
Rect2 rect;
2440
// Cameras (overridden or not) don't affect `CanvasLayer`s.
2441
if (!ci->get_canvas_layer_node() || ci->get_canvas_layer_node()->is_following_viewport()) {
2442
rect = (root->is_canvas_transform_override_enabled() ? root->get_canvas_transform_override() : root->get_canvas_transform()).affine_inverse().xform(p_rect);
2443
} else {
2444
rect = p_rect;
2445
}
2446
rect = (xform * ci->get_transform()).affine_inverse().xform(rect);
2447
2448
bool selected = false;
2449
if (ci->_edit_use_rect()) {
2450
Rect2 ci_rect = ci->_edit_get_rect();
2451
if (rect.has_point(ci_rect.position) &&
2452
rect.has_point(ci_rect.position + Vector2(ci_rect.size.x, 0)) &&
2453
rect.has_point(ci_rect.position + Vector2(ci_rect.size.x, ci_rect.size.y)) &&
2454
rect.has_point(ci_rect.position + Vector2(0, ci_rect.size.y))) {
2455
selected = true;
2456
}
2457
} else if (rect.has_point(Point2())) {
2458
selected = true;
2459
}
2460
2461
if (selected) {
2462
SelectResult res;
2463
res.item = ci;
2464
res.order = ci->get_effective_z_index() + ci->get_canvas_layer();
2465
r_items.push_back(res);
2466
}
2467
}
2468
2469
void RuntimeNodeSelect::_pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event) {
2470
Vector2 scroll = SceneTree::get_singleton()->get_root()->get_screen_transform().affine_inverse().xform(p_scroll_vec);
2471
view_2d_offset.x -= scroll.x / view_2d_zoom;
2472
view_2d_offset.y -= scroll.y / view_2d_zoom;
2473
2474
_update_view_2d();
2475
}
2476
2477
// A very shallow copy of the same function inside CanvasItemEditor.
2478
void RuntimeNodeSelect::_zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event) {
2479
real_t prev_zoom = view_2d_zoom;
2480
view_2d_zoom = CLAMP(view_2d_zoom * p_zoom_factor, VIEW_2D_MIN_ZOOM, VIEW_2D_MAX_ZOOM);
2481
2482
Vector2 pos = SceneTree::get_singleton()->get_root()->get_screen_transform().affine_inverse().xform(p_origin);
2483
view_2d_offset += pos / prev_zoom - pos / view_2d_zoom;
2484
2485
// We want to align in-scene pixels to screen pixels, this prevents blurry rendering
2486
// of small details (texts, lines).
2487
// This correction adds a jitter movement when zooming, so we correct only when the
2488
// zoom factor is an integer. (in the other cases, all pixels won't be aligned anyway)
2489
const real_t closest_zoom_factor = Math::round(view_2d_zoom);
2490
if (Math::is_zero_approx(view_2d_zoom - closest_zoom_factor)) {
2491
// Make sure scene pixel at view_offset is aligned on a screen pixel.
2492
Vector2 view_offset_int = view_2d_offset.floor();
2493
Vector2 view_offset_frac = view_2d_offset - view_offset_int;
2494
view_2d_offset = view_offset_int + (view_offset_frac * closest_zoom_factor).round() / closest_zoom_factor;
2495
}
2496
2497
_update_view_2d();
2498
}
2499
2500
void RuntimeNodeSelect::_reset_camera_2d() {
2501
view_2d_offset = -SceneTree::get_singleton()->get_root()->get_canvas_transform().get_origin();
2502
view_2d_zoom = 1;
2503
2504
_update_view_2d();
2505
}
2506
2507
void RuntimeNodeSelect::_update_view_2d() {
2508
Transform2D transform = Transform2D();
2509
transform.scale_basis(Size2(view_2d_zoom, view_2d_zoom));
2510
transform.columns[2] = -view_2d_offset * view_2d_zoom;
2511
2512
SceneTree::get_singleton()->get_root()->set_canvas_transform_override(transform);
2513
2514
_queue_selection_update();
2515
}
2516
2517
#ifndef _3D_DISABLED
2518
void RuntimeNodeSelect::_find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items) {
2519
Window *root = SceneTree::get_singleton()->get_root();
2520
2521
Vector3 ray, pos, to;
2522
if (root->is_camera_3d_override_enabled()) {
2523
ray = root->camera_3d_override_project_ray_normal(p_pos);
2524
pos = root->camera_3d_override_project_ray_origin(p_pos);
2525
to = pos + ray * root->get_camera_3d_override_properties()["z_far"];
2526
} else {
2527
Camera3D *camera = root->get_camera_3d();
2528
if (!camera) {
2529
return;
2530
}
2531
2532
ray = camera->project_ray_normal(p_pos);
2533
pos = camera->project_ray_origin(p_pos);
2534
to = pos + ray * camera->get_far();
2535
}
2536
2537
#ifndef PHYSICS_3D_DISABLED
2538
// Start with physical objects.
2539
PhysicsDirectSpaceState3D *ss = root->get_world_3d()->get_direct_space_state();
2540
PhysicsDirectSpaceState3D::RayResult result;
2541
HashSet<RID> excluded;
2542
PhysicsDirectSpaceState3D::RayParameters ray_params;
2543
ray_params.from = pos;
2544
ray_params.to = to;
2545
ray_params.collide_with_areas = true;
2546
while (true) {
2547
ray_params.exclude = excluded;
2548
if (ss->intersect_ray(ray_params, result)) {
2549
SelectResult res;
2550
res.item = Object::cast_to<Node>(result.collider);
2551
res.order = -pos.distance_to(result.position);
2552
2553
// Fetch collision shapes.
2554
CollisionObject3D *collision = Object::cast_to<CollisionObject3D>(result.collider);
2555
if (collision) {
2556
List<uint32_t> owners;
2557
collision->get_shape_owners(&owners);
2558
for (uint32_t &I : owners) {
2559
SelectResult res_shape;
2560
res_shape.item = Object::cast_to<Node>(collision->shape_owner_get_owner(I));
2561
res_shape.order = res.order;
2562
r_items.push_back(res_shape);
2563
}
2564
}
2565
2566
r_items.push_back(res);
2567
2568
excluded.insert(result.rid);
2569
} else {
2570
break;
2571
}
2572
}
2573
#endif // PHYSICS_3D_DISABLED
2574
2575
// Then go for the meshes.
2576
Vector<ObjectID> items = RS::get_singleton()->instances_cull_ray(pos, to, root->get_world_3d()->get_scenario());
2577
for (int i = 0; i < items.size(); i++) {
2578
Object *obj = ObjectDB::get_instance(items[i]);
2579
2580
GeometryInstance3D *geo_instance = Object::cast_to<GeometryInstance3D>(obj);
2581
if (geo_instance) {
2582
Ref<TriangleMesh> mesh_collision = geo_instance->generate_triangle_mesh();
2583
2584
if (mesh_collision.is_valid()) {
2585
Transform3D gt = geo_instance->get_global_transform();
2586
Transform3D ai = gt.affine_inverse();
2587
Vector3 point, normal;
2588
if (mesh_collision->intersect_ray(ai.xform(pos), ai.basis.xform(ray).normalized(), point, normal)) {
2589
SelectResult res;
2590
res.item = Object::cast_to<Node>(obj);
2591
res.order = -pos.distance_to(gt.xform(point));
2592
r_items.push_back(res);
2593
2594
continue;
2595
}
2596
}
2597
}
2598
2599
items.remove_at(i);
2600
i--;
2601
}
2602
}
2603
2604
void RuntimeNodeSelect::_find_3d_items_at_rect(const Rect2 &p_rect, Vector<SelectResult> &r_items) {
2605
Window *root = SceneTree::get_singleton()->get_root();
2606
Camera3D *camera = root->get_camera_3d();
2607
if (!camera) {
2608
return;
2609
}
2610
2611
bool cam_override = root->is_camera_3d_override_enabled();
2612
Vector3 cam_pos;
2613
Vector3 dist_pos;
2614
if (cam_override) {
2615
cam_pos = root->get_camera_3d_override_transform().origin;
2616
dist_pos = root->camera_3d_override_project_ray_origin(p_rect.position + p_rect.size / 2);
2617
} else {
2618
cam_pos = camera->get_global_position();
2619
dist_pos = camera->project_ray_origin(p_rect.position + p_rect.size / 2);
2620
}
2621
2622
real_t znear, zfar = 0;
2623
real_t zofs = 5.0;
2624
if (cam_override) {
2625
HashMap<StringName, real_t> override_props = root->get_camera_3d_override_properties();
2626
znear = override_props["z_near"];
2627
zfar = override_props["z_far"];
2628
zofs -= znear;
2629
} else {
2630
znear = camera->get_near();
2631
zfar = camera->get_far();
2632
zofs -= znear;
2633
}
2634
zofs = MAX(0.0, zofs);
2635
2636
const Point2 pos_end = p_rect.position + p_rect.size;
2637
Vector3 box[4] = {
2638
Vector3(
2639
MIN(p_rect.position.x, pos_end.x),
2640
MIN(p_rect.position.y, pos_end.y),
2641
zofs),
2642
Vector3(
2643
MAX(p_rect.position.x, pos_end.x),
2644
MIN(p_rect.position.y, pos_end.y),
2645
zofs),
2646
Vector3(
2647
MAX(p_rect.position.x, pos_end.x),
2648
MAX(p_rect.position.y, pos_end.y),
2649
zofs),
2650
Vector3(
2651
MIN(p_rect.position.x, pos_end.x),
2652
MAX(p_rect.position.y, pos_end.y),
2653
zofs)
2654
};
2655
2656
Vector<Plane> frustum;
2657
for (int i = 0; i < 4; i++) {
2658
Vector3 a = _get_screen_to_space(box[i]);
2659
Vector3 b = _get_screen_to_space(box[(i + 1) % 4]);
2660
frustum.push_back(Plane(a, b, cam_pos));
2661
}
2662
2663
Plane near_plane;
2664
// Get the camera normal.
2665
if (cam_override) {
2666
near_plane = Plane(root->get_camera_3d_override_transform().basis.get_column(2), cam_pos);
2667
} else {
2668
near_plane = Plane(camera->get_global_transform().basis.get_column(2), cam_pos);
2669
}
2670
near_plane.d -= znear;
2671
frustum.push_back(near_plane);
2672
2673
Plane far_plane = -near_plane;
2674
far_plane.d += zfar;
2675
frustum.push_back(far_plane);
2676
2677
#ifndef PHYSICS_3D_DISABLED
2678
Vector<Vector3> points = Geometry3D::compute_convex_mesh_points(&frustum[0], frustum.size());
2679
Ref<ConvexPolygonShape3D> shape;
2680
shape.instantiate();
2681
shape->set_points(points);
2682
2683
// Start with physical objects.
2684
PhysicsDirectSpaceState3D *ss = root->get_world_3d()->get_direct_space_state();
2685
PhysicsDirectSpaceState3D::ShapeResult result;
2686
PhysicsDirectSpaceState3D::ShapeParameters shape_params;
2687
shape_params.shape_rid = shape->get_rid();
2688
shape_params.collide_with_areas = true;
2689
if (ss->intersect_shape(shape_params, &result, 32)) {
2690
SelectResult res;
2691
res.item = Object::cast_to<Node>(result.collider);
2692
res.order = -dist_pos.distance_to(Object::cast_to<Node3D>(res.item)->get_global_transform().origin);
2693
2694
// Fetch collision shapes.
2695
CollisionObject3D *collision = Object::cast_to<CollisionObject3D>(result.collider);
2696
if (collision) {
2697
List<uint32_t> owners;
2698
collision->get_shape_owners(&owners);
2699
for (uint32_t &I : owners) {
2700
SelectResult res_shape;
2701
res_shape.item = Object::cast_to<Node>(collision->shape_owner_get_owner(I));
2702
res_shape.order = res.order;
2703
r_items.push_back(res_shape);
2704
}
2705
}
2706
2707
r_items.push_back(res);
2708
}
2709
#endif // PHYSICS_3D_DISABLED
2710
2711
// Then go for the meshes.
2712
Vector<ObjectID> items = RS::get_singleton()->instances_cull_convex(frustum, root->get_world_3d()->get_scenario());
2713
for (int i = 0; i < items.size(); i++) {
2714
Object *obj = ObjectDB::get_instance(items[i]);
2715
GeometryInstance3D *geo_instance = Object::cast_to<GeometryInstance3D>(obj);
2716
if (geo_instance) {
2717
Ref<TriangleMesh> mesh_collision = geo_instance->generate_triangle_mesh();
2718
2719
if (mesh_collision.is_valid()) {
2720
Transform3D gt = geo_instance->get_global_transform();
2721
Vector3 mesh_scale = gt.get_basis().get_scale();
2722
gt.orthonormalize();
2723
2724
Transform3D it = gt.affine_inverse();
2725
2726
Vector<Plane> transformed_frustum;
2727
int plane_count = frustum.size();
2728
transformed_frustum.resize(plane_count);
2729
2730
for (int j = 0; j < plane_count; j++) {
2731
transformed_frustum.write[j] = it.xform(frustum[j]);
2732
}
2733
Vector<Vector3> convex_points = Geometry3D::compute_convex_mesh_points(transformed_frustum.ptr(), plane_count);
2734
if (mesh_collision->inside_convex_shape(transformed_frustum.ptr(), transformed_frustum.size(), convex_points.ptr(), convex_points.size(), mesh_scale)) {
2735
SelectResult res;
2736
res.item = Object::cast_to<Node>(obj);
2737
res.order = -dist_pos.distance_to(gt.origin);
2738
r_items.push_back(res);
2739
2740
continue;
2741
}
2742
}
2743
}
2744
2745
items.remove_at(i);
2746
i--;
2747
}
2748
}
2749
2750
Vector3 RuntimeNodeSelect::_get_screen_to_space(const Vector3 &p_vector3) {
2751
Window *root = SceneTree::get_singleton()->get_root();
2752
Camera3D *camera = root->get_camera_3d();
2753
2754
Size2 size = root->get_size();
2755
real_t znear = 0;
2756
2757
Projection cm;
2758
Transform3D camera_transform;
2759
if (root->is_camera_3d_override_enabled()) {
2760
HashMap<StringName, real_t> override_props = root->get_camera_3d_override_properties();
2761
znear = override_props["z_near"];
2762
cm.set_perspective(override_props["fov"], size.aspect(), znear + p_vector3.z, override_props["z_far"]);
2763
2764
camera_transform.translate_local(cursor.pos);
2765
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
2766
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
2767
camera_transform.translate_local(0, 0, cursor.distance);
2768
} else {
2769
znear = camera->get_near();
2770
cm.set_perspective(camera->get_fov(), size.aspect(), znear + p_vector3.z, camera->get_far());
2771
2772
camera_transform = camera->get_camera_transform();
2773
}
2774
2775
Vector2 screen_he = cm.get_viewport_half_extents();
2776
return camera_transform.xform(Vector3(((p_vector3.x / size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (p_vector3.y / size.height)) * 2.0 - 1.0) * screen_he.y, -(znear + p_vector3.z)));
2777
}
2778
2779
bool RuntimeNodeSelect::_handle_3d_input(const Ref<InputEvent> &p_event) {
2780
Ref<InputEventMouseButton> b = p_event;
2781
if (b.is_valid()) {
2782
const real_t zoom_factor = 1.08 * b->get_factor();
2783
switch (b->get_button_index()) {
2784
case MouseButton::WHEEL_UP: {
2785
if (!camera_freelook) {
2786
_cursor_scale_distance(1.0 / zoom_factor);
2787
} else {
2788
_scale_freelook_speed(zoom_factor);
2789
}
2790
2791
return true;
2792
} break;
2793
case MouseButton::WHEEL_DOWN: {
2794
if (!camera_freelook) {
2795
_cursor_scale_distance(zoom_factor);
2796
} else {
2797
_scale_freelook_speed(1.0 / zoom_factor);
2798
}
2799
2800
return true;
2801
} break;
2802
case MouseButton::RIGHT: {
2803
_set_camera_freelook_enabled(b->is_pressed());
2804
return true;
2805
} break;
2806
default: {
2807
}
2808
}
2809
}
2810
2811
Ref<InputEventMouseMotion> m = p_event;
2812
if (m.is_valid()) {
2813
if (camera_freelook) {
2814
_cursor_look(m);
2815
} else if (m->get_button_mask().has_flag(MouseButtonMask::MIDDLE)) {
2816
if (m->is_shift_pressed()) {
2817
_cursor_pan(m);
2818
} else {
2819
_cursor_orbit(m);
2820
}
2821
}
2822
2823
return true;
2824
}
2825
2826
Ref<InputEventKey> k = p_event;
2827
if (k.is_valid()) {
2828
if (k->get_physical_keycode() == Key::ESCAPE) {
2829
_set_camera_freelook_enabled(false);
2830
return true;
2831
} else if (k->is_ctrl_pressed()) {
2832
switch (k->get_physical_keycode()) {
2833
case Key::EQUAL: {
2834
cursor.fov_scale = CLAMP(cursor.fov_scale - 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
2835
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
2836
2837
return true;
2838
} break;
2839
case Key::MINUS: {
2840
cursor.fov_scale = CLAMP(cursor.fov_scale + 0.05, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
2841
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
2842
2843
return true;
2844
} break;
2845
case Key::KEY_0: {
2846
cursor.fov_scale = 1;
2847
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov, camera_znear, camera_zfar);
2848
2849
return true;
2850
} break;
2851
default: {
2852
}
2853
}
2854
}
2855
}
2856
2857
// TODO: Handle magnify and pan input gestures.
2858
2859
return false;
2860
}
2861
2862
void RuntimeNodeSelect::_set_camera_freelook_enabled(bool p_enabled) {
2863
camera_freelook = p_enabled;
2864
2865
if (p_enabled) {
2866
// Make sure eye_pos is synced, because freelook referential is eye pos rather than orbit pos
2867
Vector3 forward = _get_cursor_transform().basis.xform(Vector3(0, 0, -1));
2868
cursor.eye_pos = cursor.pos - cursor.distance * forward;
2869
2870
previous_mouse_position = SceneTree::get_singleton()->get_root()->get_mouse_position();
2871
2872
// Hide mouse like in an FPS (warping doesn't work).
2873
Input::get_singleton()->set_mouse_mode_override(Input::MOUSE_MODE_CAPTURED);
2874
2875
} else {
2876
// Restore mouse.
2877
Input::get_singleton()->set_mouse_mode_override(Input::MOUSE_MODE_VISIBLE);
2878
2879
// Restore the previous mouse position when leaving freelook mode.
2880
// This is done because leaving `Input.MOUSE_MODE_CAPTURED` will center the cursor
2881
// due to OS limitations.
2882
Input::get_singleton()->warp_mouse(previous_mouse_position);
2883
}
2884
}
2885
2886
void RuntimeNodeSelect::_cursor_scale_distance(real_t p_scale) {
2887
real_t min_distance = MAX(camera_znear * 4, VIEW_3D_MIN_ZOOM);
2888
real_t max_distance = MIN(camera_zfar / 4, VIEW_3D_MAX_ZOOM);
2889
cursor.distance = CLAMP(cursor.distance * p_scale, min_distance, max_distance);
2890
2891
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
2892
}
2893
2894
void RuntimeNodeSelect::_scale_freelook_speed(real_t p_scale) {
2895
real_t min_speed = MAX(camera_znear * 4, VIEW_3D_MIN_ZOOM);
2896
real_t max_speed = MIN(camera_zfar / 4, VIEW_3D_MAX_ZOOM);
2897
if (unlikely(min_speed > max_speed)) {
2898
freelook_base_speed = (min_speed + max_speed) / 2;
2899
} else {
2900
freelook_base_speed = CLAMP(freelook_base_speed * p_scale, min_speed, max_speed);
2901
}
2902
}
2903
2904
void RuntimeNodeSelect::_cursor_look(Ref<InputEventWithModifiers> p_event) {
2905
Window *root = SceneTree::get_singleton()->get_root();
2906
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(), root->get_size()));
2907
const Transform3D prev_camera_transform = _get_cursor_transform();
2908
2909
if (invert_y_axis) {
2910
cursor.x_rot -= relative.y * freelook_sensitivity;
2911
} else {
2912
cursor.x_rot += relative.y * freelook_sensitivity;
2913
}
2914
// Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
2915
cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
2916
2917
cursor.y_rot += relative.x * freelook_sensitivity;
2918
2919
// Look is like the opposite of Orbit: the focus point rotates around the camera.
2920
Transform3D camera_transform = _get_cursor_transform();
2921
Vector3 pos = camera_transform.xform(Vector3(0, 0, 0));
2922
Vector3 prev_pos = prev_camera_transform.xform(Vector3(0, 0, 0));
2923
Vector3 diff = prev_pos - pos;
2924
cursor.pos += diff;
2925
2926
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
2927
}
2928
2929
void RuntimeNodeSelect::_cursor_pan(Ref<InputEventWithModifiers> p_event) {
2930
Window *root = SceneTree::get_singleton()->get_root();
2931
// Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen.
2932
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2)));
2933
const real_t pan_speed = translation_sensitivity / 150.0;
2934
2935
Transform3D camera_transform;
2936
camera_transform.translate_local(cursor.pos);
2937
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
2938
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
2939
2940
Vector3 translation(1 * -relative.x * pan_speed, relative.y * pan_speed, 0);
2941
translation *= cursor.distance / 4;
2942
camera_transform.translate_local(translation);
2943
cursor.pos = camera_transform.origin;
2944
2945
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
2946
}
2947
2948
void RuntimeNodeSelect::_cursor_orbit(Ref<InputEventWithModifiers> p_event) {
2949
Window *root = SceneTree::get_singleton()->get_root();
2950
// Reduce all sides of the area by 1, so warping works when windows are maximized/fullscreen.
2951
const Vector2 relative = _get_warped_mouse_motion(p_event, Rect2(Vector2(1, 1), root->get_size() - Vector2(2, 2)));
2952
2953
if (invert_y_axis) {
2954
cursor.x_rot -= relative.y * orbit_sensitivity;
2955
} else {
2956
cursor.x_rot += relative.y * orbit_sensitivity;
2957
}
2958
// Clamp the Y rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
2959
cursor.x_rot = CLAMP(cursor.x_rot, -1.57, 1.57);
2960
2961
if (invert_x_axis) {
2962
cursor.y_rot -= relative.x * orbit_sensitivity;
2963
} else {
2964
cursor.y_rot += relative.x * orbit_sensitivity;
2965
}
2966
2967
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
2968
}
2969
2970
Point2 RuntimeNodeSelect::_get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_area) const {
2971
ERR_FAIL_COND_V(p_event.is_null(), Point2());
2972
2973
if (warped_mouse_panning_3d) {
2974
return Input::get_singleton()->warp_mouse_motion(p_event, p_area);
2975
}
2976
2977
return p_event->get_relative();
2978
}
2979
2980
Transform3D RuntimeNodeSelect::_get_cursor_transform() {
2981
Transform3D camera_transform;
2982
camera_transform.translate_local(cursor.pos);
2983
camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot);
2984
camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot);
2985
camera_transform.translate_local(0, 0, cursor.distance);
2986
2987
return camera_transform;
2988
}
2989
2990
void RuntimeNodeSelect::_reset_camera_3d() {
2991
camera_first_override = true;
2992
2993
cursor = Cursor();
2994
Window *root = SceneTree::get_singleton()->get_root();
2995
Camera3D *camera = root->get_camera_3d();
2996
if (camera) {
2997
Transform3D transform = camera->get_global_transform();
2998
transform.translate_local(0, 0, -cursor.distance);
2999
cursor.pos = transform.origin;
3000
3001
cursor.x_rot = -camera->get_global_rotation().x;
3002
cursor.y_rot = -camera->get_global_rotation().y;
3003
3004
cursor.fov_scale = CLAMP(camera->get_fov() / camera_fov, CAMERA_MIN_FOV_SCALE, CAMERA_MAX_FOV_SCALE);
3005
} else {
3006
cursor.fov_scale = 1.0;
3007
}
3008
3009
SceneTree::get_singleton()->get_root()->set_camera_3d_override_transform(_get_cursor_transform());
3010
SceneTree::get_singleton()->get_root()->set_camera_3d_override_perspective(camera_fov * cursor.fov_scale, camera_znear, camera_zfar);
3011
}
3012
#endif // _3D_DISABLED
3013
3014
#endif // DEBUG_ENABLED
3015
3016